2
0

BsRenderTargets.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496
  1. //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
  2. //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
  3. #include "BsRenderTargets.h"
  4. #include "BsGpuResourcePool.h"
  5. #include "BsViewport.h"
  6. #include "BsRenderAPI.h"
  7. #include "BsTextureManager.h"
  8. #include "BsRendererUtility.h"
  9. #include "BsGpuBuffer.h"
  10. namespace bs { namespace ct
  11. {
  12. RenderTargets::RenderTargets(const RENDERER_VIEW_TARGET_DESC& view, bool hdr)
  13. :mViewTarget(view), mHDR(hdr), mWidth(view.targetWidth), mHeight(view.targetHeight)
  14. {
  15. // Note: Consider customizable HDR format via options? e.g. smaller PF_FLOAT_R11G11B10 or larger 32-bit format
  16. mSceneColorFormat = PF_FLOAT16_RGBA;
  17. mAlbedoFormat = PF_R8G8B8A8; // Note: Also consider customizable format (e.g. 16-bit float?)
  18. mNormalFormat = PF_UNORM_R10G10B10A2; // Note: Also consider customizable format (e.g. 16-bit float?)
  19. }
  20. SPtr<RenderTargets> RenderTargets::create(const RENDERER_VIEW_TARGET_DESC& view, bool hdr)
  21. {
  22. return bs_shared_ptr<RenderTargets>(new (bs_alloc<RenderTargets>()) RenderTargets(view, hdr));
  23. }
  24. void RenderTargets::prepare()
  25. {
  26. GpuResourcePool& texPool = GpuResourcePool::instance();
  27. UINT32 width = mViewTarget.viewRect.width;
  28. UINT32 height = mViewTarget.viewRect.height;
  29. mDepthTex = texPool.get(POOLED_RENDER_TEXTURE_DESC::create2D(PF_D32_S8X24, width, height, TU_DEPTHSTENCIL,
  30. mViewTarget.numSamples, false));
  31. }
  32. void RenderTargets::cleanup()
  33. {
  34. RenderAPI& rapi = RenderAPI::instance();
  35. rapi.setRenderTarget(nullptr);
  36. GpuResourcePool& texPool = GpuResourcePool::instance();
  37. texPool.release(mDepthTex);
  38. }
  39. void RenderTargets::allocate(RenderTargetType type)
  40. {
  41. GpuResourcePool& texPool = GpuResourcePool::instance();
  42. UINT32 width = mViewTarget.viewRect.width;
  43. UINT32 height = mViewTarget.viewRect.height;
  44. // Note: This class is keeping all these textures alive for too long (even after they are done for a frame). We
  45. // could save on memory by deallocating and reallocating them every frame, but it remains to be seen how much of
  46. // a performance impact would that have.
  47. if (type == RTT_GBuffer)
  48. {
  49. // Note: Albedo is allocated as SRGB, meaning when reading from textures during depth pass we decode from sRGB
  50. // into linear, then back into sRGB when writing to albedo, and back to linear when reading from albedo during
  51. // light pass. This /might/ have a performance impact. In which case we could just use a higher precision albedo
  52. // buffer, which can then store linear color directly (storing linear in 8bit buffer causes too much detail to
  53. // be lost in the blacks).
  54. mAlbedoTex = texPool.get(POOLED_RENDER_TEXTURE_DESC::create2D(mAlbedoFormat, width, height, TU_RENDERTARGET,
  55. mViewTarget.numSamples, true));
  56. mNormalTex = texPool.get(POOLED_RENDER_TEXTURE_DESC::create2D(mNormalFormat, width, height, TU_RENDERTARGET,
  57. mViewTarget.numSamples, false));
  58. mRoughMetalTex = texPool.get(POOLED_RENDER_TEXTURE_DESC::create2D(PF_FLOAT16_RG, width, height, TU_RENDERTARGET,
  59. mViewTarget.numSamples, false)); // Note: Metal doesn't need 16-bit float
  60. bool rebuildRT = false;
  61. if (mGBufferRT != nullptr)
  62. {
  63. rebuildRT |= mGBufferRT->getColorTexture(0) != mAlbedoTex->texture;
  64. rebuildRT |= mGBufferRT->getColorTexture(1) != mNormalTex->texture;
  65. rebuildRT |= mGBufferRT->getColorTexture(2) != mRoughMetalTex->texture;
  66. rebuildRT |= mGBufferRT->getDepthStencilTexture() != mDepthTex->texture;
  67. }
  68. else
  69. rebuildRT = true;
  70. if (mGBufferRT == nullptr || rebuildRT)
  71. {
  72. RENDER_TEXTURE_DESC gbufferDesc;
  73. gbufferDesc.colorSurfaces[0].texture = mAlbedoTex->texture;
  74. gbufferDesc.colorSurfaces[0].face = 0;
  75. gbufferDesc.colorSurfaces[0].numFaces = 1;
  76. gbufferDesc.colorSurfaces[0].mipLevel = 0;
  77. gbufferDesc.colorSurfaces[1].texture = mNormalTex->texture;
  78. gbufferDesc.colorSurfaces[1].face = 0;
  79. gbufferDesc.colorSurfaces[1].numFaces = 1;
  80. gbufferDesc.colorSurfaces[1].mipLevel = 0;
  81. gbufferDesc.colorSurfaces[2].texture = mRoughMetalTex->texture;
  82. gbufferDesc.colorSurfaces[2].face = 0;
  83. gbufferDesc.colorSurfaces[2].numFaces = 1;
  84. gbufferDesc.colorSurfaces[2].mipLevel = 0;
  85. gbufferDesc.depthStencilSurface.texture = mDepthTex->texture;
  86. gbufferDesc.depthStencilSurface.face = 0;
  87. gbufferDesc.depthStencilSurface.mipLevel = 0;
  88. mGBufferRT = RenderTexture::create(gbufferDesc);
  89. }
  90. }
  91. else if(type == RTT_SceneColor)
  92. {
  93. mSceneColorTex = texPool.get(POOLED_RENDER_TEXTURE_DESC::create2D(mSceneColorFormat, width,
  94. height, TU_RENDERTARGET | TU_LOADSTORE, mViewTarget.numSamples, false));
  95. if (mViewTarget.numSamples > 1)
  96. {
  97. UINT32 bufferNumElements = width * height * mViewTarget.numSamples;
  98. mFlattenedSceneColorBuffer = texPool.get(POOLED_STORAGE_BUFFER_DESC::createStandard(BF_16X4F, bufferNumElements));
  99. }
  100. bool rebuildRT = false;
  101. if (mSceneColorRT != nullptr)
  102. {
  103. rebuildRT |= mSceneColorRT->getColorTexture(0) != mSceneColorTex->texture;
  104. rebuildRT |= mSceneColorRT->getDepthStencilTexture() != mDepthTex->texture;
  105. }
  106. else
  107. rebuildRT = true;
  108. if (rebuildRT)
  109. {
  110. RENDER_TEXTURE_DESC sceneColorDesc;
  111. sceneColorDesc.colorSurfaces[0].texture = mSceneColorTex->texture;
  112. sceneColorDesc.colorSurfaces[0].face = 0;
  113. sceneColorDesc.colorSurfaces[0].numFaces = 1;
  114. sceneColorDesc.colorSurfaces[0].mipLevel = 0;
  115. sceneColorDesc.depthStencilSurface.texture = mDepthTex->texture;
  116. sceneColorDesc.depthStencilSurface.face = 0;
  117. sceneColorDesc.depthStencilSurface.numFaces = 1;
  118. sceneColorDesc.depthStencilSurface.mipLevel = 0;
  119. mSceneColorRT = TextureManager::instance().createRenderTexture(sceneColorDesc);
  120. }
  121. }
  122. else if(type == RTT_LightAccumulation)
  123. {
  124. if (mViewTarget.numSamples > 1)
  125. {
  126. UINT32 bufferNumElements = width * height * mViewTarget.numSamples;
  127. mFlattenedLightAccumulationBuffer =
  128. texPool.get(POOLED_STORAGE_BUFFER_DESC::createStandard(BF_16X4F, bufferNumElements));
  129. SPtr<GpuBuffer> buffer = mFlattenedLightAccumulationBuffer->buffer;
  130. auto& bufferProps = buffer->getProperties();
  131. UINT32 bufferSize = bufferProps.getElementSize() * bufferProps.getElementCount();
  132. UINT16* data = (UINT16*)buffer->lock(0, bufferSize, GBL_WRITE_ONLY_DISCARD);
  133. {
  134. memset(data, 0, bufferSize);
  135. }
  136. buffer->unlock();
  137. }
  138. mLightAccumulationTex = texPool.get(POOLED_RENDER_TEXTURE_DESC::create2D(mSceneColorFormat, width,
  139. height, TU_LOADSTORE | TU_RENDERTARGET, mViewTarget.numSamples, false));
  140. bool rebuildRT;
  141. if (mLightAccumulationRT != nullptr)
  142. rebuildRT = mLightAccumulationRT->getColorTexture(0) != mLightAccumulationTex->texture;
  143. else
  144. rebuildRT = true;
  145. if (rebuildRT)
  146. {
  147. RENDER_TEXTURE_DESC lightAccumulationRTDesc;
  148. lightAccumulationRTDesc.colorSurfaces[0].texture = mLightAccumulationTex->texture;
  149. lightAccumulationRTDesc.colorSurfaces[0].face = 0;
  150. lightAccumulationRTDesc.colorSurfaces[0].numFaces = 1;
  151. lightAccumulationRTDesc.colorSurfaces[0].mipLevel = 0;
  152. mLightAccumulationRT = TextureManager::instance().createRenderTexture(lightAccumulationRTDesc);
  153. }
  154. }
  155. else if(type == RTT_LightOcclusion)
  156. {
  157. mLightOcclusionTex = texPool.get(POOLED_RENDER_TEXTURE_DESC::create2D(PF_R8, width,
  158. height, TU_RENDERTARGET, mViewTarget.numSamples, false));
  159. bool rebuildRT = false;
  160. if (mLightOcclusionRT != nullptr)
  161. {
  162. rebuildRT |= mLightOcclusionRT->getColorTexture(0) != mLightOcclusionTex->texture;
  163. rebuildRT |= mLightOcclusionRT->getDepthStencilTexture() != mDepthTex->texture;
  164. }
  165. else
  166. rebuildRT = true;
  167. if (rebuildRT)
  168. {
  169. RENDER_TEXTURE_DESC lightOcclusionRTDesc;
  170. lightOcclusionRTDesc.colorSurfaces[0].texture = mLightOcclusionTex->texture;
  171. lightOcclusionRTDesc.colorSurfaces[0].face = 0;
  172. lightOcclusionRTDesc.colorSurfaces[0].numFaces = 1;
  173. lightOcclusionRTDesc.colorSurfaces[0].mipLevel = 0;
  174. lightOcclusionRTDesc.depthStencilSurface.texture = mDepthTex->texture;
  175. lightOcclusionRTDesc.depthStencilSurface.face = 0;
  176. lightOcclusionRTDesc.depthStencilSurface.numFaces = 1;
  177. lightOcclusionRTDesc.depthStencilSurface.mipLevel = 0;
  178. mLightOcclusionRT = TextureManager::instance().createRenderTexture(lightOcclusionRTDesc);
  179. }
  180. }
  181. else if(type == RTT_ResolvedSceneColor)
  182. {
  183. // If not using MSAA, this is equivalent to default scene color texture
  184. if(mViewTarget.numSamples > 1)
  185. {
  186. mResolvedSceneColorTex1 = texPool.get(POOLED_RENDER_TEXTURE_DESC::create2D(mSceneColorFormat, width, height,
  187. TU_RENDERTARGET, 1, false));
  188. }
  189. }
  190. else if(type == RTT_ResolvedSceneColorSecondary)
  191. {
  192. mResolvedSceneColorTex2 = texPool.get(POOLED_RENDER_TEXTURE_DESC::create2D(mSceneColorFormat,
  193. width, height, TU_RENDERTARGET, 1, false));
  194. }
  195. else if(type == RTT_HiZ)
  196. {
  197. mHiZ = GpuResourcePool::instance().get(
  198. BuildHiZ::getHiZTextureDesc(
  199. mViewTarget.viewRect.width,
  200. mViewTarget.viewRect.height)
  201. );
  202. }
  203. else if(type == RTT_ResolvedDepth)
  204. {
  205. // If not using MSAA, this is equivalent to default depth texture
  206. if(mViewTarget.numSamples > 1)
  207. {
  208. mResolvedDepthTex = texPool.get(POOLED_RENDER_TEXTURE_DESC::create2D(PF_D32, width, height, TU_RENDERTARGET,
  209. 1, false));
  210. }
  211. }
  212. else if(type == RTT_AmbientOcclusion)
  213. {
  214. mAmbientOcclusionTex = texPool.get(POOLED_RENDER_TEXTURE_DESC::create2D(PF_R8, width, height, TU_RENDERTARGET));
  215. }
  216. }
  217. void RenderTargets::release(RenderTargetType type)
  218. {
  219. GpuResourcePool& texPool = GpuResourcePool::instance();
  220. if (type == RTT_GBuffer)
  221. {
  222. texPool.release(mSceneColorTex);
  223. texPool.release(mAlbedoTex);
  224. texPool.release(mNormalTex);
  225. texPool.release(mRoughMetalTex);
  226. }
  227. else if(type == RTT_SceneColor)
  228. {
  229. texPool.release(mSceneColorTex);
  230. if (mFlattenedSceneColorBuffer != nullptr)
  231. texPool.release(mFlattenedSceneColorBuffer);
  232. }
  233. else if(type == RTT_LightAccumulation)
  234. {
  235. if (mLightAccumulationTex != nullptr)
  236. texPool.release(mLightAccumulationTex);
  237. if (mFlattenedLightAccumulationBuffer != nullptr)
  238. texPool.release(mFlattenedLightAccumulationBuffer);
  239. }
  240. else if(type == RTT_LightOcclusion)
  241. {
  242. if (mLightOcclusionTex != nullptr)
  243. texPool.release(mLightOcclusionTex);
  244. }
  245. else if(type == RTT_ResolvedSceneColor)
  246. {
  247. if (mResolvedSceneColorTex1 != nullptr)
  248. texPool.release(mResolvedSceneColorTex1);
  249. }
  250. else if(type == RTT_ResolvedSceneColorSecondary)
  251. {
  252. if (mResolvedSceneColorTex2 != nullptr)
  253. texPool.release(mResolvedSceneColorTex2);
  254. }
  255. else if(type == RTT_HiZ)
  256. {
  257. if (mHiZ != nullptr)
  258. texPool.release(mHiZ);
  259. }
  260. else if(type == RTT_ResolvedDepth)
  261. {
  262. if (mResolvedDepthTex != nullptr)
  263. texPool.release(mResolvedDepthTex);
  264. }
  265. else if(type == RTT_AmbientOcclusion)
  266. {
  267. if (mAmbientOcclusionTex != nullptr)
  268. texPool.release(mAmbientOcclusionTex);
  269. }
  270. }
  271. void RenderTargets::bind(RenderTargetType type, bool readOnlyDepthStencil)
  272. {
  273. RenderAPI& rapi = RenderAPI::instance();
  274. switch(type)
  275. {
  276. case RTT_GBuffer:
  277. {
  278. rapi.setRenderTarget(mGBufferRT);
  279. Rect2 area(0.0f, 0.0f, 1.0f, 1.0f);
  280. rapi.setViewport(area);
  281. // Clear depth & stencil according to user defined values, don't clear color as all values will get written to
  282. UINT32 clearFlags = mViewTarget.clearFlags & ~FBT_COLOR;
  283. if (clearFlags != 0)
  284. {
  285. RenderAPI::instance().clearViewport(clearFlags, mViewTarget.clearColor,
  286. mViewTarget.clearDepthValue, mViewTarget.clearStencilValue, 0x01);
  287. }
  288. // Clear all non primary targets (Note: I could perhaps clear all but albedo, since it stores a per-pixel write mask)
  289. RenderAPI::instance().clearViewport(FBT_COLOR, Color::ZERO, 1.0f, 0, 0xFF & ~0x01);
  290. }
  291. break;
  292. case RTT_SceneColor:
  293. {
  294. int readOnlyFlags = 0;
  295. if (readOnlyDepthStencil)
  296. readOnlyFlags = FBT_DEPTH | FBT_STENCIL;
  297. rapi.setRenderTarget(mSceneColorRT, readOnlyFlags, RT_COLOR0 | RT_DEPTH_STENCIL);
  298. Rect2 area(0.0f, 0.0f, 1.0f, 1.0f);
  299. rapi.setViewport(area);
  300. }
  301. break;
  302. case RTT_LightAccumulation:
  303. rapi.setRenderTarget(mLightAccumulationRT, FBT_DEPTH | FBT_STENCIL, RT_COLOR0 | RT_DEPTH_STENCIL);
  304. break;
  305. case RTT_LightOcclusion:
  306. {
  307. rapi.setRenderTarget(mLightOcclusionRT, FBT_DEPTH, RT_DEPTH_STENCIL);
  308. Rect2 area(0.0f, 0.0f, 1.0f, 1.0f);
  309. rapi.setViewport(area);
  310. RenderAPI::instance().clearViewport(FBT_COLOR, Color::ZERO);
  311. }
  312. break;
  313. default:
  314. {
  315. int readOnlyFlags = 0;
  316. if (readOnlyDepthStencil)
  317. readOnlyFlags = FBT_DEPTH | FBT_STENCIL;
  318. SPtr<RenderTexture> rt = getRT(type);
  319. if (rt)
  320. rapi.setRenderTarget(rt, readOnlyFlags);
  321. }
  322. break;
  323. }
  324. }
  325. void RenderTargets::generate(RenderTargetType type)
  326. {
  327. switch(type)
  328. {
  329. case RTT_HiZ:
  330. mBuildHiZ.execute(mViewTarget, get(RTT_ResolvedDepth), mHiZ->texture);
  331. break;
  332. case RTT_ResolvedSceneColor:
  333. if (mViewTarget.numSamples > 1)
  334. {
  335. RenderAPI::instance().setRenderTarget(mResolvedSceneColorTex1->renderTexture);
  336. gRendererUtility().blit(mDepthTex->texture);
  337. }
  338. break;
  339. default:
  340. break;
  341. }
  342. }
  343. SPtr<Texture> RenderTargets::get(RenderTargetType type, RenderSurfaceMaskBits surface) const
  344. {
  345. switch(type)
  346. {
  347. case RTT_ResolvedDepth:
  348. if (mViewTarget.numSamples > 1)
  349. return mResolvedDepthTex->texture;
  350. return mDepthTex->texture;
  351. case RTT_ResolvedSceneColor:
  352. if (mViewTarget.numSamples > 1)
  353. return mResolvedSceneColorTex1->texture;
  354. else
  355. return mSceneColorTex->texture;
  356. default:
  357. {
  358. SPtr<PooledRenderTexture> pooledTex = getPooledTexture(type, surface);
  359. if(pooledTex)
  360. return pooledTex->texture;
  361. return nullptr;
  362. }
  363. }
  364. }
  365. SPtr<RenderTexture> RenderTargets::getRT(RenderTargetType type) const
  366. {
  367. switch(type)
  368. {
  369. case RTT_GBuffer:
  370. return mGBufferRT;
  371. case RTT_SceneColor:
  372. return mSceneColorRT;
  373. case RTT_LightOcclusion:
  374. return mLightOcclusionRT;
  375. case RTT_LightAccumulation:
  376. return mLightAccumulationRT;
  377. case RTT_ResolvedSceneColor:
  378. if (mViewTarget.numSamples > 1)
  379. return mResolvedSceneColorTex1->renderTexture;
  380. else
  381. return mSceneColorRT;
  382. default:
  383. {
  384. SPtr<PooledRenderTexture> pooledTex = getPooledTexture(type);
  385. if(pooledTex)
  386. return pooledTex->renderTexture;
  387. return nullptr;
  388. }
  389. }
  390. }
  391. SPtr<PooledRenderTexture> RenderTargets::getPooledTexture(RenderTargetType type, RenderSurfaceMaskBits surface) const
  392. {
  393. switch(type)
  394. {
  395. case RTT_GBuffer:
  396. {
  397. switch (surface)
  398. {
  399. default:
  400. case RT_COLOR0:
  401. return mAlbedoTex;
  402. case RT_COLOR1:
  403. return mNormalTex;
  404. case RT_COLOR2:
  405. return mRoughMetalTex;
  406. case RT_DEPTH_STENCIL:
  407. case RT_DEPTH:
  408. return mDepthTex;
  409. }
  410. }
  411. case RTT_SceneColor:
  412. return mSceneColorTex;
  413. case RTT_LightAccumulation:
  414. return mLightAccumulationTex;
  415. case RTT_LightOcclusion:
  416. return mLightOcclusionTex;
  417. case RTT_ResolvedSceneColor:
  418. return mResolvedSceneColorTex1;
  419. case RTT_ResolvedSceneColorSecondary:
  420. return mResolvedSceneColorTex1;
  421. case RTT_HiZ:
  422. return mHiZ;
  423. case RTT_ResolvedDepth:
  424. return mResolvedDepthTex;
  425. case RTT_AmbientOcclusion:
  426. return mAmbientOcclusionTex;
  427. default:
  428. return nullptr;
  429. }
  430. }
  431. SPtr<GpuBuffer> RenderTargets::getSceneColorBuffer() const
  432. {
  433. return mFlattenedSceneColorBuffer->buffer;
  434. }
  435. SPtr<GpuBuffer> RenderTargets::getLightAccumulationBuffer() const
  436. {
  437. return mFlattenedLightAccumulationBuffer->buffer;
  438. }
  439. }}