Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

333 lines
8.7 KiB

  1. //============ Copyright (c) Valve Corporation, All rights reserved. ============
  2. //
  3. // cglmfbo.cpp
  4. //
  5. //===============================================================================
  6. #include "togl/rendermechanism.h"
  7. // memdbgon -must- be the last include file in a .cpp file.
  8. #include "tier0/memdbgon.h"
  9. CGLMFBO::CGLMFBO( GLMContext *ctx )
  10. {
  11. m_ctx = ctx;
  12. m_ctx->CheckCurrent();
  13. gGL->glGenFramebuffersEXT( 1, &m_name );
  14. memset( m_attach, 0, sizeof( m_attach ) );
  15. }
  16. CGLMFBO::~CGLMFBO( )
  17. {
  18. m_ctx->CheckCurrent();
  19. // detach all known attached textures first... necessary ?
  20. for( int index = 0; index < kAttCount; index++)
  21. {
  22. if (m_attach[ index ].m_tex)
  23. {
  24. TexDetach( (EGLMFBOAttachment)index );
  25. }
  26. }
  27. gGL->glDeleteFramebuffersEXT( 1, &m_name );
  28. m_name = 0;
  29. m_ctx = NULL;
  30. }
  31. // the tex attach path should also select a specific slice of the texture...
  32. // and we need a way to make renderbuffers..
  33. static GLenum EncodeAttachmentFBO( EGLMFBOAttachment index )
  34. {
  35. if (index < kAttDepth)
  36. {
  37. return GL_COLOR_ATTACHMENT0_EXT + (int) index;
  38. }
  39. else
  40. {
  41. switch( index )
  42. {
  43. case kAttDepth:
  44. return GL_DEPTH_ATTACHMENT_EXT;
  45. break;
  46. case kAttStencil:
  47. return GL_STENCIL_ATTACHMENT_EXT;
  48. break;
  49. case kAttDepthStencil:
  50. return GL_DEPTH_STENCIL_ATTACHMENT_EXT;
  51. break;
  52. default:
  53. GLMStop(); // bad news
  54. break;
  55. }
  56. }
  57. GLMStop(); // bad news
  58. // shouldn't get here
  59. return GL_COLOR_ATTACHMENT0_EXT;
  60. }
  61. void CGLMFBO::TexAttach( GLMFBOTexAttachParams *params, EGLMFBOAttachment attachIndex, GLenum fboBindPoint )
  62. {
  63. // force our parent context to be current
  64. m_ctx->MakeCurrent();
  65. // bind to context (will cause FBO object creation on first use)
  66. m_ctx->BindFBOToCtx( this, fboBindPoint );
  67. // it's either a plain 2D, a 2D face of a cube map, or a slice of a 3D.
  68. CGLMTex *tex = params->m_tex;
  69. // always detach what is currently there, if anything
  70. this->TexDetach( attachIndex, fboBindPoint );
  71. if (!tex)
  72. {
  73. // andif they pass NULL to us, then we are done.
  74. return;
  75. }
  76. GLMTexLayout *layout = tex->m_layout;
  77. GLenum target = tex->m_layout->m_key.m_texGLTarget;
  78. GLenum attachIndexGL = EncodeAttachmentFBO( attachIndex );
  79. switch( target )
  80. {
  81. case GL_TEXTURE_2D:
  82. {
  83. // we will attach the underlying RBO on a multisampled tex, iff the tex has one, **and** we're not being asked to attach it to the read buffer.
  84. // if we get a req to attach an MSAA tex to the read buffer, chances are it's BlitTex calling, andit has already resolved the tex, so in those
  85. // cases you really do want to attach the texture and not the RBO to the FBO in question.
  86. bool useRBO = false; // initial state
  87. if (layout->m_key.m_texFlags & kGLMTexMultisampled)
  88. {
  89. // it is an MSAA tex
  90. if (fboBindPoint == GL_READ_FRAMEBUFFER_EXT)
  91. {
  92. // I think you just want to read a resolved tex.
  93. // But I will check that it is resolved first..
  94. Assert( tex->IsRBODirty() == false );
  95. }
  96. else
  97. {
  98. // you want to draw into it. You get the RBO bound instead of the tex.
  99. useRBO = true;
  100. }
  101. }
  102. if (useRBO)
  103. {
  104. // MSAA path - attach the RBO, not the texture, and mark the RBO dirty
  105. if (attachIndexGL==GL_DEPTH_STENCIL_ATTACHMENT_EXT)
  106. {
  107. // you have to attach it both places...
  108. // http://www.opengl.org/wiki/GL_EXT_framebuffer_object
  109. // bind the RBO to the GL_RENDERBUFFER_EXT target
  110. gGL->glBindRenderbufferEXT( GL_RENDERBUFFER_EXT, tex->m_rboName );
  111. // attach the GL_RENDERBUFFER_EXT target to the depth and stencil attach points
  112. gGL->glFramebufferRenderbufferEXT( fboBindPoint, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, tex->m_rboName);
  113. gGL->glFramebufferRenderbufferEXT( fboBindPoint, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, tex->m_rboName);
  114. // no need to leave the RBO hanging on
  115. gGL->glBindRenderbufferEXT( GL_RENDERBUFFER_EXT, 0 );
  116. }
  117. else
  118. {
  119. // color attachment (likely 0)
  120. gGL->glBindRenderbufferEXT( GL_RENDERBUFFER_EXT, tex->m_rboName );
  121. gGL->glFramebufferRenderbufferEXT( fboBindPoint, attachIndexGL, GL_RENDERBUFFER_EXT, tex->m_rboName);
  122. gGL->glBindRenderbufferEXT( GL_RENDERBUFFER_EXT, 0 );
  123. }
  124. tex->ForceRBODirty();
  125. }
  126. else
  127. {
  128. // regular path - attaching a texture2d
  129. if (attachIndexGL==GL_DEPTH_STENCIL_ATTACHMENT_EXT)
  130. {
  131. // you have to attach it both places...
  132. // http://www.opengl.org/wiki/GL_EXT_framebuffer_object
  133. gGL->glFramebufferTexture2DEXT( fboBindPoint, GL_DEPTH_ATTACHMENT_EXT, target, tex->m_texName, params->m_mip );
  134. gGL->glFramebufferTexture2DEXT( fboBindPoint, GL_STENCIL_ATTACHMENT_EXT, target, tex->m_texName, params->m_mip );
  135. }
  136. else
  137. {
  138. gGL->glFramebufferTexture2DEXT( fboBindPoint, attachIndexGL, target, tex->m_texName, params->m_mip );
  139. }
  140. }
  141. }
  142. break;
  143. case GL_TEXTURE_3D:
  144. {
  145. gGL->glFramebufferTexture3DEXT( fboBindPoint, attachIndexGL, target, tex->m_texName, params->m_mip, params->m_zslice );
  146. }
  147. break;
  148. case GL_TEXTURE_CUBE_MAP:
  149. {
  150. // adjust target to steer to the proper face of the cube map
  151. target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + params->m_face;
  152. gGL->glFramebufferTexture2DEXT( fboBindPoint, attachIndexGL, target, tex->m_texName, params->m_mip );
  153. }
  154. break;
  155. }
  156. // log the attached tex
  157. m_attach[ attachIndex ] = *params;
  158. // indicate that the tex has been bound to an RT
  159. tex->m_rtAttachCount++;
  160. }
  161. void CGLMFBO::TexDetach( EGLMFBOAttachment attachIndex, GLenum fboBindPoint )
  162. {
  163. // force our parent context to be current
  164. m_ctx->MakeCurrent();
  165. // bind to context (will cause FBO object creation on first use)
  166. m_ctx->BindFBOToCtx( this, fboBindPoint );
  167. if (m_attach[ attachIndex ].m_tex)
  168. {
  169. CGLMTex *tex = m_attach[ attachIndex ].m_tex;
  170. GLMTexLayout *layout = tex->m_layout;
  171. GLenum target = tex->m_layout->m_key.m_texGLTarget;
  172. GLenum attachIndexGL = EncodeAttachmentFBO( attachIndex );
  173. switch( target )
  174. {
  175. case GL_TEXTURE_2D:
  176. {
  177. if (layout->m_key.m_texFlags & kGLMTexMultisampled)
  178. {
  179. // MSAA path - detach the RBO, not the texture
  180. // (is this the right time to resolve? probably better to wait until someone tries to sample the texture)
  181. gGL->glBindRenderbufferEXT( GL_RENDERBUFFER_EXT, 0 );
  182. if (attachIndexGL==GL_DEPTH_STENCIL_ATTACHMENT_EXT)
  183. {
  184. // detach the GL_RENDERBUFFER_EXT target at depth and stencil attach points
  185. gGL->glFramebufferRenderbufferEXT( GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0);
  186. gGL->glFramebufferRenderbufferEXT( GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0);
  187. }
  188. else
  189. {
  190. // color attachment (likely 0)
  191. gGL->glFramebufferRenderbufferEXT( GL_FRAMEBUFFER_EXT, attachIndexGL, GL_RENDERBUFFER_EXT, 0);
  192. }
  193. }
  194. else
  195. {
  196. // plain tex detach
  197. if (attachIndexGL==GL_DEPTH_STENCIL_ATTACHMENT_EXT)
  198. {
  199. // you have to detach it both places...
  200. // http://www.opengl.org/wiki/GL_EXT_framebuffer_object
  201. gGL->glFramebufferTexture2DEXT( fboBindPoint, GL_DEPTH_ATTACHMENT_EXT, target, 0, 0 );
  202. gGL->glFramebufferTexture2DEXT( fboBindPoint, GL_STENCIL_ATTACHMENT_EXT, target, 0, 0 );
  203. }
  204. else
  205. {
  206. gGL->glFramebufferTexture2DEXT( fboBindPoint, attachIndexGL, target, 0, 0 );
  207. }
  208. }
  209. }
  210. break;
  211. case GL_TEXTURE_3D:
  212. {
  213. gGL->glFramebufferTexture3DEXT( fboBindPoint, attachIndexGL, target, 0, 0, 0 );
  214. }
  215. break;
  216. case GL_TEXTURE_CUBE_MAP:
  217. {
  218. gGL->glFramebufferTexture2DEXT( fboBindPoint, attachIndexGL, target, 0, 0 );
  219. }
  220. break;
  221. }
  222. // un-log the attached tex
  223. memset( &m_attach[ attachIndex ], 0, sizeof( m_attach[0] ) );
  224. // drop the RT attach count
  225. tex->m_rtAttachCount--;
  226. }
  227. else
  228. {
  229. //Debugger(); // odd, but not harmful - typ comes from D3D code passing NULL into SetRenderTarget
  230. }
  231. }
  232. void CGLMFBO::TexScrub( CGLMTex *tex )
  233. {
  234. // see if it's attached anywhere
  235. for( int attachIndex = 0; attachIndex < kAttCount; attachIndex++ )
  236. {
  237. if (m_attach[ attachIndex ].m_tex == tex)
  238. {
  239. // blammo
  240. TexDetach( (EGLMFBOAttachment)attachIndex, GL_DRAW_FRAMEBUFFER_EXT );
  241. }
  242. }
  243. }
  244. bool CGLMFBO::IsReady( void )
  245. {
  246. bool result = false;
  247. // ensure our parent context is current
  248. m_ctx->CheckCurrent();
  249. // bind to context (will cause FBO object creation on first use)
  250. m_ctx->BindFBOToCtx( this );
  251. GLenum status;
  252. status = gGL->glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
  253. switch(status)
  254. {
  255. case GL_FRAMEBUFFER_COMPLETE_EXT:
  256. result = true;
  257. break;
  258. case GL_FRAMEBUFFER_UNSUPPORTED_EXT:
  259. result = false;
  260. DebuggerBreak();
  261. /* choose different formats */
  262. break;
  263. default:
  264. result = false;
  265. DebuggerBreak();
  266. /* programming error; will fail on all hardware */
  267. break;
  268. }
  269. return result;
  270. }