From 584d43962079da0b46bfa1999a0dcd06491f5eff Mon Sep 17 00:00:00 2001 From: baldurk Date: Fri, 24 Apr 2015 11:07:02 +0200 Subject: [PATCH] Add util function to align serialised buffers in chunks. Refs #133 * To align a buffer inside a chunk to a wider boundary like 32-bytes in this case, the chunk needs to be aligned and the buffer within it also needs to be aligned. * The utility function accounts for the buffer serialised having a uint32 length in front of it, so it pads out until that will be at the desired boundary. This is a bit of a messy solution, but the easiest way to ensure the padding is there while being easily backwards compatible with old logs without the padding. * D3D11 and GL serialise versions are bumped, D3D11 version is backwards compatible, GL breaks compatibility. --- .../driver/d3d11/d3d11_context1_wrap.cpp | 6 ++++ renderdoc/driver/d3d11/d3d11_context_wrap.cpp | 6 ++++ renderdoc/driver/d3d11/d3d11_device.cpp | 1 + renderdoc/driver/d3d11/d3d11_device.h | 4 +-- renderdoc/driver/d3d11/d3d11_device_wrap.cpp | 12 ++++++++ renderdoc/driver/gl/gl_driver.h | 2 +- .../driver/gl/wrappers/gl_buffer_funcs.cpp | 6 ++++ renderdoc/serialise/serialiser.cpp | 30 +++++++++++++++++++ renderdoc/serialise/serialiser.h | 1 + 9 files changed, 65 insertions(+), 3 deletions(-) diff --git a/renderdoc/driver/d3d11/d3d11_context1_wrap.cpp b/renderdoc/driver/d3d11/d3d11_context1_wrap.cpp index ece717e65..c9fd2f1ec 100644 --- a/renderdoc/driver/d3d11/d3d11_context1_wrap.cpp +++ b/renderdoc/driver/d3d11/d3d11_context1_wrap.cpp @@ -171,6 +171,12 @@ bool WrappedID3D11DeviceContext::Serialise_UpdateSubresource1(ID3D11Resource *pD byte *padding = m_State >= WRITING ? new byte[ResourceBufLen] : NULL; + // this is a bit of a hack, but to maintain backwards compatibility we have a + // separate function here that aligns the next serialised buffer to a 32-byte + // boundary in memory while writing (just skips the padding on read). + if(m_State >= WRITING || m_pDevice->GetLogVersion() >= 0x000007) + m_pSerialiser->AlignNextBuffer(32); + SERIALISE_ELEMENT_BUF(byte *, bufData, padding, ResourceBufLen); if(record) diff --git a/renderdoc/driver/d3d11/d3d11_context_wrap.cpp b/renderdoc/driver/d3d11/d3d11_context_wrap.cpp index 6371240bc..581e9638b 100644 --- a/renderdoc/driver/d3d11/d3d11_context_wrap.cpp +++ b/renderdoc/driver/d3d11/d3d11_context_wrap.cpp @@ -7024,6 +7024,12 @@ bool WrappedID3D11DeviceContext::Serialise_Unmap(ID3D11Resource *pResource, UINT m_pSerialiser->Serialise("DiffStart", diffStart); m_pSerialiser->Serialise("DiffEnd", diffEnd); + // this is a bit of a hack, but to maintain backwards compatibility we have a + // separate function here that aligns the next serialised buffer to a 32-byte + // boundary in memory while writing (just skips the padding on read). + if(m_State >= WRITING || m_pDevice->GetLogVersion() >= 0x000007) + m_pSerialiser->AlignNextBuffer(32); + byte *buf = (byte *)intercept.app.pData; m_pSerialiser->SerialiseBuffer("MapData", buf, len); diff --git a/renderdoc/driver/d3d11/d3d11_device.cpp b/renderdoc/driver/d3d11/d3d11_device.cpp index b681729b3..b56e6dac6 100644 --- a/renderdoc/driver/d3d11/d3d11_device.cpp +++ b/renderdoc/driver/d3d11/d3d11_device.cpp @@ -206,6 +206,7 @@ D3D11InitParams::D3D11InitParams() const uint32_t D3D11InitParams::D3D11_OLD_VERSIONS[D3D11InitParams::D3D11_NUM_SUPPORTED_OLD_VERSIONS] = { 0x0000004, // from 0x4 to 0x5, we added the stream-out hidden counters in the context's Serialise_BeginCaptureFrame 0x0000005, // from 0x5 to 0x6, several new calls were made 'drawcalls', like Copy & GenerateMips, with serialised debug messages + 0x0000006, // from 0x6 to 0x7, we added some more padding in some buffer & texture chunks to get larger alignment than 16-byte }; ReplayCreateStatus D3D11InitParams::Serialise() diff --git a/renderdoc/driver/d3d11/d3d11_device.h b/renderdoc/driver/d3d11/d3d11_device.h index a86797056..e15193b69 100644 --- a/renderdoc/driver/d3d11/d3d11_device.h +++ b/renderdoc/driver/d3d11/d3d11_device.h @@ -66,10 +66,10 @@ struct D3D11InitParams : public RDCInitParams UINT NumFeatureLevels; D3D_FEATURE_LEVEL FeatureLevels[16]; - static const uint32_t D3D11_SERIALISE_VERSION = 0x0000006; + static const uint32_t D3D11_SERIALISE_VERSION = 0x0000007; // backwards compatibility for old logs described at the declaration of this array - static const uint32_t D3D11_NUM_SUPPORTED_OLD_VERSIONS = 2; + static const uint32_t D3D11_NUM_SUPPORTED_OLD_VERSIONS = 3; static const uint32_t D3D11_OLD_VERSIONS[D3D11_NUM_SUPPORTED_OLD_VERSIONS]; // version number internal to d3d11 stream diff --git a/renderdoc/driver/d3d11/d3d11_device_wrap.cpp b/renderdoc/driver/d3d11/d3d11_device_wrap.cpp index 7fa7e3bf6..ed473ca10 100644 --- a/renderdoc/driver/d3d11/d3d11_device_wrap.cpp +++ b/renderdoc/driver/d3d11/d3d11_device_wrap.cpp @@ -44,6 +44,12 @@ bool WrappedID3D11Device::Serialise_CreateBuffer( pInitialData = &fakeData; } + // this is a bit of a hack, but to maintain backwards compatibility we have a + // separate function here that aligns the next serialised buffer to a 32-byte + // boundary in memory while writing (just skips the padding on read). + if(m_State >= WRITING || GetLogVersion() >= 0x000007) + m_pSerialiser->AlignNextBuffer(32); + SERIALISE_ELEMENT_BUF(byte *, InitialData, pInitialData->pSysMem, Descriptor.ByteWidth); uint64_t offs = m_pSerialiser->GetOffset()-Descriptor.ByteWidth; @@ -261,6 +267,12 @@ vector WrappedID3D11Device::Serialise_CreateTextureData( intercept.CopyFromD3D(); } + // this is a bit of a hack, but to maintain backwards compatibility we have a + // separate function here that aligns the next serialised buffer to a 32-byte + // boundary in memory while writing (just skips the padding on read). + if(m_State >= WRITING || GetLogVersion() >= 0x000007) + m_pSerialiser->AlignNextBuffer(32); + SERIALISE_ELEMENT_BUF(byte *, buf, scratch, subresourceSize); if(m_State >= WRITING) diff --git a/renderdoc/driver/gl/gl_driver.h b/renderdoc/driver/gl/gl_driver.h index 05996b024..5a92f9c35 100644 --- a/renderdoc/driver/gl/gl_driver.h +++ b/renderdoc/driver/gl/gl_driver.h @@ -55,7 +55,7 @@ struct GLInitParams : public RDCInitParams uint32_t width; uint32_t height; - static const uint32_t GL_SERIALISE_VERSION = 0x000000C; + static const uint32_t GL_SERIALISE_VERSION = 0x000000D; // version number internal to opengl stream uint32_t SerialiseVersion; diff --git a/renderdoc/driver/gl/wrappers/gl_buffer_funcs.cpp b/renderdoc/driver/gl/wrappers/gl_buffer_funcs.cpp index 50d4a1524..055dbee45 100644 --- a/renderdoc/driver/gl/wrappers/gl_buffer_funcs.cpp +++ b/renderdoc/driver/gl/wrappers/gl_buffer_funcs.cpp @@ -309,6 +309,9 @@ bool WrappedOpenGL::Serialise_glNamedBufferStorageEXT(GLuint buffer, GLsizeiptr SERIALISE_ELEMENT(ResourceId, id, GetResourceManager()->GetID(BufferRes(GetCtx(), buffer))); SERIALISE_ELEMENT(uint64_t, Bytesize, (uint64_t)size); + // for satisfying GL_MIN_MAP_BUFFER_ALIGNMENT + m_pSerialiser->AlignNextBuffer(64); + SERIALISE_ELEMENT_BUF(byte *, bytes, data, (size_t)Bytesize); uint64_t offs = m_pSerialiser->GetOffset(); @@ -424,6 +427,9 @@ bool WrappedOpenGL::Serialise_glNamedBufferDataEXT(GLuint buffer, GLsizeiptr siz SERIALISE_ELEMENT(ResourceId, id, GetResourceManager()->GetID(BufferRes(GetCtx(), buffer))); SERIALISE_ELEMENT(uint64_t, Bytesize, (uint64_t)size); + // for satisfying GL_MIN_MAP_BUFFER_ALIGNMENT + m_pSerialiser->AlignNextBuffer(64); + SERIALISE_ELEMENT_BUF(byte *, bytes, data, (size_t)Bytesize); if(m_State == WRITING_CAPFRAME && id.id == 22) diff --git a/renderdoc/serialise/serialiser.cpp b/renderdoc/serialise/serialiser.cpp index c534dba00..9d0d757fa 100644 --- a/renderdoc/serialise/serialiser.cpp +++ b/renderdoc/serialise/serialiser.cpp @@ -940,6 +940,36 @@ void Serialiser::SkipBuffer() ReadBytes(len); } +void Serialiser::AlignNextBuffer(const size_t alignment) +{ + // this is a super hack but it's the easiest way to align a buffer to a larger pow2 alignment + // than the default 16-bytes, while still able to be backwards compatible with old logs that + // weren't so aligned. We know that SerialiseBuffer will align to the nearest 16-byte boundary + // after serialising 4 bytes of length, so we pad up to exactly 4 bytes before the desired + // alignment, then after the 4 byte length there's nothing for the other padding to do. + // + // Note the chunk still needs to be aligned when the memory is allocated - this just ensures + // the offset from the start is also aligned + + size_t len = 0; + + if(m_Mode >= WRITING) + { + // add sizeof(uint32_t) since we'll be serialising out how much padding is here + uint64_t curoffs = GetOffset() + sizeof(uint32_t); + uint64_t alignedoffs = AlignUp(curoffs, (uint64_t)alignment); + + len = size_t(alignedoffs - curoffs); + } + + // avoid dynamically allocating + RDCASSERT(alignment <= 128); + byte padding[128] = {0}; + byte *p = &padding[0]; + + SerialiseBuffer("", p, len); +} + void Serialiser::SerialiseBuffer(const char *name, byte *&buf, size_t &len) { uint32_t bufLen = (uint32_t)len; diff --git a/renderdoc/serialise/serialiser.h b/renderdoc/serialise/serialiser.h index 019ba2fb9..8740b87dd 100644 --- a/renderdoc/serialise/serialiser.h +++ b/renderdoc/serialise/serialiser.h @@ -487,6 +487,7 @@ class Serialiser // memory will be returned, or it must be already large enough. void SerialiseBuffer(const char *name, byte *&buf, size_t &len); void SkipBuffer(); + void AlignNextBuffer(const size_t alignment); // NOT recommended interface. Useful for specific situations if e.g. you have // a buffer of data that is not arbitrary in size and can be determined by a 'type' or