mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-05-05 17:40:39 +00:00
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:
committed by
Baldur Karlsson
parent
6e06eb5164
commit
6bc0851121
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user