AppRenderer.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  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. #include "AppRenderer.h"
  22. #include <array>
  23. AppRenderer::AppRenderer(DeviceResources& deviceResources, UIData& ui, const std::vector<std::string>& shaderPaths, bool glsl)
  24. : m_ui(ui)
  25. , m_deviceResources(deviceResources)
  26. , m_NVSharpen(deviceResources, shaderPaths, glsl)
  27. , m_NVScaler(deviceResources, shaderPaths, glsl)
  28. {}
  29. bool AppRenderer::update()
  30. {
  31. bool updateWindowSize = m_currentFilePath != m_ui.FilePath || m_currentScale != m_ui.Scale;
  32. bool updateSharpeness = m_ui.Sharpness != m_currentSharpness;
  33. if (updateWindowSize)
  34. {
  35. if (m_currentFilePath != m_ui.FilePath)
  36. {
  37. img::load(m_ui.FilePath.string(), m_image, m_inputWidth, m_inputHeight, m_rowPitch, img::Fmt::R8G8B8A8);
  38. if (m_input) {
  39. vkDestroyImage(m_deviceResources.logicalDevice(), m_input, nullptr);
  40. vkFreeMemory(m_deviceResources.logicalDevice(), m_inputDeviceMemory, nullptr);
  41. vkDestroyImageView(m_deviceResources.logicalDevice(), m_inputSRV, nullptr);
  42. }
  43. m_deviceResources.createTexture2D(m_inputWidth, m_inputHeight, DeviceResources::SwapchainFormat, m_image.data(), m_rowPitch, m_rowPitch * m_inputHeight, &m_input, &m_inputDeviceMemory);
  44. m_deviceResources.createSRV(m_input, DeviceResources::SwapchainFormat, &m_inputSRV);
  45. m_currentFilePath = m_ui.FilePath;
  46. }
  47. if (m_ui.Scale == 100)
  48. {
  49. m_outputWidth = m_inputWidth;
  50. m_outputHeight = m_inputHeight;
  51. }
  52. else
  53. {
  54. m_outputWidth = uint32_t(std::ceil(m_inputWidth * 100.f / m_ui.Scale));
  55. m_outputHeight = uint32_t(std::ceil(m_inputHeight * 100.f / m_ui.Scale));
  56. }
  57. if (m_temp) {
  58. vkDestroyImage(m_deviceResources.logicalDevice(), m_temp, nullptr);
  59. vkDestroyImageView(m_deviceResources.logicalDevice(), m_tempSRV, nullptr);
  60. vkFreeMemory(m_deviceResources.logicalDevice(), m_tempDeviceMemory, nullptr);
  61. }
  62. m_deviceResources.createTexture2D(m_outputWidth, m_outputHeight, DeviceResources::SwapchainFormat, &m_temp, &m_tempDeviceMemory);
  63. m_deviceResources.createSRV(m_temp, DeviceResources::SwapchainFormat, &m_tempSRV);
  64. m_currentScale = m_ui.Scale;
  65. m_ui.InputWidth = m_inputWidth;
  66. m_ui.InputHeight = m_inputHeight;
  67. m_ui.OutputWidth = m_outputWidth;
  68. m_ui.OutputHeight = m_outputHeight;
  69. m_updateWindowSize = true;
  70. }
  71. if (updateSharpeness) {
  72. m_currentSharpness = m_ui.Sharpness;
  73. }
  74. if (updateSharpeness || updateWindowSize) {
  75. m_NVScaler.update(m_currentSharpness / 100.f, m_inputWidth, m_inputHeight, m_outputWidth, m_outputHeight);
  76. m_NVSharpen.update(m_currentSharpness / 100.f, m_inputWidth, m_inputHeight);
  77. }
  78. return updateWindowSize;
  79. }
  80. void AppRenderer::render()
  81. {
  82. if (m_deviceResources.queryPool() != VK_NULL_HANDLE)
  83. {
  84. auto cmdBuff = m_deviceResources.commandBuffer();
  85. vkCmdResetQueryPool(cmdBuff, m_deviceResources.queryPool(), 0, DeviceResources::NumQueryValues);
  86. vkCmdWriteTimestamp(cmdBuff, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, m_deviceResources.queryPool(), 0);
  87. }
  88. if (!m_ui.EnableNVScaler)
  89. {
  90. blitInputToTemp();
  91. }
  92. else
  93. {
  94. if (m_ui.Scale == 100)
  95. {
  96. m_NVSharpen.dispatch(m_inputSRV, m_tempSRV);
  97. }
  98. else
  99. {
  100. m_NVScaler.dispatch(m_inputSRV, m_tempSRV);
  101. }
  102. }
  103. if (m_deviceResources.queryPool() != VK_NULL_HANDLE)
  104. {
  105. vkCmdWriteTimestamp(m_deviceResources.commandBuffer(), VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, m_deviceResources.queryPool(), 1);
  106. }
  107. blitCopyToRenderTarget();
  108. }
  109. void AppRenderer::present()
  110. {
  111. if (m_deviceResources.queryPool() != VK_NULL_HANDLE)
  112. {
  113. VK_OK(vkDeviceWaitIdle(m_deviceResources.logicalDevice()));
  114. typedef uint64_t QueryType; // because of VK_QUERY_RESULT_64_BIT
  115. const uint32_t numQueryResultInts = 2; // because of VK_QUERY_RESULT_WITH_AVAILABILITY_BIT (an additional word)
  116. const auto stride = numQueryResultInts * sizeof(QueryType); // Bytes for single query result and its availability "bit"
  117. constexpr auto allQueriesSize = DeviceResources::NumQueryValues * stride;
  118. std::array<QueryType, numQueryResultInts * DeviceResources::NumQueryValues> query;
  119. VK_OK(vkGetQueryPoolResults(m_deviceResources.logicalDevice(), m_deviceResources.queryPool(), 0, DeviceResources::NumQueryValues, allQueriesSize, query.data(), stride, VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WITH_AVAILABILITY_BIT));
  120. const bool checkAvailabilityBits = query[1] != 0 && query[3] != 0;
  121. if (checkAvailabilityBits)
  122. {
  123. const auto topOfPipeTimestamp = query[0]; // "start"
  124. const auto bottomOfPipeTimestamp = query[2]; // "end"
  125. m_ui.FilterTime = double(bottomOfPipeTimestamp - topOfPipeTimestamp) * m_deviceResources.timestampPeriod() / 1E3; // ns => us
  126. }
  127. }
  128. }
  129. void AppRenderer::cleanUp()
  130. {
  131. vkDestroyImageView(m_deviceResources.logicalDevice(), m_inputSRV, nullptr);
  132. vkFreeMemory(m_deviceResources.logicalDevice(), m_inputDeviceMemory, nullptr);
  133. vkDestroyImage(m_deviceResources.logicalDevice(), m_input, nullptr);
  134. m_NVScaler.cleanUp();
  135. m_NVSharpen.cleanUp();
  136. }
  137. void AppRenderer::blitCopyToRenderTarget()
  138. {
  139. // Layout transition source texture for copy
  140. {
  141. VkImageMemoryBarrier barrier{};
  142. barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
  143. barrier.oldLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
  144. barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
  145. barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
  146. barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
  147. barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
  148. barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
  149. barrier.image = m_temp;
  150. barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
  151. barrier.subresourceRange.levelCount = 1;
  152. barrier.subresourceRange.layerCount = 1;
  153. vkCmdPipelineBarrier(m_deviceResources.commandBuffer(), VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, nullptr, 0, nullptr, 1, &barrier);
  154. }
  155. // Copy source texture to backbuffer
  156. VkImageBlit region{};
  157. region.srcSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 };
  158. region.srcOffsets[0] = { 0, 0, 0 };
  159. region.srcOffsets[1] = { (int32_t)m_outputWidth, (int32_t)m_outputHeight, 1 };
  160. region.dstSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 };
  161. region.dstOffsets[0] = { 0, 0, 0 };
  162. region.dstOffsets[1] = { (int32_t)m_deviceResources.width(), (int32_t)m_deviceResources.height(), 1 };
  163. // Must use vkCmdBlitImage instead of vkCmdCopyImage to handle RGBA to BGRA conversion for backbuffer. Plus, it can also scale.
  164. vkCmdBlitImage(m_deviceResources.commandBuffer(), m_temp,
  165. VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
  166. m_deviceResources.backBuffer(),
  167. VK_IMAGE_LAYOUT_GENERAL,
  168. 1, &region, VK_FILTER_LINEAR);
  169. // Layout transition source texture for shader access
  170. {
  171. VkImageMemoryBarrier barrier{};
  172. barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
  173. barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
  174. barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
  175. barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
  176. barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
  177. barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
  178. barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
  179. barrier.image = m_input;
  180. barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
  181. barrier.subresourceRange.levelCount = 1;
  182. barrier.subresourceRange.layerCount = 1;
  183. vkCmdPipelineBarrier(m_deviceResources.commandBuffer(), VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, nullptr, 0, nullptr, 1, &barrier);
  184. }
  185. }
  186. void AppRenderer::blitInputToTemp()
  187. {
  188. // Layout transition source texture for copy
  189. {
  190. VkImageMemoryBarrier barrier{};
  191. barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
  192. barrier.oldLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
  193. barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
  194. barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
  195. barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
  196. barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
  197. barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
  198. barrier.image = m_input;
  199. barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
  200. barrier.subresourceRange.levelCount = 1;
  201. barrier.subresourceRange.layerCount = 1;
  202. vkCmdPipelineBarrier(m_deviceResources.commandBuffer(), VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, nullptr, 0, nullptr, 1, &barrier);
  203. }
  204. // Copy source texture to backbuffer
  205. VkImageBlit region{};
  206. region.srcSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 };
  207. region.srcOffsets[0] = { 0, 0, 0 };
  208. region.srcOffsets[1] = { (int32_t)m_inputWidth, (int32_t)m_inputHeight, 1 };
  209. region.dstSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 };
  210. region.dstOffsets[0] = { 0, 0, 0 };
  211. region.dstOffsets[1] = { (int32_t)m_outputWidth, (int32_t)m_outputHeight, 1 };
  212. // Must use vkCmdBlitImage instead of vkCmdCopyImage to handle RGBA to BGRA conversion for backbuffer. Plus, it can also scale.
  213. vkCmdBlitImage(m_deviceResources.commandBuffer(), m_input,
  214. VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
  215. m_temp,
  216. VK_IMAGE_LAYOUT_GENERAL,
  217. 1, &region, VK_FILTER_LINEAR);
  218. // Layout transition source texture for shader access
  219. {
  220. VkImageMemoryBarrier barrier{};
  221. barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
  222. barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
  223. barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
  224. barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
  225. barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
  226. barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
  227. barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
  228. barrier.image = m_input;
  229. barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
  230. barrier.subresourceRange.levelCount = 1;
  231. barrier.subresourceRange.layerCount = 1;
  232. vkCmdPipelineBarrier(m_deviceResources.commandBuffer(), VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, nullptr, 0, nullptr, 1, &barrier);
  233. }
  234. }