diff --git a/code/renderer/crp_local.h b/code/renderer/crp_local.h index 87bc26d..b4f20e8 100644 --- a/code/renderer/crp_local.h +++ b/code/renderer/crp_local.h @@ -407,7 +407,7 @@ private: FrameData frameData[RTFrameCount]; BLASBuffers staticBLASBuffers[BLASBucket::Count] = {}; - StaticUnorderedArray tlasInstanceDescs; + StaticArray tlasInstanceDescs; uint32_t staticTLASInstanceCount = 0; }; diff --git a/code/renderer/crp_prepass.cpp b/code/renderer/crp_prepass.cpp index 665cfef..115462e 100644 --- a/code/renderer/crp_prepass.cpp +++ b/code/renderer/crp_prepass.cpp @@ -130,7 +130,7 @@ struct EntityTracker } private: - typedef RHI::StaticUnorderedArray EntityArray; + typedef RHI::StaticArray EntityArray; EntityArray entities[2]; EntityArray* currEnts = &entities[0]; EntityArray* prevEnts = &entities[1]; diff --git a/code/renderer/rhi_d3d12.cpp b/code/renderer/rhi_d3d12.cpp index 64485d5..91130a9 100644 --- a/code/renderer/rhi_d3d12.cpp +++ b/code/renderer/rhi_d3d12.cpp @@ -276,7 +276,9 @@ namespace RHI uint32_t uavIndex; bool mapped; bool uploading; - UINT64 uploadByteOffset; + UINT64 uploadSrcByteOffset; + UINT64 uploadDestByteOffset; + UINT64 uploadByteCount; bool shortLifeTime = false; }; @@ -372,7 +374,7 @@ namespace RHI { void Create(); void Release(); - uint8_t* BeginBufferUpload(HBuffer buffer); + uint8_t* BeginBufferUpload(HBuffer buffer, uint32_t destByteOffset, uint32_t byteCount); void EndBufferUpload(HBuffer buffer); void BeginTextureUpload(MappedTexture& mappedTexture, HTexture texture); void EndTextureUpload(); @@ -635,9 +637,9 @@ namespace RHI LinearAllocator tempStringAllocator; UploadManager upload; ReadbackManager readback; - StaticUnorderedArray texturesToTransition; - StaticUnorderedArray buffersToTransition; - StaticUnorderedArray buffersToDelete; + StaticArray texturesToTransition; + StaticArray buffersToTransition; + StaticArray buffersToDelete; FrameQueries frameQueries[FrameCount]; ResolvedQueries resolvedQueries; PIX pix; @@ -743,7 +745,12 @@ namespace RHI } // fatal error mode always on for now - ri.Error(ERR_FATAL, "'%s' failed with code 0x%08X (%s)\n", function, (unsigned int)hr, GetSystemErrorString(hr)); + const char* const errorMessage = GetSystemErrorString(hr); + if(IsDebuggerPresent()) + { + __debugbreak(); + } + ri.Error(ERR_FATAL, "'%s' failed with code 0x%08X (%s)\n", function, (unsigned int)hr, errorMessage); return false; } @@ -958,7 +965,7 @@ namespace RHI COM_RELEASE(commandAllocator); } - uint8_t* UploadManager::BeginBufferUpload(HBuffer userHBuffer) + uint8_t* UploadManager::BeginBufferUpload(HBuffer userHBuffer, uint32_t destByteOffset, uint32_t byteCount) { Q_assert(bufferUploadCounter >= 0); bufferUploadCounter++; @@ -968,20 +975,29 @@ namespace RHI } Buffer& userBuffer = rhi.buffers.Get(userHBuffer); + Buffer& uploadBuffer = rhi.buffers.Get(uploadHBuffer); Q_assert(!userBuffer.uploading); + if(byteCount == 0) + { + Q_assert(destByteOffset == 0); + destByteOffset = 0; + byteCount = min(userBuffer.desc.byteCount, uploadBuffer.desc.byteCount); + } + Q_assert(destByteOffset + byteCount <= userBuffer.desc.byteCount); uint8_t* mapped = NULL; Q_assert(userBuffer.desc.memoryUsage != MemoryUsage::Readback); if(userBuffer.desc.memoryUsage == MemoryUsage::GPU && rhi.umaPool == NULL) { - const uint32_t uploadByteCount = userBuffer.desc.byteCount; - WaitToStartUploading(uploadByteCount); + WaitToStartUploading(byteCount); mapped = mappedBuffer + bufferByteOffset; - userBuffer.uploadByteOffset = bufferByteOffset; + userBuffer.uploadSrcByteOffset = bufferByteOffset; + userBuffer.uploadDestByteOffset = destByteOffset; + userBuffer.uploadByteCount = byteCount; - bufferByteOffset = AlignUp(bufferByteOffset + uploadByteCount, D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT); + bufferByteOffset = AlignUp(bufferByteOffset + byteCount, D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT); if(multiBufferUpload) { @@ -1008,19 +1024,21 @@ namespace RHI Buffer& userBuffer = rhi.buffers.Get(userHBuffer); Q_assert(userBuffer.uploading); - Buffer& uploadBuffer = rhi.buffers.Get(uploadHBuffer); - if(!userBuffer.mapped) { D3D(commandList->Reset(commandAllocator, NULL)); - const UINT64 byteCount = min(userBuffer.desc.byteCount, uploadBuffer.desc.byteCount); #if defined(RHI_ENABLE_AFTERMATH) + const uint64_t byteCount = (uint64_t)userBuffer.uploadByteCount; const char* const marker = va("Upload: CopyBufferRegion -> %s (%s)", userBuffer.desc.name, Com_FormatBytes(byteCount)); const GFSDK_Aftermath_Result result = GFSDK_Aftermath_SetEventMarker(rhi.aftermathUploadCommandList, marker, strlen(marker) + 1); Q_assert(result == GFSDK_Aftermath_Result_Success); #endif - commandList->CopyBufferRegion(userBuffer.buffer, 0, uploadBuffer.buffer, userBuffer.uploadByteOffset, byteCount); + const Buffer& uploadBuffer = rhi.buffers.Get(uploadHBuffer); + commandList->CopyBufferRegion( + userBuffer.buffer, userBuffer.uploadDestByteOffset, + uploadBuffer.buffer, userBuffer.uploadSrcByteOffset, + userBuffer.uploadByteCount); ID3D12CommandList* commandLists[] = { commandList }; D3D(commandList->Close()); @@ -3003,6 +3021,10 @@ namespace RHI TableRow(2, "Shader model", model); } + TableRow(2, "UMA", rhiInfo.isUMA ? "YES" : "NO"); + TableRow(2, "Cache-coherent UMA", rhiInfo.isCacheCoherentUMA ? "YES" : "NO"); + TableRow(2, "Barycentrics", rhiInfo.hasBarycentrics ? "YES" : "NO"); + // the validation layer reports live objects at shutdown when NvAPI_D3D12_QueryCpuVisibleVidmem is called #if defined(RHI_ENABLE_NVAPI) if(rhi.nvapiActive) @@ -3710,6 +3732,7 @@ namespace RHI rhiInfo.isCacheCoherentUMA = rhi.allocator->IsCacheCoherentUMA(); rhiInfo.hasInlineRaytracing = hasInlineRaytracing; rhiInfo.hasBarycentrics = hasBarycentrics; + rhiInfo.allocatedByteCount = 0; rhi.initialized = true; @@ -3880,6 +3903,9 @@ namespace RHI } #endif + D3D12MA::Budget budget; + rhi.allocator->GetBudget(&budget, NULL); + rhiInfo.allocatedByteCount = (uint64_t)budget.UsageBytes; DrawGUI(); Q_assert(rhi.commandList == rhi.mainCommandList); @@ -3926,7 +3952,7 @@ namespace RHI if(rhi.beginFrameCounter >= rhi.buffersToDelete[b].beginFrameCounter) { DestroyBuffer(rhi.buffersToDelete[b].buffer); - rhi.buffersToDelete.Remove(b); + rhi.buffersToDelete.RemoveUnordered(b); } else { @@ -5497,9 +5523,10 @@ namespace RHI memcpy(gpuMicroSeconds, rhi.resolvedQueries.gpuMicroSeconds, rhi.resolvedQueries.durationQueryCount * sizeof(uint32_t)); } - uint8_t* BeginBufferUpload(HBuffer buffer) + uint8_t* BeginBufferUpload(HBuffer buffer, uint32_t destByteOffset, uint32_t byteCount) { - return rhi.upload.BeginBufferUpload(buffer); + Q_assert(!IsNullHandle(buffer)); + return rhi.upload.BeginBufferUpload(buffer, destByteOffset, byteCount); } void EndBufferUpload(HBuffer buffer) @@ -5509,6 +5536,7 @@ namespace RHI void BeginTextureUpload(MappedTexture& mappedTexture, HTexture texture) { + Q_assert(!IsNullHandle(texture)); rhi.upload.BeginTextureUpload(mappedTexture, texture); } diff --git a/code/renderer/rhi_local.h b/code/renderer/rhi_local.h index 8758dd3..6eb7f24 100644 --- a/code/renderer/rhi_local.h +++ b/code/renderer/rhi_local.h @@ -818,7 +818,7 @@ namespace RHI uint32_t GetDurationCount(); void GetDurations(uint32_t* gpuMicroSeconds); - uint8_t* BeginBufferUpload(HBuffer buffer); + uint8_t* BeginBufferUpload(HBuffer buffer, uint32_t destByteOffset = 0, uint32_t byteCount = 0); void EndBufferUpload(HBuffer buffer); void BeginTextureUpload(MappedTexture& mappedTexture, HTexture texture); @@ -1012,9 +1012,9 @@ namespace RHI }; template - struct StaticUnorderedArray + struct StaticArray { - StaticUnorderedArray() + StaticArray() { Clear(); } @@ -1033,7 +1033,23 @@ namespace RHI void Remove(uint32_t index) { Q_assert(index < N); - if(count >= N) + if(index >= N) + { + return; + } + + if(index < count - 1) + { + const uint32_t moveCount = count - (index + 1); + memmove(&items[index], &items[index + 1], sizeof(T) * (size_t)moveCount); + } + count--; + } + + void RemoveUnordered(uint32_t index) + { + Q_assert(index < N); + if(index >= N) { return; } @@ -1045,6 +1061,23 @@ namespace RHI count--; } + void RemoveRange(uint32_t index, uint32_t removalCount) + { + Q_assert(index < count); + Q_assert(index + removalCount <= count); + if(removalCount == 0 || index + removalCount > count) + { + return; + } + + if(index + removalCount < count) + { + const uint32_t moveCount = count - (index + removalCount); + memmove(&items[index], &items[index + removalCount], sizeof(T) * (size_t)moveCount); + } + count -= removalCount; + } + void Clear() { count = 0; @@ -1064,13 +1097,24 @@ namespace RHI return items[index]; } + bool IsFull() const + { + return count == N; + } + + bool IsEmpty() const + { + return count == 0; + } + private: - StaticUnorderedArray(const StaticUnorderedArray&); - void operator=(const StaticUnorderedArray&); + StaticArray(const StaticArray&); + void operator=(const StaticArray&); public: T items[N]; uint32_t count; + const uint32_t capacity = N; }; template diff --git a/code/renderer/tr_gui.cpp b/code/renderer/tr_gui.cpp index 3b4c781..aceb117 100644 --- a/code/renderer/tr_gui.cpp +++ b/code/renderer/tr_gui.cpp @@ -1924,7 +1924,7 @@ void RE_DrawMainMenuBarInfo() frameCount = 0; } - const char* const info = va("%s | %3d FPS", rhiInfo.adapter, displayedFPS); + const char* const info = va("%s | %s | %3d FPS", rhiInfo.adapter, Com_FormatBytes(rhiInfo.allocatedByteCount), displayedFPS); const float offset = ImGui::GetWindowWidth() - ImGui::CalcTextSize("___").x - ImGui::CalcTextSize(info).x; ImGui::SameLine(offset); ImGui::Text(info); diff --git a/code/renderer/tr_local.h b/code/renderer/tr_local.h index 869509f..540ce44 100644 --- a/code/renderer/tr_local.h +++ b/code/renderer/tr_local.h @@ -1766,6 +1766,7 @@ struct RHIInfo { char name[MAX_QPATH]; char adapter[MAX_QPATH]; + uint64_t allocatedByteCount; qbool hasTearing; qbool hasBaseVRS; qbool hasExtendedVRS;