On glDrawArrays, copy client vertex arrays into temporary VBOs.

GLES allows drawing from client memory instead of VBOs. We keep a set of
buffers, one for each potential attribute, to bind the vertex attribute to
instead of the client array pointer. These buffers are then filled before
the draw call.
This commit is contained in:
Michael Rennie
2017-03-24 11:12:57 +00:00
committed by Baldur Karlsson
parent 6e06eb5164
commit 6bc0851121
6 changed files with 121 additions and 14 deletions
+18
View File
@@ -823,6 +823,24 @@ GLenum QueryEnum(size_t idx)
return eGL_NONE;
}
size_t GLTypeSize(GLenum type)
{
switch(type)
{
case eGL_UNSIGNED_BYTE:
case eGL_BYTE: return 1;
case eGL_UNSIGNED_SHORT:
case eGL_SHORT:
case eGL_HALF_FLOAT: return 2;
case eGL_UNSIGNED_INT:
case eGL_INT:
case eGL_FLOAT: return 4;
case eGL_DOUBLE: return 8;
default: RDCWARN("Unhandled element type %s", ToStr::Get(type).c_str());
}
return 0;
}
size_t ShaderIdx(GLenum buf)
{
switch(buf)
+2
View File
@@ -236,6 +236,8 @@ struct GLMarkerRegion
static const GLHookSet *gl;
};
size_t GLTypeSize(GLenum type);
size_t BufferIdx(GLenum buf);
GLenum BufferEnum(size_t idx);
+9
View File
@@ -1452,6 +1452,15 @@ void WrappedOpenGL::ActivateContext(GLWindowingData winData)
m_Internal = m_Real;
glEmulate::EmulateRequiredExtensions(&m_Real, &m_Internal);
// Initialize VBOs used in case we copy from client memory.
glGenBuffers(ARRAY_COUNT(ctxdata.m_ClientMemoryVBOs), ctxdata.m_ClientMemoryVBOs);
for(size_t i = 0; i < ARRAY_COUNT(ctxdata.m_ClientMemoryVBOs); i++)
{
glBindBuffer(eGL_ARRAY_BUFFER, ctxdata.m_ClientMemoryVBOs[i]);
glBufferData(eGL_ARRAY_BUFFER, 64, NULL, eGL_DYNAMIC_DRAW);
}
glBindBuffer(eGL_ARRAY_BUFFER, 0);
}
}
}
+20
View File
@@ -442,8 +442,28 @@ private:
GLuint m_Program;
GLResourceRecord *GetActiveTexRecord() { return m_TextureRecord[m_TextureUnit]; }
// GLES allows drawing from client memory, in which case we will copy to
// temporary VBOs so that input mesh data is recorded. See struct ClientMemoryData
GLuint m_ClientMemoryVBOs[16];
};
struct ClientMemoryData
{
struct VertexAttrib
{
GLuint index;
GLint size;
GLenum type;
GLboolean normalized;
GLsizei stride;
void *pointer;
};
std::vector<VertexAttrib> attribs;
GLuint prevArrayBufferBinding;
};
ClientMemoryData *CopyClientMemoryArrays(GLint first, GLsizei count);
void RestoreClientMemoryArrays(ClientMemoryData *clientMemoryArrays);
map<void *, ContextData> m_ContextData;
ContextData &GetCtxData();
+1 -14
View File
@@ -181,20 +181,7 @@ byte *PixelUnpackState::Unpack(byte *pixels, GLsizei width, GLsizei height, GLsi
size_t destrowstride = pixelSize * width;
size_t destimgstride = destrowstride * height;
size_t elemSize = 1;
switch(basetype)
{
case eGL_UNSIGNED_BYTE:
case eGL_BYTE: elemSize = 1; break;
case eGL_UNSIGNED_SHORT:
case eGL_SHORT:
case eGL_HALF_FLOAT: elemSize = 2; break;
case eGL_UNSIGNED_INT:
case eGL_INT:
case eGL_FLOAT: elemSize = 4; break;
case eGL_DOUBLE: elemSize = 8; break;
default: break;
}
size_t elemSize = GLTypeSize(basetype);
size_t allocsize = width * RDCMAX(1, height) * RDCMAX(1, depth) * pixelSize;
byte *ret = new byte[allocsize];
@@ -709,10 +709,75 @@ bool WrappedOpenGL::Serialise_glDrawArrays(GLenum mode, GLint first, GLsizei cou
return true;
}
WrappedOpenGL::ClientMemoryData *WrappedOpenGL::CopyClientMemoryArrays(GLint first, GLsizei count)
{
ContextData &cd = GetCtxData();
GLResourceRecord *varecord = cd.m_VertexArrayRecord;
if(m_State != WRITING_CAPFRAME || varecord) // Early out if VAO bound, as VAOs are VBO-only.
return NULL;
ClientMemoryData *clientMemory = new ClientMemoryData;
m_Real.glGetIntegerv(eGL_ARRAY_BUFFER_BINDING, (GLint *)&clientMemory->prevArrayBufferBinding);
for(GLuint i = 0; i < ARRAY_COUNT(cd.m_ClientMemoryVBOs); i++)
{
GLint enabled = 0;
m_Real.glGetVertexAttribiv(i, eGL_VERTEX_ATTRIB_ARRAY_ENABLED, &enabled);
if(!enabled)
continue;
// Check that the attrib is using client-memory.
GLuint buffer;
m_Real.glGetVertexAttribiv(i, eGL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, (GLint *)&buffer);
if(buffer != 0)
continue;
// App initially used client memory, so copy it into the temporary buffer.
ClientMemoryData::VertexAttrib attrib;
memset(&attrib, 0, sizeof(attrib));
attrib.index = i;
m_Real.glGetVertexAttribiv(i, eGL_VERTEX_ATTRIB_ARRAY_SIZE, &attrib.size);
m_Real.glGetVertexAttribiv(i, eGL_VERTEX_ATTRIB_ARRAY_TYPE, (GLint *)&attrib.type);
m_Real.glGetVertexAttribiv(i, eGL_VERTEX_ATTRIB_ARRAY_NORMALIZED, (GLint *)&attrib.normalized);
m_Real.glGetVertexAttribiv(i, eGL_VERTEX_ATTRIB_ARRAY_STRIDE, &attrib.stride);
m_Real.glGetVertexAttribPointerv(i, eGL_VERTEX_ATTRIB_ARRAY_POINTER, &attrib.pointer);
GLint totalStride = attrib.stride ? attrib.stride : (GLint)GLTypeSize(attrib.type) * attrib.size;
glBindBuffer(eGL_ARRAY_BUFFER, cd.m_ClientMemoryVBOs[i]);
// Copy all client memory, and the pointer becomes a zero offset.
glBufferData(eGL_ARRAY_BUFFER, (first + count) * totalStride, attrib.pointer, eGL_STATIC_DRAW);
glVertexAttribPointer(attrib.index, attrib.size, attrib.type, attrib.normalized, attrib.stride,
NULL);
clientMemory->attribs.push_back(attrib);
}
return clientMemory;
}
void WrappedOpenGL::RestoreClientMemoryArrays(ClientMemoryData *clientMemoryArrays)
{
if(!clientMemoryArrays)
return;
// Restore the 0-buffer bindings and attrib pointers.
glBindBuffer(eGL_ARRAY_BUFFER, 0);
for(const ClientMemoryData::VertexAttrib &attrib : clientMemoryArrays->attribs)
{
glVertexAttribPointer(attrib.index, attrib.size, attrib.type, attrib.normalized, attrib.stride,
attrib.pointer);
}
glBindBuffer(eGL_ARRAY_BUFFER, clientMemoryArrays->prevArrayBufferBinding);
delete clientMemoryArrays;
}
void WrappedOpenGL::glDrawArrays(GLenum mode, GLint first, GLsizei count)
{
CoherentMapImplicitBarrier();
ClientMemoryData *clientMemory = CopyClientMemoryArrays(first, count);
m_Real.glDrawArrays(mode, first, count);
if(m_State == WRITING_CAPFRAME)
@@ -731,6 +796,8 @@ void WrappedOpenGL::glDrawArrays(GLenum mode, GLint first, GLsizei count)
GLRenderState state(&m_Real, m_pSerialiser, m_State);
state.MarkDirty(this);
}
RestoreClientMemoryArrays(clientMemory);
}
bool WrappedOpenGL::Serialise_glDrawArraysIndirect(GLenum mode, const void *indirect)
@@ -849,6 +916,8 @@ void WrappedOpenGL::glDrawArraysInstanced(GLenum mode, GLint first, GLsizei coun
{
CoherentMapImplicitBarrier();
ClientMemoryData *clientMemory = CopyClientMemoryArrays(first, count);
m_Real.glDrawArraysInstanced(mode, first, count, instancecount);
if(m_State == WRITING_CAPFRAME)
@@ -867,6 +936,8 @@ void WrappedOpenGL::glDrawArraysInstanced(GLenum mode, GLint first, GLsizei coun
GLRenderState state(&m_Real, m_pSerialiser, m_State);
state.MarkDirty(this);
}
RestoreClientMemoryArrays(clientMemory);
}
bool WrappedOpenGL::Serialise_glDrawArraysInstancedBaseInstance(GLenum mode, GLint first,