FramebufferImpl.cpp 8.4 KB

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