GPU: Renderdoc Frame Capturing
This PR uses renderdoc for frame capturing when enabled. It enabled an easier workflow for frame capturing. - Capture GPU API calls from test cases - Capture GPU API calls from background threads - Capture GPU API calls from background rendering. Renderdoc is an important GPU debugger used by the Eevee/ Viewport module. Previously we needed to change code in order to record background rendering, that could on its own lead to other side-effects. The integration with renderdoc can be enabled using `WITH_RENDERDOC=On` compiler option. `GPU_debug_capture_begin` and `GPU_debug_capture_end` can be added to the section of the code you want to debug. When running Blender inside renderdoc this part will automatically be captured. All GPU test cases are now guarded by these calls. In order to capture the test cases you need to start the test cases from renderdoc and the captured GPU API calls will appear where each capture is a single test case. Pull Request: https://projects.blender.org/blender/blender/pulls/105921
This commit is contained in:
committed by
Clément Foucault
parent
0efb7a202e
commit
fda65ad5ca
17
intern/renderdoc_dynload/CMakeLists.txt
Normal file
17
intern/renderdoc_dynload/CMakeLists.txt
Normal file
@@ -0,0 +1,17 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
set(INC
|
||||
include
|
||||
../../extern/renderdoc/include
|
||||
)
|
||||
|
||||
set(INC_SYS
|
||||
)
|
||||
|
||||
set(SRC
|
||||
intern/renderdoc_api.cc
|
||||
|
||||
include/renderdoc_api.hh
|
||||
)
|
||||
|
||||
blender_add_lib(bf_intern_renderdoc_dynload "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
|
||||
45
intern/renderdoc_dynload/include/renderdoc_api.hh
Normal file
45
intern/renderdoc_dynload/include/renderdoc_api.hh
Normal file
@@ -0,0 +1,45 @@
|
||||
#pragma once
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
* Copyright 2023 Blender Foundation. All rights reserved. */
|
||||
|
||||
#include "renderdoc_app.h"
|
||||
|
||||
namespace renderdoc::api {
|
||||
class Renderdoc {
|
||||
private:
|
||||
enum class State {
|
||||
/**
|
||||
* Initial state of the API indicating that the API hasn't checked if it can find renderdoc.
|
||||
*/
|
||||
UNINITIALIZED,
|
||||
|
||||
/**
|
||||
* API has looked for renderdoc, but couldn't find it. This indicates that renderdoc isn't
|
||||
* available on the platform, or wasn't registered correctly.
|
||||
*/
|
||||
NOT_FOUND,
|
||||
|
||||
/**
|
||||
* API has loaded the symbols of renderdoc.
|
||||
*/
|
||||
LOADED,
|
||||
};
|
||||
State state_ = State::UNINITIALIZED;
|
||||
RENDERDOC_API_1_6_0 *renderdoc_api_ = nullptr;
|
||||
|
||||
public:
|
||||
bool start_frame_capture(RENDERDOC_DevicePointer device_handle,
|
||||
RENDERDOC_WindowHandle window_handle);
|
||||
void end_frame_capture(RENDERDOC_DevicePointer device_handle,
|
||||
RENDERDOC_WindowHandle window_handle);
|
||||
|
||||
private:
|
||||
/**
|
||||
* Check if renderdoc has been loaded.
|
||||
*
|
||||
* When not loaded it tries to load the API, but only tries to do it once.
|
||||
*/
|
||||
bool check_loaded();
|
||||
void load();
|
||||
};
|
||||
} // namespace renderdoc::api
|
||||
77
intern/renderdoc_dynload/intern/renderdoc_api.cc
Normal file
77
intern/renderdoc_dynload/intern/renderdoc_api.cc
Normal file
@@ -0,0 +1,77 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
* Copyright 2023 Blender Foundation. All rights reserved. */
|
||||
|
||||
#include "renderdoc_api.hh"
|
||||
|
||||
#ifdef _WIN32
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
# include <Windows.h>
|
||||
#else
|
||||
# include <dlfcn.h>
|
||||
#endif
|
||||
#include <iostream>
|
||||
|
||||
namespace renderdoc::api {
|
||||
bool Renderdoc::start_frame_capture(RENDERDOC_DevicePointer device_handle,
|
||||
RENDERDOC_WindowHandle window_handle)
|
||||
{
|
||||
if (!check_loaded()) {
|
||||
return false;
|
||||
}
|
||||
renderdoc_api_->StartFrameCapture(device_handle, window_handle);
|
||||
return true;
|
||||
}
|
||||
|
||||
void Renderdoc::end_frame_capture(RENDERDOC_DevicePointer device_handle,
|
||||
RENDERDOC_WindowHandle window_handle)
|
||||
|
||||
{
|
||||
if (!check_loaded()) {
|
||||
return;
|
||||
}
|
||||
renderdoc_api_->EndFrameCapture(device_handle, window_handle);
|
||||
}
|
||||
|
||||
bool Renderdoc::check_loaded()
|
||||
{
|
||||
switch (state_) {
|
||||
case State::UNINITIALIZED:
|
||||
load();
|
||||
return renderdoc_api_ != nullptr;
|
||||
break;
|
||||
case State::NOT_FOUND:
|
||||
return false;
|
||||
case State::LOADED:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Renderdoc::load()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
if (HMODULE mod = GetModuleHandleA("renderdoc.dll")) {
|
||||
pRENDERDOC_GetAPI RENDERDOC_GetAPI = (pRENDERDOC_GetAPI)GetProcAddress(mod,
|
||||
"RENDERDOC_GetAPI");
|
||||
RENDERDOC_GetAPI(eRENDERDOC_API_Version_1_1_2, (void **)&renderdoc_api_);
|
||||
}
|
||||
#else
|
||||
if (void *mod = dlopen("librenderdoc.so", RTLD_NOW | RTLD_NOLOAD)) {
|
||||
pRENDERDOC_GetAPI RENDERDOC_GetAPI = (pRENDERDOC_GetAPI)dlsym(mod, "RENDERDOC_GetAPI");
|
||||
RENDERDOC_GetAPI(eRENDERDOC_API_Version_1_1_2, (void **)&renderdoc_api_);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (renderdoc_api_ != nullptr) {
|
||||
int major;
|
||||
int minor;
|
||||
int patch;
|
||||
renderdoc_api_->GetAPIVersion(&major, &minor, &patch);
|
||||
std::cout << "Found renderdoc API [" << major << "." << minor << "." << patch << "]";
|
||||
}
|
||||
else {
|
||||
std::cerr << "Unable to load renderdoc API.\n";
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace renderdoc::api
|
||||
Reference in New Issue
Block a user