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->getMipMapLevels() != 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   bool mGenMips;
141   
142   _GFXGLTextureTargetFBOImpl(GFXGLTextureTarget* target);
143   virtual ~_GFXGLTextureTargetFBOImpl();
144   
145   virtual void applyState();
146   virtual void makeActive();
147   virtual void finish();
148};
149
150_GFXGLTextureTargetFBOImpl::_GFXGLTextureTargetFBOImpl(GFXGLTextureTarget* target)
151{
152   mGenMips = target->isGenMipsEnabled();
153   mTarget = target;
154   glGenFramebuffers(1, &mFramebuffer);
155}
156
157_GFXGLTextureTargetFBOImpl::~_GFXGLTextureTargetFBOImpl()
158{
159   glDeleteFramebuffers(1, &mFramebuffer);
160}
161
162void _GFXGLTextureTargetFBOImpl::applyState()
163{   
164   // REMINDER: When we implement MRT support, check against GFXGLDevice::getNumRenderTargets()
165   
166   PRESERVE_FRAMEBUFFER();
167   glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
168   glEnable(GL_FRAMEBUFFER_SRGB);
169   bool drawbufs[16];
170   int bufsize = 0;
171   for (int i = 0; i < 16; i++)
172           drawbufs[i] = false;
173   bool hasColor = false;
174   for(int i = 0; i < GFXGL->getNumRenderTargets(); ++i)
175   {   
176      _GFXGLTargetDesc* color = mTarget->getTargetDesc( static_cast<GFXTextureTarget::RenderSlot>(GFXTextureTarget::Color0+i ));
177      if(color)
178      {
179         hasColor = true;
180         const GLenum binding = color->getBinding();
181         if( binding == GL_TEXTURE_2D || (binding >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && binding <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z) )
182            glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, color->getBinding( ), color->getHandle( ), color->getMipLevel( ) );
183         else if( binding == GL_TEXTURE_1D )
184            glFramebufferTexture1D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, color->getBinding( ), color->getHandle( ), color->getMipLevel( ) );
185         else if( binding == GL_TEXTURE_3D )
186            glFramebufferTexture3D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, color->getBinding( ), color->getHandle( ), color->getMipLevel( ), color->getZOffset( ) );
187         else
188             Con::errorf("_GFXGLTextureTargetFBOImpl::applyState - Bad binding");
189      }
190      else
191      {
192         // Clears the texture (note that the binding is irrelevent)
193         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0+i, GL_TEXTURE_2D, 0, 0);
194      }
195   }
196   
197   _GFXGLTargetDesc* depthStecil = mTarget->getTargetDesc(GFXTextureTarget::DepthStencil);
198   if(depthStecil)
199   {
200      // Certain drivers have issues with depth only FBOs.  That and the next two asserts assume we have a color target.
201      AssertFatal(hasColor, "GFXGLTextureTarget::applyState() - Cannot set DepthStencil target without Color0 target!");
202      glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, depthStecil->getBinding(), depthStecil->getHandle(), depthStecil->getMipLevel());
203   }
204   else
205   {
206      // Clears the texture (note that the binding is irrelevent)
207      glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
208   }
209
210   GLenum *buf = new GLenum[bufsize];
211   int count = 0;
212   for (int i = 0; i < bufsize; i++)
213   {
214           if (drawbufs[i])
215           {
216                   buf[count] = GL_COLOR_ATTACHMENT0 + i;
217                   count++;
218           }
219   }
220 
221   glDrawBuffers(bufsize, buf);
222 
223   delete[] buf;
224   CHECK_FRAMEBUFFER_STATUS();
225}
226
227void _GFXGLTextureTargetFBOImpl::makeActive()
228{
229    glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
230    GFXGL->getOpenglCache()->setCacheBinded(GL_FRAMEBUFFER, mFramebuffer);
231
232    int i = 0;
233    GLenum draws[16];
234    for( i = 0; i < GFXGL->getNumRenderTargets(); ++i)
235    {
236        _GFXGLTargetDesc* color = mTarget->getTargetDesc( static_cast<GFXTextureTarget::RenderSlot>(GFXTextureTarget::Color0+i ));
237        if(color)
238            draws[i] = GL_COLOR_ATTACHMENT0 + i;
239        else
240            break;
241    }
242
243    glDrawBuffers( i, draws );
244}
245
246void _GFXGLTextureTargetFBOImpl::finish()
247{
248   glBindFramebuffer(GL_FRAMEBUFFER, 0);
249   GFXGL->getOpenglCache()->setCacheBinded(GL_FRAMEBUFFER, 0);
250
251   if (!mGenMips)
252      return;
253
254   for(int i = 0; i < GFXGL->getNumRenderTargets(); ++i)
255   {   
256      _GFXGLTargetDesc* color = mTarget->getTargetDesc( static_cast<GFXTextureTarget::RenderSlot>(GFXTextureTarget::Color0+i ) );
257      if(!color || !(color->hasMips()))
258         continue;
259   
260      // Generate mips if necessary
261      // Assumes a 2D texture.
262      GLenum binding = color->getBinding();
263      binding = (binding >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && binding <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z) ? GL_TEXTURE_CUBE_MAP : binding;
264
265      PRESERVE_TEXTURE( binding );
266      glBindTexture( binding, color->getHandle() );
267      glGenerateMipmap( binding );
268   }
269}
270
271// Actual GFXGLTextureTarget interface
272GFXGLTextureTarget::GFXGLTextureTarget(bool genMips) : mCopyFboSrc(0), mCopyFboDst(0)
273{
274   mGenMips = genMips;
275   for(U32 i=0; i<MaxRenderSlotId; i++)
276      mTargets[i] = NULL;
277   
278   GFXTextureManager::addEventDelegate( this, &GFXGLTextureTarget::_onTextureEvent );
279
280   _impl = new _GFXGLTextureTargetFBOImpl(this);
281    
282   glGenFramebuffers(1, &mCopyFboSrc);
283   glGenFramebuffers(1, &mCopyFboDst);
284}
285
286GFXGLTextureTarget::~GFXGLTextureTarget()
287{
288   GFXTextureManager::removeEventDelegate(this, &GFXGLTextureTarget::_onTextureEvent);
289
290   glDeleteFramebuffers(1, &mCopyFboSrc);
291   glDeleteFramebuffers(1, &mCopyFboDst);
292}
293
294const Point2I GFXGLTextureTarget::getSize()
295{
296   if(mTargets[Color0].isValid())
297      return Point2I(mTargets[Color0]->getWidth(), mTargets[Color0]->getHeight());
298
299   return Point2I(0, 0);
300}
301
302GFXFormat GFXGLTextureTarget::getFormat()
303{
304   if(mTargets[Color0].isValid())
305      return mTargets[Color0]->getFormat();
306
307   return GFXFormatR8G8B8A8;
308}
309
310void GFXGLTextureTarget::attachTexture( RenderSlot slot, GFXTextureObject *tex, U32 mipLevel/*=0*/, U32 zOffset /*= 0*/ )
311{
312   if( tex == GFXTextureTarget::sDefaultDepthStencil )
313      tex = GFXGL->getDefaultDepthTex();
314
315   _GFXGLTextureTargetDesc* mTex = static_cast<_GFXGLTextureTargetDesc*>(mTargets[slot].ptr());
316   if( (!tex && !mTex) || (mTex && mTex->getTextureObject() == tex) )
317      return;
318   
319   // Triggers an update when we next render
320   invalidateState();
321
322   // We stash the texture and info into an internal struct.
323   GFXGLTextureObject* glTexture = static_cast<GFXGLTextureObject*>(tex);
324   if(tex && tex != GFXTextureTarget::sDefaultDepthStencil)
325      mTargets[slot] = new _GFXGLTextureTargetDesc(glTexture, mipLevel, zOffset);
326   else
327      mTargets[slot] = NULL;
328}
329
330void GFXGLTextureTarget::attachTexture( RenderSlot slot, GFXCubemap *tex, U32 face, U32 mipLevel/*=0*/ )
331{
332   // No depth cubemaps, sorry
333   AssertFatal(slot != DepthStencil, "GFXGLTextureTarget::attachTexture (cube) - Cube depth textures not supported!");
334   if(slot == DepthStencil)
335      return;
336    
337   // Triggers an update when we next render
338   invalidateState();
339   
340   // We stash the texture and info into an internal struct.
341   GFXGLCubemap* glTexture = static_cast<GFXGLCubemap*>(tex);
342   if(tex)
343      mTargets[slot] = new _GFXGLCubemapTargetDesc(glTexture, face, mipLevel, 0);
344   else
345      mTargets[slot] = NULL;
346}
347
348void GFXGLTextureTarget::clearAttachments()
349{
350   deactivate();
351   for(S32 i=1; i<MaxRenderSlotId; i++)
352      attachTexture((RenderSlot)i, NULL);
353}
354
355void GFXGLTextureTarget::zombify()
356{
357   invalidateState();
358   
359   // Will be recreated in applyState
360   _impl = NULL;
361}
362
363void GFXGLTextureTarget::resurrect()
364{
365   // Dealt with when the target is next bound
366}
367
368void GFXGLTextureTarget::makeActive()
369{
370   _impl->makeActive();
371}
372
373void GFXGLTextureTarget::deactivate()
374{
375   _impl->finish();
376}
377
378void GFXGLTextureTarget::applyState()
379{
380   if(!isPendingState())
381      return;
382
383   // So we don't do this over and over again
384   stateApplied();
385   
386   if(_impl.isNull())
387      _impl = new _GFXGLTextureTargetFBOImpl(this);
388           
389   _impl->applyState();
390}
391
392_GFXGLTargetDesc* GFXGLTextureTarget::getTargetDesc(RenderSlot slot) const
393{
394   // This can only be called by our implementations, and then will not actually store the pointer so this is (almost) safe
395   return mTargets[slot].ptr();
396}
397
398void GFXGLTextureTarget::_onTextureEvent( GFXTexCallbackCode code )
399{
400   invalidateState();
401}
402
403const String GFXGLTextureTarget::describeSelf() const
404{
405   String ret = String::ToString("   Color0 Attachment: %i", mTargets[Color0].isValid() ? mTargets[Color0]->getHandle() : 0);
406   ret += String::ToString("   Depth Attachment: %i", mTargets[DepthStencil].isValid() ? mTargets[DepthStencil]->getHandle() : 0);
407   
408   return ret;
409}
410
411void GFXGLTextureTarget::resolve()
412{
413}
414
415void GFXGLTextureTarget::resolveTo(GFXTextureObject* obj)
416{
417   AssertFatal(dynamic_cast<GFXGLTextureObject*>(obj), "GFXGLTextureTarget::resolveTo - Incorrect type of texture, expected a GFXGLTextureObject");
418   GFXGLTextureObject* glTexture = static_cast<GFXGLTextureObject*>(obj);
419
420   if( GFXGL->mCapabilities.copyImage && mTargets[Color0]->isCompatible(glTexture) )
421   {
422      GLenum binding = mTargets[Color0]->getBinding();      
423      binding = (binding >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && binding <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z) ? GL_TEXTURE_CUBE_MAP : binding;
424      U32 srcStartDepth = binding == GL_TEXTURE_CUBE_MAP ? mTargets[Color0]->getBinding() - GL_TEXTURE_CUBE_MAP_POSITIVE_X : 0;
425      glCopyImageSubData(
426        mTargets[Color0]->getHandle(), binding, 0, 0, 0, srcStartDepth,
427        glTexture->getHandle(), glTexture->getBinding(), 0, 0, 0, 0,
428        mTargets[Color0]->getWidth(), mTargets[Color0]->getHeight(), 1);
429
430      return;
431   }
432
433   PRESERVE_FRAMEBUFFER();
434   
435   glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mCopyFboDst);
436   glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, glTexture->getBinding(), glTexture->getHandle(), 0);
437   
438   glBindFramebuffer(GL_READ_FRAMEBUFFER, mCopyFboSrc);
439   glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTargets[Color0]->getBinding(), mTargets[Color0]->getHandle(), 0);
440   
441   glBlitFramebuffer(0, 0, mTargets[Color0]->getWidth(), mTargets[Color0]->getHeight(),
442      0, 0, glTexture->getWidth(), glTexture->getHeight(), GL_COLOR_BUFFER_BIT, GL_NEAREST);
443}
444