AppRenderer.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. // The MIT License(MIT)
  2. //
  3. // Copyright(c) 2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
  4. //
  5. // Permission is hereby granted, free of charge, to any person obtaining a copy of
  6. // this software and associated documentation files(the "Software"), to deal in
  7. // the Software without restriction, including without limitation the rights to
  8. // use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of
  9. // the Software, and to permit persons to whom the Software is furnished to do so,
  10. // subject to the following conditions :
  11. //
  12. // The above copyright notice and this permission notice shall be included in all
  13. // copies or substantial portions of the Software.
  14. //
  15. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
  17. // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR
  18. // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
  19. // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  20. // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  21. #pragma once
  22. #include "AppRenderer.h"
  23. using namespace Microsoft::WRL;
  24. AppRenderer::AppRenderer(DeviceResources& deviceResources, UIData& ui, const std::vector<std::string>& shaderPaths)
  25. : m_ui(ui)
  26. , m_deviceResources(deviceResources)
  27. , m_NVScaler(deviceResources, shaderPaths)
  28. , m_NVSharpen(deviceResources, shaderPaths)
  29. , m_upscale(deviceResources, shaderPaths)
  30. {
  31. D3D12_SAMPLER_DESC samplerDesc;
  32. ZeroMemory(&samplerDesc, sizeof(samplerDesc));
  33. samplerDesc.Filter = D3D12_FILTER_MIN_MAG_LINEAR_MIP_POINT;
  34. samplerDesc.AddressU = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
  35. samplerDesc.AddressV = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
  36. samplerDesc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
  37. samplerDesc.MipLODBias = 0.0f;
  38. samplerDesc.MaxAnisotropy = 1;
  39. samplerDesc.ComparisonFunc = D3D12_COMPARISON_FUNC_NEVER;
  40. samplerDesc.MinLOD = 0;
  41. samplerDesc.MaxLOD = D3D12_FLOAT32_MAX;
  42. m_samplerDescriptorHeap.Create(m_deviceResources.device(), D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, 1, D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE, L"samplerDescriptorHeap");
  43. m_deviceResources.device()->CreateSampler(&samplerDesc, m_samplerDescriptorHeap.getCPUDescriptorHandle(0));
  44. m_RVDescriptorHeap.Create(m_deviceResources.device(), D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, DescriptorHeapIndex::iHeapEnd, D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE, L"RVDescriptorHeap");
  45. D3D12_CONSTANT_BUFFER_VIEW_DESC cbvDesc = {};
  46. // Bilinear
  47. cbvDesc.BufferLocation = m_upscale.getConstantBuffer()->GetGPUVirtualAddress();
  48. cbvDesc.SizeInBytes = sizeof(BilinearUpscaleConfig);
  49. m_deviceResources.device()->CreateConstantBufferView(&cbvDesc, m_RVDescriptorHeap.getCPUDescriptorHandle(iCB));
  50. // NVScaler
  51. cbvDesc.BufferLocation = m_NVScaler.getConstantBuffer()->GetGPUVirtualAddress();
  52. cbvDesc.SizeInBytes = sizeof(NISConfig);
  53. m_deviceResources.device()->CreateConstantBufferView(&cbvDesc, m_RVDescriptorHeap.getCPUDescriptorHandle(iCB + 1));
  54. m_deviceResources.device()->CreateShaderResourceView(m_NVScaler.getCoefScaler(), nullptr, m_RVDescriptorHeap.getCPUDescriptorHandle(iSRV + 1));
  55. m_deviceResources.device()->CreateShaderResourceView(m_NVScaler.getCoefUSM(), nullptr, m_RVDescriptorHeap.getCPUDescriptorHandle(iSRV + 2));
  56. // NVSharpen
  57. cbvDesc.BufferLocation = m_NVSharpen.getConstantBuffer()->GetGPUVirtualAddress();
  58. cbvDesc.SizeInBytes = sizeof(NISConfig);
  59. m_deviceResources.device()->CreateConstantBufferView(&cbvDesc, m_RVDescriptorHeap.getCPUDescriptorHandle(iCB + 2));
  60. }
  61. bool AppRenderer::updateSize()
  62. {
  63. bool updateWindowSize = m_currentFilePath != m_ui.FilePath || m_currentScale != m_ui.Scale;
  64. bool updateSharpness = m_ui.Sharpness != m_currentSharpness;
  65. if (updateWindowSize)
  66. {
  67. if (m_currentFilePath != m_ui.FilePath)
  68. {
  69. img::load(m_ui.FilePath.string(), m_image, m_inputWidth, m_inputHeight, m_rowPitch, img::Fmt::R16G16B16A16, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
  70. m_currentFilePath = m_ui.FilePath;
  71. }
  72. if (m_ui.Scale == 100)
  73. {
  74. m_outputWidth = m_inputWidth;
  75. m_outputHeight = m_inputHeight;
  76. }
  77. else
  78. {
  79. m_outputWidth = uint32_t(std::ceil(m_inputWidth * 100.f / m_ui.Scale));
  80. m_outputHeight = uint32_t(std::ceil(m_inputHeight * 100.f / m_ui.Scale));
  81. }
  82. m_currentScale = m_ui.Scale;
  83. m_ui.InputWidth = m_inputWidth;
  84. m_ui.InputHeight = m_inputHeight;
  85. m_ui.OutputWidth = m_outputWidth;
  86. m_ui.OutputHeight = m_outputHeight;
  87. m_updateWindowSize = true;
  88. }
  89. if (updateSharpness) {
  90. m_currentSharpness = m_ui.Sharpness;
  91. m_updateSharpness = true;
  92. }
  93. m_init = true;
  94. return updateWindowSize;
  95. }
  96. void AppRenderer::update()
  97. {
  98. if (m_updateWindowSize) {
  99. m_deviceResources.CreateBuffer(uint32_t(m_image.size()), D3D12_HEAP_TYPE_UPLOAD, D3D12_RESOURCE_STATE_GENERIC_READ, &m_inputUpload);
  100. m_deviceResources.CreateTexture2D(m_inputWidth, m_inputHeight, DXGI_FORMAT_R16G16B16A16_FLOAT, D3D12_RESOURCE_STATE_COMMON, &m_input);
  101. m_deviceResources.UploadTextureData(m_image.data(), uint32_t(m_image.size()), m_rowPitch , m_input.Get(), m_inputUpload.Get());
  102. m_deviceResources.device()->CreateShaderResourceView(m_input.Get(), nullptr, m_RVDescriptorHeap.getCPUDescriptorHandle(iSRV));
  103. m_deviceResources.CreateTexture2D(m_outputWidth, m_outputHeight, DXGI_FORMAT_R8G8B8A8_UNORM, D3D12_RESOURCE_STATE_COMMON, &m_output);
  104. m_deviceResources.device()->CreateShaderResourceView(m_output.Get(), nullptr, m_RVDescriptorHeap.getCPUDescriptorHandle(iUAV));
  105. }
  106. if (m_updateSharpness || m_updateWindowSize) {
  107. m_upscale.update(m_inputWidth, m_inputHeight, m_outputWidth, m_outputHeight);
  108. m_NVScaler.update(m_currentSharpness / 100.f, m_inputWidth, m_inputHeight, m_outputWidth, m_outputHeight);
  109. m_NVSharpen.update(m_currentSharpness / 100.f, m_inputWidth, m_inputHeight);
  110. m_updateWindowSize = false;
  111. m_updateSharpness = false;
  112. }
  113. if (m_uploadCoefficients) {
  114. m_NVScaler.uploadCoefficients();
  115. m_uploadCoefficients = false;
  116. }
  117. if (m_saveOutput && m_saveReadBack) {
  118. saveOutputToFile();
  119. m_saveOutput = false;
  120. m_saveReadBack = false;
  121. }
  122. }
  123. void AppRenderer::render()
  124. {
  125. auto computeCommandList = m_deviceResources.computeCommandList();
  126. std::vector<ID3D12DescriptorHeap*> pHeaps{ m_RVDescriptorHeap.getDescriptorHeap(), m_samplerDescriptorHeap.getDescriptorHeap() };
  127. computeCommandList->SetDescriptorHeaps(uint32_t(pHeaps.size()), pHeaps.data());
  128. std::vector<uint32_t> dispatch;
  129. if (m_ui.EnableNVScaler) {
  130. if (m_currentScale != 100) {
  131. dispatch = m_NVScaler.getDispatchDim();
  132. computeCommandList->SetComputeRootSignature(m_NVScaler.getRootSignature());
  133. computeCommandList->SetComputeRootDescriptorTable(0, m_RVDescriptorHeap.getGPUDescriptorHandle(iCB + 1)); // ConstantBuffer config
  134. computeCommandList->SetComputeRootDescriptorTable(4, m_RVDescriptorHeap.getGPUDescriptorHandle(iSRV + 1)); // coef_scaler
  135. computeCommandList->SetComputeRootDescriptorTable(5, m_RVDescriptorHeap.getGPUDescriptorHandle(iSRV + 2)); // coef_USM
  136. computeCommandList->SetPipelineState(m_NVScaler.getComputePSO());
  137. }
  138. else
  139. {
  140. dispatch = m_NVSharpen.getDispatchDim();
  141. computeCommandList->SetComputeRootSignature(m_NVSharpen.getRootSignature());
  142. computeCommandList->SetComputeRootDescriptorTable(0, m_RVDescriptorHeap.getGPUDescriptorHandle(iCB + 2)); // ConstantBuffer config
  143. computeCommandList->SetPipelineState(m_NVSharpen.getComputePSO());
  144. }
  145. }
  146. else {
  147. dispatch = m_upscale.getDispatchDim();
  148. computeCommandList->SetComputeRootSignature(m_upscale.getRootSignature());
  149. computeCommandList->SetComputeRootDescriptorTable(0, m_RVDescriptorHeap.getGPUDescriptorHandle(iCB)); // ConstantBuffer config
  150. computeCommandList->SetPipelineState(m_upscale.getComputePSO());
  151. }
  152. computeCommandList->SetComputeRootDescriptorTable(1, m_samplerDescriptorHeap.getGPUDescriptorHandle(0)); // sampler
  153. computeCommandList->SetComputeRootDescriptorTable(2, m_RVDescriptorHeap.getGPUDescriptorHandle(iSRV)); // input
  154. computeCommandList->SetComputeRootDescriptorTable(3, m_RVDescriptorHeap.getGPUDescriptorHandle(iUAV)); // output
  155. m_deviceResources.StartComputeTimer();
  156. computeCommandList->Dispatch(dispatch[0], dispatch[1], dispatch[2]);
  157. m_deviceResources.StopComputeTimer();
  158. m_deviceResources.ResolveComputeTimerQuery();
  159. if (m_saveOutput) {
  160. scheduleCopyOutput();
  161. m_saveReadBack = true;
  162. }
  163. computeCommandList->Close();
  164. m_deviceResources.CopyToRenderTarget(m_output.Get());
  165. m_deviceResources.m_output = m_output.Get();
  166. }
  167. void AppRenderer::saveOutput(const std::string& filename)
  168. {
  169. m_saveOutput = true;
  170. m_saveFileName = filename;
  171. }
  172. void AppRenderer::saveOutputToFile()
  173. {
  174. D3D12_RESOURCE_DESC desc = m_output->GetDesc();
  175. img::Fmt format = img::Fmt::R8G8B8A8;
  176. switch (desc.Format)
  177. {
  178. case DXGI_FORMAT_R8G8B8A8_UNORM:
  179. format = img::Fmt::R8G8B8A8;
  180. break;
  181. case DXGI_FORMAT_R32G32B32A32_FLOAT:
  182. format = img::Fmt::R32G32B32A32;
  183. break;
  184. case DXGI_FORMAT_R16G16B16A16_FLOAT:
  185. format = img::Fmt::R16G16B16A16;
  186. break;
  187. }
  188. std::vector<uint8_t> data;
  189. constexpr uint32_t channels = 4;
  190. uint32_t imageSize = m_saveRowPitch * m_saveHeight;
  191. data.resize(imageSize);
  192. uint8_t* mappedData = nullptr;
  193. m_outputReadBack->Map(0, nullptr, reinterpret_cast<void**>(&mappedData));
  194. memcpy(data.data(), mappedData, imageSize);
  195. m_outputReadBack->Unmap(0, nullptr);
  196. img::save(m_saveFileName, data.data(), m_saveWidth, m_saveHeight, channels, m_saveRowPitch, format);
  197. }
  198. void AppRenderer::scheduleCopyOutput()
  199. {
  200. static std::unordered_map<DXGI_FORMAT, uint32_t> Bpp{ {DXGI_FORMAT_R32G32B32A32_FLOAT, 16}, { DXGI_FORMAT_R16G16B16A16_FLOAT, 8}, {DXGI_FORMAT_R8G8B8A8_UNORM, 4} };
  201. D3D12_RESOURCE_DESC desc = m_output->GetDesc();
  202. if (Bpp.find(desc.Format) == Bpp.end())
  203. return;
  204. m_saveWidth = uint32_t(desc.Width);
  205. m_saveHeight = uint32_t(desc.Height);
  206. m_saveRowPitch = Align(m_saveWidth * Bpp[desc.Format], D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
  207. m_deviceResources.CreateBuffer(m_saveRowPitch * desc.Height, D3D12_HEAP_TYPE_READBACK, D3D12_RESOURCE_STATE_COPY_DEST, &m_outputReadBack);
  208. CD3DX12_TEXTURE_COPY_LOCATION src(m_output.Get(), 0);
  209. D3D12_PLACED_SUBRESOURCE_FOOTPRINT footprint = {};
  210. footprint.Footprint.Width = m_saveWidth;
  211. footprint.Footprint.Height = m_saveHeight;
  212. footprint.Footprint.Depth = 1;
  213. footprint.Footprint.RowPitch = m_saveRowPitch;
  214. footprint.Footprint.Format = desc.Format;
  215. CD3DX12_TEXTURE_COPY_LOCATION dst(m_outputReadBack.Get(), footprint);
  216. m_deviceResources.computeCommandList()->CopyTextureRegion(&dst, 0, 0, 0, &src, nullptr);
  217. }