Move bound vertex buffers from general state to VAO state

This commit is contained in:
baldurk
2014-11-25 23:58:04 +00:00
parent 11d6ca5956
commit 16dd0b77f4
6 changed files with 113 additions and 100 deletions
+33
View File
@@ -170,6 +170,39 @@ GLenum ShaderEnum(size_t idx)
return eGL_NONE;
}
GLuint GetBoundVertexBuffer(const GLHookSet &gl, GLuint i)
{
static int hackAMDBugVBBinding = -1;
// linux AMD driver doesn't recognise GL_VERTEX_BINDING_BUFFER, see below.
if(hackAMDBugVBBinding == -1)
{
GLenum err = gl.glGetError();
while(err != eGL_NONE) err = gl.glGetError();
GLint dummy = 0;
gl.glGetIntegeri_v(eGL_VERTEX_BINDING_BUFFER, 0, &dummy);
err = gl.glGetError();
hackAMDBugVBBinding = (err == eGL_NONE ? 0 : 1);
if(hackAMDBugVBBinding)
RDCWARN("Using AMD hack to avoid GL_VERTEX_BINDING_BUFFER");
}
GLuint buffer = 0;
// the linux AMD driver has a "two wrongs make a right" type deal. Instead of returning the buffer that the
// i'th index is bound to (as above, vbslot) for GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, it returns the i'th
// vertex buffer which is exactly what we wanted from GL_VERTEX_BINDING_BUFFER!
// see: http://devgurus.amd.com/message/1306745#1306745
if(hackAMDBugVBBinding)
gl.glGetVertexAttribiv(i, eGL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, (GLint *)&buffer);
else
gl.glGetIntegeri_v(eGL_VERTEX_BINDING_BUFFER, i, (GLint *)&buffer);
return buffer;
}
ResourceFormat MakeResourceFormat(WrappedOpenGL &gl, GLenum target, GLenum fmt)
{
ResourceFormat ret;
+2
View File
@@ -82,6 +82,8 @@ GLenum ShaderEnum(size_t idx);
ResourceFormat MakeResourceFormat(WrappedOpenGL &gl, GLenum target, GLenum fmt);
GLenum MakeGLFormat(WrappedOpenGL &gl, GLenum target, ResourceFormat fmt);
GLuint GetBoundVertexBuffer(const GLHookSet &gl, GLuint idx);
extern int GLCoreVersion;
void UpdateExtensionSupport(const GLHookSet &gl);
bool ExtensionSupported(const char *ext);
+71 -23
View File
@@ -26,9 +26,9 @@
#include "driver/gl/gl_manager.h"
#include "driver/gl/gl_driver.h"
struct VertexArrayInitialData
struct VertexAttribInitialData
{
VertexArrayInitialData()
VertexAttribInitialData()
{
RDCEraseEl(*this);
}
@@ -41,8 +41,26 @@ struct VertexArrayInitialData
uint32_t size;
};
struct VertexBufferInitialData
{
VertexBufferInitialData()
{
RDCEraseEl(*this);
}
ResourceId Buffer;
uint64_t Stride;
uint64_t Offset;
uint32_t Divisor;
};
struct VAOInitialData
{
VertexAttribInitialData VertexAttribs[16];
VertexBufferInitialData VertexBuffers[16];
};
template<>
void Serialiser::Serialise(const char *name, VertexArrayInitialData &el)
void Serialiser::Serialise(const char *name, VertexAttribInitialData &el)
{
ScopedContext scope(this, this, name, "VertexArrayInitialData", 0, true);
Serialise("enabled", el.enabled);
@@ -54,6 +72,16 @@ void Serialiser::Serialise(const char *name, VertexArrayInitialData &el)
Serialise("size", el.size);
}
template<>
void Serialiser::Serialise(const char *name, VertexBufferInitialData &el)
{
ScopedContext scope(this, this, name, "VertexBufferInitialData", 0, true);
Serialise("Buffer", el.Buffer);
Serialise("Stride", el.Stride);
Serialise("Offset", el.Offset);
Serialise("Divisor", el.Divisor);
}
struct TextureStateInitialData
{
TextureStateInitialData()
@@ -240,17 +268,25 @@ bool GLResourceManager::Prepare_InitialState(GLResource res)
gl.glBindVertexArray(res.name);
VertexArrayInitialData *data = (VertexArrayInitialData *)Serialiser::AllocAlignedBuffer(sizeof(VertexArrayInitialData)*16);
VAOInitialData *data = (VAOInitialData *)Serialiser::AllocAlignedBuffer(sizeof(VAOInitialData));
for(GLuint i=0; i < 16; i++)
{
gl.glGetVertexAttribiv(i, eGL_VERTEX_ATTRIB_ARRAY_ENABLED, (GLint *)&data[i].enabled);
gl.glGetVertexAttribiv(i, eGL_VERTEX_ATTRIB_BINDING, (GLint *)&data[i].vbslot);
gl.glGetVertexAttribiv(i, eGL_VERTEX_ATTRIB_RELATIVE_OFFSET, (GLint*)&data[i].offset);
gl.glGetVertexAttribiv(i, eGL_VERTEX_ATTRIB_ARRAY_TYPE, (GLint *)&data[i].type);
gl.glGetVertexAttribiv(i, eGL_VERTEX_ATTRIB_ARRAY_NORMALIZED, (GLint *)&data[i].normalized);
gl.glGetVertexAttribiv(i, eGL_VERTEX_ATTRIB_ARRAY_INTEGER, (GLint *)&data[i].integer);
gl.glGetVertexAttribiv(i, eGL_VERTEX_ATTRIB_ARRAY_SIZE, (GLint *)&data[i].size);
gl.glGetVertexAttribiv(i, eGL_VERTEX_ATTRIB_ARRAY_ENABLED, (GLint *)&data->VertexAttribs[i].enabled);
gl.glGetVertexAttribiv(i, eGL_VERTEX_ATTRIB_BINDING, (GLint *)&data->VertexAttribs[i].vbslot);
gl.glGetVertexAttribiv(i, eGL_VERTEX_ATTRIB_RELATIVE_OFFSET, (GLint*)&data->VertexAttribs[i].offset);
gl.glGetVertexAttribiv(i, eGL_VERTEX_ATTRIB_ARRAY_TYPE, (GLint *)&data->VertexAttribs[i].type);
gl.glGetVertexAttribiv(i, eGL_VERTEX_ATTRIB_ARRAY_NORMALIZED, (GLint *)&data->VertexAttribs[i].normalized);
gl.glGetVertexAttribiv(i, eGL_VERTEX_ATTRIB_ARRAY_INTEGER, (GLint *)&data->VertexAttribs[i].integer);
gl.glGetVertexAttribiv(i, eGL_VERTEX_ATTRIB_ARRAY_SIZE, (GLint *)&data->VertexAttribs[i].size);
GLuint buffer = GetBoundVertexBuffer(gl, i);
data->VertexBuffers[i].Buffer = GetID(BufferRes(res.Context, buffer));
gl.glGetIntegeri_v(eGL_VERTEX_BINDING_STRIDE, i, (GLint *)&data->VertexBuffers[i].Stride);
gl.glGetIntegeri_v(eGL_VERTEX_BINDING_OFFSET, i, (GLint *)&data->VertexBuffers[i].Offset);
gl.glGetIntegeri_v(eGL_VERTEX_BINDING_DIVISOR, i, (GLint *)&data->VertexBuffers[i].Divisor);
}
SetInitialContents(Id, InitialContentData(GLResource(MakeNullResource), 0, (byte *)data));
@@ -687,21 +723,24 @@ bool GLResourceManager::Serialise_InitialState(GLResource res)
}
else if(res.Namespace == eResVertexArray)
{
VertexArrayInitialData data[16];
VAOInitialData data;
if(m_State >= WRITING)
{
VertexArrayInitialData *initialdata = (VertexArrayInitialData *)GetInitialContents(Id).blob;
memcpy(data, initialdata, sizeof(data));
VAOInitialData *initialdata = (VAOInitialData *)GetInitialContents(Id).blob;
memcpy(&data, initialdata, sizeof(data));
}
for(GLuint i=0; i < 16; i++)
m_pSerialiser->Serialise("data[]", data[i]);
{
m_pSerialiser->Serialise("VertexAttrib[]", data.VertexAttribs[i]);
m_pSerialiser->Serialise("VertexBuffer[]", data.VertexBuffers[i]);
}
if(m_State < WRITING)
{
byte *blob = Serialiser::AllocAlignedBuffer(sizeof(data));
memcpy(blob, data, sizeof(data));
memcpy(blob, &data, sizeof(data));
SetInitialContents(Id, InitialContentData(GLResource(MakeNullResource), 0, blob));
}
@@ -799,21 +838,30 @@ void GLResourceManager::Apply_InitialState(GLResource live, InitialContentData i
gl.glBindVertexArray(live.name);
VertexArrayInitialData *initialdata = (VertexArrayInitialData *)initial.blob;
VAOInitialData *initialdata = (VAOInitialData *)initial.blob;
for(GLuint i=0; i < 16; i++)
{
if(initialdata[i].enabled)
VertexAttribInitialData &attrib = initialdata->VertexAttribs[i];
if(attrib.enabled)
gl.glEnableVertexAttribArray(i);
else
gl.glDisableVertexAttribArray(i);
gl.glVertexAttribBinding(i, initialdata[i].vbslot);
gl.glVertexAttribBinding(i, attrib.vbslot);
if(initialdata[i].integer == 0)
gl.glVertexAttribFormat(i, initialdata[i].size, initialdata[i].type, (GLboolean)initialdata[i].normalized, initialdata[i].offset);
if(initialdata->VertexAttribs[i].integer == 0)
gl.glVertexAttribFormat(i, attrib.size, attrib.type, (GLboolean)attrib.normalized, attrib.offset);
else
gl.glVertexAttribIFormat(i, initialdata[i].size, initialdata[i].type, initialdata[i].offset);
gl.glVertexAttribIFormat(i, attrib.size, attrib.type, attrib.offset);
VertexBufferInitialData &buf = initialdata->VertexBuffers[i];
GLuint buffer = GetLiveResource(buf.Buffer).name;
gl.glBindVertexBuffer(i, buffer, (GLintptr)buf.Offset, (GLsizei)buf.Stride);
gl.glVertexBindingDivisor(i, buf.Divisor);
}
gl.glBindVertexArray(VAO);
-66
View File
@@ -95,53 +95,6 @@ void GLRenderState::FetchState()
m_Real->glGetIntegerv(eGL_VERTEX_ARRAY_BINDING, (GLint *)&VAO);
static int hackAMDBugVBBinding = -1;
if(hackAMDBugVBBinding == -1)
{
GLenum err = m_Real->glGetError();
while(err != eGL_NONE) err = m_Real->glGetError();
GLint dummy = 0;
m_Real->glGetIntegeri_v(eGL_VERTEX_BINDING_BUFFER, 0, &dummy);
err = m_Real->glGetError();
hackAMDBugVBBinding = (err == eGL_NONE ? 0 : 1);
if(hackAMDBugVBBinding)
RDCWARN("Using AMD hack to avoid GL_VERTEX_BINDING_BUFFER");
}
if(VAO != 0)
{
GLuint hackVAO = 0;
if(hackAMDBugVBBinding)
{
// create 'pass through' VAO so we can use GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING to fetch buffers
m_Real->glGenVertexArrays(1, &hackVAO);
m_Real->glBindVertexArray(hackVAO);
for(GLuint i=0; i < (GLuint)ARRAY_COUNT(VertexBuffers); i++)
m_Real->glVertexAttribBinding(i, i);
}
for(GLuint i=0; i < (GLuint)ARRAY_COUNT(VertexBuffers); i++)
{
if(hackAMDBugVBBinding)
m_Real->glGetVertexAttribiv(i, eGL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, (GLint *)&VertexBuffers[i].Buffer);
else
m_Real->glGetIntegeri_v(eGL_VERTEX_BINDING_BUFFER, i, (GLint *)&VertexBuffers[i].Buffer);
m_Real->glGetIntegeri_v(eGL_VERTEX_BINDING_STRIDE, i, (GLint *)&VertexBuffers[i].Stride);
m_Real->glGetIntegeri_v(eGL_VERTEX_BINDING_OFFSET, i, (GLint *)&VertexBuffers[i].Offset);
m_Real->glGetIntegeri_v(eGL_VERTEX_BINDING_DIVISOR, i, (GLint *)&VertexBuffers[i].Divisor);
}
if(hackAMDBugVBBinding)
{
m_Real->glBindVertexArray(VAO);
m_Real->glDeleteVertexArrays(1, &hackVAO);
}
}
// the spec says that you can only query for the format that was previously set, or you get
// undefined results. Ie. if someone set ints, this might return anything. However there's also
// no way to query for the type so we just have to hope for the best and hope most people are
@@ -367,14 +320,6 @@ void GLRenderState::ApplyState()
m_Real->glActiveTexture(ActiveTexture);
m_Real->glBindVertexArray(VAO);
if(VAO != 0)
{
for(GLuint i=0; i < (GLuint)ARRAY_COUNT(VertexBuffers); i++)
{
m_Real->glBindVertexBuffer(i, VertexBuffers[i].Buffer, (GLintptr)VertexBuffers[i].Offset, (GLsizei)VertexBuffers[i].Stride);
m_Real->glVertexBindingDivisor(i, VertexBuffers[i].Divisor);
}
}
// See FetchState(). The spec says that you have to SET the right format for the shader too,
// but we couldn't query for the format so we can't set it here.
@@ -568,7 +513,6 @@ void GLRenderState::Clear()
RDCEraseEl(Subroutines);
RDCEraseEl(VAO);
RDCEraseEl(VertexBuffers);
RDCEraseEl(GenericVertexAttribs);
@@ -652,16 +596,6 @@ void GLRenderState::Serialise(LogState state, void *ctx, WrappedOpenGL *gl)
m_pSerialiser->Serialise("GL_VERTEX_ARRAY_BINDING", ID);
if(state < WRITING && ID != ResourceId()) VAO = rm->GetLiveResource(ID).name;
}
for(size_t i=0; i < ARRAY_COUNT(VertexBuffers); i++)
{
ResourceId ID = ResourceId();
if(state >= WRITING) ID = rm->GetID(BufferRes(ctx, VertexBuffers[i].Buffer));
m_pSerialiser->Serialise("GL_VERTEX_BINDING_BUFFER", ID);
m_pSerialiser->Serialise("GL_VERTEX_BINDING_DIVISOR", VertexBuffers[i].Divisor);
m_pSerialiser->Serialise("GL_VERTEX_BINDING_OFFSET", VertexBuffers[i].Offset);
m_pSerialiser->Serialise("GL_VERTEX_BINDING_STRIDE", VertexBuffers[i].Stride);
if(state < WRITING && ID != ResourceId()) VertexBuffers[i].Buffer = rm->GetLiveResource(ID).name;
}
for(size_t i=0; i < ARRAY_COUNT(GenericVertexAttribs); i++)
{
-7
View File
@@ -106,13 +106,6 @@ struct GLRenderState
eBufIdx_Texture,
};
struct VertexBuffer
{
GLuint Buffer;
uint64_t Stride;
uint64_t Offset;
uint32_t Divisor;
} VertexBuffers[16];
GLuint VAO;
Vec4f GenericVertexAttribs[32];
+7 -4
View File
@@ -797,11 +797,14 @@ void GLReplay::SavePipelineState()
for(GLuint i=0; i < (GLuint)numVBufferBindings; i++)
{
pipe.m_VtxIn.vbuffers[i].Buffer = rm->GetOriginalID(rm->GetID(BufferRes(ctx, rs.VertexBuffers[i].Buffer)));
GLuint buffer = GetBoundVertexBuffer(gl.m_Real, i);
pipe.m_VtxIn.vbuffers[i].Buffer = rm->GetOriginalID(rm->GetID(BufferRes(ctx, buffer)));
gl.glGetIntegeri_v(eGL_VERTEX_BINDING_STRIDE, i, (GLint *)&pipe.m_VtxIn.vbuffers[i].Stride);
gl.glGetIntegeri_v(eGL_VERTEX_BINDING_OFFSET, i, (GLint *)&pipe.m_VtxIn.vbuffers[i].Offset);
gl.glGetIntegeri_v(eGL_VERTEX_BINDING_DIVISOR, i, (GLint *)&pipe.m_VtxIn.vbuffers[i].Divisor);
pipe.m_VtxIn.vbuffers[i].Stride = (uint32_t)rs.VertexBuffers[i].Stride;
pipe.m_VtxIn.vbuffers[i].Offset = (uint32_t)rs.VertexBuffers[i].Offset;
pipe.m_VtxIn.vbuffers[i].Divisor = rs.VertexBuffers[i].Divisor;
pipe.m_VtxIn.vbuffers[i].PerInstance = (pipe.m_VtxIn.vbuffers[i].Divisor != 0);
}