gfxGLTextureTarget.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442
  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. virtual GFXFormat getFormat() = 0;
  47. virtual bool isCompatible(const GFXGLTextureObject* tex) = 0;
  48. U32 getMipLevel() { return mipLevel; }
  49. U32 getZOffset() { return zOffset; }
  50. private:
  51. U32 mipLevel;
  52. U32 zOffset;
  53. };
  54. /// Internal struct used to track 2D/Rect texture information for FBO attachment
  55. class _GFXGLTextureTargetDesc : public _GFXGLTargetDesc
  56. {
  57. public:
  58. _GFXGLTextureTargetDesc(GFXGLTextureObject* tex, U32 _mipLevel, U32 _zOffset)
  59. : _GFXGLTargetDesc(_mipLevel, _zOffset), mTex(tex)
  60. {
  61. }
  62. virtual ~_GFXGLTextureTargetDesc() {}
  63. virtual U32 getHandle() { return mTex->getHandle(); }
  64. virtual U32 getWidth() { return mTex->getWidth(); }
  65. virtual U32 getHeight() { return mTex->getHeight(); }
  66. virtual U32 getDepth() { return mTex->getDepth(); }
  67. virtual bool hasMips() { return mTex->mMipLevels != 1; }
  68. virtual GLenum getBinding() { return mTex->getBinding(); }
  69. virtual GFXFormat getFormat() { return mTex->getFormat(); }
  70. virtual bool isCompatible(const GFXGLTextureObject* tex)
  71. {
  72. return mTex->getFormat() == tex->getFormat()
  73. && mTex->getWidth() == tex->getWidth()
  74. && mTex->getHeight() == tex->getHeight();
  75. }
  76. GFXGLTextureObject* getTextureObject() const {return mTex; }
  77. private:
  78. StrongRefPtr<GFXGLTextureObject> mTex;
  79. };
  80. /// Internal struct used to track Cubemap texture information for FBO attachment
  81. class _GFXGLCubemapTargetDesc : public _GFXGLTargetDesc
  82. {
  83. public:
  84. _GFXGLCubemapTargetDesc(GFXGLCubemap* tex, U32 _face, U32 _mipLevel, U32 _zOffset)
  85. : _GFXGLTargetDesc(_mipLevel, _zOffset), mTex(tex), mFace(_face)
  86. {
  87. }
  88. virtual ~_GFXGLCubemapTargetDesc() {}
  89. virtual U32 getHandle() { return mTex->getHandle(); }
  90. virtual U32 getWidth() { return mTex->getWidth(); }
  91. virtual U32 getHeight() { return mTex->getHeight(); }
  92. virtual U32 getDepth() { return 0; }
  93. virtual bool hasMips() { return mTex->getMipMapLevels() != 1; }
  94. virtual GLenum getBinding() { return GFXGLCubemap::getEnumForFaceNumber(mFace); }
  95. virtual GFXFormat getFormat() { return mTex->getFormat(); }
  96. virtual bool isCompatible(const GFXGLTextureObject* tex)
  97. {
  98. return mTex->getFormat() == tex->getFormat()
  99. && mTex->getWidth() == tex->getWidth()
  100. && mTex->getHeight() == tex->getHeight();
  101. }
  102. private:
  103. StrongRefPtr<GFXGLCubemap> mTex;
  104. U32 mFace;
  105. };
  106. // Internal implementations
  107. class _GFXGLTextureTargetImpl // TODO OPENGL remove and implement on GFXGLTextureTarget
  108. {
  109. public:
  110. GFXGLTextureTarget* mTarget;
  111. virtual ~_GFXGLTextureTargetImpl() {}
  112. virtual void applyState() = 0;
  113. virtual void makeActive() = 0;
  114. virtual void finish() = 0;
  115. };
  116. // Use FBOs to render to texture. This is the preferred implementation and is almost always used.
  117. class _GFXGLTextureTargetFBOImpl : public _GFXGLTextureTargetImpl
  118. {
  119. public:
  120. GLuint mFramebuffer;
  121. bool mGenMips;
  122. _GFXGLTextureTargetFBOImpl(GFXGLTextureTarget* target);
  123. virtual ~_GFXGLTextureTargetFBOImpl();
  124. virtual void applyState();
  125. virtual void makeActive();
  126. virtual void finish();
  127. };
  128. _GFXGLTextureTargetFBOImpl::_GFXGLTextureTargetFBOImpl(GFXGLTextureTarget* target)
  129. {
  130. mGenMips = target->isGenMipsEnabled();
  131. mTarget = target;
  132. glGenFramebuffers(1, &mFramebuffer);
  133. }
  134. _GFXGLTextureTargetFBOImpl::~_GFXGLTextureTargetFBOImpl()
  135. {
  136. glDeleteFramebuffers(1, &mFramebuffer);
  137. }
  138. void _GFXGLTextureTargetFBOImpl::applyState()
  139. {
  140. // REMINDER: When we implement MRT support, check against GFXGLDevice::getNumRenderTargets()
  141. PRESERVE_FRAMEBUFFER();
  142. glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
  143. glEnable(GL_FRAMEBUFFER_SRGB);
  144. bool drawbufs[16];
  145. int bufsize = 0;
  146. for (int i = 0; i < 16; i++)
  147. drawbufs[i] = false;
  148. bool hasColor = false;
  149. for(int i = 0; i < GFXGL->getNumRenderTargets(); ++i)
  150. {
  151. _GFXGLTargetDesc* color = mTarget->getTargetDesc( static_cast<GFXTextureTarget::RenderSlot>(GFXTextureTarget::Color0+i ));
  152. if(color)
  153. {
  154. hasColor = true;
  155. const GLenum binding = color->getBinding();
  156. if( binding == GL_TEXTURE_2D || (binding >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && binding <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z) )
  157. glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, color->getBinding( ), color->getHandle( ), color->getMipLevel( ) );
  158. else if( binding == GL_TEXTURE_1D )
  159. glFramebufferTexture1D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, color->getBinding( ), color->getHandle( ), color->getMipLevel( ) );
  160. else if( binding == GL_TEXTURE_3D )
  161. glFramebufferTexture3D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, color->getBinding( ), color->getHandle( ), color->getMipLevel( ), color->getZOffset( ) );
  162. else
  163. Con::errorf("_GFXGLTextureTargetFBOImpl::applyState - Bad binding");
  164. }
  165. else
  166. {
  167. // Clears the texture (note that the binding is irrelevent)
  168. glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0+i, GL_TEXTURE_2D, 0, 0);
  169. }
  170. }
  171. _GFXGLTargetDesc* depthStecil = mTarget->getTargetDesc(GFXTextureTarget::DepthStencil);
  172. if(depthStecil)
  173. {
  174. // Certain drivers have issues with depth only FBOs. That and the next two asserts assume we have a color target.
  175. AssertFatal(hasColor, "GFXGLTextureTarget::applyState() - Cannot set DepthStencil target without Color0 target!");
  176. glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, depthStecil->getBinding(), depthStecil->getHandle(), depthStecil->getMipLevel());
  177. }
  178. else
  179. {
  180. // Clears the texture (note that the binding is irrelevent)
  181. glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
  182. }
  183. GLenum *buf = new GLenum[bufsize];
  184. int count = 0;
  185. for (int i = 0; i < bufsize; i++)
  186. {
  187. if (drawbufs[i])
  188. {
  189. buf[count] = GL_COLOR_ATTACHMENT0 + i;
  190. count++;
  191. }
  192. }
  193. glDrawBuffers(bufsize, buf);
  194. delete[] buf;
  195. CHECK_FRAMEBUFFER_STATUS();
  196. }
  197. void _GFXGLTextureTargetFBOImpl::makeActive()
  198. {
  199. glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
  200. GFXGL->getOpenglCache()->setCacheBinded(GL_FRAMEBUFFER, mFramebuffer);
  201. int i = 0;
  202. GLenum draws[16];
  203. for( i = 0; i < GFXGL->getNumRenderTargets(); ++i)
  204. {
  205. _GFXGLTargetDesc* color = mTarget->getTargetDesc( static_cast<GFXTextureTarget::RenderSlot>(GFXTextureTarget::Color0+i ));
  206. if(color)
  207. draws[i] = GL_COLOR_ATTACHMENT0 + i;
  208. else
  209. break;
  210. }
  211. glDrawBuffers( i, draws );
  212. }
  213. void _GFXGLTextureTargetFBOImpl::finish()
  214. {
  215. glBindFramebuffer(GL_FRAMEBUFFER, 0);
  216. GFXGL->getOpenglCache()->setCacheBinded(GL_FRAMEBUFFER, 0);
  217. if (!mGenMips)
  218. return;
  219. for(int i = 0; i < GFXGL->getNumRenderTargets(); ++i)
  220. {
  221. _GFXGLTargetDesc* color = mTarget->getTargetDesc( static_cast<GFXTextureTarget::RenderSlot>(GFXTextureTarget::Color0+i ) );
  222. if(!color || !(color->hasMips()))
  223. continue;
  224. // Generate mips if necessary
  225. // Assumes a 2D texture.
  226. GLenum binding = color->getBinding();
  227. binding = (binding >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && binding <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z) ? GL_TEXTURE_CUBE_MAP : binding;
  228. PRESERVE_TEXTURE( binding );
  229. glBindTexture( binding, color->getHandle() );
  230. glGenerateMipmap( binding );
  231. }
  232. }
  233. // Actual GFXGLTextureTarget interface
  234. GFXGLTextureTarget::GFXGLTextureTarget(bool genMips) : mCopyFboSrc(0), mCopyFboDst(0)
  235. {
  236. mGenMips = genMips;
  237. for(U32 i=0; i<MaxRenderSlotId; i++)
  238. mTargets[i] = NULL;
  239. GFXTextureManager::addEventDelegate( this, &GFXGLTextureTarget::_onTextureEvent );
  240. _impl = new _GFXGLTextureTargetFBOImpl(this);
  241. glGenFramebuffers(1, &mCopyFboSrc);
  242. glGenFramebuffers(1, &mCopyFboDst);
  243. }
  244. GFXGLTextureTarget::~GFXGLTextureTarget()
  245. {
  246. GFXTextureManager::removeEventDelegate(this, &GFXGLTextureTarget::_onTextureEvent);
  247. glDeleteFramebuffers(1, &mCopyFboSrc);
  248. glDeleteFramebuffers(1, &mCopyFboDst);
  249. }
  250. const Point2I GFXGLTextureTarget::getSize()
  251. {
  252. if(mTargets[Color0].isValid())
  253. return Point2I(mTargets[Color0]->getWidth(), mTargets[Color0]->getHeight());
  254. return Point2I(0, 0);
  255. }
  256. GFXFormat GFXGLTextureTarget::getFormat()
  257. {
  258. if(mTargets[Color0].isValid())
  259. return mTargets[Color0]->getFormat();
  260. return GFXFormatR8G8B8A8;
  261. }
  262. void GFXGLTextureTarget::attachTexture( RenderSlot slot, GFXTextureObject *tex, U32 mipLevel/*=0*/, U32 zOffset /*= 0*/ )
  263. {
  264. if( tex == GFXTextureTarget::sDefaultDepthStencil )
  265. tex = GFXGL->getDefaultDepthTex();
  266. _GFXGLTextureTargetDesc* mTex = static_cast<_GFXGLTextureTargetDesc*>(mTargets[slot].ptr());
  267. if( (!tex && !mTex) || (mTex && mTex->getTextureObject() == tex) )
  268. return;
  269. // Triggers an update when we next render
  270. invalidateState();
  271. // We stash the texture and info into an internal struct.
  272. GFXGLTextureObject* glTexture = static_cast<GFXGLTextureObject*>(tex);
  273. if(tex && tex != GFXTextureTarget::sDefaultDepthStencil)
  274. mTargets[slot] = new _GFXGLTextureTargetDesc(glTexture, mipLevel, zOffset);
  275. else
  276. mTargets[slot] = NULL;
  277. }
  278. void GFXGLTextureTarget::attachTexture( RenderSlot slot, GFXCubemap *tex, U32 face, U32 mipLevel/*=0*/ )
  279. {
  280. // No depth cubemaps, sorry
  281. AssertFatal(slot != DepthStencil, "GFXGLTextureTarget::attachTexture (cube) - Cube depth textures not supported!");
  282. if(slot == DepthStencil)
  283. return;
  284. // Triggers an update when we next render
  285. invalidateState();
  286. // We stash the texture and info into an internal struct.
  287. GFXGLCubemap* glTexture = static_cast<GFXGLCubemap*>(tex);
  288. if(tex)
  289. mTargets[slot] = new _GFXGLCubemapTargetDesc(glTexture, face, mipLevel, 0);
  290. else
  291. mTargets[slot] = NULL;
  292. }
  293. void GFXGLTextureTarget::clearAttachments()
  294. {
  295. deactivate();
  296. for(S32 i=1; i<MaxRenderSlotId; i++)
  297. attachTexture((RenderSlot)i, NULL);
  298. }
  299. void GFXGLTextureTarget::zombify()
  300. {
  301. invalidateState();
  302. // Will be recreated in applyState
  303. _impl = NULL;
  304. }
  305. void GFXGLTextureTarget::resurrect()
  306. {
  307. // Dealt with when the target is next bound
  308. }
  309. void GFXGLTextureTarget::makeActive()
  310. {
  311. _impl->makeActive();
  312. }
  313. void GFXGLTextureTarget::deactivate()
  314. {
  315. _impl->finish();
  316. }
  317. void GFXGLTextureTarget::applyState()
  318. {
  319. if(!isPendingState())
  320. return;
  321. // So we don't do this over and over again
  322. stateApplied();
  323. if(_impl.isNull())
  324. _impl = new _GFXGLTextureTargetFBOImpl(this);
  325. _impl->applyState();
  326. }
  327. _GFXGLTargetDesc* GFXGLTextureTarget::getTargetDesc(RenderSlot slot) const
  328. {
  329. // This can only be called by our implementations, and then will not actually store the pointer so this is (almost) safe
  330. return mTargets[slot].ptr();
  331. }
  332. void GFXGLTextureTarget::_onTextureEvent( GFXTexCallbackCode code )
  333. {
  334. invalidateState();
  335. }
  336. const String GFXGLTextureTarget::describeSelf() const
  337. {
  338. String ret = String::ToString(" Color0 Attachment: %i", mTargets[Color0].isValid() ? mTargets[Color0]->getHandle() : 0);
  339. ret += String::ToString(" Depth Attachment: %i", mTargets[DepthStencil].isValid() ? mTargets[DepthStencil]->getHandle() : 0);
  340. return ret;
  341. }
  342. void GFXGLTextureTarget::resolve()
  343. {
  344. }
  345. void GFXGLTextureTarget::resolveTo(GFXTextureObject* obj)
  346. {
  347. AssertFatal(dynamic_cast<GFXGLTextureObject*>(obj), "GFXGLTextureTarget::resolveTo - Incorrect type of texture, expected a GFXGLTextureObject");
  348. GFXGLTextureObject* glTexture = static_cast<GFXGLTextureObject*>(obj);
  349. if( GFXGL->mCapabilities.copyImage && mTargets[Color0]->isCompatible(glTexture) )
  350. {
  351. GLenum binding = mTargets[Color0]->getBinding();
  352. binding = (binding >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && binding <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z) ? GL_TEXTURE_CUBE_MAP : binding;
  353. U32 srcStartDepth = binding == GL_TEXTURE_CUBE_MAP ? mTargets[Color0]->getBinding() - GL_TEXTURE_CUBE_MAP_POSITIVE_X : 0;
  354. glCopyImageSubData(
  355. mTargets[Color0]->getHandle(), binding, 0, 0, 0, srcStartDepth,
  356. glTexture->getHandle(), glTexture->getBinding(), 0, 0, 0, 0,
  357. mTargets[Color0]->getWidth(), mTargets[Color0]->getHeight(), 1);
  358. return;
  359. }
  360. PRESERVE_FRAMEBUFFER();
  361. glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mCopyFboDst);
  362. glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, glTexture->getBinding(), glTexture->getHandle(), 0);
  363. glBindFramebuffer(GL_READ_FRAMEBUFFER, mCopyFboSrc);
  364. glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTargets[Color0]->getBinding(), mTargets[Color0]->getHandle(), 0);
  365. glBlitFramebuffer(0, 0, mTargets[Color0]->getWidth(), mTargets[Color0]->getHeight(),
  366. 0, 0, glTexture->getWidth(), glTexture->getHeight(), GL_COLOR_BUFFER_BIT, GL_NEAREST);
  367. }