Update GFXTextureManager and GBitmap

GBitmap Changes:
Added all other formats to gbitmap that we support
gbitmap now supports cubemaps
added converters for all these other formats
added stb_image_resize for extrudemips so we can extrude mipmaps for all other formats

GFXTextureManager
Can now directly make cubemaps and texture arrays based on the GFXTextureProfile
API implementations for all functions that cubemaps and arrays needed
This commit is contained in:
marauder2k7 2025-12-22 10:29:01 +00:00
parent 975fc924cc
commit 3aef90a6bc
66 changed files with 4235 additions and 2590 deletions

View file

@ -55,6 +55,7 @@ GFXTextureObject *GFXGLTextureManager::_createTextureObject( U32 height,
U32 numMipLevels,
bool forceMips,
S32 antialiasLevel,
U32 arraySize,
GFXTextureObject *inTex )
{
AssertFatal(format >= 0 && format < GFXFormat_COUNT, "GFXGLTextureManager::_createTexture - invalid format!");
@ -73,7 +74,7 @@ GFXTextureObject *GFXGLTextureManager::_createTextureObject( U32 height,
retTex->registerResourceWithDevice( GFX );
}
innerCreateTexture(retTex, height, width, depth, format, profile, numMipLevels, forceMips);
innerCreateTexture(retTex, height, width, depth, format, profile, numMipLevels, forceMips, arraySize);
return retTex;
}
@ -89,19 +90,40 @@ void GFXGLTextureManager::innerCreateTexture( GFXGLTextureObject *retTex,
GFXFormat format,
GFXTextureProfile *profile,
U32 numMipLevels,
bool forceMips)
bool forceMips,
U32 arraySize)
{
// No 24 bit formats. They trigger various oddities because hardware (and Apple's drivers apparently...) don't natively support them.
if (format == GFXFormatR8G8B8)
format = GFXFormatR8G8B8A8;
else if (format == GFXFormatR8G8B8_SRGB)
format = GFXFormatR8G8B8A8_SRGB;
retTex->mProfile = profile;
retTex->mFormat = format;
retTex->mIsZombie = false;
retTex->mIsNPoT2 = false;
GLenum binding = ( (height == 1 || width == 1) && ( height != width ) ) ? GL_TEXTURE_1D : ( (depth == 0) ? GL_TEXTURE_2D : GL_TEXTURE_3D );
const bool isCube = profile->isCubeMap();
GLenum binding;
if (isCube)
{
binding = (arraySize > 1) ? GL_TEXTURE_CUBE_MAP_ARRAY : GL_TEXTURE_CUBE_MAP;
}
else
{
const bool is3D = (depth > 1);
const bool is1D = (height == 1 && width > 1);
if (is3D)
binding = GL_TEXTURE_3D;
else if (is1D)
binding = (arraySize > 1) ? GL_TEXTURE_1D_ARRAY : GL_TEXTURE_1D;
else
binding = (arraySize > 1) ? GL_TEXTURE_2D_ARRAY : GL_TEXTURE_2D;
}
if((profile->testFlag(GFXTextureProfile::RenderTarget) || profile->testFlag(GFXTextureProfile::ZTarget)) && (!isPow2(width) || !isPow2(height)) && !depth)
retTex->mIsNPoT2 = true;
retTex->mBinding = binding;
@ -155,55 +177,155 @@ void GFXGLTextureManager::innerCreateTexture( GFXGLTextureObject *retTex,
retTex->mMipLevels = getMaxMipmaps(width, height, 1);
glTexParameteri(binding, GL_TEXTURE_MAX_LEVEL, retTex->mMipLevels-1 );
if( GFXGL->mCapabilities.textureStorage )
bool hasTexStorage = false;
// not supported when creating these.
if (arraySize > 1 || isCube || profile->isDynamic())
hasTexStorage = false;
const bool isCompressed = ImageUtil::isCompressedFormat(format);
// --- Allocation by binding ---
if (binding == GL_TEXTURE_CUBE_MAP)
{
if(binding == GL_TEXTURE_2D)
glTexStorage2D( retTex->getBinding(), retTex->mMipLevels, GFXGLTextureInternalFormat[format], width, height );
else if(binding == GL_TEXTURE_1D)
glTexStorage1D( retTex->getBinding(), retTex->mMipLevels, GFXGLTextureInternalFormat[format], getMax(width, height) );
else
glTexStorage3D( retTex->getBinding(), retTex->mMipLevels, GFXGLTextureInternalFormat[format], width, height, depth );
// Single cubemap: prefer glTexStorage2D if available, else per-face texImage2D
if (hasTexStorage)
{
// Some drivers accept texStorage2D with GL_TEXTURE_CUBE_MAP
glTexStorage2D(GL_TEXTURE_CUBE_MAP, retTex->mMipLevels, GFXGLTextureInternalFormat[format], width, height);
}
else
{
// Explicitly allocate each face/level
for (U32 face = 0; face < 6; ++face)
{
for (U32 mip = 0; mip < retTex->mMipLevels; ++mip)
{
U32 mipW = getMax(1u, width >> mip);
U32 mipH = getMax(1u, height >> mip);
if (isCompressed)
{
U32 size = getCompressedSurfaceSize(format, width, height, mip);
glCompressedTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, mip, GFXGLTextureInternalFormat[format], mipW, mipH, 0, size, nullptr);
}
else
{
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, mip, GFXGLTextureInternalFormat[format], mipW, mipH, 0, GFXGLTextureFormat[format], GFXGLTextureType[format], nullptr);
}
}
}
}
}
else
else if (binding == GL_TEXTURE_CUBE_MAP_ARRAY)
{
//If it wasn't for problems on amd drivers this next part could be really simplified and we wouldn't need to go through manually creating our
//mipmap pyramid and instead just use glGenerateMipmap
if(ImageUtil::isCompressedFormat(format))
{
AssertFatal(binding == GL_TEXTURE_2D,
"GFXGLTextureManager::innerCreateTexture - Only compressed 2D textures are supported");
U32 tempWidth = width;
U32 tempHeight = height;
U32 size = getCompressedSurfaceSize(format,height,width);
//Fill compressed images with 0's
U8 *pTemp = (U8*)dMalloc(sizeof(U8)*size);
dMemset(pTemp,0,size);
for(U32 i=0;i< retTex->mMipLevels;i++)
{
tempWidth = getMax( U32(1), width >> i );
tempHeight = getMax( U32(1), height >> i );
size = getCompressedSurfaceSize(format,width,height,i);
glCompressedTexImage2D(binding,i,GFXGLTextureInternalFormat[format],tempWidth,tempHeight,0,size,pTemp);
}
dFree(pTemp);
}
else
{
if(binding == GL_TEXTURE_2D)
glTexImage2D(binding, 0, GFXGLTextureInternalFormat[format], width, height, 0, GFXGLTextureFormat[format], GFXGLTextureType[format], NULL);
else if(binding == GL_TEXTURE_1D)
glTexImage1D(binding, 0, GFXGLTextureInternalFormat[format], (width > 1 ? width : height), 0, GFXGLTextureFormat[format], GFXGLTextureType[format], NULL);
else
glTexImage3D(GL_TEXTURE_3D, 0, GFXGLTextureInternalFormat[format], width, height, depth, 0, GFXGLTextureFormat[format], GFXGLTextureType[format], NULL);
if(retTex->mMipLevels > 1)
glGenerateMipmap(binding);
}
// cube-map array: layers = arraySize * 6
U32 layers = getMax(1u, arraySize) * 6u;
if (hasTexStorage)
{
glTexStorage3D(GL_TEXTURE_CUBE_MAP_ARRAY, retTex->mMipLevels, GFXGLTextureInternalFormat[format], width, height, layers);
}
else
{
// fallback to glTexImage3D with NULL data
for (U32 mip = 0; mip < retTex->mMipLevels; ++mip)
{
U32 mipW = getMax(1u, width >> mip);
U32 mipH = getMax(1u, height >> mip);
glTexImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, mip, GFXGLTextureInternalFormat[format], mipW, mipH, layers, 0, GFXGLTextureFormat[format], GFXGLTextureType[format], NULL);
}
}
}
else if (binding == GL_TEXTURE_2D_ARRAY)
{
// 2D texture array: depth = arraySize (layers)
U32 layers = getMax(1u, arraySize);
if (hasTexStorage)
{
glTexStorage3D(GL_TEXTURE_2D_ARRAY, retTex->mMipLevels, GFXGLTextureInternalFormat[format], width, height, layers);
}
else
{
for (U32 mip = 0; mip < retTex->mMipLevels; ++mip)
{
U32 mipW = getMax(1u, width >> mip);
U32 mipH = getMax(1u, height >> mip);
glTexImage3D(GL_TEXTURE_2D_ARRAY, mip, GFXGLTextureInternalFormat[format], mipW, mipH, layers, 0, GFXGLTextureFormat[format], GFXGLTextureType[format], NULL);
}
}
}
else if (binding == GL_TEXTURE_1D_ARRAY)
{
// 1D array stored as GL_TEXTURE_1D_ARRAY. glTexStorage2D can be used for 1D arrays with height=layers on many drivers.
U32 layers = getMax(1u, arraySize);
if (hasTexStorage)
{
// glTexStorage2D works for GL_TEXTURE_1D_ARRAY (width, layers)
glTexStorage2D(GL_TEXTURE_1D_ARRAY, retTex->mMipLevels, GFXGLTextureInternalFormat[format], getMax(width, height), layers);
}
else
{
// fallback: allocate as 2D where the "height" dimension is layers via glTexImage2D? Not ideal.
// Safer: use glTexImage2D with target GL_TEXTURE_1D_ARRAY is invalid; instead use glTexImage3D with depth=layers
for (U32 mip = 0; mip < retTex->mMipLevels; ++mip)
{
U32 mipW = getMax(1u, getMax(width, height) >> mip);
glTexImage3D(GL_TEXTURE_1D_ARRAY, mip, GFXGLTextureInternalFormat[format], mipW, layers, 1, 0, GFXGLTextureFormat[format], GFXGLTextureType[format], NULL);
}
}
}
else if (binding == GL_TEXTURE_1D)
{
if (hasTexStorage)
glTexStorage1D(GL_TEXTURE_1D, retTex->mMipLevels, GFXGLTextureInternalFormat[format], getMax(width, height));
else
{
for (U32 mip = 0; mip < retTex->mMipLevels; ++mip)
{
U32 mipW = getMax(1u, getMax(width, height) >> mip);
glTexImage1D(GL_TEXTURE_1D, mip, GFXGLTextureInternalFormat[format], mipW, 0, GFXGLTextureFormat[format], GFXGLTextureType[format], NULL);
}
}
}
else if (binding == GL_TEXTURE_3D)
{
if (hasTexStorage)
glTexStorage3D(GL_TEXTURE_3D, retTex->mMipLevels, GFXGLTextureInternalFormat[format], width, height, depth);
else
{
for (U32 mip = 0; mip < retTex->mMipLevels; ++mip)
{
U32 mipW = getMax(1u, width >> mip);
U32 mipH = getMax(1u, height >> mip);
U32 mipD = getMax(1u, depth >> mip);
glTexImage3D(GL_TEXTURE_3D, mip, GFXGLTextureInternalFormat[format], mipW, mipH, mipD, 0, GFXGLTextureFormat[format], GFXGLTextureType[format], NULL);
}
}
}
else // GL_TEXTURE_2D (default)
{
if (hasTexStorage)
glTexStorage2D(GL_TEXTURE_2D, retTex->mMipLevels, GFXGLTextureInternalFormat[format], width, height);
else
{
for (U32 mip = 0; mip < retTex->mMipLevels; ++mip)
{
U32 mipW = getMax(1u, width >> mip);
U32 mipH = getMax(1u, height >> mip);
if (isCompressed)
{
U32 size = getCompressedSurfaceSize(format, width, height, mip);
glCompressedTexImage2D(GL_TEXTURE_2D, mip, GFXGLTextureInternalFormat[format], mipW, mipH, 0, size, nullptr);
}
else
{
glTexImage2D(GL_TEXTURE_2D, mip, GFXGLTextureInternalFormat[format], mipW, mipH, 0, GFXGLTextureFormat[format], GFXGLTextureType[format], NULL);
}
}
}
}
// Complete the texture
// Complete the texture - this does get changed later but we need to complete the texture anyway
@ -221,14 +343,20 @@ void GFXGLTextureManager::innerCreateTexture( GFXGLTextureObject *retTex,
if(GFXGLTextureSwizzle[format])
glTexParameteriv(binding, GL_TEXTURE_SWIZZLE_RGBA, GFXGLTextureSwizzle[format]);
// Get the size from GL (you never know...)
GLint texHeight, texWidth, texDepth = 0;
glGetTexLevelParameteriv(binding, 0, GL_TEXTURE_WIDTH, &texWidth);
glGetTexLevelParameteriv(binding, 0, GL_TEXTURE_HEIGHT, &texHeight);
if(binding == GL_TEXTURE_3D)
glGetTexLevelParameteriv(binding, 0, GL_TEXTURE_DEPTH, &texDepth);
GLint texHeight = 0, texWidth = 0, texDepth = 0;
GLenum queryTarget = binding;
if (binding == GL_TEXTURE_CUBE_MAP)
{
// Query a specific face, e.g. +X
queryTarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X;
}
glGetTexLevelParameteriv(queryTarget, 0, GL_TEXTURE_WIDTH, &texWidth);
glGetTexLevelParameteriv(queryTarget, 0, GL_TEXTURE_HEIGHT, &texHeight);
if (binding == GL_TEXTURE_3D)
glGetTexLevelParameteriv(GL_TEXTURE_3D, 0, GL_TEXTURE_DEPTH, &texDepth);
retTex->mTextureSize.set(texWidth, texHeight, texDepth);
}
@ -236,7 +364,7 @@ void GFXGLTextureManager::innerCreateTexture( GFXGLTextureObject *retTex,
// loadTexture - GBitmap
//-----------------------------------------------------------------------------
static void _textureUpload(const S32 width, const S32 height,const S32 bytesPerPixel,const GFXGLTextureObject* texture, const GFXFormat fmt, const U8* data,const S32 mip=0, Swizzle<U8, 4> *pSwizzle = NULL)
static void _textureUpload(const S32 width, const S32 height,const S32 bytesPerPixel,const GFXGLTextureObject* texture, const GFXFormat fmt, const U8* data,const S32 mip=0, const U32 face = 0, Swizzle<U8, 4> *pSwizzle = NULL)
{
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, texture->getBuffer());
U32 bufSize = width * height * bytesPerPixel;
@ -256,7 +384,9 @@ static void _textureUpload(const S32 width, const S32 height,const S32 bytesPerP
glBufferSubData(GL_PIXEL_UNPACK_BUFFER, 0, bufSize, data);
}
if (texture->getBinding() == GL_TEXTURE_2D)
if(texture->getBinding() == GL_TEXTURE_CUBE_MAP)
glTexSubImage2D(GFXGLFaceType[face], mip, 0, 0, width, height, GFXGLTextureFormat[fmt], GFXGLTextureType[fmt], NULL);
else if (texture->getBinding() == GL_TEXTURE_2D)
glTexSubImage2D(texture->getBinding(), mip, 0, 0, width, height, GFXGLTextureFormat[fmt], GFXGLTextureType[fmt], NULL);
else
glTexSubImage1D(texture->getBinding(), mip, 0, (width > 1 ? width : height), GFXGLTextureFormat[fmt], GFXGLTextureType[fmt], NULL);
@ -266,76 +396,125 @@ static void _textureUpload(const S32 width, const S32 height,const S32 bytesPerP
bool GFXGLTextureManager::_loadTexture(GFXTextureObject *aTexture, GBitmap *pDL)
{
PROFILE_SCOPE(GFXGLTextureManager_loadTexture);
PROFILE_SCOPE(GFXGLTextureManager_loadTextureGBitmap);
GFXGLTextureObject *texture = static_cast<GFXGLTextureObject*>(aTexture);
AssertFatal(texture->getBinding() == GL_TEXTURE_1D || texture->getBinding() == GL_TEXTURE_2D,
"GFXGLTextureManager::_loadTexture(GBitmap) - This method can only be used with 1D/2D textures");
const GLenum target = texture->getBinding();
AssertFatal(target == GL_TEXTURE_1D || target == GL_TEXTURE_2D || target == GL_TEXTURE_CUBE_MAP,
"GFXGLTextureManager::_loadTexture(GBitmap) - This method can only be used with 1D/2D and CubeMap textures");
if(texture->getBinding() == GL_TEXTURE_3D)
return false;
// No 24bit formats.
if(pDL->getFormat() == GFXFormatR8G8B8)
pDL->setFormat(GFXFormatR8G8B8A8);
else if (pDL->getFormat() == GFXFormatR8G8B8_SRGB)
pDL->setFormat(GFXFormatR8G8B8A8_SRGB);
//
//// No 24bit formats.
//if(pDL->getFormat() == GFXFormatR8G8B8)
// pDL->setFormat(GFXFormatR8G8B8A8);
//else if (pDL->getFormat() == GFXFormatR8G8B8_SRGB)
// pDL->setFormat(GFXFormatR8G8B8A8_SRGB);
// Bind to edit
PRESERVE_TEXTURE(texture->getBinding());
glBindTexture(texture->getBinding(), texture->getHandle());
_textureUpload(pDL->getWidth(),pDL->getHeight(),pDL->getBytesPerPixel(),texture,pDL->getFormat(), pDL->getBits(), 0);
const U32 mipLevels = texture->getMipLevels();
const bool isCubemap = (target == GL_TEXTURE_CUBE_MAP) && pDL->getNumFaces() > 1;
U32 faceCount = isCubemap ? 6 : 1;
if(!ImageUtil::isCompressedFormat(pDL->getFormat()))
glGenerateMipmap(texture->getBinding());
for (U32 mip = 0; mip < mipLevels; mip++)
{
const GLsizei width = getMax(1u, pDL->getWidth(mip));
const GLsizei height = getMax(1u, pDL->getHeight(mip));
for (U32 face = 0; face < faceCount; ++face)
{
_textureUpload(width, height, pDL->getBytesPerPixel(), texture, pDL->getFormat(), pDL->getBits(mip,face), mip, face);
}
}
if(!ImageUtil::isCompressedFormat(pDL->getFormat()))
glGenerateMipmap(texture->getBinding());
glBindTexture(target, 0);
return true;
}
bool GFXGLTextureManager::_loadTexture(GFXTextureObject *aTexture, DDSFile *dds)
{
PROFILE_SCOPE(GFXGLTextureManager_loadTextureDDS);
GFXGLTextureObject* texture = static_cast<GFXGLTextureObject*>(aTexture);
AssertFatal(texture->getBinding() == GL_TEXTURE_2D,
"GFXGLTextureManager::_loadTexture(DDSFile) - This method can only be used with 2D textures");
if(texture->getBinding() != GL_TEXTURE_2D)
return false;
PRESERVE_TEXTURE(texture->getBinding());
glBindTexture(texture->getBinding(), texture->getHandle());
U32 numMips = dds->mSurfaces[0]->mMips.size();
const GLenum target = texture->getBinding();
const bool isCube = texture->getBinding() == GL_TEXTURE_CUBE_MAP && dds->isCubemap();
const bool isCompressed = ImageUtil::isCompressedFormat(texture->mFormat);
AssertFatal(target == GL_TEXTURE_1D || target == GL_TEXTURE_2D || target == GL_TEXTURE_CUBE_MAP,
"GFXGLTextureManager::_loadTexture(DDS) - This method can only be used with 1D/2D and CubeMap textures");
if (texture->getBinding() == GL_TEXTURE_3D)
return false;
PRESERVE_TEXTURE(target);
glBindTexture(target, texture->getHandle());
const U32 numFaces = isCube ? 6 : 1;
const U32 numMips = dds->mSurfaces[0]->mMips.size();
const GFXFormat fmt = texture->mFormat;
for(U32 i = 0; i < numMips; i++)
for (U32 face = 0; face < numFaces; ++face)
{
PROFILE_SCOPE(GFXGLTexMan_loadSurface);
// Skip empty surfaces
if (!dds->mSurfaces[face])
continue;
if(ImageUtil::isCompressedFormat(texture->mFormat))
for (U32 mip = 0; mip < numMips; ++mip)
{
if((!isPow2(dds->getWidth()) || !isPow2(dds->getHeight())) && GFX->getCardProfiler()->queryProfile("GL::Workaround::noCompressedNPoTTextures"))
const U32 mipWidth = getMax(1u, dds->getWidth(mip));
const U32 mipHeight = getMax(1u, dds->getHeight(mip));
GLenum uploadTarget = target;
if (isCube)
uploadTarget = GFXGLFaceType[face];
if (isCompressed)
{
U8* uncompressedTex = new U8[dds->getWidth(i) * dds->getHeight(i) * 4];
ImageUtil::decompress(dds->mSurfaces[0]->mMips[i],uncompressedTex, dds->getWidth(i), dds->getHeight(i), fmt);
glTexSubImage2D(texture->getBinding(), i, 0, 0, dds->getWidth(i), dds->getHeight(i), GL_RGBA, GL_UNSIGNED_BYTE, uncompressedTex);
delete[] uncompressedTex;
// Handle NPOT workaround
if ((!isPow2(mipWidth) || !isPow2(mipHeight)) && GFX->getCardProfiler()->queryProfile("GL::Workaround::noCompressedNPoTTextures"))
{
U8* uncompressedTex = new U8[mipWidth * mipHeight * 4];
ImageUtil::decompress(dds->mSurfaces[face]->mMips[mip], uncompressedTex, mipWidth, mipHeight, fmt);
glTexSubImage2D(uploadTarget,
mip, 0, 0, mipWidth, mipHeight, GL_RGBA, GL_UNSIGNED_BYTE, uncompressedTex
);
delete[] uncompressedTex;
}
else
{
glCompressedTexImage2D(uploadTarget,
mip, GFXGLTextureInternalFormat[fmt], mipWidth, mipHeight, 0,
dds->getSurfaceSize(mip), dds->mSurfaces[face]->mMips[mip]
);
}
}
else
glCompressedTexSubImage2D(texture->getBinding(), i, 0, 0, dds->getWidth(i), dds->getHeight(i), GFXGLTextureInternalFormat[fmt], dds->getSurfaceSize(dds->getHeight(), dds->getWidth(), i), dds->mSurfaces[0]->mMips[i]);
}
else
{
Swizzle<U8, 4> *pSwizzle = NULL;
if (fmt == GFXFormatR8G8B8A8 || fmt == GFXFormatR8G8B8X8 || fmt == GFXFormatR8G8B8A8_SRGB || fmt == GFXFormatR8G8B8A8_LINEAR_FORCE || fmt == GFXFormatB8G8R8A8)
pSwizzle = &Swizzles::bgra;
{
Swizzle<U8, 4>* pSwizzle = nullptr;
if (fmt == GFXFormatR8G8B8A8 || fmt == GFXFormatR8G8B8X8 || fmt == GFXFormatR8G8B8A8_SRGB ||
fmt == GFXFormatR8G8B8A8_LINEAR_FORCE || fmt == GFXFormatB8G8R8A8)
pSwizzle = &Swizzles::bgra;
_textureUpload(
mipWidth, mipHeight, dds->mBytesPerPixel, texture, fmt,
dds->mSurfaces[face]->mMips[mip], mip, face, pSwizzle);
}
_textureUpload(dds->getWidth(i), dds->getHeight(i),dds->mBytesPerPixel, texture, fmt, dds->mSurfaces[0]->mMips[i],i, pSwizzle);
}
}
if(numMips !=1 && !ImageUtil::isCompressedFormat(texture->mFormat))
if (numMips != 1 && !isCompressed)
glGenerateMipmap(texture->getBinding());
glBindTexture(target, 0);
return true;
}

View file

@ -45,6 +45,7 @@ protected:
U32 numMipLevels,
bool forceMips = false,
S32 antialiasLevel = 0,
U32 arraySize = 1,
GFXTextureObject *inTex = NULL ) override;
bool _loadTexture(GFXTextureObject *texture, DDSFile *dds) override;
bool _loadTexture(GFXTextureObject *texture, GBitmap *bmp) override;
@ -56,7 +57,7 @@ private:
friend class GFXGLTextureObject;
/// Creates internal GL texture
void innerCreateTexture(GFXGLTextureObject *obj, U32 height, U32 width, U32 depth, GFXFormat format, GFXTextureProfile *profile, U32 numMipLevels, bool forceMips = false);
void innerCreateTexture(GFXGLTextureObject *obj, U32 height, U32 width, U32 depth, GFXFormat format, GFXTextureProfile *profile, U32 numMipLevels, bool forceMips = false, U32 arraySize = 1);
};
#endif
#endif

View file

@ -64,7 +64,7 @@ GFXGLTextureObject::~GFXGLTextureObject()
kill();
}
GFXLockedRect* GFXGLTextureObject::lock(U32 mipLevel, RectI *inRect)
GFXLockedRect* GFXGLTextureObject::lock(U32 mipLevel /*= 0*/, RectI* inRect /*= NULL*/, U32 faceIndex /*= 0*/)
{
//AssertFatal(mBinding != GL_TEXTURE_3D, "GFXGLTextureObject::lock - We don't support locking 3D textures yet");
U32 width = mTextureSize.x >> mipLevel;
@ -100,7 +100,7 @@ GFXLockedRect* GFXGLTextureObject::lock(U32 mipLevel, RectI *inRect)
return &mLockedRect;
}
void GFXGLTextureObject::unlock(U32 mipLevel)
void GFXGLTextureObject::unlock(U32 mipLevel /*= 0*/, U32 faceIndex /*= 0*/)
{
if(!mLockedRect.bits)
return;
@ -175,38 +175,231 @@ bool GFXGLTextureObject::copyToBmp(GBitmap * bmp)
FrameAllocatorMarker mem;
const bool isCubemap = (mBinding == GL_TEXTURE_CUBE_MAP);
const U32 numFaces = isCubemap ? 6 : 1;
U32 mipLevels = getMipLevels();
for (U32 mip = 0; mip < mipLevels; mip++)
for (U32 mip = 0; mip < getMipLevels(); mip++)
{
U32 srcPixelCount = bmp->getSurfaceSize(mip)/ srcBytesPerPixel;
U32 width = getWidth() >> mip;
U32 height = getHeight() >> mip;
if (width == 0) width = 1;
if (height == 0) height = 1;
U8* dest = bmp->getWritableBits(mip);
U8* orig = (U8*)mem.alloc(srcPixelCount * srcBytesPerPixel);
// Check if multisampled
GLint samples = 0;
GLenum target = mBinding;
if (mBinding == GL_TEXTURE_CUBE_MAP)
target = GL_TEXTURE_CUBE_MAP_POSITIVE_X;
glGetTexImage(mBinding, mip, GFXGLTextureFormat[mFormat], GFXGLTextureType[mFormat], orig);
if (mFormat == GFXFormatR16G16B16A16F)
glGetTexLevelParameteriv(target, mip, GL_TEXTURE_SAMPLES, &samples);
if (samples > 0)
{
dMemcpy(dest, orig, srcPixelCount * srcBytesPerPixel);
Con::warnf("GFXGLTextureObject::copyToBmp - Texture is multisampled (%d samples) at mip %d; resolve first.", samples, mip);
return false;
}
else
{
for (int i = 0; i < srcPixelCount; ++i)
{
dest[0] = orig[0];
dest[1] = orig[1];
dest[2] = orig[2];
if (dstBytesPerPixel == 4)
dest[3] = orig[3];
orig += srcBytesPerPixel;
dest += dstBytesPerPixel;
for (U32 face = 0; face < numFaces; face++)
{
GLenum faceTarget = isCubemap ? GFXGLFaceType[face] : mBinding;
U32 pixelCount = width * height;
U8* srcPixels = (U8*)mem.alloc(pixelCount * srcBytesPerPixel);
U8* dest = bmp->getWritableBits(mip, face);
if (!dest)
{
Con::errorf("GFXGLTextureObject::copyToBmp - No destination bits for mip=%u face=%u", mip, face);
continue;
}
// Read texture data
glGetTexImage(faceTarget, mip, GFXGLTextureFormat[mFormat], GFXGLTextureType[mFormat], srcPixels);
if (mFormat == GFXFormatR16G16B16A16F)
{
dMemcpy(dest, srcPixels, pixelCount * srcBytesPerPixel);
}
else
{
// Simple 8-bit per channel copy (RGBA)
U8* src = srcPixels;
for (U32 i = 0; i < pixelCount; ++i)
{
dest[0] = src[0];
dest[1] = src[1];
dest[2] = src[2];
if (dstBytesPerPixel == 4)
dest[3] = src[3];
src += srcBytesPerPixel;
dest += dstBytesPerPixel;
}
}
} // face
} // mip
glBindTexture(mBinding, 0);
return true;
}
void GFXGLTextureObject::updateTextureSlot(const GFXTexHandle& texHandle, const U32 slot, const S32 face)
{
if (!texHandle.isValid())
return;
GFXGLTextureObject* srcTex = static_cast<GFXGLTextureObject*>(texHandle.getPointer());
if (!srcTex || srcTex->getHandle() == 0)
return;
const GLenum dstTarget = mBinding; // destination binding (this)
const GLenum srcTarget = srcTex->getBinding(); // source binding
const bool srcIsCube = (srcTarget == GL_TEXTURE_CUBE_MAP || srcTarget == GL_TEXTURE_CUBE_MAP_ARRAY);
// Determine list of faces to copy from source
U32 firstFace = 0;
U32 faceCount = 1;
if (face >= 0)
{
firstFace = (U32)face;
faceCount = 1;
}
else if (srcIsCube)
{
firstFace = 0;
faceCount = 6;
}
else
{
firstFace = 0;
faceCount = 1;
}
// Ensure textures are valid
if (!glIsTexture(mHandle) || !glIsTexture(srcTex->getHandle()))
{
Con::errorf("updateTextureSlot: invalid GL texture handle src=%u dst=%u", srcTex->getHandle(), mHandle);
return;
}
// If copyImage supported, prefer that. We'll copy face-by-face (one-layer depth = 1)
if (GFXGL->mCapabilities.copyImage)
{
for (U32 mip = 0; mip < getMipLevels(); ++mip)
{
const GLsizei mipW = getMax(1u, srcTex->getWidth() >> mip);
const GLsizei mipH = getMax(1u, srcTex->getHeight() >> mip);
for (U32 f = firstFace; f < firstFace + faceCount; ++f)
{
// Compute source z offset (for cube arrays it's layer index; for cubemap it's face index)
GLint srcZ = 0;
if (srcTarget == GL_TEXTURE_CUBE_MAP_ARRAY)
{
srcZ = f;
}
else if (srcTarget == GL_TEXTURE_CUBE_MAP)
{
srcZ = f;
}
else
{
srcZ = 0; // 2D source
}
// Compute destination layer (z offset) depending on destination type
GLint dstZ = 0;
if (dstTarget == GL_TEXTURE_CUBE_MAP_ARRAY)
{
// each slot is a whole cubemap => slot * 6 + faceIndex
dstZ = (GLint)(slot * 6 + f);
}
else if (dstTarget == GL_TEXTURE_2D_ARRAY)
{
dstZ = (GLint)slot; // each slot is a single layer
}
else if (dstTarget == GL_TEXTURE_CUBE_MAP)
{
dstZ = (GLint)f;
}
else
{
dstZ = 0; // 2D texture target
}
// Copy single layer/face at this mip
glCopyImageSubData(
srcTex->getHandle(), srcTarget, mip, 0, 0, srcZ,
mHandle, dstTarget, mip, 0, 0, dstZ,
mipW, mipH, 1
);
GLenum err = glGetError();
if (err != GL_NO_ERROR)
Con::errorf("glCopyImageSubData failed with 0x%X (mip=%u face=%u)", err, mip, f);
}
}
}
glBindTexture(mBinding, 0);
return true;
return;
}
// Fallback: CPU-side copy using glGetTexImage + glTexSubImage
for (U32 mip = 0; mip < getMipLevels() && mip < srcTex->getMipLevels(); ++mip)
{
const GLsizei mipW = getMax(1u, srcTex->getWidth() >> mip);
const GLsizei mipH = getMax(1u, srcTex->getHeight() >> mip);
const U32 pixelSize = GFXFormat_getByteSize(mFormat); // assuming same fmt for src/dst
const U32 dataSize = mipW * mipH * pixelSize;
FrameAllocatorMarker mem;
U8* buffer = (U8*)mem.alloc(dataSize);
glBindTexture(srcTarget, srcTex->getHandle());
glBindTexture(dstTarget, mHandle);
for (U32 f = firstFace; f < firstFace + faceCount; ++f)
{
GLenum srcFaceTarget = srcTarget;
if (srcTarget == GL_TEXTURE_CUBE_MAP)
srcFaceTarget = GFXGLFaceType[f];
// read pixels from source
glGetTexImage(srcFaceTarget, mip, GFXGLTextureFormat[mFormat], GFXGLTextureType[mFormat], buffer);
GLint dstLayer = 0;
if (dstTarget == GL_TEXTURE_CUBE_MAP_ARRAY)
dstLayer = (GLint)(slot * 6 + f);
else if (dstTarget == GL_TEXTURE_2D_ARRAY)
dstLayer = (GLint)slot;
else if (dstTarget == GL_TEXTURE_CUBE_MAP)
dstLayer = (GLint)f;
else
dstLayer = 0;
if (dstTarget == GL_TEXTURE_CUBE_MAP)
{
GLenum dstFaceTarget = GFXGLFaceType[f];
glTexSubImage2D(dstFaceTarget, mip, 0, 0, mipW, mipH,
GFXGLTextureFormat[mFormat], GFXGLTextureType[mFormat], buffer);
}
else if (dstTarget == GL_TEXTURE_2D)
{
glTexSubImage2D(GL_TEXTURE_2D, mip, 0, 0, mipW, mipH,
GFXGLTextureFormat[mFormat], GFXGLTextureType[mFormat], buffer);
}
else if (dstTarget == GL_TEXTURE_2D_ARRAY || dstTarget == GL_TEXTURE_CUBE_MAP_ARRAY)
{
glTexSubImage3D(dstTarget, mip, 0, 0, dstLayer, mipW, mipH, 1,
GFXGLTextureFormat[mFormat], GFXGLTextureType[mFormat], buffer);
}
}
glBindTexture(dstTarget, 0);
glBindTexture(srcTarget, 0);
}
}
void GFXGLTextureObject::copyTo(GFXTextureObject* dstTex)
{
}
void GFXGLTextureObject::initSamplerState(const GFXSamplerStateDesc &ssd)

View file

@ -26,7 +26,9 @@
#include "gfx/gfxTextureObject.h"
#include "gfx/gl/tGL/tGL.h"
#include "gfx/gfxStateBlock.h"
#ifndef _MRECT_H_
#include "math/mRect.h"
#endif
class GFXGLDevice;
class GFXGLTextureObject : public GFXTextureObject
@ -64,11 +66,13 @@ public:
/// Get/set data from texture (for dynamic textures and render targets)
/// @attention DO NOT READ FROM THE RETURNED RECT! It is not guaranteed to work and may incur significant performance penalties.
GFXLockedRect* lock(U32 mipLevel = 0, RectI *inRect = NULL) override;
void unlock(U32 mipLevel = 0 ) override;
GFXLockedRect* lock(U32 mipLevel = 0, RectI *inRect = NULL, U32 faceIndex = 0) override;
void unlock(U32 mipLevel = 0, U32 faceIndex = 0) override;
bool copyToBmp(GBitmap *) override; ///< Not implemented
void updateTextureSlot(const GFXTexHandle& texHandle, const U32 slot, const S32 face = -1) override;
void copyTo(GFXTextureObject* dstTex) override;
void generateMipMaps() override {};
bool mIsNPoT2;
// GFXResource interface

View file

@ -38,9 +38,9 @@ public:
mipLevel(_mipLevel), zOffset(_zOffset)
{
}
virtual ~_GFXGLTargetDesc() {}
virtual U32 getHandle() = 0;
virtual U32 getWidth() = 0;
virtual U32 getHeight() = 0;
@ -49,10 +49,10 @@ public:
virtual GLenum getBinding() = 0;
virtual GFXFormat getFormat() = 0;
virtual bool isCompatible(const GFXGLTextureObject* tex) = 0;
U32 getMipLevel() { return mipLevel; }
U32 getZOffset() { return zOffset; }
private:
U32 mipLevel;
U32 zOffset;
@ -62,19 +62,21 @@ private:
class _GFXGLTextureTargetDesc : public _GFXGLTargetDesc
{
public:
_GFXGLTextureTargetDesc(GFXGLTextureObject* tex, U32 _mipLevel, U32 _zOffset)
: _GFXGLTargetDesc(_mipLevel, _zOffset), mTex(tex)
_GFXGLTextureTargetDesc(GFXGLTextureObject* tex, U32 _mipLevel, U32 _zOffset, U32 _face = 0, bool isCube = false)
: _GFXGLTargetDesc(_mipLevel, _zOffset), mTex(tex), mFace(_face), mIsCube(isCube)
{
}
virtual ~_GFXGLTextureTargetDesc() {}
U32 getHandle() override { return mTex->getHandle(); }
U32 getWidth() override { return mTex->getWidth(); }
U32 getHeight() override { return mTex->getHeight(); }
U32 getDepth() override { return mTex->getDepth(); }
U32 getFace() { return mFace; }
bool hasMips() override { return mTex->mMipLevels != 1; }
GLenum getBinding() override { return mTex->getBinding(); }
GLenum getBinding() override { return mIsCube ? GFXGLFaceType[mFace] : mTex->getBinding(); }
GFXFormat getFormat() override { return mTex->getFormat(); }
bool isCompatible(const GFXGLTextureObject* tex) override
{
@ -82,40 +84,12 @@ public:
&& mTex->getWidth() == tex->getWidth()
&& mTex->getHeight() == tex->getHeight();
}
GFXGLTextureObject* getTextureObject() const {return mTex; }
GFXGLTextureObject* getTextureObject() const { return mTex; }
private:
StrongRefPtr<GFXGLTextureObject> mTex;
};
/// Internal struct used to track Cubemap texture information for FBO attachment
class _GFXGLCubemapTargetDesc : public _GFXGLTargetDesc
{
public:
_GFXGLCubemapTargetDesc(GFXGLCubemap* tex, U32 _face, U32 _mipLevel, U32 _zOffset)
: _GFXGLTargetDesc(_mipLevel, _zOffset), mTex(tex), mFace(_face)
{
}
virtual ~_GFXGLCubemapTargetDesc() {}
U32 getHandle() override { return mTex->getHandle(); }
U32 getWidth() override { return mTex->getWidth(); }
U32 getHeight() override { return mTex->getHeight(); }
U32 getDepth() override { return 0; }
bool hasMips() override { return mTex->getMipMapLevels() != 1; }
GLenum getBinding() override { return GFXGLCubemap::getEnumForFaceNumber(mFace); }
GFXFormat getFormat() override { return mTex->getFormat(); }
bool isCompatible(const GFXGLTextureObject* tex) override
{
return mTex->getFormat() == tex->getFormat()
&& mTex->getWidth() == tex->getWidth()
&& mTex->getHeight() == tex->getHeight();
}
private:
StrongRefPtr<GFXGLCubemap> mTex;
U32 mFace;
bool mIsCube;
};
// Internal implementations
@ -123,9 +97,9 @@ class _GFXGLTextureTargetImpl // TODO OPENGL remove and implement on GFXGLTextur
{
public:
GFXGLTextureTarget* mTarget;
virtual ~_GFXGLTextureTargetImpl() {}
virtual void applyState() = 0;
virtual void makeActive() = 0;
virtual void finish() = 0;
@ -137,10 +111,10 @@ class _GFXGLTextureTargetFBOImpl : public _GFXGLTextureTargetImpl
public:
GLuint mFramebuffer;
bool mGenMips;
_GFXGLTextureTargetFBOImpl(GFXGLTextureTarget* target);
virtual ~_GFXGLTextureTargetFBOImpl();
void applyState() override;
void makeActive() override;
void finish() override;
@ -159,42 +133,42 @@ _GFXGLTextureTargetFBOImpl::~_GFXGLTextureTargetFBOImpl()
}
void _GFXGLTextureTargetFBOImpl::applyState()
{
{
// REMINDER: When we implement MRT support, check against GFXGLDevice::getNumRenderTargets()
PRESERVE_FRAMEBUFFER();
glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
glEnable(GL_FRAMEBUFFER_SRGB);
bool drawbufs[16];
int bufsize = 0;
for (int i = 0; i < 16; i++)
drawbufs[i] = false;
drawbufs[i] = false;
bool hasColor = false;
for(int i = 0; i < GFXGL->getNumRenderTargets(); ++i)
{
_GFXGLTargetDesc* color = mTarget->getTargetDesc( static_cast<GFXTextureTarget::RenderSlot>(GFXTextureTarget::Color0+i ));
if(color)
for (int i = 0; i < GFXGL->getNumRenderTargets(); ++i)
{
_GFXGLTargetDesc* color = mTarget->getTargetDesc(static_cast<GFXTextureTarget::RenderSlot>(GFXTextureTarget::Color0 + i));
if (color)
{
hasColor = true;
const GLenum binding = color->getBinding();
if( binding == GL_TEXTURE_2D || (binding >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && binding <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z) )
glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, color->getBinding( ), color->getHandle( ), color->getMipLevel( ) );
else if( binding == GL_TEXTURE_1D )
glFramebufferTexture1D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, color->getBinding( ), color->getHandle( ), color->getMipLevel( ) );
else if( binding == GL_TEXTURE_3D )
glFramebufferTexture3D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, color->getBinding( ), color->getHandle( ), color->getMipLevel( ), color->getZOffset( ) );
if (binding == GL_TEXTURE_2D || (binding >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && binding <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z))
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, color->getBinding(), color->getHandle(), color->getMipLevel());
else if (binding == GL_TEXTURE_1D)
glFramebufferTexture1D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, color->getBinding(), color->getHandle(), color->getMipLevel());
else if (binding == GL_TEXTURE_3D)
glFramebufferTexture3D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, color->getBinding(), color->getHandle(), color->getMipLevel(), color->getZOffset());
else
Con::errorf("_GFXGLTextureTargetFBOImpl::applyState - Bad binding");
Con::errorf("_GFXGLTextureTargetFBOImpl::applyState - Bad binding");
}
else
{
// Clears the texture (note that the binding is irrelevent)
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0+i, GL_TEXTURE_2D, 0, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, GL_TEXTURE_2D, 0, 0);
}
}
_GFXGLTargetDesc* depthStecil = mTarget->getTargetDesc(GFXTextureTarget::DepthStencil);
if(depthStecil)
if (depthStecil)
{
// Certain drivers have issues with depth only FBOs. That and the next two asserts assume we have a color target.
AssertFatal(hasColor, "GFXGLTextureTarget::applyState() - Cannot set DepthStencil target without Color0 target!");
@ -206,40 +180,40 @@ void _GFXGLTextureTargetFBOImpl::applyState()
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
}
GLenum *buf = new GLenum[bufsize];
GLenum* buf = new GLenum[bufsize];
int count = 0;
for (int i = 0; i < bufsize; i++)
{
if (drawbufs[i])
{
buf[count] = GL_COLOR_ATTACHMENT0 + i;
count++;
}
if (drawbufs[i])
{
buf[count] = GL_COLOR_ATTACHMENT0 + i;
count++;
}
}
glDrawBuffers(bufsize, buf);
delete[] buf;
CHECK_FRAMEBUFFER_STATUS();
}
void _GFXGLTextureTargetFBOImpl::makeActive()
{
glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
GFXGL->getOpenglCache()->setCacheBinded(GL_FRAMEBUFFER, mFramebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
GFXGL->getOpenglCache()->setCacheBinded(GL_FRAMEBUFFER, mFramebuffer);
int i = 0;
GLenum draws[16];
for( i = 0; i < GFXGL->getNumRenderTargets(); ++i)
{
_GFXGLTargetDesc* color = mTarget->getTargetDesc( static_cast<GFXTextureTarget::RenderSlot>(GFXTextureTarget::Color0+i ));
if(color)
draws[i] = GL_COLOR_ATTACHMENT0 + i;
else
break;
}
int i = 0;
GLenum draws[16];
for (i = 0; i < GFXGL->getNumRenderTargets(); ++i)
{
_GFXGLTargetDesc* color = mTarget->getTargetDesc(static_cast<GFXTextureTarget::RenderSlot>(GFXTextureTarget::Color0 + i));
if (color)
draws[i] = GL_COLOR_ATTACHMENT0 + i;
else
break;
}
glDrawBuffers( i, draws );
glDrawBuffers(i, draws);
}
void _GFXGLTextureTargetFBOImpl::finish()
@ -250,20 +224,20 @@ void _GFXGLTextureTargetFBOImpl::finish()
if (!mGenMips)
return;
for(int i = 0; i < GFXGL->getNumRenderTargets(); ++i)
{
_GFXGLTargetDesc* color = mTarget->getTargetDesc( static_cast<GFXTextureTarget::RenderSlot>(GFXTextureTarget::Color0+i ) );
if(!color || !(color->hasMips()))
for (int i = 0; i < GFXGL->getNumRenderTargets(); ++i)
{
_GFXGLTargetDesc* color = mTarget->getTargetDesc(static_cast<GFXTextureTarget::RenderSlot>(GFXTextureTarget::Color0 + i));
if (!color || !(color->hasMips()))
continue;
// Generate mips if necessary
// Assumes a 2D texture.
GLenum binding = color->getBinding();
binding = (binding >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && binding <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z) ? GL_TEXTURE_CUBE_MAP : binding;
PRESERVE_TEXTURE( binding );
glBindTexture( binding, color->getHandle() );
glGenerateMipmap( binding );
PRESERVE_TEXTURE(binding);
glBindTexture(binding, color->getHandle());
glGenerateMipmap(binding);
}
}
@ -271,13 +245,13 @@ void _GFXGLTextureTargetFBOImpl::finish()
GFXGLTextureTarget::GFXGLTextureTarget(bool genMips) : mCopyFboSrc(0), mCopyFboDst(0)
{
mGenMips = genMips;
for(U32 i=0; i<MaxRenderSlotId; i++)
for (U32 i = 0; i < MaxRenderSlotId; i++)
mTargets[i] = NULL;
GFXTextureManager::addEventDelegate( this, &GFXGLTextureTarget::_onTextureEvent );
GFXTextureManager::addEventDelegate(this, &GFXGLTextureTarget::_onTextureEvent);
_impl = new _GFXGLTextureTargetFBOImpl(this);
glGenFramebuffers(1, &mCopyFboSrc);
glGenFramebuffers(1, &mCopyFboDst);
}
@ -292,7 +266,7 @@ GFXGLTextureTarget::~GFXGLTextureTarget()
const Point2I GFXGLTextureTarget::getSize()
{
if(mTargets[Color0].isValid())
if (mTargets[Color0].isValid())
return Point2I(mTargets[Color0]->getWidth(), mTargets[Color0]->getHeight());
return Point2I(0, 0);
@ -300,61 +274,50 @@ const Point2I GFXGLTextureTarget::getSize()
GFXFormat GFXGLTextureTarget::getFormat()
{
if(mTargets[Color0].isValid())
if (mTargets[Color0].isValid())
return mTargets[Color0]->getFormat();
return GFXFormatR8G8B8A8;
}
void GFXGLTextureTarget::attachTexture( RenderSlot slot, GFXTextureObject *tex, U32 mipLevel/*=0*/, U32 zOffset /*= 0*/ )
void GFXGLTextureTarget::attachTexture(RenderSlot slot, GFXTextureObject* tex, U32 mipLevel/*=0*/, U32 zOffset /*= 0*/, U32 face /*= 0*/)
{
if( tex == GFXTextureTarget::sDefaultDepthStencil )
if (tex == GFXTextureTarget::sDefaultDepthStencil)
tex = GFXGL->getDefaultDepthTex();
// are we readding the same thing, face and all?
_GFXGLTextureTargetDesc* mTex = static_cast<_GFXGLTextureTargetDesc*>(mTargets[slot].ptr());
if( (!tex && !mTex) || (mTex && mTex->getTextureObject() == tex) )
if ((!tex && !mTex) || (mTex && mTex->getTextureObject() == tex && mTex->getFace() == face))
return;
// Triggers an update when we next render
invalidateState();
// We stash the texture and info into an internal struct.
GFXGLTextureObject* glTexture = static_cast<GFXGLTextureObject*>(tex);
if(tex && tex != GFXTextureTarget::sDefaultDepthStencil)
mTargets[slot] = new _GFXGLTextureTargetDesc(glTexture, mipLevel, zOffset);
if (tex && tex != GFXTextureTarget::sDefaultDepthStencil)
{
mTargets[slot] = new _GFXGLTextureTargetDesc(glTexture, mipLevel, zOffset, face, glTexture->isCubeMap());
}
else
mTargets[slot] = NULL;
}
void GFXGLTextureTarget::attachTexture( RenderSlot slot, GFXCubemap *tex, U32 face, U32 mipLevel/*=0*/ )
void GFXGLTextureTarget::attachTexture(RenderSlot slot, GFXCubemap* tex, U32 face, U32 mipLevel/*=0*/)
{
// No depth cubemaps, sorry
AssertFatal(slot != DepthStencil, "GFXGLTextureTarget::attachTexture (cube) - Cube depth textures not supported!");
if(slot == DepthStencil)
return;
// Triggers an update when we next render
invalidateState();
// We stash the texture and info into an internal struct.
GFXGLCubemap* glTexture = static_cast<GFXGLCubemap*>(tex);
if(tex)
mTargets[slot] = new _GFXGLCubemapTargetDesc(glTexture, face, mipLevel, 0);
else
mTargets[slot] = NULL;
}
void GFXGLTextureTarget::clearAttachments()
{
deactivate();
for(S32 i=1; i<MaxRenderSlotId; i++)
for (S32 i = 1; i < MaxRenderSlotId; i++)
attachTexture((RenderSlot)i, NULL);
}
void GFXGLTextureTarget::zombify()
{
invalidateState();
// Will be recreated in applyState
_impl = NULL;
}
@ -376,15 +339,15 @@ void GFXGLTextureTarget::deactivate()
void GFXGLTextureTarget::applyState()
{
if(!isPendingState())
if (!isPendingState())
return;
// So we don't do this over and over again
stateApplied();
if(_impl.isNull())
if (_impl.isNull())
_impl = new _GFXGLTextureTargetFBOImpl(this);
_impl->applyState();
}
@ -394,7 +357,7 @@ _GFXGLTargetDesc* GFXGLTextureTarget::getTargetDesc(RenderSlot slot) const
return mTargets[slot].ptr();
}
void GFXGLTextureTarget::_onTextureEvent( GFXTexCallbackCode code )
void GFXGLTextureTarget::_onTextureEvent(GFXTexCallbackCode code)
{
invalidateState();
}
@ -403,7 +366,7 @@ const String GFXGLTextureTarget::describeSelf() const
{
String ret = String::ToString(" Color0 Attachment: %i", mTargets[Color0].isValid() ? mTargets[Color0]->getHandle() : 0);
ret += String::ToString(" Depth Attachment: %i", mTargets[DepthStencil].isValid() ? mTargets[DepthStencil]->getHandle() : 0);
return ret;
}
@ -416,27 +379,27 @@ void GFXGLTextureTarget::resolveTo(GFXTextureObject* obj)
AssertFatal(dynamic_cast<GFXGLTextureObject*>(obj), "GFXGLTextureTarget::resolveTo - Incorrect type of texture, expected a GFXGLTextureObject");
GFXGLTextureObject* glTexture = static_cast<GFXGLTextureObject*>(obj);
if( GFXGL->mCapabilities.copyImage && mTargets[Color0]->isCompatible(glTexture) )
if (GFXGL->mCapabilities.copyImage && mTargets[Color0]->isCompatible(glTexture))
{
GLenum binding = mTargets[Color0]->getBinding();
GLenum binding = mTargets[Color0]->getBinding();
binding = (binding >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && binding <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z) ? GL_TEXTURE_CUBE_MAP : binding;
U32 srcStartDepth = binding == GL_TEXTURE_CUBE_MAP ? mTargets[Color0]->getBinding() - GL_TEXTURE_CUBE_MAP_POSITIVE_X : 0;
glCopyImageSubData(
mTargets[Color0]->getHandle(), binding, 0, 0, 0, srcStartDepth,
glTexture->getHandle(), glTexture->getBinding(), 0, 0, 0, 0,
mTargets[Color0]->getWidth(), mTargets[Color0]->getHeight(), 1);
mTargets[Color0]->getHandle(), binding, 0, 0, 0, srcStartDepth,
glTexture->getHandle(), glTexture->getBinding(), 0, 0, 0, 0,
mTargets[Color0]->getWidth(), mTargets[Color0]->getHeight(), 1);
return;
}
PRESERVE_FRAMEBUFFER();
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mCopyFboDst);
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, glTexture->getBinding(), glTexture->getHandle(), 0);
glBindFramebuffer(GL_READ_FRAMEBUFFER, mCopyFboSrc);
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTargets[Color0]->getBinding(), mTargets[Color0]->getHandle(), 0);
glBlitFramebuffer(0, 0, mTargets[Color0]->getWidth(), mTargets[Color0]->getHeight(),
0, 0, glTexture->getWidth(), glTexture->getHeight(), GL_COLOR_BUFFER_BIT, GL_NEAREST);
}

View file

@ -50,35 +50,35 @@ public:
const Point2I getSize() override;
GFXFormat getFormat() override;
void attachTexture(RenderSlot slot, GFXTextureObject *tex, U32 mipLevel=0, U32 zOffset = 0) override;
void attachTexture(RenderSlot slot, GFXCubemap *tex, U32 face, U32 mipLevel=0) override;
void attachTexture(RenderSlot slot, GFXTextureObject* tex, U32 mipLevel = 0, U32 zOffset = 0, U32 face = 0) override;
void attachTexture(RenderSlot slot, GFXCubemap* tex, U32 face, U32 mipLevel = 0) override;
virtual void clearAttachments();
/// Functions to query internal state
/// @{
/// Returns the internal structure for the given slot. This should only be called by our internal implementations.
_GFXGLTargetDesc* getTargetDesc(RenderSlot slot) const;
/// @}
void deactivate() override;
void zombify() override;
void resurrect() override;
const String describeSelf() const override;
void resolve() override;
void resolveTo(GFXTextureObject* obj) override;
protected:
friend class GFXGLDevice;
/// The callback used to get texture events.
/// @see GFXTextureManager::addEventDelegate
void _onTextureEvent( GFXTexCallbackCode code );
void _onTextureEvent(GFXTexCallbackCode code);
/// Pointer to our internal implementation
AutoPtr<_GFXGLTextureTargetImpl> _impl;
@ -87,10 +87,10 @@ protected:
/// These redirect to our internal implementation
/// @{
void applyState();
void makeActive();
/// @}
//copy FBO

View file

@ -103,8 +103,6 @@ void GFXGLDevice::enumerateAdapters( Vector<GFXAdapter*> &adapterList )
}
SDL_ClearError();
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
SDL_GL_SetAttribute(SDL_GL_FRAMEBUFFER_SRGB_CAPABLE, 1);
@ -140,6 +138,10 @@ void GFXGLDevice::enumerateAdapters( Vector<GFXAdapter*> &adapterList )
return;
}
// Set our sdl attribute to use this version.
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, major);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, minor);
//check for required extensions
if (!gglHasExtension(ARB_texture_cube_map_array))
{
@ -168,7 +170,24 @@ void GFXGLDevice::enumerateAdapters( Vector<GFXAdapter*> &adapterList )
dStrcpy(toAdd->mName, "OpenGL", GFXAdapter::MaxAdapterNameLen);
toAdd->mType = OpenGL;
toAdd->mShaderModel = 0.f;
F32 shaderModel = 3.3f;
if (major == 4)
{
if (minor == 0)
shaderModel = 4.00f; // GLSL 4.00
else if (minor == 1)
shaderModel = 4.10f; // GLSL 4.10
else if (minor == 2)
shaderModel = 4.20f; // GLSL 4.20
else if (minor == 3)
shaderModel = 4.30f; // GLSL 4.30
else if (minor == 4)
shaderModel = 4.40f; // GLSL 4.40
else if (minor == 5)
shaderModel = 4.50f; // GLSL 4.50
else if (minor == 6)
shaderModel = 4.60f; // GLSL 4.60
}
toAdd->mCreateDeviceInstanceDelegate = mCreateDeviceInstance;
// Enumerate all available resolutions: