forked from blender/blender
main sync #3
@ -5,6 +5,40 @@
|
|||||||
* \ingroup gpu
|
* \ingroup gpu
|
||||||
*
|
*
|
||||||
* Helpers for GPU / drawing debugging.
|
* 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
|
#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);
|
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
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -47,6 +47,7 @@ class Context {
|
|||||||
FrameBuffer *front_right = nullptr;
|
FrameBuffer *front_right = nullptr;
|
||||||
|
|
||||||
DebugStack debug_stack;
|
DebugStack debug_stack;
|
||||||
|
bool debug_is_capturing = false;
|
||||||
|
|
||||||
/* GPUContext counter used to assign a unique ID to each GPUContext.
|
/* 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
|
* 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_begin(const char *, int){};
|
||||||
virtual void debug_group_end(){};
|
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();
|
bool is_active_on_thread();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -73,3 +73,96 @@ bool GPU_debug_group_match(const char *ref)
|
|||||||
}
|
}
|
||||||
return false;
|
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_begin(const char *name, int index) override;
|
||||||
void debug_group_end() 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. */
|
/*** 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
|
} // namespace blender::gpu
|
||||||
|
@ -134,6 +134,11 @@ class GLContext : public Context {
|
|||||||
|
|
||||||
void debug_group_begin(const char *name, int index) override;
|
void debug_group_begin(const char *name, int index) override;
|
||||||
void debug_group_end() 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:
|
private:
|
||||||
static void orphans_add(Vector<GLuint> &orphan_list, std::mutex &list_mutex, GLuint id);
|
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
|
} // 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
|
} // namespace blender::gpu
|
||||||
|
@ -49,6 +49,11 @@ class VKContext : public Context {
|
|||||||
|
|
||||||
void debug_group_begin(const char *, int) override;
|
void debug_group_begin(const char *, int) override;
|
||||||
void debug_group_end() 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)
|
static VKContext *get(void)
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user