forked from blender/blender
main sync #3
@ -5,6 +5,40 @@
|
||||
* \ingroup gpu
|
||||
*
|
||||
* Helpers for GPU / drawing debugging.
|
||||
*
|
||||
*
|
||||
** GPU debug capture usage example:
|
||||
*
|
||||
** Instant frame capture. **
|
||||
*
|
||||
* \code
|
||||
* #include "GPU_debug.h"
|
||||
* static void do_render_engine(Render *re)
|
||||
* {
|
||||
* GPU_debug_capture_begin();
|
||||
* RE_engine_render(re, false);
|
||||
* GPU_debug_capture_end();
|
||||
* }
|
||||
* \endcode
|
||||
*
|
||||
** Capture scopes. **
|
||||
*
|
||||
* \code
|
||||
* #include "GPU_debug.h"
|
||||
* void *capture_scope = nullptr;
|
||||
* static void do_render_engine(Render *re)
|
||||
* {
|
||||
* if (!capture_scope) {
|
||||
* // Create capture scope which will display in external tool.
|
||||
* capture_scope = GPU_debug_capture_scope_create("Render Frame");
|
||||
* }
|
||||
*
|
||||
* // Commands within scope boundary captured when requested in tool.
|
||||
* GPU_debug_capture_scope_begin(capture_scope);
|
||||
* RE_engine_render(re, false);
|
||||
* GPU_debug_capture_scope_end(capture_scope);
|
||||
* }
|
||||
* \endcode
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
@ -29,6 +63,37 @@ void GPU_debug_get_groups_names(int name_buf_len, char *r_name_buf);
|
||||
*/
|
||||
bool GPU_debug_group_match(const char *ref);
|
||||
|
||||
/**
|
||||
* GPU Frame capture support.
|
||||
*
|
||||
* Allows instananeous frame capture of GPU calls between begin/end.
|
||||
*/
|
||||
void GPU_debug_capture_begin(void);
|
||||
void GPU_debug_capture_end(void);
|
||||
|
||||
/**
|
||||
* GPU debug frame capture scopes.
|
||||
*
|
||||
* Allows creation of a GPU frame capture scope that define a region within which an external GPU
|
||||
* Frame capture tool can perform a deferred capture of GPU API calls within the boundary upon user
|
||||
* request.
|
||||
*
|
||||
* \param name Unique name of capture scope displayed within capture tool.
|
||||
* \return pointer wrapping an API-specific capture scope object.
|
||||
* \note a capture scope should be created a single time and only used within one begin/end pair.
|
||||
*/
|
||||
void *GPU_debug_capture_scope_create(const char *name);
|
||||
|
||||
/**
|
||||
* Used to declare the region within which GPU calls are captured when the scope is triggered.
|
||||
*
|
||||
* \param scope Pointer to capture scope object created with GPU_debug_capture_scope_create.
|
||||
* \return True if the capture tool is actively capturing this scope when function is executed.
|
||||
* Otherwise, False.
|
||||
*/
|
||||
bool GPU_debug_capture_scope_begin(void *scope);
|
||||
void GPU_debug_capture_scope_end(void *scope);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -47,6 +47,7 @@ class Context {
|
||||
FrameBuffer *front_right = nullptr;
|
||||
|
||||
DebugStack debug_stack;
|
||||
bool debug_is_capturing = false;
|
||||
|
||||
/* GPUContext counter used to assign a unique ID to each GPUContext.
|
||||
* NOTE(Metal): This is required by the Metal Backend, as a bug exists in the global OS shader
|
||||
@ -84,6 +85,13 @@ class Context {
|
||||
virtual void debug_group_begin(const char *, int){};
|
||||
virtual void debug_group_end(){};
|
||||
|
||||
/* Returns true if capture successfully started. */
|
||||
virtual bool debug_capture_begin() = 0;
|
||||
virtual void debug_capture_end() = 0;
|
||||
virtual void *debug_capture_scope_create(const char *name) = 0;
|
||||
virtual bool debug_capture_scope_begin(void *scope) = 0;
|
||||
virtual void debug_capture_scope_end(void *scope) = 0;
|
||||
|
||||
bool is_active_on_thread();
|
||||
};
|
||||
|
||||
|
@ -73,3 +73,96 @@ bool GPU_debug_group_match(const char *ref)
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void GPU_debug_capture_begin()
|
||||
{
|
||||
/* GPU Frame capture is only enabled when --debug-gpu is specified. */
|
||||
if (!(G.debug & G_DEBUG_GPU)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Context *ctx = Context::get();
|
||||
if (ctx && !ctx->debug_is_capturing) {
|
||||
ctx->debug_is_capturing = ctx->debug_capture_begin();
|
||||
if (!ctx->debug_is_capturing) {
|
||||
printf("Failed to start GPU frame capture!\n");
|
||||
}
|
||||
/* Call GPU_finish to ensure all desired GPU commands occur within the capture boundary. */
|
||||
GPU_finish();
|
||||
}
|
||||
}
|
||||
|
||||
void GPU_debug_capture_end()
|
||||
{
|
||||
/* GPU Frame capture is only enabled when --debug-gpu is specified. */
|
||||
if (!(G.debug & G_DEBUG_GPU)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Context *ctx = Context::get();
|
||||
if (ctx && ctx->debug_is_capturing) {
|
||||
/* Call GPU_finish to ensure all desired GPU commands occur within the capture boundary. */
|
||||
GPU_finish();
|
||||
ctx->debug_capture_end();
|
||||
ctx->debug_is_capturing = false;
|
||||
}
|
||||
}
|
||||
|
||||
void *GPU_debug_capture_scope_create(const char *name)
|
||||
{
|
||||
/* GPU Frame capture is only enabled when --debug-gpu is specified. */
|
||||
if (!(G.debug & G_DEBUG_GPU)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Context *ctx = Context::get();
|
||||
if (!ctx) {
|
||||
return NULL;
|
||||
}
|
||||
return ctx->debug_capture_scope_create(name);
|
||||
}
|
||||
|
||||
bool GPU_debug_capture_scope_begin(void *scope)
|
||||
{
|
||||
/* Early exit if scope does not exist or not in debug mode. */
|
||||
if (!(G.debug & G_DEBUG_GPU) || !scope) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Context *ctx = Context::get();
|
||||
if (!ctx) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Declare beginning of capture scope region. */
|
||||
bool scope_capturing = ctx->debug_capture_scope_begin(scope);
|
||||
if (scope_capturing && !ctx->debug_is_capturing) {
|
||||
/* Call GPU_finish to ensure all desired GPU commands occur within the capture boundary. */
|
||||
GPU_finish();
|
||||
ctx->debug_is_capturing = true;
|
||||
}
|
||||
return ctx->debug_is_capturing;
|
||||
}
|
||||
|
||||
void GPU_debug_capture_scope_end(void *scope)
|
||||
{
|
||||
/* Early exit if scope does not exist or not in debug mode. */
|
||||
if (!(G.debug & G_DEBUG_GPU) || !scope) {
|
||||
return;
|
||||
}
|
||||
|
||||
Context *ctx = Context::get();
|
||||
if (!ctx) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* If capturing, call GPU_finish to ensure all desired GPU commands occur within the capture
|
||||
* boundary. */
|
||||
if (ctx->debug_is_capturing) {
|
||||
GPU_finish();
|
||||
ctx->debug_is_capturing = false;
|
||||
}
|
||||
|
||||
/* Declare end of capture scope region. */
|
||||
ctx->debug_capture_scope_end(scope);
|
||||
}
|
||||
|
@ -740,6 +740,11 @@ class MTLContext : public Context {
|
||||
|
||||
void debug_group_begin(const char *name, int index) override;
|
||||
void debug_group_end() override;
|
||||
bool debug_capture_begin() override;
|
||||
void debug_capture_end() override;
|
||||
void *debug_capture_scope_create(const char *name) override;
|
||||
bool debug_capture_scope_begin(void *scope) override;
|
||||
void debug_capture_scope_end(void *scope) override;
|
||||
|
||||
/*** MTLContext Utility functions. */
|
||||
/*
|
||||
|
@ -57,6 +57,63 @@ void MTLContext::debug_group_end()
|
||||
}
|
||||
}
|
||||
|
||||
bool MTLContext::debug_capture_begin()
|
||||
{
|
||||
MTLCaptureManager *capture_manager = [MTLCaptureManager sharedCaptureManager];
|
||||
if (!capture_manager) {
|
||||
/* Early exit if frame capture is disabled. */
|
||||
return false;
|
||||
}
|
||||
MTLCaptureDescriptor *capture_descriptor = [[MTLCaptureDescriptor alloc] init];
|
||||
capture_descriptor.captureObject = this->device;
|
||||
NSError *error;
|
||||
if (![capture_manager startCaptureWithDescriptor:capture_descriptor error:&error]) {
|
||||
NSLog(@"Failed to start Metal frame capture, error %@", error);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void MTLContext::debug_capture_end()
|
||||
{
|
||||
MTLCaptureManager *capture_manager = [MTLCaptureManager sharedCaptureManager];
|
||||
if (!capture_manager) {
|
||||
/* Early exit if frame capture is disabled. */
|
||||
return;
|
||||
}
|
||||
[capture_manager stopCapture];
|
||||
}
|
||||
|
||||
void *MTLContext::debug_capture_scope_create(const char *name)
|
||||
{
|
||||
/* Create a capture scope visible to xCode Metal Frame capture utility. */
|
||||
MTLCaptureManager *capture_manager = [MTLCaptureManager sharedCaptureManager];
|
||||
if (!capture_manager) {
|
||||
/* Early exit if frame capture is disabled. */
|
||||
return nullptr;
|
||||
}
|
||||
id<MTLCaptureScope> capture_scope = [capture_manager newCaptureScopeWithDevice:this->device];
|
||||
capture_scope.label = [NSString stringWithUTF8String:name];
|
||||
[capture_scope retain];
|
||||
|
||||
return reinterpret_cast<void *>(capture_scope);
|
||||
}
|
||||
|
||||
bool MTLContext::debug_capture_scope_begin(void *scope)
|
||||
{
|
||||
/* Declare opening boundary of scope.
|
||||
* When scope is selected for capture, GPU commands between begin/end scope will be captured. */
|
||||
[(id<MTLCaptureScope>)scope beginScope];
|
||||
|
||||
MTLCaptureManager *capture_manager = [MTLCaptureManager sharedCaptureManager];
|
||||
return [capture_manager isCapturing];
|
||||
}
|
||||
|
||||
void MTLContext::debug_capture_scope_end(void *scope)
|
||||
{
|
||||
[(id<MTLCaptureScope>)scope endScope];
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
} // namespace blender::gpu
|
||||
|
@ -134,6 +134,11 @@ class GLContext : public Context {
|
||||
|
||||
void debug_group_begin(const char *name, int index) override;
|
||||
void debug_group_end() override;
|
||||
bool debug_capture_begin() override;
|
||||
void debug_capture_end() override;
|
||||
void *debug_capture_scope_create(const char *name) override;
|
||||
bool debug_capture_scope_begin(void *scope) override;
|
||||
void debug_capture_scope_end(void *scope) override;
|
||||
|
||||
private:
|
||||
static void orphans_add(Vector<GLuint> &orphan_list, std::mutex &list_mutex, GLuint id);
|
||||
|
@ -380,6 +380,29 @@ void GLContext::debug_group_end()
|
||||
}
|
||||
}
|
||||
|
||||
bool GLContext::debug_capture_begin()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void GLContext::debug_capture_end()
|
||||
{
|
||||
}
|
||||
|
||||
void *GLContext::debug_capture_scope_create(const char *name)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool GLContext::debug_capture_scope_begin(void *scope)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void GLContext::debug_capture_scope_end(void *scope)
|
||||
{
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
} // namespace blender::gpu
|
||||
|
@ -128,4 +128,27 @@ void VKContext::debug_group_end()
|
||||
{
|
||||
}
|
||||
|
||||
bool VKContext::debug_capture_begin()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void VKContext::debug_capture_end()
|
||||
{
|
||||
}
|
||||
|
||||
void *VKContext::debug_capture_scope_create(const char *name)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool VKContext::debug_capture_scope_begin(void *scope)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void VKContext::debug_capture_scope_end(void *scope)
|
||||
{
|
||||
}
|
||||
|
||||
} // namespace blender::gpu
|
||||
|
@ -49,6 +49,11 @@ class VKContext : public Context {
|
||||
|
||||
void debug_group_begin(const char *, int) override;
|
||||
void debug_group_end() override;
|
||||
bool debug_capture_begin() override;
|
||||
void debug_capture_end() override;
|
||||
void *debug_capture_scope_create(const char *name) override;
|
||||
bool debug_capture_scope_begin(void *scope) override;
|
||||
void debug_capture_scope_end(void *scope) override;
|
||||
|
||||
static VKContext *get(void)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user