FramebufferImpl.cpp 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  1. // Copyright (C) 2009-2022, Panagiotis Christopoulos Charitos and contributors.
  2. // All rights reserved.
  3. // Code licensed under the BSD License.
  4. // http://www.anki3d.org/LICENSE
  5. #include <AnKi/Gr/gl/FramebufferImpl.h>
  6. #include <AnKi/Gr/Texture.h>
  7. #include <AnKi/Gr/gl/TextureViewImpl.h>
  8. #include <AnKi/Gr/gl/GlState.h>
  9. #include <AnKi/Gr/GrManager.h>
  10. #include <AnKi/Gr/gl/GrManagerImpl.h>
  11. #include <AnKi/Gr/gl/RenderingThread.h>
  12. #include <AnKi/Util/Logger.h>
  13. namespace anki {
  14. Error FramebufferImpl::init(const FramebufferInitInfo& init)
  15. {
  16. ANKI_ASSERT(!isCreated());
  17. m_in = init;
  18. glGenFramebuffers(1, &m_glName);
  19. ANKI_ASSERT(m_glName != 0);
  20. const GLenum target = GL_FRAMEBUFFER;
  21. glBindFramebuffer(target, m_glName);
  22. // Attach color
  23. for(U i = 0; i < m_in.m_colorAttachmentCount; i++)
  24. {
  25. const FramebufferAttachmentInfo& att = m_in.m_colorAttachments[i];
  26. const TextureViewImpl& viewImpl = static_cast<const TextureViewImpl&>(*att.m_textureView);
  27. ANKI_ASSERT(viewImpl.m_tex->isSubresourceGoodForFramebufferAttachment(viewImpl.getSubresource()));
  28. const GLenum binding = GL_COLOR_ATTACHMENT0 + i;
  29. attachTextureInternal(binding, viewImpl, att);
  30. m_drawBuffers[i] = binding;
  31. if(att.m_loadOperation == AttachmentLoadOperation::DONT_CARE)
  32. {
  33. m_invalidateBuffers[m_invalidateBuffersCount++] = binding;
  34. }
  35. if(m_fbSize[0] == 0)
  36. {
  37. m_fbSize[0] = viewImpl.m_tex->getWidth() >> viewImpl.getSubresource().m_firstMipmap;
  38. m_fbSize[1] = viewImpl.m_tex->getHeight() >> viewImpl.getSubresource().m_firstMipmap;
  39. }
  40. else
  41. {
  42. ANKI_ASSERT(m_fbSize[0] == (viewImpl.m_tex->getWidth() >> viewImpl.getSubresource().m_firstMipmap));
  43. ANKI_ASSERT(m_fbSize[1] == (viewImpl.m_tex->getHeight() >> viewImpl.getSubresource().m_firstMipmap));
  44. }
  45. }
  46. // Attach depth/stencil
  47. if(m_in.m_depthStencilAttachment.m_textureView.isCreated())
  48. {
  49. const FramebufferAttachmentInfo& att = m_in.m_depthStencilAttachment;
  50. const TextureViewImpl& viewImpl = static_cast<const TextureViewImpl&>(*att.m_textureView);
  51. ANKI_ASSERT(viewImpl.m_tex->isSubresourceGoodForFramebufferAttachment(viewImpl.getSubresource()));
  52. GLenum binding;
  53. if(viewImpl.getSubresource().m_depthStencilAspect == DepthStencilAspectBit::kDepth)
  54. {
  55. binding = GL_DEPTH_ATTACHMENT;
  56. }
  57. else if(viewImpl.getSubresource().m_depthStencilAspect == DepthStencilAspectBit::STENCIL)
  58. {
  59. binding = GL_STENCIL_ATTACHMENT;
  60. }
  61. else
  62. {
  63. ANKI_ASSERT(viewImpl.getSubresource().m_depthStencilAspect == DepthStencilAspectBit::DEPTH_STENCIL);
  64. binding = GL_DEPTH_STENCIL_ATTACHMENT;
  65. }
  66. attachTextureInternal(binding, viewImpl, att);
  67. if(att.m_loadOperation == AttachmentLoadOperation::DONT_CARE)
  68. {
  69. m_invalidateBuffers[m_invalidateBuffersCount++] = binding;
  70. }
  71. if(m_fbSize[0] == 0)
  72. {
  73. m_fbSize[0] = viewImpl.m_tex->getWidth() >> viewImpl.getSubresource().m_firstMipmap;
  74. m_fbSize[1] = viewImpl.m_tex->getHeight() >> viewImpl.getSubresource().m_firstMipmap;
  75. }
  76. else
  77. {
  78. ANKI_ASSERT(m_fbSize[0] == (viewImpl.m_tex->getWidth() >> viewImpl.getSubresource().m_firstMipmap));
  79. ANKI_ASSERT(m_fbSize[1] == (viewImpl.m_tex->getHeight() >> viewImpl.getSubresource().m_firstMipmap));
  80. }
  81. // Misc
  82. m_clearDepth = !!(viewImpl.getSubresource().m_depthStencilAspect & DepthStencilAspectBit::kDepth)
  83. && att.m_loadOperation == AttachmentLoadOperation::CLEAR;
  84. m_clearStencil = !!(viewImpl.getSubresource().m_depthStencilAspect & DepthStencilAspectBit::STENCIL)
  85. && att.m_stencilLoadOperation == AttachmentLoadOperation::CLEAR;
  86. }
  87. // Check completeness
  88. GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
  89. if(status != GL_FRAMEBUFFER_COMPLETE)
  90. {
  91. ANKI_GL_LOGE("FBO is incomplete. Status: 0x%x", status);
  92. return Error::kFunctionFailed;
  93. }
  94. glBindFramebuffer(GL_FRAMEBUFFER, 0);
  95. return Error::kNone;
  96. }
  97. void FramebufferImpl::attachTextureInternal(GLenum attachment, const TextureViewImpl& view,
  98. const FramebufferAttachmentInfo& info)
  99. {
  100. const GLenum target = GL_FRAMEBUFFER;
  101. const TextureImpl& tex = static_cast<const TextureImpl&>(*view.m_tex);
  102. switch(tex.m_target)
  103. {
  104. case GL_TEXTURE_2D:
  105. #if ANKI_GL == ANKI_GL_DESKTOP
  106. case GL_TEXTURE_2D_MULTISAMPLE:
  107. #endif
  108. glFramebufferTexture2D(target, attachment, tex.m_target, tex.getGlName(), view.getSubresource().m_firstMipmap);
  109. break;
  110. case GL_TEXTURE_CUBE_MAP:
  111. glFramebufferTexture2D(target, attachment, GL_TEXTURE_CUBE_MAP_POSITIVE_X + view.getSubresource().m_firstFace,
  112. tex.getGlName(), view.getSubresource().m_firstMipmap);
  113. break;
  114. case GL_TEXTURE_2D_ARRAY:
  115. glFramebufferTextureLayer(target, attachment, tex.getGlName(), view.getSubresource().m_firstMipmap,
  116. view.getSubresource().m_firstLayer);
  117. break;
  118. case GL_TEXTURE_3D:
  119. ANKI_ASSERT(!"TODO");
  120. break;
  121. case GL_TEXTURE_CUBE_MAP_ARRAY:
  122. glFramebufferTextureLayer(target, attachment, tex.getGlName(), view.getSubresource().m_firstMipmap,
  123. view.getSubresource().m_firstLayer * 6 + view.getSubresource().m_firstFace);
  124. break;
  125. default:
  126. ANKI_ASSERT(0);
  127. break;
  128. }
  129. }
  130. void FramebufferImpl::bind(const GlState& state, U32 minx, U32 miny, U32 width, U32 height) const
  131. {
  132. ANKI_ASSERT(width > 0 && height > 0);
  133. if(m_in.getName() && static_cast<const GrManagerImpl&>(getManager()).debugMarkersEnabled())
  134. {
  135. glPushDebugGroup(GL_DEBUG_SOURCE_APPLICATION, m_glName, 0, &m_in.getName()[0]);
  136. }
  137. // Clear in the render area
  138. const U maxx = min<U>(minx + width, m_fbSize[0]);
  139. const U maxy = min<U>(miny + height, m_fbSize[1]);
  140. ANKI_ASSERT(minx < m_fbSize[0] && miny < m_fbSize[1] && maxx <= m_fbSize[0] && maxy <= m_fbSize[1]);
  141. width = maxx - minx;
  142. height = maxy - miny;
  143. glScissor(minx, miny, width, height);
  144. ANKI_ASSERT(m_glName != 0);
  145. glBindFramebuffer(GL_FRAMEBUFFER, m_glName);
  146. // Set the draw buffers
  147. if(m_in.m_colorAttachmentCount)
  148. {
  149. glDrawBuffers(m_in.m_colorAttachmentCount, &m_drawBuffers[0]);
  150. }
  151. // Invalidate
  152. if(m_invalidateBuffersCount)
  153. {
  154. glInvalidateSubFramebuffer(GL_FRAMEBUFFER, m_invalidateBuffersCount, &m_invalidateBuffers[0], minx, miny, width,
  155. height);
  156. }
  157. // Clear buffers
  158. for(U i = 0; i < m_in.m_colorAttachmentCount; i++)
  159. {
  160. const FramebufferAttachmentInfo& att = m_in.m_colorAttachments[i];
  161. if(att.m_loadOperation == AttachmentLoadOperation::CLEAR)
  162. {
  163. // Enable write mask in case a pipeline changed it (else no clear will happen) and then restore state
  164. Bool restore = false;
  165. if(state.m_colorWriteMasks[i][0] != true || state.m_colorWriteMasks[i][1] != true
  166. || state.m_colorWriteMasks[i][2] != true || state.m_colorWriteMasks[i][3] != true)
  167. {
  168. glColorMaski(i, true, true, true, true);
  169. restore = true;
  170. }
  171. glClearBufferfv(GL_COLOR, i, &att.m_clearValue.m_colorf[0]);
  172. if(restore)
  173. {
  174. glColorMaski(i, state.m_colorWriteMasks[i][0], state.m_colorWriteMasks[i][1],
  175. state.m_colorWriteMasks[i][2], state.m_colorWriteMasks[i][3]);
  176. }
  177. }
  178. }
  179. // Clear depth
  180. if(m_clearDepth)
  181. {
  182. // Enable write mask in case a pipeline changed it (else no clear will happen) and then restore state
  183. if(state.m_depthWriteMask == false)
  184. {
  185. glDepthMask(true);
  186. }
  187. glClearBufferfv(GL_DEPTH, 0, &m_in.m_depthStencilAttachment.m_clearValue.m_depthStencil.m_depth);
  188. if(state.m_depthWriteMask == false)
  189. {
  190. glDepthMask(false);
  191. }
  192. }
  193. // Clear stencil
  194. if(m_clearStencil)
  195. {
  196. // Enable write mask in case a pipeline changed it (else no clear will happen) and then restore state
  197. // From the spec: The clear operation always uses the front stencil write mask when clearing the stencil
  198. // buffer
  199. if(state.m_stencilWriteMask[0] != kMaxU32)
  200. {
  201. glStencilMaskSeparate(GL_FRONT, kMaxU32);
  202. }
  203. GLint clearVal = m_in.m_depthStencilAttachment.m_clearValue.m_depthStencil.m_stencil;
  204. glClearBufferiv(GL_STENCIL, 0, &clearVal);
  205. if(state.m_stencilWriteMask[0] != kMaxU32)
  206. {
  207. glStencilMaskSeparate(GL_FRONT, state.m_stencilWriteMask[0]);
  208. }
  209. }
  210. glScissor(state.m_scissor[0], state.m_scissor[1], state.m_scissor[2], state.m_scissor[3]);
  211. }
  212. void FramebufferImpl::endRenderPass() const
  213. {
  214. if(m_in.getName() && static_cast<const GrManagerImpl&>(getManager()).debugMarkersEnabled())
  215. {
  216. glPopDebugGroup();
  217. }
  218. }
  219. } // end namespace anki