From d9a7615cc89ef9e16f0392a7a119361d7cf3c394 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 14 Apr 2017 17:52:44 -0700 Subject: [PATCH] Add compression support for skyboxes --- .../src/gpu/gl41/GL41BackendTexture.cpp | 14 ++- .../src/gpu/gl45/GL45BackendTexture.cpp | 30 +++-- libraries/gpu/src/gpu/Texture.cpp | 2 +- libraries/gpu/src/gpu/Texture.h | 1 + libraries/image/src/image/Image.cpp | 112 ++++++------------ libraries/image/src/image/Image.h | 4 +- tests/ktx/src/main.cpp | 2 +- 7 files changed, 77 insertions(+), 88 deletions(-) diff --git a/libraries/gpu-gl/src/gpu/gl41/GL41BackendTexture.cpp b/libraries/gpu-gl/src/gpu/gl41/GL41BackendTexture.cpp index 6811ef7020..ac5eab4738 100644 --- a/libraries/gpu-gl/src/gpu/gl41/GL41BackendTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl41/GL41BackendTexture.cpp @@ -108,7 +108,19 @@ void GL41Texture::copyMipFaceLinesFromTexture(uint16_t mip, uint8_t face, const } } else if (GL_TEXTURE_CUBE_MAP == _target) { auto target = GLTexture::CUBE_FACE_LAYOUT[face]; - glTexSubImage2D(target, mip, 0, yOffset, size.x, size.y, format, type, sourcePointer); + + switch (internalFormat) { + case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT: + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT: + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT: + case GL_COMPRESSED_RED_RGTC1: + case GL_COMPRESSED_RG_RGTC2: + glCompressedTexSubImage2D(target, mip, 0, yOffset, size.x, size.y, internalFormat, sourceSize, sourcePointer); + break; + default: + glTexSubImage2D(target, mip, 0, yOffset, size.x, size.y, format, type, sourcePointer); + break; + } } else { assert(false); } diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp index 893e6412ea..1814be08d7 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp @@ -132,13 +132,29 @@ void GL45Texture::copyMipFaceLinesFromTexture(uint16_t mip, uint8_t face, const break; } } else if (GL_TEXTURE_CUBE_MAP == _target) { - // DSA ARB does not work on AMD, so use EXT - // unless EXT is not available on the driver - if (glTextureSubImage2DEXT) { - auto target = GLTexture::CUBE_FACE_LAYOUT[face]; - glTextureSubImage2DEXT(_id, target, mip, 0, yOffset, size.x, size.y, format, type, sourcePointer); - } else { - glTextureSubImage3D(_id, mip, 0, yOffset, face, size.x, size.y, 1, format, type, sourcePointer); + switch (internalFormat) { + case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT: + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT: + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT: + case GL_COMPRESSED_RED_RGTC1: + case GL_COMPRESSED_RG_RGTC2: + if (glCompressedTextureSubImage2DEXT) { + auto target = GLTexture::CUBE_FACE_LAYOUT[face]; + glCompressedTextureSubImage2DEXT(_id, target, mip, 0, yOffset, size.x, size.y, internalFormat, sourceSize, sourcePointer); + } else { + glCompressedTextureSubImage3D(_id, mip, 0, yOffset, face, size.x, size.y, 1, internalFormat, sourceSize, sourcePointer); + } + break; + default: + // DSA ARB does not work on AMD, so use EXT + // unless EXT is not available on the driver + if (glTextureSubImage2DEXT) { + auto target = GLTexture::CUBE_FACE_LAYOUT[face]; + glTextureSubImage2DEXT(_id, target, mip, 0, yOffset, size.x, size.y, format, type, sourcePointer); + } else { + glTextureSubImage3D(_id, mip, 0, yOffset, face, size.x, size.y, 1, format, type, sourcePointer); + } + break; } } else { Q_ASSERT(false); diff --git a/libraries/gpu/src/gpu/Texture.cpp b/libraries/gpu/src/gpu/Texture.cpp index 6c92886864..1e212c01c7 100755 --- a/libraries/gpu/src/gpu/Texture.cpp +++ b/libraries/gpu/src/gpu/Texture.cpp @@ -752,7 +752,7 @@ bool sphericalHarmonicsFromTexture(const gpu::Texture& cubeTexture, std::vector< boffset = 0; } - auto data = cubeTexture.accessStoredMipFace(0,face)->readData(); + auto data = cubeTexture.accessStoredMipFace(0, face)->readData(); if (data == nullptr) { continue; } diff --git a/libraries/gpu/src/gpu/Texture.h b/libraries/gpu/src/gpu/Texture.h index f100b17b3b..898b63c73c 100755 --- a/libraries/gpu/src/gpu/Texture.h +++ b/libraries/gpu/src/gpu/Texture.h @@ -499,6 +499,7 @@ public: // For Cube Texture, it's possible to generate the irradiance spherical harmonics and make them availalbe with the texture bool generateIrradiance(); const SHPointer& getIrradiance(uint16 slice = 0) const { return _irradiance; } + void overrideIrradiance(SHPointer irradiance) { _irradiance = irradiance; } bool isIrradianceValid() const { return _isIrradianceValid; } // Own sampler diff --git a/libraries/image/src/image/Image.cpp b/libraries/image/src/image/Image.cpp index 18f549ebc7..d64601d4ac 100644 --- a/libraries/image/src/image/Image.cpp +++ b/libraries/image/src/image/Image.cpp @@ -219,53 +219,8 @@ const QImage TextureUsage::process2DImageColor(const QImage& srcImage, bool& val return image; } -void TextureUsage::defineColorTexelFormats(gpu::Element& formatGPU, gpu::Element& formatMip, - const QImage& image, bool isLinear) { - if (image.hasAlphaChannel()) { - gpu::Semantic gpuSemantic; - gpu::Semantic mipSemantic; - if (isLinear) { - mipSemantic = gpu::BGRA; - gpuSemantic = gpu::RGBA; - } else { - mipSemantic = gpu::SBGRA; - gpuSemantic = gpu::SRGBA; - } - formatGPU = gpu::Element(gpu::VEC4, gpu::NUINT8, gpuSemantic); - formatMip = gpu::Element(gpu::VEC4, gpu::NUINT8, mipSemantic); - } else { - gpu::Semantic gpuSemantic; - gpu::Semantic mipSemantic; - if (isLinear) { - mipSemantic = gpu::RGB; - gpuSemantic = gpu::RGB; - } else { - mipSemantic = gpu::SRGB; - gpuSemantic = gpu::SRGB; - } - formatGPU = gpu::Element(gpu::VEC3, gpu::NUINT8, gpuSemantic); - formatMip = gpu::Element(gpu::VEC3, gpu::NUINT8, mipSemantic); - } -} - -void generateFaceMips(gpu::Texture* texture, QImage& image, uint8 face) { -#if CPU_MIPMAPS - PROFILE_RANGE(resource_parse, "generateFaceMips"); - - - auto numMips = texture->getNumMips(); - for (uint16 level = 1; level < numMips; ++level) { - QSize mipSize(texture->evalMipWidth(level), texture->evalMipHeight(level)); - QImage mipImage = image.scaled(mipSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); - texture->assignStoredMipFace(level, face, mipImage.byteCount(), mipImage.constBits()); - } -#else - texture->autoGenerateMips(-1); -#endif -} - struct MyOutputHandler : public nvtt::OutputHandler { - MyOutputHandler(gpu::Texture* texture) : _texture(texture) {} + MyOutputHandler(gpu::Texture* texture, int face) : _texture(texture), _face(face) {} virtual void beginImage(int size, int width, int height, int depth, int face, int miplevel) { _size = size; @@ -281,7 +236,11 @@ struct MyOutputHandler : public nvtt::OutputHandler { return true; } virtual void endImage() { - _texture->assignStoredMip(_miplevel, _size, static_cast(_data)); + if (_face >= 0) { + _texture->assignStoredMipFace(_miplevel, _face, _size, static_cast(_data)); + } else { + _texture->assignStoredMip(_miplevel, _size, static_cast(_data)); + } free(_data); _data = nullptr; } @@ -291,6 +250,7 @@ struct MyOutputHandler : public nvtt::OutputHandler { gpu::Texture* _texture{ nullptr }; int _miplevel = 0; int _size = 0; + int _face = -1; }; struct MyErrorHandler : public nvtt::ErrorHandler { virtual void error(nvtt::Error e) override { @@ -298,7 +258,7 @@ struct MyErrorHandler : public nvtt::ErrorHandler { } }; -void generateMips(gpu::Texture* texture, QImage& image, bool validAlpha, bool alphaAsMask, bool grayscale, bool normalMap) { +void generateMips(gpu::Texture* texture, QImage& image, bool validAlpha, bool alphaAsMask, bool grayscale = false, bool normalMap = false, int face = -1) { #if CPU_MIPMAPS PROFILE_RANGE(resource_parse, "generateMips"); @@ -343,7 +303,7 @@ void generateMips(gpu::Texture* texture, QImage& image, bool validAlpha, bool al nvtt::OutputOptions outputOptions; outputOptions.setOutputHeader(false); - MyOutputHandler outputHandler(texture); + MyOutputHandler outputHandler(texture, face); outputOptions.setOutputHandler(&outputHandler); MyErrorHandler errorHandler; outputOptions.setErrorHandler(&errorHandler); @@ -359,7 +319,7 @@ void generateMips(gpu::Texture* texture, QImage& image, bool validAlpha, bool al #endif } -gpu::Texture* TextureUsage::process2DTextureColorFromImage(const QImage& srcImage, const std::string& srcImageName, bool isLinear, bool doGenerateMips, bool isStrict) { +gpu::Texture* TextureUsage::process2DTextureColorFromImage(const QImage& srcImage, const std::string& srcImageName, bool isLinear, bool isStrict) { PROFILE_RANGE(resource_parse, "process2DTextureColorFromImage"); bool validAlpha = false; bool alphaAsMask = true; @@ -391,10 +351,7 @@ gpu::Texture* TextureUsage::process2DTextureColorFromImage(const QImage& srcImag } theTexture->setUsage(usage.build()); theTexture->setStoredMipFormat(formatMip); - - if (doGenerateMips) { - generateMips(theTexture, image, validAlpha, alphaAsMask, false, false); - } + generateMips(theTexture, image, validAlpha, alphaAsMask, false, false); theTexture->setSource(srcImageName); } @@ -402,23 +359,23 @@ gpu::Texture* TextureUsage::process2DTextureColorFromImage(const QImage& srcImag } gpu::Texture* TextureUsage::createStrict2DTextureFromImage(const QImage& srcImage, const std::string& srcImageName) { - return process2DTextureColorFromImage(srcImage, srcImageName, false, true, true); + return process2DTextureColorFromImage(srcImage, srcImageName, false, true); } gpu::Texture* TextureUsage::create2DTextureFromImage(const QImage& srcImage, const std::string& srcImageName) { - return process2DTextureColorFromImage(srcImage, srcImageName, false, true); + return process2DTextureColorFromImage(srcImage, srcImageName, false); } gpu::Texture* TextureUsage::createAlbedoTextureFromImage(const QImage& srcImage, const std::string& srcImageName) { - return process2DTextureColorFromImage(srcImage, srcImageName, false, true); + return process2DTextureColorFromImage(srcImage, srcImageName, false); } gpu::Texture* TextureUsage::createEmissiveTextureFromImage(const QImage& srcImage, const std::string& srcImageName) { - return process2DTextureColorFromImage(srcImage, srcImageName, false, true); + return process2DTextureColorFromImage(srcImage, srcImageName, false); } gpu::Texture* TextureUsage::createLightmapTextureFromImage(const QImage& srcImage, const std::string& srcImageName) { - return process2DTextureColorFromImage(srcImage, srcImageName, false, true); + return process2DTextureColorFromImage(srcImage, srcImageName, false); } @@ -892,7 +849,7 @@ const CubeLayout CubeLayout::CUBEMAP_LAYOUTS[] = { }; const int CubeLayout::NUM_CUBEMAP_LAYOUTS = sizeof(CubeLayout::CUBEMAP_LAYOUTS) / sizeof(CubeLayout); -gpu::Texture* TextureUsage::processCubeTextureColorFromImage(const QImage& srcImage, const std::string& srcImageName, bool isLinear, bool generateMips, bool generateIrradiance) { +gpu::Texture* TextureUsage::processCubeTextureColorFromImage(const QImage& srcImage, const std::string& srcImageName, bool isLinear, bool generateIrradiance) { PROFILE_RANGE(resource_parse, "processCubeTextureColorFromImage"); gpu::Texture* theTexture = nullptr; @@ -902,9 +859,8 @@ gpu::Texture* TextureUsage::processCubeTextureColorFromImage(const QImage& srcIm image = image.convertToFormat(QImage::Format_ARGB32); } - gpu::Element formatGPU; - gpu::Element formatMip; - defineColorTexelFormats(formatGPU, formatMip, image, isLinear); + gpu::Element formatGPU = gpu::Element::COLOR_COMPRESSED_SRGBA; + gpu::Element formatMip = gpu::Element::COLOR_COMPRESSED_SRGBA; // Find the layout of the cubemap in the 2D image // Use the original image size since processSourceImage may have altered the size / aspect ratio @@ -943,22 +899,26 @@ gpu::Texture* TextureUsage::processCubeTextureColorFromImage(const QImage& srcIm theTexture = gpu::Texture::createCube(formatGPU, faces[0].width(), gpu::Texture::MAX_NUM_MIPS, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR, gpu::Sampler::WRAP_CLAMP)); theTexture->setSource(srcImageName); theTexture->setStoredMipFormat(formatMip); - int f = 0; - for (auto& face : faces) { - theTexture->assignStoredMipFace(0, f, face.byteCount(), face.constBits()); - if (generateMips) { - generateFaceMips(theTexture, face, f); - } - f++; + + for (int face = 0; face < faces.size(); ++face) { + generateMips(theTexture, faces[face], true, false, false, false, face); } // Generate irradiance while we are at it if (generateIrradiance) { - PROFILE_RANGE(resource_parse, "generateIrradiance"); - theTexture->generateIrradiance(); - } + auto irradianceTexture = gpu::Texture::createCube(gpu::Element::COLOR_SRGBA_32, faces[0].width(), gpu::Texture::MAX_NUM_MIPS, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR, gpu::Sampler::WRAP_CLAMP)); + irradianceTexture->setSource(srcImageName); + irradianceTexture->setStoredMipFormat(gpu::Element::COLOR_SRGBA_32); + for (int face = 0; face < faces.size(); ++face) { + irradianceTexture->assignStoredMipFace(0, face, faces[face].byteCount(), faces[face].constBits()); + } - theTexture->setSource(srcImageName); + PROFILE_RANGE(resource_parse, "generateIrradiance"); + irradianceTexture->generateIrradiance(); + + auto irradiance = irradianceTexture->getIrradiance(); + theTexture->overrideIrradiance(irradiance); + } } } @@ -966,11 +926,11 @@ gpu::Texture* TextureUsage::processCubeTextureColorFromImage(const QImage& srcIm } gpu::Texture* TextureUsage::createCubeTextureFromImage(const QImage& srcImage, const std::string& srcImageName) { - return processCubeTextureColorFromImage(srcImage, srcImageName, false, true, true); + return processCubeTextureColorFromImage(srcImage, srcImageName, false, true); } gpu::Texture* TextureUsage::createCubeTextureFromImageWithoutIrradiance(const QImage& srcImage, const std::string& srcImageName) { - return processCubeTextureColorFromImage(srcImage, srcImageName, false, true, false); + return processCubeTextureColorFromImage(srcImage, srcImageName, false, false); } } // namespace image \ No newline at end of file diff --git a/libraries/image/src/image/Image.h b/libraries/image/src/image/Image.h index 5c3becf2af..391f871542 100644 --- a/libraries/image/src/image/Image.h +++ b/libraries/image/src/image/Image.h @@ -45,8 +45,8 @@ gpu::Texture* createLightmapTextureFromImage(const QImage& image, const std::str const QImage process2DImageColor(const QImage& srcImage, bool& validAlpha, bool& alphaAsMask); void defineColorTexelFormats(gpu::Element& formatGPU, gpu::Element& formatMip, const QImage& srcImage, bool isLinear); -gpu::Texture* process2DTextureColorFromImage(const QImage& srcImage, const std::string& srcImageName, bool isLinear, bool generateMips, bool isStrict = false); -gpu::Texture* processCubeTextureColorFromImage(const QImage& srcImage, const std::string& srcImageName, bool isLinear, bool generateMips, bool generateIrradiance); +gpu::Texture* process2DTextureColorFromImage(const QImage& srcImage, const std::string& srcImageName, bool isLinear, bool isStrict = false); +gpu::Texture* processCubeTextureColorFromImage(const QImage& srcImage, const std::string& srcImageName, bool isLinear, bool generateIrradiance); } // namespace TextureUsage diff --git a/tests/ktx/src/main.cpp b/tests/ktx/src/main.cpp index bd560a20f9..2be22a00c6 100644 --- a/tests/ktx/src/main.cpp +++ b/tests/ktx/src/main.cpp @@ -95,7 +95,7 @@ int main(int argc, char** argv) { QLoggingCategory::setFilterRules(LOG_FILTER_RULES); QImage image(TEST_IMAGE); - gpu::Texture* testTexture = image::TextureUsage::process2DTextureColorFromImage(image, TEST_IMAGE.toStdString(), true, false, true); + gpu::Texture* testTexture = image::TextureUsage::process2DTextureColorFromImage(image, TEST_IMAGE.toStdString(), true, true); auto ktxMemory = gpu::Texture::serialize(*testTexture); {