Use the baseEventID for checking if a glMultiDraw* is valid

Prevents driver crash is invalid data is passed to glMultiDraw* i.e. no vertex buffers.
This commit is contained in:
Jake Turner
2025-01-08 10:29:10 +00:00
parent 898e4e0028
commit 10500d0327
2 changed files with 24 additions and 16 deletions
+1
View File
@@ -604,6 +604,7 @@ private:
// final check function to ensure we don't try and render with no index or vertex buffer bound, as
// many drivers will still try to access memory via legacy behaviour even on core profile.
bool Check_SafeDraw(bool indexed);
bool Check_SafeDrawAtEventID(uint32_t eid) const;
void StoreCompressedTexData(ResourceId texId, GLenum target, GLint level, bool subUpdate,
GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width,
+23 -16
View File
@@ -158,10 +158,15 @@ static constexpr uint32_t GetIdxSize(GLenum idxtype)
return (idxtype == eGL_UNSIGNED_BYTE ? 1 : (idxtype == eGL_UNSIGNED_SHORT ? 2 : 4));
}
bool WrappedOpenGL::Check_SafeDrawAtEventID(uint32_t eid) const
{
return m_UnsafeDraws.find(eid) == m_UnsafeDraws.end();
}
bool WrappedOpenGL::Check_SafeDraw(bool indexed)
{
if(IsActiveReplaying(m_State))
return m_UnsafeDraws.find(m_CurEventID) == m_UnsafeDraws.end();
return Check_SafeDrawAtEventID(m_CurEventID);
bool ret = true;
@@ -2255,8 +2260,9 @@ bool WrappedOpenGL::Serialise_glMultiDrawArrays(SerialiserType &ser, GLenum mode
// if we're replaying part-way into a multidraw, we can replay the first part 'easily'
// by just reducing the drawcount parameter to however many we want to replay. This only
// works if we're replaying from the first multidraw to the nth (n less than drawcount)
GL.glMultiDrawArrays(mode, first, count,
RDCMIN((uint32_t)drawcount, m_LastEventID - baseEventID));
if(drawcount == 0 || count == 0 || Check_SafeDrawAtEventID(baseEventID))
GL.glMultiDrawArrays(mode, first, count,
RDCMIN((uint32_t)drawcount, m_LastEventID - baseEventID));
m_CurEventID += (uint32_t)drawcount;
}
@@ -2278,7 +2284,8 @@ bool WrappedOpenGL::Serialise_glMultiDrawArrays(SerialiserType &ser, GLenum mode
for(uint32_t d = 0; d < firstDrawIdx; d++)
modcount[d] = 0;
GL.glMultiDrawArrays(mode, first, count, lastDrawIdx + 1);
if(count == 0 || Check_SafeDrawAtEventID(baseEventID))
GL.glMultiDrawArrays(mode, first, count, lastDrawIdx + 1);
m_CurEventID += (uint32_t)RDCMIN((uint32_t)drawcount, lastDrawIdx - firstDrawIdx);
}
@@ -2423,7 +2430,7 @@ bool WrappedOpenGL::Serialise_glMultiDrawElements(SerialiserType &ser, GLenum mo
// if we're replaying part-way into a multidraw, we can replay the first part 'easily'
// by just reducing the Count parameter to however many we want to replay. This only
// works if we're replaying from the first multidraw to the nth (n less than Count)
if(drawcount == 0 || count == 0 || Check_SafeDraw(true))
if(drawcount == 0 || count == 0 || Check_SafeDrawAtEventID(baseEventID))
GL.glMultiDrawElements(mode, count, type, inds.data(),
RDCMIN((uint32_t)drawcount, m_LastEventID - baseEventID));
@@ -2447,7 +2454,7 @@ bool WrappedOpenGL::Serialise_glMultiDrawElements(SerialiserType &ser, GLenum mo
for(uint32_t d = 0; d < firstDrawIdx; d++)
modcount[d] = 0;
if(count == 0 || Check_SafeDraw(true))
if(count == 0 || Check_SafeDrawAtEventID(baseEventID))
GL.glMultiDrawElements(mode, count, type, inds.data(), lastDrawIdx + 1);
m_CurEventID += (uint32_t)RDCMIN((uint32_t)drawcount, lastDrawIdx - firstDrawIdx);
@@ -2596,7 +2603,7 @@ bool WrappedOpenGL::Serialise_glMultiDrawElementsBaseVertex(SerialiserType &ser,
// if we're replaying part-way into a multidraw, we can replay the first part 'easily'
// by just reducing the Count parameter to however many we want to replay. This only
// works if we're replaying from the first multidraw to the nth (n less than Count)
if(count == 0 || Check_SafeDraw(true))
if(count == 0 || Check_SafeDrawAtEventID(baseEventID))
GL.glMultiDrawElementsBaseVertex(mode, count, type, inds.data(),
RDCMIN((uint32_t)drawcount, m_LastEventID - baseEventID),
basevertex);
@@ -2621,7 +2628,7 @@ bool WrappedOpenGL::Serialise_glMultiDrawElementsBaseVertex(SerialiserType &ser,
for(uint32_t d = 0; d < firstDrawIdx; d++)
modcount[d] = 0;
if(count == 0 || Check_SafeDraw(true))
if(count == 0 || Check_SafeDrawAtEventID(baseEventID))
GL.glMultiDrawElementsBaseVertex(mode, count, type, inds.data(), lastDrawIdx + 1,
basevertex);
@@ -2788,7 +2795,7 @@ bool WrappedOpenGL::Serialise_glMultiDrawArraysIndirect(SerialiserType &ser, GLe
// if we're replaying part-way into a multidraw, we can replay the first part 'easily'
// by just reducing the Count parameter to however many we want to replay. This only
// works if we're replaying from the first multidraw to the nth (n less than Count)
if(drawcount == 0 || Check_SafeDraw(false))
if(drawcount == 0 || Check_SafeDrawAtEventID(baseEventID))
GL.glMultiDrawArraysIndirect(mode, (const void *)offset,
RDCMIN((uint32_t)drawcount, m_LastEventID - baseEventID),
stride);
@@ -2841,7 +2848,7 @@ bool WrappedOpenGL::Serialise_glMultiDrawArraysIndirect(SerialiserType &ser, GLe
// the offset is 0 because it's referring to our custom buffer, stride is 0 because we
// tightly pack.
if(Check_SafeDraw(false))
if(Check_SafeDrawAtEventID(baseEventID))
GL.glMultiDrawArraysIndirect(mode, (const void *)0, lastDrawIdx + 1, 0);
GL.glBindBuffer(eGL_DRAW_INDIRECT_BUFFER, prevBuf);
@@ -3018,7 +3025,7 @@ bool WrappedOpenGL::Serialise_glMultiDrawElementsIndirect(SerialiserType &ser, G
// if we're replaying part-way into a multidraw, we can replay the first part 'easily'
// by just reducing the Count parameter to however many we want to replay. This only
// works if we're replaying from the first multidraw to the nth (n less than Count)
if(Check_SafeDraw(true))
if(Check_SafeDrawAtEventID(baseEventID))
GL.glMultiDrawElementsIndirect(mode, type, (const void *)offset,
RDCMIN((uint32_t)drawcount, m_LastEventID - baseEventID),
stride);
@@ -3071,7 +3078,7 @@ bool WrappedOpenGL::Serialise_glMultiDrawElementsIndirect(SerialiserType &ser, G
// the offset is 0 because it's referring to our custom buffer, stride is 0 because we
// tightly pack.
if(Check_SafeDraw(true))
if(Check_SafeDrawAtEventID(baseEventID))
GL.glMultiDrawElementsIndirect(mode, type, (const void *)0, lastDrawIdx + 1, 0);
GL.glBindBuffer(eGL_DRAW_INDIRECT_BUFFER, prevBuf);
@@ -3256,7 +3263,7 @@ bool WrappedOpenGL::Serialise_glMultiDrawArraysIndirectCount(SerialiserType &ser
// if we're replaying part-way into a multidraw, we can replay the first part 'easily'
// by just reducing the Count parameter to however many we want to replay. This only
// works if we're replaying from the first multidraw to the nth (n less than Count)
if(maxdrawcount == 0 || Check_SafeDraw(false))
if(maxdrawcount == 0 || Check_SafeDrawAtEventID(baseEventID))
GL.glMultiDrawArraysIndirect(mode, (const void *)offset,
RDCMIN((uint32_t)realdrawcount, m_LastEventID - baseEventID),
stride);
@@ -3309,7 +3316,7 @@ bool WrappedOpenGL::Serialise_glMultiDrawArraysIndirectCount(SerialiserType &ser
// the offset is 0 because it's referring to our custom buffer, stride is 0 because we
// tightly pack.
if(Check_SafeDraw(false))
if(Check_SafeDrawAtEventID(baseEventID))
GL.glMultiDrawArraysIndirect(mode, (const void *)0, lastDrawIdx + 1, 0);
GL.glBindBuffer(eGL_DRAW_INDIRECT_BUFFER, prevBuf);
@@ -3503,7 +3510,7 @@ bool WrappedOpenGL::Serialise_glMultiDrawElementsIndirectCount(SerialiserType &s
// if we're replaying part-way into a multidraw, we can replay the first part 'easily'
// by just reducing the Count parameter to however many we want to replay. This only
// works if we're replaying from the first multidraw to the nth (n less than Count)
if(maxdrawcount == 0 || Check_SafeDraw(true))
if(maxdrawcount == 0 || Check_SafeDrawAtEventID(baseEventID))
GL.glMultiDrawElementsIndirect(
mode, type, (const void *)offset,
RDCMIN((uint32_t)realdrawcount, m_LastEventID - baseEventID), stride);
@@ -3556,7 +3563,7 @@ bool WrappedOpenGL::Serialise_glMultiDrawElementsIndirectCount(SerialiserType &s
// the offset is 0 because it's referring to our custom buffer, stride is 0 because we
// tightly pack.
if(maxdrawcount == 0 || Check_SafeDraw(true))
if(maxdrawcount == 0 || Check_SafeDrawAtEventID(baseEventID))
GL.glMultiDrawElementsIndirect(mode, type, (const void *)0, lastDrawIdx + 1, 0);
GL.glBindBuffer(eGL_DRAW_INDIRECT_BUFFER, prevBuf);