diff --git a/renderdoc/driver/vulkan/vk_acceleration_structure.cpp b/renderdoc/driver/vulkan/vk_acceleration_structure.cpp index 71f68d51dd..c571202975 100644 --- a/renderdoc/driver/vulkan/vk_acceleration_structure.cpp +++ b/renderdoc/driver/vulkan/vk_acceleration_structure.cpp @@ -25,6 +25,7 @@ #include "vk_acceleration_structure.h" #include "core/settings.h" #include "vk_core.h" +#include "vk_manager.h" RDOC_EXTERN_CONFIG(bool, Vulkan_Debug_SingleSubmitFlushing); @@ -37,6 +38,34 @@ constexpr VkDeviceSize handleCountSize = 8; // Spec says VkCopyAccelerationStructureToMemoryInfoKHR::dst::deviceAddress must be 256 bytes aligned constexpr VkDeviceSize asBufferAlignment = 256; + +VkDeviceSize IndexTypeSize(VkIndexType type) +{ + switch(type) + { + case VK_INDEX_TYPE_UINT32: return 4; + case VK_INDEX_TYPE_UINT16: return 2; + case VK_INDEX_TYPE_UINT8_KHR: return 1; + default: return 0; + } +} +} + +VkAccelerationStructureInfo::~VkAccelerationStructureInfo() +{ + for(const GeometryData &geoData : geometryData) + { + if(geoData.readbackMem != VK_NULL_HANDLE) + ObjDisp(device)->FreeMemory(Unwrap(device), geoData.readbackMem, NULL); + } +} + +void VkAccelerationStructureInfo::Release() +{ + const int32_t ref = Atomic::Dec32(&refCount); + RDCASSERT(ref >= 0); + if(ref <= 0) + delete this; } VulkanAccelerationStructureManager::VulkanAccelerationStructureManager(WrappedVulkan *driver) @@ -44,6 +73,383 @@ VulkanAccelerationStructureManager::VulkanAccelerationStructureManager(WrappedVu { } +RDResult VulkanAccelerationStructureManager::CopyInputBuffers( + VkCommandBuffer commandBuffer, const VkAccelerationStructureBuildGeometryInfoKHR &info, + const VkAccelerationStructureBuildRangeInfoKHR *buildRange, CaptureState state) +{ + VkResourceRecord *cmdRecord = GetRecord(commandBuffer); + RDCASSERT(cmdRecord); + + VkResourceRecord *asRecord = GetRecord(info.dstAccelerationStructure); + RDCASSERT(asRecord); + + // If this is an update then replace the existing and safely delete it + VkAccelerationStructureInfo *metadata = asRecord->accelerationStructureInfo; + if(!metadata->geometryData.empty()) + { + DeletePreviousInfo(commandBuffer, metadata, state); + metadata = asRecord->accelerationStructureInfo = new VkAccelerationStructureInfo(); + } + + VkDevice device = cmdRecord->cmdInfo->device; + metadata->device = device; + metadata->type = info.type; + metadata->flags = info.flags; + + metadata->geometryData.reserve(info.geometryCount); + + struct BufferData + { + BufferData() = default; + BufferData(RecordAndOffset r) : rao(r) + { + if(rao.record != NULL) + buf = ToUnwrappedHandle(rao.record->Resource); + } + + operator bool() const { return buf != VK_NULL_HANDLE; } + bool operator!() const { return buf == VK_NULL_HANDLE; } + + void SetReadPosition(VkDeviceSize startFrom) { start = startFrom; } + VkDeviceSize GetReadPosition() const { return rao.offset + start; } + + RecordAndOffset rao; + VkBuffer buf = VK_NULL_HANDLE; + + VkDeviceSize alignment = 0; + VkDeviceSize size = 0; + + private: + VkDeviceSize start = 0; + }; + + for(uint32_t i = 0; i < info.geometryCount; ++i) + { + // Work out the buffer size needed for each geometry type + const VkAccelerationStructureGeometryKHR &geometry = + info.pGeometries != NULL ? info.pGeometries[i] : *(info.ppGeometries[i]); + const VkAccelerationStructureBuildRangeInfoKHR &rangeInfo = buildRange[i]; + + Allocation readbackmem; + + // Make sure nothing writes to our source buffers before we finish copying them + VkMemoryBarrier barrier = { + VK_STRUCTURE_TYPE_MEMORY_BARRIER, + NULL, + VK_ACCESS_TRANSFER_WRITE_BIT, + VK_ACCESS_MEMORY_WRITE_BIT, + }; + + switch(geometry.geometryType) + { + case VK_GEOMETRY_TYPE_TRIANGLES_KHR: + { + const VkAccelerationStructureGeometryTrianglesDataKHR &triInfo = geometry.geometry.triangles; + + // Find the associated VkBuffers + BufferData vertexData = GetDeviceAddressData(triInfo.vertexData.deviceAddress); + if(!vertexData) + { + RDCERR("Unable to find VkBuffer for vertex data at 0x%llx", + triInfo.vertexData.deviceAddress); + continue; + } + + BufferData indexData; + if(triInfo.indexType != VK_INDEX_TYPE_NONE_KHR) + { + indexData = GetDeviceAddressData(triInfo.indexData.deviceAddress); + if(!indexData) + { + RDCERR("Unable to find VkBuffer for index data at 0x%llx", + triInfo.indexData.deviceAddress); + continue; + } + } + + BufferData transformData; + if(triInfo.transformData.deviceAddress != 0x0) + { + transformData = GetDeviceAddressData(triInfo.transformData.deviceAddress); + if(!transformData) + { + RDCERR("Unable to find VkBuffer for transform data at 0x%llx", + triInfo.transformData.deviceAddress); + continue; + } + } + + // Find the alignment requirements for each type + { + VkMemoryRequirements mrq = {}; + + // Vertex buffer. The complexity here is that the rangeInfo members are interpreted + // differently depending on whether or not index buffers are used + ObjDisp(device)->GetBufferMemoryRequirements(Unwrap(device), vertexData.buf, &mrq); + vertexData.alignment = mrq.alignment; + + if(indexData) + { + // If we're using an index buffer we don't know how much of the vertex buffer we need, + // and we can't trust the app to set maxVertex correctly, so we take the whole buffer + vertexData.size = vertexData.rao.record->memSize - vertexData.rao.offset; + vertexData.SetReadPosition(0); + } + else + { + vertexData.size = rangeInfo.primitiveCount * 3 * triInfo.vertexStride; + vertexData.SetReadPosition(rangeInfo.primitiveOffset + + (triInfo.vertexStride * rangeInfo.firstVertex)); + } + + // Index buffer + if(indexData) + { + ObjDisp(device)->GetBufferMemoryRequirements(Unwrap(device), indexData.buf, &mrq); + indexData.alignment = mrq.alignment; + indexData.size = rangeInfo.primitiveCount * 3 * IndexTypeSize(triInfo.indexType); + indexData.SetReadPosition(rangeInfo.primitiveOffset); + } + + // Transform buffer + if(transformData) + { + ObjDisp(device)->GetBufferMemoryRequirements(Unwrap(device), transformData.buf, &mrq); + transformData.alignment = mrq.alignment; + transformData.size = sizeof(VkTransformMatrixKHR); + transformData.SetReadPosition(rangeInfo.transformOffset); + } + } + const VkDeviceSize maxAlignment = + RDCMAX(RDCMAX(vertexData.alignment, indexData.alignment), transformData.alignment); + + // We want to copy the input buffers into one big block so sum the sizes up together + const VkDeviceSize totalMemSize = AlignUp(vertexData.size, vertexData.alignment) + + AlignUp(indexData.size, indexData.alignment) + + AlignUp(transformData.size, transformData.alignment); + + readbackmem = CreateReadBackMemory(device, totalMemSize, maxAlignment); + if(readbackmem.mem == VK_NULL_HANDLE) + { + RDCERR("Unable to allocate AS triangle input buffer readback memory (size: %u bytes)", + totalMemSize); + continue; + } + + // Insert copy commands + VkBufferCopy region = { + vertexData.GetReadPosition(), + 0, + vertexData.size, + }; + ObjDisp(device)->CmdCopyBuffer(Unwrap(commandBuffer), vertexData.buf, readbackmem.buf, 1, + ®ion); + + if(indexData) + { + region = { + indexData.GetReadPosition(), + AlignUp(vertexData.size, vertexData.alignment), + indexData.size, + }; + ObjDisp(device)->CmdCopyBuffer(Unwrap(commandBuffer), indexData.buf, readbackmem.buf, 1, + ®ion); + } + + if(transformData) + { + region = { + transformData.GetReadPosition(), + AlignUp(vertexData.size, vertexData.alignment) + + AlignUp(indexData.size, indexData.alignment), + transformData.size, + }; + ObjDisp(device)->CmdCopyBuffer(Unwrap(commandBuffer), transformData.buf, readbackmem.buf, + 1, ®ion); + } + + // Store the metadata + VkAccelerationStructureInfo::GeometryData geoData; + geoData.geometryType = geometry.geometryType; + geoData.flags = geometry.flags; + geoData.readbackMem = readbackmem.mem; + geoData.memSize = readbackmem.size; + + geoData.tris.vertexFormat = geometry.geometry.triangles.vertexFormat; + geoData.tris.vertexStride = geometry.geometry.triangles.vertexStride; + geoData.tris.maxVertex = geometry.geometry.triangles.maxVertex; + geoData.tris.indexType = geometry.geometry.triangles.indexType; + geoData.tris.hasTransformData = transformData; + + // Frustratingly rangeInfo.primitiveOffset represents either the offset into the index or + // vertex buffer depending if indices are in use or not + VkAccelerationStructureBuildRangeInfoKHR &buildData = geoData.buildRangeInfo; + buildData.primitiveCount = rangeInfo.primitiveCount; + buildData.primitiveOffset = 0; + buildData.firstVertex = 0; + buildData.transformOffset = 0; + + if(indexData) + { + buildData.primitiveOffset = (uint32_t)AlignUp(vertexData.size, vertexData.alignment); + buildData.firstVertex = rangeInfo.firstVertex; + } + if(transformData) + buildData.transformOffset = (uint32_t)(AlignUp(vertexData.size, vertexData.alignment) + + AlignUp(indexData.size, indexData.alignment)); + + metadata->geometryData.push_back(geoData); + + break; + } + case VK_GEOMETRY_TYPE_AABBS_KHR: + { + const VkAccelerationStructureGeometryAabbsDataKHR &aabbInfo = geometry.geometry.aabbs; + + // Find the associated VkBuffer + BufferData data = GetDeviceAddressData(aabbInfo.data.deviceAddress); + if(!data) + { + RDCERR("Unable to find VkBuffer for AABB data at 0x%llx", aabbInfo.data.deviceAddress); + continue; + } + + data.size = rangeInfo.primitiveCount * sizeof(VkAabbPositionsKHR); + data.SetReadPosition(rangeInfo.primitiveOffset); + + // Get the alignment + VkMemoryRequirements mrq = {}; + ObjDisp(device)->GetBufferMemoryRequirements(Unwrap(device), data.buf, &mrq); + + // Allocate copy buffer + readbackmem = CreateReadBackMemory(device, data.size, mrq.alignment); + if(readbackmem.mem == VK_NULL_HANDLE) + { + RDCERR("Unable to allocate AS AABB input buffer readback memory (size: %u bytes)", + mrq.size); + continue; + } + + // Insert copy commands + VkBufferCopy region = { + data.GetReadPosition(), + 0, + data.size, + }; + ObjDisp(device)->CmdCopyBuffer(Unwrap(commandBuffer), data.buf, readbackmem.buf, 1, ®ion); + + // Store the metadata + VkAccelerationStructureInfo::GeometryData geoData; + geoData.geometryType = geometry.geometryType; + geoData.flags = geometry.flags; + geoData.readbackMem = readbackmem.mem; + geoData.memSize = readbackmem.size; + + geoData.aabbs.stride = aabbInfo.stride; + + geoData.buildRangeInfo = rangeInfo; + geoData.buildRangeInfo.primitiveOffset = 0; + + metadata->geometryData.push_back(geoData); + + break; + } + case VK_GEOMETRY_TYPE_INSTANCES_KHR: + { + const VkAccelerationStructureGeometryInstancesDataKHR &instanceInfo = + geometry.geometry.instances; + + if(instanceInfo.arrayOfPointers) + return RDResult(ResultCode::InternalError, + "AS instance build arrayOfPointers unsupported"); + + // Find the associated VkBuffer + BufferData data = GetDeviceAddressData(instanceInfo.data.deviceAddress); + if(!data) + { + RDCERR("Unable to find VkBuffer for instance data at 0x%llx", + instanceInfo.data.deviceAddress); + continue; + } + + data.size = rangeInfo.primitiveCount * sizeof(VkAccelerationStructureInstanceKHR); + data.SetReadPosition(rangeInfo.primitiveOffset); + + // Get the alignment + VkMemoryRequirements mrq = {}; + ObjDisp(device)->GetBufferMemoryRequirements(Unwrap(device), data.buf, &mrq); + + // Allocate copy buffer + readbackmem = CreateReadBackMemory(device, data.size, mrq.alignment); + if(readbackmem.mem == VK_NULL_HANDLE) + { + RDCERR("Unable to allocate AS instance input buffer readback memory (size: %u bytes)", + data.size); + continue; + } + + // Insert copy commands + VkBufferCopy region = { + data.GetReadPosition(), + 0, + data.size, + }; + ObjDisp(device)->CmdCopyBuffer(Unwrap(commandBuffer), data.buf, readbackmem.buf, 1, ®ion); + + // Store the metadata + VkAccelerationStructureInfo::GeometryData geoData; + geoData.geometryType = geometry.geometryType; + geoData.flags = geometry.flags; + geoData.readbackMem = readbackmem.mem; + geoData.memSize = readbackmem.size; + + geoData.buildRangeInfo = rangeInfo; + geoData.buildRangeInfo.primitiveOffset = 0; + + metadata->geometryData.push_back(geoData); + + break; + } + default: RDCERR("Unhandled geometry type: %d", geometry.geometryType); continue; + } + + // Insert barriers to block any other commands until the buffers are copied + if(readbackmem.mem != VK_NULL_HANDLE) + { + ObjDisp(device)->CmdPipelineBarrier(Unwrap(commandBuffer), VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 0, 1, &barrier, 0, + VK_NULL_HANDLE, 0, VK_NULL_HANDLE); + + // We can schedule buffer deletion now as it isn't needed anymore + cmdRecord->cmdInfo->pendingSubmissionCompleteCallbacks->callbacks.push_back( + [device, buffer = readbackmem.buf]() { + ObjDisp(device)->DestroyBuffer(Unwrap(device), buffer, NULL); + }); + } + } + + return {}; +} + +void VulkanAccelerationStructureManager::CopyAccelerationStructure( + VkCommandBuffer commandBuffer, const VkCopyAccelerationStructureInfoKHR &pInfo, CaptureState state) +{ + VkResourceRecord *srcRecord = GetRecord(pInfo.src); + RDCASSERT(srcRecord->accelerationStructureInfo != NULL); + + // Delete any previous data associated with AS + VkResourceRecord *dstRecord = GetRecord(pInfo.dst); + VkAccelerationStructureInfo *info = dstRecord->accelerationStructureInfo; + if(!info->geometryData.empty()) + DeletePreviousInfo(commandBuffer, info, state); + + // Rather than copy the backing mem, we can just increase the ref count. If there is an update + // build to the AS then the ref will be replaced in the record, so there's no risk of aliasing. + // The copy mode is irrelevant as it doesn't affect the rebuild + dstRecord->accelerationStructureInfo = srcRecord->accelerationStructureInfo; + dstRecord->accelerationStructureInfo->AddRef(); +} + bool VulkanAccelerationStructureManager::Prepare(VkAccelerationStructureKHR unwrappedAs, const rdcarray &queueFamilyIndices, ASMemory &result) @@ -360,6 +766,112 @@ void VulkanAccelerationStructureManager::Apply(ResourceId id, const VkInitialCon } } +VulkanAccelerationStructureManager::Allocation VulkanAccelerationStructureManager::CreateReadBackMemory( + VkDevice device, VkDeviceSize size, VkDeviceSize alignment) +{ + VkBufferCreateInfo bufInfo = { + VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, + NULL, + 0, + size, + VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | + VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, + }; + + // we make the buffer concurrently accessible by all queue families to not invalidate the + // contents of the memory we're reading back from. + bufInfo.sharingMode = VK_SHARING_MODE_CONCURRENT; + bufInfo.queueFamilyIndexCount = (uint32_t)m_pDriver->GetQueueFamilyIndices().size(); + bufInfo.pQueueFamilyIndices = m_pDriver->GetQueueFamilyIndices().data(); + + // spec requires that CONCURRENT must specify more than one queue family. If there is only one + // queue family, we can safely use exclusive. + if(bufInfo.queueFamilyIndexCount == 1) + bufInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + + Allocation readbackmem; + VkResult vkr = ObjDisp(device)->CreateBuffer(Unwrap(device), &bufInfo, NULL, &readbackmem.buf); + if(vkr != VK_SUCCESS) + { + RDCERR("Failed to create readback buffer"); + return {}; + } + + VkMemoryRequirements mrq = {}; + ObjDisp(device)->GetBufferMemoryRequirements(Unwrap(device), readbackmem.buf, &mrq); + + if(alignment != 0) + mrq.alignment = RDCMAX(mrq.alignment, alignment); + + readbackmem.size = AlignUp(mrq.size, mrq.alignment); + readbackmem.size = + AlignUp(readbackmem.size, m_pDriver->GetDeviceProps().limits.nonCoherentAtomSize); + + VkMemoryAllocateFlagsInfo flagsInfo = { + VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO, + NULL, + VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT, + }; + VkMemoryAllocateInfo info = { + VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, + &flagsInfo, + readbackmem.size, + m_pDriver->GetReadbackMemoryIndex(mrq.memoryTypeBits), + }; + + vkr = ObjDisp(device)->AllocateMemory(Unwrap(device), &info, NULL, &readbackmem.mem); + if(vkr != VK_SUCCESS) + { + RDCERR("Failed to allocate readback memory"); + return {}; + } + + vkr = ObjDisp(device)->BindBufferMemory(Unwrap(device), readbackmem.buf, readbackmem.mem, 0); + if(vkr != VK_SUCCESS) + { + RDCERR("Failed to bind readback memory"); + return {}; + } + + return readbackmem; +} + +VulkanAccelerationStructureManager::RecordAndOffset VulkanAccelerationStructureManager::GetDeviceAddressData( + VkDeviceAddress address) const +{ + RecordAndOffset result; + + ResourceId id; + m_pDriver->GetResIDFromAddr(address, id, result.offset); + + // No match + if(id == ResourceId()) + return {}; + + // Convert the ID to a resource record + result.record = m_pDriver->GetResourceManager()->GetResourceRecord(id); + RDCASSERTMSG("Unable to find record", result.record, id); + if(!result.record) + return {}; + + result.address = address - result.offset; + return result; +} + +template +void VulkanAccelerationStructureManager::DeletePreviousInfo(VkCommandBuffer commandBuffer, T *info, + CaptureState state) +{ + VkResourceRecord *cmdRecord = GetRecord(commandBuffer); + cmdRecord->cmdInfo->pendingSubmissionCompleteCallbacks->callbacks.push_back( + [info]() { info->Release(); }); +} + +// OMM suport todo +template void VulkanAccelerationStructureManager::DeletePreviousInfo(VkCommandBuffer commandBuffer, + VkAccelerationStructureInfo *info, + CaptureState state); + VkDeviceSize VulkanAccelerationStructureManager::SerialisedASSize(VkAccelerationStructureKHR unwrappedAs) { VkDevice d = m_pDriver->GetDev(); diff --git a/renderdoc/driver/vulkan/vk_acceleration_structure.h b/renderdoc/driver/vulkan/vk_acceleration_structure.h index bdce6bb6b1..74aed5d657 100644 --- a/renderdoc/driver/vulkan/vk_acceleration_structure.h +++ b/renderdoc/driver/vulkan/vk_acceleration_structure.h @@ -24,14 +24,58 @@ #pragma once -#include "vk_manager.h" +#include "vk_resources.h" class WrappedVulkan; +struct VkInitialContents; -// Just holds the built flag, will eventually hold all the AS build data struct VkAccelerationStructureInfo { + struct GeometryData + { + struct Triangles + { + VkFormat vertexFormat; + VkDeviceSize vertexStride; + uint32_t maxVertex; + VkIndexType indexType; + bool hasTransformData; + }; + + struct Aabbs + { + VkDeviceSize stride; + }; + + VkGeometryTypeKHR geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR; + VkGeometryFlagsKHR flags; + + VkDeviceMemory readbackMem; + VkDeviceSize memSize; + + Triangles tris; + Aabbs aabbs; + + VkAccelerationStructureBuildRangeInfoKHR buildRangeInfo; + }; + + ~VkAccelerationStructureInfo(); + + void AddRef() { Atomic::Inc32(&refCount); } + void Release(); + + VkDevice device = VK_NULL_HANDLE; + + VkAccelerationStructureTypeKHR type = + VkAccelerationStructureTypeKHR::VK_ACCELERATION_STRUCTURE_TYPE_GENERIC_KHR; + VkBuildAccelerationStructureFlagsKHR flags = 0; + + rdcarray geometryData; + bool accelerationStructureBuilt = false; + +private: + int32_t refCount = 1; }; class VulkanAccelerationStructureManager @@ -43,8 +87,35 @@ class VulkanAccelerationStructureManager bool isTLAS; }; + struct Allocation + { + VkDeviceMemory mem = VK_NULL_HANDLE; + VkDeviceSize size = 0; + VkBuffer buf = VK_NULL_HANDLE; + }; + + struct RecordAndOffset + { + VkResourceRecord *record = NULL; + VkDeviceAddress address = 0x0; + VkDeviceSize offset = 0; + }; + explicit VulkanAccelerationStructureManager(WrappedVulkan *driver); + // Allocates readback mem and injects commands into the command buffer so that the input buffers + // are copied. + RDResult CopyInputBuffers(VkCommandBuffer commandBuffer, + const VkAccelerationStructureBuildGeometryInfoKHR &info, + const VkAccelerationStructureBuildRangeInfoKHR *buildRange, + CaptureState state); + + // Copies the metadata from src to dst, the input buffers are identical so don't need to be + // duplicated. Compaction is ignored but the copy is still performed so the dst handle is valid + // on replay + void CopyAccelerationStructure(VkCommandBuffer commandBuffer, + const VkCopyAccelerationStructureInfoKHR &pInfo, CaptureState state); + // Called when the initial state is prepared. Any TLAS and BLAS data is copied into temporary // buffers and the handles for that memory and the buffers is stored in the init state bool Prepare(VkAccelerationStructureKHR unwrappedAs, const rdcarray &queueFamilyIndices, @@ -59,6 +130,13 @@ class VulkanAccelerationStructureManager void Apply(ResourceId id, const VkInitialContents &initial); private: + Allocation CreateReadBackMemory(VkDevice device, VkDeviceSize size, VkDeviceSize alignment = 0); + + RecordAndOffset GetDeviceAddressData(VkDeviceAddress address) const; + + template + void DeletePreviousInfo(VkCommandBuffer commandBuffer, T *info, CaptureState state); + VkDeviceSize SerialisedASSize(VkAccelerationStructureKHR unwrappedAs); WrappedVulkan *m_pDriver; diff --git a/renderdoc/driver/vulkan/vk_core.h b/renderdoc/driver/vulkan/vk_core.h index 76ca8d741b..83d6b3332f 100644 --- a/renderdoc/driver/vulkan/vk_core.h +++ b/renderdoc/driver/vulkan/vk_core.h @@ -1225,6 +1225,7 @@ class WrappedVulkan : public IFrameCapturer void RemapQueueFamilyIndices(uint32_t &srcQueueFamily, uint32_t &dstQueueFamily); uint32_t GetQueueFamilyIndex() const { return m_QueueFamilyIdx; } bool ReleaseResource(WrappedVkRes *res); + const rdcarray &GetQueueFamilyIndices() const { return m_QueueFamilyIndices; } void AddDebugMessage(MessageCategory c, MessageSeverity sv, MessageSource src, rdcstr d); @@ -1275,6 +1276,7 @@ class WrappedVulkan : public IFrameCapturer void TrackBufferAddress(VkDevice device, VkBuffer buffer); void UntrackBufferAddress(VkDevice device, VkBuffer buffer); + void GetResIDFromAddr(GPUAddressRange::Address addr, ResourceId &id, uint64_t &offs); EventFlags GetEventFlags(uint32_t eid) { return m_EventFlags[eid]; } rdcarray GetUsage(ResourceId id) { return m_ResourceUses[id]; } diff --git a/renderdoc/driver/vulkan/vk_memory.cpp b/renderdoc/driver/vulkan/vk_memory.cpp index d899803edc..24c3a5a626 100644 --- a/renderdoc/driver/vulkan/vk_memory.cpp +++ b/renderdoc/driver/vulkan/vk_memory.cpp @@ -77,6 +77,11 @@ void WrappedVulkan::UntrackBufferAddress(VkDevice device, VkBuffer buffer) m_AddressTracker.RemoveFrom(rng); } +void WrappedVulkan::GetResIDFromAddr(GPUAddressRange::Address addr, ResourceId &id, uint64_t &offs) +{ + m_AddressTracker.GetResIDFromAddr(addr, id, offs); +} + void WrappedVulkan::ChooseMemoryIndices() { // we need to do this little dance because Get*MemoryIndex checks to see if the existing diff --git a/renderdoc/driver/vulkan/vk_resources.cpp b/renderdoc/driver/vulkan/vk_resources.cpp index 243ce48621..3f0a51fb67 100644 --- a/renderdoc/driver/vulkan/vk_resources.cpp +++ b/renderdoc/driver/vulkan/vk_resources.cpp @@ -3996,8 +3996,8 @@ VkResourceRecord::~VkResourceRecord() if(resType == eResCommandPool) SAFE_DELETE(cmdPoolInfo); - if(resType == eResAccelerationStructureKHR) - SAFE_DELETE(accelerationStructureInfo); + if(resType == eResAccelerationStructureKHR && accelerationStructureInfo) + accelerationStructureInfo->Release(); } void VkResourceRecord::MarkImageFrameReferenced(VkResourceRecord *img, const ImageRange &range, diff --git a/renderdoc/driver/vulkan/wrappers/vk_cmd_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_cmd_funcs.cpp index 97087c0150..9ac89b960a 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_cmd_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_cmd_funcs.cpp @@ -7873,6 +7873,15 @@ void WrappedVulkan::vkCmdBuildAccelerationStructuresKHR( // Add to the command buffer metadata, so we can know when it has been submitted record->cmdInfo->accelerationStructures.push_back(GetRecord(geomInfo.dstAccelerationStructure)); + + const RDResult copyResult = GetAccelerationStructureManager()->CopyInputBuffers( + commandBuffer, geomInfo, ppBuildRangeInfos[i], m_State); + if(copyResult != ResultCode::Succeeded) + { + m_LastCaptureError = copyResult; + RDCERR("%s", copyResult.message.c_str()); + m_CaptureFailure = true; + } } } } diff --git a/renderdoc/driver/vulkan/wrappers/vk_get_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_get_funcs.cpp index 5bc3b5a53e..3db681c281 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_get_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_get_funcs.cpp @@ -860,8 +860,9 @@ void WrappedVulkan::vkGetPhysicalDeviceFeatures2(VkPhysicalDevice physicalDevice if(accStruct && accStruct->accelerationStructureHostCommands) { - RDCWARN("Disabling support for acceleration structure host commands"); + RDCWARN("Disabling support for acceleration structure host commands and indirect builds"); accStruct->accelerationStructureHostCommands = VK_FALSE; + accStruct->accelerationStructureIndirectBuild = VK_FALSE; } } diff --git a/renderdoc/driver/vulkan/wrappers/vk_resource_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_resource_funcs.cpp index b03e4be901..2eb28a16d9 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_resource_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_resource_funcs.cpp @@ -3389,7 +3389,6 @@ VkResult WrappedVulkan::vkCreateAccelerationStructureKHR( record->baseResource = bufferRecord->GetResourceID(); record->baseResourceMem = bufferRecord->baseResource; record->dedicated = bufferRecord->dedicated; - record->resInfo = bufferRecord->resInfo; record->storable = bufferRecord->storable; record->memOffset = bufferRecord->memOffset + pCreateInfo->offset; record->memSize = pCreateInfo->size;