mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-08-08 13:38:30 +02:00
Merge pull request #11349 from Zvork/hdrcube
Under the hood support for HDR cube maps
This commit is contained in:
commit
c44efda978
11 changed files with 501 additions and 89 deletions
|
@ -19,6 +19,7 @@ bool GLTexelFormat::isCompressed() const {
|
||||||
case GL_COMPRESSED_RED_RGTC1:
|
case GL_COMPRESSED_RED_RGTC1:
|
||||||
case GL_COMPRESSED_RG_RGTC2:
|
case GL_COMPRESSED_RG_RGTC2:
|
||||||
case GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM:
|
case GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM:
|
||||||
|
case GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT:
|
||||||
return true;
|
return true;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
|
@ -94,6 +95,11 @@ GLenum GLTexelFormat::evalGLTexelFormatInternal(const gpu::Element& dstFormat) {
|
||||||
result = GL_R11F_G11F_B10F;
|
result = GL_R11F_G11F_B10F;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case gpu::RGB9E5:
|
||||||
|
// the type should be float
|
||||||
|
result = GL_RGB9_E5;
|
||||||
|
break;
|
||||||
|
|
||||||
case gpu::DEPTH:
|
case gpu::DEPTH:
|
||||||
result = GL_DEPTH_COMPONENT32;
|
result = GL_DEPTH_COMPONENT32;
|
||||||
switch (dstFormat.getType()) {
|
switch (dstFormat.getType()) {
|
||||||
|
@ -244,6 +250,9 @@ GLenum GLTexelFormat::evalGLTexelFormatInternal(const gpu::Element& dstFormat) {
|
||||||
case gpu::COMPRESSED_BC5_XY:
|
case gpu::COMPRESSED_BC5_XY:
|
||||||
result = GL_COMPRESSED_RG_RGTC2;
|
result = GL_COMPRESSED_RG_RGTC2;
|
||||||
break;
|
break;
|
||||||
|
case gpu::COMPRESSED_BC6_RGB:
|
||||||
|
result = GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT;
|
||||||
|
break;
|
||||||
case gpu::COMPRESSED_BC7_SRGBA:
|
case gpu::COMPRESSED_BC7_SRGBA:
|
||||||
result = GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM;
|
result = GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM;
|
||||||
break;
|
break;
|
||||||
|
@ -396,6 +405,9 @@ GLTexelFormat GLTexelFormat::evalGLTexelFormat(const Element& dstFormat, const E
|
||||||
case gpu::COMPRESSED_BC5_XY:
|
case gpu::COMPRESSED_BC5_XY:
|
||||||
texel.internalFormat = GL_COMPRESSED_RG_RGTC2;
|
texel.internalFormat = GL_COMPRESSED_RG_RGTC2;
|
||||||
break;
|
break;
|
||||||
|
case gpu::COMPRESSED_BC6_RGB:
|
||||||
|
texel.internalFormat = GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT;
|
||||||
|
break;
|
||||||
case gpu::COMPRESSED_BC7_SRGBA:
|
case gpu::COMPRESSED_BC7_SRGBA:
|
||||||
texel.internalFormat = GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM;
|
texel.internalFormat = GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM;
|
||||||
break;
|
break;
|
||||||
|
@ -495,10 +507,16 @@ GLTexelFormat GLTexelFormat::evalGLTexelFormat(const Element& dstFormat, const E
|
||||||
|
|
||||||
case gpu::R11G11B10:
|
case gpu::R11G11B10:
|
||||||
texel.format = GL_RGB;
|
texel.format = GL_RGB;
|
||||||
// the type should be float
|
texel.type = GL_UNSIGNED_INT_10F_11F_11F_REV;
|
||||||
texel.internalFormat = GL_R11F_G11F_B10F;
|
texel.internalFormat = GL_R11F_G11F_B10F;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case gpu::RGB9E5:
|
||||||
|
texel.format = GL_RGB;
|
||||||
|
texel.type = GL_UNSIGNED_INT_5_9_9_9_REV;
|
||||||
|
texel.internalFormat = GL_RGB9_E5;
|
||||||
|
break;
|
||||||
|
|
||||||
case gpu::DEPTH:
|
case gpu::DEPTH:
|
||||||
texel.format = GL_DEPTH_COMPONENT; // It's depth component to load it
|
texel.format = GL_DEPTH_COMPONENT; // It's depth component to load it
|
||||||
texel.internalFormat = GL_DEPTH_COMPONENT32;
|
texel.internalFormat = GL_DEPTH_COMPONENT32;
|
||||||
|
@ -694,6 +712,9 @@ GLTexelFormat GLTexelFormat::evalGLTexelFormat(const Element& dstFormat, const E
|
||||||
case gpu::COMPRESSED_BC5_XY:
|
case gpu::COMPRESSED_BC5_XY:
|
||||||
texel.internalFormat = GL_COMPRESSED_RG_RGTC2;
|
texel.internalFormat = GL_COMPRESSED_RG_RGTC2;
|
||||||
break;
|
break;
|
||||||
|
case gpu::COMPRESSED_BC6_RGB:
|
||||||
|
texel.internalFormat = GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT;
|
||||||
|
break;
|
||||||
case gpu::COMPRESSED_BC7_SRGBA:
|
case gpu::COMPRESSED_BC7_SRGBA:
|
||||||
texel.internalFormat = GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM;
|
texel.internalFormat = GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -114,6 +114,7 @@ Size GL41Texture::copyMipFaceLinesFromTexture(uint16_t mip, uint8_t face, const
|
||||||
case GL_COMPRESSED_RED_RGTC1:
|
case GL_COMPRESSED_RED_RGTC1:
|
||||||
case GL_COMPRESSED_RG_RGTC2:
|
case GL_COMPRESSED_RG_RGTC2:
|
||||||
case GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM:
|
case GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM:
|
||||||
|
case GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT:
|
||||||
glCompressedTexSubImage2D(_target, mip, 0, yOffset, size.x, size.y, internalFormat,
|
glCompressedTexSubImage2D(_target, mip, 0, yOffset, size.x, size.y, internalFormat,
|
||||||
static_cast<GLsizei>(sourceSize), sourcePointer);
|
static_cast<GLsizei>(sourceSize), sourcePointer);
|
||||||
break;
|
break;
|
||||||
|
@ -131,6 +132,7 @@ Size GL41Texture::copyMipFaceLinesFromTexture(uint16_t mip, uint8_t face, const
|
||||||
case GL_COMPRESSED_RED_RGTC1:
|
case GL_COMPRESSED_RED_RGTC1:
|
||||||
case GL_COMPRESSED_RG_RGTC2:
|
case GL_COMPRESSED_RG_RGTC2:
|
||||||
case GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM:
|
case GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM:
|
||||||
|
case GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT:
|
||||||
glCompressedTexSubImage2D(target, mip, 0, yOffset, size.x, size.y, internalFormat,
|
glCompressedTexSubImage2D(target, mip, 0, yOffset, size.x, size.y, internalFormat,
|
||||||
static_cast<GLsizei>(sourceSize), sourcePointer);
|
static_cast<GLsizei>(sourceSize), sourcePointer);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -143,6 +143,7 @@ Size GL45Texture::copyMipFaceLinesFromTexture(uint16_t mip, uint8_t face, const
|
||||||
case GL_COMPRESSED_RED_RGTC1:
|
case GL_COMPRESSED_RED_RGTC1:
|
||||||
case GL_COMPRESSED_RG_RGTC2:
|
case GL_COMPRESSED_RG_RGTC2:
|
||||||
case GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM:
|
case GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM:
|
||||||
|
case GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT:
|
||||||
glCompressedTextureSubImage2D(_id, mip, 0, yOffset, size.x, size.y, internalFormat,
|
glCompressedTextureSubImage2D(_id, mip, 0, yOffset, size.x, size.y, internalFormat,
|
||||||
static_cast<GLsizei>(sourceSize), sourcePointer);
|
static_cast<GLsizei>(sourceSize), sourcePointer);
|
||||||
break;
|
break;
|
||||||
|
@ -158,6 +159,7 @@ Size GL45Texture::copyMipFaceLinesFromTexture(uint16_t mip, uint8_t face, const
|
||||||
case GL_COMPRESSED_RED_RGTC1:
|
case GL_COMPRESSED_RED_RGTC1:
|
||||||
case GL_COMPRESSED_RG_RGTC2:
|
case GL_COMPRESSED_RG_RGTC2:
|
||||||
case GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM:
|
case GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM:
|
||||||
|
case GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT:
|
||||||
if (glCompressedTextureSubImage2DEXT) {
|
if (glCompressedTextureSubImage2DEXT) {
|
||||||
auto target = GLTexture::CUBE_FACE_LAYOUT[face];
|
auto target = GLTexture::CUBE_FACE_LAYOUT[face];
|
||||||
glCompressedTextureSubImage2DEXT(_id, target, mip, 0, yOffset, size.x, size.y, internalFormat,
|
glCompressedTextureSubImage2DEXT(_id, target, mip, 0, yOffset, size.x, size.y, internalFormat,
|
||||||
|
|
|
@ -24,11 +24,13 @@ const Element Element::COLOR_COMPRESSED_SRGB { TILE4x4, COMPRESSED, COMPRESSED_B
|
||||||
const Element Element::COLOR_COMPRESSED_SRGBA_MASK { TILE4x4, COMPRESSED, COMPRESSED_BC1_SRGBA };
|
const Element Element::COLOR_COMPRESSED_SRGBA_MASK { TILE4x4, COMPRESSED, COMPRESSED_BC1_SRGBA };
|
||||||
const Element Element::COLOR_COMPRESSED_SRGBA { TILE4x4, COMPRESSED, COMPRESSED_BC3_SRGBA };
|
const Element Element::COLOR_COMPRESSED_SRGBA { TILE4x4, COMPRESSED, COMPRESSED_BC3_SRGBA };
|
||||||
const Element Element::COLOR_COMPRESSED_XY { TILE4x4, COMPRESSED, COMPRESSED_BC5_XY };
|
const Element Element::COLOR_COMPRESSED_XY { TILE4x4, COMPRESSED, COMPRESSED_BC5_XY };
|
||||||
const Element Element::COLOR_COMPRESSED_SRGBA_HIGH { TILE4x4, COMPRESSED, COMPRESSED_BC7_SRGBA };
|
const Element Element::COLOR_COMPRESSED_SRGBA_HIGH{ TILE4x4, COMPRESSED, COMPRESSED_BC7_SRGBA };
|
||||||
|
const Element Element::COLOR_COMPRESSED_HDR_RGB{ TILE4x4, COMPRESSED, COMPRESSED_BC6_RGB };
|
||||||
|
|
||||||
const Element Element::VEC2NU8_XY{ VEC2, NUINT8, XY };
|
const Element Element::VEC2NU8_XY{ VEC2, NUINT8, XY };
|
||||||
|
|
||||||
const Element Element::COLOR_R11G11B10{ SCALAR, FLOAT, R11G11B10 };
|
const Element Element::COLOR_R11G11B10{ SCALAR, FLOAT, R11G11B10 };
|
||||||
|
const Element Element::COLOR_RGB9E5{ SCALAR, FLOAT, RGB9E5 };
|
||||||
const Element Element::VEC4F_COLOR_RGBA{ VEC4, FLOAT, RGBA };
|
const Element Element::VEC4F_COLOR_RGBA{ VEC4, FLOAT, RGBA };
|
||||||
const Element Element::VEC2F_UV{ VEC2, FLOAT, UV };
|
const Element Element::VEC2F_UV{ VEC2, FLOAT, UV };
|
||||||
const Element Element::VEC2F_XY{ VEC2, FLOAT, XY };
|
const Element Element::VEC2F_XY{ VEC2, FLOAT, XY };
|
||||||
|
|
|
@ -187,11 +187,13 @@ enum Semantic : uint8_t {
|
||||||
COMPRESSED_BC3_SRGBA,
|
COMPRESSED_BC3_SRGBA,
|
||||||
COMPRESSED_BC4_RED,
|
COMPRESSED_BC4_RED,
|
||||||
COMPRESSED_BC5_XY,
|
COMPRESSED_BC5_XY,
|
||||||
|
COMPRESSED_BC6_RGB,
|
||||||
COMPRESSED_BC7_SRGBA,
|
COMPRESSED_BC7_SRGBA,
|
||||||
|
|
||||||
_LAST_COMPRESSED,
|
_LAST_COMPRESSED,
|
||||||
|
|
||||||
R11G11B10,
|
R11G11B10,
|
||||||
|
RGB9E5,
|
||||||
|
|
||||||
UNIFORM,
|
UNIFORM,
|
||||||
UNIFORM_BUFFER,
|
UNIFORM_BUFFER,
|
||||||
|
@ -240,11 +242,13 @@ static const int SEMANTIC_SIZE_FACTOR[NUM_SEMANTICS] = {
|
||||||
16, //COMPRESSED_BC3_SRGBA, 1 byte/pixel * 4x4 pixels = 16 bytes
|
16, //COMPRESSED_BC3_SRGBA, 1 byte/pixel * 4x4 pixels = 16 bytes
|
||||||
8, //COMPRESSED_BC4_RED, 1/2 byte/pixel * 4x4 pixels = 8 bytes
|
8, //COMPRESSED_BC4_RED, 1/2 byte/pixel * 4x4 pixels = 8 bytes
|
||||||
16, //COMPRESSED_BC5_XY, 1 byte/pixel * 4x4 pixels = 16 bytes
|
16, //COMPRESSED_BC5_XY, 1 byte/pixel * 4x4 pixels = 16 bytes
|
||||||
|
16, //COMPRESSED_BC6_RGB, 1 byte/pixel * 4x4 pixels = 16 bytes
|
||||||
16, //COMPRESSED_BC7_SRGBA, 1 byte/pixel * 4x4 pixels = 16 bytes
|
16, //COMPRESSED_BC7_SRGBA, 1 byte/pixel * 4x4 pixels = 16 bytes
|
||||||
|
|
||||||
1, //_LAST_COMPRESSED,
|
1, //_LAST_COMPRESSED,
|
||||||
|
|
||||||
1, //R11G11B10,
|
1, //R11G11B10,
|
||||||
|
1, //RGB9E5
|
||||||
|
|
||||||
1, //UNIFORM,
|
1, //UNIFORM,
|
||||||
1, //UNIFORM_BUFFER,
|
1, //UNIFORM_BUFFER,
|
||||||
|
@ -306,12 +310,14 @@ public:
|
||||||
static const Element COLOR_BGRA_32;
|
static const Element COLOR_BGRA_32;
|
||||||
static const Element COLOR_SBGRA_32;
|
static const Element COLOR_SBGRA_32;
|
||||||
static const Element COLOR_R11G11B10;
|
static const Element COLOR_R11G11B10;
|
||||||
|
static const Element COLOR_RGB9E5;
|
||||||
static const Element COLOR_COMPRESSED_RED;
|
static const Element COLOR_COMPRESSED_RED;
|
||||||
static const Element COLOR_COMPRESSED_SRGB;
|
static const Element COLOR_COMPRESSED_SRGB;
|
||||||
static const Element COLOR_COMPRESSED_SRGBA_MASK;
|
static const Element COLOR_COMPRESSED_SRGBA_MASK;
|
||||||
static const Element COLOR_COMPRESSED_SRGBA;
|
static const Element COLOR_COMPRESSED_SRGBA;
|
||||||
static const Element COLOR_COMPRESSED_XY;
|
static const Element COLOR_COMPRESSED_XY;
|
||||||
static const Element COLOR_COMPRESSED_SRGBA_HIGH;
|
static const Element COLOR_COMPRESSED_SRGBA_HIGH;
|
||||||
|
static const Element COLOR_COMPRESSED_HDR_RGB;
|
||||||
static const Element VEC2NU8_XY;
|
static const Element VEC2NU8_XY;
|
||||||
static const Element VEC4F_COLOR_RGBA;
|
static const Element VEC4F_COLOR_RGBA;
|
||||||
static const Element VEC2F_UV;
|
static const Element VEC2F_UV;
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
|
|
||||||
#include <glm/gtc/constants.hpp>
|
#include <glm/gtc/constants.hpp>
|
||||||
#include <glm/gtx/component_wise.hpp>
|
#include <glm/gtx/component_wise.hpp>
|
||||||
|
#include <glm/gtc/packing.hpp>
|
||||||
|
|
||||||
#include <QtCore/QDebug>
|
#include <QtCore/QDebug>
|
||||||
#include <QtCore/QThread>
|
#include <QtCore/QThread>
|
||||||
|
@ -683,6 +684,21 @@ bool sphericalHarmonicsFromTexture(const gpu::Texture& cubeTexture, std::vector<
|
||||||
|
|
||||||
PROFILE_RANGE(render_gpu, "sphericalHarmonicsFromTexture");
|
PROFILE_RANGE(render_gpu, "sphericalHarmonicsFromTexture");
|
||||||
|
|
||||||
|
auto mipFormat = cubeTexture.getStoredMipFormat();
|
||||||
|
std::function<glm::vec3(uint32)> unpackFunc;
|
||||||
|
|
||||||
|
switch (mipFormat.getSemantic()) {
|
||||||
|
case gpu::R11G11B10:
|
||||||
|
unpackFunc = glm::unpackF2x11_1x10;
|
||||||
|
break;
|
||||||
|
case gpu::RGB9E5:
|
||||||
|
unpackFunc = glm::unpackF3x9_E1x5;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assert(false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
const uint sqOrder = order*order;
|
const uint sqOrder = order*order;
|
||||||
|
|
||||||
// allocate memory for calculations
|
// allocate memory for calculations
|
||||||
|
@ -716,17 +732,7 @@ bool sphericalHarmonicsFromTexture(const gpu::Texture& cubeTexture, std::vector<
|
||||||
for(int face=0; face < gpu::Texture::NUM_CUBE_FACES; face++) {
|
for(int face=0; face < gpu::Texture::NUM_CUBE_FACES; face++) {
|
||||||
PROFILE_RANGE(render_gpu, "ProcessFace");
|
PROFILE_RANGE(render_gpu, "ProcessFace");
|
||||||
|
|
||||||
auto mipFormat = cubeTexture.getStoredMipFormat();
|
auto data = reinterpret_cast<const uint32*>( cubeTexture.accessStoredMipFace(0, face)->readData() );
|
||||||
auto numComponents = mipFormat.getScalarCount();
|
|
||||||
int roffset { 0 };
|
|
||||||
int goffset { 1 };
|
|
||||||
int boffset { 2 };
|
|
||||||
if ((mipFormat.getSemantic() == gpu::BGRA) || (mipFormat.getSemantic() == gpu::SBGRA)) {
|
|
||||||
roffset = 2;
|
|
||||||
boffset = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto data = cubeTexture.accessStoredMipFace(0, face)->readData();
|
|
||||||
if (data == nullptr) {
|
if (data == nullptr) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -806,29 +812,24 @@ bool sphericalHarmonicsFromTexture(const gpu::Texture& cubeTexture, std::vector<
|
||||||
|
|
||||||
// index of texel in texture
|
// index of texel in texture
|
||||||
|
|
||||||
// get color from texture and map to range [0, 1]
|
// get color from texture
|
||||||
float red { 0.0f };
|
glm::vec3 color{ 0.0f, 0.0f, 0.0f };
|
||||||
float green { 0.0f };
|
|
||||||
float blue { 0.0f };
|
|
||||||
for (int i = 0; i < stride; ++i) {
|
for (int i = 0; i < stride; ++i) {
|
||||||
for (int j = 0; j < stride; ++j) {
|
for (int j = 0; j < stride; ++j) {
|
||||||
int k = (int)(x + i - halfStride + (y + j - halfStride) * width) * numComponents;
|
int k = (int)(x + i - halfStride + (y + j - halfStride) * width);
|
||||||
red += ColorUtils::sRGB8ToLinearFloat(data[k + roffset]);
|
color += unpackFunc(data[k]);
|
||||||
green += ColorUtils::sRGB8ToLinearFloat(data[k + goffset]);
|
|
||||||
blue += ColorUtils::sRGB8ToLinearFloat(data[k + boffset]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
glm::vec3 clr(red, green, blue);
|
|
||||||
|
|
||||||
// scale color and add to previously accumulated coefficients
|
// scale color and add to previously accumulated coefficients
|
||||||
// red
|
// red
|
||||||
sphericalHarmonicsScale(shBuffB.data(), order, shBuff.data(), clr.r * fDiffSolid);
|
sphericalHarmonicsScale(shBuffB.data(), order, shBuff.data(), color.r * fDiffSolid);
|
||||||
sphericalHarmonicsAdd(resultR.data(), order, resultR.data(), shBuffB.data());
|
sphericalHarmonicsAdd(resultR.data(), order, resultR.data(), shBuffB.data());
|
||||||
// green
|
// green
|
||||||
sphericalHarmonicsScale(shBuffB.data(), order, shBuff.data(), clr.g * fDiffSolid);
|
sphericalHarmonicsScale(shBuffB.data(), order, shBuff.data(), color.g * fDiffSolid);
|
||||||
sphericalHarmonicsAdd(resultG.data(), order, resultG.data(), shBuffB.data());
|
sphericalHarmonicsAdd(resultG.data(), order, resultG.data(), shBuffB.data());
|
||||||
// blue
|
// blue
|
||||||
sphericalHarmonicsScale(shBuffB.data(), order, shBuff.data(), clr.b * fDiffSolid);
|
sphericalHarmonicsScale(shBuffB.data(), order, shBuff.data(), color.b * fDiffSolid);
|
||||||
sphericalHarmonicsAdd(resultB.data(), order, resultB.data(), shBuffB.data());
|
sphericalHarmonicsAdd(resultB.data(), order, resultB.data(), shBuffB.data());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -515,8 +515,6 @@ TexturePointer Texture::build(const ktx::KTXDescriptor& descriptor) {
|
||||||
return texture;
|
return texture;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
TexturePointer Texture::unserialize(const cache::FilePointer& cacheEntry) {
|
TexturePointer Texture::unserialize(const cache::FilePointer& cacheEntry) {
|
||||||
std::unique_ptr<ktx::KTX> ktxPointer = ktx::KTX::create(std::make_shared<storage::FileStorage>(cacheEntry->getFilepath().c_str()));
|
std::unique_ptr<ktx::KTX> ktxPointer = ktx::KTX::create(std::make_shared<storage::FileStorage>(cacheEntry->getFilepath().c_str()));
|
||||||
if (!ktxPointer) {
|
if (!ktxPointer) {
|
||||||
|
@ -536,7 +534,7 @@ TexturePointer Texture::unserialize(const std::string& ktxfile) {
|
||||||
if (!ktxPointer) {
|
if (!ktxPointer) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto texture = build(ktxPointer->toDescriptor());
|
auto texture = build(ktxPointer->toDescriptor());
|
||||||
if (texture) {
|
if (texture) {
|
||||||
texture->setKtxBacking(ktxfile);
|
texture->setKtxBacking(ktxfile);
|
||||||
|
@ -570,6 +568,12 @@ bool Texture::evalKTXFormat(const Element& mipFormat, const Element& texelFormat
|
||||||
header.setCompressed(ktx::GLInternalFormat::COMPRESSED_RG_RGTC2, ktx::GLBaseInternalFormat::RG);
|
header.setCompressed(ktx::GLInternalFormat::COMPRESSED_RG_RGTC2, ktx::GLBaseInternalFormat::RG);
|
||||||
} else if (texelFormat == Format::COLOR_COMPRESSED_SRGBA_HIGH && mipFormat == Format::COLOR_COMPRESSED_SRGBA_HIGH) {
|
} else if (texelFormat == Format::COLOR_COMPRESSED_SRGBA_HIGH && mipFormat == Format::COLOR_COMPRESSED_SRGBA_HIGH) {
|
||||||
header.setCompressed(ktx::GLInternalFormat::COMPRESSED_SRGB_ALPHA_BPTC_UNORM, ktx::GLBaseInternalFormat::RGBA);
|
header.setCompressed(ktx::GLInternalFormat::COMPRESSED_SRGB_ALPHA_BPTC_UNORM, ktx::GLBaseInternalFormat::RGBA);
|
||||||
|
} else if (texelFormat == Format::COLOR_COMPRESSED_HDR_RGB && mipFormat == Format::COLOR_COMPRESSED_HDR_RGB) {
|
||||||
|
header.setCompressed(ktx::GLInternalFormat::COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT, ktx::GLBaseInternalFormat::RGB);
|
||||||
|
} else if (texelFormat == Format::COLOR_RGB9E5 && mipFormat == Format::COLOR_RGB9E5) {
|
||||||
|
header.setUncompressed(ktx::GLType::UNSIGNED_INT_5_9_9_9_REV, 1, ktx::GLFormat::RGB, ktx::GLInternalFormat::RGB9_E5, ktx::GLBaseInternalFormat::RGB);
|
||||||
|
} else if (texelFormat == Format::COLOR_R11G11B10 && mipFormat == Format::COLOR_R11G11B10) {
|
||||||
|
header.setUncompressed(ktx::GLType::UNSIGNED_INT_10F_11F_11F_REV, 1, ktx::GLFormat::RGB, ktx::GLInternalFormat::R11F_G11F_B10F, ktx::GLBaseInternalFormat::RGB);
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -612,6 +616,12 @@ bool Texture::evalTextureFormat(const ktx::Header& header, Element& mipFormat, E
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
} else if (header.getGLFormat() == ktx::GLFormat::RGB && header.getGLType() == ktx::GLType::UNSIGNED_INT_10F_11F_11F_REV) {
|
||||||
|
mipFormat = Format::COLOR_R11G11B10;
|
||||||
|
texelFormat = Format::COLOR_R11G11B10;
|
||||||
|
} else if (header.getGLFormat() == ktx::GLFormat::RGB && header.getGLType() == ktx::GLType::UNSIGNED_INT_5_9_9_9_REV) {
|
||||||
|
mipFormat = Format::COLOR_RGB9E5;
|
||||||
|
texelFormat = Format::COLOR_RGB9E5;
|
||||||
} else if (header.isCompressed()) {
|
} else if (header.isCompressed()) {
|
||||||
if (header.getGLInternaFormat() == ktx::GLInternalFormat::COMPRESSED_SRGB_S3TC_DXT1_EXT) {
|
if (header.getGLInternaFormat() == ktx::GLInternalFormat::COMPRESSED_SRGB_S3TC_DXT1_EXT) {
|
||||||
mipFormat = Format::COLOR_COMPRESSED_SRGB;
|
mipFormat = Format::COLOR_COMPRESSED_SRGB;
|
||||||
|
@ -631,6 +641,9 @@ bool Texture::evalTextureFormat(const ktx::Header& header, Element& mipFormat, E
|
||||||
} else if (header.getGLInternaFormat() == ktx::GLInternalFormat::COMPRESSED_SRGB_ALPHA_BPTC_UNORM) {
|
} else if (header.getGLInternaFormat() == ktx::GLInternalFormat::COMPRESSED_SRGB_ALPHA_BPTC_UNORM) {
|
||||||
mipFormat = Format::COLOR_COMPRESSED_SRGBA_HIGH;
|
mipFormat = Format::COLOR_COMPRESSED_SRGBA_HIGH;
|
||||||
texelFormat = Format::COLOR_COMPRESSED_SRGBA_HIGH;
|
texelFormat = Format::COLOR_COMPRESSED_SRGBA_HIGH;
|
||||||
|
} else if (header.getGLInternaFormat() == ktx::GLInternalFormat::COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT) {
|
||||||
|
mipFormat = Format::COLOR_COMPRESSED_HDR_RGB;
|
||||||
|
texelFormat = Format::COLOR_COMPRESSED_HDR_RGB;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,9 +11,10 @@
|
||||||
|
|
||||||
#include "Image.h"
|
#include "Image.h"
|
||||||
|
|
||||||
|
#include <nvtt/nvtt.h>
|
||||||
|
#include <glm/gtc/packing.hpp>
|
||||||
|
|
||||||
#include <QtCore/QtGlobal>
|
#include <QtCore/QtGlobal>
|
||||||
|
|
||||||
|
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
#include <QImage>
|
#include <QImage>
|
||||||
#include <QBuffer>
|
#include <QBuffer>
|
||||||
|
@ -42,6 +43,8 @@ bool DEV_DECIMATE_TEXTURES = false;
|
||||||
std::atomic<size_t> DECIMATED_TEXTURE_COUNT{ 0 };
|
std::atomic<size_t> DECIMATED_TEXTURE_COUNT{ 0 };
|
||||||
std::atomic<size_t> RECTIFIED_TEXTURE_COUNT{ 0 };
|
std::atomic<size_t> RECTIFIED_TEXTURE_COUNT{ 0 };
|
||||||
|
|
||||||
|
static const auto HDR_FORMAT = gpu::Element::COLOR_R11G11B10;
|
||||||
|
|
||||||
static std::atomic<bool> compressColorTextures { false };
|
static std::atomic<bool> compressColorTextures { false };
|
||||||
static std::atomic<bool> compressNormalTextures { false };
|
static std::atomic<bool> compressNormalTextures { false };
|
||||||
static std::atomic<bool> compressGrayscaleTextures { false };
|
static std::atomic<bool> compressGrayscaleTextures { false };
|
||||||
|
@ -71,6 +74,10 @@ glm::uvec2 rectifyToSparseSize(const glm::uvec2& size) {
|
||||||
|
|
||||||
namespace image {
|
namespace image {
|
||||||
|
|
||||||
|
enum {
|
||||||
|
QIMAGE_HDR_FORMAT = QImage::Format_RGB30
|
||||||
|
};
|
||||||
|
|
||||||
TextureUsage::TextureLoader TextureUsage::getTextureLoaderForType(Type type, const QVariantMap& options) {
|
TextureUsage::TextureLoader TextureUsage::getTextureLoaderForType(Type type, const QVariantMap& options) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case ALBEDO_TEXTURE:
|
case ALBEDO_TEXTURE:
|
||||||
|
@ -213,6 +220,25 @@ void setCubeTexturesCompressionEnabled(bool enabled) {
|
||||||
compressCubeTextures.store(enabled);
|
compressCubeTextures.store(enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static float denormalize(float value, const float minValue) {
|
||||||
|
return value < minValue ? 0.0f : value;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 packR11G11B10F(const glm::vec3& color) {
|
||||||
|
// Denormalize else unpacking gives high and incorrect values
|
||||||
|
// See https://www.khronos.org/opengl/wiki/Small_Float_Formats for this min value
|
||||||
|
static const auto minValue = 6.10e-5f;
|
||||||
|
static const auto maxValue = 6.50e4f;
|
||||||
|
glm::vec3 ucolor;
|
||||||
|
ucolor.r = denormalize(color.r, minValue);
|
||||||
|
ucolor.g = denormalize(color.g, minValue);
|
||||||
|
ucolor.b = denormalize(color.b, minValue);
|
||||||
|
ucolor.r = std::min(ucolor.r, maxValue);
|
||||||
|
ucolor.g = std::min(ucolor.g, maxValue);
|
||||||
|
ucolor.b = std::min(ucolor.b, maxValue);
|
||||||
|
return glm::packF2x11_1x10(ucolor);
|
||||||
|
}
|
||||||
|
|
||||||
gpu::TexturePointer processImage(const QByteArray& content, const std::string& filename,
|
gpu::TexturePointer processImage(const QByteArray& content, const std::string& filename,
|
||||||
int maxNumPixels, TextureUsage::Type textureType,
|
int maxNumPixels, TextureUsage::Type textureType,
|
||||||
const std::atomic<bool>& abortProcessing) {
|
const std::atomic<bool>& abortProcessing) {
|
||||||
|
@ -270,8 +296,6 @@ gpu::TexturePointer processImage(const QByteArray& content, const std::string& f
|
||||||
return texture;
|
return texture;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
QImage processSourceImage(const QImage& srcImage, bool cubemap) {
|
QImage processSourceImage(const QImage& srcImage, bool cubemap) {
|
||||||
PROFILE_RANGE(resource_parse, "processSourceImage");
|
PROFILE_RANGE(resource_parse, "processSourceImage");
|
||||||
const glm::uvec2 srcImageSize = toGlm(srcImage.size());
|
const glm::uvec2 srcImageSize = toGlm(srcImage.size());
|
||||||
|
@ -303,8 +327,8 @@ QImage processSourceImage(const QImage& srcImage, bool cubemap) {
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(NVTT_API)
|
#if defined(NVTT_API)
|
||||||
struct MyOutputHandler : public nvtt::OutputHandler {
|
struct OutputHandler : public nvtt::OutputHandler {
|
||||||
MyOutputHandler(gpu::Texture* texture, int face) : _texture(texture), _face(face) {}
|
OutputHandler(gpu::Texture* texture, int face) : _texture(texture), _face(face) {}
|
||||||
|
|
||||||
virtual void beginImage(int size, int width, int height, int depth, int face, int miplevel) override {
|
virtual void beginImage(int size, int width, int height, int depth, int face, int miplevel) override {
|
||||||
_size = size;
|
_size = size;
|
||||||
|
@ -313,12 +337,14 @@ struct MyOutputHandler : public nvtt::OutputHandler {
|
||||||
_data = static_cast<gpu::Byte*>(malloc(size));
|
_data = static_cast<gpu::Byte*>(malloc(size));
|
||||||
_current = _data;
|
_current = _data;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool writeData(const void* data, int size) override {
|
virtual bool writeData(const void* data, int size) override {
|
||||||
assert(_current + size <= _data + _size);
|
assert(_current + size <= _data + _size);
|
||||||
memcpy(_current, data, size);
|
memcpy(_current, data, size);
|
||||||
_current += size;
|
_current += size;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void endImage() override {
|
virtual void endImage() override {
|
||||||
if (_face >= 0) {
|
if (_face >= 0) {
|
||||||
_texture->assignStoredMipFace(_miplevel, _face, _size, static_cast<const gpu::Byte*>(_data));
|
_texture->assignStoredMipFace(_miplevel, _face, _size, static_cast<const gpu::Byte*>(_data));
|
||||||
|
@ -336,6 +362,51 @@ struct MyOutputHandler : public nvtt::OutputHandler {
|
||||||
int _size = 0;
|
int _size = 0;
|
||||||
int _face = -1;
|
int _face = -1;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct PackedFloatOutputHandler : public OutputHandler {
|
||||||
|
PackedFloatOutputHandler(gpu::Texture* texture, int face, gpu::Element format) : OutputHandler(texture, face) {
|
||||||
|
if (format == gpu::Element::COLOR_RGB9E5) {
|
||||||
|
_packFunc = glm::packF3x9_E1x5;
|
||||||
|
} else if (format == gpu::Element::COLOR_R11G11B10) {
|
||||||
|
_packFunc = packR11G11B10F;
|
||||||
|
} else {
|
||||||
|
qCWarning(imagelogging) << "Unknown handler format";
|
||||||
|
Q_UNREACHABLE();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void beginImage(int size, int width, int height, int depth, int face, int miplevel) override {
|
||||||
|
// Divide by 3 because we will compress from 3*floats to 1 uint32
|
||||||
|
OutputHandler::beginImage(size / 3, width, height, depth, face, miplevel);
|
||||||
|
}
|
||||||
|
virtual bool writeData(const void* data, int size) override {
|
||||||
|
// Expecting to write multiple of floats
|
||||||
|
if (_packFunc) {
|
||||||
|
assert((size % sizeof(float)) == 0);
|
||||||
|
auto floatCount = size / sizeof(float);
|
||||||
|
const float* floatBegin = (const float*)data;
|
||||||
|
const float* floatEnd = floatBegin + floatCount;
|
||||||
|
|
||||||
|
while (floatBegin < floatEnd) {
|
||||||
|
_pixel[_coordIndex] = *floatBegin;
|
||||||
|
floatBegin++;
|
||||||
|
_coordIndex++;
|
||||||
|
if (_coordIndex == 3) {
|
||||||
|
uint32 packedRGB = _packFunc(_pixel);
|
||||||
|
_coordIndex = 0;
|
||||||
|
OutputHandler::writeData(&packedRGB, sizeof(packedRGB));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::function<uint32(const glm::vec3&)> _packFunc;
|
||||||
|
glm::vec3 _pixel;
|
||||||
|
int _coordIndex{ 0 };
|
||||||
|
};
|
||||||
|
|
||||||
struct MyErrorHandler : public nvtt::ErrorHandler {
|
struct MyErrorHandler : public nvtt::ErrorHandler {
|
||||||
virtual void error(nvtt::Error e) override {
|
virtual void error(nvtt::Error e) override {
|
||||||
qCWarning(imagelogging) << "Texture compression error:" << nvtt::errorString(e);
|
qCWarning(imagelogging) << "Texture compression error:" << nvtt::errorString(e);
|
||||||
|
@ -343,10 +414,115 @@ struct MyErrorHandler : public nvtt::ErrorHandler {
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void generateMips(gpu::Texture* texture, QImage& image, const std::atomic<bool>& abortProcessing = false, int face = -1) {
|
class SequentialTaskDispatcher : public nvtt::TaskDispatcher {
|
||||||
#if CPU_MIPMAPS
|
public:
|
||||||
PROFILE_RANGE(resource_parse, "generateMips");
|
SequentialTaskDispatcher(const std::atomic<bool>& abortProcessing) : _abortProcessing(abortProcessing) {};
|
||||||
|
|
||||||
|
const std::atomic<bool>& _abortProcessing;
|
||||||
|
|
||||||
|
virtual void dispatch(nvtt::Task* task, void* context, int count) override {
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
if (!_abortProcessing.load()) {
|
||||||
|
task(context, i);
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void generateHDRMips(gpu::Texture* texture, const QImage& image, const std::atomic<bool>& abortProcessing, int face) {
|
||||||
|
assert(image.format() == QIMAGE_HDR_FORMAT);
|
||||||
|
|
||||||
|
const int width = image.width(), height = image.height();
|
||||||
|
std::vector<glm::vec4> data;
|
||||||
|
std::vector<glm::vec4>::iterator dataIt;
|
||||||
|
auto mipFormat = texture->getStoredMipFormat();
|
||||||
|
std::function<glm::vec3(uint32)> unpackFunc;
|
||||||
|
|
||||||
|
nvtt::TextureType textureType = nvtt::TextureType_2D;
|
||||||
|
nvtt::InputFormat inputFormat = nvtt::InputFormat_RGBA_32F;
|
||||||
|
nvtt::WrapMode wrapMode = nvtt::WrapMode_Mirror;
|
||||||
|
nvtt::RoundMode roundMode = nvtt::RoundMode_None;
|
||||||
|
nvtt::AlphaMode alphaMode = nvtt::AlphaMode_None;
|
||||||
|
|
||||||
|
nvtt::CompressionOptions compressionOptions;
|
||||||
|
compressionOptions.setQuality(nvtt::Quality_Production);
|
||||||
|
|
||||||
|
if (mipFormat == gpu::Element::COLOR_COMPRESSED_HDR_RGB) {
|
||||||
|
compressionOptions.setFormat(nvtt::Format_BC6);
|
||||||
|
} else if (mipFormat == gpu::Element::COLOR_RGB9E5) {
|
||||||
|
compressionOptions.setFormat(nvtt::Format_RGB);
|
||||||
|
compressionOptions.setPixelType(nvtt::PixelType_Float);
|
||||||
|
compressionOptions.setPixelFormat(32, 32, 32, 0);
|
||||||
|
} else if (mipFormat == gpu::Element::COLOR_R11G11B10) {
|
||||||
|
compressionOptions.setFormat(nvtt::Format_RGB);
|
||||||
|
compressionOptions.setPixelType(nvtt::PixelType_Float);
|
||||||
|
compressionOptions.setPixelFormat(32, 32, 32, 0);
|
||||||
|
} else {
|
||||||
|
qCWarning(imagelogging) << "Unknown mip format";
|
||||||
|
Q_UNREACHABLE();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (HDR_FORMAT == gpu::Element::COLOR_RGB9E5) {
|
||||||
|
unpackFunc = glm::unpackF3x9_E1x5;
|
||||||
|
} else if (HDR_FORMAT == gpu::Element::COLOR_R11G11B10) {
|
||||||
|
unpackFunc = glm::unpackF2x11_1x10;
|
||||||
|
} else {
|
||||||
|
qCWarning(imagelogging) << "Unknown HDR encoding format in QImage";
|
||||||
|
Q_UNREACHABLE();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
data.resize(width*height);
|
||||||
|
dataIt = data.begin();
|
||||||
|
for (auto lineNb = 0; lineNb < height; lineNb++) {
|
||||||
|
const uint32* srcPixelIt = reinterpret_cast<const uint32*>( image.constScanLine(lineNb) );
|
||||||
|
const uint32* srcPixelEnd = srcPixelIt + width;
|
||||||
|
|
||||||
|
while (srcPixelIt < srcPixelEnd) {
|
||||||
|
*dataIt = glm::vec4(unpackFunc(*srcPixelIt), 1.0f);
|
||||||
|
++srcPixelIt;
|
||||||
|
++dataIt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert(dataIt == data.end());
|
||||||
|
|
||||||
|
nvtt::OutputOptions outputOptions;
|
||||||
|
outputOptions.setOutputHeader(false);
|
||||||
|
std::unique_ptr<nvtt::OutputHandler> outputHandler;
|
||||||
|
MyErrorHandler errorHandler;
|
||||||
|
outputOptions.setErrorHandler(&errorHandler);
|
||||||
|
nvtt::Context context;
|
||||||
|
int mipLevel = 0;
|
||||||
|
|
||||||
|
if (mipFormat == gpu::Element::COLOR_RGB9E5 || mipFormat == gpu::Element::COLOR_R11G11B10) {
|
||||||
|
// Don't use NVTT (at least version 2.1) as it outputs wrong RGB9E5 and R11G11B10F values from floats
|
||||||
|
outputHandler.reset(new PackedFloatOutputHandler(texture, face, mipFormat));
|
||||||
|
} else {
|
||||||
|
outputHandler.reset( new OutputHandler(texture, face) );
|
||||||
|
}
|
||||||
|
|
||||||
|
outputOptions.setOutputHandler(outputHandler.get());
|
||||||
|
|
||||||
|
nvtt::Surface surface;
|
||||||
|
surface.setImage(inputFormat, width, height, 1, &(*data.begin()));
|
||||||
|
surface.setAlphaMode(alphaMode);
|
||||||
|
surface.setWrapMode(wrapMode);
|
||||||
|
|
||||||
|
SequentialTaskDispatcher dispatcher(abortProcessing);
|
||||||
|
nvtt::Compressor compressor;
|
||||||
|
context.setTaskDispatcher(&dispatcher);
|
||||||
|
|
||||||
|
context.compress(surface, face, mipLevel++, compressionOptions, outputOptions);
|
||||||
|
while (surface.canMakeNextMipmap() && !abortProcessing.load()) {
|
||||||
|
surface.buildNextMipmap(nvtt::MipmapFilter_Box);
|
||||||
|
context.compress(surface, face, mipLevel++, compressionOptions, outputOptions);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void generateLDRMips(gpu::Texture* texture, QImage& image, const std::atomic<bool>& abortProcessing, int face) {
|
||||||
if (image.format() != QImage::Format_ARGB32) {
|
if (image.format() != QImage::Format_ARGB32) {
|
||||||
image = image.convertToFormat(QImage::Format_ARGB32);
|
image = image.convertToFormat(QImage::Format_ARGB32);
|
||||||
}
|
}
|
||||||
|
@ -400,10 +576,10 @@ void generateMips(gpu::Texture* texture, QImage& image, const std::atomic<bool>&
|
||||||
compressionOptions.setPixelType(nvtt::PixelType_UnsignedNorm);
|
compressionOptions.setPixelType(nvtt::PixelType_UnsignedNorm);
|
||||||
compressionOptions.setPitchAlignment(4);
|
compressionOptions.setPitchAlignment(4);
|
||||||
compressionOptions.setPixelFormat(32,
|
compressionOptions.setPixelFormat(32,
|
||||||
0x000000FF,
|
0x000000FF,
|
||||||
0x0000FF00,
|
0x0000FF00,
|
||||||
0x00FF0000,
|
0x00FF0000,
|
||||||
0xFF000000);
|
0xFF000000);
|
||||||
inputGamma = 1.0f;
|
inputGamma = 1.0f;
|
||||||
outputGamma = 1.0f;
|
outputGamma = 1.0f;
|
||||||
} else if (mipFormat == gpu::Element::COLOR_BGRA_32) {
|
} else if (mipFormat == gpu::Element::COLOR_BGRA_32) {
|
||||||
|
@ -411,10 +587,10 @@ void generateMips(gpu::Texture* texture, QImage& image, const std::atomic<bool>&
|
||||||
compressionOptions.setPixelType(nvtt::PixelType_UnsignedNorm);
|
compressionOptions.setPixelType(nvtt::PixelType_UnsignedNorm);
|
||||||
compressionOptions.setPitchAlignment(4);
|
compressionOptions.setPitchAlignment(4);
|
||||||
compressionOptions.setPixelFormat(32,
|
compressionOptions.setPixelFormat(32,
|
||||||
0x00FF0000,
|
0x00FF0000,
|
||||||
0x0000FF00,
|
0x0000FF00,
|
||||||
0x000000FF,
|
0x000000FF,
|
||||||
0xFF000000);
|
0xFF000000);
|
||||||
inputGamma = 1.0f;
|
inputGamma = 1.0f;
|
||||||
outputGamma = 1.0f;
|
outputGamma = 1.0f;
|
||||||
} else if (mipFormat == gpu::Element::COLOR_SRGBA_32) {
|
} else if (mipFormat == gpu::Element::COLOR_SRGBA_32) {
|
||||||
|
@ -422,19 +598,19 @@ void generateMips(gpu::Texture* texture, QImage& image, const std::atomic<bool>&
|
||||||
compressionOptions.setPixelType(nvtt::PixelType_UnsignedNorm);
|
compressionOptions.setPixelType(nvtt::PixelType_UnsignedNorm);
|
||||||
compressionOptions.setPitchAlignment(4);
|
compressionOptions.setPitchAlignment(4);
|
||||||
compressionOptions.setPixelFormat(32,
|
compressionOptions.setPixelFormat(32,
|
||||||
0x000000FF,
|
0x000000FF,
|
||||||
0x0000FF00,
|
0x0000FF00,
|
||||||
0x00FF0000,
|
0x00FF0000,
|
||||||
0xFF000000);
|
0xFF000000);
|
||||||
} else if (mipFormat == gpu::Element::COLOR_SBGRA_32) {
|
} else if (mipFormat == gpu::Element::COLOR_SBGRA_32) {
|
||||||
compressionOptions.setFormat(nvtt::Format_RGBA);
|
compressionOptions.setFormat(nvtt::Format_RGBA);
|
||||||
compressionOptions.setPixelType(nvtt::PixelType_UnsignedNorm);
|
compressionOptions.setPixelType(nvtt::PixelType_UnsignedNorm);
|
||||||
compressionOptions.setPitchAlignment(4);
|
compressionOptions.setPitchAlignment(4);
|
||||||
compressionOptions.setPixelFormat(32,
|
compressionOptions.setPixelFormat(32,
|
||||||
0x00FF0000,
|
0x00FF0000,
|
||||||
0x0000FF00,
|
0x0000FF00,
|
||||||
0x000000FF,
|
0x000000FF,
|
||||||
0xFF000000);
|
0xFF000000);
|
||||||
} else if (mipFormat == gpu::Element::COLOR_R_8) {
|
} else if (mipFormat == gpu::Element::COLOR_R_8) {
|
||||||
compressionOptions.setFormat(nvtt::Format_RGB);
|
compressionOptions.setFormat(nvtt::Format_RGB);
|
||||||
compressionOptions.setPixelType(nvtt::PixelType_UnsignedNorm);
|
compressionOptions.setPixelType(nvtt::PixelType_UnsignedNorm);
|
||||||
|
@ -454,32 +630,26 @@ void generateMips(gpu::Texture* texture, QImage& image, const std::atomic<bool>&
|
||||||
|
|
||||||
nvtt::OutputOptions outputOptions;
|
nvtt::OutputOptions outputOptions;
|
||||||
outputOptions.setOutputHeader(false);
|
outputOptions.setOutputHeader(false);
|
||||||
MyOutputHandler outputHandler(texture, face);
|
OutputHandler outputHandler(texture, face);
|
||||||
outputOptions.setOutputHandler(&outputHandler);
|
outputOptions.setOutputHandler(&outputHandler);
|
||||||
MyErrorHandler errorHandler;
|
MyErrorHandler errorHandler;
|
||||||
outputOptions.setErrorHandler(&errorHandler);
|
outputOptions.setErrorHandler(&errorHandler);
|
||||||
|
|
||||||
class SequentialTaskDispatcher : public nvtt::TaskDispatcher {
|
|
||||||
public:
|
|
||||||
SequentialTaskDispatcher(const std::atomic<bool>& abortProcessing) : _abortProcessing(abortProcessing) {};
|
|
||||||
|
|
||||||
const std::atomic<bool>& _abortProcessing;
|
|
||||||
|
|
||||||
virtual void dispatch(nvtt::Task* task, void* context, int count) override {
|
|
||||||
for (int i = 0; i < count; i++) {
|
|
||||||
if (!_abortProcessing.load()) {
|
|
||||||
task(context, i);
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
SequentialTaskDispatcher dispatcher(abortProcessing);
|
SequentialTaskDispatcher dispatcher(abortProcessing);
|
||||||
nvtt::Compressor compressor;
|
nvtt::Compressor compressor;
|
||||||
compressor.setTaskDispatcher(&dispatcher);
|
compressor.setTaskDispatcher(&dispatcher);
|
||||||
compressor.process(inputOptions, compressionOptions, outputOptions);
|
compressor.process(inputOptions, compressionOptions, outputOptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
void generateMips(gpu::Texture* texture, QImage& image, const std::atomic<bool>& abortProcessing = false, int face = -1) {
|
||||||
|
#if CPU_MIPMAPS
|
||||||
|
PROFILE_RANGE(resource_parse, "generateMips");
|
||||||
|
|
||||||
|
if (image.format() == QIMAGE_HDR_FORMAT) {
|
||||||
|
generateHDRMips(texture, image, abortProcessing, face);
|
||||||
|
} else {
|
||||||
|
generateLDRMips(texture, image, abortProcessing, face);
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
texture->setAutoGenerateMips(true);
|
texture->setAutoGenerateMips(true);
|
||||||
#endif
|
#endif
|
||||||
|
@ -961,6 +1131,62 @@ const CubeLayout CubeLayout::CUBEMAP_LAYOUTS[] = {
|
||||||
};
|
};
|
||||||
const int CubeLayout::NUM_CUBEMAP_LAYOUTS = sizeof(CubeLayout::CUBEMAP_LAYOUTS) / sizeof(CubeLayout);
|
const int CubeLayout::NUM_CUBEMAP_LAYOUTS = sizeof(CubeLayout::CUBEMAP_LAYOUTS) / sizeof(CubeLayout);
|
||||||
|
|
||||||
|
//#define DEBUG_COLOR_PACKING
|
||||||
|
|
||||||
|
QImage convertToHDRFormat(QImage srcImage, gpu::Element format) {
|
||||||
|
QImage hdrImage(srcImage.width(), srcImage.height(), (QImage::Format)QIMAGE_HDR_FORMAT);
|
||||||
|
std::function<uint32(const glm::vec3&)> packFunc;
|
||||||
|
#ifdef DEBUG_COLOR_PACKING
|
||||||
|
std::function<glm::vec3(uint32)> unpackFunc;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
switch (format.getSemantic()) {
|
||||||
|
case gpu::R11G11B10:
|
||||||
|
packFunc = packR11G11B10F;
|
||||||
|
#ifdef DEBUG_COLOR_PACKING
|
||||||
|
unpackFunc = glm::unpackF2x11_1x10;
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
case gpu::RGB9E5:
|
||||||
|
packFunc = glm::packF3x9_E1x5;
|
||||||
|
#ifdef DEBUG_COLOR_PACKING
|
||||||
|
unpackFunc = glm::unpackF3x9_E1x5;
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
qCWarning(imagelogging) << "Unsupported HDR format";
|
||||||
|
Q_UNREACHABLE();
|
||||||
|
return srcImage;
|
||||||
|
}
|
||||||
|
|
||||||
|
srcImage = srcImage.convertToFormat(QImage::Format_ARGB32);
|
||||||
|
for (auto y = 0; y < srcImage.height(); y++) {
|
||||||
|
const QRgb* srcLineIt = reinterpret_cast<const QRgb*>( srcImage.constScanLine(y) );
|
||||||
|
const QRgb* srcLineEnd = srcLineIt + srcImage.width();
|
||||||
|
uint32* hdrLineIt = reinterpret_cast<uint32*>( hdrImage.scanLine(y) );
|
||||||
|
glm::vec3 color;
|
||||||
|
|
||||||
|
while (srcLineIt < srcLineEnd) {
|
||||||
|
color.r = qRed(*srcLineIt);
|
||||||
|
color.g = qGreen(*srcLineIt);
|
||||||
|
color.b = qBlue(*srcLineIt);
|
||||||
|
// Normalize and apply gamma
|
||||||
|
color /= 255.0f;
|
||||||
|
color.r = powf(color.r, 2.2f);
|
||||||
|
color.g = powf(color.g, 2.2f);
|
||||||
|
color.b = powf(color.b, 2.2f);
|
||||||
|
*hdrLineIt = packFunc(color);
|
||||||
|
#ifdef DEBUG_COLOR_PACKING
|
||||||
|
glm::vec3 ucolor = unpackFunc(*hdrLineIt);
|
||||||
|
assert(glm::distance(color, ucolor) <= 5e-2);
|
||||||
|
#endif
|
||||||
|
++srcLineIt;
|
||||||
|
++hdrLineIt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return hdrImage;
|
||||||
|
}
|
||||||
|
|
||||||
gpu::TexturePointer TextureUsage::processCubeTextureColorFromImage(const QImage& srcImage, const std::string& srcImageName,
|
gpu::TexturePointer TextureUsage::processCubeTextureColorFromImage(const QImage& srcImage, const std::string& srcImageName,
|
||||||
bool generateIrradiance,
|
bool generateIrradiance,
|
||||||
const std::atomic<bool>& abortProcessing) {
|
const std::atomic<bool>& abortProcessing) {
|
||||||
|
@ -969,18 +1195,19 @@ gpu::TexturePointer TextureUsage::processCubeTextureColorFromImage(const QImage&
|
||||||
gpu::TexturePointer theTexture = nullptr;
|
gpu::TexturePointer theTexture = nullptr;
|
||||||
if ((srcImage.width() > 0) && (srcImage.height() > 0)) {
|
if ((srcImage.width() > 0) && (srcImage.height() > 0)) {
|
||||||
QImage image = processSourceImage(srcImage, true);
|
QImage image = processSourceImage(srcImage, true);
|
||||||
if (image.format() != QImage::Format_ARGB32) {
|
|
||||||
image = image.convertToFormat(QImage::Format_ARGB32);
|
|
||||||
}
|
|
||||||
|
|
||||||
gpu::Element formatMip;
|
gpu::Element formatMip;
|
||||||
gpu::Element formatGPU;
|
gpu::Element formatGPU;
|
||||||
if (isCubeTexturesCompressionEnabled()) {
|
if (isCubeTexturesCompressionEnabled()) {
|
||||||
formatMip = gpu::Element::COLOR_COMPRESSED_SRGBA_HIGH;
|
formatMip = gpu::Element::COLOR_COMPRESSED_HDR_RGB;
|
||||||
formatGPU = gpu::Element::COLOR_COMPRESSED_SRGBA_HIGH;
|
formatGPU = gpu::Element::COLOR_COMPRESSED_HDR_RGB;
|
||||||
} else {
|
} else {
|
||||||
formatMip = gpu::Element::COLOR_SRGBA_32;
|
formatMip = HDR_FORMAT;
|
||||||
formatGPU = gpu::Element::COLOR_SRGBA_32;
|
formatGPU = HDR_FORMAT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (image.format() != QIMAGE_HDR_FORMAT) {
|
||||||
|
image = convertToHDRFormat(image, HDR_FORMAT);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find the layout of the cubemap in the 2D image
|
// Find the layout of the cubemap in the 2D image
|
||||||
|
@ -1028,9 +1255,9 @@ gpu::TexturePointer TextureUsage::processCubeTextureColorFromImage(const QImage&
|
||||||
// Generate irradiance while we are at it
|
// Generate irradiance while we are at it
|
||||||
if (generateIrradiance) {
|
if (generateIrradiance) {
|
||||||
PROFILE_RANGE(resource_parse, "generateIrradiance");
|
PROFILE_RANGE(resource_parse, "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));
|
auto irradianceTexture = gpu::Texture::createCube(HDR_FORMAT, 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->setSource(srcImageName);
|
||||||
irradianceTexture->setStoredMipFormat(gpu::Element::COLOR_SBGRA_32);
|
irradianceTexture->setStoredMipFormat(HDR_FORMAT);
|
||||||
for (uint8 face = 0; face < faces.size(); ++face) {
|
for (uint8 face = 0; face < faces.size(); ++face) {
|
||||||
irradianceTexture->assignStoredMipFace(0, face, faces[face].byteCount(), faces[face].constBits());
|
irradianceTexture->assignStoredMipFace(0, face, faces[face].byteCount(), faces[face].constBits());
|
||||||
}
|
}
|
||||||
|
|
|
@ -209,6 +209,137 @@ namespace khronos {
|
||||||
COMPRESSED_SIGNED_RG11_EAC = 0x9273,
|
COMPRESSED_SIGNED_RG11_EAC = 0x9273,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
inline uint8_t evalUncompressedBlockBitSize(InternalFormat format) {
|
||||||
|
switch (format) {
|
||||||
|
case InternalFormat::R8:
|
||||||
|
case InternalFormat::R8_SNORM:
|
||||||
|
return 8;
|
||||||
|
case InternalFormat::R16:
|
||||||
|
case InternalFormat::R16_SNORM:
|
||||||
|
case InternalFormat::RG8:
|
||||||
|
case InternalFormat::RG8_SNORM:
|
||||||
|
return 16;
|
||||||
|
case InternalFormat::RG16:
|
||||||
|
case InternalFormat::RG16_SNORM:
|
||||||
|
return 16;
|
||||||
|
case InternalFormat::R3_G3_B2:
|
||||||
|
return 8;
|
||||||
|
case InternalFormat::RGB4:
|
||||||
|
return 12;
|
||||||
|
case InternalFormat::RGB5:
|
||||||
|
case InternalFormat::RGB565:
|
||||||
|
return 16;
|
||||||
|
case InternalFormat::RGB8:
|
||||||
|
case InternalFormat::RGB8_SNORM:
|
||||||
|
return 24;
|
||||||
|
case InternalFormat::RGB10:
|
||||||
|
// TODO: check if this is really the case
|
||||||
|
return 32;
|
||||||
|
case InternalFormat::RGB12:
|
||||||
|
// TODO: check if this is really the case
|
||||||
|
return 48;
|
||||||
|
case InternalFormat::RGB16:
|
||||||
|
case InternalFormat::RGB16_SNORM:
|
||||||
|
return 48;
|
||||||
|
case InternalFormat::RGBA2:
|
||||||
|
return 8;
|
||||||
|
case InternalFormat::RGBA4:
|
||||||
|
case InternalFormat::RGB5_A1:
|
||||||
|
return 16;
|
||||||
|
case InternalFormat::RGBA8:
|
||||||
|
case InternalFormat::RGBA8_SNORM:
|
||||||
|
case InternalFormat::RGB10_A2:
|
||||||
|
case InternalFormat::RGB10_A2UI:
|
||||||
|
return 32;
|
||||||
|
case InternalFormat::RGBA12:
|
||||||
|
return 48;
|
||||||
|
case InternalFormat::RGBA16:
|
||||||
|
case InternalFormat::RGBA16_SNORM:
|
||||||
|
return 64;
|
||||||
|
case InternalFormat::SRGB8:
|
||||||
|
return 24;
|
||||||
|
case InternalFormat::SRGB8_ALPHA8:
|
||||||
|
return 32;
|
||||||
|
case InternalFormat::R16F:
|
||||||
|
return 16;
|
||||||
|
case InternalFormat::RG16F:
|
||||||
|
return 32;
|
||||||
|
case InternalFormat::RGB16F:
|
||||||
|
return 48;
|
||||||
|
case InternalFormat::RGBA16F:
|
||||||
|
return 64;
|
||||||
|
case InternalFormat::R32F:
|
||||||
|
return 32;
|
||||||
|
case InternalFormat::RG32F:
|
||||||
|
return 64;
|
||||||
|
case InternalFormat::RGB32F:
|
||||||
|
return 96;
|
||||||
|
case InternalFormat::RGBA32F:
|
||||||
|
return 128;
|
||||||
|
case InternalFormat::R11F_G11F_B10F:
|
||||||
|
case InternalFormat::RGB9_E5:
|
||||||
|
return 32;
|
||||||
|
case InternalFormat::R8I:
|
||||||
|
case InternalFormat::R8UI:
|
||||||
|
return 8;
|
||||||
|
case InternalFormat::R16I:
|
||||||
|
case InternalFormat::R16UI:
|
||||||
|
return 16;
|
||||||
|
case InternalFormat::R32I:
|
||||||
|
case InternalFormat::R32UI:
|
||||||
|
return 32;
|
||||||
|
case InternalFormat::RG8I:
|
||||||
|
case InternalFormat::RG8UI:
|
||||||
|
return 16;
|
||||||
|
case InternalFormat::RG16I:
|
||||||
|
case InternalFormat::RG16UI:
|
||||||
|
return 32;
|
||||||
|
case InternalFormat::RG32I:
|
||||||
|
case InternalFormat::RG32UI:
|
||||||
|
return 64;
|
||||||
|
case InternalFormat::RGB8I:
|
||||||
|
case InternalFormat::RGB8UI:
|
||||||
|
return 24;
|
||||||
|
case InternalFormat::RGB16I:
|
||||||
|
case InternalFormat::RGB16UI:
|
||||||
|
return 48;
|
||||||
|
case InternalFormat::RGB32I:
|
||||||
|
case InternalFormat::RGB32UI:
|
||||||
|
return 96;
|
||||||
|
case InternalFormat::RGBA8I:
|
||||||
|
case InternalFormat::RGBA8UI:
|
||||||
|
return 32;
|
||||||
|
case InternalFormat::RGBA16I:
|
||||||
|
case InternalFormat::RGBA16UI:
|
||||||
|
return 64;
|
||||||
|
case InternalFormat::RGBA32I:
|
||||||
|
case InternalFormat::RGBA32UI:
|
||||||
|
return 128;
|
||||||
|
case InternalFormat::DEPTH_COMPONENT16:
|
||||||
|
return 16;
|
||||||
|
case InternalFormat::DEPTH_COMPONENT24:
|
||||||
|
return 24;
|
||||||
|
case InternalFormat::DEPTH_COMPONENT32:
|
||||||
|
case InternalFormat::DEPTH_COMPONENT32F:
|
||||||
|
case InternalFormat::DEPTH24_STENCIL8:
|
||||||
|
return 32;
|
||||||
|
case InternalFormat::DEPTH32F_STENCIL8:
|
||||||
|
// TODO : check if this true
|
||||||
|
return 40;
|
||||||
|
case InternalFormat::STENCIL_INDEX1:
|
||||||
|
return 1;
|
||||||
|
case InternalFormat::STENCIL_INDEX4:
|
||||||
|
return 4;
|
||||||
|
case InternalFormat::STENCIL_INDEX8:
|
||||||
|
return 8;
|
||||||
|
case InternalFormat::STENCIL_INDEX16:
|
||||||
|
return 16;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
template <uint32_t ALIGNMENT>
|
template <uint32_t ALIGNMENT>
|
||||||
inline uint32_t evalAlignedCompressedBlockCount(uint32_t value) {
|
inline uint32_t evalAlignedCompressedBlockCount(uint32_t value) {
|
||||||
enum { val = ALIGNMENT && !(ALIGNMENT & (ALIGNMENT - 1)) };
|
enum { val = ALIGNMENT && !(ALIGNMENT & (ALIGNMENT - 1)) };
|
||||||
|
@ -225,6 +356,7 @@ namespace khronos {
|
||||||
case InternalFormat::COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT: // BC3
|
case InternalFormat::COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT: // BC3
|
||||||
case InternalFormat::COMPRESSED_RED_RGTC1: // BC4
|
case InternalFormat::COMPRESSED_RED_RGTC1: // BC4
|
||||||
case InternalFormat::COMPRESSED_RG_RGTC2: // BC5
|
case InternalFormat::COMPRESSED_RG_RGTC2: // BC5
|
||||||
|
case InternalFormat::COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT: // BC6
|
||||||
case InternalFormat::COMPRESSED_SRGB_ALPHA_BPTC_UNORM: // BC7
|
case InternalFormat::COMPRESSED_SRGB_ALPHA_BPTC_UNORM: // BC7
|
||||||
return evalAlignedCompressedBlockCount<4>(value);
|
return evalAlignedCompressedBlockCount<4>(value);
|
||||||
|
|
||||||
|
@ -241,6 +373,7 @@ namespace khronos {
|
||||||
return 8;
|
return 8;
|
||||||
|
|
||||||
case InternalFormat::COMPRESSED_SRGB_ALPHA_BPTC_UNORM:
|
case InternalFormat::COMPRESSED_SRGB_ALPHA_BPTC_UNORM:
|
||||||
|
case InternalFormat::COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT:
|
||||||
case InternalFormat::COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT:
|
case InternalFormat::COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT:
|
||||||
case InternalFormat::COMPRESSED_RG_RGTC2:
|
case InternalFormat::COMPRESSED_RG_RGTC2:
|
||||||
return 16;
|
return 16;
|
||||||
|
@ -250,6 +383,10 @@ namespace khronos {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline uint8_t evalCompressedBlockBitSize(InternalFormat format) {
|
||||||
|
return evalCompressedBlockSize(format) * 8;
|
||||||
|
}
|
||||||
|
|
||||||
enum class BaseInternalFormat : uint32_t {
|
enum class BaseInternalFormat : uint32_t {
|
||||||
// GL 4.4 Table 8.11
|
// GL 4.4 Table 8.11
|
||||||
DEPTH_COMPONENT = 0x1902,
|
DEPTH_COMPONENT = 0x1902,
|
||||||
|
|
|
@ -54,15 +54,13 @@ uint32_t Header::evalPixelOrBlockDepth(uint32_t level) const {
|
||||||
return evalMipDimension(level, getPixelDepth());
|
return evalMipDimension(level, getPixelDepth());
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t Header::evalPixelOrBlockSize() const {
|
size_t Header::evalPixelOrBlockBitSize() const {
|
||||||
size_t result = 0;
|
size_t result = 0;
|
||||||
|
auto format = getGLInternaFormat();
|
||||||
if (isCompressed()) {
|
if (isCompressed()) {
|
||||||
auto format = getGLInternaFormat();
|
result = khronos::gl::texture::evalCompressedBlockBitSize(format);
|
||||||
result = khronos::gl::texture::evalCompressedBlockSize(format);
|
|
||||||
} else {
|
} else {
|
||||||
// FIXME should really be using the internal format, not the base internal format
|
result = khronos::gl::texture::evalUncompressedBlockBitSize(format);
|
||||||
auto baseFormat = getGLBaseInternalFormat();
|
|
||||||
result = khronos::gl::texture::evalComponentCount(baseFormat);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (0 == result) {
|
if (0 == result) {
|
||||||
|
@ -73,11 +71,14 @@ size_t Header::evalPixelOrBlockSize() const {
|
||||||
|
|
||||||
size_t Header::evalRowSize(uint32_t level) const {
|
size_t Header::evalRowSize(uint32_t level) const {
|
||||||
auto pixWidth = evalPixelOrBlockWidth(level);
|
auto pixWidth = evalPixelOrBlockWidth(level);
|
||||||
auto pixSize = evalPixelOrBlockSize();
|
auto pixSize = evalPixelOrBlockBitSize();
|
||||||
if (pixSize == 0) {
|
if (pixSize == 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return evalPaddedSize(pixWidth * pixSize);
|
auto totalByteSize = pixWidth * pixSize;
|
||||||
|
// Round to the nearest upper byte size
|
||||||
|
totalByteSize = (totalByteSize / 8) + (((totalByteSize % 8) != 0) & 1);
|
||||||
|
return evalPaddedSize(totalByteSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t Header::evalFaceSize(uint32_t level) const {
|
size_t Header::evalFaceSize(uint32_t level) const {
|
||||||
|
|
|
@ -170,7 +170,7 @@ namespace ktx {
|
||||||
uint32_t evalPixelOrBlockHeight(uint32_t level) const;
|
uint32_t evalPixelOrBlockHeight(uint32_t level) const;
|
||||||
uint32_t evalPixelOrBlockDepth(uint32_t level) const;
|
uint32_t evalPixelOrBlockDepth(uint32_t level) const;
|
||||||
|
|
||||||
size_t evalPixelOrBlockSize() const;
|
size_t evalPixelOrBlockBitSize() const;
|
||||||
size_t evalRowSize(uint32_t level) const;
|
size_t evalRowSize(uint32_t level) const;
|
||||||
size_t evalFaceSize(uint32_t level) const;
|
size_t evalFaceSize(uint32_t level) const;
|
||||||
size_t evalImageSize(uint32_t level) const;
|
size_t evalImageSize(uint32_t level) const;
|
||||||
|
|
Loading…
Reference in a new issue