Team Fortress 2 Source Code as on 22/4/2020
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.

355 lines
9.9 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. // TOGL CODE LICENSE
  3. //
  4. // Copyright 2011-2014 Valve Corporation
  5. // All Rights Reserved.
  6. //
  7. // Permission is hereby granted, free of charge, to any person obtaining a copy
  8. // of this software and associated documentation files (the "Software"), to deal
  9. // in the Software without restriction, including without limitation the rights
  10. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  11. // copies of the Software, and to permit persons to whom the Software is
  12. // furnished to do so, subject to the following conditions:
  13. //
  14. // The above copyright notice and this permission notice shall be included in
  15. // all copies or substantial portions of the Software.
  16. //
  17. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  18. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  20. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  21. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  22. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  23. // THE SOFTWARE.
  24. //
  25. // cglmfbo.cpp
  26. //
  27. //===============================================================================
  28. #include "togl/rendermechanism.h"
  29. // memdbgon -must- be the last include file in a .cpp file.
  30. #include "tier0/memdbgon.h"
  31. CGLMFBO::CGLMFBO( GLMContext *ctx )
  32. {
  33. m_ctx = ctx;
  34. m_ctx->CheckCurrent();
  35. gGL->glGenFramebuffersEXT( 1, &m_name );
  36. memset( m_attach, 0, sizeof( m_attach ) );
  37. }
  38. CGLMFBO::~CGLMFBO( )
  39. {
  40. m_ctx->CheckCurrent();
  41. // detach all known attached textures first... necessary ?
  42. for( int index = 0; index < kAttCount; index++)
  43. {
  44. if (m_attach[ index ].m_tex)
  45. {
  46. TexDetach( (EGLMFBOAttachment)index );
  47. }
  48. }
  49. gGL->glDeleteFramebuffersEXT( 1, &m_name );
  50. m_name = 0;
  51. m_ctx = NULL;
  52. }
  53. // the tex attach path should also select a specific slice of the texture...
  54. // and we need a way to make renderbuffers..
  55. static GLenum EncodeAttachmentFBO( EGLMFBOAttachment index )
  56. {
  57. if (index < kAttDepth)
  58. {
  59. return GL_COLOR_ATTACHMENT0_EXT + (int) index;
  60. }
  61. else
  62. {
  63. switch( index )
  64. {
  65. case kAttDepth:
  66. return GL_DEPTH_ATTACHMENT_EXT;
  67. break;
  68. case kAttStencil:
  69. return GL_STENCIL_ATTACHMENT_EXT;
  70. break;
  71. case kAttDepthStencil:
  72. return GL_DEPTH_STENCIL_ATTACHMENT_EXT;
  73. break;
  74. default:
  75. GLMStop(); // bad news
  76. break;
  77. }
  78. }
  79. GLMStop(); // bad news
  80. // shouldn't get here
  81. return GL_COLOR_ATTACHMENT0_EXT;
  82. }
  83. void CGLMFBO::TexAttach( GLMFBOTexAttachParams *params, EGLMFBOAttachment attachIndex, GLenum fboBindPoint )
  84. {
  85. // force our parent context to be current
  86. m_ctx->MakeCurrent();
  87. // bind to context (will cause FBO object creation on first use)
  88. m_ctx->BindFBOToCtx( this, fboBindPoint );
  89. // it's either a plain 2D, a 2D face of a cube map, or a slice of a 3D.
  90. CGLMTex *tex = params->m_tex;
  91. // always detach what is currently there, if anything
  92. this->TexDetach( attachIndex, fboBindPoint );
  93. if (!tex)
  94. {
  95. // andif they pass NULL to us, then we are done.
  96. return;
  97. }
  98. GLMTexLayout *layout = tex->m_layout;
  99. GLenum target = tex->m_layout->m_key.m_texGLTarget;
  100. GLenum attachIndexGL = EncodeAttachmentFBO( attachIndex );
  101. switch( target )
  102. {
  103. case GL_TEXTURE_2D:
  104. {
  105. // 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.
  106. // 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
  107. // cases you really do want to attach the texture and not the RBO to the FBO in question.
  108. bool useRBO = false; // initial state
  109. if (layout->m_key.m_texFlags & kGLMTexMultisampled)
  110. {
  111. // it is an MSAA tex
  112. if (fboBindPoint == GL_READ_FRAMEBUFFER_EXT)
  113. {
  114. // I think you just want to read a resolved tex.
  115. // But I will check that it is resolved first..
  116. Assert( tex->IsRBODirty() == false );
  117. }
  118. else
  119. {
  120. // you want to draw into it. You get the RBO bound instead of the tex.
  121. useRBO = true;
  122. }
  123. }
  124. if (useRBO)
  125. {
  126. // MSAA path - attach the RBO, not the texture, and mark the RBO dirty
  127. if (attachIndexGL==GL_DEPTH_STENCIL_ATTACHMENT_EXT)
  128. {
  129. // you have to attach it both places...
  130. // http://www.opengl.org/wiki/GL_EXT_framebuffer_object
  131. // bind the RBO to the GL_RENDERBUFFER_EXT target
  132. gGL->glBindRenderbufferEXT( GL_RENDERBUFFER_EXT, tex->m_rboName );
  133. // attach the GL_RENDERBUFFER_EXT target to the depth and stencil attach points
  134. gGL->glFramebufferRenderbufferEXT( fboBindPoint, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, tex->m_rboName);
  135. gGL->glFramebufferRenderbufferEXT( fboBindPoint, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, tex->m_rboName);
  136. // no need to leave the RBO hanging on
  137. gGL->glBindRenderbufferEXT( GL_RENDERBUFFER_EXT, 0 );
  138. }
  139. else
  140. {
  141. // color attachment (likely 0)
  142. gGL->glBindRenderbufferEXT( GL_RENDERBUFFER_EXT, tex->m_rboName );
  143. gGL->glFramebufferRenderbufferEXT( fboBindPoint, attachIndexGL, GL_RENDERBUFFER_EXT, tex->m_rboName);
  144. gGL->glBindRenderbufferEXT( GL_RENDERBUFFER_EXT, 0 );
  145. }
  146. tex->ForceRBODirty();
  147. }
  148. else
  149. {
  150. // regular path - attaching a texture2d
  151. if (attachIndexGL==GL_DEPTH_STENCIL_ATTACHMENT_EXT)
  152. {
  153. // you have to attach it both places...
  154. // http://www.opengl.org/wiki/GL_EXT_framebuffer_object
  155. gGL->glFramebufferTexture2DEXT( fboBindPoint, GL_DEPTH_ATTACHMENT_EXT, target, tex->m_texName, params->m_mip );
  156. gGL->glFramebufferTexture2DEXT( fboBindPoint, GL_STENCIL_ATTACHMENT_EXT, target, tex->m_texName, params->m_mip );
  157. }
  158. else
  159. {
  160. gGL->glFramebufferTexture2DEXT( fboBindPoint, attachIndexGL, target, tex->m_texName, params->m_mip );
  161. }
  162. }
  163. }
  164. break;
  165. case GL_TEXTURE_3D:
  166. {
  167. gGL->glFramebufferTexture3DEXT( fboBindPoint, attachIndexGL, target, tex->m_texName, params->m_mip, params->m_zslice );
  168. }
  169. break;
  170. case GL_TEXTURE_CUBE_MAP:
  171. {
  172. // adjust target to steer to the proper face of the cube map
  173. target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + params->m_face;
  174. gGL->glFramebufferTexture2DEXT( fboBindPoint, attachIndexGL, target, tex->m_texName, params->m_mip );
  175. }
  176. break;
  177. }
  178. // log the attached tex
  179. m_attach[ attachIndex ] = *params;
  180. // indicate that the tex has been bound to an RT
  181. tex->m_rtAttachCount++;
  182. }
  183. void CGLMFBO::TexDetach( EGLMFBOAttachment attachIndex, GLenum fboBindPoint )
  184. {
  185. // force our parent context to be current
  186. m_ctx->MakeCurrent();
  187. // bind to context (will cause FBO object creation on first use)
  188. m_ctx->BindFBOToCtx( this, fboBindPoint );
  189. if (m_attach[ attachIndex ].m_tex)
  190. {
  191. CGLMTex *tex = m_attach[ attachIndex ].m_tex;
  192. GLMTexLayout *layout = tex->m_layout;
  193. GLenum target = tex->m_layout->m_key.m_texGLTarget;
  194. GLenum attachIndexGL = EncodeAttachmentFBO( attachIndex );
  195. switch( target )
  196. {
  197. case GL_TEXTURE_2D:
  198. {
  199. if (layout->m_key.m_texFlags & kGLMTexMultisampled)
  200. {
  201. // MSAA path - detach the RBO, not the texture
  202. // (is this the right time to resolve? probably better to wait until someone tries to sample the texture)
  203. gGL->glBindRenderbufferEXT( GL_RENDERBUFFER_EXT, 0 );
  204. if (attachIndexGL==GL_DEPTH_STENCIL_ATTACHMENT_EXT)
  205. {
  206. // detach the GL_RENDERBUFFER_EXT target at depth and stencil attach points
  207. gGL->glFramebufferRenderbufferEXT( GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0);
  208. gGL->glFramebufferRenderbufferEXT( GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0);
  209. }
  210. else
  211. {
  212. // color attachment (likely 0)
  213. gGL->glFramebufferRenderbufferEXT( GL_FRAMEBUFFER_EXT, attachIndexGL, GL_RENDERBUFFER_EXT, 0);
  214. }
  215. }
  216. else
  217. {
  218. // plain tex detach
  219. if (attachIndexGL==GL_DEPTH_STENCIL_ATTACHMENT_EXT)
  220. {
  221. // you have to detach it both places...
  222. // http://www.opengl.org/wiki/GL_EXT_framebuffer_object
  223. gGL->glFramebufferTexture2DEXT( fboBindPoint, GL_DEPTH_ATTACHMENT_EXT, target, 0, 0 );
  224. gGL->glFramebufferTexture2DEXT( fboBindPoint, GL_STENCIL_ATTACHMENT_EXT, target, 0, 0 );
  225. }
  226. else
  227. {
  228. gGL->glFramebufferTexture2DEXT( fboBindPoint, attachIndexGL, target, 0, 0 );
  229. }
  230. }
  231. }
  232. break;
  233. case GL_TEXTURE_3D:
  234. {
  235. gGL->glFramebufferTexture3DEXT( fboBindPoint, attachIndexGL, target, 0, 0, 0 );
  236. }
  237. break;
  238. case GL_TEXTURE_CUBE_MAP:
  239. {
  240. gGL->glFramebufferTexture2DEXT( fboBindPoint, attachIndexGL, target, 0, 0 );
  241. }
  242. break;
  243. }
  244. // un-log the attached tex
  245. memset( &m_attach[ attachIndex ], 0, sizeof( m_attach[0] ) );
  246. // drop the RT attach count
  247. tex->m_rtAttachCount--;
  248. }
  249. else
  250. {
  251. //Debugger(); // odd, but not harmful - typ comes from D3D code passing NULL into SetRenderTarget
  252. }
  253. }
  254. void CGLMFBO::TexScrub( CGLMTex *tex )
  255. {
  256. // see if it's attached anywhere
  257. for( int attachIndex = 0; attachIndex < kAttCount; attachIndex++ )
  258. {
  259. if (m_attach[ attachIndex ].m_tex == tex)
  260. {
  261. // blammo
  262. TexDetach( (EGLMFBOAttachment)attachIndex, GL_DRAW_FRAMEBUFFER_EXT );
  263. }
  264. }
  265. }
  266. bool CGLMFBO::IsReady( void )
  267. {
  268. bool result = false;
  269. // ensure our parent context is current
  270. m_ctx->CheckCurrent();
  271. // bind to context (will cause FBO object creation on first use)
  272. m_ctx->BindFBOToCtx( this );
  273. GLenum status;
  274. status = gGL->glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
  275. switch(status)
  276. {
  277. case GL_FRAMEBUFFER_COMPLETE_EXT:
  278. result = true;
  279. break;
  280. case GL_FRAMEBUFFER_UNSUPPORTED_EXT:
  281. result = false;
  282. DebuggerBreak();
  283. /* choose different formats */
  284. break;
  285. default:
  286. result = false;
  287. DebuggerBreak();
  288. /* programming error; will fail on all hardware */
  289. break;
  290. }
  291. return result;
  292. }