mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-05-12 13:00:32 +00:00
Improve glMap() handling, handle non-invalidate case etc.
This commit is contained in:
@@ -133,6 +133,8 @@ class WrappedOpenGL
|
||||
PerformanceTimer m_FrameTimer;
|
||||
vector<double> m_FrameTimes;
|
||||
double m_TotalTime, m_AvgFrametime, m_MinFrametime, m_MaxFrametime;
|
||||
|
||||
set<GLResource> m_HighTrafficResources;
|
||||
|
||||
vector<FetchFrameRecord> m_FrameRecord;
|
||||
|
||||
|
||||
@@ -97,8 +97,15 @@ struct GLResourceRecord : public ResourceRecord
|
||||
|
||||
GLResourceRecord(ResourceId id) :
|
||||
ResourceRecord(id, true),
|
||||
datatype(eGL_UNKNOWN_ENUM)
|
||||
datatype(eGL_UNKNOWN_ENUM),
|
||||
usage(eGL_UNKNOWN_ENUM)
|
||||
{
|
||||
RDCEraseEl(ShadowPtr);
|
||||
}
|
||||
|
||||
~GLResourceRecord()
|
||||
{
|
||||
FreeShadowStorage();
|
||||
}
|
||||
|
||||
enum MapStatus
|
||||
@@ -108,7 +115,7 @@ struct GLResourceRecord : public ResourceRecord
|
||||
Mapped_Read_Real,
|
||||
Mapped_Write,
|
||||
Mapped_Write_Real,
|
||||
Mapped_Write_Alloc,
|
||||
Mapped_Ignore_Real,
|
||||
};
|
||||
|
||||
struct
|
||||
@@ -117,11 +124,39 @@ struct GLResourceRecord : public ResourceRecord
|
||||
GLsizeiptr length;
|
||||
GLbitfield access;
|
||||
MapStatus status;
|
||||
bool invalidate;
|
||||
byte *ptr;
|
||||
} Map;
|
||||
|
||||
// pointer into binding chunk where datatype enum lives for this resource
|
||||
GLenum datatype;
|
||||
GLenum usage;
|
||||
|
||||
void AllocShadowStorage(size_t size)
|
||||
{
|
||||
if(ShadowPtr[0] == NULL)
|
||||
{
|
||||
ShadowPtr[0] = Serialiser::AllocAlignedBuffer(size);
|
||||
ShadowPtr[1] = Serialiser::AllocAlignedBuffer(size);
|
||||
}
|
||||
}
|
||||
|
||||
void FreeShadowStorage()
|
||||
{
|
||||
if(ShadowPtr[0] != NULL)
|
||||
{
|
||||
Serialiser::FreeAlignedBuffer(ShadowPtr[0]);
|
||||
Serialiser::FreeAlignedBuffer(ShadowPtr[1]);
|
||||
}
|
||||
ShadowPtr[0] = ShadowPtr[1] = NULL;
|
||||
}
|
||||
|
||||
byte *GetShadowPtr(int p)
|
||||
{
|
||||
return ShadowPtr[p];
|
||||
}
|
||||
|
||||
private:
|
||||
byte *ShadowPtr[2];
|
||||
};
|
||||
|
||||
namespace TrackedResource
|
||||
|
||||
@@ -403,18 +403,32 @@ void WrappedOpenGL::glNamedBufferSubDataEXT(GLuint buffer, GLintptr offset, GLsi
|
||||
|
||||
if(m_State >= WRITING)
|
||||
{
|
||||
if(m_HighTrafficResources.find(BufferRes(buffer)) != m_HighTrafficResources.end() && m_State != WRITING_CAPFRAME)
|
||||
return;
|
||||
|
||||
GLResourceRecord *record = GetResourceManager()->GetResourceRecord(BufferRes(buffer));
|
||||
RDCASSERT(record);
|
||||
|
||||
SCOPED_SERIALISE_CONTEXT(BUFFERDATA);
|
||||
SCOPED_SERIALISE_CONTEXT(BUFFERSUBDATA);
|
||||
Serialise_glNamedBufferSubDataEXT(buffer, offset, size, data);
|
||||
|
||||
Chunk *chunk = scope.Get();
|
||||
|
||||
if(m_State == WRITING_CAPFRAME)
|
||||
{
|
||||
m_ContextRecord->AddChunk(chunk);
|
||||
}
|
||||
else
|
||||
{
|
||||
record->AddChunk(chunk);
|
||||
record->UpdateCount++;
|
||||
|
||||
if(record->UpdateCount > 60)
|
||||
{
|
||||
m_HighTrafficResources.insert(BufferRes(buffer));
|
||||
GetResourceManager()->MarkDirtyResource(record->GetResourceID());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -614,15 +628,39 @@ void *WrappedOpenGL::glMapNamedBufferEXT(GLuint buffer, GLenum access)
|
||||
|
||||
GLint length;
|
||||
m_Real.glGetNamedBufferParameterivEXT(buffer, eGL_BUFFER_SIZE, &length);
|
||||
|
||||
bool straightUp = false;
|
||||
if(m_HighTrafficResources.find(BufferRes(buffer)) != m_HighTrafficResources.end() && m_State != WRITING_CAPFRAME)
|
||||
straightUp = true;
|
||||
|
||||
if(GetResourceManager()->IsResourceDirty(record->GetResourceID()) && m_State != WRITING_CAPFRAME)
|
||||
straightUp = true;
|
||||
|
||||
// TODO align return pointer to GL_MIN_MAP_BUFFER_ALIGNMENT (min 64)
|
||||
|
||||
if(!straightUp && (access == eGL_WRITE_ONLY || access == eGL_READ_WRITE) && m_State != WRITING_CAPFRAME)
|
||||
{
|
||||
straightUp = true;
|
||||
m_HighTrafficResources.insert(BufferRes(buffer));
|
||||
if(m_State != WRITING_CAPFRAME)
|
||||
GetResourceManager()->MarkDirtyResource(record->GetResourceID());
|
||||
}
|
||||
|
||||
record->Map.offset = 0;
|
||||
record->Map.length = length;
|
||||
record->Map.invalidate = false;
|
||||
if(access == eGL_READ_ONLY) record->Map.access = GL_MAP_READ_BIT;
|
||||
else if(access == eGL_WRITE_ONLY) record->Map.access = GL_MAP_WRITE_BIT;
|
||||
else if(access == eGL_READ_WRITE) record->Map.access = GL_MAP_READ_BIT|GL_MAP_WRITE_BIT;
|
||||
|
||||
if(straightUp && m_State == WRITING_IDLE)
|
||||
{
|
||||
record->Map.ptr = (byte *)m_Real.glMapNamedBufferEXT(buffer, access);
|
||||
record->Map.status = GLResourceRecord::Mapped_Ignore_Real;
|
||||
|
||||
return record->Map.ptr;
|
||||
}
|
||||
|
||||
// TODO align return pointer to GL_MIN_MAP_BUFFER_ALIGNMENT (min 64)
|
||||
|
||||
if(access == eGL_READ_ONLY)
|
||||
{
|
||||
record->Map.status = GLResourceRecord::Mapped_Read_Real;
|
||||
@@ -633,15 +671,52 @@ void *WrappedOpenGL::glMapNamedBufferEXT(GLuint buffer, GLenum access)
|
||||
|
||||
if(ptr == NULL)
|
||||
{
|
||||
ptr = new byte[length];
|
||||
|
||||
RDCWARN("Mapping buffer that hasn't been allocated");
|
||||
|
||||
ptr = (byte *)m_Real.glMapNamedBufferEXT(buffer, access);
|
||||
|
||||
record->Map.status = GLResourceRecord::Mapped_Write_Alloc;
|
||||
record->Map.ptr = ptr;
|
||||
record->Map.status = GLResourceRecord::Mapped_Write_Real;
|
||||
}
|
||||
else
|
||||
{
|
||||
record->Map.status = GLResourceRecord::Mapped_Write;
|
||||
if(m_State == WRITING_CAPFRAME)
|
||||
{
|
||||
byte *shadow = (byte *)record->GetShadowPtr(0);
|
||||
|
||||
if(shadow == NULL)
|
||||
{
|
||||
record->AllocShadowStorage(length);
|
||||
shadow = (byte *)record->GetShadowPtr(0);
|
||||
|
||||
if(GetResourceManager()->IsResourceDirty(record->GetResourceID()))
|
||||
{
|
||||
// TODO get contents from frame initial state
|
||||
|
||||
m_Real.glGetNamedBufferSubDataEXT(buffer, 0, length, ptr);
|
||||
memcpy(shadow, ptr, length);
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(shadow, ptr, length);
|
||||
}
|
||||
|
||||
memcpy(record->GetShadowPtr(1), shadow, length);
|
||||
}
|
||||
|
||||
record->Map.ptr = ptr = shadow;
|
||||
record->Map.status = GLResourceRecord::Mapped_Write;
|
||||
}
|
||||
else
|
||||
{
|
||||
record->Map.ptr = ptr;
|
||||
record->Map.status = GLResourceRecord::Mapped_Write;
|
||||
|
||||
record->UpdateCount++;
|
||||
|
||||
if(record->UpdateCount > 60)
|
||||
m_HighTrafficResources.insert(BufferRes(buffer));
|
||||
}
|
||||
}
|
||||
|
||||
m_Real.glGetNamedBufferSubDataEXT(buffer, 0, length, ptr);
|
||||
@@ -674,17 +749,40 @@ void *WrappedOpenGL::glMapNamedBufferRangeEXT(GLuint buffer, GLintptr offset, GL
|
||||
{
|
||||
GLResourceRecord *record = GetResourceManager()->GetResourceRecord(BufferRes(buffer));
|
||||
|
||||
// TODO align return pointer to GL_MIN_MAP_BUFFER_ALIGNMENT (min 64)
|
||||
|
||||
if((access & (GL_MAP_INVALIDATE_BUFFER_BIT|GL_MAP_INVALIDATE_RANGE_BIT|GL_MAP_READ_BIT)) == 0)
|
||||
RDCUNIMPLEMENTED("haven't implemented non-invalidating glMap WRITE");
|
||||
bool straightUp = false;
|
||||
if(m_HighTrafficResources.find(BufferRes(buffer)) != m_HighTrafficResources.end() && m_State != WRITING_CAPFRAME)
|
||||
straightUp = true;
|
||||
|
||||
if((access & (GL_MAP_COHERENT_BIT|GL_MAP_PERSISTENT_BIT)) != 0)
|
||||
RDCUNIMPLEMENTED("haven't implemented coherent/persistant glMap calls");
|
||||
if(GetResourceManager()->IsResourceDirty(record->GetResourceID()) && m_State != WRITING_CAPFRAME)
|
||||
straightUp = true;
|
||||
|
||||
bool invalidateMap = (access & (GL_MAP_INVALIDATE_BUFFER_BIT|GL_MAP_INVALIDATE_RANGE_BIT)) != 0;
|
||||
|
||||
if(!straightUp && !invalidateMap && (access & GL_MAP_WRITE_BIT) && m_State != WRITING_CAPFRAME)
|
||||
{
|
||||
straightUp = true;
|
||||
m_HighTrafficResources.insert(BufferRes(buffer));
|
||||
if(m_State != WRITING_CAPFRAME)
|
||||
GetResourceManager()->MarkDirtyResource(record->GetResourceID());
|
||||
}
|
||||
|
||||
record->Map.offset = offset;
|
||||
record->Map.length = length;
|
||||
record->Map.access = access;
|
||||
record->Map.invalidate = invalidateMap;
|
||||
|
||||
if(straightUp && m_State == WRITING_IDLE)
|
||||
{
|
||||
record->Map.ptr = (byte *)m_Real.glMapNamedBufferRangeEXT(buffer, offset, length, access);
|
||||
record->Map.status = GLResourceRecord::Mapped_Ignore_Real;
|
||||
|
||||
return record->Map.ptr;
|
||||
}
|
||||
|
||||
// TODO align return pointer to GL_MIN_MAP_BUFFER_ALIGNMENT (min 64)
|
||||
|
||||
if((access & (GL_MAP_COHERENT_BIT|GL_MAP_PERSISTENT_BIT)) != 0)
|
||||
RDCUNIMPLEMENTED("haven't implemented coherent/persistant glMap calls");
|
||||
|
||||
if((access & GL_MAP_READ_BIT) != 0)
|
||||
{
|
||||
@@ -722,10 +820,43 @@ void *WrappedOpenGL::glMapNamedBufferRangeEXT(GLuint buffer, GLintptr offset, GL
|
||||
{
|
||||
if(m_State == WRITING_CAPFRAME)
|
||||
{
|
||||
ptr = new byte[length];
|
||||
|
||||
record->Map.ptr = ptr;
|
||||
record->Map.status = GLResourceRecord::Mapped_Write_Alloc;
|
||||
byte *shadow = (byte *)record->GetShadowPtr(0);
|
||||
|
||||
if(shadow == NULL)
|
||||
{
|
||||
GLint buflength;
|
||||
m_Real.glGetNamedBufferParameterivEXT(buffer, eGL_BUFFER_SIZE, &buflength);
|
||||
|
||||
record->AllocShadowStorage(buflength);
|
||||
shadow = (byte *)record->GetShadowPtr(0);
|
||||
|
||||
if(!invalidateMap)
|
||||
{
|
||||
if(GetResourceManager()->IsResourceDirty(record->GetResourceID()))
|
||||
{
|
||||
// TODO get contents from frame initial state
|
||||
|
||||
m_Real.glGetNamedBufferSubDataEXT(buffer, 0, buflength, ptr);
|
||||
memcpy(shadow, ptr, buflength);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(shadow+offset, ptr+offset, length);
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(record->GetShadowPtr(1), shadow, buflength);
|
||||
}
|
||||
|
||||
if(invalidateMap)
|
||||
{
|
||||
memset(shadow+offset, 0xcc, length);
|
||||
memset(record->GetShadowPtr(1)+offset, 0xcc, length);
|
||||
}
|
||||
|
||||
record->Map.ptr = ptr = shadow;
|
||||
record->Map.status = GLResourceRecord::Mapped_Write;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -733,6 +864,11 @@ void *WrappedOpenGL::glMapNamedBufferRangeEXT(GLuint buffer, GLintptr offset, GL
|
||||
|
||||
record->Map.ptr = ptr;
|
||||
record->Map.status = GLResourceRecord::Mapped_Write;
|
||||
|
||||
record->UpdateCount++;
|
||||
|
||||
if(record->UpdateCount > 60)
|
||||
m_HighTrafficResources.insert(BufferRes(buffer));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -765,31 +901,80 @@ bool WrappedOpenGL::Serialise_glUnmapNamedBufferEXT(GLuint buffer)
|
||||
if(m_State >= WRITING)
|
||||
record = GetResourceManager()->GetResourceRecord(BufferRes(buffer));
|
||||
|
||||
SERIALISE_ELEMENT(ResourceId, bufID, record->GetResourceID());
|
||||
SERIALISE_ELEMENT(uint64_t, offs, record->Map.offset);
|
||||
SERIALISE_ELEMENT(uint64_t, len, record->Map.length);
|
||||
ResourceId bufID;
|
||||
uint64_t offs = 0;
|
||||
uint64_t len = 0;
|
||||
|
||||
if(m_State < WRITING || m_State == WRITING_CAPFRAME)
|
||||
{
|
||||
SERIALISE_ELEMENT(ResourceId, ID, record->GetResourceID());
|
||||
SERIALISE_ELEMENT(uint64_t, offset, record->Map.offset);
|
||||
SERIALISE_ELEMENT(uint64_t, length, record->Map.length);
|
||||
|
||||
bufID = ID;
|
||||
offs = offset;
|
||||
len = length;
|
||||
}
|
||||
else if(m_State == WRITING_IDLE)
|
||||
{
|
||||
bufID = record->GetResourceID();
|
||||
offs = record->Map.offset;
|
||||
len = record->Map.length;
|
||||
|
||||
void *ptr = m_Real.glMapNamedBufferRangeEXT(buffer, (GLintptr)offs, (GLsizeiptr)len, GL_MAP_WRITE_BIT);
|
||||
memcpy(ptr, record->Map.ptr, (size_t)len);
|
||||
m_Real.glUnmapNamedBufferEXT(buffer);
|
||||
return true;
|
||||
}
|
||||
|
||||
uint64_t bufBindStart = 0;
|
||||
|
||||
SERIALISE_ELEMENT_BUF(byte *, data, record->Map.ptr, (size_t)len);
|
||||
size_t diffStart = 0;
|
||||
size_t diffEnd = (size_t)len;
|
||||
|
||||
if(m_State >= WRITING && record && record->GetDataPtr() == NULL)
|
||||
record->SetDataOffset(m_pSerialiser->GetOffset() - (uint64_t)len);
|
||||
|
||||
if(m_State < WRITING ||
|
||||
(m_State >= WRITING &&
|
||||
(record->Map.status == GLResourceRecord::Mapped_Write || record->Map.status == GLResourceRecord::Mapped_Write_Alloc)
|
||||
)
|
||||
)
|
||||
if(m_State == WRITING_CAPFRAME && len > 512 && !record->Map.invalidate)
|
||||
{
|
||||
if(m_State < WRITING)
|
||||
bool found = FindDiffRange(record->Map.ptr, record->GetShadowPtr(1), (size_t)len, diffStart, diffEnd);
|
||||
if(found)
|
||||
{
|
||||
GLResource res = GetResourceManager()->GetLiveResource(bufID);
|
||||
buffer = res.name;
|
||||
}
|
||||
static size_t saved = 0;
|
||||
|
||||
void *ptr = m_Real.glMapNamedBufferRangeEXT(buffer, (GLintptr)offs, (GLsizeiptr)len, GL_MAP_WRITE_BIT);
|
||||
memcpy(ptr, data, (size_t)len);
|
||||
saved += (size_t)len - (diffEnd-diffStart);
|
||||
|
||||
RDCDEBUG("Mapped resource size %u, difference: %u -> %u. Total bytes saved so far: %u",
|
||||
(uint32_t)len, (uint32_t)diffStart, (uint32_t)diffEnd, (uint32_t)saved);
|
||||
|
||||
len = diffEnd-diffStart;
|
||||
}
|
||||
else
|
||||
{
|
||||
diffStart = 0;
|
||||
diffEnd = 0;
|
||||
|
||||
len = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if(m_State == WRITING_CAPFRAME && record->GetShadowPtr(1))
|
||||
{
|
||||
memcpy(record->GetShadowPtr(1)+diffStart, record->Map.ptr+diffStart, diffEnd-diffStart);
|
||||
}
|
||||
|
||||
SERIALISE_ELEMENT(uint32_t, DiffStart, (uint32_t)diffStart);
|
||||
SERIALISE_ELEMENT(uint32_t, DiffEnd, (uint32_t)diffEnd);
|
||||
|
||||
SERIALISE_ELEMENT_BUF(byte *, data, record->Map.ptr+diffStart, (size_t)len);
|
||||
|
||||
if(m_State < WRITING)
|
||||
{
|
||||
GLResource res = GetResourceManager()->GetLiveResource(bufID);
|
||||
buffer = res.name;
|
||||
}
|
||||
|
||||
if(DiffEnd > DiffStart)
|
||||
{
|
||||
void *ptr = m_Real.glMapNamedBufferRangeEXT(buffer, (GLintptr)(offs+DiffStart), GLsizeiptr(DiffEnd-DiffStart), GL_MAP_WRITE_BIT);
|
||||
memcpy(ptr, data, size_t(DiffEnd-DiffStart));
|
||||
m_Real.glUnmapNamedBufferEXT(buffer);
|
||||
}
|
||||
|
||||
@@ -816,43 +1001,25 @@ GLboolean WrappedOpenGL::glUnmapNamedBufferEXT(GLuint buffer)
|
||||
case GLResourceRecord::Mapped_Read:
|
||||
// can ignore
|
||||
break;
|
||||
case GLResourceRecord::Mapped_Ignore_Real:
|
||||
if(m_State == WRITING_CAPFRAME)
|
||||
RDCWARN("Failed to cap frame - uncapped Map/Unmap");
|
||||
// deliberate fallthrough
|
||||
case GLResourceRecord::Mapped_Read_Real:
|
||||
// need to do real unmap
|
||||
ret = m_Real.glUnmapNamedBufferEXT(buffer);
|
||||
break;
|
||||
case GLResourceRecord::Mapped_Write:
|
||||
{
|
||||
if(m_State == WRITING_CAPFRAME)
|
||||
RDCWARN("Failed to cap frame - uncapped Map/Unmap");
|
||||
|
||||
SCOPED_SERIALISE_CONTEXT(UNMAP);
|
||||
Serialise_glUnmapNamedBufferEXT(buffer);
|
||||
|
||||
if(m_State == WRITING_CAPFRAME)
|
||||
m_ContextRecord->AddChunk(scope.Get());
|
||||
else
|
||||
record->AddChunk(scope.Get());
|
||||
|
||||
break;
|
||||
}
|
||||
case GLResourceRecord::Mapped_Write_Alloc:
|
||||
{
|
||||
SCOPED_SERIALISE_CONTEXT(UNMAP);
|
||||
Serialise_glUnmapNamedBufferEXT(buffer);
|
||||
|
||||
if(m_State == WRITING_CAPFRAME)
|
||||
{
|
||||
SCOPED_SERIALISE_CONTEXT(UNMAP);
|
||||
Serialise_glUnmapNamedBufferEXT(buffer);
|
||||
m_ContextRecord->AddChunk(scope.Get());
|
||||
}
|
||||
else
|
||||
{
|
||||
Chunk *chunk = scope.Get();
|
||||
record->AddChunk(chunk);
|
||||
record->SetDataPtr(chunk->GetData());
|
||||
}
|
||||
|
||||
delete[] record->Map.ptr;
|
||||
|
||||
Serialise_glUnmapNamedBufferEXT(buffer);
|
||||
|
||||
break;
|
||||
}
|
||||
case GLResourceRecord::Mapped_Write_Real:
|
||||
|
||||
Reference in New Issue
Block a user