Torque3D Documentation / _generateds / gfxGLTextureTarget.cpp

gfxGLTextureTarget.cpp

Engine/source/gfx/gl/gfxGLTextureTarget.cpp

More...

Classes:

class

Internal struct used to track Cubemap texture information for FBO attachment.

class

Internal struct used to track texture information for FBO attachments This serves as an abstract base so we can deal with cubemaps and standard 2D/Rect textures through the same interface.

class

Internal struct used to track 2D/Rect texture information for FBO attachment.

Detailed Description

  1
  2//-----------------------------------------------------------------------------
  3// Copyright (c) 2012 GarageGames, LLC
  4//
  5// Permission is hereby granted, free of charge, to any person obtaining a copy
  6// of this software and associated documentation files (the "Software"), to
  7// deal in the Software without restriction, including without limitation the
  8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  9// sell copies of the Software, and to permit persons to whom the Software is
 10// furnished to do so, subject to the following conditions:
 11//
 12// The above copyright notice and this permission notice shall be included in
 13// all copies or substantial portions of the Software.
 14//
 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 21// IN THE SOFTWARE.
 22//-----------------------------------------------------------------------------
 23
 24#include "console/console.h"
 25#include "gfx/gl/gfxGLDevice.h"
 26#include "gfx/gl/gfxGLTextureTarget.h"
 27#include "gfx/gl/gfxGLTextureObject.h"
 28#include "gfx/gl/gfxGLCubemap.h"
 29#include "gfx/gfxTextureManager.h"
 30#include "gfx/gl/gfxGLUtils.h"
 31
 32/// Internal struct used to track texture information for FBO attachments
 33/// This serves as an abstract base so we can deal with cubemaps and standard 
 34/// 2D/Rect textures through the same interface
 35class _GFXGLTargetDesc
 36{
 37public:
 38   _GFXGLTargetDesc(U32 _mipLevel, U32 _zOffset) :
 39      mipLevel(_mipLevel), zOffset(_zOffset)
 40   {
 41   }
 42   
 43   virtual ~_GFXGLTargetDesc() {}
 44   
 45   virtual U32 getHandle() = 0;
 46   virtual U32 getWidth() = 0;
 47   virtual U32 getHeight() = 0;
 48   virtual U32 getDepth() = 0;
 49   virtual bool hasMips() = 0;
 50   virtual GLenum getBinding() = 0;
 51   virtual GFXFormat getFormat() = 0;
 52   virtual bool isCompatible(const GFXGLTextureObject* tex) = 0;
 53   
 54   U32 getMipLevel() { return mipLevel; }
 55   U32 getZOffset() { return zOffset; }
 56   
 57private:
 58   U32 mipLevel;
 59   U32 zOffset;
 60};
 61
 62/// Internal struct used to track 2D/Rect texture information for FBO attachment
 63class _GFXGLTextureTargetDesc : public _GFXGLTargetDesc
 64{
 65public:
 66   _GFXGLTextureTargetDesc(GFXGLTextureObject* tex, U32 _mipLevel, U32 _zOffset) 
 67      : _GFXGLTargetDesc(_mipLevel, _zOffset), mTex(tex)
 68   {
 69   }
 70   
 71   virtual ~_GFXGLTextureTargetDesc() {}
 72   
 73   virtual U32 getHandle() { return mTex->getHandle(); }
 74   virtual U32 getWidth() { return mTex->getWidth(); }
 75   virtual U32 getHeight() { return mTex->getHeight(); }
 76   virtual U32 getDepth() { return mTex->getDepth(); }
 77   virtual bool hasMips() { return mTex->mMipLevels != 1; }
 78   virtual GLenum getBinding() { return mTex->getBinding(); }
 79   virtual GFXFormat getFormat() { return mTex->getFormat(); }
 80   virtual bool isCompatible(const GFXGLTextureObject* tex)
 81   {
 82      return mTex->getFormat() == tex->getFormat()
 83         && mTex->getWidth() == tex->getWidth()
 84         && mTex->getHeight() == tex->getHeight();
 85   }
 86   GFXGLTextureObject* getTextureObject() const {return mTex; }
 87   
 88private:
 89   StrongRefPtr<GFXGLTextureObject> mTex;
 90};
 91
 92/// Internal struct used to track Cubemap texture information for FBO attachment
 93class _GFXGLCubemapTargetDesc : public _GFXGLTargetDesc
 94{
 95public:
 96   _GFXGLCubemapTargetDesc(GFXGLCubemap* tex, U32 _face, U32 _mipLevel, U32 _zOffset) 
 97      : _GFXGLTargetDesc(_mipLevel, _zOffset), mTex(tex), mFace(_face)
 98   {
 99   }
100   
101   virtual ~_GFXGLCubemapTargetDesc() {}
102   
103   virtual U32 getHandle() { return mTex->getHandle(); }
104   virtual U32 getWidth() { return mTex->getWidth(); }
105   virtual U32 getHeight() { return mTex->getHeight(); }
106   virtual U32 getDepth() { return 0; }
107   virtual bool hasMips() { return mTex->getNumMipLevels() != 1; }
108   virtual GLenum getBinding() { return GFXGLCubemap::getEnumForFaceNumber(mFace); }
109   virtual GFXFormat getFormat() { return mTex->getFormat(); }
110   virtual bool isCompatible(const GFXGLTextureObject* tex)
111   {
112      return mTex->getFormat() == tex->getFormat()
113         && mTex->getWidth() == tex->getWidth()
114         && mTex->getHeight() == tex->getHeight();
115   }
116   
117private:
118   StrongRefPtr<GFXGLCubemap> mTex;
119   U32 mFace;
120};
121
122// Internal implementations
123class _GFXGLTextureTargetImpl // TODO OPENGL remove and implement on GFXGLTextureTarget
124{
125public:
126   GFXGLTextureTarget* mTarget;
127   
128   virtual ~_GFXGLTextureTargetImpl() {}
129   
130   virtual void applyState() = 0;
131   virtual void makeActive() = 0;
132   virtual void finish() = 0;
133};
134
135// Use FBOs to render to texture.  This is the preferred implementation and is almost always used.
136class _GFXGLTextureTargetFBOImpl : public _GFXGLTextureTargetImpl
137{
138public:
139   GLuint mFramebuffer;
140   
141   _GFXGLTextureTargetFBOImpl(GFXGLTextureTarget* target);
142   virtual ~_GFXGLTextureTargetFBOImpl();
143   
144   virtual void applyState();
145   virtual void makeActive();
146   virtual void finish();
147};
148
149_GFXGLTextureTargetFBOImpl::_GFXGLTextureTargetFBOImpl(GFXGLTextureTarget* target)
150{
151   mTarget = target;
152   glGenFramebuffers(1, &mFramebuffer);
153}
154
155_GFXGLTextureTargetFBOImpl::~_GFXGLTextureTargetFBOImpl()
156{
157   glDeleteFramebuffers(1, &mFramebuffer);
158}
159
160void _GFXGLTextureTargetFBOImpl::applyState()
161{   
162   // REMINDER: When we implement MRT support, check against GFXGLDevice::getNumRenderTargets()
163   
164   PRESERVE_FRAMEBUFFER();
165   glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
166
167   bool drawbufs[16];
168   int bufsize = 0;
169   for (int i = 0; i < 16; i++)
170           drawbufs[i] = false;
171   bool hasColor = false;
172   for(int i = 0; i < GFXGL->getNumRenderTargets(); ++i)
173   {   
174      _GFXGLTargetDesc* color = mTarget->getTargetDesc( static_cast<GFXTextureTarget::RenderSlot>(GFXTextureTarget::Color0+i ));
175      if(color)
176      {
177         hasColor = true;
178         const GLenum binding = color->getBinding();
179         if( binding == GL_TEXTURE_2D || (binding >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && binding <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z) )
180            glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, color->getBinding( ), color->getHandle( ), color->getMipLevel( ) );
181         else if( binding == GL_TEXTURE_1D )
182            glFramebufferTexture1D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, color->getBinding( ), color->getHandle( ), color->getMipLevel( ) );
183         else if( binding == GL_TEXTURE_3D )
184            glFramebufferTexture3D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, color->getBinding( ), color->getHandle( ), color->getMipLevel( ), color->getZOffset( ) );
185         else
186             Con::errorf("_GFXGLTextureTargetFBOImpl::applyState - Bad binding");
187      }
188      else
189      {
190         // Clears the texture (note that the binding is irrelevent)
191         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0+i, GL_TEXTURE_2D, 0, 0);
192      }
193   }
194   
195   _GFXGLTargetDesc* depthStecil = mTarget->getTargetDesc(GFXTextureTarget::DepthStencil);
196   if(depthStecil)
197   {
198      // Certain drivers have issues with depth only FBOs.  That and the next two asserts assume we have a color target.
199      AssertFatal(hasColor, "GFXGLTextureTarget::applyState() - Cannot set DepthStencil target without Color0 target!");
200      glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, depthStecil->getBinding(), depthStecil->getHandle(), depthStecil->getMipLevel());
201   }
202   else
203   {
204      // Clears the texture (note that the binding is irrelevent)
205      glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
206   }
207
208   GLenum *buf = new GLenum[bufsize];
209   int count = 0;
210   for (int i = 0; i < bufsize; i++)
211   {
212           if (drawbufs[i])
213           {
214                   buf[count] = GL_COLOR_ATTACHMENT0 + i;
215                   count++;
216           }
217   }
218 
219   glDrawBuffers(bufsize, buf);
220 
221   delete[] buf;
222   CHECK_FRAMEBUFFER_STATUS();
223}
224
225void _GFXGLTextureTargetFBOImpl::makeActive()
226{
227    glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
228    GFXGL->getOpenglCache()->setCacheBinded(GL_FRAMEBUFFER, mFramebuffer);
229
230    int i = 0;
231    GLenum draws[16];
232    for( i = 0; i < GFXGL->getNumRenderTargets(); ++i)
233    {
234        _GFXGLTargetDesc* color = mTarget->getTargetDesc( static_cast<GFXTextureTarget::RenderSlot>(GFXTextureTarget::Color0+i ));
235        if(color)
236            draws[i] = GL_COLOR_ATTACHMENT0 + i;
237        else
238            break;
239    }
240
241    glDrawBuffers( i, draws );
242}
243
244void _GFXGLTextureTargetFBOImpl::finish()
245{
246   glBindFramebuffer(GL_FRAMEBUFFER, 0);
247   GFXGL->getOpenglCache()->setCacheBinded(GL_FRAMEBUFFER, 0);
248
249   for(int i = 0; i < GFXGL->getNumRenderTargets(); ++i)
250   {   
251      _GFXGLTargetDesc* color = mTarget->getTargetDesc( static_cast<GFXTextureTarget::RenderSlot>(GFXTextureTarget::Color0+i ) );
252      if(!color || !(color->hasMips()))
253         continue;
254   
255      // Generate mips if necessary
256      // Assumes a 2D texture.
257      GLenum binding = color->getBinding();
258      binding = (binding >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && binding <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z) ? GL_TEXTURE_CUBE_MAP : binding;
259
260      PRESERVE_TEXTURE( binding );
261      glBindTexture( binding, color->getHandle() );
262      glGenerateMipmap( binding );
263   }
264}
265
266// Actual GFXGLTextureTarget interface
267GFXGLTextureTarget::GFXGLTextureTarget() : mCopyFboSrc(0), mCopyFboDst(0)
268{
269   for(U32 i=0; i<MaxRenderSlotId; i++)
270      mTargets[i] = NULL;
271   
272   GFXTextureManager::addEventDelegate( this, &GFXGLTextureTarget::_onTextureEvent );
273
274   _impl = new _GFXGLTextureTargetFBOImpl(this);
275    
276   glGenFramebuffers(1, &mCopyFboSrc);
277   glGenFramebuffers(1, &mCopyFboDst);
278}
279
280GFXGLTextureTarget::~GFXGLTextureTarget()
281{
282   GFXTextureManager::removeEventDelegate(this, &GFXGLTextureTarget::_onTextureEvent);
283
284   glDeleteFramebuffers(1, &mCopyFboSrc);
285   glDeleteFramebuffers(1, &mCopyFboDst);
286}
287
288const Point2I GFXGLTextureTarget::getSize()
289{
290   if(mTargets[Color0].isValid())
291      return Point2I(mTargets[Color0]->getWidth(), mTargets[Color0]->getHeight());
292
293   return Point2I(0, 0);
294}
295
296GFXFormat GFXGLTextureTarget::getFormat()
297{
298   if(mTargets[Color0].isValid())
299      return mTargets[Color0]->getFormat();
300
301   return GFXFormatR8G8B8A8;
302}
303
304void GFXGLTextureTarget::attachTexture( RenderSlot slot, GFXTextureObject *tex, U32 mipLevel/*=0*/, U32 zOffset /*= 0*/ )
305{
306   if( tex == GFXTextureTarget::sDefaultDepthStencil )
307      tex = GFXGL->getDefaultDepthTex();
308
309   _GFXGLTextureTargetDesc* mTex = static_cast<_GFXGLTextureTargetDesc*>(mTargets[slot].ptr());
310   if( (!tex && !mTex) || (mTex && mTex->getTextureObject() == tex) )
311      return;
312   
313   // Triggers an update when we next render
314   invalidateState();
315
316   // We stash the texture and info into an internal struct.
317   GFXGLTextureObject* glTexture = static_cast<GFXGLTextureObject*>(tex);
318   if(tex && tex != GFXTextureTarget::sDefaultDepthStencil)
319      mTargets[slot] = new _GFXGLTextureTargetDesc(glTexture, mipLevel, zOffset);
320   else
321      mTargets[slot] = NULL;
322}
323
324void GFXGLTextureTarget::attachTexture( RenderSlot slot, GFXCubemap *tex, U32 face, U32 mipLevel/*=0*/ )
325{
326   // No depth cubemaps, sorry
327   AssertFatal(slot != DepthStencil, "GFXGLTextureTarget::attachTexture (cube) - Cube depth textures not supported!");
328   if(slot == DepthStencil)
329      return;
330    
331   // Triggers an update when we next render
332   invalidateState();
333   
334   // We stash the texture and info into an internal struct.
335   GFXGLCubemap* glTexture = static_cast<GFXGLCubemap*>(tex);
336   if(tex)
337      mTargets[slot] = new _GFXGLCubemapTargetDesc(glTexture, face, mipLevel, 0);
338   else
339      mTargets[slot] = NULL;
340}
341
342void GFXGLTextureTarget::clearAttachments()
343{
344   deactivate();
345   for(S32 i=1; i<MaxRenderSlotId; i++)
346      attachTexture((RenderSlot)i, NULL);
347}
348
349void GFXGLTextureTarget::zombify()
350{
351   invalidateState();
352   
353   // Will be recreated in applyState
354   _impl = NULL;
355}
356
357void GFXGLTextureTarget::resurrect()
358{
359   // Dealt with when the target is next bound
360}
361
362void GFXGLTextureTarget::makeActive()
363{
364   _impl->makeActive();
365}
366
367void GFXGLTextureTarget::deactivate()
368{
369   _impl->finish();
370}
371
372void GFXGLTextureTarget::applyState()
373{
374   if(!isPendingState())
375      return;
376
377   // So we don't do this over and over again
378   stateApplied();
379   
380   if(_impl.isNull())
381      _impl = new _GFXGLTextureTargetFBOImpl(this);
382           
383   _impl->applyState();
384}
385
386_GFXGLTargetDesc* GFXGLTextureTarget::getTargetDesc(RenderSlot slot) const
387{
388   // This can only be called by our implementations, and then will not actually store the pointer so this is (almost) safe
389   return mTargets[slot].ptr();
390}
391
392void GFXGLTextureTarget::_onTextureEvent( GFXTexCallbackCode code )
393{
394   invalidateState();
395}
396
397const String GFXGLTextureTarget::describeSelf() const
398{
399   String ret = String::ToString("   Color0 Attachment: %i", mTargets[Color0].isValid() ? mTargets[Color0]->getHandle() : 0);
400   ret += String::ToString("   Depth Attachment: %i", mTargets[DepthStencil].isValid() ? mTargets[DepthStencil]->getHandle() : 0);
401   
402   return ret;
403}
404
405void GFXGLTextureTarget::resolve()
406{
407}
408
409void GFXGLTextureTarget::resolveTo(GFXTextureObject* obj)
410{
411   AssertFatal(dynamic_cast<GFXGLTextureObject*>(obj), "GFXGLTextureTarget::resolveTo - Incorrect type of texture, expected a GFXGLTextureObject");
412   GFXGLTextureObject* glTexture = static_cast<GFXGLTextureObject*>(obj);
413
414   if( GFXGL->mCapabilities.copyImage && mTargets[Color0]->isCompatible(glTexture) )
415   {
416      GLenum binding = mTargets[Color0]->getBinding();      
417      binding = (binding >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && binding <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z) ? GL_TEXTURE_CUBE_MAP : binding;
418      U32 srcStartDepth = binding == GL_TEXTURE_CUBE_MAP ? mTargets[Color0]->getBinding() - GL_TEXTURE_CUBE_MAP_POSITIVE_X : 0;
419      glCopyImageSubData(
420        mTargets[Color0]->getHandle(), binding, 0, 0, 0, srcStartDepth,
421        glTexture->getHandle(), glTexture->getBinding(), 0, 0, 0, 0,
422        mTargets[Color0]->getWidth(), mTargets[Color0]->getHeight(), 1);
423
424      return;
425   }
426
427   PRESERVE_FRAMEBUFFER();
428   
429   glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mCopyFboDst);
430   glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, glTexture->getBinding(), glTexture->getHandle(), 0);
431   
432   glBindFramebuffer(GL_READ_FRAMEBUFFER, mCopyFboSrc);
433   glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTargets[Color0]->getBinding(), mTargets[Color0]->getHandle(), 0);
434   
435   glBlitFramebuffer(0, 0, mTargets[Color0]->getWidth(), mTargets[Color0]->getHeight(),
436      0, 0, glTexture->getWidth(), glTexture->getHeight(), GL_COLOR_BUFFER_BIT, GL_NEAREST);
437}
438