gfxGLTextureTarget.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2012 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #include "console/console.h"
  23. #include "gfx/gl/gfxGLDevice.h"
  24. #include "gfx/gl/gfxGLTextureTarget.h"
  25. #include "gfx/gl/gfxGLTextureObject.h"
  26. #include "gfx/gl/gfxGLCubemap.h"
  27. #include "gfx/gfxTextureManager.h"
  28. #include "gfx/gl/gfxGLUtils.h"
  29. /// Internal struct used to track texture information for FBO attachments
  30. /// This serves as an abstract base so we can deal with cubemaps and standard
  31. /// 2D/Rect textures through the same interface
  32. class _GFXGLTargetDesc
  33. {
  34. public:
  35. _GFXGLTargetDesc(U32 _mipLevel, U32 _zOffset) :
  36. mipLevel(_mipLevel), zOffset(_zOffset)
  37. {
  38. }
  39. virtual ~_GFXGLTargetDesc() {}
  40. virtual U32 getHandle() = 0;
  41. virtual U32 getWidth() = 0;
  42. virtual U32 getHeight() = 0;
  43. virtual U32 getDepth() = 0;
  44. virtual bool hasMips() = 0;
  45. virtual GLenum getBinding() = 0;
  46. U32 getMipLevel() { return mipLevel; }
  47. U32 getZOffset() { return zOffset; }
  48. private:
  49. U32 mipLevel;
  50. U32 zOffset;
  51. };
  52. /// Internal struct used to track 2D/Rect texture information for FBO attachment
  53. class _GFXGLTextureTargetDesc : public _GFXGLTargetDesc
  54. {
  55. public:
  56. _GFXGLTextureTargetDesc(GFXGLTextureObject* tex, U32 _mipLevel, U32 _zOffset)
  57. : _GFXGLTargetDesc(_mipLevel, _zOffset), mTex(tex)
  58. {
  59. }
  60. virtual ~_GFXGLTextureTargetDesc() {}
  61. virtual U32 getHandle() { return mTex->getHandle(); }
  62. virtual U32 getWidth() { return mTex->getWidth(); }
  63. virtual U32 getHeight() { return mTex->getHeight(); }
  64. virtual U32 getDepth() { return mTex->getDepth(); }
  65. virtual bool hasMips() { return mTex->mMipLevels != 1; }
  66. virtual GLenum getBinding() { return mTex->getBinding(); }
  67. private:
  68. StrongRefPtr<GFXGLTextureObject> mTex;
  69. };
  70. /// Internal struct used to track Cubemap texture information for FBO attachment
  71. class _GFXGLCubemapTargetDesc : public _GFXGLTargetDesc
  72. {
  73. public:
  74. _GFXGLCubemapTargetDesc(GFXGLCubemap* tex, U32 _face, U32 _mipLevel, U32 _zOffset)
  75. : _GFXGLTargetDesc(_mipLevel, _zOffset), mTex(tex), mFace(_face)
  76. {
  77. }
  78. virtual ~_GFXGLCubemapTargetDesc() {}
  79. virtual U32 getHandle() { return mTex->getHandle(); }
  80. virtual U32 getWidth() { return mTex->getWidth(); }
  81. virtual U32 getHeight() { return mTex->getHeight(); }
  82. virtual U32 getDepth() { return 0; }
  83. virtual bool hasMips() { return mTex->getNumMipLevels() != 1; }
  84. virtual GLenum getBinding() { return GFXGLCubemap::getEnumForFaceNumber(mFace); }
  85. private:
  86. StrongRefPtr<GFXGLCubemap> mTex;
  87. U32 mFace;
  88. };
  89. // Internal implementations
  90. class _GFXGLTextureTargetImpl
  91. {
  92. public:
  93. GFXGLTextureTarget* mTarget;
  94. virtual ~_GFXGLTextureTargetImpl() {}
  95. virtual void applyState() = 0;
  96. virtual void makeActive() = 0;
  97. virtual void finish() = 0;
  98. };
  99. // Use FBOs to render to texture. This is the preferred implementation and is almost always used.
  100. class _GFXGLTextureTargetFBOImpl : public _GFXGLTextureTargetImpl
  101. {
  102. public:
  103. GLuint mFramebuffer;
  104. _GFXGLTextureTargetFBOImpl(GFXGLTextureTarget* target);
  105. virtual ~_GFXGLTextureTargetFBOImpl();
  106. virtual void applyState();
  107. virtual void makeActive();
  108. virtual void finish();
  109. };
  110. // Handy macro for checking the status of a framebuffer. Framebuffers can fail in
  111. // all sorts of interesting ways, these are just the most common. Further, no existing GL profiling
  112. // tool catches framebuffer errors when the framebuffer is created, so we actually need this.
  113. #define CHECK_FRAMEBUFFER_STATUS()\
  114. {\
  115. GLenum status;\
  116. status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);\
  117. switch(status) {\
  118. case GL_FRAMEBUFFER_COMPLETE_EXT:\
  119. break;\
  120. case GL_FRAMEBUFFER_UNSUPPORTED_EXT:\
  121. AssertFatal(false, "Unsupported FBO");\
  122. break;\
  123. case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT:\
  124. AssertFatal(false, "Incomplete FBO Attachment");\
  125. break;\
  126. case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT:\
  127. AssertFatal(false, "Incomplete FBO dimensions");\
  128. break;\
  129. case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT:\
  130. AssertFatal(false, "Incomplete FBO formats");\
  131. default:\
  132. /* programming error; will fail on all hardware */\
  133. AssertFatal(false, "Something really bad happened with an FBO");\
  134. }\
  135. }
  136. _GFXGLTextureTargetFBOImpl::_GFXGLTextureTargetFBOImpl(GFXGLTextureTarget* target)
  137. {
  138. mTarget = target;
  139. glGenFramebuffersEXT(1, &mFramebuffer);
  140. }
  141. _GFXGLTextureTargetFBOImpl::~_GFXGLTextureTargetFBOImpl()
  142. {
  143. glDeleteFramebuffersEXT(1, &mFramebuffer);
  144. }
  145. void _GFXGLTextureTargetFBOImpl::applyState()
  146. {
  147. // REMINDER: When we implement MRT support, check against GFXGLDevice::getNumRenderTargets()
  148. glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, mFramebuffer);
  149. _GFXGLTargetDesc* color0 = mTarget->getTargetDesc(GFXTextureTarget::Color0);
  150. if(color0)
  151. {
  152. if(color0->getDepth() == 0)
  153. glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, color0->getBinding(), color0->getHandle(), color0->getMipLevel());
  154. else
  155. glFramebufferTexture3DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, color0->getBinding(), color0->getHandle(), color0->getMipLevel(), color0->getZOffset());
  156. }
  157. else
  158. {
  159. // Clears the texture (note that the binding is irrelevent)
  160. glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, 0, 0);
  161. }
  162. _GFXGLTargetDesc* depthStecil = mTarget->getTargetDesc(GFXTextureTarget::DepthStencil);
  163. if(depthStecil)
  164. {
  165. // Certain drivers have issues with depth only FBOs. That and the next two asserts assume we have a color target.
  166. AssertFatal(color0, "GFXGLTextureTarget::applyState() - Cannot set DepthStencil target without Color0 target!");
  167. AssertFatal(depthStecil->getWidth() == color0->getWidth(), "GFXGLTextureTarget::applyState() - DepthStencil and Color0 targets MUST have the same width!");
  168. AssertFatal(depthStecil->getHeight() == color0->getHeight(), "GFXGLTextureTarget::applyState() - DepthStencil and Color0 targets MUST have the same height!");
  169. glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, depthStecil->getBinding(), depthStecil->getHandle(), depthStecil->getMipLevel());
  170. }
  171. else
  172. {
  173. // Clears the texture (note that the binding is irrelevent)
  174. glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0);
  175. }
  176. glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
  177. }
  178. void _GFXGLTextureTargetFBOImpl::makeActive()
  179. {
  180. glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, mFramebuffer);
  181. glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, mFramebuffer);
  182. }
  183. void _GFXGLTextureTargetFBOImpl::finish()
  184. {
  185. glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0);
  186. glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0);
  187. _GFXGLTargetDesc* color0 = mTarget->getTargetDesc(GFXTextureTarget::Color0);
  188. if(!color0 || !(color0->hasMips()))
  189. return;
  190. // Generate mips if necessary
  191. // Assumes a 2D texture.
  192. glActiveTexture(GL_TEXTURE0);
  193. PRESERVE_2D_TEXTURE();
  194. glBindTexture(GL_TEXTURE_2D, color0->getHandle());
  195. glGenerateMipmapEXT(GL_TEXTURE_2D);
  196. }
  197. // This implementations uses AUX buffers (we should always have at least one) to do render to texture. It is currently only used when we need access to the windows depth buffer.
  198. class _GFXGLTextureTargetAUXBufferImpl : public _GFXGLTextureTargetImpl
  199. {
  200. public:
  201. _GFXGLTextureTargetAUXBufferImpl(GFXGLTextureTarget* target);
  202. virtual void applyState();
  203. virtual void makeActive();
  204. virtual void finish();
  205. };
  206. _GFXGLTextureTargetAUXBufferImpl::_GFXGLTextureTargetAUXBufferImpl(GFXGLTextureTarget* target)
  207. {
  208. mTarget = target;
  209. }
  210. void _GFXGLTextureTargetAUXBufferImpl::applyState()
  211. {
  212. }
  213. void _GFXGLTextureTargetAUXBufferImpl::makeActive()
  214. {
  215. glDrawBuffer(GL_AUX0);
  216. glReadBuffer(GL_AUX0);
  217. }
  218. void _GFXGLTextureTargetAUXBufferImpl::finish()
  219. {
  220. // Bind the Color0 texture
  221. _GFXGLTargetDesc* color0 = mTarget->getTargetDesc(GFXTextureTarget::Color0);
  222. glActiveTexture(GL_TEXTURE0);
  223. // Assume we're a 2D texture for now.
  224. PRESERVE_2D_TEXTURE();
  225. glBindTexture(color0->getBinding(), color0->getHandle());
  226. glCopyTexSubImage2D(color0->getBinding(), 0, 0, 0, 0, 0, color0->getWidth(), color0->getHeight());
  227. glDrawBuffer(GL_BACK);
  228. glReadBuffer(GL_BACK);
  229. }
  230. // Actual GFXGLTextureTarget interface
  231. GFXGLTextureTarget::GFXGLTextureTarget()
  232. {
  233. for(U32 i=0; i<MaxRenderSlotId; i++)
  234. mTargets[i] = NULL;
  235. GFXTextureManager::addEventDelegate( this, &GFXGLTextureTarget::_onTextureEvent );
  236. _impl = new _GFXGLTextureTargetFBOImpl(this);
  237. _needsAux = false;
  238. }
  239. GFXGLTextureTarget::~GFXGLTextureTarget()
  240. {
  241. GFXTextureManager::removeEventDelegate( this, &GFXGLTextureTarget::_onTextureEvent );
  242. }
  243. const Point2I GFXGLTextureTarget::getSize()
  244. {
  245. if(mTargets[Color0].isValid())
  246. return Point2I(mTargets[Color0]->getWidth(), mTargets[Color0]->getHeight());
  247. return Point2I(0, 0);
  248. }
  249. GFXFormat GFXGLTextureTarget::getFormat()
  250. {
  251. // TODO: Fix me!
  252. return GFXFormatR8G8B8A8;
  253. }
  254. void GFXGLTextureTarget::attachTexture( RenderSlot slot, GFXTextureObject *tex, U32 mipLevel/*=0*/, U32 zOffset /*= 0*/ )
  255. {
  256. // GFXTextureTarget::sDefaultDepthStencil is a hint that we want the window's depth buffer.
  257. if(tex == GFXTextureTarget::sDefaultDepthStencil)
  258. _needsAux = true;
  259. if(slot == DepthStencil && tex != GFXTextureTarget::sDefaultDepthStencil)
  260. _needsAux = false;
  261. // Triggers an update when we next render
  262. invalidateState();
  263. // We stash the texture and info into an internal struct.
  264. GFXGLTextureObject* glTexture = static_cast<GFXGLTextureObject*>(tex);
  265. if(tex && tex != GFXTextureTarget::sDefaultDepthStencil)
  266. mTargets[slot] = new _GFXGLTextureTargetDesc(glTexture, mipLevel, zOffset);
  267. else
  268. mTargets[slot] = NULL;
  269. }
  270. void GFXGLTextureTarget::attachTexture( RenderSlot slot, GFXCubemap *tex, U32 face, U32 mipLevel/*=0*/ )
  271. {
  272. // No depth cubemaps, sorry
  273. AssertFatal(slot != DepthStencil, "GFXGLTextureTarget::attachTexture (cube) - Cube depth textures not supported!");
  274. if(slot == DepthStencil)
  275. return;
  276. // Triggers an update when we next render
  277. invalidateState();
  278. // We stash the texture and info into an internal struct.
  279. GFXGLCubemap* glTexture = static_cast<GFXGLCubemap*>(tex);
  280. if(tex)
  281. mTargets[slot] = new _GFXGLCubemapTargetDesc(glTexture, face, mipLevel, 0);
  282. else
  283. mTargets[slot] = NULL;
  284. }
  285. void GFXGLTextureTarget::clearAttachments()
  286. {
  287. deactivate();
  288. for(S32 i=1; i<MaxRenderSlotId; i++)
  289. attachTexture((RenderSlot)i, NULL);
  290. }
  291. void GFXGLTextureTarget::zombify()
  292. {
  293. invalidateState();
  294. // Will be recreated in applyState
  295. _impl = NULL;
  296. }
  297. void GFXGLTextureTarget::resurrect()
  298. {
  299. // Dealt with when the target is next bound
  300. }
  301. void GFXGLTextureTarget::makeActive()
  302. {
  303. _impl->makeActive();
  304. }
  305. void GFXGLTextureTarget::deactivate()
  306. {
  307. _impl->finish();
  308. }
  309. void GFXGLTextureTarget::applyState()
  310. {
  311. if(!isPendingState())
  312. return;
  313. // So we don't do this over and over again
  314. stateApplied();
  315. // Ensure we have the proper implementation (consider changing to an enum?)
  316. if(_needsAux && dynamic_cast<_GFXGLTextureTargetAUXBufferImpl*>(_impl.ptr()) == NULL)
  317. _impl = new _GFXGLTextureTargetAUXBufferImpl(this);
  318. else if(!_needsAux && dynamic_cast<_GFXGLTextureTargetFBOImpl*>(_impl.ptr()) == NULL)
  319. _impl = new _GFXGLTextureTargetFBOImpl(this);
  320. _impl->applyState();
  321. }
  322. _GFXGLTargetDesc* GFXGLTextureTarget::getTargetDesc(RenderSlot slot) const
  323. {
  324. // This can only be called by our implementations, and then will not actually store the pointer so this is (almost) safe
  325. return mTargets[slot].ptr();
  326. }
  327. void GFXGLTextureTarget::_onTextureEvent( GFXTexCallbackCode code )
  328. {
  329. invalidateState();
  330. }
  331. const String GFXGLTextureTarget::describeSelf() const
  332. {
  333. String ret = String::ToString(" Color0 Attachment: %i", mTargets[Color0].isValid() ? mTargets[Color0]->getHandle() : 0);
  334. ret += String::ToString(" Depth Attachment: %i", mTargets[DepthStencil].isValid() ? mTargets[DepthStencil]->getHandle() : 0);
  335. return ret;
  336. }
  337. void GFXGLTextureTarget::resolve()
  338. {
  339. }
  340. void GFXGLTextureTarget::resolveTo(GFXTextureObject* obj)
  341. {
  342. AssertFatal(dynamic_cast<GFXGLTextureObject*>(obj), "GFXGLTextureTarget::resolveTo - Incorrect type of texture, expected a GFXGLTextureObject");
  343. GFXGLTextureObject* glTexture = static_cast<GFXGLTextureObject*>(obj);
  344. PRESERVE_FRAMEBUFFER();
  345. GLuint dest;
  346. GLuint src;
  347. glGenFramebuffersEXT(1, &dest);
  348. glGenFramebuffersEXT(1, &src);
  349. glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, dest);
  350. glFramebufferTexture2DEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, glTexture->getHandle(), 0);
  351. glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, src);
  352. glFramebufferTexture2DEXT(GL_READ_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D,mTargets[Color0]->getHandle(), 0);
  353. glBlitFramebufferEXT(0, 0, mTargets[Color0]->getWidth(), mTargets[Color0]->getHeight(),
  354. 0, 0, glTexture->getWidth(), glTexture->getHeight(), GL_COLOR_BUFFER_BIT, GL_NEAREST);
  355. glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0);
  356. glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0);
  357. glDeleteFramebuffersEXT(1, &dest);
  358. glDeleteFramebuffersEXT(1, &src);
  359. }