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.
This commit is contained in:
baldurk
2015-04-24 11:07:02 +02:00
parent 24df051659
commit 584d439620
9 changed files with 65 additions and 3 deletions
@@ -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)
@@ -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);
+1
View File
@@ -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()
+2 -2
View File
@@ -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
@@ -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<D3D11_SUBRESOURCE_DATA> 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)
+1 -1
View File
@@ -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;
@@ -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)
+30
View File
@@ -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;
+1
View File
@@ -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