mesa: detect inefficient buffer use and report through debug output

When a buffer is created with GL_STATIC_DRAW, its contents should not
be changed frequently.  But that's exactly what one application I'm
debugging does.  This patch adds code to try to detect inefficient
buffer use in a couple places.  The GL_ARB_debug_output mechanism is
used to report the issue.

NVIDIA's driver detects these sort of things too.

Other types of inefficient buffer use could also be detected in the
future.

Reviewed-by: José Fonseca <jfonseca@vmware.com>
This commit is contained in:
Brian Paul 2015-12-07 18:38:03 -07:00
parent 7d3df58125
commit ab0651ccfd
2 changed files with 59 additions and 0 deletions

View File

@ -50,6 +50,34 @@
/*#define BOUNDS_CHECK*/
/**
* We count the number of buffer modification calls to check for
* inefficient buffer use. This is the number of such calls before we
* issue a warning.
*/
#define BUFFER_WARNING_CALL_COUNT 4
/**
* Helper to warn of possible performance issues, such as frequently
* updating a buffer created with GL_STATIC_DRAW.
*/
static void
buffer_usage_warning(struct gl_context *ctx, const char *fmt, ...)
{
va_list args;
GLuint msg_id = 0;
va_start(args, fmt);
_mesa_gl_vdebug(ctx, &msg_id,
MESA_DEBUG_SOURCE_API,
MESA_DEBUG_TYPE_PERFORMANCE,
MESA_DEBUG_SEVERITY_MEDIUM,
fmt, args);
va_end(args);
}
/**
* Used as a placeholder for buffer objects between glGenBuffers() and
* glBindBuffer() so that glIsBuffer() can work correctly.
@ -1677,6 +1705,21 @@ _mesa_buffer_sub_data(struct gl_context *ctx, struct gl_buffer_object *bufObj,
if (size == 0)
return;
bufObj->NumSubDataCalls++;
if ((bufObj->Usage == GL_STATIC_DRAW ||
bufObj->Usage == GL_STATIC_COPY) &&
bufObj->NumSubDataCalls >= BUFFER_WARNING_CALL_COUNT) {
/* If the application declared the buffer as static draw/copy or stream
* draw, it should not be frequently modified with glBufferSubData.
*/
buffer_usage_warning(ctx,
"using %s(buffer %u, offset %u, size %u) to "
"update a %s buffer",
func, bufObj->Name, offset, size,
_mesa_enum_to_string(bufObj->Usage));
}
bufObj->Written = GL_TRUE;
assert(ctx->Driver.BufferSubData);
@ -2384,6 +2427,18 @@ _mesa_map_buffer_range(struct gl_context *ctx,
return NULL;
}
if (access & GL_MAP_WRITE_BIT) {
bufObj->NumMapBufferWriteCalls++;
if ((bufObj->Usage == GL_STATIC_DRAW ||
bufObj->Usage == GL_STATIC_COPY) &&
bufObj->NumMapBufferWriteCalls >= BUFFER_WARNING_CALL_COUNT) {
buffer_usage_warning(ctx,
"using %s(buffer %u, offset %u, length %u) to "
"update a %s buffer",
func, bufObj->Name, offset, length,
_mesa_enum_to_string(bufObj->Usage));
}
}
assert(ctx->Driver.MapBufferRange);
map = ctx->Driver.MapBufferRange(ctx, offset, length, access, bufObj,

View File

@ -1275,6 +1275,10 @@ struct gl_buffer_object
GLboolean Immutable; /**< GL_ARB_buffer_storage */
gl_buffer_usage UsageHistory; /**< How has this buffer been used so far? */
/** Counters used for buffer usage warnings */
GLuint NumSubDataCalls;
GLuint NumMapBufferWriteCalls;
struct gl_buffer_mapping Mappings[MAP_COUNT];
};