From 8fb49d08f3a305d3c7019f83c75aaeffcc99c8f1 Mon Sep 17 00:00:00 2001 From: baldurk Date: Fri, 13 Jan 2017 15:53:45 +0000 Subject: [PATCH] Reduce minimum requirements for replay to 3.2 + a few extensions * The checking for a capable replay context is centralised so there's less code duplication between linux (GLX) and windows (WGL) --- renderdoc/driver/gl/gl_common.cpp | 338 ++++++++++++++++++++++ renderdoc/driver/gl/gl_common.h | 13 +- renderdoc/driver/gl/gl_replay_linux.cpp | 101 +++---- renderdoc/driver/gl/gl_replay_win32.cpp | 369 ++---------------------- 4 files changed, 422 insertions(+), 399 deletions(-) diff --git a/renderdoc/driver/gl/gl_common.cpp b/renderdoc/driver/gl/gl_common.cpp index d2a2e4f88..e31934ef8 100644 --- a/renderdoc/driver/gl/gl_common.cpp +++ b/renderdoc/driver/gl/gl_common.cpp @@ -40,6 +40,344 @@ void DeleteContext(GLWindowingData context); void MakeContextCurrent(GLWindowingData data); +bool CheckReplayContext(PFNGLGETSTRINGPROC getStr, PFNGLGETINTEGERVPROC getInt, + PFNGLGETSTRINGIPROC getStri) +{ +// we can't do without these extensions, but they should be present on any reasonable driver +// as they should have minimal or no hardware requirement. They were present on mesa 10.6 +// for all drivers which dates to mid 2015. +#undef EXT_TO_CHECK +#define EXT_TO_CHECK(ext) CONCAT(GLExt_, ext), + enum + { + EXTENSION_CHECKS() ext_count, + }; + bool exts[ext_count] = {}; + + if(getStr) + RDCLOG("Running GL replay on: %s / %s / %s", getStr(eGL_VENDOR), getStr(eGL_RENDERER), + getStr(eGL_VERSION)); + + string extensionString = ""; + + GLint numExts = 0; + getInt(eGL_NUM_EXTENSIONS, &numExts); + for(GLint e = 0; e < numExts; e++) + { + const char *ext = (const char *)getStri(eGL_EXTENSIONS, (GLuint)e); + + extensionString += StringFormat::Fmt("[%d]: %s, ", e, ext); + + if(e > 0 && (e % 100) == 0) + { + RDCLOG("%s", extensionString.c_str()); + extensionString = ""; + } + + // skip the "GL_" + ext += 3; + +#undef EXT_TO_CHECK +#define EXT_TO_CHECK(extname) \ + if(!strcmp(ext, STRINGIZE(extname))) \ + exts[CONCAT(GLExt_, extname)] = true; + + EXTENSION_CHECKS() + } + + if(!extensionString.empty()) + RDCLOG("%s", extensionString.c_str()); + + bool missingExt = false; + +#define REQUIRE_EXTENSION(extname) \ + if(!exts[CONCAT(GLExt_, extname)]) \ + { \ + missingExt = true; \ + RDCERR( \ + "RenderDoc requires " STRINGIZE(extname) " availability, and it is not reported. Try " \ + "updating your drivers."); \ + } + + // we require the below extensions on top of a 3.2 context. Some of these we could in theory + // do without, but support for them is so widespread it's not worthwhile + + // used for reflecting out vertex bindings with most generality and remapping from old-style + // Pointer functions + // Should be possible to remove by falling back to reflecting vertex bindings the old way only and + // remapping to 'fake' new-style bindings for representing in the UI + REQUIRE_EXTENSION(ARB_vertex_attrib_binding); + // for program introspection, needed for shader reflection. + // Possible to remove by compiling shaders to SPIR-V and reflecting ourselves. + REQUIRE_EXTENSION(ARB_program_interface_query); + // strangely, this is the extension needed for layout(binding = X) on uniforms, textures, etc. + // Possible to remove by #defining out the layout specifiers and manually setting the uniform + // values. + REQUIRE_EXTENSION(ARB_shading_language_420pack); + // needed for program pipelines, glProgramUniform*, and reflecting shaders on their own + // Possible to remove this with self-compiled SPIR-V for reflection - see above. Likewise + // convenience for our own pipelines when replacing single shaders or such. + REQUIRE_EXTENSION(ARB_separate_shader_objects); + // needed for layout(location = X) on fragment shader outputs + // similar to ARB_shading_language_420pack we could do without this by assigning locations in code + REQUIRE_EXTENSION(ARB_explicit_attrib_location); + // adds sampler objects so we can swap sampling behaviour when sampling from the capture's + // textures + // Possible to remove by manually pushing and popping all of the sampler state that we're + // interested in on each texture instead of binding sampler objects. + REQUIRE_EXTENSION(ARB_sampler_objects); + + return missingExt; +} + +bool ValidateFunctionPointers(const GLHookSet &real) +{ + PFNGLGETSTRINGPROC *ptrs = (PFNGLGETSTRINGPROC *)ℜ + size_t num = sizeof(real) / sizeof(PFNGLGETSTRINGPROC); + + RDCLOG("Function pointers available:"); + for(size_t ptr = 0; ptr < num;) + { + uint64_t ptrmask = 0; + + for(size_t j = 0; j < 64; j++) + if(ptr + j < num && ptrs[ptr + j]) + ptrmask |= 1ULL << (63 - j); + + ptr += 64; + + RDCLOG("%064llb", ptrmask); + } + + // check for the presence of GL functions we will call unconditionally as part of the replay + // process. + // Other functions that are only called to deserialise are checked for presence separately + + bool ret = true; + +#define CHECK_PRESENT(func) \ + if(!real.func) \ + { \ + RDCERR( \ + "Missing function %s, required for replay. RenderDoc requires a 3.2 context, " \ + "and a handful of extensions, see the Documentation.", \ + #func); \ + ret = false; \ + } + + // these functions should all be present as part of a 3.2 context plus the extensions we require, + // but let's just be extra-careful + CHECK_PRESENT(glActiveTexture) + CHECK_PRESENT(glAttachShader) + CHECK_PRESENT(glBeginQuery) + CHECK_PRESENT(glBeginTransformFeedback) + CHECK_PRESENT(glBindAttribLocation) + CHECK_PRESENT(glBindBuffer) + CHECK_PRESENT(glBindBufferBase) + CHECK_PRESENT(glBindBufferRange) + CHECK_PRESENT(glBindFragDataLocation) + CHECK_PRESENT(glBindFramebuffer) + CHECK_PRESENT(glBindProgramPipeline) + CHECK_PRESENT(glBindSampler) + CHECK_PRESENT(glBindTexture) + CHECK_PRESENT(glBindTransformFeedback) + CHECK_PRESENT(glBindVertexArray) + CHECK_PRESENT(glBindVertexBuffer) + CHECK_PRESENT(glBlendColor) + CHECK_PRESENT(glBlendEquationSeparate) + CHECK_PRESENT(glBlendFunc) + CHECK_PRESENT(glBlendFuncSeparate) + CHECK_PRESENT(glBlitFramebuffer) + CHECK_PRESENT(glBufferData) + CHECK_PRESENT(glBufferSubData) + CHECK_PRESENT(glClearBufferData) + CHECK_PRESENT(glClearBufferfi) + CHECK_PRESENT(glClearBufferfv) + CHECK_PRESENT(glClearBufferiv) + CHECK_PRESENT(glClearBufferuiv) + CHECK_PRESENT(glClearColor) + CHECK_PRESENT(glClearDepth) + CHECK_PRESENT(glColorMaski) + CHECK_PRESENT(glCompileShader) + CHECK_PRESENT(glCopyImageSubData) + CHECK_PRESENT(glCreateProgram) + CHECK_PRESENT(glCreateShader) + CHECK_PRESENT(glCreateShaderProgramv) + CHECK_PRESENT(glCullFace) + CHECK_PRESENT(glDeleteBuffers) + CHECK_PRESENT(glDeleteFramebuffers) + CHECK_PRESENT(glDeleteProgram) + CHECK_PRESENT(glDeleteProgramPipelines) + CHECK_PRESENT(glDeleteQueries) + CHECK_PRESENT(glDeleteSamplers) + CHECK_PRESENT(glDeleteShader) + CHECK_PRESENT(glDeleteTextures) + CHECK_PRESENT(glDeleteTransformFeedbacks) + CHECK_PRESENT(glDeleteVertexArrays) + CHECK_PRESENT(glDepthFunc) + CHECK_PRESENT(glDepthMask) + CHECK_PRESENT(glDetachShader) + CHECK_PRESENT(glDisable) + CHECK_PRESENT(glDisablei) + CHECK_PRESENT(glDisableVertexAttribArray) + CHECK_PRESENT(glDrawArrays) + CHECK_PRESENT(glDrawArraysInstanced) + CHECK_PRESENT(glDrawBuffers) + CHECK_PRESENT(glDrawElements) + CHECK_PRESENT(glDrawElementsBaseVertex) + CHECK_PRESENT(glEnable) + CHECK_PRESENT(glEnablei) + CHECK_PRESENT(glEnableVertexAttribArray) + CHECK_PRESENT(glEndConditionalRender) + CHECK_PRESENT(glEndQuery) + CHECK_PRESENT(glEndTransformFeedback) + CHECK_PRESENT(glFramebufferTexture) + CHECK_PRESENT(glFramebufferTexture2D) + CHECK_PRESENT(glFramebufferTexture3D) + CHECK_PRESENT(glFramebufferTextureLayer) + CHECK_PRESENT(glFrontFace) + CHECK_PRESENT(glGenBuffers) + CHECK_PRESENT(glGenFramebuffers) + CHECK_PRESENT(glGenProgramPipelines) + CHECK_PRESENT(glGenQueries) + CHECK_PRESENT(glGenSamplers) + CHECK_PRESENT(glGenTextures) + CHECK_PRESENT(glGenTransformFeedbacks) + CHECK_PRESENT(glGenVertexArrays) + CHECK_PRESENT(glGetActiveUniformBlockiv) + CHECK_PRESENT(glGetAttribLocation) + CHECK_PRESENT(glGetBooleani_v) + CHECK_PRESENT(glGetBooleanv) + CHECK_PRESENT(glGetBufferParameteriv) + CHECK_PRESENT(glGetBufferSubData) + CHECK_PRESENT(glGetCompressedTexImage) + CHECK_PRESENT(glGetDoublev) + CHECK_PRESENT(glGetError) + CHECK_PRESENT(glGetFloatv) + CHECK_PRESENT(glGetFragDataLocation) + CHECK_PRESENT(glGetFramebufferAttachmentParameteriv) + CHECK_PRESENT(glGetInteger64i_v) + CHECK_PRESENT(glGetIntegeri_v) + CHECK_PRESENT(glGetIntegerv) + CHECK_PRESENT(glGetInternalformativ) + CHECK_PRESENT(glGetProgramInfoLog) + CHECK_PRESENT(glGetProgramInterfaceiv) + CHECK_PRESENT(glGetProgramiv) + CHECK_PRESENT(glGetProgramPipelineiv) + CHECK_PRESENT(glGetProgramResourceIndex) + CHECK_PRESENT(glGetProgramResourceiv) + CHECK_PRESENT(glGetProgramResourceName) + CHECK_PRESENT(glGetQueryObjectuiv) + CHECK_PRESENT(glGetSamplerParameterfv) + CHECK_PRESENT(glGetSamplerParameteriv) + CHECK_PRESENT(glGetShaderInfoLog) + CHECK_PRESENT(glGetShaderiv) + CHECK_PRESENT(glGetString) + CHECK_PRESENT(glGetStringi) + CHECK_PRESENT(glGetTexImage) + CHECK_PRESENT(glGetTexLevelParameteriv) + CHECK_PRESENT(glGetTexParameterfv) + CHECK_PRESENT(glGetTexParameteriv) + CHECK_PRESENT(glGetUniformBlockIndex) + CHECK_PRESENT(glGetUniformdv) + CHECK_PRESENT(glGetUniformfv) + CHECK_PRESENT(glGetUniformiv) + CHECK_PRESENT(glGetUniformLocation) + CHECK_PRESENT(glGetUniformuiv) + CHECK_PRESENT(glGetVertexAttribfv) + CHECK_PRESENT(glGetVertexAttribiv) + CHECK_PRESENT(glHint) + CHECK_PRESENT(glIsEnabled) + CHECK_PRESENT(glIsEnabledi) + CHECK_PRESENT(glLineWidth) + CHECK_PRESENT(glLinkProgram) + CHECK_PRESENT(glLogicOp) + CHECK_PRESENT(glMapBufferRange) + CHECK_PRESENT(glPixelStorei) + CHECK_PRESENT(glPointParameterf) + CHECK_PRESENT(glPointParameteri) + CHECK_PRESENT(glPointSize) + CHECK_PRESENT(glPolygonMode) + CHECK_PRESENT(glPolygonOffset) + CHECK_PRESENT(glPrimitiveRestartIndex) + CHECK_PRESENT(glProgramParameteri) + CHECK_PRESENT(glProgramUniform1dv) + CHECK_PRESENT(glProgramUniform1fv) + CHECK_PRESENT(glProgramUniform1iv) + CHECK_PRESENT(glProgramUniform1ui) + CHECK_PRESENT(glProgramUniform1uiv) + CHECK_PRESENT(glProgramUniform2dv) + CHECK_PRESENT(glProgramUniform2fv) + CHECK_PRESENT(glProgramUniform2iv) + CHECK_PRESENT(glProgramUniform2uiv) + CHECK_PRESENT(glProgramUniform3dv) + CHECK_PRESENT(glProgramUniform3fv) + CHECK_PRESENT(glProgramUniform3iv) + CHECK_PRESENT(glProgramUniform3uiv) + CHECK_PRESENT(glProgramUniform4dv) + CHECK_PRESENT(glProgramUniform4fv) + CHECK_PRESENT(glProgramUniform4iv) + CHECK_PRESENT(glProgramUniform4ui) + CHECK_PRESENT(glProgramUniform4uiv) + CHECK_PRESENT(glProgramUniformMatrix2dv) + CHECK_PRESENT(glProgramUniformMatrix2fv) + CHECK_PRESENT(glProgramUniformMatrix2x3dv) + CHECK_PRESENT(glProgramUniformMatrix2x3fv) + CHECK_PRESENT(glProgramUniformMatrix2x4dv) + CHECK_PRESENT(glProgramUniformMatrix2x4fv) + CHECK_PRESENT(glProgramUniformMatrix3dv) + CHECK_PRESENT(glProgramUniformMatrix3fv) + CHECK_PRESENT(glProgramUniformMatrix3x2dv) + CHECK_PRESENT(glProgramUniformMatrix3x2fv) + CHECK_PRESENT(glProgramUniformMatrix3x4dv) + CHECK_PRESENT(glProgramUniformMatrix3x4fv) + CHECK_PRESENT(glProgramUniformMatrix4dv) + CHECK_PRESENT(glProgramUniformMatrix4fv) + CHECK_PRESENT(glProgramUniformMatrix4x2dv) + CHECK_PRESENT(glProgramUniformMatrix4x2fv) + CHECK_PRESENT(glProgramUniformMatrix4x3dv) + CHECK_PRESENT(glProgramUniformMatrix4x3fv) + CHECK_PRESENT(glProvokingVertex) + CHECK_PRESENT(glReadBuffer) + CHECK_PRESENT(glReadPixels) + CHECK_PRESENT(glSampleCoverage) + CHECK_PRESENT(glSampleMaski) + CHECK_PRESENT(glSamplerParameteri) + CHECK_PRESENT(glShaderSource) + CHECK_PRESENT(glStencilFuncSeparate) + CHECK_PRESENT(glStencilMask) + CHECK_PRESENT(glStencilMaskSeparate) + CHECK_PRESENT(glStencilOpSeparate) + CHECK_PRESENT(glTexImage2D) + CHECK_PRESENT(glTexParameteri) + CHECK_PRESENT(glTransformFeedbackVaryings) + CHECK_PRESENT(glUniform1i) + CHECK_PRESENT(glUniform1ui) + CHECK_PRESENT(glUniform2f) + CHECK_PRESENT(glUniform2fv) + CHECK_PRESENT(glUniform4fv) + CHECK_PRESENT(glUniformBlockBinding) + CHECK_PRESENT(glUniformMatrix4fv) + CHECK_PRESENT(glUnmapBuffer) + CHECK_PRESENT(glUseProgram) + CHECK_PRESENT(glUseProgramStages) + CHECK_PRESENT(glVertexAttrib4fv) + CHECK_PRESENT(glVertexAttribBinding) + CHECK_PRESENT(glVertexAttribFormat) + CHECK_PRESENT(glVertexAttribIFormat) + CHECK_PRESENT(glVertexAttribLFormat) + CHECK_PRESENT(glVertexAttribPointer) + CHECK_PRESENT(glVertexBindingDivisor) + CHECK_PRESENT(glViewport) + + // other functions are either checked for presence explicitly (like + // depth bounds or polygon offset clamp EXT functions), or they are + // only called when such a call is serialised from the logfile, and + // so they are checked for validity separately. + + return ret; +} + void CheckExtensions(const GLHookSet &gl) { GLint numExts = 0; diff --git a/renderdoc/driver/gl/gl_common.h b/renderdoc/driver/gl/gl_common.h index d3cf422fe..14d494a5e 100644 --- a/renderdoc/driver/gl/gl_common.h +++ b/renderdoc/driver/gl/gl_common.h @@ -205,7 +205,13 @@ extern bool GLIsCore; EXT_TO_CHECK(ARB_clear_buffer_object) \ EXT_TO_CHECK(ARB_internalformat_query2) \ EXT_TO_CHECK(ARB_texture_swizzle) \ - EXT_TO_CHECK(EXT_texture_swizzle) + EXT_TO_CHECK(EXT_texture_swizzle) \ + EXT_TO_CHECK(ARB_shading_language_420pack) \ + EXT_TO_CHECK(ARB_separate_shader_objects) \ + EXT_TO_CHECK(ARB_explicit_attrib_location) \ + EXT_TO_CHECK(ARB_vertex_attrib_binding) \ + EXT_TO_CHECK(ARB_sampler_objects) \ + EXT_TO_CHECK(KHR_debug) // extensions we know we want to check for are precached, indexd by this enum enum ExtensionCheckEnum @@ -240,6 +246,11 @@ extern bool VendorCheck[VendorCheck_Count]; void DoVendorChecks(const GLHookSet &gl, GLWindowingData context); void CheckExtensions(const GLHookSet &gl); +// verify that we got a replay context that we can work with +bool CheckReplayContext(PFNGLGETSTRINGPROC getStr, PFNGLGETINTEGERVPROC getInt, + PFNGLGETSTRINGIPROC getStri); +bool ValidateFunctionPointers(const GLHookSet &real); + namespace glEmulate { void EmulateUnsupportedFunctions(GLHookSet *hooks); diff --git a/renderdoc/driver/gl/gl_replay_linux.cpp b/renderdoc/driver/gl/gl_replay_linux.cpp index 61f9292dc..4ce64dd6a 100644 --- a/renderdoc/driver/gl/gl_replay_linux.cpp +++ b/renderdoc/driver/gl/gl_replay_linux.cpp @@ -247,6 +247,17 @@ bool GLReplay::IsOutputWindowVisible(uint64_t id) const GLHookSet &GetRealGLFunctions(); +static bool X11ErrorSeen = false; + +int NonFatalX11ErrorHandler(Display *display, XErrorEvent *error) +{ + X11ErrorSeen = true; + + return 0; +} + +typedef int (*X11ErrorHandler)(Display *display, XErrorEvent *error); + ReplayCreateStatus GL_CreateReplayDevice(const char *logfile, IReplayDriver **driver) { RDCDEBUG("Creating an OpenGL replay device"); @@ -302,9 +313,9 @@ ReplayCreateStatus GL_CreateReplayDevice(const char *logfile, IReplayDriver **dr GLReplay::PreContextInitCounters(); attribs[i++] = GLX_CONTEXT_MAJOR_VERSION_ARB; - attribs[i++] = 4; - attribs[i++] = GLX_CONTEXT_MINOR_VERSION_ARB; attribs[i++] = 3; + attribs[i++] = GLX_CONTEXT_MINOR_VERSION_ARB; + attribs[i++] = 2; attribs[i++] = GLX_CONTEXT_FLAGS_ARB; #if ENABLED(RDOC_DEVEL) attribs[i++] = GLX_CONTEXT_DEBUG_BIT_ARB; @@ -336,14 +347,24 @@ ReplayCreateStatus GL_CreateReplayDevice(const char *logfile, IReplayDriver **dr return eReplayCreate_APIInitFailed; } - GLXContext ctx = glXCreateContextAttribsProc(dpy, fbcfg[0], 0, true, attribs); + GLXContext ctx = NULL; - if(ctx == NULL) + { + X11ErrorHandler prev = XSetErrorHandler(&NonFatalX11ErrorHandler); + + X11ErrorSeen = false; + + ctx = glXCreateContextAttribsProc(dpy, fbcfg[0], 0, true, attribs); + + XSetErrorHandler(prev); + } + + if(ctx == NULL || X11ErrorSeen) { XFree(fbcfg); XCloseDisplay(dpy); GLReplay::PostContextShutdownCounters(); - RDCERR("Couldn't create 4.3 context - RenderDoc requires OpenGL 4.3 availability"); + RDCERR("Couldn't create 3.2 context - RenderDoc requires OpenGL 3.2 availability"); return eReplayCreate_APIHardwareUnsupported; } @@ -384,53 +405,35 @@ ReplayCreateStatus GL_CreateReplayDevice(const char *logfile, IReplayDriver **dr GLReplay::PostContextShutdownCounters(); return eReplayCreate_APIInitFailed; } - else + + const GLHookSet &real = GetRealGLFunctions(); + + bool missingExt = CheckReplayContext(getStr, getInt, getStri); + + if(missingExt) { - // eventually we want to emulate EXT_dsa on replay if it isn't present, but for - // now we just require it. - bool dsa = false; - bool bufstorage = false; - - if(getStr) - RDCLOG("Running GL replay on: %s / %s / %s", getStr(eGL_VENDOR), getStr(eGL_RENDERER), - getStr(eGL_VERSION)); - - GLint numExts = 0; - getInt(eGL_NUM_EXTENSIONS, &numExts); - for(GLint e = 0; e < numExts; e++) - { - const char *ext = (const char *)getStri(eGL_EXTENSIONS, (GLuint)e); - - RDCLOG("Extension % 3d: %s", e, ext); - - if(!strcmp(ext, "GL_EXT_direct_state_access")) - dsa = true; - if(!strcmp(ext, "GL_ARB_buffer_storage")) - bufstorage = true; - } - - if(!dsa) - RDCERR( - "RenderDoc requires EXT_direct_state_access availability, and it is not reported. Try " - "updating your drivers."); - - if(!bufstorage) - RDCERR( - "RenderDoc requires ARB_buffer_storage availability, and it is not reported. Try " - "updating your drivers."); - - if(!dsa || !bufstorage) - { - glXDestroyPbufferProc(dpy, pbuffer); - glXDestroyCtxProc(dpy, ctx); - XFree(fbcfg); - XCloseDisplay(dpy); - GLReplay::PostContextShutdownCounters(); - return eReplayCreate_APIHardwareUnsupported; - } + exit(0); + glXDestroyPbufferProc(dpy, pbuffer); + glXDestroyCtxProc(dpy, ctx); + XFree(fbcfg); + XCloseDisplay(dpy); + GLReplay::PostContextShutdownCounters(); + return eReplayCreate_APIHardwareUnsupported; } - WrappedOpenGL *gl = new WrappedOpenGL(logfile, GetRealGLFunctions()); + bool extensionsValidated = ValidateFunctionPointers(real); + + if(!extensionsValidated) + { + glXDestroyPbufferProc(dpy, pbuffer); + glXDestroyCtxProc(dpy, ctx); + XFree(fbcfg); + XCloseDisplay(dpy); + GLReplay::PostContextShutdownCounters(); + return eReplayCreate_APIHardwareUnsupported; + } + + WrappedOpenGL *gl = new WrappedOpenGL(logfile, real); gl->Initialise(initParams); if(gl->GetSerialiser()->HasError()) diff --git a/renderdoc/driver/gl/gl_replay_win32.cpp b/renderdoc/driver/gl/gl_replay_win32.cpp index ba6830969..bb4e0fdb0 100644 --- a/renderdoc/driver/gl/gl_replay_win32.cpp +++ b/renderdoc/driver/gl/gl_replay_win32.cpp @@ -402,9 +402,9 @@ ReplayCreateStatus GL_CreateReplayDevice(const char *logfile, IReplayDriver **dr int i = 0; attribs[i++] = WGL_CONTEXT_MAJOR_VERSION_ARB; - attribs[i++] = 4; - attribs[i++] = WGL_CONTEXT_MINOR_VERSION_ARB; attribs[i++] = 3; + attribs[i++] = WGL_CONTEXT_MINOR_VERSION_ARB; + attribs[i++] = 2; attribs[i++] = WGL_CONTEXT_FLAGS_ARB; #if ENABLED(RDOC_DEVEL) attribs[i++] = WGL_CONTEXT_DEBUG_BIT_ARB; @@ -417,7 +417,7 @@ ReplayCreateStatus GL_CreateReplayDevice(const char *logfile, IReplayDriver **dr rc = createContextAttribs(dc, NULL, attribs); if(rc == NULL) { - RDCERR("Couldn't create 4.3 RC - RenderDoc requires OpenGL 4.3 availability"); + RDCERR("Couldn't create 3.2 RC - RenderDoc requires OpenGL 3.2 availability"); ReleaseDC(w, dc); GLReplay::PostContextShutdownCounters(); return eReplayCreate_APIHardwareUnsupported; @@ -426,7 +426,7 @@ ReplayCreateStatus GL_CreateReplayDevice(const char *logfile, IReplayDriver **dr res = wglMakeCurrentProc(dc, rc); if(res == FALSE) { - RDCERR("Couldn't make 4.3 RC current"); + RDCERR("Couldn't make 3.2 RC current"); wglMakeCurrentProc(NULL, NULL); wglDeleteRC(rc); ReleaseDC(w, dc); @@ -448,360 +448,31 @@ ReplayCreateStatus GL_CreateReplayDevice(const char *logfile, IReplayDriver **dr GLReplay::PostContextShutdownCounters(); return eReplayCreate_APIInitFailed; } - else + + bool missingExt = CheckReplayContext(getStr, getInt, getStri); + + if(missingExt) { - // eventually we want to emulate EXT_dsa on replay if it isn't present, but for - // now we just require it. - bool dsa = false; - bool bufstorage = false; - - if(getStr) - RDCLOG("Running GL replay on: %s / %s / %s", getStr(eGL_VENDOR), getStr(eGL_RENDERER), - getStr(eGL_VERSION)); - - GLint numExts = 0; - getInt(eGL_NUM_EXTENSIONS, &numExts); - for(GLint e = 0; e < numExts; e++) - { - const char *ext = (const char *)getStri(eGL_EXTENSIONS, (GLuint)e); - - RDCLOG("Extension % 3d: %s", e, ext); - - if(!strcmp(ext, "GL_EXT_direct_state_access")) - dsa = true; - if(!strcmp(ext, "GL_ARB_buffer_storage")) - bufstorage = true; - } - - if(!dsa) - RDCERR( - "RenderDoc requires EXT_direct_state_access availability, and it is not reported. Try " - "updating your drivers."); - - if(!bufstorage) - RDCERR( - "RenderDoc requires ARB_buffer_storage availability, and it is not reported. Try " - "updating your drivers."); - - if(!dsa || !bufstorage) - { - wglMakeCurrentProc(NULL, NULL); - wglDeleteRC(rc); - ReleaseDC(w, dc); - GLReplay::PostContextShutdownCounters(); - return eReplayCreate_APIHardwareUnsupported; - } + wglMakeCurrentProc(NULL, NULL); + wglDeleteRC(rc); + ReleaseDC(w, dc); + GLReplay::PostContextShutdownCounters(); + return eReplayCreate_APIInitFailed; } const GLHookSet &real = GetRealGLFunctions(); - PFNGLGETSTRINGPROC *ptrs = (PFNGLGETSTRINGPROC *)ℜ - size_t num = sizeof(real) / sizeof(PFNGLGETSTRINGPROC); + bool extensionsValidated = ValidateFunctionPointers(real); - RDCLOG("Function pointers available:"); - for(size_t ptr = 0; ptr < num;) + if(!extensionsValidated) { - uint64_t ptrmask = 0; - - for(size_t j = 0; j < 64; j++) - if(ptr + j < num && ptrs[ptr + j]) - ptrmask |= 1ULL << (63 - j); - - ptr += 64; - - RDCLOG("%064llb", ptrmask); + wglMakeCurrentProc(NULL, NULL); + wglDeleteRC(rc); + ReleaseDC(w, dc); + GLReplay::PostContextShutdownCounters(); + return eReplayCreate_APIInitFailed; } -// check for the presence of GL functions we will call unconditionally as part of the replay -// process. -// Other functions that are only called to deserialise are checked for presence separately - -#define CHECK_PRESENT(func) \ - if(!real.func) \ - { \ - RDCERR( \ - "Missing function %s, required for replay. RenderDoc requires a 4.3 context, " \ - "EXT_direct_state_access and ARB_buffer_storage", \ - #func); \ - wglMakeCurrentProc(NULL, NULL); \ - wglDeleteRC(rc); \ - ReleaseDC(w, dc); \ - GLReplay::PostContextShutdownCounters(); \ - return eReplayCreate_APIHardwareUnsupported; \ - } - - // these functions should all be present as part of a 4.3 context, but let's just be extra-careful - CHECK_PRESENT(glActiveTexture) - CHECK_PRESENT(glAttachShader) - CHECK_PRESENT(glBeginQuery) - CHECK_PRESENT(glBeginTransformFeedback) - CHECK_PRESENT(glBindAttribLocation) - CHECK_PRESENT(glBindBuffer) - CHECK_PRESENT(glBindBufferBase) - CHECK_PRESENT(glBindBufferRange) - CHECK_PRESENT(glBindFragDataLocation) - CHECK_PRESENT(glBindFramebuffer) - CHECK_PRESENT(glBindImageTexture) - CHECK_PRESENT(glBindProgramPipeline) - CHECK_PRESENT(glBindSampler) - CHECK_PRESENT(glBindTexture) - CHECK_PRESENT(glBindTransformFeedback) - CHECK_PRESENT(glBindVertexArray) - CHECK_PRESENT(glBindVertexBuffer) - CHECK_PRESENT(glBlendColor) - CHECK_PRESENT(glBlendEquationSeparate) - CHECK_PRESENT(glBlendEquationSeparatei) - CHECK_PRESENT(glBlendFunc) - CHECK_PRESENT(glBlendFuncSeparate) - CHECK_PRESENT(glBlendFuncSeparatei) - CHECK_PRESENT(glBlitFramebuffer) - CHECK_PRESENT(glBufferData) - CHECK_PRESENT(glBufferSubData) - CHECK_PRESENT(glClearBufferData) - CHECK_PRESENT(glClearBufferfi) - CHECK_PRESENT(glClearBufferfv) - CHECK_PRESENT(glClearBufferiv) - CHECK_PRESENT(glClearBufferuiv) - CHECK_PRESENT(glClearColor) - CHECK_PRESENT(glClearDepth) - CHECK_PRESENT(glColorMaski) - CHECK_PRESENT(glCompileShader) - CHECK_PRESENT(glCopyImageSubData) - CHECK_PRESENT(glCreateProgram) - CHECK_PRESENT(glCreateShader) - CHECK_PRESENT(glCreateShaderProgramv) - CHECK_PRESENT(glCullFace) - CHECK_PRESENT(glDebugMessageCallback) - CHECK_PRESENT(glDeleteBuffers) - CHECK_PRESENT(glDeleteFramebuffers) - CHECK_PRESENT(glDeleteProgram) - CHECK_PRESENT(glDeleteProgramPipelines) - CHECK_PRESENT(glDeleteQueries) - CHECK_PRESENT(glDeleteSamplers) - CHECK_PRESENT(glDeleteShader) - CHECK_PRESENT(glDeleteTextures) - CHECK_PRESENT(glDeleteTransformFeedbacks) - CHECK_PRESENT(glDeleteVertexArrays) - CHECK_PRESENT(glDepthFunc) - CHECK_PRESENT(glDepthMask) - CHECK_PRESENT(glDepthRangeArrayv) - CHECK_PRESENT(glDetachShader) - CHECK_PRESENT(glDisable) - CHECK_PRESENT(glDisablei) - CHECK_PRESENT(glDisableVertexAttribArray) - CHECK_PRESENT(glDispatchCompute) - CHECK_PRESENT(glDrawArrays) - CHECK_PRESENT(glDrawArraysInstanced) - CHECK_PRESENT(glDrawArraysInstancedBaseInstance) - CHECK_PRESENT(glDrawBuffers) - CHECK_PRESENT(glDrawElements) - CHECK_PRESENT(glDrawElementsBaseVertex) - CHECK_PRESENT(glDrawElementsInstancedBaseVertexBaseInstance) - CHECK_PRESENT(glEnable) - CHECK_PRESENT(glEnablei) - CHECK_PRESENT(glEnableVertexAttribArray) - CHECK_PRESENT(glEndConditionalRender) - CHECK_PRESENT(glEndQuery) - CHECK_PRESENT(glEndQueryIndexed) - CHECK_PRESENT(glEndTransformFeedback) - CHECK_PRESENT(glFramebufferTexture) - CHECK_PRESENT(glFramebufferTexture2D) - CHECK_PRESENT(glFramebufferTexture3D) - CHECK_PRESENT(glFramebufferTextureLayer) - CHECK_PRESENT(glFrontFace) - CHECK_PRESENT(glGenBuffers) - CHECK_PRESENT(glGenFramebuffers) - CHECK_PRESENT(glGenProgramPipelines) - CHECK_PRESENT(glGenQueries) - CHECK_PRESENT(glGenSamplers) - CHECK_PRESENT(glGenTextures) - CHECK_PRESENT(glGenTransformFeedbacks) - CHECK_PRESENT(glGenVertexArrays) - CHECK_PRESENT(glGetActiveAtomicCounterBufferiv) - CHECK_PRESENT(glGetActiveUniformBlockiv) - CHECK_PRESENT(glGetAttribLocation) - CHECK_PRESENT(glGetBooleani_v) - CHECK_PRESENT(glGetBooleanv) - CHECK_PRESENT(glGetBufferParameteriv) - CHECK_PRESENT(glGetBufferSubData) - CHECK_PRESENT(glGetCompressedTexImage) - CHECK_PRESENT(glGetDoublei_v) - CHECK_PRESENT(glGetDoublev) - CHECK_PRESENT(glGetError) - CHECK_PRESENT(glGetFloati_v) - CHECK_PRESENT(glGetFloatv) - CHECK_PRESENT(glGetFragDataLocation) - CHECK_PRESENT(glGetFramebufferAttachmentParameteriv) - CHECK_PRESENT(glGetInteger64i_v) - CHECK_PRESENT(glGetIntegeri_v) - CHECK_PRESENT(glGetIntegerv) - CHECK_PRESENT(glGetInternalformativ) - CHECK_PRESENT(glGetObjectLabel) - CHECK_PRESENT(glGetProgramInfoLog) - CHECK_PRESENT(glGetProgramInterfaceiv) - CHECK_PRESENT(glGetProgramiv) - CHECK_PRESENT(glGetProgramPipelineiv) - CHECK_PRESENT(glGetProgramResourceIndex) - CHECK_PRESENT(glGetProgramResourceiv) - CHECK_PRESENT(glGetProgramResourceName) - CHECK_PRESENT(glGetProgramStageiv) - CHECK_PRESENT(glGetQueryObjectuiv) - CHECK_PRESENT(glGetSamplerParameterfv) - CHECK_PRESENT(glGetSamplerParameteriv) - CHECK_PRESENT(glGetShaderInfoLog) - CHECK_PRESENT(glGetShaderiv) - CHECK_PRESENT(glGetString) - CHECK_PRESENT(glGetStringi) - CHECK_PRESENT(glGetTexImage) - CHECK_PRESENT(glGetTexLevelParameteriv) - CHECK_PRESENT(glGetTexParameterfv) - CHECK_PRESENT(glGetTexParameteriv) - CHECK_PRESENT(glGetUniformBlockIndex) - CHECK_PRESENT(glGetUniformdv) - CHECK_PRESENT(glGetUniformfv) - CHECK_PRESENT(glGetUniformiv) - CHECK_PRESENT(glGetUniformLocation) - CHECK_PRESENT(glGetUniformSubroutineuiv) - CHECK_PRESENT(glGetUniformuiv) - CHECK_PRESENT(glGetVertexAttribfv) - CHECK_PRESENT(glGetVertexAttribiv) - CHECK_PRESENT(glHint) - CHECK_PRESENT(glIsEnabled) - CHECK_PRESENT(glIsEnabledi) - CHECK_PRESENT(glLineWidth) - CHECK_PRESENT(glLinkProgram) - CHECK_PRESENT(glLogicOp) - CHECK_PRESENT(glMapBufferRange) - CHECK_PRESENT(glMinSampleShading) - CHECK_PRESENT(glObjectLabel) - CHECK_PRESENT(glPatchParameterfv) - CHECK_PRESENT(glPatchParameteri) - CHECK_PRESENT(glPixelStorei) - CHECK_PRESENT(glPointParameterf) - CHECK_PRESENT(glPointParameteri) - CHECK_PRESENT(glPointSize) - CHECK_PRESENT(glPolygonMode) - CHECK_PRESENT(glPolygonOffset) - CHECK_PRESENT(glPrimitiveRestartIndex) - CHECK_PRESENT(glProgramParameteri) - CHECK_PRESENT(glProgramUniform1dv) - CHECK_PRESENT(glProgramUniform1fv) - CHECK_PRESENT(glProgramUniform1iv) - CHECK_PRESENT(glProgramUniform1ui) - CHECK_PRESENT(glProgramUniform1uiv) - CHECK_PRESENT(glProgramUniform2dv) - CHECK_PRESENT(glProgramUniform2fv) - CHECK_PRESENT(glProgramUniform2iv) - CHECK_PRESENT(glProgramUniform2uiv) - CHECK_PRESENT(glProgramUniform3dv) - CHECK_PRESENT(glProgramUniform3fv) - CHECK_PRESENT(glProgramUniform3iv) - CHECK_PRESENT(glProgramUniform3uiv) - CHECK_PRESENT(glProgramUniform4dv) - CHECK_PRESENT(glProgramUniform4fv) - CHECK_PRESENT(glProgramUniform4iv) - CHECK_PRESENT(glProgramUniform4ui) - CHECK_PRESENT(glProgramUniform4uiv) - CHECK_PRESENT(glProgramUniformMatrix2dv) - CHECK_PRESENT(glProgramUniformMatrix2fv) - CHECK_PRESENT(glProgramUniformMatrix2x3dv) - CHECK_PRESENT(glProgramUniformMatrix2x3fv) - CHECK_PRESENT(glProgramUniformMatrix2x4dv) - CHECK_PRESENT(glProgramUniformMatrix2x4fv) - CHECK_PRESENT(glProgramUniformMatrix3dv) - CHECK_PRESENT(glProgramUniformMatrix3fv) - CHECK_PRESENT(glProgramUniformMatrix3x2dv) - CHECK_PRESENT(glProgramUniformMatrix3x2fv) - CHECK_PRESENT(glProgramUniformMatrix3x4dv) - CHECK_PRESENT(glProgramUniformMatrix3x4fv) - CHECK_PRESENT(glProgramUniformMatrix4dv) - CHECK_PRESENT(glProgramUniformMatrix4fv) - CHECK_PRESENT(glProgramUniformMatrix4x2dv) - CHECK_PRESENT(glProgramUniformMatrix4x2fv) - CHECK_PRESENT(glProgramUniformMatrix4x3dv) - CHECK_PRESENT(glProgramUniformMatrix4x3fv) - CHECK_PRESENT(glProvokingVertex) - CHECK_PRESENT(glReadBuffer) - CHECK_PRESENT(glReadPixels) - CHECK_PRESENT(glSampleCoverage) - CHECK_PRESENT(glSampleMaski) - CHECK_PRESENT(glSamplerParameteri) - CHECK_PRESENT(glScissorIndexedv) - CHECK_PRESENT(glShaderSource) - CHECK_PRESENT(glShaderStorageBlockBinding) - CHECK_PRESENT(glStencilFuncSeparate) - CHECK_PRESENT(glStencilMask) - CHECK_PRESENT(glStencilMaskSeparate) - CHECK_PRESENT(glStencilOpSeparate) - CHECK_PRESENT(glTexImage2D) - CHECK_PRESENT(glTexParameteri) - CHECK_PRESENT(glTexStorage2D) - CHECK_PRESENT(glTextureView) - CHECK_PRESENT(glTransformFeedbackVaryings) - CHECK_PRESENT(glUniform1i) - CHECK_PRESENT(glUniform1ui) - CHECK_PRESENT(glUniform2f) - CHECK_PRESENT(glUniform2fv) - CHECK_PRESENT(glUniform4fv) - CHECK_PRESENT(glUniformBlockBinding) - CHECK_PRESENT(glUniformMatrix4fv) - CHECK_PRESENT(glUniformSubroutinesuiv) - CHECK_PRESENT(glUnmapBuffer) - CHECK_PRESENT(glUseProgram) - CHECK_PRESENT(glUseProgramStages) - CHECK_PRESENT(glVertexAttrib4fv) - CHECK_PRESENT(glVertexAttribBinding) - CHECK_PRESENT(glVertexAttribFormat) - CHECK_PRESENT(glVertexAttribIFormat) - CHECK_PRESENT(glVertexAttribLFormat) - CHECK_PRESENT(glVertexAttribPointer) - CHECK_PRESENT(glVertexBindingDivisor) - CHECK_PRESENT(glViewport) - CHECK_PRESENT(glViewportArrayv) - CHECK_PRESENT(glViewportIndexedf) - - // these functions should be present as part of EXT_direct_state_access, - // and ARB_buffer_storage. Let's verify - CHECK_PRESENT(glCompressedTextureImage1DEXT) - CHECK_PRESENT(glCompressedTextureImage2DEXT) - CHECK_PRESENT(glCompressedTextureImage3DEXT) - CHECK_PRESENT(glCompressedTextureSubImage1DEXT) - CHECK_PRESENT(glCompressedTextureSubImage2DEXT) - CHECK_PRESENT(glCompressedTextureSubImage3DEXT) - CHECK_PRESENT(glGetCompressedTextureImageEXT) - CHECK_PRESENT(glGetNamedBufferParameterivEXT) - CHECK_PRESENT(glGetNamedBufferSubDataEXT) - CHECK_PRESENT(glGetNamedFramebufferAttachmentParameterivEXT) - CHECK_PRESENT(glGetTextureLevelParameterivEXT) - CHECK_PRESENT(glGetTextureParameterfvEXT) - CHECK_PRESENT(glGetTextureParameterivEXT) - CHECK_PRESENT(glMapNamedBufferEXT) - CHECK_PRESENT(glNamedBufferDataEXT) - CHECK_PRESENT(glNamedBufferStorageEXT) // needs ARB_buffer_storage as well - CHECK_PRESENT(glNamedBufferSubDataEXT) - CHECK_PRESENT(glNamedFramebufferRenderbufferEXT) - CHECK_PRESENT(glNamedFramebufferTextureEXT) - CHECK_PRESENT(glNamedFramebufferTextureLayerEXT) - CHECK_PRESENT(glTextureImage1DEXT) - CHECK_PRESENT(glTextureImage2DEXT) - CHECK_PRESENT(glTextureImage3DEXT) - CHECK_PRESENT(glTextureParameterfvEXT) - CHECK_PRESENT(glTextureParameterivEXT) - CHECK_PRESENT(glTextureStorage1DEXT) - CHECK_PRESENT(glTextureStorage2DEXT) - CHECK_PRESENT(glTextureStorage2DMultisampleEXT) - CHECK_PRESENT(glTextureStorage3DEXT) - CHECK_PRESENT(glTextureStorage3DMultisampleEXT) - CHECK_PRESENT(glTextureSubImage1DEXT) - CHECK_PRESENT(glTextureSubImage2DEXT) - CHECK_PRESENT(glTextureSubImage3DEXT) - CHECK_PRESENT(glUnmapNamedBufferEXT) - - // other functions are either checked for presence explicitly (like - // depth bounds or polygon offset clamp EXT functions), or they are - // only called when such a call is serialised from the logfile, and - // so they are checked for validity separately. - WrappedOpenGL *gl = new WrappedOpenGL(logfile, real); gl->Initialise(initParams);