mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2026-06-09 23:08:18 +02:00
mesa/main: Auto-generate MESA_VERBOSE=api trace dispatch
With the trace plumbing in place, fill in the wrappers from gl_and_es_API.xml so the trace tracks new entrypoints. Generated-by: Claude Signed-off-by: Christian Gmeiner <cgmeiner@igalia.com> Reviewed-by: Marek Olšák <maraeo@gmail.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/41147>
This commit is contained in:
parent
d128c6f111
commit
9f7f5a27a7
7 changed files with 374 additions and 0 deletions
226
src/mesa/glapi/glapi/gen/api_trace_c.py
Normal file
226
src/mesa/glapi/glapi/gen/api_trace_c.py
Normal file
|
|
@ -0,0 +1,226 @@
|
|||
# Copyright © 2026 Igalia S.L.
|
||||
# SPDX-License-Identifier: MIT
|
||||
#
|
||||
# Generates api_trace.c: per-entrypoint wrappers that log GL calls to stderr
|
||||
# and forward to the real dispatch. Installed at context create when
|
||||
# MESA_VERBOSE=api is set.
|
||||
|
||||
import apiexec
|
||||
import gl_XML
|
||||
import license
|
||||
|
||||
|
||||
TRACE_ARRAY_BUFSZ = 512
|
||||
|
||||
|
||||
header = """
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "glapi/glapi/glapi.h"
|
||||
#include "main/api_trace_helpers.h"
|
||||
#include "main/context.h"
|
||||
#include "main/enums.h"
|
||||
#include "main/errors.h"
|
||||
#include "dispatch.h"
|
||||
"""
|
||||
|
||||
|
||||
TYPE_FORMAT = {
|
||||
'GLenum': ('%s', '_mesa_enum_to_string({p})'),
|
||||
'GLboolean': ('%s', '{p} ? "GL_TRUE" : "GL_FALSE"'),
|
||||
'GLbitfield': ('0x%x', '{p}'),
|
||||
'GLbyte': ('%d', '{p}'),
|
||||
'GLubyte': ('%u', '{p}'),
|
||||
'GLshort': ('%d', '{p}'),
|
||||
'GLushort': ('%u', '{p}'),
|
||||
'GLint': ('%d', '{p}'),
|
||||
'GLuint': ('%u', '{p}'),
|
||||
'GLint64': ('%" PRId64 "', '(int64_t){p}'),
|
||||
'GLuint64': ('%" PRIu64 "', '(uint64_t){p}'),
|
||||
'GLsizei': ('%d', '{p}'),
|
||||
'GLintptr': ('%" PRIdPTR "','(intptr_t){p}'),
|
||||
'GLsizeiptr': ('%" PRIdPTR "','(intptr_t){p}'),
|
||||
'GLfloat': ('%f', '{p}'),
|
||||
'GLclampf': ('%f', '{p}'),
|
||||
'GLdouble': ('%f', '{p}'),
|
||||
'GLclampd': ('%f', '{p}'),
|
||||
'GLfixed': ('%d', '{p}'),
|
||||
'GLclampx': ('%d', '{p}'),
|
||||
'GLhalfNV': ('0x%x', '{p}'),
|
||||
'GLvdpauSurfaceNV': ('%" PRIdPTR "', '(intptr_t){p}'),
|
||||
'GLsync': ('%p', '(void *){p}'),
|
||||
'GLhandleARB': ('%u', '{p}'),
|
||||
'GLDEBUGPROC': ('%p', '(void *){p}'),
|
||||
'GLDEBUGPROCARB': ('%p', '(void *){p}'),
|
||||
'GLDEBUGPROCAMD': ('%p', '(void *){p}'),
|
||||
'GLDEBUGPROCKHR': ('%p', '(void *){p}'),
|
||||
'GLVULKANPROCNV': ('%p', '(void *){p}'),
|
||||
}
|
||||
|
||||
TYPE_ALIASES = {
|
||||
'GLint64EXT': 'GLint64',
|
||||
'GLuint64EXT': 'GLuint64',
|
||||
'GLintptrARB': 'GLintptr',
|
||||
'GLsizeiptrARB': 'GLsizeiptr',
|
||||
'float': 'GLfloat',
|
||||
'int': 'GLint',
|
||||
}
|
||||
|
||||
|
||||
# Element types not listed here fall back to ``%p`` at the call site.
|
||||
ARRAY_ELEM_KIND = {
|
||||
'GLfloat': 'MESA_TRACE_ELEM_FLOAT',
|
||||
'GLclampf': 'MESA_TRACE_ELEM_FLOAT',
|
||||
'GLdouble': 'MESA_TRACE_ELEM_DOUBLE',
|
||||
'GLclampd': 'MESA_TRACE_ELEM_DOUBLE',
|
||||
'GLbyte': 'MESA_TRACE_ELEM_BYTE',
|
||||
'GLshort': 'MESA_TRACE_ELEM_SHORT',
|
||||
'GLint': 'MESA_TRACE_ELEM_INT',
|
||||
'GLsizei': 'MESA_TRACE_ELEM_INT',
|
||||
'GLfixed': 'MESA_TRACE_ELEM_INT',
|
||||
'GLclampx': 'MESA_TRACE_ELEM_INT',
|
||||
'GLubyte': 'MESA_TRACE_ELEM_UBYTE',
|
||||
'GLushort': 'MESA_TRACE_ELEM_USHORT',
|
||||
'GLuint': 'MESA_TRACE_ELEM_UINT',
|
||||
'GLhalfNV': 'MESA_TRACE_ELEM_HALF',
|
||||
'GLint64': 'MESA_TRACE_ELEM_INT64',
|
||||
'GLuint64': 'MESA_TRACE_ELEM_UINT64',
|
||||
'GLintptr': 'MESA_TRACE_ELEM_INTPTR',
|
||||
'GLsizeiptr': 'MESA_TRACE_ELEM_INTPTR',
|
||||
}
|
||||
|
||||
|
||||
def array_count_expr(p):
|
||||
if p.counter:
|
||||
scale = p.count_scale if p.count_scale else 1
|
||||
if scale == 1:
|
||||
return '(size_t){0}'.format(p.counter)
|
||||
return '(size_t){0} * {1}'.format(p.counter, scale)
|
||||
if p.count and p.count >= 2:
|
||||
return str(p.count)
|
||||
return None
|
||||
|
||||
|
||||
def classify_param(p):
|
||||
"""Return one of:
|
||||
('scalar', spec, expr) - printed inline
|
||||
('array', kind, count_expr, name)
|
||||
('opaque', spec, expr) - printed as %p / hex fallback
|
||||
"""
|
||||
opaque = ('opaque', '%p', '(void *){0}'.format(p.name))
|
||||
|
||||
if not p.is_pointer():
|
||||
ts = TYPE_ALIASES.get(p.type_string().strip(), p.type_string().strip())
|
||||
if ts in TYPE_FORMAT:
|
||||
spec, expr = TYPE_FORMAT[ts]
|
||||
return ('scalar', spec, expr.format(p=p.name))
|
||||
return ('scalar', '0x%x', p.name)
|
||||
|
||||
base = p.get_base_type_string()
|
||||
|
||||
if base in ('GLchar', 'GLcharARB'):
|
||||
ts = p.type_string().lstrip()
|
||||
if ts.startswith('const'):
|
||||
return ('scalar', '%s',
|
||||
'{p} ? (const char *){p} : "(null)"'.format(p=p.name))
|
||||
return opaque
|
||||
|
||||
if p.is_output:
|
||||
return opaque
|
||||
|
||||
elem = TYPE_ALIASES.get(base, base)
|
||||
count_expr = array_count_expr(p)
|
||||
if elem in ARRAY_ELEM_KIND and count_expr is not None:
|
||||
return ('array', ARRAY_ELEM_KIND[elem], count_expr, p.name)
|
||||
|
||||
return opaque
|
||||
|
||||
|
||||
class PrintCode(gl_XML.gl_print_base):
|
||||
def __init__(self):
|
||||
super(PrintCode, self).__init__()
|
||||
self.name = 'api_trace_c.py'
|
||||
self.license = license.bsd_license_template % (
|
||||
'Copyright (C) 2026 Christian Gmeiner', 'Christian Gmeiner')
|
||||
|
||||
def printRealHeader(self):
|
||||
print(header)
|
||||
|
||||
def printRealFooter(self):
|
||||
pass
|
||||
|
||||
def print_wrapper(self, f):
|
||||
params = [p for p in f.parameters if not p.is_padding]
|
||||
classified = [classify_param(p) for p in params]
|
||||
|
||||
specs = []
|
||||
args = []
|
||||
prelude = []
|
||||
for p, c in zip(params, classified):
|
||||
if c[0] == 'array':
|
||||
_, kind, count_expr, name = c
|
||||
buf_name = '{0}_buf'.format(name)
|
||||
prelude.append('char {buf}[{sz}];'
|
||||
.format(buf=buf_name, sz=TRACE_ARRAY_BUFSZ))
|
||||
prelude.append(
|
||||
'_mesa_trace_format_array({buf}, sizeof({buf}),'
|
||||
' {name}, {count}, {kind});'
|
||||
.format(buf=buf_name, name=name,
|
||||
count=count_expr, kind=kind))
|
||||
specs.append('%s')
|
||||
args.append(buf_name)
|
||||
else:
|
||||
_, spec, expr = c
|
||||
specs.append(spec)
|
||||
args.append(expr)
|
||||
|
||||
ret = f.return_type
|
||||
param_string = f.get_parameter_string()
|
||||
called = f.get_called_parameter_string()
|
||||
|
||||
print('static {rt} GLAPIENTRY'.format(rt=ret))
|
||||
print('_mesa_trace_{name}({ps})'.format(name=f.name, ps=param_string))
|
||||
print('{')
|
||||
print(' GET_CURRENT_CONTEXT(ctx);')
|
||||
for stmt in prelude:
|
||||
print(' {0}'.format(stmt))
|
||||
if args:
|
||||
fmt_body = 'gl{0}({1})\\n'.format(f.name, ', '.join(specs))
|
||||
print(' _mesa_debug(ctx, "{fmt}", {args});'
|
||||
.format(fmt=fmt_body, args=', '.join(args)))
|
||||
else:
|
||||
print(' _mesa_debug(ctx, "gl{0}()\\n");'.format(f.name))
|
||||
call = 'CALL_{name}(ctx->Dispatch.RealPublished, ({ca}));'.format(
|
||||
name=f.name, ca=called if called else '')
|
||||
if ret != 'void':
|
||||
print(' return {call}'.format(call=call))
|
||||
else:
|
||||
print(' {call}'.format(call=call))
|
||||
print('}')
|
||||
print('')
|
||||
|
||||
def print_install(self, functions):
|
||||
print('bool')
|
||||
print('_mesa_init_dispatch_trace(struct gl_context *ctx)')
|
||||
print('{')
|
||||
print(' struct _glapi_table *table = _mesa_alloc_dispatch_table(false);')
|
||||
print(' if (!table)')
|
||||
print(' return false;')
|
||||
print('')
|
||||
for f in functions:
|
||||
print(' SET_{name}(table, _mesa_trace_{name});'.format(name=f.name))
|
||||
print('')
|
||||
print(' ctx->Dispatch.Trace = table;')
|
||||
print(' return true;')
|
||||
print('}')
|
||||
|
||||
def printBody(self, api):
|
||||
functions = list(api.functionIterateByOffset())
|
||||
for f in functions:
|
||||
self.print_wrapper(f)
|
||||
self.print_install(functions)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
apiexec.print_glapi_file(PrintCode())
|
||||
|
|
@ -111,6 +111,15 @@ main_unmarshal_table_c = custom_target(
|
|||
capture : true,
|
||||
)
|
||||
|
||||
main_api_trace_c = custom_target(
|
||||
'api_trace.c',
|
||||
input : ['api_trace_c.py', 'gl_and_es_API.xml'],
|
||||
output : 'api_trace.c',
|
||||
command : [prog_python, '@INPUT0@', '-f', '@INPUT1@'],
|
||||
depend_files : glapi_xml_py_deps,
|
||||
capture : true,
|
||||
)
|
||||
|
||||
main_marshal_generated_c = []
|
||||
foreach x : ['0', '1', '2', '3', '4', '5', '6', '7']
|
||||
main_marshal_generated_c += custom_target(
|
||||
|
|
|
|||
101
src/mesa/main/api_trace_helpers.c
Normal file
101
src/mesa/main/api_trace_helpers.c
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
* Copyright © 2026 Igalia S.L.
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "util/glheader.h"
|
||||
|
||||
#include "main/api_trace_helpers.h"
|
||||
|
||||
void
|
||||
_mesa_trace_format_array(char *buf, size_t buflen,
|
||||
const void *arr, size_t n,
|
||||
enum mesa_trace_elem_kind kind)
|
||||
{
|
||||
static const size_t MAX_TRACE_ARRAY = 16;
|
||||
|
||||
if (!arr) {
|
||||
snprintf(buf, buflen, "(null)");
|
||||
return;
|
||||
}
|
||||
|
||||
size_t shown = (n < MAX_TRACE_ARRAY) ? n : MAX_TRACE_ARRAY;
|
||||
size_t pos = 0;
|
||||
int w;
|
||||
|
||||
w = snprintf(buf + pos, buflen - pos, "[");
|
||||
if (w < 0 || (size_t)w >= buflen - pos)
|
||||
return;
|
||||
pos += w;
|
||||
|
||||
for (size_t i = 0; i < shown; i++) {
|
||||
if (i > 0) {
|
||||
w = snprintf(buf + pos, buflen - pos, ", ");
|
||||
if (w < 0 || (size_t)w >= buflen - pos)
|
||||
return;
|
||||
pos += w;
|
||||
}
|
||||
|
||||
switch (kind) {
|
||||
case MESA_TRACE_ELEM_FLOAT:
|
||||
w = snprintf(buf + pos, buflen - pos, "%f",
|
||||
((const GLfloat *)arr)[i]);
|
||||
break;
|
||||
case MESA_TRACE_ELEM_DOUBLE:
|
||||
w = snprintf(buf + pos, buflen - pos, "%f",
|
||||
((const GLdouble *)arr)[i]);
|
||||
break;
|
||||
case MESA_TRACE_ELEM_BYTE:
|
||||
w = snprintf(buf + pos, buflen - pos, "%d",
|
||||
((const GLbyte *)arr)[i]);
|
||||
break;
|
||||
case MESA_TRACE_ELEM_SHORT:
|
||||
w = snprintf(buf + pos, buflen - pos, "%d",
|
||||
((const GLshort *)arr)[i]);
|
||||
break;
|
||||
case MESA_TRACE_ELEM_INT:
|
||||
w = snprintf(buf + pos, buflen - pos, "%d",
|
||||
((const GLint *)arr)[i]);
|
||||
break;
|
||||
case MESA_TRACE_ELEM_UBYTE:
|
||||
w = snprintf(buf + pos, buflen - pos, "%u",
|
||||
((const GLubyte *)arr)[i]);
|
||||
break;
|
||||
case MESA_TRACE_ELEM_USHORT:
|
||||
w = snprintf(buf + pos, buflen - pos, "%u",
|
||||
((const GLushort *)arr)[i]);
|
||||
break;
|
||||
case MESA_TRACE_ELEM_UINT:
|
||||
w = snprintf(buf + pos, buflen - pos, "%u",
|
||||
((const GLuint *)arr)[i]);
|
||||
break;
|
||||
case MESA_TRACE_ELEM_HALF:
|
||||
w = snprintf(buf + pos, buflen - pos, "0x%x",
|
||||
((const GLhalfNV *)arr)[i]);
|
||||
break;
|
||||
case MESA_TRACE_ELEM_INT64:
|
||||
w = snprintf(buf + pos, buflen - pos, "%" PRId64,
|
||||
(int64_t)((const GLint64 *)arr)[i]);
|
||||
break;
|
||||
case MESA_TRACE_ELEM_UINT64:
|
||||
w = snprintf(buf + pos, buflen - pos, "%" PRIu64,
|
||||
(uint64_t)((const GLuint64 *)arr)[i]);
|
||||
break;
|
||||
case MESA_TRACE_ELEM_INTPTR:
|
||||
w = snprintf(buf + pos, buflen - pos, "%" PRIdPTR,
|
||||
(intptr_t)((const GLintptr *)arr)[i]);
|
||||
break;
|
||||
}
|
||||
if (w < 0 || (size_t)w >= buflen - pos)
|
||||
return;
|
||||
pos += w;
|
||||
}
|
||||
|
||||
if (n > MAX_TRACE_ARRAY)
|
||||
snprintf(buf + pos, buflen - pos, ", ... %zu of %zu]", shown, n);
|
||||
else
|
||||
snprintf(buf + pos, buflen - pos, "]");
|
||||
}
|
||||
28
src/mesa/main/api_trace_helpers.h
Normal file
28
src/mesa/main/api_trace_helpers.h
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* Copyright © 2026 Igalia S.L.
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
enum mesa_trace_elem_kind {
|
||||
MESA_TRACE_ELEM_FLOAT,
|
||||
MESA_TRACE_ELEM_DOUBLE,
|
||||
MESA_TRACE_ELEM_BYTE,
|
||||
MESA_TRACE_ELEM_SHORT,
|
||||
MESA_TRACE_ELEM_INT,
|
||||
MESA_TRACE_ELEM_UBYTE,
|
||||
MESA_TRACE_ELEM_USHORT,
|
||||
MESA_TRACE_ELEM_UINT,
|
||||
MESA_TRACE_ELEM_HALF,
|
||||
MESA_TRACE_ELEM_INT64,
|
||||
MESA_TRACE_ELEM_UINT64,
|
||||
MESA_TRACE_ELEM_INTPTR,
|
||||
};
|
||||
|
||||
void
|
||||
_mesa_trace_format_array(char *buf, size_t buflen,
|
||||
const void *arr, size_t n,
|
||||
enum mesa_trace_elem_kind kind);
|
||||
|
|
@ -906,6 +906,10 @@ _mesa_initialize_dispatch_tables(struct gl_context *ctx)
|
|||
_mesa_init_dispatch_save_begin_end(ctx);
|
||||
}
|
||||
|
||||
if ((MESA_VERBOSE & VERBOSE_API) &&
|
||||
!_mesa_init_dispatch_trace(ctx))
|
||||
return false;
|
||||
|
||||
/* This binds the dispatch table to the context, but MakeCurrent will
|
||||
* bind it for the user. If glthread is enabled, it will override it.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -91,6 +91,9 @@ _mesa_alloc_dispatch_tables(gl_api api, struct gl_dispatch *d, bool glthread);
|
|||
extern bool
|
||||
_mesa_initialize_dispatch_tables(struct gl_context *ctx);
|
||||
|
||||
extern bool
|
||||
_mesa_init_dispatch_trace(struct gl_context *ctx);
|
||||
|
||||
extern void
|
||||
_mesa_set_dispatch(struct gl_context *ctx, struct _glapi_table *t);
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,8 @@ files_libmesa = files(
|
|||
'main/accum.h',
|
||||
'main/api_arrayelt.c',
|
||||
'main/api_arrayelt.h',
|
||||
'main/api_trace_helpers.c',
|
||||
'main/api_trace_helpers.h',
|
||||
'main/arbprogram.c',
|
||||
'main/arrayobj.c',
|
||||
'main/arrayobj.h',
|
||||
|
|
@ -417,6 +419,7 @@ files_libmesa += [
|
|||
mesa_lex,
|
||||
program_parse_tab,
|
||||
main_api_exec_c,
|
||||
main_api_trace_c,
|
||||
main_api_exec_decl_h,
|
||||
main_api_save_h,
|
||||
main_api_save_init_h,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue