gfxGLTextureObject.cpp
Engine/source/gfx/gl/gfxGLTextureObject.cpp
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/tGL/tGL.h" 26#include "math/mRect.h" 27#include "gfx/gl/gfxGLTextureObject.h" 28#include "gfx/gfxDevice.h" 29#include "gfx/gl/gfxGLEnumTranslate.h" 30#include "gfx/gl/gfxGLTextureManager.h" 31#include "gfx/gl/gfxGLUtils.h" 32#include "gfx/gfxCardProfile.h" 33 34 35GFXGLTextureObject::GFXGLTextureObject(GFXDevice * aDevice, GFXTextureProfile *profile) : 36 GFXTextureObject(aDevice, profile), 37 mIsNPoT2(false), 38 mBinding(GL_TEXTURE_2D), 39 mBytesPerTexel(4), 40 mLockedRectRect(0, 0, 0, 0), 41 mGLDevice(static_cast<GFXGLDevice*>(mDevice)), 42 mIsZombie(false), 43 mZombieCache(NULL), 44 mNeedInitSamplerState(true), 45 mFrameAllocatorMark(0), 46 mFrameAllocatorPtr(NULL) 47{ 48 49#if TORQUE_DEBUG 50 mFrameAllocatorMarkGuard == FrameAllocator::getWaterMark(); 51#endif 52 53 dMemset(&mLockedRect, 0, sizeof(mLockedRect)); 54 55 AssertFatal(dynamic_cast<GFXGLDevice*>(mDevice), "GFXGLTextureObject::GFXGLTextureObject - Invalid device type, expected GFXGLDevice!"); 56 glGenTextures(1, &mHandle); 57 glGenBuffers(1, &mBuffer); 58} 59 60GFXGLTextureObject::~GFXGLTextureObject() 61{ 62 glDeleteTextures(1, &mHandle); 63 glDeleteBuffers(1, &mBuffer); 64 delete[] mZombieCache; 65 kill(); 66} 67 68GFXLockedRect* GFXGLTextureObject::lock(U32 mipLevel, RectI *inRect) 69{ 70 //AssertFatal(mBinding != GL_TEXTURE_3D, "GFXGLTextureObject::lock - We don't support locking 3D textures yet"); 71 U32 width = mTextureSize.x >> mipLevel; 72 U32 height = mTextureSize.y >> mipLevel; 73 74 if(inRect) 75 { 76 if((inRect->point.x + inRect->extent.x > width) || (inRect->point.y + inRect->extent.y > height)) 77 AssertFatal(false, "GFXGLTextureObject::lock - Rectangle too big!"); 78 79 mLockedRectRect = *inRect; 80 } 81 else 82 { 83 mLockedRectRect = RectI(0, 0, width, height); 84 } 85 86 mLockedRect.pitch = mLockedRectRect.extent.x * mBytesPerTexel; 87 88 // CodeReview [ags 12/19/07] This one texel boundary is necessary to keep the clipmap code from crashing. Figure out why. 89 U32 size = (mLockedRectRect.extent.x + 1) * (mLockedRectRect.extent.y + 1) * getDepth() * mBytesPerTexel; 90 AssertFatal(!mFrameAllocatorMark && !mFrameAllocatorPtr, ""); 91 mFrameAllocatorMark = FrameAllocator::getWaterMark(); 92 mFrameAllocatorPtr = (U8*)FrameAllocator::alloc( size ); 93 mLockedRect.bits = mFrameAllocatorPtr; 94#if TORQUE_DEBUG 95 mFrameAllocatorMarkGuard = FrameAllocator::getWaterMark(); 96#endif 97 98 if( !mLockedRect.bits ) 99 return NULL; 100 101 return &mLockedRect; 102} 103 104void GFXGLTextureObject::unlock(U32 mipLevel) 105{ 106 if(!mLockedRect.bits) 107 return; 108 109 // I know this is in unlock, but in GL we actually do our submission in unlock. 110 PROFILE_SCOPE(GFXGLTextureObject_lockRT); 111 112 PRESERVE_TEXTURE(mBinding); 113 glBindTexture(mBinding, mHandle); 114 glBindBuffer(GL_PIXEL_UNPACK_BUFFER, mBuffer); 115 glBufferData(GL_PIXEL_UNPACK_BUFFER, (mLockedRectRect.extent.x + 1) * (mLockedRectRect.extent.y + 1) * mBytesPerTexel, mFrameAllocatorPtr, GL_STREAM_DRAW); 116 S32 z = getDepth(); 117 if (mBinding == GL_TEXTURE_3D) 118 glTexSubImage3D(mBinding, mipLevel, mLockedRectRect.point.x, mLockedRectRect.point.y, z, 119 mLockedRectRect.extent.x, mLockedRectRect.extent.y, z, GFXGLTextureFormat[mFormat], GFXGLTextureType[mFormat], NULL); 120 else if(mBinding == GL_TEXTURE_2D) 121 glTexSubImage2D(mBinding, mipLevel, mLockedRectRect.point.x, mLockedRectRect.point.y, 122 mLockedRectRect.extent.x, mLockedRectRect.extent.y, GFXGLTextureFormat[mFormat], GFXGLTextureType[mFormat], NULL); 123 else if(mBinding == GL_TEXTURE_1D) 124 glTexSubImage1D(mBinding, mipLevel, (mLockedRectRect.point.x > 1 ? mLockedRectRect.point.x : mLockedRectRect.point.y), 125 (mLockedRectRect.extent.x > 1 ? mLockedRectRect.extent.x : mLockedRectRect.extent.y), GFXGLTextureFormat[mFormat], GFXGLTextureType[mFormat], NULL); 126 127 glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); 128 129 mLockedRect.bits = NULL; 130#if TORQUE_DEBUG 131 AssertFatal(mFrameAllocatorMarkGuard == FrameAllocator::getWaterMark(), ""); 132#endif 133 FrameAllocator::setWaterMark(mFrameAllocatorMark); 134 mFrameAllocatorMark = 0; 135 mFrameAllocatorPtr = NULL; 136} 137 138void GFXGLTextureObject::release() 139{ 140 glDeleteTextures(1, &mHandle); 141 glDeleteBuffers(1, &mBuffer); 142 143 mHandle = 0; 144 mBuffer = 0; 145} 146 147void GFXGLTextureObject::reInit() 148{ 149 AssertFatal(!mHandle && !mBuffer,"Must release before reInit"); 150 glGenTextures(1, &mHandle); 151 glGenBuffers(1, &mBuffer); 152} 153 154bool GFXGLTextureObject::copyToBmp(GBitmap * bmp) 155{ 156 if (!bmp) 157 return false; 158 159 // check format limitations 160 // at the moment we only support RGBA for the source (other 4 byte formats should 161 // be easy to add though) 162 AssertFatal(mFormat == GFXFormatR16G16B16A16F || mFormat == GFXFormatR8G8B8A8 || mFormat == GFXFormatR8G8B8A8_LINEAR_FORCE || mFormat == GFXFormatR8G8B8A8_SRGB, "copyToBmp: invalid format"); 163 if (mFormat != GFXFormatR16G16B16A16F && mFormat != GFXFormatR8G8B8A8 && mFormat != GFXFormatR8G8B8A8_LINEAR_FORCE && mFormat != GFXFormatR8G8B8A8_SRGB) 164 return false; 165 166 AssertFatal(bmp->getWidth() == getWidth(), "GFXGLTextureObject::copyToBmp - invalid size"); 167 AssertFatal(bmp->getHeight() == getHeight(), "GFXGLTextureObject::copyToBmp - invalid size"); 168 169 PROFILE_SCOPE(GFXGLTextureObject_copyToBmp); 170 171 PRESERVE_TEXTURE(mBinding); 172 glBindTexture(mBinding, mHandle); 173 174 U8 dstBytesPerPixel = GFXFormat_getByteSize( bmp->getFormat() ); 175 U8 srcBytesPerPixel = GFXFormat_getByteSize( mFormat ); 176 177 FrameAllocatorMarker mem; 178 179 180 U32 mipLevels = getMipLevels(); 181 for (U32 mip = 0; mip < mipLevels; mip++) 182 { 183 U32 srcPixelCount = bmp->getSurfaceSize(mip)/ srcBytesPerPixel; 184 185 U8* dest = bmp->getWritableBits(mip); 186 U8* orig = (U8*)mem.alloc(srcPixelCount * srcBytesPerPixel); 187 188 glGetTexImage(mBinding, mip, GFXGLTextureFormat[mFormat], GFXGLTextureType[mFormat], orig); 189 if (mFormat == GFXFormatR16G16B16A16F) 190 { 191 dMemcpy(dest, orig, srcPixelCount * srcBytesPerPixel); 192 } 193 else 194 { 195 for (int i = 0; i < srcPixelCount; ++i) 196 { 197 dest[0] = orig[0]; 198 dest[1] = orig[1]; 199 dest[2] = orig[2]; 200 if (dstBytesPerPixel == 4) 201 dest[3] = orig[3]; 202 203 orig += srcBytesPerPixel; 204 dest += dstBytesPerPixel; 205 } 206 } 207 } 208 glBindTexture(mBinding, NULL); 209 210 return true; 211} 212 213void GFXGLTextureObject::initSamplerState(const GFXSamplerStateDesc &ssd) 214{ 215 glTexParameteri(mBinding, GL_TEXTURE_MIN_FILTER, minificationFilter(ssd.minFilter, ssd.mipFilter, mMipLevels)); 216 glTexParameteri(mBinding, GL_TEXTURE_MAG_FILTER, GFXGLTextureFilter[ssd.magFilter]); 217 glTexParameteri(mBinding, GL_TEXTURE_WRAP_S, !mIsNPoT2 ? GFXGLTextureAddress[ssd.addressModeU] : GL_CLAMP_TO_EDGE); 218 glTexParameteri(mBinding, GL_TEXTURE_WRAP_T, !mIsNPoT2 ? GFXGLTextureAddress[ssd.addressModeV] : GL_CLAMP_TO_EDGE); 219 if(mBinding == GL_TEXTURE_3D) 220 glTexParameteri(mBinding, GL_TEXTURE_WRAP_R, GFXGLTextureAddress[ssd.addressModeW]); 221 if(static_cast< GFXGLDevice* >( GFX )->supportsAnisotropic() ) 222 glTexParameterf(mBinding, GL_TEXTURE_MAX_ANISOTROPY_EXT, ssd.maxAnisotropy); 223 224 mNeedInitSamplerState = false; 225 mSampler = ssd; 226} 227 228void GFXGLTextureObject::bind(U32 textureUnit) 229{ 230 glActiveTexture(GL_TEXTURE0 + textureUnit); 231 glBindTexture(mBinding, mHandle); 232 GFXGL->getOpenglCache()->setCacheBindedTex(textureUnit, mBinding, mHandle); 233} 234 235U8* GFXGLTextureObject::getTextureData( U32 mip ) 236{ 237 AssertFatal( mMipLevels, ""); 238 mip = (mip < mMipLevels) ? mip : 0; 239 240 const U32 dataSize = ImageUtil::isCompressedFormat(mFormat) 241 ? getCompressedSurfaceSize( mFormat, mTextureSize.x, mTextureSize.y, mip ) 242 : (mTextureSize.x >> mip) * (mTextureSize.y >> mip) * mBytesPerTexel; 243 244 U8* data = new U8[dataSize]; 245 PRESERVE_TEXTURE(mBinding); 246 glBindTexture(mBinding, mHandle); 247 248 if( ImageUtil::isCompressedFormat(mFormat) ) 249 glGetCompressedTexImage( mBinding, mip, data ); 250 else 251 glGetTexImage(mBinding, mip, GFXGLTextureFormat[mFormat], GFXGLTextureType[mFormat], data); 252 return data; 253} 254 255void GFXGLTextureObject::copyIntoCache() 256{ 257 PRESERVE_TEXTURE(mBinding); 258 glBindTexture(mBinding, mHandle); 259 U32 cacheSize = mTextureSize.x * mTextureSize.y; 260 if(mBinding == GL_TEXTURE_3D) 261 cacheSize *= mTextureSize.z; 262 263 cacheSize *= mBytesPerTexel; 264 mZombieCache = new U8[cacheSize]; 265 266 glGetTexImage(mBinding, 0, GFXGLTextureFormat[mFormat], GFXGLTextureType[mFormat], mZombieCache); 267} 268 269void GFXGLTextureObject::reloadFromCache() 270{ 271 if(!mZombieCache) 272 return; 273 274 if(mBinding == GL_TEXTURE_3D) 275 { 276 static_cast<GFXGLTextureManager*>(TEXMGR)->_loadTexture(this, mZombieCache); 277 delete[] mZombieCache; 278 mZombieCache = NULL; 279 return; 280 } 281 282 PRESERVE_TEXTURE(mBinding); 283 glBindTexture(mBinding, mHandle); 284 285 if(mBinding == GL_TEXTURE_2D) 286 glTexSubImage2D(mBinding, 0, 0, 0, mTextureSize.x, mTextureSize.y, GFXGLTextureFormat[mFormat], GFXGLTextureType[mFormat], mZombieCache); 287 else if(mBinding == GL_TEXTURE_1D) 288 glTexSubImage1D(mBinding, 0, 0, (mTextureSize.x > 1 ? mTextureSize.x : mTextureSize.y), GFXGLTextureFormat[mFormat], GFXGLTextureType[mFormat], mZombieCache); 289 290 if(mMipLevels != 1) 291 glGenerateMipmap(mBinding); 292 293 delete[] mZombieCache; 294 mZombieCache = NULL; 295 mIsZombie = false; 296} 297 298void GFXGLTextureObject::zombify() 299{ 300 if(mIsZombie) 301 return; 302 303 mIsZombie = true; 304 if(!mProfile->doStoreBitmap() && !mProfile->isRenderTarget() && !mProfile->isDynamic() && !mProfile->isZTarget()) 305 copyIntoCache(); 306 307 release(); 308} 309 310void GFXGLTextureObject::resurrect() 311{ 312 if(!mIsZombie) 313 return; 314 315 glGenTextures(1, &mHandle); 316 glGenBuffers(1, &mBuffer); 317} 318 319F32 GFXGLTextureObject::getMaxUCoord() const 320{ 321 return mBinding == GL_TEXTURE_2D ? 1.0f : (F32)getWidth(); 322} 323 324F32 GFXGLTextureObject::getMaxVCoord() const 325{ 326 return mBinding == GL_TEXTURE_2D ? 1.0f : (F32)getHeight(); 327} 328 329const String GFXGLTextureObject::describeSelf() const 330{ 331 String ret = Parent::describeSelf(); 332 ret += String::ToString(" GL Handle: %i", mHandle); 333 334 return ret; 335} 336