From 6a504631e2ff89ba091c0bf4898e666a28a2a6a3 Mon Sep 17 00:00:00 2001 From: baldurk Date: Fri, 26 Jun 2026 11:35:25 +0100 Subject: [PATCH] Allow serialising normal/estimated chunks as 64-bit if predeclared * Normally we only allowed 64-bit chunks in initial contents where the size was known up front and they were serialised direct to file. --- .../vulkan/wrappers/vk_shader_funcs.cpp | 6 +--- renderdoc/serialise/serialiser.cpp | 28 ++++++++++++++----- renderdoc/serialise/serialiser.h | 16 ++++++----- 3 files changed, 31 insertions(+), 19 deletions(-) diff --git a/renderdoc/driver/vulkan/wrappers/vk_shader_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_shader_funcs.cpp index e77bae0b8..6b0134437 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_shader_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_shader_funcs.cpp @@ -638,10 +638,6 @@ VkResult WrappedVulkan::vkCreatePipelineCache(VkDevice device, { VkPipelineCacheCreateInfo createInfo = *pCreateInfo; - // ignore pipeline caches that are too large and overflow 32-bit chunk size - if(createInfo.initialDataSize > 0xffff0000) - createInfo.initialDataSize = 0; - VkResult ret; SERIALISE_TIME_CALL(ret = ObjDisp(device)->CreatePipelineCache(Unwrap(device), &createInfo, NULL, pPipelineCache)); @@ -657,7 +653,7 @@ VkResult WrappedVulkan::vkCreatePipelineCache(VkDevice device, { CACHE_THREAD_SERIALISER(); - SCOPED_SERIALISE_CHUNK(VulkanChunk::vkCreatePipelineCache); + SCOPED_SERIALISE_CHUNK(VulkanChunk::vkCreatePipelineCache, LARGE_CHUNK_SIZE); Serialise_vkCreatePipelineCache(ser, device, &createInfo, NULL, pPipelineCache); chunk = scope.Get(); diff --git a/renderdoc/serialise/serialiser.cpp b/renderdoc/serialise/serialiser.cpp index dcfd6ccdb..a3ee578fe 100644 --- a/renderdoc/serialise/serialiser.cpp +++ b/renderdoc/serialise/serialiser.cpp @@ -427,7 +427,7 @@ uint32_t Serialiser::BeginChunk(uint32_t chunkID, uint6 m_Write->Write(m_ChunkMetadata.timestampMicro); } - if(byteLength > 0 || m_DataStreaming) + if((byteLength > 0 && byteLength != LARGE_CHUNK_SIZE) || m_DataStreaming) { // write length, assuming it is an upper bound m_ChunkFixup = 0; @@ -443,6 +443,13 @@ uint32_t Serialiser::BeginChunk(uint32_t chunkID, uint6 m_LastChunkOffset = m_Write->GetOffset(); m_ChunkMetadata.length = byteLength; } + else if(byteLength == LARGE_CHUNK_SIZE) + { + uint64_t chunkSize = 0xbeebfeedbeebfeedULL; + m_ChunkFixup = m_Write->GetOffset(); + m_Write->Write(chunkSize); + m_ChunkMetadata.length = LARGE_CHUNK_SIZE; + } else { // length will be fixed up in EndChunk @@ -494,13 +501,20 @@ void Serialiser::EndChunk() RDCASSERT(curOffset > chunkOffset); uint64_t chunkLength = (curOffset - chunkOffset) - sizeof(uint32_t); - if(chunkLength > 0xffffffff) + if(m_ChunkMetadata.length == LARGE_CHUNK_SIZE) { - RDCERR("!!! CHUNK LENGTH %llu EXCEEDED 32 BIT VALUE. CAPTURE WILL BE CORRUPTED. !!!", - chunkLength); + m_Write->WriteAt(chunkOffset, chunkLength); } + else + { + if(chunkLength > 0xffffffff) + { + RDCERR("!!! CHUNK LENGTH %llu EXCEEDED 32 BIT VALUE. CAPTURE WILL BE CORRUPTED. !!!", + chunkLength); + } - m_Write->WriteAt(chunkOffset, uint32_t(chunkLength & 0xffffffff)); + m_Write->WriteAt(chunkOffset, uint32_t(chunkLength & 0xffffffff)); + } m_ChunkMetadata.length = chunkLength; } @@ -1036,8 +1050,8 @@ Chunk *Chunk::Create(Serialiser &ser, uint16_t chunkTyp { RDCCOMPILE_ASSERT(sizeof(Chunk) <= 16, "Chunk should be no more than 16 bytes"); - RDCASSERT(ser.GetWriter()->GetOffset() < 0xffffffff); - uint32_t length = (uint32_t)ser.GetWriter()->GetOffset(); + uint64_t length = ser.GetWriter()->GetOffset(); + RDCASSERT(length < (1ULL << CHUNK_LENGTH_BITS)); byte *data = NULL; diff --git a/renderdoc/serialise/serialiser.h b/renderdoc/serialise/serialiser.h index bd08b6320..e779399ff 100644 --- a/renderdoc/serialise/serialiser.h +++ b/renderdoc/serialise/serialiser.h @@ -1909,7 +1909,7 @@ private: // passed around and moved between owners before being serialised out class Chunk { - Chunk(bool fromAllocator) : m_FromAllocator(fromAllocator) {} + Chunk(bool fromAllocator) : m_FromAllocator(fromAllocator ? 1 : 0) {} ~Chunk() { FreeAlignedBuffer(m_Data); @@ -1921,8 +1921,8 @@ class Chunk } public: - void Delete() { Delete(m_FromAllocator); } - bool IsFromAllocator() { return m_FromAllocator; } + void Delete() { Delete(IsFromAllocator()); } + bool IsFromAllocator() { return m_FromAllocator != 0; } void Delete(bool fromAllocator) { if(!fromAllocator) @@ -1954,7 +1954,7 @@ public: ret->m_ChunkType = m_ChunkType; ret->m_Data = AllocAlignedBuffer(m_Length); - ret->m_FromAllocator = false; + ret->m_FromAllocator = 0; memcpy(ret->m_Data, m_Data, (size_t)m_Length); @@ -1976,11 +1976,12 @@ private: Chunk(const Chunk &) = delete; Chunk &operator=(const Chunk &) = delete; - uint16_t m_ChunkType; +#define CHUNK_LENGTH_BITS 45 - bool m_FromAllocator = false; + uint64_t m_ChunkType : 16; + uint64_t m_FromAllocator : 1; + uint64_t m_Length : CHUNK_LENGTH_BITS; - uint32_t m_Length; byte *m_Data; #if ENABLED(RDOC_DEVEL) @@ -2131,6 +2132,7 @@ struct ScopedDeserialiseArray // can be overridden to change the name in the helper macros locally #define GET_SERIALISER (ser) +#define LARGE_CHUNK_SIZE (~0ULL) #define SCOPED_SERIALISE_CHUNK(...) ScopedChunk scope(GET_SERIALISER, __VA_ARGS__); // these helper macros are intended for use when serialising objects in chunks