gfxGLTextureTarget.cpp
Engine/source/gfx/gl/gfxGLTextureTarget.cpp
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
