TextureDX12.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. // Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
  2. // SPDX-FileCopyrightText: 2024 Jorrit Rouwe
  3. // SPDX-License-Identifier: MIT
  4. #include <TestFramework.h>
  5. #include <Renderer/DX12/TextureDX12.h>
  6. #include <Renderer/DX12/RendererDX12.h>
  7. #include <Renderer/DX12/FatalErrorIfFailedDX12.h>
  8. #include <Image/BlitSurface.h>
  9. TextureDX12::TextureDX12(RendererDX12 *inRenderer, const Surface *inSurface) :
  10. Texture(inSurface->GetWidth(), inSurface->GetHeight()),
  11. mRenderer(inRenderer)
  12. {
  13. // Create description
  14. D3D12_RESOURCE_DESC desc = {};
  15. desc.MipLevels = 1;
  16. ESurfaceFormat format = inSurface->GetFormat();
  17. switch (format)
  18. {
  19. case ESurfaceFormat::A4L4: desc.Format = DXGI_FORMAT_R8G8_UNORM; format = ESurfaceFormat::A8L8; break;
  20. case ESurfaceFormat::L8: desc.Format = DXGI_FORMAT_R8_UNORM; break;
  21. case ESurfaceFormat::A8: desc.Format = DXGI_FORMAT_A8_UNORM; break;
  22. case ESurfaceFormat::A8L8: desc.Format = DXGI_FORMAT_R8G8_UNORM; break;
  23. case ESurfaceFormat::R5G6B5: desc.Format = DXGI_FORMAT_B5G6R5_UNORM; break;
  24. case ESurfaceFormat::X1R5G5B5: desc.Format = DXGI_FORMAT_B5G5R5A1_UNORM; format = ESurfaceFormat::A1R5G5B5; break;
  25. case ESurfaceFormat::X4R4G4B4: desc.Format = DXGI_FORMAT_B4G4R4A4_UNORM; format = ESurfaceFormat::A4R4G4B4; break;
  26. case ESurfaceFormat::A1R5G5B5: desc.Format = DXGI_FORMAT_B5G5R5A1_UNORM; break;
  27. case ESurfaceFormat::A4R4G4B4: desc.Format = DXGI_FORMAT_B4G4R4A4_UNORM; break;
  28. case ESurfaceFormat::R8G8B8: desc.Format = DXGI_FORMAT_B8G8R8X8_UNORM; format = ESurfaceFormat::X8R8G8B8; break;
  29. case ESurfaceFormat::B8G8R8: desc.Format = DXGI_FORMAT_B8G8R8X8_UNORM; format = ESurfaceFormat::X8R8G8B8; break;
  30. case ESurfaceFormat::X8R8G8B8: desc.Format = DXGI_FORMAT_B8G8R8X8_UNORM; break;
  31. case ESurfaceFormat::X8B8G8R8: desc.Format = DXGI_FORMAT_B8G8R8X8_UNORM; format = ESurfaceFormat::X8R8G8B8; break;
  32. case ESurfaceFormat::A8R8G8B8: desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; break;
  33. case ESurfaceFormat::A8B8G8R8: desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; format = ESurfaceFormat::A8R8G8B8; break;
  34. case ESurfaceFormat::Invalid:
  35. default: JPH_ASSERT(false); break;
  36. }
  37. desc.Width = mWidth;
  38. desc.Height = mHeight;
  39. desc.Flags = D3D12_RESOURCE_FLAG_NONE;
  40. desc.DepthOrArraySize = 1;
  41. desc.SampleDesc.Count = 1;
  42. desc.SampleDesc.Quality = 0;
  43. desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
  44. // Blit the surface to another temporary surface if the format changed
  45. const Surface *surface = inSurface;
  46. Ref<Surface> tmp;
  47. if (format != inSurface->GetFormat())
  48. {
  49. tmp = new SoftwareSurface(mWidth, mHeight, format);
  50. BlitSurface(inSurface, tmp);
  51. surface = tmp;
  52. }
  53. // Create texture in default heap
  54. D3D12_HEAP_PROPERTIES heap_properties = {};
  55. heap_properties.Type = D3D12_HEAP_TYPE_DEFAULT;
  56. heap_properties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
  57. heap_properties.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
  58. heap_properties.CreationNodeMask = 1;
  59. heap_properties.VisibleNodeMask = 1;
  60. FatalErrorIfFailed(inRenderer->GetDevice()->CreateCommittedResource(&heap_properties, D3D12_HEAP_FLAG_NONE, &desc, D3D12_RESOURCE_STATE_COPY_DEST, nullptr, IID_PPV_ARGS(&mTexture)));
  61. JPH_IF_DEBUG(mTexture->SetName(L"Texture");)
  62. // Determine required size of data to copy
  63. D3D12_PLACED_SUBRESOURCE_FOOTPRINT footprint;
  64. UINT64 row_size_in_bytes;
  65. UINT64 required_size = 0;
  66. inRenderer->GetDevice()->GetCopyableFootprints(&desc, 0, 1, 0, &footprint, nullptr, &row_size_in_bytes, &required_size);
  67. // Create the GPU upload buffer
  68. ComPtr<ID3D12Resource> upload_resource = mRenderer->CreateD3DResourceOnUploadHeap(required_size);
  69. JPH_IF_DEBUG(upload_resource->SetName(L"Texture Upload");)
  70. // Copy data to upload texture
  71. surface->Lock(ESurfaceLockMode::Read);
  72. uint8 *upload_data;
  73. D3D12_RANGE range = { 0, 0 }; // We're not going to read
  74. FatalErrorIfFailed(upload_resource->Map(0, &range, (void **)&upload_data));
  75. for (int y = 0; y < mHeight; ++y)
  76. memcpy(upload_data + y * row_size_in_bytes, surface->GetData() + y * surface->GetStride(), surface->GetBytesPerPixel() * mWidth);
  77. upload_resource->Unmap(0, nullptr);
  78. surface->UnLock();
  79. // Start a commandlist for the upload
  80. ID3D12GraphicsCommandList *list = inRenderer->GetUploadQueue().Start();
  81. // Copy the texture from our upload buffer to our final texture
  82. D3D12_TEXTURE_COPY_LOCATION copy_dst;
  83. copy_dst.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
  84. copy_dst.pResource = mTexture.Get();
  85. copy_dst.SubresourceIndex = 0;
  86. D3D12_TEXTURE_COPY_LOCATION copy_src;
  87. copy_src.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
  88. copy_src.pResource = upload_resource.Get();
  89. copy_src.PlacedFootprint = footprint;
  90. list->CopyTextureRegion(&copy_dst, 0, 0, 0, &copy_src, nullptr);
  91. // Indicate that the texture is now ready to be used by a pixel shader
  92. D3D12_RESOURCE_BARRIER barrier;
  93. barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
  94. barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
  95. barrier.Transition.pResource = mTexture.Get();
  96. barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST;
  97. barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
  98. barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
  99. list->ResourceBarrier(1, &barrier);
  100. // Create a SRV for the texture
  101. mSRV = inRenderer->GetSRVHeap().Allocate();
  102. D3D12_SHADER_RESOURCE_VIEW_DESC srv_desc = {};
  103. srv_desc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
  104. srv_desc.Format = desc.Format;
  105. srv_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
  106. srv_desc.Texture2D.MipLevels = 1;
  107. inRenderer->GetDevice()->CreateShaderResourceView(mTexture.Get(), &srv_desc, mSRV);
  108. // Wait for copying to finish so we can destroy the upload texture
  109. inRenderer->GetUploadQueue().ExecuteAndWait();
  110. // Recycle the upload buffer
  111. inRenderer->RecycleD3DResourceOnUploadHeap(upload_resource.Get(), required_size);
  112. }
  113. TextureDX12::TextureDX12(RendererDX12 *inRenderer, int inWidth, int inHeight) :
  114. Texture(inWidth, inHeight),
  115. mRenderer(inRenderer)
  116. {
  117. // Allocate depth stencil buffer
  118. D3D12_CLEAR_VALUE clear_value = {};
  119. clear_value.Format = DXGI_FORMAT_D32_FLOAT;
  120. clear_value.DepthStencil.Depth = 0;
  121. clear_value.DepthStencil.Stencil = 0;
  122. D3D12_HEAP_PROPERTIES heap_properties = {};
  123. heap_properties.Type = D3D12_HEAP_TYPE_DEFAULT;
  124. heap_properties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
  125. heap_properties.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
  126. heap_properties.CreationNodeMask = 1;
  127. heap_properties.VisibleNodeMask = 1;
  128. D3D12_RESOURCE_DESC depth_stencil_desc = {};
  129. depth_stencil_desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
  130. depth_stencil_desc.Alignment = 0;
  131. depth_stencil_desc.Width = mWidth;
  132. depth_stencil_desc.Height = mHeight;
  133. depth_stencil_desc.DepthOrArraySize = 1;
  134. depth_stencil_desc.MipLevels = 1;
  135. depth_stencil_desc.Format = DXGI_FORMAT_D32_FLOAT;
  136. depth_stencil_desc.SampleDesc.Count = 1;
  137. depth_stencil_desc.SampleDesc.Quality = 0;
  138. depth_stencil_desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
  139. depth_stencil_desc.Flags = D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;
  140. FatalErrorIfFailed(inRenderer->GetDevice()->CreateCommittedResource(&heap_properties, D3D12_HEAP_FLAG_NONE, &depth_stencil_desc, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, &clear_value, IID_PPV_ARGS(&mTexture)));
  141. JPH_IF_DEBUG(mTexture->SetName(L"Render Target Texture");)
  142. // Create DSV for the texture
  143. mDSV = inRenderer->GetDSVHeap().Allocate();
  144. D3D12_DEPTH_STENCIL_VIEW_DESC dsv_desc = {};
  145. dsv_desc.Format = DXGI_FORMAT_D32_FLOAT;
  146. dsv_desc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2D;
  147. dsv_desc.Flags = D3D12_DSV_FLAG_NONE;
  148. inRenderer->GetDevice()->CreateDepthStencilView(mTexture.Get(), &dsv_desc, mDSV);
  149. // Create a SRV for the texture
  150. mSRV = inRenderer->GetSRVHeap().Allocate();
  151. D3D12_SHADER_RESOURCE_VIEW_DESC srv_desc = {};
  152. srv_desc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
  153. srv_desc.Format = DXGI_FORMAT_R32_FLOAT;
  154. srv_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
  155. srv_desc.Texture2D.MipLevels = 1;
  156. inRenderer->GetDevice()->CreateShaderResourceView(mTexture.Get(), &srv_desc, mSRV);
  157. }
  158. TextureDX12::~TextureDX12()
  159. {
  160. if (mSRV.ptr != 0)
  161. mRenderer->GetSRVHeap().Free(mSRV);
  162. if (mDSV.ptr != 0)
  163. mRenderer->GetDSVHeap().Free(mDSV);
  164. if (mTexture != nullptr)
  165. mRenderer->RecycleD3DObject(mTexture.Get());
  166. }
  167. void TextureDX12::Bind() const
  168. {
  169. mRenderer->GetCommandList()->SetGraphicsRootDescriptorTable(2 /* All shaders use slot 2 to bind their texture */, mRenderer->GetSRVHeap().ConvertToGPUHandle(mSRV));
  170. }
  171. void TextureDX12::SetAsRenderTarget(bool inSet) const
  172. {
  173. if (inSet)
  174. {
  175. // Indicate make the texture ready for rendering to
  176. D3D12_RESOURCE_BARRIER barrier;
  177. barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
  178. barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
  179. barrier.Transition.pResource = mTexture.Get();
  180. barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
  181. barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_DEPTH_WRITE;
  182. barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
  183. mRenderer->GetCommandList()->ResourceBarrier(1, &barrier);
  184. // Set as render target
  185. mRenderer->GetCommandList()->OMSetRenderTargets(0, nullptr, FALSE, &mDSV);
  186. // Set view port
  187. D3D12_VIEWPORT viewport = { 0.0f, 0.0f, static_cast<float>(mWidth), static_cast<float>(mHeight), 0.0f, 1.0f };
  188. mRenderer->GetCommandList()->RSSetViewports(1, &viewport);
  189. // Set scissor rect
  190. D3D12_RECT scissor_rect = { 0, 0, static_cast<LONG>(mWidth), static_cast<LONG>(mHeight) };
  191. mRenderer->GetCommandList()->RSSetScissorRects(1, &scissor_rect);
  192. // Clear the render target
  193. mRenderer->GetCommandList()->ClearDepthStencilView(mDSV, D3D12_CLEAR_FLAG_DEPTH, 0, 0, 0, nullptr);
  194. }
  195. else
  196. {
  197. // Indicate that the texture is now ready to be used by a pixel shader
  198. D3D12_RESOURCE_BARRIER barrier;
  199. barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
  200. barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
  201. barrier.Transition.pResource = mTexture.Get();
  202. barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_DEPTH_WRITE;
  203. barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
  204. barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
  205. mRenderer->GetCommandList()->ResourceBarrier(1, &barrier);
  206. }
  207. }