1########################################################################## 2# 3# Copyright 2008-2010 VMware, Inc. 4# All Rights Reserved. 5# 6# Permission is hereby granted, free of charge, to any person obtaining a copy 7# of this software and associated documentation files (the "Software"), to deal 8# in the Software without restriction, including without limitation the rights 9# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10# copies of the Software, and to permit persons to whom the Software is 11# furnished to do so, subject to the following conditions: 12# 13# The above copyright notice and this permission notice shall be included in 14# all copies or substantial portions of the Software. 15# 16# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22# THE SOFTWARE. 23# 24##########################################################################/ 25 26 27"""GL tracing generator.""" 28 29 30import re 31import sys 32 33from trace import Tracer 34from dispatch import function_pointer_type, function_pointer_value 35import specs.stdapi as stdapi 36import specs.glapi as glapi 37import specs.glparams as glparams 38from specs.glxapi import glxapi 39 40 41class TypeGetter(stdapi.Visitor): 42 '''Determine which glGet*v function that matches the specified type.''' 43 44 def __init__(self, prefix = 'glGet', long_suffix = True, ext_suffix = ''): 45 self.prefix = prefix 46 self.long_suffix = long_suffix 47 self.ext_suffix = ext_suffix 48 49 def visitConst(self, const): 50 return self.visit(const.type) 51 52 def visitAlias(self, alias): 53 if alias.expr == 'GLboolean': 54 if self.long_suffix: 55 suffix = 'Booleanv' 56 arg_type = alias.expr 57 else: 58 suffix = 'iv' 59 arg_type = 'GLint' 60 elif alias.expr == 'GLdouble': 61 if self.long_suffix: 62 suffix = 'Doublev' 63 arg_type = alias.expr 64 else: 65 suffix = 'dv' 66 arg_type = alias.expr 67 elif alias.expr == 'GLfloat': 68 if self.long_suffix: 69 suffix = 'Floatv' 70 arg_type = alias.expr 71 else: 72 suffix = 'fv' 73 arg_type = alias.expr 74 elif alias.expr in ('GLint', 'GLuint', 'GLsizei'): 75 if self.long_suffix: 76 suffix = 'Integerv' 77 arg_type = 'GLint' 78 else: 79 suffix = 'iv' 80 arg_type = 'GLint' 81 else: 82 print(alias.expr) 83 assert False 84 function_name = self.prefix + suffix + self.ext_suffix 85 return function_name, arg_type 86 87 def visitEnum(self, enum): 88 return self.visit(glapi.GLint) 89 90 def visitBitmask(self, bitmask): 91 return self.visit(glapi.GLint) 92 93 def visitOpaque(self, pointer): 94 return self.prefix + 'Pointerv' + self.ext_suffix, 'GLvoid *' 95 96 97class GlTracer(Tracer): 98 99 arrays = [ 100 ("Vertex", "VERTEX"), 101 ("Normal", "NORMAL"), 102 ("Color", "COLOR"), 103 ("Index", "INDEX"), 104 ("TexCoord", "TEXTURE_COORD"), 105 ("EdgeFlag", "EDGE_FLAG"), 106 ("FogCoord", "FOG_COORD"), 107 ("SecondaryColor", "SECONDARY_COLOR"), 108 ] 109 arrays.reverse() 110 111 # arrays available in ES1 112 arrays_es1 = ("Vertex", "Normal", "Color", "TexCoord") 113 114 buffer_targets = [ 115 "GL_ARRAY_BUFFER", 116 "GL_ATOMIC_COUNTER_BUFFER", 117 "GL_COPY_READ_BUFFER", 118 "GL_COPY_WRITE_BUFFER", 119 "GL_DRAW_INDIRECT_BUFFER", 120 "GL_DISPATCH_INDIRECT_BUFFER", 121 "GL_ELEMENT_ARRAY_BUFFER", 122 "GL_PIXEL_PACK_BUFFER", 123 "GL_PIXEL_UNPACK_BUFFER", 124 "GL_QUERY_BUFFER", 125 "GL_SHADER_STORAGE_BUFFER", 126 "GL_TEXTURE_BUFFER", 127 "GL_TRANSFORM_FEEDBACK_BUFFER", 128 "GL_UNIFORM_BUFFER", 129 ] 130 131 # Names of the functions that can pack into the current pixel buffer 132 # object. See also the ARB_pixel_buffer_object specification. 133 pack_function_regex = re.compile(r'^gl(' + r'|'.join([ 134 r'Getn?Histogram', 135 r'Getn?PolygonStipple', 136 r'Getn?PixelMap[a-z]+v', 137 r'Getn?Minmax', 138 r'Getn?(Convolution|Separable)Filter', 139 r'Getn?(Compressed)?(Multi)?Tex(ture)?(Sub)?Image', 140 r'Readn?Pixels', 141 ]) + r')[0-9A-Z]*$') 142 143 def header(self, api): 144 Tracer.header(self, api) 145 146 print('#include <algorithm>') 147 print('#include "cxx_compat.hpp"') 148 print() 149 print('#include "gltrace.hpp"') 150 print('#include "gltrace_arrays.hpp"') 151 print('#include "glmemshadow.hpp"') 152 print() 153 154 # Whether we need user arrays 155 print('static inline bool _need_user_arrays(gltrace::Context *_ctx)') 156 print('{') 157 print(' if (!_ctx->user_arrays) {') 158 print(' return false;') 159 print(' }') 160 print() 161 print(' glfeatures::Profile profile = _ctx->profile;') 162 print(' bool es1 = profile.es() && profile.major == 1;') 163 print() 164 165 for camelcase_name, uppercase_name in self.arrays: 166 # in which profile is the array available? 167 profile_check = 'profile.desktop()' 168 if camelcase_name in self.arrays_es1: 169 profile_check = '(' + profile_check + ' || es1)'; 170 171 function_name = 'gl%sPointer' % camelcase_name 172 enable_name = 'GL_%s_ARRAY' % uppercase_name 173 binding_name = 'GL_%s_ARRAY_BUFFER_BINDING' % uppercase_name 174 print(' // %s' % function_name) 175 print(' if (%s) {' % profile_check) 176 self.array_prolog(api, uppercase_name) 177 print(' if (_glIsEnabled(%s) &&' % enable_name) 178 print(' _glGetInteger(%s) == 0) {' % binding_name) 179 self.array_cleanup(api, uppercase_name) 180 print(' return true;') 181 print(' }') 182 self.array_epilog(api, uppercase_name) 183 print(' }') 184 print() 185 186 print(' // ES1 does not support generic vertex attributes') 187 print(' if (es1)') 188 print(' return false;') 189 print() 190 print(' // glVertexAttribPointer') 191 print(' GLint _max_vertex_attribs = _glGetInteger(GL_MAX_VERTEX_ATTRIBS);') 192 print(' for (GLint index = 0; index < _max_vertex_attribs; ++index) {') 193 print(' if (_glGetVertexAttribi(index, GL_VERTEX_ATTRIB_ARRAY_ENABLED) &&') 194 print(' _glGetVertexAttribi(index, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING) == 0) {') 195 print(' return true;') 196 print(' }') 197 print(' }') 198 print() 199 200 print(' return false;') 201 print('}') 202 print() 203 204 print(r'static void _trace_user_arrays(gltrace::Context *_ctx, GLuint count);') 205 print() 206 207 # Declare helper functions to emit fake function calls into the trace 208 for function in api.getAllFunctions(): 209 if function.name in self.fake_function_names: 210 print(function.prototype('_fake_' + function.name) + ';') 211 print() 212 print(r'static inline void') 213 print(r'_fakeStringMarker(const std::string &s) {') 214 print(r' _fake_glStringMarkerGREMEDY(s.length(), s.data());') 215 print(r'}') 216 print() 217 218 # Buffer mappings 219 print('// whether glMapBufferRange(GL_MAP_WRITE_BIT) has ever been called') 220 print('static bool _checkBufferMapRange = false;') 221 print() 222 print('// whether glBufferParameteriAPPLE(GL_BUFFER_FLUSHING_UNMAP_APPLE, GL_FALSE) has ever been called') 223 print('static bool _checkBufferFlushingUnmapAPPLE = false;') 224 print() 225 226 # Generate a helper function to determine whether a parameter name 227 # refers to a symbolic value or not 228 print('static bool') 229 print('is_symbolic_pname(GLenum pname) {') 230 print(' switch (pname) {') 231 for function, type, count, name in glparams.parameters: 232 if type is glapi.GLenum: 233 print(' case %s:' % name) 234 print(' return true;') 235 print(' default:') 236 print(' return false;') 237 print(' }') 238 print('}') 239 print() 240 241 # Generate a helper function to determine whether a parameter value is 242 # potentially symbolic or not; i.e., if the value can be represented in 243 # an enum or not 244 print('template<class T>') 245 print('static inline bool') 246 print('is_symbolic_param(T param) {') 247 print(' return static_cast<T>(static_cast<GLenum>(param)) == param;') 248 print('}') 249 print() 250 251 # Generate a helper function to know how many elements a parameter has 252 print('static size_t') 253 print('_gl_param_size(GLenum pname) {') 254 print(' switch (pname) {') 255 for function, type, count, name in glparams.parameters: 256 if name == 'GL_PROGRAM_BINARY_FORMATS': 257 count = 0 258 if type is not None: 259 print(' case %s: return %s;' % (name, count)) 260 print(' default:') 261 print(r' os::log("apitrace: warning: %s: unknown GLenum 0x%04X\n", __FUNCTION__, pname);') 262 print(' return 1;') 263 print(' }') 264 print('}') 265 print() 266 267 # Generate a helper function to get buffer binding 268 print('static GLenum') 269 print('getBufferBinding(GLenum target) {') 270 print(' switch (target) {') 271 for target in self.buffer_targets: 272 print(' case %s:' % target) 273 print(' return %s_BINDING;' % target) 274 print(' default:') 275 print(' assert(false);') 276 print(' return 0;') 277 print(' }') 278 print('}') 279 print() 280 281 print('static GLint') 282 print('getBufferName(GLenum target) {') 283 print(' GLint bufferName = 0;') 284 print(' _glGetIntegerv(getBufferBinding(target), &bufferName);') 285 print(' assert(bufferName != 0);') 286 print(' return bufferName;') 287 print('}') 288 print() 289 290 # states such as GL_UNPACK_ROW_LENGTH are not available in GLES 291 print('static inline bool') 292 print('can_unpack_subimage(void) {') 293 print(' gltrace::Context *_ctx = gltrace::getContext();') 294 print(' return _ctx->features.unpack_subimage;') 295 print('}') 296 print() 297 298 # VMWX_map_buffer_debug 299 print(r'extern "C" PUBLIC') 300 print(r'void APIENTRY') 301 print(r'glNotifyMappedBufferRangeVMWX(const void * start, GLsizeiptr length) {') 302 self.emit_memcpy('start', 'length') 303 print(r'}') 304 print() 305 306 getProcAddressFunctionNames = [] 307 308 def traceApi(self, api): 309 if self.getProcAddressFunctionNames: 310 # Generate a function to wrap proc addresses 311 getProcAddressFunction = api.getFunctionByName(self.getProcAddressFunctionNames[0]) 312 argType = getProcAddressFunction.args[0].type 313 retType = getProcAddressFunction.type 314 315 print('static %s _wrapProcAddress(%s procName, %s procPtr);' % (retType, argType, retType)) 316 print() 317 318 Tracer.traceApi(self, api) 319 320 print('static %s _wrapProcAddress(%s procName, %s procPtr) {' % (retType, argType, retType)) 321 322 # Provide fallback functions to missing debug functions 323 print(' if (!procPtr) {') 324 else_ = '' 325 for function_name in self.debug_functions: 326 if self.api.getFunctionByName(function_name): 327 print(' %sif (strcmp("%s", (const char *)procName) == 0) {' % (else_, function_name)) 328 print(' return (%s)&%s;' % (retType, function_name)) 329 print(' }') 330 else_ = 'else ' 331 print(' %s{' % else_) 332 print(' return NULL;') 333 print(' }') 334 print(' }') 335 336 for function in api.getAllFunctions(): 337 ptype = function_pointer_type(function) 338 pvalue = function_pointer_value(function) 339 print(' if (strcmp("%s", (const char *)procName) == 0) {' % function.name) 340 print(' assert(procPtr != (%s)&%s);' % (retType, function.name)) 341 print(' %s = (%s)procPtr;' % (pvalue, ptype)) 342 print(' return (%s)&%s;' % (retType, function.name,)) 343 print(' }') 344 print(' os::log("apitrace: warning: unknown function \\"%s\\"\\n", (const char *)procName);') 345 print(' return procPtr;') 346 print('}') 347 print() 348 else: 349 Tracer.traceApi(self, api) 350 351 array_pointer_function_names = set(( 352 "glVertexPointer", 353 "glNormalPointer", 354 "glColorPointer", 355 "glIndexPointer", 356 "glTexCoordPointer", 357 "glEdgeFlagPointer", 358 "glFogCoordPointer", 359 "glSecondaryColorPointer", 360 361 "glInterleavedArrays", 362 363 "glVertexPointerEXT", 364 "glNormalPointerEXT", 365 "glColorPointerEXT", 366 "glIndexPointerEXT", 367 "glTexCoordPointerEXT", 368 "glEdgeFlagPointerEXT", 369 "glFogCoordPointerEXT", 370 "glSecondaryColorPointerEXT", 371 372 "glVertexAttribPointer", 373 "glVertexAttribPointerARB", 374 "glVertexAttribPointerNV", 375 "glVertexAttribIPointer", 376 "glVertexAttribIPointerEXT", 377 "glVertexAttribLPointer", 378 "glVertexAttribLPointerEXT", 379 380 #"glMatrixIndexPointerARB", 381 )) 382 383 # XXX: We currently ignore the gl*Draw*ElementArray* functions 384 draw_function_regex = re.compile(r'^(?P<radical>gl([A-Z][a-z]+)*Draw(Range)?(Arrays|Elements))(?P<suffix>[A-Z][a-zA-Z]*)?$' ) 385 386 interleaved_formats = [ 387 'GL_V2F', 388 'GL_V3F', 389 'GL_C4UB_V2F', 390 'GL_C4UB_V3F', 391 'GL_C3F_V3F', 392 'GL_N3F_V3F', 393 'GL_C4F_N3F_V3F', 394 'GL_T2F_V3F', 395 'GL_T4F_V4F', 396 'GL_T2F_C4UB_V3F', 397 'GL_T2F_C3F_V3F', 398 'GL_T2F_N3F_V3F', 399 'GL_T2F_C4F_N3F_V3F', 400 'GL_T4F_C4F_N3F_V4F', 401 ] 402 403 def traceFunctionImplBody(self, function): 404 # Defer tracing of user array pointers... 405 if function.name in self.array_pointer_function_names: 406 print(' GLint _array_buffer = _glGetInteger(GL_ARRAY_BUFFER_BINDING);') 407 print(' if (!_array_buffer) {') 408 print(' static bool warned = false;') 409 print(' if (!warned) {') 410 print(' warned = true;') 411 print(' os::log("apitrace: warning: %s: call will be faked due to pointer to user memory (https://github.com/apitrace/apitrace/blob/master/docs/BUGS.markdown#tracing)\\n", __FUNCTION__);') 412 print(' }') 413 print(' gltrace::Context *_ctx = gltrace::getContext();') 414 print(' _ctx->user_arrays = true;') 415 if function.name == "glVertexAttribPointerNV": 416 print(r' os::log("apitrace: warning: %s: user memory arrays with NV_vertex_program longer supported\n", __FUNCTION__);') 417 self.invokeFunction(function) 418 419 # And also break down glInterleavedArrays into the individual calls 420 if function.name == 'glInterleavedArrays': 421 print() 422 423 # Initialize the enable flags 424 for camelcase_name, uppercase_name in self.arrays: 425 flag_name = '_' + uppercase_name.lower() 426 print(' GLboolean %s = GL_FALSE;' % flag_name) 427 print() 428 429 # Switch for the interleaved formats 430 print(' switch (format) {') 431 for format in self.interleaved_formats: 432 print(' case %s:' % format) 433 for camelcase_name, uppercase_name in self.arrays: 434 flag_name = '_' + uppercase_name.lower() 435 if format.find('_' + uppercase_name[0]) >= 0: 436 print(' %s = GL_TRUE;' % flag_name) 437 print(' break;') 438 print(' default:') 439 print(' return;') 440 print(' }') 441 print() 442 443 # Emit fake glEnableClientState/glDisableClientState flags 444 for camelcase_name, uppercase_name in self.arrays: 445 flag_name = '_' + uppercase_name.lower() 446 enable_name = 'GL_%s_ARRAY' % uppercase_name 447 448 # Emit a fake function 449 print(' if (%s) {' % flag_name) 450 print(' _fake_glEnableClientState(%s);' % enable_name) 451 print(' } else {') 452 print(' _fake_glDisableClientState(%s);' % enable_name) 453 print(' }') 454 455 # Warn about buggy glGet(GL_*ARRAY_SIZE) not returning GL_BGRA 456 buggyFunctions = { 457 'glColorPointer': ('glGetIntegerv', '', 'GL_COLOR_ARRAY_SIZE'), 458 'glSecondaryColorPointer': ('glGetIntegerv', '', 'GL_SECONDARY_COLOR_ARRAY_SIZE'), 459 'glVertexAttribPointer': ('glGetVertexAttribiv', 'index, ', 'GL_VERTEX_ATTRIB_ARRAY_SIZE'), 460 'glVertexAttribPointerARB': ('glGetVertexAttribivARB', 'index, ', 'GL_VERTEX_ATTRIB_ARRAY_SIZE_ARB'), 461 } 462 if function.name in buggyFunctions: 463 getter, extraArg, pname = buggyFunctions[function.name] 464 print(r' static bool _checked = false;') 465 print(r' if (!_checked && size == GL_BGRA) {') 466 print(r' GLint _size = 0;') 467 print(r' _%s(%s%s, &_size);' % (getter, extraArg, pname)) 468 print(r' if (_size != GL_BGRA) {') 469 print(r' os::log("apitrace: warning: %s(%s) does not return GL_BGRA; trace will be incorrect (https://github.com/apitrace/apitrace/issues/261)\n");' % (getter, pname)) 470 print(r' }') 471 print(r' _checked = true;') 472 print(r' }') 473 474 print(' return;') 475 print(' }') 476 477 # ... to the draw calls 478 mo = self.draw_function_regex.match(function.name) 479 if mo: 480 functionRadical = mo.group('radical') 481 print(' gltrace::Context *_ctx = gltrace::getContext();') 482 483 print(' GLMemoryShadow::commitAllWrites(_ctx, trace::fakeMemcpy);') 484 485 print(' if (_need_user_arrays(_ctx)) {') 486 if 'Indirect' in function.name: 487 print(r' os::log("apitrace: warning: %s: indirect user arrays not supported\n");' % (function.name,)) 488 else: 489 # Pick the corresponding *Params 490 if 'Arrays' in functionRadical: 491 paramsType = 'DrawArraysParams' 492 elif 'Elements' in functionRadical: 493 paramsType = 'DrawElementsParams' 494 else: 495 assert 0 496 if 'Multi' in functionRadical: 497 assert 'drawcount' in function.argNames() 498 paramsType = 'Multi' + paramsType 499 print(r' %s _params;' % paramsType) 500 501 for arg in function.args: 502 paramsMember = arg.name.lower() 503 if paramsMember in ('mode', 'modestride'): 504 continue 505 print(r' _params.%s = %s;' % (paramsMember, arg.name)) 506 507 print(' GLuint _count = _glDraw_count(_ctx, _params);') 508 print(' _trace_user_arrays(_ctx, _count);') 509 print(' }') 510 511 if function.name.startswith("glDispatchCompute"): 512 print(' gltrace::Context *_ctx = gltrace::getContext();') 513 print(' GLMemoryShadow::commitAllWrites(_ctx, trace::fakeMemcpy);') 514 515 if function.name == 'glLockArraysEXT': 516 print(' gltrace::Context *_ctx = gltrace::getContext();') 517 print(' if (_ctx) {') 518 print(' _ctx->lockedArrayCount = first + count;') 519 print(' }') 520 521 # Warn if user arrays are used with glBegin/glArrayElement/glEnd. 522 if function.name == 'glBegin': 523 print(r' gltrace::Context *_ctx = gltrace::getContext();') 524 print(r' _ctx->userArraysOnBegin = _need_user_arrays(_ctx);') 525 if function.name.startswith('glArrayElement'): 526 print(r' gltrace::Context *_ctx = gltrace::getContext();') 527 print(r' if (_ctx->userArraysOnBegin) {') 528 print(r' os::log("apitrace: warning: user arrays with glArrayElement not supported (https://github.com/apitrace/apitrace/issues/276)\n");') 529 print(r' _ctx->userArraysOnBegin = false;') 530 print(r' }') 531 532 # Emit a fake memcpy on buffer uploads 533 if function.name == 'glBufferParameteriAPPLE': 534 print(' if (pname == GL_BUFFER_FLUSHING_UNMAP_APPLE && param == GL_FALSE) {') 535 print(' _checkBufferFlushingUnmapAPPLE = true;') 536 print(' }') 537 if function.name in ('glUnmapBuffer', 'glUnmapBufferARB'): 538 if function.name.endswith('ARB'): 539 suffix = 'ARB' 540 else: 541 suffix = '' 542 print(' GLint access_flags = 0;') 543 print(' GLint access = 0;') 544 print(' bool flush;') 545 print(' // GLES3 does not have GL_BUFFER_ACCESS;') 546 print(' if (_checkBufferMapRange) {') 547 print(' _glGetBufferParameteriv%s(target, GL_BUFFER_ACCESS_FLAGS, &access_flags);' % suffix) 548 print(' flush = (access_flags & GL_MAP_WRITE_BIT) && !(access_flags & (GL_MAP_FLUSH_EXPLICIT_BIT | GL_MAP_PERSISTENT_BIT));') 549 print(' } else {') 550 print(' _glGetBufferParameteriv%s(target, GL_BUFFER_ACCESS, &access);' % suffix) 551 print(' flush = access != GL_READ_ONLY;') 552 print(' }') 553 print(' if ((access_flags & GL_MAP_COHERENT_BIT) && (access_flags & GL_MAP_WRITE_BIT)) {') 554 print(' gltrace::Context *_ctx = gltrace::getContext();') 555 print(' GLint buffer = getBufferName(target);') 556 print(' auto it = _ctx->bufferToShadowMemory.find(buffer);') 557 print(' if (it != _ctx->bufferToShadowMemory.end()) {') 558 print(' it->second->unmap(trace::fakeMemcpy);') 559 print(' } else {') 560 print(r' os::log("apitrace: error: %s: cannot find memory shadow\n", __FUNCTION__);') 561 print(' }') 562 print(' flush = false;') 563 print(' }') 564 print(' if (flush) {') 565 print(' GLvoid *map = NULL;') 566 print(' _glGetBufferPointerv%s(target, GL_BUFFER_MAP_POINTER, &map);' % suffix) 567 print(' if (map) {') 568 print(' GLint length = -1;') 569 print(' if (_checkBufferMapRange) {') 570 print(' _glGetBufferParameteriv%s(target, GL_BUFFER_MAP_LENGTH, &length);' % suffix) 571 print(' if (length == -1) {') 572 print(' // Mesa drivers refuse GL_BUFFER_MAP_LENGTH without GL 3.0 up-to') 573 print(' // http://cgit.freedesktop.org/mesa/mesa/commit/?id=ffee498fb848b253a7833373fe5430f8c7ca0c5f') 574 print(' static bool warned = false;') 575 print(' if (!warned) {') 576 print(' os::log("apitrace: warning: glGetBufferParameteriv%s(GL_BUFFER_MAP_LENGTH) failed\\n");' % suffix) 577 print(' warned = true;') 578 print(' }') 579 print(' }') 580 print(' } else {') 581 print(' length = 0;') 582 print(' _glGetBufferParameteriv%s(target, GL_BUFFER_SIZE, &length);' % suffix) 583 print(' }') 584 print(' if (_checkBufferFlushingUnmapAPPLE) {') 585 print(' GLint flushing_unmap = GL_TRUE;') 586 print(' _glGetBufferParameteriv%s(target, GL_BUFFER_FLUSHING_UNMAP_APPLE, &flushing_unmap);' % suffix) 587 print(' flush = flush && flushing_unmap;') 588 print(' }') 589 print(' if (flush && length > 0) {') 590 self.emit_memcpy('map', 'length') 591 print(' }') 592 print(' }') 593 print(' }') 594 if function.name == 'glUnmapBufferOES': 595 print(' GLint access_flags = 0;') 596 print(' GLint access = 0;') 597 print(' bool flush;') 598 print(' // GLES3 does not have GL_BUFFER_ACCESS;') 599 print(' if (_checkBufferMapRange) {') 600 print(' _glGetBufferParameteriv(target, GL_BUFFER_ACCESS_FLAGS, &access_flags);') 601 print(' flush = (access_flags & GL_MAP_WRITE_BIT) && !(access_flags & (GL_MAP_FLUSH_EXPLICIT_BIT | GL_MAP_PERSISTENT_BIT));') 602 print(' } else {') 603 print(' _glGetBufferParameteriv(target, GL_BUFFER_ACCESS, &access);') 604 print(' flush = access != GL_READ_ONLY;') 605 print(' }') 606 print(' if (flush) {') 607 print(' GLvoid *map = NULL;') 608 print(' _glGetBufferPointervOES(target, GL_BUFFER_MAP_POINTER, &map);') 609 print(' if (map) {') 610 print(' GLint length = 0;') 611 print(' GLint offset = 0;') 612 print(' if (_checkBufferMapRange) {') 613 print(' _glGetBufferParameteriv(target, GL_BUFFER_MAP_LENGTH, &length);') 614 print(' _glGetBufferParameteriv(target, GL_BUFFER_MAP_OFFSET, &offset);') 615 print(' } else {') 616 print(' _glGetBufferParameteriv(target, GL_BUFFER_SIZE, &length);') 617 print(' }') 618 print(' if (flush && length > 0) {') 619 self.emit_memcpy('map', 'length') 620 print(' }') 621 print(' }') 622 print(' }') 623 if function.name == 'glUnmapNamedBuffer': 624 print(' GLint access_flags = 0;') 625 print(' _glGetNamedBufferParameteriv(buffer, GL_BUFFER_ACCESS_FLAGS, &access_flags);') 626 print(' if ((access_flags & GL_MAP_COHERENT_BIT) && (access_flags & GL_MAP_WRITE_BIT)) {') 627 print(' gltrace::Context *_ctx = gltrace::getContext();') 628 print(' auto it = _ctx->bufferToShadowMemory.find(buffer);') 629 print(' if (it != _ctx->bufferToShadowMemory.end()) {') 630 print(' it->second->unmap(trace::fakeMemcpy);') 631 print(' } else {') 632 print(r' os::log("apitrace: error: %s: cannot find memory shadow\n", __FUNCTION__);') 633 print(' }') 634 print(' } else if ((access_flags & GL_MAP_WRITE_BIT) &&') 635 print(' !(access_flags & (GL_MAP_FLUSH_EXPLICIT_BIT | GL_MAP_PERSISTENT_BIT))) {') 636 print(' GLvoid *map = NULL;') 637 print(' _glGetNamedBufferPointerv(buffer, GL_BUFFER_MAP_POINTER, &map);') 638 print(' GLint length = 0;') 639 print(' _glGetNamedBufferParameteriv(buffer, GL_BUFFER_MAP_LENGTH, &length);') 640 print(' if (map && length > 0) {') 641 self.emit_memcpy('map', 'length') 642 print(' }') 643 print(' }') 644 if function.name == 'glUnmapNamedBufferEXT': 645 print(' GLint access_flags = 0;') 646 print(' _glGetNamedBufferParameterivEXT(buffer, GL_BUFFER_ACCESS_FLAGS, &access_flags);') 647 print(' if ((access_flags & GL_MAP_COHERENT_BIT) && (access_flags & GL_MAP_WRITE_BIT)) {') 648 print(' gltrace::Context *_ctx = gltrace::getContext();') 649 print(' auto it = _ctx->bufferToShadowMemory.find(buffer);') 650 print(' if (it != _ctx->bufferToShadowMemory.end()) {') 651 print(' it->second->unmap(trace::fakeMemcpy);') 652 print(' } else {') 653 print(r' os::log("apitrace: error: %s: cannot find memory shadow\n", __FUNCTION__);') 654 print(' }') 655 print(' } else if ((access_flags & GL_MAP_WRITE_BIT) &&') 656 print(' !(access_flags & (GL_MAP_FLUSH_EXPLICIT_BIT | GL_MAP_PERSISTENT_BIT))) {') 657 print(' GLvoid *map = NULL;') 658 print(' _glGetNamedBufferPointervEXT(buffer, GL_BUFFER_MAP_POINTER, &map);') 659 print(' GLint length = 0;') 660 print(' _glGetNamedBufferParameterivEXT(buffer, GL_BUFFER_MAP_LENGTH, &length);') 661 print(' if (map && length > 0) {') 662 self.emit_memcpy('map', 'length') 663 print(' }') 664 print(' }') 665 if function.name == 'glFlushMappedBufferRange': 666 print(' GLvoid *map = NULL;') 667 print(' _glGetBufferPointerv(target, GL_BUFFER_MAP_POINTER, &map);') 668 print(' if (map && length > 0) {') 669 self.emit_memcpy('(const char *)map + offset', 'length') 670 print(' }') 671 if function.name == 'glFlushMappedBufferRangeEXT': 672 print(' GLvoid *map = NULL;') 673 print(' _glGetBufferPointervOES(target, GL_BUFFER_MAP_POINTER_OES, &map);') 674 print(' if (map && length > 0) {') 675 self.emit_memcpy('(const char *)map + offset', 'length') 676 print(' }') 677 if function.name == 'glFlushMappedBufferRangeAPPLE': 678 print(' GLvoid *map = NULL;') 679 print(' _glGetBufferPointerv(target, GL_BUFFER_MAP_POINTER, &map);') 680 print(' if (map && size > 0) {') 681 self.emit_memcpy('(const char *)map + offset', 'size') 682 print(' }') 683 if function.name == 'glFlushMappedNamedBufferRange': 684 print(' GLvoid *map = NULL;') 685 print(' _glGetNamedBufferPointerv(buffer, GL_BUFFER_MAP_POINTER, &map);') 686 print(' if (map && length > 0) {') 687 self.emit_memcpy('(const char *)map + offset', 'length') 688 print(' }') 689 if function.name == 'glFlushMappedNamedBufferRangeEXT': 690 print(' GLvoid *map = NULL;') 691 print(' _glGetNamedBufferPointervEXT(buffer, GL_BUFFER_MAP_POINTER, &map);') 692 print(' if (map && length > 0) {') 693 self.emit_memcpy('(const char *)map + offset', 'length') 694 print(' }') 695 696 # FIXME: We don't support AMD_pinned_memory 697 if function.name in ('glBufferStorage', 'glNamedBufferStorage', 'glNamedBufferStorageEXT'): 698 print(r' if (flags & GL_MAP_NOTIFY_EXPLICIT_BIT_VMWX) {') 699 print(r' if (!(flags & GL_MAP_PERSISTENT_BIT)) {') 700 print(r' os::log("apitrace: warning: %s: MAP_NOTIFY_EXPLICIT_BIT_VMWX set w/o MAP_PERSISTENT_BIT\n", __FUNCTION__);') 701 print(r' }') 702 print(r' if (!(flags & GL_MAP_WRITE_BIT)) {') 703 print(r' os::log("apitrace: warning: %s: MAP_NOTIFY_EXPLICIT_BIT_VMWX set w/o MAP_WRITE_BIT\n", __FUNCTION__);') 704 print(r' }') 705 print(r' flags &= ~GL_MAP_NOTIFY_EXPLICIT_BIT_VMWX;') 706 print(r' }') 707 print(r'') 708 print(r' if ((flags & GL_MAP_COHERENT_BIT) && (flags & GL_MAP_WRITE_BIT)) {') 709 print(r' gltrace::Context *_ctx = gltrace::getContext();') 710 if function.name in ('glBufferStorage'): 711 print(r' GLint buffer = getBufferName(target);') 712 print(r' auto memoryShadow = std::make_unique<GLMemoryShadow>();') 713 print(r' const bool success = memoryShadow->init(data, size);') 714 print(r' if (success) {') 715 print(r' _ctx->bufferToShadowMemory.insert(std::make_pair(buffer, std::move(memoryShadow)));') 716 print(r' } else {') 717 print(r' os::log("apitrace: error: %s: cannot create memory shadow\n", __FUNCTION__);') 718 print(r' }') 719 print(r' }') 720 if function.name in ('glMapBufferRange', 'glMapBufferRangeEXT', 'glMapNamedBufferRange', 'glMapNamedBufferRangeEXT'): 721 print(r' if (access & GL_MAP_NOTIFY_EXPLICIT_BIT_VMWX) {') 722 print(r' if (!(access & GL_MAP_PERSISTENT_BIT)) {') 723 print(r' os::log("apitrace: warning: %s: MAP_NOTIFY_EXPLICIT_BIT_VMWX set w/o MAP_PERSISTENT_BIT\n", __FUNCTION__);') 724 print(r' }') 725 print(r' if (!(access & GL_MAP_WRITE_BIT)) {') 726 print(r' os::log("apitrace: warning: %s: MAP_NOTIFY_EXPLICIT_BIT_VMWX set w/o MAP_WRITE_BIT\n", __FUNCTION__);') 727 print(r' }') 728 print(r' if (access & GL_MAP_FLUSH_EXPLICIT_BIT) {') 729 print(r' os::log("apitrace: warning: %s: MAP_NOTIFY_EXPLICIT_BIT_VMWX set w/ MAP_FLUSH_EXPLICIT_BIT\n", __FUNCTION__);') 730 print(r' }') 731 print(r' access &= ~GL_MAP_NOTIFY_EXPLICIT_BIT_VMWX;') 732 print(r' }') 733 if function.name in ('glBufferData', 'glBufferDataARB'): 734 print(r' if (target == GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD) {') 735 print(r' os::log("apitrace: warning: GL_AMD_pinned_memory not fully supported\n");') 736 print(r' }') 737 738 # TODO: We don't track GL_INTEL_map_texture mappings 739 if function.name == 'glMapTexture2DINTEL': 740 print(r' if (access & GL_MAP_WRITE_BIT) {') 741 print(r' os::log("apitrace: warning: GL_INTEL_map_texture not fully supported\n");') 742 print(r' }') 743 744 # Operations on PBO may use coherent buffers so we must commit them first 745 if self.unpack_function_regex.match(function.name) or self.pack_function_regex.match(function.name): 746 print(' gltrace::Context *_ctx = gltrace::getContext();') 747 print(' GLMemoryShadow::commitAllWrites(_ctx, trace::fakeMemcpy);') 748 print('') 749 750 # Don't leave vertex attrib locations to chance. Instead emit fake 751 # glBindAttribLocation calls to ensure that the same locations will be 752 # used when retracing. Trying to remap locations after the fact would 753 # be an herculian task given that vertex attrib locations appear in 754 # many entry-points, including non-shader related ones. 755 if function.name == 'glLinkProgram': 756 Tracer.invokeFunction(self, function) 757 print(' GLint active_attributes = 0;') 758 print(' _glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &active_attributes);') 759 print(' for (GLint attrib = 0; attrib < active_attributes; ++attrib) {') 760 print(' GLint size = 0;') 761 print(' GLenum type = 0;') 762 print(' GLchar name[256];') 763 # TODO: Use ACTIVE_ATTRIBUTE_MAX_LENGTH instead of 256 764 print(' _glGetActiveAttrib(program, attrib, sizeof name, NULL, &size, &type, name);') 765 print(" if (name[0] != 'g' || name[1] != 'l' || name[2] != '_') {") 766 print(' GLint location = _glGetAttribLocation(program, name);') 767 print(' if (location >= 0) {') 768 print(' _fake_glBindAttribLocation(program, location, name);') 769 print(' }') 770 print(' }') 771 print(' }') 772 if function.name == 'glLinkProgramARB': 773 Tracer.invokeFunction(self, function) 774 print(' GLint active_attributes = 0;') 775 print(' _glGetObjectParameterivARB(programObj, GL_OBJECT_ACTIVE_ATTRIBUTES_ARB, &active_attributes);') 776 print(' for (GLint attrib = 0; attrib < active_attributes; ++attrib) {') 777 print(' GLint size = 0;') 778 print(' GLenum type = 0;') 779 print(' GLcharARB name[256];') 780 # TODO: Use ACTIVE_ATTRIBUTE_MAX_LENGTH instead of 256 781 print(' _glGetActiveAttribARB(programObj, attrib, sizeof name, NULL, &size, &type, name);') 782 print(" if (name[0] != 'g' || name[1] != 'l' || name[2] != '_') {") 783 print(' GLint location = _glGetAttribLocationARB(programObj, name);') 784 print(' if (location >= 0) {') 785 print(' _fake_glBindAttribLocationARB(programObj, location, name);') 786 print(' }') 787 print(' }') 788 print(' }') 789 790 Tracer.traceFunctionImplBody(self, function) 791 792 # These entrypoints are only expected to be implemented by tools; 793 # drivers will probably not implement them. 794 marker_functions = [ 795 # GL_GREMEDY_string_marker 796 'glStringMarkerGREMEDY', 797 # GL_GREMEDY_frame_terminator 798 'glFrameTerminatorGREMEDY', 799 ] 800 801 # These entrypoints may be implemented by drivers, but are also very useful 802 # for debugging / analysis tools. 803 debug_functions = [ 804 # GL_KHR_debug 805 'glDebugMessageControl', 806 'glDebugMessageInsert', 807 'glDebugMessageCallback', 808 'glGetDebugMessageLog', 809 'glPushDebugGroup', 810 'glPopDebugGroup', 811 'glObjectLabel', 812 'glGetObjectLabel', 813 'glObjectPtrLabel', 814 'glGetObjectPtrLabel', 815 # GL_KHR_debug (for OpenGL ES) 816 'glDebugMessageControlKHR', 817 'glDebugMessageInsertKHR', 818 'glDebugMessageCallbackKHR', 819 'glGetDebugMessageLogKHR', 820 'glPushDebugGroupKHR', 821 'glPopDebugGroupKHR', 822 'glObjectLabelKHR', 823 'glGetObjectLabelKHR', 824 'glObjectPtrLabelKHR', 825 'glGetObjectPtrLabelKHR', 826 # GL_ARB_debug_output 827 'glDebugMessageControlARB', 828 'glDebugMessageInsertARB', 829 'glDebugMessageCallbackARB', 830 'glGetDebugMessageLogARB', 831 # GL_AMD_debug_output 832 'glDebugMessageEnableAMD', 833 'glDebugMessageInsertAMD', 834 'glDebugMessageCallbackAMD', 835 'glGetDebugMessageLogAMD', 836 # GL_EXT_debug_label 837 'glLabelObjectEXT', 838 'glGetObjectLabelEXT', 839 # GL_EXT_debug_marker 840 'glInsertEventMarkerEXT', 841 'glPushGroupMarkerEXT', 842 'glPopGroupMarkerEXT', 843 ] 844 845 def invokeFunction(self, function): 846 if function.name in ('glLinkProgram', 'glLinkProgramARB'): 847 # These functions have been dispatched already 848 return 849 850 # Force glProgramBinary to fail. Per ARB_get_program_binary this 851 # should signal the app that it needs to recompile. 852 if function.name in ('glProgramBinary', 'glProgramBinaryOES'): 853 print(r' binaryFormat = 0xDEADDEAD;') 854 print(r' binary = &binaryFormat;') 855 print(r' length = sizeof binaryFormat;') 856 857 Tracer.invokeFunction(self, function) 858 859 def doInvokeFunction(self, function): 860 # Same as invokeFunction() but called both when trace is enabled or disabled. 861 # 862 # Used to modify the behavior of GL entry-points. 863 864 # Override GL extensions 865 if function.name in ('glGetString', 'glGetIntegerv', 'glGetStringi'): 866 Tracer.doInvokeFunction(self, function, prefix = 'gltrace::_', suffix = '_override') 867 return 868 869 # We implement GL_GREMEDY_*, etc., and not the driver 870 if function.name in self.marker_functions: 871 return 872 873 # We may be faking KHR_debug, so ensure the pointer queries result is 874 # always zeroed to prevent dereference of unitialized pointers 875 if function.name == 'glGetPointerv': 876 print(' if (params &&') 877 print(' (pname == GL_DEBUG_CALLBACK_FUNCTION ||') 878 print(' pname == GL_DEBUG_CALLBACK_USER_PARAM)) {') 879 print(' *params = NULL;') 880 print(' }') 881 882 if function.name in self.getProcAddressFunctionNames: 883 nameArg = function.args[0].name 884 print(' if (strcmp("glNotifyMappedBufferRangeVMWX", (const char *)%s) == 0) {' % (nameArg,)) 885 print(' _result = (%s)&glNotifyMappedBufferRangeVMWX;' % (function.type,)) 886 for marker_function in self.marker_functions: 887 if self.api.getFunctionByName(marker_function): 888 print(' } else if (strcmp("%s", (const char *)%s) == 0) {' % (marker_function, nameArg)) 889 print(' _result = (%s)&%s;' % (function.type, marker_function)) 890 print(' } else {') 891 Tracer.doInvokeFunction(self, function) 892 893 # Replace function addresses with ours 894 # XXX: Doing this here instead of wrapRet means that the trace will 895 # contain the addresses of the wrapper functions, and not the real 896 # functions, but in practice this should make no difference. 897 if function.name in self.getProcAddressFunctionNames: 898 print(' _result = _wrapProcAddress(%s, _result);' % (nameArg,)) 899 900 print(' }') 901 return 902 903 if function.name in ('glGetProgramBinary', 'glGetProgramBinaryOES'): 904 print(r' bufSize = 0;') 905 906 Tracer.doInvokeFunction(self, function) 907 908 if function.name in ('glMapBufferRange', 'glMapBufferRangeEXT', 'glMapNamedBufferRange', 'glMapNamedBufferRangeEXT'): 909 print(r' if ((access & GL_MAP_COHERENT_BIT) && (access & GL_MAP_WRITE_BIT)) {') 910 print(r' gltrace::Context *_ctx = gltrace::getContext();') 911 if function.name in ('glMapBufferRange', 'glMapBufferRangeEXT'): 912 print(r' GLint buffer = getBufferName(target);') 913 print(r' auto it = _ctx->bufferToShadowMemory.find(buffer);') 914 print(r' if (it != _ctx->bufferToShadowMemory.end()) {') 915 print(r' _result = it->second->map(_ctx, _result, access, offset, length);') 916 print(r' } else {') 917 print(r' os::log("apitrace: error: %s: cannot find memory shadow\n", __FUNCTION__);') 918 print(r' }') 919 print(r' }') 920 921 # We should sync back readable coherent buffers only when a fence become signaled 922 # because in any other moment application cannot know if changes from operations on 923 # GPU are done and buffers are updated. 924 if function.name == 'glWaitSync': 925 print(r' gltrace::Context *_ctx = gltrace::getContext();') 926 print(r' GLMemoryShadow::syncAllForReads(_ctx);') 927 928 if function.name == 'glClientWaitSync': 929 print(r' if (_result == GL_ALREADY_SIGNALED || _result == GL_CONDITION_SATISFIED) {') 930 print(r' gltrace::Context *_ctx = gltrace::getContext();') 931 print(r' GLMemoryShadow::syncAllForReads(_ctx);') 932 print(r' }') 933 934 if function.name == 'glGetSynciv': 935 print(r' if (pname == GL_SYNC_STATUS && bufSize > 0 && values[0] == GL_SIGNALED) {') 936 print(r' gltrace::Context *_ctx = gltrace::getContext();') 937 print(r' GLMemoryShadow::syncAllForReads(_ctx);') 938 print(r' }') 939 940 if function.name == 'glGetProgramiv': 941 print(r' if (params && pname == GL_PROGRAM_BINARY_LENGTH) {') 942 print(r' *params = 0;') 943 print(r' }') 944 if function.name in ('glGetProgramBinary', 'glGetProgramBinaryOES'): 945 print(r' if (length) {') 946 print(r' *length = 0;') 947 print(r' }') 948 949 def wrapRet(self, function, instance): 950 Tracer.wrapRet(self, function, instance) 951 952 # Keep track of buffer mappings 953 if function.name in ('glMapBufferRange', 'glMapBufferRangeEXT'): 954 print(' if (access & GL_MAP_WRITE_BIT) {') 955 print(' _checkBufferMapRange = true;') 956 print(' }') 957 958 boolean_names = [ 959 'GL_FALSE', 960 'GL_TRUE', 961 ] 962 963 def gl_boolean(self, value): 964 return self.boolean_names[int(bool(value))] 965 966 # Regular expression for the names of the functions that unpack from a 967 # pixel buffer object. See the ARB_pixel_buffer_object specification. 968 unpack_function_regex = re.compile(r'^gl(' + r'|'.join([ 969 r'Bitmap', 970 r'PolygonStipple', 971 r'PixelMap[a-z]+v', 972 r'DrawPixels', 973 r'Color(Sub)?Table', 974 r'(Convolution|Separable)Filter[12]D', 975 r'(Compressed)?(Multi)?Tex(ture)?(Sub)?Image[1-4]D', 976 ]) + r')[0-9A-Z]*$') 977 978 def serializeArgValue(self, function, arg): 979 # Recognize offsets instead of blobs when a PBO is bound 980 if self.unpack_function_regex.match(function.name) \ 981 and (isinstance(arg.type, stdapi.Blob) \ 982 or (isinstance(arg.type, stdapi.Const) \ 983 and isinstance(arg.type.type, stdapi.Blob))): 984 print(' {') 985 print(' gltrace::Context *_ctx = gltrace::getContext();') 986 print(' GLint _unpack_buffer = 0;') 987 print(' if (_ctx->features.pixel_buffer_object)') 988 print(' _glGetIntegerv(GL_PIXEL_UNPACK_BUFFER_BINDING, &_unpack_buffer);') 989 print(' if (_unpack_buffer) {') 990 print(' trace::localWriter.writePointer((uintptr_t)%s);' % arg.name) 991 print(' } else {') 992 Tracer.serializeArgValue(self, function, arg) 993 print(' }') 994 print(' }') 995 return 996 997 # Recognize offsets instead of pointers when query buffer is bound 998 if function.name.startswith('glGetQueryObject') and arg.output: 999 print(r' gltrace::Context *_ctx = gltrace::getContext();') 1000 print(r' GLint _query_buffer = 0;') 1001 print(r' if (_ctx->features.query_buffer_object) {') 1002 print(r' _query_buffer = _glGetInteger(GL_QUERY_BUFFER_BINDING);') 1003 print(r' }') 1004 print(r' if (_query_buffer) {') 1005 print(r' trace::localWriter.writePointer((uintptr_t)%s);' % arg.name) 1006 print(r' } else {') 1007 Tracer.serializeArgValue(self, function, arg) 1008 print(r' }') 1009 return 1010 1011 # Several GL state functions take GLenum symbolic names as 1012 # integer/floats; so dump the symbolic name whenever possible 1013 if function.name.startswith('gl') \ 1014 and arg.type in (glapi.GLint, glapi.GLfloat, glapi.GLdouble) \ 1015 and arg.name == 'param': 1016 assert arg.index > 0 1017 assert function.args[arg.index - 1].name == 'pname' 1018 assert function.args[arg.index - 1].type == glapi.GLenum 1019 print(' if (is_symbolic_pname(pname) && is_symbolic_param(%s)) {' % arg.name) 1020 self.serializeValue(glapi.GLenum, arg.name) 1021 print(' } else {') 1022 Tracer.serializeArgValue(self, function, arg) 1023 print(' }') 1024 return 1025 1026 Tracer.serializeArgValue(self, function, arg) 1027 1028 fake_function_names = [ 1029 'glBindAttribLocation', 1030 'glBindAttribLocationARB', 1031 'glBindBuffer', 1032 'glBitmap', 1033 'glClientActiveTexture', 1034 'glDisableClientState', 1035 'glEnableClientState', 1036 'glEndList', 1037 'glNewList', 1038 'glScissor', 1039 'glStringMarkerGREMEDY', 1040 'glTexImage2D', 1041 'glViewport', 1042 ] 1043 1044 def footer(self, api): 1045 Tracer.footer(self, api) 1046 1047 # Generate helper functions to emit fake function calls into the trace 1048 for function in api.getAllFunctions(): 1049 if function.name in self.fake_function_names: 1050 print(function.prototype('_fake_' + function.name)) 1051 print(r'{') 1052 self.fake_call(function, function.argNames()) 1053 print(r'}') 1054 print() 1055 1056 # A simple state tracker to track the pointer values 1057 # update the state 1058 print('static void _trace_user_arrays(gltrace::Context *_ctx, GLuint count)') 1059 print('{') 1060 print(' glfeatures::Profile profile = _ctx->profile;') 1061 print(' bool es1 = profile.es() && profile.major == 1;') 1062 print() 1063 1064 # Some apps, in particular Quake3, can tell the driver to lock more 1065 # vertices than those actually required for the draw call. 1066 print(' count = std::max(count, _ctx->lockedArrayCount);') 1067 print() 1068 1069 # Temporarily unbind the array buffer 1070 print(' GLint _array_buffer = _glGetInteger(GL_ARRAY_BUFFER_BINDING);') 1071 print(' if (_array_buffer) {') 1072 print(' _fake_glBindBuffer(GL_ARRAY_BUFFER, 0);') 1073 print(' }') 1074 print() 1075 1076 for camelcase_name, uppercase_name in self.arrays: 1077 # in which profile is the array available? 1078 profile_check = 'profile.desktop()' 1079 if camelcase_name in self.arrays_es1: 1080 profile_check = '(' + profile_check + ' || es1)'; 1081 1082 function_name = 'gl%sPointer' % camelcase_name 1083 enable_name = 'GL_%s_ARRAY' % uppercase_name 1084 binding_name = 'GL_%s_ARRAY_BUFFER_BINDING' % uppercase_name 1085 function = api.getFunctionByName(function_name) 1086 1087 print(' // %s' % function.prototype()) 1088 print(' if (%s) {' % profile_check) 1089 self.array_trace_prolog(api, uppercase_name) 1090 self.array_prolog(api, uppercase_name) 1091 print(' if (_glIsEnabled(%s)) {' % enable_name) 1092 print(' GLint _binding = _glGetInteger(%s);' % binding_name) 1093 print(' if (!_binding) {') 1094 1095 # Get the arguments via glGet* 1096 for arg in function.args: 1097 arg_get_enum = 'GL_%s_ARRAY_%s' % (uppercase_name, arg.name.upper()) 1098 arg_get_function, arg_type = TypeGetter().visit(arg.type) 1099 print(' %s %s = 0;' % (arg_type, arg.name)) 1100 print(' _%s(%s, &%s);' % (arg_get_function, arg_get_enum, arg.name)) 1101 1102 arg_names = ', '.join([arg.name for arg in function.args[:-1]]) 1103 print(' size_t _size = _%s_size(%s, count);' % (function.name, arg_names)) 1104 1105 # Emit a fake function 1106 self.array_trace_intermezzo(api, uppercase_name) 1107 print(' unsigned _call = trace::localWriter.beginEnter(&_%s_sig, true);' % (function.name,)) 1108 for arg in function.args: 1109 assert not arg.output 1110 print(' trace::localWriter.beginArg(%u);' % (arg.index,)) 1111 if arg.name != 'pointer': 1112 self.serializeValue(arg.type, arg.name) 1113 else: 1114 print(' trace::localWriter.writeBlob((const void *)%s, _size);' % (arg.name)) 1115 print(' trace::localWriter.endArg();') 1116 1117 print(' trace::localWriter.endEnter();') 1118 print(' trace::localWriter.beginLeave(_call);') 1119 print(' trace::localWriter.endLeave();') 1120 print(' }') 1121 print(' }') 1122 self.array_epilog(api, uppercase_name) 1123 self.array_trace_epilog(api, uppercase_name) 1124 print(' }') 1125 print() 1126 1127 # Samething, but for glVertexAttribPointer* 1128 # 1129 # Some variants of glVertexAttribPointer alias conventional and generic attributes: 1130 # - glVertexAttribPointer: no 1131 # - glVertexAttribPointerARB: implementation dependent 1132 # - glVertexAttribPointerNV: yes 1133 # 1134 # This means that the implementations of these functions do not always 1135 # alias, and they need to be considered independently. 1136 # 1137 print(' // ES1 does not support generic vertex attributes') 1138 print(' if (es1)') 1139 print(' return;') 1140 print() 1141 1142 function_name = 'glVertexAttribPointer' 1143 function = api.getFunctionByName(function_name) 1144 1145 print(' // %s' % function.prototype()) 1146 print(' GLint _max_vertex_attribs = _glGetInteger(GL_MAX_VERTEX_ATTRIBS);') 1147 print(' for (GLint index = 0; index < _max_vertex_attribs; ++index) {') 1148 print(' GLint _enabled = 0;') 1149 print(' _glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &_enabled);') 1150 print(' if (_enabled) {') 1151 print(' GLint _binding = 0;') 1152 print(' _glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, &_binding);') 1153 print(' if (!_binding) {') 1154 1155 # Get the arguments via glGet* 1156 for arg in function.args[1:]: 1157 arg_get_enum = 'GL_VERTEX_ATTRIB_ARRAY_%s' % (arg.name.upper()) 1158 arg_get_function, arg_type = TypeGetter('glGetVertexAttrib', False).visit(arg.type) 1159 print(' %s %s = 0;' % (arg_type, arg.name)) 1160 print(' _%s(index, %s, &%s);' % (arg_get_function, arg_get_enum, arg.name)) 1161 1162 arg_names = ', '.join([arg.name for arg in function.args[1:-1]]) 1163 print(' size_t _size = _%s_size(%s, count);' % (function.name, arg_names)) 1164 1165 # Emit a fake function 1166 print(' unsigned _call = trace::localWriter.beginEnter(&_%s_sig, true);' % (function.name,)) 1167 for arg in function.args: 1168 assert not arg.output 1169 print(' trace::localWriter.beginArg(%u);' % (arg.index,)) 1170 if arg.name != 'pointer': 1171 self.serializeValue(arg.type, arg.name) 1172 else: 1173 print(' trace::localWriter.writeBlob((const void *)%s, _size);' % (arg.name)) 1174 print(' trace::localWriter.endArg();') 1175 1176 print(' trace::localWriter.endEnter();') 1177 print(' trace::localWriter.beginLeave(_call);') 1178 print(' trace::localWriter.endLeave();') 1179 print(' }') 1180 print(' }') 1181 print(' }') 1182 print() 1183 1184 # Restore the original array_buffer 1185 print(' if (_array_buffer) {') 1186 print(' _fake_glBindBuffer(GL_ARRAY_BUFFER, _array_buffer);') 1187 print(' }') 1188 print() 1189 1190 print('}') 1191 print() 1192 1193 # 1194 # Hooks for glTexCoordPointer, which is identical to the other array 1195 # pointers except the fact that it is indexed by glClientActiveTexture. 1196 # 1197 1198 def array_prolog(self, api, uppercase_name): 1199 if uppercase_name == 'TEXTURE_COORD': 1200 print(' GLint max_units = 0;') 1201 print(' if (_ctx->profile.desktop())') 1202 print(' _glGetIntegerv(GL_MAX_TEXTURE_COORDS, &max_units);') 1203 print(' else') 1204 print(' _glGetIntegerv(GL_MAX_TEXTURE_UNITS, &max_units);') 1205 print(' GLint client_active_texture = GL_TEXTURE0;') 1206 print(' if (max_units > 0) {') 1207 print(' _glGetIntegerv(GL_CLIENT_ACTIVE_TEXTURE, &client_active_texture);') 1208 print(' }') 1209 print(' GLint unit = 0;') 1210 print(' do {') 1211 print(' GLint texture = GL_TEXTURE0 + unit;') 1212 print(' if (max_units > 0) {') 1213 print(' _glClientActiveTexture(texture);') 1214 print(' }') 1215 1216 def array_trace_prolog(self, api, uppercase_name): 1217 if uppercase_name == 'TEXTURE_COORD': 1218 print(' bool client_active_texture_dirty = false;') 1219 1220 def array_epilog(self, api, uppercase_name): 1221 if uppercase_name == 'TEXTURE_COORD': 1222 print(' } while (++unit < max_units);') 1223 self.array_cleanup(api, uppercase_name) 1224 1225 def array_cleanup(self, api, uppercase_name): 1226 if uppercase_name == 'TEXTURE_COORD': 1227 print(' if (max_units > 0) {') 1228 print(' _glClientActiveTexture(client_active_texture);') 1229 print(' }') 1230 1231 def array_trace_intermezzo(self, api, uppercase_name): 1232 if uppercase_name == 'TEXTURE_COORD': 1233 print(' if (texture != client_active_texture || client_active_texture_dirty) {') 1234 print(' client_active_texture_dirty = true;') 1235 print(' _fake_glClientActiveTexture(texture);') 1236 print(' }') 1237 1238 def array_trace_epilog(self, api, uppercase_name): 1239 if uppercase_name == 'TEXTURE_COORD': 1240 print(' if (client_active_texture_dirty) {') 1241 print(' _fake_glClientActiveTexture(client_active_texture);') 1242 print(' }') 1243 1244 def emitFakeTexture2D(self): 1245 print(r' _fake_glTexImage2D(target, level, internalformat, width, height, border, format, type, pixels);') 1246 1247