FramebufferImpl.cpp 8.0 KB

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