When replaying specific GL extension functions, check availability

* In theory we should check everywhere on every function otherwise we crash with
  a NULL pointer, but figuring out which functions to check is non-trivial in
  some cases and there's the risk of false positives with fallbacks available
  etc in cases where there are several possible alternatives for a given
  function.
* These checks have been sprinkled around in places where it's safe because
  there's only one implementation of a function that never made it to core, as
  well as the most common problems - glFramebufferTexture2DMultisampleEXT and
  glFramebufferTextureMultiviewOVR/glFramebufferTextureMultisampleMultiviewOVR
  which comes from users mistakenly replaying a mobile capture on desktop. This
  is not expected to work but it shouldn't crash.
This commit is contained in:
baldurk
2019-04-04 11:49:30 +01:00
parent c7ea78022c
commit d44a00c898
7 changed files with 68 additions and 0 deletions
+10
View File
@@ -428,6 +428,16 @@ T CheckConstParam(T t);
// Writing is unambiguously during capture mode, so we don't have to check both in that case.
#define IsReplayingAndReading() (ser.IsReading() && IsReplayMode(m_State))
// on GL we don't have an easy way of checking which functions/extensions were used or which
// functions/extensions on replay could suffice. So we check at the last minute on replay and bail
// out if it's not present
#define CheckReplayFunctionPresent(func) \
if(func == NULL) \
{ \
m_FailedReplayStatus = ReplayStatus::APIHardwareUnsupported; \
return false; \
}
// no longer in glcorearb.h or glext.h
const GLenum eGL_LIGHTING = (GLenum)0x0B50;
const GLenum eGL_ALPHA_TEST = (GLenum)0x0BC0;
@@ -308,6 +308,8 @@ bool WrappedOpenGL::Serialise_glDispatchComputeGroupSizeARB(SerialiserType &ser,
if(IsReplayingAndReading())
{
CheckReplayFunctionPresent(GL.glDispatchComputeGroupSizeARB);
GL.glDispatchComputeGroupSizeARB(num_groups_x, num_groups_y, num_groups_z, group_size_x,
group_size_y, group_size_z);
@@ -408,6 +410,8 @@ bool WrappedOpenGL::Serialise_glDispatchComputeIndirect(SerialiserType &ser, GLi
if(IsReplayingAndReading())
{
CheckReplayFunctionPresent(GL.glDispatchComputeIndirect);
GL.glDispatchComputeIndirect((GLintptr)offset);
if(IsLoading(m_State))
@@ -1094,6 +1098,8 @@ bool WrappedOpenGL::Serialise_glDrawArraysIndirect(SerialiserType &ser, GLenum m
if(IsReplayingAndReading())
{
CheckReplayFunctionPresent(GL.glDrawArraysIndirect);
if(Check_SafeDraw(false))
GL.glDrawArraysIndirect(mode, (const void *)offset);
@@ -1397,6 +1403,8 @@ bool WrappedOpenGL::Serialise_glDrawElementsIndirect(SerialiserType &ser, GLenum
if(IsReplayingAndReading())
{
CheckReplayFunctionPresent(GL.glDrawElementsIndirect);
if(Check_SafeDraw(true))
GL.glDrawElementsIndirect(mode, type, (const void *)offset);
@@ -2529,6 +2537,8 @@ bool WrappedOpenGL::Serialise_glMultiDrawArraysIndirect(SerialiserType &ser, GLe
{
if(IsLoading(m_State))
{
CheckReplayFunctionPresent(GL.glMultiDrawArraysIndirect);
if(Check_SafeDraw(false))
GL.glMultiDrawArraysIndirect(mode, (const void *)offset, drawcount, stride);
@@ -2743,6 +2753,8 @@ bool WrappedOpenGL::Serialise_glMultiDrawElementsIndirect(SerialiserType &ser, G
{
if(IsLoading(m_State))
{
CheckReplayFunctionPresent(GL.glMultiDrawElementsIndirect);
GLRenderState state;
state.FetchState(this);
@@ -2970,6 +2982,8 @@ bool WrappedOpenGL::Serialise_glMultiDrawArraysIndirectCount(SerialiserType &ser
if(IsLoading(m_State))
{
CheckReplayFunctionPresent(GL.glMultiDrawArraysIndirectCount);
if(Check_SafeDraw(false))
GL.glMultiDrawArraysIndirectCount(mode, (const void *)offset, (GLintptr)drawcount,
maxdrawcount, stride);
@@ -3196,6 +3210,8 @@ bool WrappedOpenGL::Serialise_glMultiDrawElementsIndirectCount(SerialiserType &s
if(IsLoading(m_State))
{
CheckReplayFunctionPresent(GL.glMultiDrawElementsIndirectCount);
if(Check_SafeDraw(true))
GL.glMultiDrawElementsIndirectCount(mode, type, (const void *)offset, (GLintptr)drawcount,
maxdrawcount, stride);
@@ -599,6 +599,8 @@ bool WrappedOpenGL::Serialise_glFramebufferTexture2DMultisampleEXT(
if(IsReplayingAndReading())
{
CheckReplayFunctionPresent(GL.glFramebufferTexture2DMultisampleEXT);
if(framebuffer.name == 0)
framebuffer.name = m_CurrentDefaultFBO;
@@ -1137,6 +1139,8 @@ bool WrappedOpenGL::Serialise_glFramebufferTextureMultiviewOVR(SerialiserType &s
if(IsReplayingAndReading())
{
CheckReplayFunctionPresent(GL.glFramebufferTextureMultiviewOVR);
GL.glFramebufferTextureMultiviewOVR(target, attachment, texture.name, level, baseViewIndex,
numViews);
@@ -1253,6 +1257,8 @@ bool WrappedOpenGL::Serialise_glFramebufferTextureMultisampleMultiviewOVR(
if(IsReplayingAndReading())
{
CheckReplayFunctionPresent(GL.glFramebufferTextureMultisampleMultiviewOVR);
GL.glFramebufferTextureMultisampleMultiviewOVR(target, attachment, texture.name, level, samples,
baseViewIndex, numViews);
@@ -2403,6 +2409,10 @@ bool WrappedOpenGL::Serialise_glNamedRenderbufferStorageMultisampleEXT(Serialise
if(IsReplayingAndReading())
{
// the DSA function is emulated if not present, but we need to check the underlying function is
// present
CheckReplayFunctionPresent(GL.glRenderbufferStorageMultisample);
ResourceId liveId = GetResourceManager()->GetID(renderbuffer);
TextureData &texDetails = m_Textures[liveId];
@@ -2596,6 +2606,8 @@ bool WrappedOpenGL::Serialise_glRenderbufferStorageMultisampleEXT(SerialiserType
if(IsReplayingAndReading())
{
CheckReplayFunctionPresent(GL.glRenderbufferStorageMultisampleEXT);
ResourceId liveId = GetResourceManager()->GetID(renderbuffer);
TextureData &texDetails = m_Textures[liveId];
@@ -541,6 +541,8 @@ bool WrappedOpenGL::Serialise_glCreateMemoryObjectsEXT(SerialiserType &ser, GLsi
if(IsReplayingAndReading())
{
CheckReplayFunctionPresent(GL.glCreateMemoryObjectsEXT);
GLuint real = 0;
GL.glCreateMemoryObjectsEXT(1, &real);
@@ -621,6 +623,8 @@ bool WrappedOpenGL::Serialise_glMemoryObjectParameterivEXT(SerialiserType &ser,
if(IsReplayingAndReading())
{
CheckReplayFunctionPresent(GL.glMemoryObjectParameterivEXT);
GL.glMemoryObjectParameterivEXT(memoryObject.name, pname, params);
AddResourceInitChunk(memoryObject);
@@ -812,6 +816,8 @@ bool WrappedOpenGL::Serialise_glGenSemaphoresEXT(SerialiserType &ser, GLsizei n,
if(IsReplayingAndReading())
{
CheckReplayFunctionPresent(GL.glGenSemaphoresEXT);
GLuint real = 0;
GL.glGenSemaphoresEXT(1, &real);
@@ -892,6 +898,8 @@ bool WrappedOpenGL::Serialise_glSemaphoreParameterui64vEXT(SerialiserType &ser,
if(IsReplayingAndReading())
{
CheckReplayFunctionPresent(GL.glSemaphoreParameterui64vEXT);
GL.glSemaphoreParameterui64vEXT(semaphore.name, pname, params);
AddResourceInitChunk(semaphore);
@@ -1633,6 +1641,10 @@ bool WrappedOpenGL::Serialise_glTextureStorageMem2DMultisampleEXT(
if(IsReplayingAndReading())
{
// the DSA function is emulated if not present, but we need to check the underlying function is
// present
CheckReplayFunctionPresent(GL.glTexStorage2DMultisample);
// Replay external texture storage backed by external memory as just a plain texture.
ResourceId liveId = GetResourceManager()->GetID(texture);
m_Textures[liveId].width = width;
@@ -1755,6 +1755,8 @@ bool WrappedOpenGL::Serialise_glCompileShaderIncludeARB(SerialiserType &ser, GLu
if(IsReplayingAndReading())
{
CheckReplayFunctionPresent(GL.glCompileShaderIncludeARB);
ResourceId liveId = GetResourceManager()->GetID(shader);
auto &shadDetails = m_Shaders[liveId];
@@ -1828,6 +1830,8 @@ bool WrappedOpenGL::Serialise_glNamedStringARB(SerialiserType &ser, GLenum type,
if(IsReplayingAndReading())
{
CheckReplayFunctionPresent(GL.glNamedStringARB);
GL.glNamedStringARB(type, (GLint)name.length(), name.c_str(), (GLint)value.length(),
value.c_str());
}
@@ -1865,6 +1869,8 @@ bool WrappedOpenGL::Serialise_glDeleteNamedStringARB(SerialiserType &ser, GLint
if(IsReplayingAndReading())
{
CheckReplayFunctionPresent(GL.glDeleteNamedStringARB);
GL.glDeleteNamedStringARB((GLint)name.length(), name.c_str());
}
@@ -1913,6 +1919,8 @@ bool WrappedOpenGL::Serialise_glSpecializeShader(SerialiserType &ser, GLuint sha
if(IsReplayingAndReading())
{
CheckReplayFunctionPresent(GL.glSpecializeShader);
ResourceId liveId = GetResourceManager()->GetID(shader);
GL.glSpecializeShader(shader.name, pEntryPoint, numSpecializationConstants, pConstantIndex,
@@ -923,6 +923,8 @@ bool WrappedOpenGL::Serialise_glDepthBoundsEXT(SerialiserType &ser, GLclampd nea
if(IsReplayingAndReading())
{
CheckReplayFunctionPresent(GL.glDepthBoundsEXT);
GL.glDepthBoundsEXT(nearVal, farVal);
}
@@ -1418,6 +1420,8 @@ bool WrappedOpenGL::Serialise_glRasterSamplesEXT(SerialiserType &ser, GLuint sam
if(IsReplayingAndReading())
{
CheckReplayFunctionPresent(GL.glRasterSamplesEXT);
GL.glRasterSamplesEXT(samples, fixedsamplelocations ? GL_TRUE : GL_FALSE);
}
@@ -1915,6 +1919,8 @@ bool WrappedOpenGL::Serialise_glPolygonOffsetClamp(SerialiserType &ser, GLfloat
if(IsReplayingAndReading())
{
CheckReplayFunctionPresent(GL.glPolygonOffsetClamp);
GL.glPolygonOffsetClamp(factor, units, clamp);
}
@@ -1953,6 +1959,8 @@ bool WrappedOpenGL::Serialise_glPrimitiveBoundingBox(SerialiserType &ser, GLfloa
if(IsReplayingAndReading())
{
CheckReplayFunctionPresent(GL.glPrimitiveBoundingBox);
GL.glPrimitiveBoundingBox(minX, minY, minZ, minW, maxX, maxY, maxZ, maxW);
}
@@ -6352,6 +6352,8 @@ bool WrappedOpenGL::Serialise_glTextureFoveationParametersQCOM(SerialiserType &s
if(IsReplayingAndReading())
{
CheckReplayFunctionPresent(GL.glTextureFoveationParametersQCOM);
GL.glTextureFoveationParametersQCOM(texture.name, layer, focalPoint, focalX, focalY, gainX,
gainY, foveaArea);