diff --git a/editor/src/Viewport/ViewportHostService.h b/editor/src/Viewport/ViewportHostService.h index b038b07e..5ddaf1d0 100644 --- a/editor/src/Viewport/ViewportHostService.h +++ b/editor/src/Viewport/ViewportHostService.h @@ -15,7 +15,6 @@ #include #include -#include #include #include #include @@ -89,181 +88,6 @@ inline uint32_t ClampViewportPixelCoordinate(float value, uint32_t extent) { return static_cast(std::floor(clamped)); } -inline bool WaitForD3D12QueueIdle( - ID3D12Device* device, - ID3D12CommandQueue* commandQueue) { - if (device == nullptr || commandQueue == nullptr) { - return false; - } - - ID3D12Fence* fence = nullptr; - if (FAILED(device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&fence)))) { - return false; - } - - HANDLE fenceEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr); - if (fenceEvent == nullptr) { - fence->Release(); - return false; - } - - constexpr UINT64 kFenceValue = 1; - const HRESULT signalResult = commandQueue->Signal(fence, kFenceValue); - if (FAILED(signalResult)) { - CloseHandle(fenceEvent); - fence->Release(); - return false; - } - - if (fence->GetCompletedValue() < kFenceValue) { - if (FAILED(fence->SetEventOnCompletion(kFenceValue, fenceEvent))) { - CloseHandle(fenceEvent); - fence->Release(); - return false; - } - WaitForSingleObject(fenceEvent, INFINITE); - } - - CloseHandle(fenceEvent); - fence->Release(); - return true; -} - -inline bool ReadBackD3D12TexturePixel( - RHI::D3D12Device& device, - RHI::D3D12CommandQueue& commandQueue, - RHI::D3D12Texture& texture, - RHI::ResourceStates sourceState, - uint32_t pixelX, - uint32_t pixelY, - std::array& outRgba) { - ID3D12Device* nativeDevice = device.GetDevice(); - ID3D12CommandQueue* nativeCommandQueue = commandQueue.GetCommandQueue(); - ID3D12Resource* sourceResource = texture.GetResource(); - if (nativeDevice == nullptr || - nativeCommandQueue == nullptr || - sourceResource == nullptr || - pixelX >= texture.GetWidth() || - pixelY >= texture.GetHeight()) { - return false; - } - - ID3D12CommandAllocator* commandAllocator = nullptr; - if (FAILED(nativeDevice->CreateCommandAllocator( - D3D12_COMMAND_LIST_TYPE_DIRECT, - IID_PPV_ARGS(&commandAllocator)))) { - return false; - } - - ID3D12GraphicsCommandList* commandList = nullptr; - if (FAILED(nativeDevice->CreateCommandList( - 0, - D3D12_COMMAND_LIST_TYPE_DIRECT, - commandAllocator, - nullptr, - IID_PPV_ARGS(&commandList)))) { - commandAllocator->Release(); - return false; - } - - D3D12_HEAP_PROPERTIES heapProperties = {}; - heapProperties.Type = D3D12_HEAP_TYPE_READBACK; - - constexpr UINT kRowPitch = D3D12_TEXTURE_DATA_PITCH_ALIGNMENT; - D3D12_RESOURCE_DESC readbackDesc = {}; - readbackDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; - readbackDesc.Width = kRowPitch; - readbackDesc.Height = 1; - readbackDesc.DepthOrArraySize = 1; - readbackDesc.MipLevels = 1; - readbackDesc.SampleDesc.Count = 1; - readbackDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; - - ID3D12Resource* readbackBuffer = nullptr; - if (FAILED(nativeDevice->CreateCommittedResource( - &heapProperties, - D3D12_HEAP_FLAG_NONE, - &readbackDesc, - D3D12_RESOURCE_STATE_COPY_DEST, - nullptr, - IID_PPV_ARGS(&readbackBuffer)))) { - commandList->Release(); - commandAllocator->Release(); - return false; - } - - D3D12_RESOURCE_BARRIER barrier = {}; - barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; - barrier.Transition.pResource = sourceResource; - barrier.Transition.StateBefore = RHI::ToD3D12(sourceState); - barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_COPY_SOURCE; - barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; - commandList->ResourceBarrier(1, &barrier); - - D3D12_TEXTURE_COPY_LOCATION srcLocation = {}; - srcLocation.pResource = sourceResource; - srcLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; - srcLocation.SubresourceIndex = 0; - - D3D12_RESOURCE_DESC sourceDesc = sourceResource->GetDesc(); - D3D12_TEXTURE_COPY_LOCATION dstLocation = {}; - dstLocation.pResource = readbackBuffer; - dstLocation.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT; - dstLocation.PlacedFootprint.Offset = 0; - dstLocation.PlacedFootprint.Footprint.Format = sourceDesc.Format; - dstLocation.PlacedFootprint.Footprint.Width = 1; - dstLocation.PlacedFootprint.Footprint.Height = 1; - dstLocation.PlacedFootprint.Footprint.Depth = 1; - dstLocation.PlacedFootprint.Footprint.RowPitch = kRowPitch; - - D3D12_BOX sourceBox = {}; - sourceBox.left = pixelX; - sourceBox.top = pixelY; - sourceBox.front = 0; - sourceBox.right = pixelX + 1u; - sourceBox.bottom = pixelY + 1u; - sourceBox.back = 1; - commandList->CopyTextureRegion(&dstLocation, 0, 0, 0, &srcLocation, &sourceBox); - - barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_SOURCE; - barrier.Transition.StateAfter = RHI::ToD3D12(sourceState); - commandList->ResourceBarrier(1, &barrier); - - if (FAILED(commandList->Close())) { - readbackBuffer->Release(); - commandList->Release(); - commandAllocator->Release(); - return false; - } - - ID3D12CommandList* commandLists[] = { commandList }; - nativeCommandQueue->ExecuteCommandLists(1, commandLists); - if (!WaitForD3D12QueueIdle(nativeDevice, nativeCommandQueue)) { - readbackBuffer->Release(); - commandList->Release(); - commandAllocator->Release(); - return false; - } - - void* mappedData = nullptr; - D3D12_RANGE readRange = { 0, 4 }; - if (FAILED(readbackBuffer->Map(0, &readRange, &mappedData))) { - readbackBuffer->Release(); - commandList->Release(); - commandAllocator->Release(); - return false; - } - - std::memcpy(outRgba.data(), mappedData, outRgba.size()); - D3D12_RANGE writeRange = { 0, 0 }; - readbackBuffer->Unmap(0, &writeRange); - - readbackBuffer->Release(); - commandList->Release(); - commandAllocator->Release(); - return true; -} - Math::Vector3 GetSceneViewportOrientationAxisVector(SceneViewportOrientationAxis axis) { switch (axis) { case SceneViewportOrientationAxis::PositiveX: @@ -1191,19 +1015,17 @@ private: } auto* commandQueue = - static_cast(m_sceneViewLastRenderContext.commandQueue); - auto* objectIdTexture = static_cast(entry.objectIdTexture); - if (commandQueue == nullptr || objectIdTexture == nullptr) { + m_sceneViewLastRenderContext.commandQueue; + if (commandQueue == nullptr) { return false; } const uint32_t pixelX = ClampViewportPixelCoordinate(viewportMousePosition.x, entry.width); const uint32_t pixelY = ClampViewportPixelCoordinate(viewportMousePosition.y, entry.height); std::array rgba = {}; - if (!ReadBackD3D12TexturePixel( - *m_device, - *commandQueue, - *objectIdTexture, + if (!m_device->ReadTexturePixelRGBA8( + commandQueue, + entry.objectIdTexture, entry.objectIdState, pixelX, pixelY, diff --git a/engine/include/XCEngine/RHI/D3D12/D3D12Device.h b/engine/include/XCEngine/RHI/D3D12/D3D12Device.h index 21453746..8ef6b53c 100644 --- a/engine/include/XCEngine/RHI/D3D12/D3D12Device.h +++ b/engine/include/XCEngine/RHI/D3D12/D3D12Device.h @@ -95,6 +95,13 @@ public: RHIResourceView* CreateDepthStencilView(RHITexture* texture, const ResourceViewDesc& desc) override; RHIResourceView* CreateShaderResourceView(RHITexture* texture, const ResourceViewDesc& desc) override; RHIResourceView* CreateUnorderedAccessView(RHITexture* texture, const ResourceViewDesc& desc) override; + bool ReadTexturePixelRGBA8( + RHICommandQueue* commandQueue, + RHITexture* texture, + ResourceStates sourceState, + uint32_t pixelX, + uint32_t pixelY, + std::array& outRgba) override; const RHICapabilities& GetCapabilities() const override; const RHIDeviceInfo& GetDeviceInfo() const override; diff --git a/engine/include/XCEngine/RHI/D3D12/D3D12Enums.h b/engine/include/XCEngine/RHI/D3D12/D3D12Enums.h index 5fffe40c..cfb4387c 100644 --- a/engine/include/XCEngine/RHI/D3D12/D3D12Enums.h +++ b/engine/include/XCEngine/RHI/D3D12/D3D12Enums.h @@ -144,6 +144,7 @@ inline DXGI_FORMAT ToD3D12(Format format) { case Format::R16_Float: return DXGI_FORMAT_R16_FLOAT; case Format::R32_Float: return DXGI_FORMAT_R32_FLOAT; case Format::R32G32_Float: return DXGI_FORMAT_R32G32_FLOAT; + case Format::R32G32B32_Float: return DXGI_FORMAT_R32G32B32_FLOAT; case Format::D16_UNorm: return DXGI_FORMAT_D16_UNORM; case Format::D24_UNorm_S8_UInt: return DXGI_FORMAT_D24_UNORM_S8_UINT; case Format::D32_Float: return DXGI_FORMAT_D32_FLOAT; @@ -172,6 +173,7 @@ inline Format FromD3D12(DXGI_FORMAT format) { case DXGI_FORMAT_R16_FLOAT: return Format::R16_Float; case DXGI_FORMAT_R32_FLOAT: return Format::R32_Float; case DXGI_FORMAT_R32G32_FLOAT: return Format::R32G32_Float; + case DXGI_FORMAT_R32G32B32_FLOAT: return Format::R32G32B32_Float; case DXGI_FORMAT_D16_UNORM: return Format::D16_UNorm; case DXGI_FORMAT_D24_UNORM_S8_UINT: return Format::D24_UNorm_S8_UInt; case DXGI_FORMAT_D32_FLOAT: return Format::D32_Float; diff --git a/engine/include/XCEngine/RHI/RHIDevice.h b/engine/include/XCEngine/RHI/RHIDevice.h index be8cf725..00196380 100644 --- a/engine/include/XCEngine/RHI/RHIDevice.h +++ b/engine/include/XCEngine/RHI/RHIDevice.h @@ -6,6 +6,8 @@ #include "RHIDescriptorSet.h" #include "RHIRenderPass.h" #include "RHIFramebuffer.h" + +#include #include namespace XCEngine { @@ -65,6 +67,22 @@ public: virtual RHIResourceView* CreateShaderResourceView(RHITexture* texture, const ResourceViewDesc& desc) = 0; virtual RHIResourceView* CreateUnorderedAccessView(RHITexture* texture, const ResourceViewDesc& desc) = 0; + virtual bool ReadTexturePixelRGBA8( + RHICommandQueue* commandQueue, + RHITexture* texture, + ResourceStates sourceState, + uint32_t pixelX, + uint32_t pixelY, + std::array& outRgba) { + (void)commandQueue; + (void)texture; + (void)sourceState; + (void)pixelX; + (void)pixelY; + outRgba = {}; + return false; + } + virtual const RHICapabilities& GetCapabilities() const = 0; virtual const RHIDeviceInfo& GetDeviceInfo() const = 0; diff --git a/engine/include/XCEngine/RHI/RHIEnums.h b/engine/include/XCEngine/RHI/RHIEnums.h index 4a282e01..54ad8a60 100644 --- a/engine/include/XCEngine/RHI/RHIEnums.h +++ b/engine/include/XCEngine/RHI/RHIEnums.h @@ -316,7 +316,8 @@ enum class Format : uint32_t { BC7_UNorm, R32G32B32A32_UInt, R32_UInt, - R32G32_Float + R32G32_Float, + R32G32B32_Float }; enum class ResourceStates : uint32_t { diff --git a/engine/include/XCEngine/RHI/Vulkan/VulkanCommon.h b/engine/include/XCEngine/RHI/Vulkan/VulkanCommon.h index 22fae948..b560d663 100644 --- a/engine/include/XCEngine/RHI/Vulkan/VulkanCommon.h +++ b/engine/include/XCEngine/RHI/Vulkan/VulkanCommon.h @@ -91,6 +91,8 @@ inline VkFormat ToVulkanFormat(Format format) { return VK_FORMAT_R32_UINT; case Format::R32G32_Float: return VK_FORMAT_R32G32_SFLOAT; + case Format::R32G32B32_Float: + return VK_FORMAT_R32G32B32_SFLOAT; case Format::R32G32B32A32_Float: return VK_FORMAT_R32G32B32A32_SFLOAT; default: @@ -116,6 +118,8 @@ inline uint32_t GetFormatSize(Format format) { return 4; case Format::R32G32_Float: return 8; + case Format::R32G32B32_Float: + return 12; case Format::R32G32B32A32_Float: return 16; default: @@ -146,6 +150,8 @@ inline Format ToRHIFormat(VkFormat format) { return Format::R32_UInt; case VK_FORMAT_R32G32_SFLOAT: return Format::R32G32_Float; + case VK_FORMAT_R32G32B32_SFLOAT: + return Format::R32G32B32_Float; case VK_FORMAT_R32G32B32A32_SFLOAT: return Format::R32G32B32A32_Float; default: diff --git a/engine/src/RHI/D3D12/D3D12Device.cpp b/engine/src/RHI/D3D12/D3D12Device.cpp index 46ab47d3..9cf13c4e 100644 --- a/engine/src/RHI/D3D12/D3D12Device.cpp +++ b/engine/src/RHI/D3D12/D3D12Device.cpp @@ -61,6 +61,46 @@ bool CompileD3D12Shader(const ShaderCompileDesc& desc, D3D12Shader& shader) { return false; } +bool WaitForQueueIdle( + ID3D12Device* device, + ID3D12CommandQueue* commandQueue) { + if (device == nullptr || commandQueue == nullptr) { + return false; + } + + ID3D12Fence* fence = nullptr; + if (FAILED(device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&fence)))) { + return false; + } + + HANDLE fenceEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr); + if (fenceEvent == nullptr) { + fence->Release(); + return false; + } + + constexpr UINT64 kFenceValue = 1; + const HRESULT signalResult = commandQueue->Signal(fence, kFenceValue); + if (FAILED(signalResult)) { + CloseHandle(fenceEvent); + fence->Release(); + return false; + } + + if (fence->GetCompletedValue() < kFenceValue) { + if (FAILED(fence->SetEventOnCompletion(kFenceValue, fenceEvent))) { + CloseHandle(fenceEvent); + fence->Release(); + return false; + } + WaitForSingleObject(fenceEvent, INFINITE); + } + + CloseHandle(fenceEvent); + fence->Release(); + return true; +} + uint32_t GetFormatBytesPerPixel(Format format) { switch (format) { case Format::R8_UNorm: @@ -77,6 +117,8 @@ uint32_t GetFormatBytesPerPixel(Format format) { return 4; case Format::R32G32_Float: return 8; + case Format::R32G32B32_Float: + return 12; case Format::R32G32B32A32_Float: return 16; default: @@ -383,6 +425,142 @@ void* D3D12Device::GetNativeDevice() { return m_device.Get(); } +bool D3D12Device::ReadTexturePixelRGBA8( + RHICommandQueue* commandQueue, + RHITexture* texture, + ResourceStates sourceState, + uint32_t pixelX, + uint32_t pixelY, + std::array& outRgba) { + outRgba = {}; + + auto* d3d12Queue = static_cast(commandQueue); + auto* d3d12Texture = static_cast(texture); + if (m_device == nullptr || + d3d12Queue == nullptr || + d3d12Texture == nullptr || + d3d12Texture->GetResource() == nullptr || + pixelX >= d3d12Texture->GetWidth() || + pixelY >= d3d12Texture->GetHeight()) { + return false; + } + + ID3D12CommandAllocator* commandAllocator = nullptr; + if (FAILED(m_device->CreateCommandAllocator( + D3D12_COMMAND_LIST_TYPE_DIRECT, + IID_PPV_ARGS(&commandAllocator)))) { + return false; + } + + ID3D12GraphicsCommandList* commandList = nullptr; + if (FAILED(m_device->CreateCommandList( + 0, + D3D12_COMMAND_LIST_TYPE_DIRECT, + commandAllocator, + nullptr, + IID_PPV_ARGS(&commandList)))) { + commandAllocator->Release(); + return false; + } + + constexpr UINT kRowPitch = D3D12_TEXTURE_DATA_PITCH_ALIGNMENT; + D3D12_HEAP_PROPERTIES heapProperties = {}; + heapProperties.Type = D3D12_HEAP_TYPE_READBACK; + + D3D12_RESOURCE_DESC readbackDesc = {}; + readbackDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; + readbackDesc.Width = kRowPitch; + readbackDesc.Height = 1; + readbackDesc.DepthOrArraySize = 1; + readbackDesc.MipLevels = 1; + readbackDesc.SampleDesc.Count = 1; + readbackDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; + + ID3D12Resource* readbackBuffer = nullptr; + if (FAILED(m_device->CreateCommittedResource( + &heapProperties, + D3D12_HEAP_FLAG_NONE, + &readbackDesc, + D3D12_RESOURCE_STATE_COPY_DEST, + nullptr, + IID_PPV_ARGS(&readbackBuffer)))) { + commandList->Release(); + commandAllocator->Release(); + return false; + } + + ID3D12Resource* sourceResource = d3d12Texture->GetResource(); + D3D12_RESOURCE_BARRIER barrier = {}; + barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; + barrier.Transition.pResource = sourceResource; + barrier.Transition.StateBefore = ToD3D12(sourceState); + barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_COPY_SOURCE; + barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; + commandList->ResourceBarrier(1, &barrier); + + D3D12_TEXTURE_COPY_LOCATION srcLocation = {}; + srcLocation.pResource = sourceResource; + srcLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; + srcLocation.SubresourceIndex = 0; + + D3D12_TEXTURE_COPY_LOCATION dstLocation = {}; + dstLocation.pResource = readbackBuffer; + dstLocation.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT; + dstLocation.PlacedFootprint.Offset = 0; + dstLocation.PlacedFootprint.Footprint.Format = sourceResource->GetDesc().Format; + dstLocation.PlacedFootprint.Footprint.Width = 1; + dstLocation.PlacedFootprint.Footprint.Height = 1; + dstLocation.PlacedFootprint.Footprint.Depth = 1; + dstLocation.PlacedFootprint.Footprint.RowPitch = kRowPitch; + + D3D12_BOX sourceBox = {}; + sourceBox.left = pixelX; + sourceBox.top = pixelY; + sourceBox.front = 0; + sourceBox.right = pixelX + 1u; + sourceBox.bottom = pixelY + 1u; + sourceBox.back = 1; + commandList->CopyTextureRegion(&dstLocation, 0, 0, 0, &srcLocation, &sourceBox); + + barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_SOURCE; + barrier.Transition.StateAfter = ToD3D12(sourceState); + commandList->ResourceBarrier(1, &barrier); + + if (FAILED(commandList->Close())) { + readbackBuffer->Release(); + commandList->Release(); + commandAllocator->Release(); + return false; + } + + ID3D12CommandList* commandLists[] = { commandList }; + d3d12Queue->GetCommandQueue()->ExecuteCommandLists(1, commandLists); + if (!WaitForQueueIdle(m_device.Get(), d3d12Queue->GetCommandQueue())) { + readbackBuffer->Release(); + commandList->Release(); + commandAllocator->Release(); + return false; + } + + void* mappedData = nullptr; + D3D12_RANGE readRange = { 0, 4 }; + if (FAILED(readbackBuffer->Map(0, &readRange, &mappedData))) { + readbackBuffer->Release(); + commandList->Release(); + commandAllocator->Release(); + return false; + } + + std::memcpy(outRgba.data(), mappedData, outRgba.size()); + D3D12_RANGE writeRange = { 0, 0 }; + readbackBuffer->Unmap(0, &writeRange); + + readbackBuffer->Release(); + commandList->Release(); + commandAllocator->Release(); + return true; +} + const RHICapabilities& D3D12Device::GetCapabilities() const { return m_capabilities; }