From 9d1f91fa19da870952f556778a1fffde8a0ee571 Mon Sep 17 00:00:00 2001 From: samcake Date: Thu, 31 Mar 2016 19:27:35 -0700 Subject: [PATCH 01/12] First pass at using compressed format when uploading textures --- examples/utilities/render/stats.qml | 13 +++++- libraries/gpu/src/gpu/Context.cpp | 17 +++++++ libraries/gpu/src/gpu/Context.h | 5 ++ libraries/gpu/src/gpu/Format.h | 7 +++ libraries/gpu/src/gpu/GLBackend.h | 10 +++- libraries/gpu/src/gpu/GLBackendPipeline.cpp | 2 + libraries/gpu/src/gpu/GLBackendTexture.cpp | 52 ++++++++++++++++++--- libraries/gpu/src/gpu/Texture.cpp | 7 ++- libraries/gpu/src/gpu/Texture.h | 1 + libraries/model/src/model/TextureMap.cpp | 18 +++---- libraries/render/src/render/EngineStats.cpp | 2 + libraries/render/src/render/EngineStats.h | 5 +- 12 files changed, 118 insertions(+), 21 deletions(-) diff --git a/examples/utilities/render/stats.qml b/examples/utilities/render/stats.qml index 0e51cb8834..d236d80dde 100644 --- a/examples/utilities/render/stats.qml +++ b/examples/utilities/render/stats.qml @@ -108,7 +108,18 @@ Item { prop: "textureGPUMemoryUsage", label: "GPU", color: "#1AC567" + }, + { + prop: "textureGPUVirtualMemoryUsage", + label: "GPU Virtual", + color: "#9495FF" + }, + { + prop: "frameTextureMemoryUsage", + label: "Frame", + color: "#E2334D" } + ] } @@ -186,7 +197,7 @@ Item { object: Render.getConfig("DrawLight"), prop: "numDrawn", label: "Lights", - color: "#E2334D" + color: "#FED959" } ] } diff --git a/libraries/gpu/src/gpu/Context.cpp b/libraries/gpu/src/gpu/Context.cpp index b14c461bc5..99ecf80e39 100644 --- a/libraries/gpu/src/gpu/Context.cpp +++ b/libraries/gpu/src/gpu/Context.cpp @@ -114,6 +114,7 @@ std::atomic Context::_bufferGPUMemoryUsage{ 0 }; std::atomic Context::_textureGPUCount{ 0 }; std::atomic Context::_textureGPUMemoryUsage{ 0 }; +std::atomic Context::_textureGPUVirtualMemoryUsage{ 0 }; void Context::incrementBufferGPUCount() { _bufferGPUCount++; @@ -149,6 +150,17 @@ void Context::updateTextureGPUMemoryUsage(Size prevObjectSize, Size newObjectSiz } } +void Context::updateTextureGPUVirtualMemoryUsage(Size prevObjectSize, Size newObjectSize) { + if (prevObjectSize == newObjectSize) { + return; + } + if (newObjectSize > prevObjectSize) { + _textureGPUVirtualMemoryUsage.fetch_add(newObjectSize - prevObjectSize); + } else { + _textureGPUVirtualMemoryUsage.fetch_sub(prevObjectSize - newObjectSize); + } +} + uint32_t Context::getBufferGPUCount() { return _bufferGPUCount.load(); } @@ -165,10 +177,15 @@ Context::Size Context::getTextureGPUMemoryUsage() { return _textureGPUMemoryUsage.load(); } +Context::Size Context::getTextureGPUVirtualMemoryUsage() { + return _textureGPUVirtualMemoryUsage.load(); +} + void Backend::incrementBufferGPUCount() { Context::incrementBufferGPUCount(); } void Backend::decrementBufferGPUCount() { Context::decrementBufferGPUCount(); } void Backend::updateBufferGPUMemoryUsage(Resource::Size prevObjectSize, Resource::Size newObjectSize) { Context::updateBufferGPUMemoryUsage(prevObjectSize, newObjectSize); } void Backend::incrementTextureGPUCount() { Context::incrementTextureGPUCount(); } void Backend::decrementTextureGPUCount() { Context::decrementTextureGPUCount(); } void Backend::updateTextureGPUMemoryUsage(Resource::Size prevObjectSize, Resource::Size newObjectSize) { Context::updateTextureGPUMemoryUsage(prevObjectSize, newObjectSize); } +void Backend::updateTextureGPUVirtualMemoryUsage(Resource::Size prevObjectSize, Resource::Size newObjectSize) { Context::updateTextureGPUVirtualMemoryUsage(prevObjectSize, newObjectSize); } diff --git a/libraries/gpu/src/gpu/Context.h b/libraries/gpu/src/gpu/Context.h index 7f442895a5..1dbe92ab38 100644 --- a/libraries/gpu/src/gpu/Context.h +++ b/libraries/gpu/src/gpu/Context.h @@ -34,6 +34,7 @@ public: int _ISNumIndexBufferChanges = 0; int _RSNumTextureBounded = 0; + int _RSAmountTextureMemoryBounded = 0; int _DSNumAPIDrawcalls = 0; int _DSNumDrawcalls = 0; @@ -128,6 +129,7 @@ public: static void incrementTextureGPUCount(); static void decrementTextureGPUCount(); static void updateTextureGPUMemoryUsage(Resource::Size prevObjectSize, Resource::Size newObjectSize); + static void updateTextureGPUVirtualMemoryUsage(Resource::Size prevObjectSize, Resource::Size newObjectSize); protected: StereoState _stereo; @@ -177,6 +179,7 @@ public: static uint32_t getTextureGPUCount(); static Size getTextureGPUMemoryUsage(); + static Size getTextureGPUVirtualMemoryUsage(); protected: Context(const Context& context); @@ -202,6 +205,7 @@ protected: static void incrementTextureGPUCount(); static void decrementTextureGPUCount(); static void updateTextureGPUMemoryUsage(Size prevObjectSize, Size newObjectSize); + static void updateTextureGPUVirtualMemoryUsage(Size prevObjectSize, Size newObjectSize); // Buffer and Texture Counters static std::atomic _bufferGPUCount; @@ -209,6 +213,7 @@ protected: static std::atomic _textureGPUCount; static std::atomic _textureGPUMemoryUsage; + static std::atomic _textureGPUVirtualMemoryUsage; friend class Backend; }; diff --git a/libraries/gpu/src/gpu/Format.h b/libraries/gpu/src/gpu/Format.h index 625ca6cec3..16de9caa28 100644 --- a/libraries/gpu/src/gpu/Format.h +++ b/libraries/gpu/src/gpu/Format.h @@ -192,6 +192,13 @@ enum Semantic { SRGBA, SBGRA, + COMPRESSED_R, + COMPRESSED_RGB, + COMPRESSED_RGBA, + + COMPRESSED_SRGB, + COMPRESSED_SRGBA, + R11G11B10, UNIFORM, diff --git a/libraries/gpu/src/gpu/GLBackend.h b/libraries/gpu/src/gpu/GLBackend.h index f5abacd279..77cb96ba9a 100644 --- a/libraries/gpu/src/gpu/GLBackend.h +++ b/libraries/gpu/src/gpu/GLBackend.h @@ -83,11 +83,17 @@ public: GLTexture(); ~GLTexture(); - void setSize(GLuint size); GLuint size() const { return _size; } + GLuint virtualSize() const { return _virtualSize; } + + void updateSize(GLuint virtualSize); private: - GLuint _size; + void setSize(GLuint size); + void setVirtualSize(GLuint size); + + GLuint _size; // true size as reported by the gl api + GLuint _virtualSize; // theorical size as expected }; static GLTexture* syncGPUObject(const Texture& texture); static GLuint getTextureID(const TexturePointer& texture, bool sync = true); diff --git a/libraries/gpu/src/gpu/GLBackendPipeline.cpp b/libraries/gpu/src/gpu/GLBackendPipeline.cpp index 046f1ff0e5..4fe083909a 100755 --- a/libraries/gpu/src/gpu/GLBackendPipeline.cpp +++ b/libraries/gpu/src/gpu/GLBackendPipeline.cpp @@ -266,6 +266,8 @@ void GLBackend::do_setResourceTexture(Batch& batch, size_t paramOffset) { _resource._textures[slot] = resourceTexture; + _stats._RSAmountTextureMemoryBounded += object->size(); + } else { releaseResourceTexture(slot); return; diff --git a/libraries/gpu/src/gpu/GLBackendTexture.cpp b/libraries/gpu/src/gpu/GLBackendTexture.cpp index 3fc7906285..600786eb3e 100755 --- a/libraries/gpu/src/gpu/GLBackendTexture.cpp +++ b/libraries/gpu/src/gpu/GLBackendTexture.cpp @@ -18,7 +18,8 @@ GLBackend::GLTexture::GLTexture() : _contentStamp(0), _texture(0), _target(GL_TEXTURE_2D), - _size(0) + _size(0), + _virtualSize(0) { Backend::incrementTextureGPUCount(); } @@ -28,6 +29,7 @@ GLBackend::GLTexture::~GLTexture() { glDeleteTextures(1, &_texture); } Backend::updateTextureGPUMemoryUsage(_size, 0); + Backend::updateTextureGPUVirtualMemoryUsage(_virtualSize, 0); Backend::decrementTextureGPUCount(); } @@ -36,6 +38,25 @@ void GLBackend::GLTexture::setSize(GLuint size) { _size = size; } +void GLBackend::GLTexture::setVirtualSize(GLuint size) { + Backend::updateTextureGPUVirtualMemoryUsage(_virtualSize, size); + _virtualSize = size; +} + +void GLBackend::GLTexture::updateSize(GLuint virtualSize) { + setVirtualSize(virtualSize); + + GLint gpuSize{ 0 }; + glGetTexLevelParameteriv(_target, 0, GL_TEXTURE_COMPRESSED, &gpuSize); + if (gpuSize) { + glGetTexLevelParameteriv(_target, 0, GL_TEXTURE_COMPRESSED_IMAGE_SIZE, &gpuSize); + setSize(gpuSize); + } else { + setSize(virtualSize); + } +} + + class GLTexelFormat { public: GLenum internalFormat; @@ -56,6 +77,11 @@ public: case gpu::RGBA: texel.internalFormat = GL_RED; break; + + case gpu::COMPRESSED_R: + texel.internalFormat = GL_COMPRESSED_RED_RGTC1; + break; + case gpu::DEPTH: texel.internalFormat = GL_DEPTH_COMPONENT; break; @@ -96,6 +122,12 @@ public: case gpu::RGBA: texel.internalFormat = GL_RGB; break; + case gpu::COMPRESSED_RGB: + texel.internalFormat = GL_COMPRESSED_RGB; + break; + case gpu::COMPRESSED_SRGB: + texel.internalFormat = GL_COMPRESSED_SRGB; + break; default: qCDebug(gpulogging) << "Unknown combination of texel format"; } @@ -133,6 +165,13 @@ public: case gpu::SRGBA: texel.internalFormat = GL_SRGB_ALPHA; break; + + case gpu::COMPRESSED_RGBA: + texel.internalFormat = GL_COMPRESSED_RGBA; + break; + case gpu::COMPRESSED_SRGBA: + texel.internalFormat = GL_COMPRESSED_SRGB_ALPHA; + break; default: qCDebug(gpulogging) << "Unknown combination of texel format"; } @@ -452,15 +491,15 @@ GLBackend::GLTexture* GLBackend::syncGPUObject(const Texture& texture) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); } - object->_target = GL_TEXTURE_2D; - - syncSampler(texture.getSampler(), texture.getType(), object); + object->_target = GL_TEXTURE_2D; + syncSampler(texture.getSampler(), texture.getType(), object); // At this point the mip piels have been loaded, we can notify texture.notifyMipFaceGPULoaded(0, 0); object->_contentStamp = texture.getDataStamp(); + object->updateSize((GLuint)texture.evalTotalSize()); } } else { const GLvoid* bytes = 0; @@ -493,7 +532,7 @@ GLBackend::GLTexture* GLBackend::syncGPUObject(const Texture& texture) { object->_storageStamp = texture.getStamp(); object->_contentStamp = texture.getDataStamp(); - object->setSize((GLuint)texture.getSize()); + object->updateSize((GLuint)texture.evalTotalSize()); } glBindTexture(GL_TEXTURE_2D, boundTex); @@ -539,6 +578,7 @@ GLBackend::GLTexture* GLBackend::syncGPUObject(const Texture& texture) { object->_contentStamp = texture.getDataStamp(); + object->updateSize((GLuint)texture.evalTotalSize()); } else { glBindTexture(GL_TEXTURE_CUBE_MAP, object->_texture); @@ -571,7 +611,7 @@ GLBackend::GLTexture* GLBackend::syncGPUObject(const Texture& texture) { object->_storageStamp = texture.getStamp(); object->_contentStamp = texture.getDataStamp(); - object->setSize((GLuint)texture.getSize()); + object->updateSize((GLuint)texture.evalTotalSize()); } glBindTexture(GL_TEXTURE_CUBE_MAP, boundTex); diff --git a/libraries/gpu/src/gpu/Texture.cpp b/libraries/gpu/src/gpu/Texture.cpp index af740ddb65..d94b6a4b93 100755 --- a/libraries/gpu/src/gpu/Texture.cpp +++ b/libraries/gpu/src/gpu/Texture.cpp @@ -46,10 +46,13 @@ uint32_t Texture::getTextureGPUCount() { Texture::Size Texture::getTextureGPUMemoryUsage() { return Context::getTextureGPUMemoryUsage(); - } -uint8 Texture::NUM_FACES_PER_TYPE[NUM_TYPES] = {1, 1, 1, 6}; +Texture::Size Texture::getTextureGPUVirtualMemoryUsage() { + return Context::getTextureGPUVirtualMemoryUsage(); +} + +uint8 Texture::NUM_FACES_PER_TYPE[NUM_TYPES] = { 1, 1, 1, 6 }; Texture::Pixels::Pixels(const Element& format, Size size, const Byte* bytes) : _format(format), diff --git a/libraries/gpu/src/gpu/Texture.h b/libraries/gpu/src/gpu/Texture.h index 80fbc867e3..fc965f3251 100755 --- a/libraries/gpu/src/gpu/Texture.h +++ b/libraries/gpu/src/gpu/Texture.h @@ -146,6 +146,7 @@ public: static Size getTextureCPUMemoryUsage(); static uint32_t getTextureGPUCount(); static Size getTextureGPUMemoryUsage(); + static Size getTextureGPUVirtualMemoryUsage(); class Usage { public: diff --git a/libraries/model/src/model/TextureMap.cpp b/libraries/model/src/model/TextureMap.cpp index 5173af438c..cc44ddef4c 100755 --- a/libraries/model/src/model/TextureMap.cpp +++ b/libraries/model/src/model/TextureMap.cpp @@ -94,10 +94,10 @@ gpu::Texture* TextureUsage::create2DTextureFromImage(const QImage& srcImage, con // bool isLinearRGB = true; //(_type == NORMAL_TEXTURE) || (_type == EMISSIVE_TEXTURE); bool isLinearRGB = false; //(_type == NORMAL_TEXTURE) || (_type == EMISSIVE_TEXTURE); - gpu::Element formatGPU = gpu::Element(gpu::VEC3, gpu::NUINT8, (isLinearRGB ? gpu::RGB : gpu::SRGB)); + gpu::Element formatGPU = gpu::Element(gpu::VEC3, gpu::NUINT8, (isLinearRGB ? gpu::RGB : gpu::COMPRESSED_SRGB)); gpu::Element formatMip = gpu::Element(gpu::VEC3, gpu::NUINT8, (isLinearRGB ? gpu::RGB : gpu::SRGB)); if (image.hasAlphaChannel()) { - formatGPU = gpu::Element(gpu::VEC4, gpu::NUINT8, (isLinearRGB ? gpu::RGBA : gpu::SRGBA)); + formatGPU = gpu::Element(gpu::VEC4, gpu::NUINT8, (isLinearRGB ? gpu::RGBA : gpu::COMPRESSED_SRGBA)); formatMip = gpu::Element(gpu::VEC4, gpu::NUINT8, (isLinearRGB ? gpu::BGRA : gpu::SBGRA)); } @@ -264,7 +264,7 @@ gpu::Texture* TextureUsage::createRoughnessTextureFromImage(const QImage& srcIma gpu::Texture* theTexture = nullptr; if ((image.width() > 0) && (image.height() > 0)) { - gpu::Element formatGPU = gpu::Element(gpu::SCALAR, gpu::NUINT8, gpu::RGB); + gpu::Element formatGPU = gpu::Element(gpu::SCALAR, gpu::NUINT8, gpu::COMPRESSED_R); gpu::Element formatMip = gpu::Element(gpu::SCALAR, gpu::NUINT8, gpu::RGB); theTexture = (gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR))); @@ -297,7 +297,7 @@ gpu::Texture* TextureUsage::createRoughnessTextureFromGlossImage(const QImage& s gpu::Texture* theTexture = nullptr; if ((image.width() > 0) && (image.height() > 0)) { - gpu::Element formatGPU = gpu::Element(gpu::SCALAR, gpu::NUINT8, gpu::RGB); + gpu::Element formatGPU = gpu::Element(gpu::SCALAR, gpu::NUINT8, gpu::COMPRESSED_R); gpu::Element formatMip = gpu::Element(gpu::SCALAR, gpu::NUINT8, gpu::RGB); theTexture = (gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR))); @@ -327,7 +327,7 @@ gpu::Texture* TextureUsage::createMetallicTextureFromImage(const QImage& srcImag gpu::Texture* theTexture = nullptr; if ((image.width() > 0) && (image.height() > 0)) { - gpu::Element formatGPU = gpu::Element(gpu::SCALAR, gpu::NUINT8, gpu::RGB); + gpu::Element formatGPU = gpu::Element(gpu::SCALAR, gpu::NUINT8, gpu::COMPRESSED_R); gpu::Element formatMip = gpu::Element(gpu::SCALAR, gpu::NUINT8, gpu::RGB); theTexture = (gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR))); @@ -446,10 +446,10 @@ gpu::Texture* TextureUsage::createCubeTextureFromImage(const QImage& srcImage, c // bool isLinearRGB = true; //(_type == NORMAL_TEXTURE) || (_type == EMISSIVE_TEXTURE); bool isLinearRGB = false; //(_type == NORMAL_TEXTURE) || (_type == EMISSIVE_TEXTURE); - gpu::Element formatGPU = gpu::Element(gpu::VEC3, gpu::NUINT8, (isLinearRGB ? gpu::RGB : gpu::SRGB)); + gpu::Element formatGPU = gpu::Element(gpu::VEC3, gpu::NUINT8, (isLinearRGB ? gpu::RGB : gpu::COMPRESSED_SRGB)); gpu::Element formatMip = gpu::Element(gpu::VEC3, gpu::NUINT8, (isLinearRGB ? gpu::RGB : gpu::SRGB)); if (image.hasAlphaChannel()) { - formatGPU = gpu::Element(gpu::VEC4, gpu::NUINT8, (isLinearRGB ? gpu::RGBA : gpu::SRGBA)); + formatGPU = gpu::Element(gpu::VEC4, gpu::NUINT8, (isLinearRGB ? gpu::RGBA : gpu::COMPRESSED_SRGBA)); formatMip = gpu::Element(gpu::VEC4, gpu::NUINT8, (isLinearRGB ? gpu::BGRA : gpu::SBGRA)); } @@ -669,10 +669,10 @@ gpu::Texture* TextureUsage::createLightmapTextureFromImage(const QImage& srcImag // bool isLinearRGB = true; //(_type == NORMAL_TEXTURE) || (_type == EMISSIVE_TEXTURE); bool isLinearRGB = true; //(_type == NORMAL_TEXTURE) || (_type == EMISSIVE_TEXTURE); - gpu::Element formatGPU = gpu::Element(gpu::VEC3, gpu::NUINT8, (isLinearRGB ? gpu::RGB : gpu::SRGB)); + gpu::Element formatGPU = gpu::Element(gpu::VEC3, gpu::NUINT8, (isLinearRGB ? gpu::RGB : gpu::COMPRESSED_SRGB)); gpu::Element formatMip = gpu::Element(gpu::VEC3, gpu::NUINT8, (isLinearRGB ? gpu::RGB : gpu::SRGB)); if (image.hasAlphaChannel()) { - formatGPU = gpu::Element(gpu::VEC4, gpu::NUINT8, (isLinearRGB ? gpu::RGBA : gpu::SRGBA)); + formatGPU = gpu::Element(gpu::VEC4, gpu::NUINT8, (isLinearRGB ? gpu::RGBA : gpu::COMPRESSED_SRGBA)); formatMip = gpu::Element(gpu::VEC4, gpu::NUINT8, (isLinearRGB ? gpu::BGRA : gpu::SBGRA)); } diff --git a/libraries/render/src/render/EngineStats.cpp b/libraries/render/src/render/EngineStats.cpp index 794f278fcf..4fc21acc5b 100644 --- a/libraries/render/src/render/EngineStats.cpp +++ b/libraries/render/src/render/EngineStats.cpp @@ -32,6 +32,7 @@ void EngineStats::run(const SceneContextPointer& sceneContext, const RenderConte config->textureGPUCount = gpu::Texture::getTextureGPUCount(); config->textureCPUMemoryUsage = gpu::Texture::getTextureCPUMemoryUsage(); config->textureGPUMemoryUsage = gpu::Texture::getTextureGPUMemoryUsage(); + config->textureGPUVirtualMemoryUsage = gpu::Texture::getTextureGPUVirtualMemoryUsage(); gpu::ContextStats gpuStats(_gpuStats); renderContext->args->_context->getStats(_gpuStats); @@ -45,6 +46,7 @@ void EngineStats::run(const SceneContextPointer& sceneContext, const RenderConte config->frameTextureCount = _gpuStats._RSNumTextureBounded - gpuStats._RSNumTextureBounded; config->frameTextureRate = config->frameTextureCount * frequency; + config->frameTextureMemoryUsage = _gpuStats._RSAmountTextureMemoryBounded - gpuStats._RSAmountTextureMemoryBounded; config->emitDirty(); } diff --git a/libraries/render/src/render/EngineStats.h b/libraries/render/src/render/EngineStats.h index 4a57724644..a5f1643d3f 100644 --- a/libraries/render/src/render/EngineStats.h +++ b/libraries/render/src/render/EngineStats.h @@ -33,6 +33,7 @@ namespace render { Q_PROPERTY(quint32 textureGPUCount MEMBER textureGPUCount NOTIFY dirty) Q_PROPERTY(qint64 textureCPUMemoryUsage MEMBER textureCPUMemoryUsage NOTIFY dirty) Q_PROPERTY(qint64 textureGPUMemoryUsage MEMBER textureGPUMemoryUsage NOTIFY dirty) + Q_PROPERTY(qint64 textureGPUVirtualMemoryUsage MEMBER textureGPUVirtualMemoryUsage NOTIFY dirty) Q_PROPERTY(quint32 frameAPIDrawcallCount MEMBER frameAPIDrawcallCount NOTIFY dirty) Q_PROPERTY(quint32 frameDrawcallCount MEMBER frameDrawcallCount NOTIFY dirty) @@ -43,7 +44,7 @@ namespace render { Q_PROPERTY(quint32 frameTextureCount MEMBER frameTextureCount NOTIFY dirty) Q_PROPERTY(quint32 frameTextureRate MEMBER frameTextureRate NOTIFY dirty) - + Q_PROPERTY(quint32 frameTextureMemoryUsage MEMBER frameTextureMemoryUsage NOTIFY dirty) public: EngineStatsConfig() : Job::Config(true) {} @@ -57,6 +58,7 @@ namespace render { quint32 textureGPUCount{ 0 }; qint64 textureCPUMemoryUsage{ 0 }; qint64 textureGPUMemoryUsage{ 0 }; + qint64 textureGPUVirtualMemoryUsage{ 0 }; quint32 frameAPIDrawcallCount{ 0 }; quint32 frameDrawcallCount{ 0 }; @@ -67,6 +69,7 @@ namespace render { quint32 frameTextureCount{ 0 }; quint32 frameTextureRate{ 0 }; + qint64 frameTextureMemoryUsage{ 0 }; void emitDirty() { emit dirty(); } From 582a6b7db308f9bd2ea9b0022254d475deffa101 Mon Sep 17 00:00:00 2001 From: samcake Date: Fri, 1 Apr 2016 01:34:33 -0700 Subject: [PATCH 02/12] Adding the correct mip evaluation --- libraries/gpu/src/gpu/GLBackendTexture.cpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/libraries/gpu/src/gpu/GLBackendTexture.cpp b/libraries/gpu/src/gpu/GLBackendTexture.cpp index 600786eb3e..8690b78503 100755 --- a/libraries/gpu/src/gpu/GLBackendTexture.cpp +++ b/libraries/gpu/src/gpu/GLBackendTexture.cpp @@ -49,7 +49,19 @@ void GLBackend::GLTexture::updateSize(GLuint virtualSize) { GLint gpuSize{ 0 }; glGetTexLevelParameteriv(_target, 0, GL_TEXTURE_COMPRESSED, &gpuSize); if (gpuSize) { - glGetTexLevelParameteriv(_target, 0, GL_TEXTURE_COMPRESSED_IMAGE_SIZE, &gpuSize); + GLint baseLevel; + GLint maxLevel; + glGetTexParameteriv(_target, GL_TEXTURE_BASE_LEVEL, &baseLevel); + glGetTexParameteriv(_target, GL_TEXTURE_MAX_LEVEL, &maxLevel); + + for (GLint level = baseLevel; level < maxLevel; level++) { + GLint levelSize{ 0 }; + glGetTexLevelParameteriv(_target, level, GL_TEXTURE_COMPRESSED_IMAGE_SIZE, &levelSize); + if (levelSize <= 0) { + break; + } + gpuSize += levelSize; + } setSize(gpuSize); } else { setSize(virtualSize); From 1ca87fa06962ae3d8645a8665f316492f6926d1f Mon Sep 17 00:00:00 2001 From: samcake Date: Fri, 1 Apr 2016 11:44:57 -0700 Subject: [PATCH 03/12] Refactoring a bit the texture loaders to factorize work --- .../src/model-networking/ModelCache.cpp | 6 +- .../src/model-networking/TextureCache.cpp | 13 +- .../src/model-networking/TextureCache.h | 1 + libraries/model/src/model/TextureMap.cpp | 171 +++++++----------- libraries/model/src/model/TextureMap.h | 4 + 5 files changed, 88 insertions(+), 107 deletions(-) diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index 4120062308..ef78c83d76 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -400,7 +400,7 @@ NetworkMaterial::NetworkMaterial(const FBXMaterial& material, const QUrl& textur { _textures = Textures(MapChannel::NUM_MAP_CHANNELS); if (!material.albedoTexture.filename.isEmpty()) { - auto map = fetchTextureMap(textureBaseUrl, material.albedoTexture, DEFAULT_TEXTURE, MapChannel::ALBEDO_MAP); + auto map = fetchTextureMap(textureBaseUrl, material.albedoTexture, ALBEDO_TEXTURE, MapChannel::ALBEDO_MAP); _albedoTransform = material.albedoTexture.transform; map->setTextureTransform(_albedoTransform); @@ -471,7 +471,7 @@ void NetworkMaterial::setTextures(const QVariantMap& textureMap) { if (!albedoName.isEmpty()) { auto url = textureMap.contains(albedoName) ? textureMap[albedoName].toUrl() : QUrl(); - auto map = fetchTextureMap(url, DEFAULT_TEXTURE, MapChannel::ALBEDO_MAP); + auto map = fetchTextureMap(url, ALBEDO_TEXTURE, MapChannel::ALBEDO_MAP); map->setTextureTransform(_albedoTransform); // when reassigning the albedo texture we also check for the alpha channel used as opacity map->setUseAlphaChannel(true); @@ -480,7 +480,7 @@ void NetworkMaterial::setTextures(const QVariantMap& textureMap) { if (!normalName.isEmpty()) { auto url = textureMap.contains(normalName) ? textureMap[normalName].toUrl() : QUrl(); - auto map = fetchTextureMap(url, DEFAULT_TEXTURE, MapChannel::NORMAL_MAP); + auto map = fetchTextureMap(url, NORMAL_TEXTURE, MapChannel::NORMAL_MAP); setTextureMap(MapChannel::NORMAL_MAP, map); } diff --git a/libraries/model-networking/src/model-networking/TextureCache.cpp b/libraries/model-networking/src/model-networking/TextureCache.cpp index 3ba36dc2da..b6c87ca386 100644 --- a/libraries/model-networking/src/model-networking/TextureCache.cpp +++ b/libraries/model-networking/src/model-networking/TextureCache.cpp @@ -199,6 +199,18 @@ NetworkTexture::NetworkTexture(const QUrl& url, const TextureLoaderFunc& texture NetworkTexture::TextureLoaderFunc NetworkTexture::getTextureLoader() const { switch (_type) { + case ALBEDO_TEXTURE: { + return TextureLoaderFunc(model::TextureUsage::createAlbedoTextureFromImage); + break; + } + case EMISSIVE_TEXTURE: { + return TextureLoaderFunc(model::TextureUsage::createEmissiveTextureFromImage); + break; + } + case LIGHTMAP_TEXTURE: { + return TextureLoaderFunc(model::TextureUsage::createLightmapTextureFromImage); + break; + } case CUBE_TEXTURE: { return TextureLoaderFunc(model::TextureUsage::createCubeTextureFromImage); break; @@ -228,7 +240,6 @@ NetworkTexture::TextureLoaderFunc NetworkTexture::getTextureLoader() const { break; } case DEFAULT_TEXTURE: - case EMISSIVE_TEXTURE: default: { return TextureLoaderFunc(model::TextureUsage::create2DTextureFromImage); break; diff --git a/libraries/model-networking/src/model-networking/TextureCache.h b/libraries/model-networking/src/model-networking/TextureCache.h index 858a40de36..4fe9a89460 100644 --- a/libraries/model-networking/src/model-networking/TextureCache.h +++ b/libraries/model-networking/src/model-networking/TextureCache.h @@ -31,6 +31,7 @@ typedef QSharedPointer NetworkTexturePointer; enum TextureType { DEFAULT_TEXTURE, + ALBEDO_TEXTURE, NORMAL_TEXTURE, BUMP_TEXTURE, SPECULAR_TEXTURE, diff --git a/libraries/model/src/model/TextureMap.cpp b/libraries/model/src/model/TextureMap.cpp index cc44ddef4c..56cc88bfc8 100755 --- a/libraries/model/src/model/TextureMap.cpp +++ b/libraries/model/src/model/TextureMap.cpp @@ -49,9 +49,7 @@ void TextureMap::setLightmapOffsetScale(float offset, float scale) { _lightmapOffsetScale.y = scale; } - -// FIXME why is this in the model library? Move to GPU or GPU_GL -gpu::Texture* TextureUsage::create2DTextureFromImage(const QImage& srcImage, const std::string& srcImageName) { +gpu::Texture* TextureUsage::process2DTextureColorFromImage(const QImage& srcImage, bool isLinear, bool doCompress, bool generateMips) { QImage image = srcImage; bool validAlpha = false; bool alphaAsMask = true; @@ -63,7 +61,7 @@ gpu::Texture* TextureUsage::create2DTextureFromImage(const QImage& srcImage, con if (image.format() != QImage::Format_ARGB32) { image = image.convertToFormat(QImage::Format_ARGB32); } - + // Actual alpha channel? create the histogram for (int y = 0; y < image.height(); ++y) { const QRgb* data = reinterpret_cast(image.constScanLine(y)); @@ -83,22 +81,58 @@ gpu::Texture* TextureUsage::create2DTextureFromImage(const QImage& srcImage, con alphaAsMask = ((numTranslucents / (double)totalNumPixels) < 0.05); } - } - + } + if (!validAlpha && image.format() != QImage::Format_RGB888) { image = image.convertToFormat(QImage::Format_RGB888); } - + gpu::Texture* theTexture = nullptr; if ((image.width() > 0) && (image.height() > 0)) { - // bool isLinearRGB = true; //(_type == NORMAL_TEXTURE) || (_type == EMISSIVE_TEXTURE); - bool isLinearRGB = false; //(_type == NORMAL_TEXTURE) || (_type == EMISSIVE_TEXTURE); - gpu::Element formatGPU = gpu::Element(gpu::VEC3, gpu::NUINT8, (isLinearRGB ? gpu::RGB : gpu::COMPRESSED_SRGB)); - gpu::Element formatMip = gpu::Element(gpu::VEC3, gpu::NUINT8, (isLinearRGB ? gpu::RGB : gpu::SRGB)); + gpu::Element formatGPU; + gpu::Element formatMip; + if (image.hasAlphaChannel()) { - formatGPU = gpu::Element(gpu::VEC4, gpu::NUINT8, (isLinearRGB ? gpu::RGBA : gpu::COMPRESSED_SRGBA)); - formatMip = gpu::Element(gpu::VEC4, gpu::NUINT8, (isLinearRGB ? gpu::BGRA : gpu::SBGRA)); + gpu::Semantic gpuSemantic; + gpu::Semantic mipSemantic; + if (isLinear) { + mipSemantic = gpu::SBGRA; + if (doCompress) { + gpuSemantic = gpu::COMPRESSED_SRGBA; + } else { + gpuSemantic = gpu::SRGBA; + } + } else { + mipSemantic = gpu::BGRA; + if (doCompress) { + gpuSemantic = gpu::COMPRESSED_RGBA; + } else { + gpuSemantic = gpu::RGBA; + } + } + 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::SRGB; + if (doCompress) { + gpuSemantic = gpu::COMPRESSED_SRGB; + } else { + gpuSemantic = gpu::SRGB; + } + } else { + mipSemantic = gpu::RGB; + if (doCompress) { + gpuSemantic = gpu::COMPRESSED_RGB; + } else { + gpuSemantic = gpu::RGB; + } + } + formatGPU = gpu::Element(gpu::VEC3, gpu::NUINT8, gpuSemantic); + formatMip = gpu::Element(gpu::VEC3, gpu::NUINT8, mipSemantic); } theTexture = (gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR))); @@ -113,15 +147,32 @@ gpu::Texture* TextureUsage::create2DTextureFromImage(const QImage& srcImage, con theTexture->setUsage(usage.build()); theTexture->assignStoredMip(0, formatMip, image.byteCount(), image.constBits()); - theTexture->autoGenerateMips(-1); - - // FIXME queue for transfer to GPU and block on completion + if (generateMips) { + theTexture->autoGenerateMips(-1); + } } - + return theTexture; } +gpu::Texture* TextureUsage::create2DTextureFromImage(const QImage& srcImage, const std::string& srcImageName) { + return process2DTextureColorFromImage(srcImage, true, false, true); +} + + +gpu::Texture* TextureUsage::createAlbedoTextureFromImage(const QImage& srcImage, const std::string& srcImageName) { + return process2DTextureColorFromImage(srcImage, true, true, true); +} + +gpu::Texture* TextureUsage::createEmissiveTextureFromImage(const QImage& srcImage, const std::string& srcImageName) { + return process2DTextureColorFromImage(srcImage, true, true, true); +} + +gpu::Texture* TextureUsage::createLightmapTextureFromImage(const QImage& srcImage, const std::string& srcImageName) { + return process2DTextureColorFromImage(srcImage, true, true, true); +} + gpu::Texture* TextureUsage::createNormalTextureFromNormalImage(const QImage& srcImage, const std::string& srcImageName) { QImage image = srcImage; @@ -598,89 +649,3 @@ gpu::Texture* TextureUsage::createCubeTextureFromImage(const QImage& srcImage, c return theTexture; } - - -gpu::Texture* TextureUsage::createLightmapTextureFromImage(const QImage& srcImage, const std::string& srcImageName) { - QImage image = srcImage; - - int imageArea = image.width() * image.height(); - - int opaquePixels = 0; - int translucentPixels = 0; - //bool isTransparent = false; - int redTotal = 0, greenTotal = 0, blueTotal = 0, alphaTotal = 0; - const int EIGHT_BIT_MAXIMUM = 255; - QColor averageColor(EIGHT_BIT_MAXIMUM, EIGHT_BIT_MAXIMUM, EIGHT_BIT_MAXIMUM); - - if (!image.hasAlphaChannel()) { - if (image.format() != QImage::Format_RGB888) { - image = image.convertToFormat(QImage::Format_RGB888); - } - // int redTotal = 0, greenTotal = 0, blueTotal = 0; - for (int y = 0; y < image.height(); y++) { - for (int x = 0; x < image.width(); x++) { - QRgb rgb = image.pixel(x, y); - redTotal += qRed(rgb); - greenTotal += qGreen(rgb); - blueTotal += qBlue(rgb); - } - } - if (imageArea > 0) { - averageColor.setRgb(redTotal / imageArea, greenTotal / imageArea, blueTotal / imageArea); - } - } else { - if (image.format() != QImage::Format_ARGB32) { - image = image.convertToFormat(QImage::Format_ARGB32); - } - - // check for translucency/false transparency - // int opaquePixels = 0; - // int translucentPixels = 0; - // int redTotal = 0, greenTotal = 0, blueTotal = 0, alphaTotal = 0; - for (int y = 0; y < image.height(); y++) { - for (int x = 0; x < image.width(); x++) { - QRgb rgb = image.pixel(x, y); - redTotal += qRed(rgb); - greenTotal += qGreen(rgb); - blueTotal += qBlue(rgb); - int alpha = qAlpha(rgb); - alphaTotal += alpha; - if (alpha == EIGHT_BIT_MAXIMUM) { - opaquePixels++; - } else if (alpha != 0) { - translucentPixels++; - } - } - } - if (opaquePixels == imageArea) { - qCDebug(modelLog) << "Image with alpha channel is completely opaque:" << QString(srcImageName.c_str()); - image = image.convertToFormat(QImage::Format_RGB888); - } - - averageColor = QColor(redTotal / imageArea, - greenTotal / imageArea, blueTotal / imageArea, alphaTotal / imageArea); - - //isTransparent = (translucentPixels >= imageArea / 2); - } - - gpu::Texture* theTexture = nullptr; - if ((image.width() > 0) && (image.height() > 0)) { - - // bool isLinearRGB = true; //(_type == NORMAL_TEXTURE) || (_type == EMISSIVE_TEXTURE); - bool isLinearRGB = true; //(_type == NORMAL_TEXTURE) || (_type == EMISSIVE_TEXTURE); - - gpu::Element formatGPU = gpu::Element(gpu::VEC3, gpu::NUINT8, (isLinearRGB ? gpu::RGB : gpu::COMPRESSED_SRGB)); - gpu::Element formatMip = gpu::Element(gpu::VEC3, gpu::NUINT8, (isLinearRGB ? gpu::RGB : gpu::SRGB)); - if (image.hasAlphaChannel()) { - formatGPU = gpu::Element(gpu::VEC4, gpu::NUINT8, (isLinearRGB ? gpu::RGBA : gpu::COMPRESSED_SRGBA)); - formatMip = gpu::Element(gpu::VEC4, gpu::NUINT8, (isLinearRGB ? gpu::BGRA : gpu::SBGRA)); - } - - - theTexture = (gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR))); - theTexture->assignStoredMip(0, formatMip, image.byteCount(), image.constBits()); - theTexture->autoGenerateMips(-1); - } - - return theTexture; -} diff --git a/libraries/model/src/model/TextureMap.h b/libraries/model/src/model/TextureMap.h index e845aebb81..fa0eea55cb 100755 --- a/libraries/model/src/model/TextureMap.h +++ b/libraries/model/src/model/TextureMap.h @@ -32,6 +32,8 @@ public: int _environmentUsage = 0; static gpu::Texture* create2DTextureFromImage(const QImage& image, const std::string& srcImageName); + static gpu::Texture* createAlbedoTextureFromImage(const QImage& image, const std::string& srcImageName); + static gpu::Texture* createEmissiveTextureFromImage(const QImage& image, const std::string& srcImageName); static gpu::Texture* createNormalTextureFromNormalImage(const QImage& image, const std::string& srcImageName); static gpu::Texture* createNormalTextureFromBumpImage(const QImage& image, const std::string& srcImageName); static gpu::Texture* createRoughnessTextureFromImage(const QImage& image, const std::string& srcImageName); @@ -40,6 +42,8 @@ public: static gpu::Texture* createCubeTextureFromImage(const QImage& image, const std::string& srcImageName); static gpu::Texture* createLightmapTextureFromImage(const QImage& image, const std::string& srcImageName); + + static gpu::Texture* process2DTextureColorFromImage(const QImage& imageSrc, bool isLinear, bool doCompress, bool generateMips); }; From be38de32398aac789757b21347ec1479590d744b Mon Sep 17 00:00:00 2001 From: samcake Date: Fri, 1 Apr 2016 17:16:22 -0700 Subject: [PATCH 04/12] Cleaning up the TextureMap loaders and cleaning for pr --- libraries/gpu/src/gpu/Format.h | 11 ++++++++++- libraries/gpu/src/gpu/GLBackendTexture.cpp | 18 ++++++++++++++++++ libraries/model/src/model/TextureMap.cpp | 13 ++++--------- 3 files changed, 32 insertions(+), 10 deletions(-) diff --git a/libraries/gpu/src/gpu/Format.h b/libraries/gpu/src/gpu/Format.h index 16de9caa28..60a90840c6 100644 --- a/libraries/gpu/src/gpu/Format.h +++ b/libraries/gpu/src/gpu/Format.h @@ -192,13 +192,22 @@ enum Semantic { SRGBA, SBGRA, + // These are generic compression format smeantic for images COMPRESSED_R, - COMPRESSED_RGB, + + COMPRESSED_RGB, COMPRESSED_RGBA, COMPRESSED_SRGB, COMPRESSED_SRGBA, + // FIXME: Will have to be supported later: + /*COMPRESSED_BC3_RGBA, // RGBA_S3TC_DXT5_EXT, + COMPRESSED_BC3_SRGBA, // SRGB_ALPHA_S3TC_DXT5_EXT + + COMPRESSED_BC7_RGBA, + COMPRESSED_BC7_SRGBA, */ + R11G11B10, UNIFORM, diff --git a/libraries/gpu/src/gpu/GLBackendTexture.cpp b/libraries/gpu/src/gpu/GLBackendTexture.cpp index 8690b78503..82e6d12054 100755 --- a/libraries/gpu/src/gpu/GLBackendTexture.cpp +++ b/libraries/gpu/src/gpu/GLBackendTexture.cpp @@ -184,6 +184,24 @@ public: case gpu::COMPRESSED_SRGBA: texel.internalFormat = GL_COMPRESSED_SRGB_ALPHA; break; + + // FIXME: WE will want to support this later + /* + case gpu::COMPRESSED_BC3_RGBA: + texel.internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; + break; + case gpu::COMPRESSED_BC3_SRGBA: + texel.internalFormat = GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT; + break; + + case gpu::COMPRESSED_BC7_RGBA: + texel.internalFormat = GL_COMPRESSED_RGBA_BPTC_UNORM_ARB; + break; + case gpu::COMPRESSED_BC7_SRGBA: + texel.internalFormat = GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM; + break; + */ + default: qCDebug(gpulogging) << "Unknown combination of texel format"; } diff --git a/libraries/model/src/model/TextureMap.cpp b/libraries/model/src/model/TextureMap.cpp index 56cc88bfc8..bd09955fd1 100755 --- a/libraries/model/src/model/TextureMap.cpp +++ b/libraries/model/src/model/TextureMap.cpp @@ -182,9 +182,7 @@ gpu::Texture* TextureUsage::createNormalTextureFromNormalImage(const QImage& src image = image.convertToFormat(QImage::Format_RGB888); } } else { - if (image.format() != QImage::Format_ARGB32) { - image = image.convertToFormat(QImage::Format_ARGB32); - } + image = image.convertToFormat(QImage::Format_RGB888); } gpu::Texture* theTexture = nullptr; @@ -192,12 +190,9 @@ gpu::Texture* TextureUsage::createNormalTextureFromNormalImage(const QImage& src bool isLinearRGB = true; - gpu::Element formatGPU = gpu::Element(gpu::VEC3, gpu::NUINT8, (isLinearRGB ? gpu::RGB : gpu::SRGB)); - gpu::Element formatMip = gpu::Element(gpu::VEC3, gpu::NUINT8, (isLinearRGB ? gpu::RGB : gpu::SRGB)); - if (image.hasAlphaChannel()) { - formatGPU = gpu::Element(gpu::VEC4, gpu::NUINT8, (isLinearRGB ? gpu::RGBA : gpu::SRGBA)); - formatMip = gpu::Element(gpu::VEC4, gpu::NUINT8, (isLinearRGB ? gpu::BGRA : gpu::SBGRA)); - } + gpu::Element formatGPU = gpu::Element(gpu::VEC3, gpu::NUINT8, gpu::RGB); + gpu::Element formatMip = gpu::Element(gpu::VEC3, gpu::NUINT8, gpu::RGB); + theTexture = (gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR))); theTexture->assignStoredMip(0, formatMip, image.byteCount(), image.constBits()); From d9bc06d92d934968e39585aa4759bd629de1297c Mon Sep 17 00:00:00 2001 From: samcake Date: Tue, 5 Apr 2016 19:13:24 -0700 Subject: [PATCH 05/12] Trying to ge5t the proper behavior for the Compression texture and textures in genral... --- libraries/gpu/src/gpu/GLBackendShared.h | 2 + .../gpu/src/gpu/GLBackendTexelFormat.cpp | 24 +++++++++ libraries/gpu/src/gpu/GLBackendTexture.cpp | 49 +++++++++++++------ 3 files changed, 61 insertions(+), 14 deletions(-) diff --git a/libraries/gpu/src/gpu/GLBackendShared.h b/libraries/gpu/src/gpu/GLBackendShared.h index d6aab6034d..aef670e6b0 100644 --- a/libraries/gpu/src/gpu/GLBackendShared.h +++ b/libraries/gpu/src/gpu/GLBackendShared.h @@ -54,6 +54,8 @@ public: static GLTexelFormat evalGLTexelFormat(const gpu::Element& dstFormat) { return evalGLTexelFormat(dstFormat, dstFormat); } + static GLTexelFormat evalGLTexelFormatInternal(const gpu::Element& dstFormat); + static GLTexelFormat evalGLTexelFormat(const gpu::Element& dstFormat, const gpu::Element& srcFormat); }; diff --git a/libraries/gpu/src/gpu/GLBackendTexelFormat.cpp b/libraries/gpu/src/gpu/GLBackendTexelFormat.cpp index 3f64f373d6..1a7b969e13 100644 --- a/libraries/gpu/src/gpu/GLBackendTexelFormat.cpp +++ b/libraries/gpu/src/gpu/GLBackendTexelFormat.cpp @@ -10,6 +10,11 @@ using namespace gpu; +GLTexelFormat GLTexelFormat::evalGLTexelFormatInternal(const gpu::Element& dstFormat) { + GLTexelFormat texel = { GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE }; + return texel; +} + GLTexelFormat GLTexelFormat::evalGLTexelFormat(const Element& dstFormat, const Element& srcFormat) { if (dstFormat != srcFormat) { GLTexelFormat texel = { GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE }; @@ -118,6 +123,7 @@ GLTexelFormat GLTexelFormat::evalGLTexelFormat(const Element& dstFormat, const E break; case gpu::COMPRESSED_SRGBA: texel.internalFormat = GL_COMPRESSED_SRGB_ALPHA; + break; // FIXME: WE will want to support this later @@ -156,6 +162,10 @@ GLTexelFormat GLTexelFormat::evalGLTexelFormat(const Element& dstFormat, const E texel.type = _elementTypeToGLType[dstFormat.getType()]; switch (dstFormat.getSemantic()) { + case gpu::COMPRESSED_R: { + texel.internalFormat = GL_COMPRESSED_RED_RGTC1; + break; + } case gpu::RGB: case gpu::RGBA: case gpu::SRGB: @@ -312,6 +322,12 @@ GLTexelFormat GLTexelFormat::evalGLTexelFormat(const Element& dstFormat, const E case gpu::SRGBA: texel.internalFormat = GL_SRGB8; // standard 2.2 gamma correction color break; + case gpu::COMPRESSED_RGB: + texel.internalFormat = GL_COMPRESSED_RGB; + break; + case gpu::COMPRESSED_SRGB: + texel.internalFormat = GL_COMPRESSED_SRGB; + break; default: qCDebug(gpulogging) << "Unknown combination of texel format"; } @@ -383,11 +399,19 @@ GLTexelFormat GLTexelFormat::evalGLTexelFormat(const Element& dstFormat, const E } break; case gpu::SRGB: + texel.format = GL_RGB; texel.internalFormat = GL_SRGB8; break; case gpu::SRGBA: + texel.format = GL_RGBA; texel.internalFormat = GL_SRGB8_ALPHA8; // standard 2.2 gamma correction color break; + case gpu::COMPRESSED_RGBA: + texel.internalFormat = GL_COMPRESSED_RGBA; + break; + case gpu::COMPRESSED_SRGBA: + texel.internalFormat = GL_COMPRESSED_SRGB_ALPHA; + break; default: qCDebug(gpulogging) << "Unknown combination of texel format"; } diff --git a/libraries/gpu/src/gpu/GLBackendTexture.cpp b/libraries/gpu/src/gpu/GLBackendTexture.cpp index 35c8666292..1e68dd1453 100755 --- a/libraries/gpu/src/gpu/GLBackendTexture.cpp +++ b/libraries/gpu/src/gpu/GLBackendTexture.cpp @@ -72,20 +72,41 @@ GLBackend::GLTexture::GLTexture(const Texture& texture) : } GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(texture.getTexelFormat()); - withPreservedTexture(_target, [&] { - glBindTexture(_target, _texture); - (void)CHECK_GL_ERROR(); - // GO through the process of allocating the correct storage - if (GLEW_VERSION_4_2) { - glTexStorage2D(_target, levels, texelFormat.internalFormat, width, height); - } else { - glTexImage2D(_target, 0, texelFormat.internalFormat, width, height, 0, texelFormat.format, texelFormat.type, 0); - } - (void)CHECK_GL_ERROR(); - syncSampler(texture.getSampler(), texture.getType(), this); - (void)CHECK_GL_ERROR(); - updateSize((GLuint)texture.evalTotalSize()); - }); + + GLint boundTex = -1; + switch (_target) { + case GL_TEXTURE_2D: + glGetIntegerv(GL_TEXTURE_BINDING_2D, &boundTex); + break; + + case GL_TEXTURE_CUBE_MAP: + glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP, &boundTex); + break; + + default: + qFatal("Unsupported texture type"); + } + (void)CHECK_GL_ERROR(); + + glBindTexture(_target, _texture); + + (void)CHECK_GL_ERROR(); + // GO through the process of allocating the correct storage + if (GLEW_VERSION_4_2) { + glTexStorage2D(_target, levels, texelFormat.internalFormat, width, height); + } else { + glTexImage2D(_target, 0, texelFormat.internalFormat, width, height, 0, texelFormat.format, texelFormat.type, 0); + } + (void)CHECK_GL_ERROR(); + + syncSampler(texture.getSampler(), texture.getType(), this); + (void)CHECK_GL_ERROR(); + + updateSize((GLuint)texture.evalTotalSize()); + (void)CHECK_GL_ERROR(); + + glBindTexture(_target, boundTex); + (void)CHECK_GL_ERROR(); } GLBackend::GLTexture::~GLTexture() { From 16174df0f319f7cda70ee2ec28fb87057f006a60 Mon Sep 17 00:00:00 2001 From: samcake Date: Wed, 6 Apr 2016 16:33:45 -0700 Subject: [PATCH 06/12] POlishing the size evaluation and trying to debug the compression scheme --- libraries/gpu/src/gpu/Format.h | 4 ++ libraries/gpu/src/gpu/GLBackend.h | 3 +- libraries/gpu/src/gpu/GLBackendOutput.cpp | 4 +- libraries/gpu/src/gpu/GLBackendTexture.cpp | 70 +++++++++++++++------- libraries/model/src/model/TextureMap.cpp | 6 +- 5 files changed, 58 insertions(+), 29 deletions(-) diff --git a/libraries/gpu/src/gpu/Format.h b/libraries/gpu/src/gpu/Format.h index 60a90840c6..b9e46b700a 100644 --- a/libraries/gpu/src/gpu/Format.h +++ b/libraries/gpu/src/gpu/Format.h @@ -193,6 +193,7 @@ enum Semantic { SBGRA, // These are generic compression format smeantic for images + _FIRST_COMPRESSED, COMPRESSED_R, COMPRESSED_RGB, @@ -208,6 +209,8 @@ enum Semantic { COMPRESSED_BC7_RGBA, COMPRESSED_BC7_SRGBA, */ + _LAST_COMPRESSED, + R11G11B10, UNIFORM, @@ -240,6 +243,7 @@ public: Dimension getDimension() const { return (Dimension)_dimension; } + bool isCompressed() const { return (getSemantic() - _FIRST_COMPRESSED <= _LAST_COMPRESSED - _FIRST_COMPRESSED); } Type getType() const { return (Type)_type; } bool isNormalized() const { return (getType() >= NORMALIZED_START); } diff --git a/libraries/gpu/src/gpu/GLBackend.h b/libraries/gpu/src/gpu/GLBackend.h index 0f64f6d199..f59e154bb9 100644 --- a/libraries/gpu/src/gpu/GLBackend.h +++ b/libraries/gpu/src/gpu/GLBackend.h @@ -130,6 +130,7 @@ public: GLuint _size; // true size as reported by the gl api GLuint _virtualSize; // theorical size as expected + GLuint _numLevels{ 0 }; void transferMip(GLenum target, const Texture::PixelsPointer& mip) const; @@ -137,7 +138,7 @@ public: const Texture& _gpuTexture; std::atomic _syncState { SyncState::Idle }; }; - static GLTexture* syncGPUObject(const TexturePointer& texture); + static GLTexture* syncGPUObject(const TexturePointer& texture, bool needTransfer = true); static GLuint getTextureID(const TexturePointer& texture, bool sync = true); // very specific for now diff --git a/libraries/gpu/src/gpu/GLBackendOutput.cpp b/libraries/gpu/src/gpu/GLBackendOutput.cpp index 4f714fb53d..545d0a8cdb 100755 --- a/libraries/gpu/src/gpu/GLBackendOutput.cpp +++ b/libraries/gpu/src/gpu/GLBackendOutput.cpp @@ -83,7 +83,7 @@ GLBackend::GLFramebuffer* GLBackend::syncGPUObject(const Framebuffer& framebuffe for (auto& b : framebuffer.getRenderBuffers()) { surface = b._texture; if (surface) { - gltexture = GLBackend::syncGPUObject(surface); + gltexture = GLBackend::syncGPUObject(surface, false); // Grab the gltexture and don't transfer } else { gltexture = nullptr; } @@ -123,7 +123,7 @@ GLBackend::GLFramebuffer* GLBackend::syncGPUObject(const Framebuffer& framebuffe if (framebuffer.getDepthStamp() != object->_depthStamp) { auto surface = framebuffer.getDepthStencilBuffer(); if (framebuffer.hasDepthStencil() && surface) { - gltexture = GLBackend::syncGPUObject(surface); + gltexture = GLBackend::syncGPUObject(surface, false); // Grab the gltexture and don't transfer } if (gltexture) { diff --git a/libraries/gpu/src/gpu/GLBackendTexture.cpp b/libraries/gpu/src/gpu/GLBackendTexture.cpp index 1e68dd1453..c4889fe6f7 100755 --- a/libraries/gpu/src/gpu/GLBackendTexture.cpp +++ b/libraries/gpu/src/gpu/GLBackendTexture.cpp @@ -53,6 +53,8 @@ GLBackend::GLTexture::GLTexture(const Texture& texture) : _target(gpuToGLTextureType(texture)), _size(0), _virtualSize(0), + // _numLevels(std::max((uint16)1, texture.maxMip())), + _numLevels(texture.maxMip() + 1), _gpuTexture(texture) { Backend::incrementTextureGPUCount(); @@ -61,15 +63,6 @@ GLBackend::GLTexture::GLTexture(const Texture& texture) : GLsizei width = texture.getWidth(); GLsizei height = texture.getHeight(); - GLsizei levels = 1; - if (texture.maxMip() > 0) { - if (texture.isAutogenerateMips()) { - while ((width | height) >> levels) { - ++levels; - } - } - levels = std::max(1, std::min(texture.maxMip() + 1, levels)); - } GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(texture.getTexelFormat()); @@ -92,12 +85,26 @@ GLBackend::GLTexture::GLTexture(const Texture& texture) : (void)CHECK_GL_ERROR(); // GO through the process of allocating the correct storage - if (GLEW_VERSION_4_2) { - glTexStorage2D(_target, levels, texelFormat.internalFormat, width, height); + if (GLEW_VERSION_4_2 && !texture.getTexelFormat().isCompressed()) { + glTexStorage2D(_target, _numLevels, texelFormat.internalFormat, width, height); + (void)CHECK_GL_ERROR(); } else { - glTexImage2D(_target, 0, texelFormat.internalFormat, width, height, 0, texelFormat.format, texelFormat.type, 0); + glTexParameteri(_target, GL_TEXTURE_BASE_LEVEL, 0); + glTexParameteri(_target, GL_TEXTURE_MAX_LEVEL, _numLevels - 1); + + for (int l = 0; l < _numLevels; l++) { + if (texture.getType() == gpu::Texture::TEX_CUBE) { + for (int face = 0; face < CUBE_NUM_FACES; face++) { + glTexImage2D(CUBE_FACE_LAYOUT[face], l, texelFormat.internalFormat, width, height, 0, texelFormat.format, texelFormat.type, NULL); + } + } else { + glTexImage2D(_target, l, texelFormat.internalFormat, width, height, 0, texelFormat.format, texelFormat.type, NULL); + } + width = std::max(1, (width / 2)); + height = std::max(1, (height / 2)); + } + (void)CHECK_GL_ERROR(); } - (void)CHECK_GL_ERROR(); syncSampler(texture.getSampler(), texture.getType(), this); (void)CHECK_GL_ERROR(); @@ -118,9 +125,6 @@ GLBackend::GLTexture::~GLTexture() { Backend::decrementTextureGPUCount(); } -bool GLBackend::GLTexture::isInvalid() const { - return _storageStamp < _gpuTexture.getStamp(); -} void GLBackend::GLTexture::setSize(GLuint size) { Backend::updateTextureGPUMemoryUsage(_size, size); @@ -136,16 +140,30 @@ void GLBackend::GLTexture::updateSize(GLuint virtualSize) { setVirtualSize(virtualSize); GLint gpuSize{ 0 }; - glGetTexLevelParameteriv(_target, 0, GL_TEXTURE_COMPRESSED, &gpuSize); + if (_target == GL_TEXTURE_CUBE_MAP) { + glGetTexLevelParameteriv(CUBE_FACE_LAYOUT[0], 0, GL_TEXTURE_COMPRESSED, &gpuSize); + } else { + glGetTexLevelParameteriv(_target, 0, GL_TEXTURE_COMPRESSED, &gpuSize); + } + (void)CHECK_GL_ERROR(); + if (gpuSize) { GLint baseLevel; GLint maxLevel; glGetTexParameteriv(_target, GL_TEXTURE_BASE_LEVEL, &baseLevel); glGetTexParameteriv(_target, GL_TEXTURE_MAX_LEVEL, &maxLevel); - for (GLint level = baseLevel; level < maxLevel; level++) { + for (GLint level = baseLevel; level <= maxLevel; level++) { GLint levelSize{ 0 }; - glGetTexLevelParameteriv(_target, level, GL_TEXTURE_COMPRESSED_IMAGE_SIZE, &levelSize); + if (_target == GL_TEXTURE_CUBE_MAP) { + for (int face = 0; face < CUBE_NUM_FACES; face++) { + GLint faceSize{ 0 }; + glGetTexLevelParameteriv(CUBE_FACE_LAYOUT[face], level, GL_TEXTURE_COMPRESSED_IMAGE_SIZE, &faceSize); + levelSize += faceSize; + } + } else { + glGetTexLevelParameteriv(_target, level, GL_TEXTURE_COMPRESSED_IMAGE_SIZE, &levelSize); + } if (levelSize <= 0) { break; } @@ -158,6 +176,10 @@ void GLBackend::GLTexture::updateSize(GLuint virtualSize) { } +bool GLBackend::GLTexture::isInvalid() const { + return _storageStamp < _gpuTexture.getStamp(); +} + bool GLBackend::GLTexture::isOutdated() const { return _contentStamp < _gpuTexture.getDataStamp(); } @@ -247,7 +269,7 @@ void GLBackend::GLTexture::postTransfer() { } } -GLBackend::GLTexture* GLBackend::syncGPUObject(const TexturePointer& texturePointer) { +GLBackend::GLTexture* GLBackend::syncGPUObject(const TexturePointer& texturePointer, bool needTransfer) { const Texture& texture = *texturePointer; if (!texture.isDefined()) { // NO texture definition yet so let's avoid thinking @@ -269,8 +291,9 @@ GLBackend::GLTexture* GLBackend::syncGPUObject(const TexturePointer& texturePoin object = new GLTexture(texture); } - // need to have a gpu object? - if (texture.getNumSlices() != 1) { + // Object maybe doens't neet to be tranasferred after creation + if (!needTransfer) { + object->_contentStamp = texturePointer->getDataStamp(); return object; } @@ -383,7 +406,8 @@ void GLBackend::do_generateTextureMips(Batch& batch, size_t paramOffset) { return; } - GLTexture* object = GLBackend::syncGPUObject(resourceTexture); + // DO not transfer the texture, this call is expected for rendering texture + GLTexture* object = GLBackend::syncGPUObject(resourceTexture, false); if (!object) { return; } diff --git a/libraries/model/src/model/TextureMap.cpp b/libraries/model/src/model/TextureMap.cpp index ce6d46fcdb..9a145ffbec 100755 --- a/libraries/model/src/model/TextureMap.cpp +++ b/libraries/model/src/model/TextureMap.cpp @@ -162,15 +162,15 @@ gpu::Texture* TextureUsage::create2DTextureFromImage(const QImage& srcImage, con gpu::Texture* TextureUsage::createAlbedoTextureFromImage(const QImage& srcImage, const std::string& srcImageName) { - return process2DTextureColorFromImage(srcImage, true, true, true); + return process2DTextureColorFromImage(srcImage, true, false, true); } gpu::Texture* TextureUsage::createEmissiveTextureFromImage(const QImage& srcImage, const std::string& srcImageName) { - return process2DTextureColorFromImage(srcImage, true, true, true); + return process2DTextureColorFromImage(srcImage, true, false, true); } gpu::Texture* TextureUsage::createLightmapTextureFromImage(const QImage& srcImage, const std::string& srcImageName) { - return process2DTextureColorFromImage(srcImage, true, true, true); + return process2DTextureColorFromImage(srcImage, true, false, true); } From a6bac7ad927789932f532a546ae27680fe626f99 Mon Sep 17 00:00:00 2001 From: samcake Date: Wed, 6 Apr 2016 18:30:18 -0700 Subject: [PATCH 07/12] Experimenting with a hidden gltexture object while beeing transfered --- libraries/gpu/src/gpu/GLBackend.h | 3 ++- libraries/gpu/src/gpu/GLBackendTexture.cpp | 26 ++++++++++++++-------- libraries/model/src/model/TextureMap.cpp | 12 ++++------ 3 files changed, 23 insertions(+), 18 deletions(-) diff --git a/libraries/gpu/src/gpu/GLBackend.h b/libraries/gpu/src/gpu/GLBackend.h index f59e154bb9..c8df1f809f 100644 --- a/libraries/gpu/src/gpu/GLBackend.h +++ b/libraries/gpu/src/gpu/GLBackend.h @@ -78,7 +78,8 @@ public: public: const Stamp _storageStamp; Stamp _contentStamp { 0 }; - const GLuint _texture; + const GLuint _secretTexture; + GLuint _texture{ 0 }; const GLenum _target; GLTexture(const gpu::Texture& gpuTexture); diff --git a/libraries/gpu/src/gpu/GLBackendTexture.cpp b/libraries/gpu/src/gpu/GLBackendTexture.cpp index c4889fe6f7..de1dd9ce2f 100755 --- a/libraries/gpu/src/gpu/GLBackendTexture.cpp +++ b/libraries/gpu/src/gpu/GLBackendTexture.cpp @@ -49,7 +49,7 @@ const GLenum GLBackend::GLTexture::CUBE_FACE_LAYOUT[6] = { // Create the texture and allocate storage GLBackend::GLTexture::GLTexture(const Texture& texture) : _storageStamp(texture.getStamp()), - _texture(allocateSingleTexture()), + _secretTexture(allocateSingleTexture()), _target(gpuToGLTextureType(texture)), _size(0), _virtualSize(0), @@ -81,18 +81,19 @@ GLBackend::GLTexture::GLTexture(const Texture& texture) : } (void)CHECK_GL_ERROR(); - glBindTexture(_target, _texture); + glBindTexture(_target, _secretTexture); (void)CHECK_GL_ERROR(); // GO through the process of allocating the correct storage - if (GLEW_VERSION_4_2 && !texture.getTexelFormat().isCompressed()) { + /* if (GLEW_VERSION_4_2 && !texture.getTexelFormat().isCompressed()) { glTexStorage2D(_target, _numLevels, texelFormat.internalFormat, width, height); (void)CHECK_GL_ERROR(); - } else { + } else*/ { glTexParameteri(_target, GL_TEXTURE_BASE_LEVEL, 0); glTexParameteri(_target, GL_TEXTURE_MAX_LEVEL, _numLevels - 1); - for (int l = 0; l < _numLevels; l++) { + // for (int l = 0; l < _numLevels; l++) { + { int l = 0; if (texture.getType() == gpu::Texture::TEX_CUBE) { for (int face = 0; face < CUBE_NUM_FACES; face++) { glTexImage2D(CUBE_FACE_LAYOUT[face], l, texelFormat.internalFormat, width, height, 0, texelFormat.format, texelFormat.type, NULL); @@ -117,9 +118,12 @@ GLBackend::GLTexture::GLTexture(const Texture& texture) : } GLBackend::GLTexture::~GLTexture() { - if (_texture != 0) { - glDeleteTextures(1, &_texture); + if (_secretTexture != 0) { + glDeleteTextures(1, &_secretTexture); } + /*if (_texture != 0) { + glDeleteTextures(1, &_texture); + }*/ Backend::updateTextureGPUMemoryUsage(_size, 0); Backend::updateTextureGPUVirtualMemoryUsage(_virtualSize, 0); Backend::decrementTextureGPUCount(); @@ -213,13 +217,15 @@ void GLBackend::GLTexture::transferMip(GLenum target, const Texture::PixelsPoint // Move content bits from the CPU to the GPU void GLBackend::GLTexture::transfer() const { PROFILE_RANGE(__FUNCTION__); - qDebug() << "Transferring texture: " << _texture; + qDebug() << "Transferring texture: " << _secretTexture; // Need to update the content of the GPU object from the source sysmem of the texture if (_contentStamp >= _gpuTexture.getDataStamp()) { return; } - glBindTexture(_target, _texture); + //_secretTexture + glBindTexture(_target, _secretTexture); + // glBindTexture(_target, _texture); // GO through the process of allocating the correct storage and/or update the content switch (_gpuTexture.getType()) { case Texture::TEX_2D: @@ -251,6 +257,7 @@ void GLBackend::GLTexture::transfer() const { // Do any post-transfer operations that might be required on the main context / rendering thread void GLBackend::GLTexture::postTransfer() { setSyncState(GLTexture::Idle); + _texture = _secretTexture; // At this point the mip pixels have been loaded, we can notify the gpu texture to abandon it's memory switch (_gpuTexture.getType()) { case Texture::TEX_2D: @@ -294,6 +301,7 @@ GLBackend::GLTexture* GLBackend::syncGPUObject(const TexturePointer& texturePoin // Object maybe doens't neet to be tranasferred after creation if (!needTransfer) { object->_contentStamp = texturePointer->getDataStamp(); + object->postTransfer(); return object; } diff --git a/libraries/model/src/model/TextureMap.cpp b/libraries/model/src/model/TextureMap.cpp index 9a145ffbec..2906fe7abf 100755 --- a/libraries/model/src/model/TextureMap.cpp +++ b/libraries/model/src/model/TextureMap.cpp @@ -162,26 +162,22 @@ gpu::Texture* TextureUsage::create2DTextureFromImage(const QImage& srcImage, con gpu::Texture* TextureUsage::createAlbedoTextureFromImage(const QImage& srcImage, const std::string& srcImageName) { - return process2DTextureColorFromImage(srcImage, true, false, true); + return process2DTextureColorFromImage(srcImage, true, true, true); } gpu::Texture* TextureUsage::createEmissiveTextureFromImage(const QImage& srcImage, const std::string& srcImageName) { - return process2DTextureColorFromImage(srcImage, true, false, true); + return process2DTextureColorFromImage(srcImage, true, true, true); } gpu::Texture* TextureUsage::createLightmapTextureFromImage(const QImage& srcImage, const std::string& srcImageName) { - return process2DTextureColorFromImage(srcImage, true, false, true); + return process2DTextureColorFromImage(srcImage, true, true, true); } gpu::Texture* TextureUsage::createNormalTextureFromNormalImage(const QImage& srcImage, const std::string& srcImageName) { QImage image = srcImage; - if (!image.hasAlphaChannel()) { - if (image.format() != QImage::Format_RGB888) { - image = image.convertToFormat(QImage::Format_RGB888); - } - } else { + if (image.format() != QImage::Format_RGB888) { image = image.convertToFormat(QImage::Format_RGB888); } From cf983e627dd341b683ed3cb8a58c834233572c4a Mon Sep 17 00:00:00 2001 From: samcake Date: Wed, 6 Apr 2016 19:36:52 -0700 Subject: [PATCH 08/12] fixing the warnings --- libraries/gpu/src/gpu/GLBackend.h | 2 +- libraries/gpu/src/gpu/GLBackendTexture.cpp | 15 ++++++++++----- .../gpu/src/gpu/GLBackendTextureTransfer.cpp | 6 +++--- 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/libraries/gpu/src/gpu/GLBackend.h b/libraries/gpu/src/gpu/GLBackend.h index c8df1f809f..ed72a7ad30 100644 --- a/libraries/gpu/src/gpu/GLBackend.h +++ b/libraries/gpu/src/gpu/GLBackend.h @@ -88,7 +88,7 @@ public: GLuint size() const { return _size; } GLuint virtualSize() const { return _virtualSize; } - void updateSize(GLuint virtualSize); + void updateSize(); enum SyncState { // The texture is currently undergoing no processing, although it's content diff --git a/libraries/gpu/src/gpu/GLBackendTexture.cpp b/libraries/gpu/src/gpu/GLBackendTexture.cpp index de1dd9ce2f..0252bd0ea4 100755 --- a/libraries/gpu/src/gpu/GLBackendTexture.cpp +++ b/libraries/gpu/src/gpu/GLBackendTexture.cpp @@ -95,7 +95,7 @@ GLBackend::GLTexture::GLTexture(const Texture& texture) : // for (int l = 0; l < _numLevels; l++) { { int l = 0; if (texture.getType() == gpu::Texture::TEX_CUBE) { - for (int face = 0; face < CUBE_NUM_FACES; face++) { + for (size_t face = 0; face < CUBE_NUM_FACES; face++) { glTexImage2D(CUBE_FACE_LAYOUT[face], l, texelFormat.internalFormat, width, height, 0, texelFormat.format, texelFormat.type, NULL); } } else { @@ -110,7 +110,9 @@ GLBackend::GLTexture::GLTexture(const Texture& texture) : syncSampler(texture.getSampler(), texture.getType(), this); (void)CHECK_GL_ERROR(); - updateSize((GLuint)texture.evalTotalSize()); + GLuint virtualSize = _gpuTexture.evalTotalSize(); + setVirtualSize(virtualSize); + setSize(virtualSize); (void)CHECK_GL_ERROR(); glBindTexture(_target, boundTex); @@ -140,9 +142,12 @@ void GLBackend::GLTexture::setVirtualSize(GLuint size) { _virtualSize = size; } -void GLBackend::GLTexture::updateSize(GLuint virtualSize) { +void GLBackend::GLTexture::updateSize() { + GLuint virtualSize = _gpuTexture.evalTotalSize(); setVirtualSize(virtualSize); - + if (!_texture) { + setSize(virtualSize); + } GLint gpuSize{ 0 }; if (_target == GL_TEXTURE_CUBE_MAP) { glGetTexLevelParameteriv(CUBE_FACE_LAYOUT[0], 0, GL_TEXTURE_COMPRESSED, &gpuSize); @@ -160,7 +165,7 @@ void GLBackend::GLTexture::updateSize(GLuint virtualSize) { for (GLint level = baseLevel; level <= maxLevel; level++) { GLint levelSize{ 0 }; if (_target == GL_TEXTURE_CUBE_MAP) { - for (int face = 0; face < CUBE_NUM_FACES; face++) { + for (size_t face = 0; face < CUBE_NUM_FACES; face++) { GLint faceSize{ 0 }; glGetTexLevelParameteriv(CUBE_FACE_LAYOUT[face], level, GL_TEXTURE_COMPRESSED_IMAGE_SIZE, &faceSize); levelSize += faceSize; diff --git a/libraries/gpu/src/gpu/GLBackendTextureTransfer.cpp b/libraries/gpu/src/gpu/GLBackendTextureTransfer.cpp index 1ad18c8c2f..657712490c 100644 --- a/libraries/gpu/src/gpu/GLBackendTextureTransfer.cpp +++ b/libraries/gpu/src/gpu/GLBackendTextureTransfer.cpp @@ -63,10 +63,10 @@ bool GLTextureTransferHelper::processQueueItems(const Queue& messages) { GLBackend::GLTexture* object = Backend::getGPUObject(*texturePointer); object->transfer(); - - - glBindTexture(object->_target, 0); auto writeSync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); + + object->updateSize(); + glBindTexture(object->_target, 0); glClientWaitSync(writeSync, GL_SYNC_FLUSH_COMMANDS_BIT, GL_TIMEOUT_IGNORED); glDeleteSync(writeSync); object->_contentStamp = texturePointer->getDataStamp(); From 76dd7405787754c1a9c11ab702a52151fd95eb81 Mon Sep 17 00:00:00 2001 From: samcake Date: Thu, 7 Apr 2016 20:05:05 -0700 Subject: [PATCH 09/12] Cleaning up to test before merge, not solved the stuttering happening when using compressed textures. cleaned up a bit of the TextureMap doanload callbacks --- libraries/gpu/src/gpu/Format.h | 2 +- libraries/gpu/src/gpu/GLBackend.h | 6 +- libraries/gpu/src/gpu/GLBackendTexture.cpp | 139 ++--- .../gpu/src/gpu/GLBackendTextureTransfer.cpp | 12 +- libraries/model/src/model/TextureMap.cpp | 498 +++++++++--------- libraries/model/src/model/TextureMap.h | 7 +- 6 files changed, 332 insertions(+), 332 deletions(-) diff --git a/libraries/gpu/src/gpu/Format.h b/libraries/gpu/src/gpu/Format.h index b9e46b700a..940b0eb85b 100644 --- a/libraries/gpu/src/gpu/Format.h +++ b/libraries/gpu/src/gpu/Format.h @@ -243,7 +243,7 @@ public: Dimension getDimension() const { return (Dimension)_dimension; } - bool isCompressed() const { return (getSemantic() - _FIRST_COMPRESSED <= _LAST_COMPRESSED - _FIRST_COMPRESSED); } + bool isCompressed() const { return uint8(getSemantic() - _FIRST_COMPRESSED) <= uint8(_LAST_COMPRESSED - _FIRST_COMPRESSED); } Type getType() const { return (Type)_type; } bool isNormalized() const { return (getType() >= NORMALIZED_START); } diff --git a/libraries/gpu/src/gpu/GLBackend.h b/libraries/gpu/src/gpu/GLBackend.h index ed72a7ad30..29256a322f 100644 --- a/libraries/gpu/src/gpu/GLBackend.h +++ b/libraries/gpu/src/gpu/GLBackend.h @@ -78,13 +78,14 @@ public: public: const Stamp _storageStamp; Stamp _contentStamp { 0 }; - const GLuint _secretTexture; GLuint _texture{ 0 }; const GLenum _target; GLTexture(const gpu::Texture& gpuTexture); ~GLTexture(); + void createTexture(); + GLuint size() const { return _size; } GLuint virtualSize() const { return _virtualSize; } @@ -125,6 +126,9 @@ public: static const GLenum CUBE_FACE_LAYOUT[6]; private: + // at creation the true texture is created in GL + // it becomes public only when ready. + GLuint _privateTexture; void setSize(GLuint size); void setVirtualSize(GLuint size); diff --git a/libraries/gpu/src/gpu/GLBackendTexture.cpp b/libraries/gpu/src/gpu/GLBackendTexture.cpp index 0252bd0ea4..54d7fb27bb 100755 --- a/libraries/gpu/src/gpu/GLBackendTexture.cpp +++ b/libraries/gpu/src/gpu/GLBackendTexture.cpp @@ -49,22 +49,30 @@ const GLenum GLBackend::GLTexture::CUBE_FACE_LAYOUT[6] = { // Create the texture and allocate storage GLBackend::GLTexture::GLTexture(const Texture& texture) : _storageStamp(texture.getStamp()), - _secretTexture(allocateSingleTexture()), + _privateTexture(allocateSingleTexture()), _target(gpuToGLTextureType(texture)), _size(0), _virtualSize(0), - // _numLevels(std::max((uint16)1, texture.maxMip())), _numLevels(texture.maxMip() + 1), _gpuTexture(texture) { Backend::incrementTextureGPUCount(); - Backend::updateTextureGPUMemoryUsage(0, _size); Backend::setGPUObject(texture, this); - GLsizei width = texture.getWidth(); - GLsizei height = texture.getHeight(); - GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(texture.getTexelFormat()); + // updateSize(); + GLuint virtualSize = _gpuTexture.evalTotalSize(); + setVirtualSize(virtualSize); + setSize(virtualSize); +} + +void GLBackend::GLTexture::createTexture() { + _privateTexture = allocateSingleTexture(); + + GLsizei width = _gpuTexture.getWidth(); + GLsizei height = _gpuTexture.getHeight(); + + GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(_gpuTexture.getTexelFormat()); GLint boundTex = -1; switch (_target) { @@ -81,51 +89,47 @@ GLBackend::GLTexture::GLTexture(const Texture& texture) : } (void)CHECK_GL_ERROR(); - glBindTexture(_target, _secretTexture); + glBindTexture(_target, _privateTexture); (void)CHECK_GL_ERROR(); + // Fixme: this usage of TexStorage doesn;t work wtih compressed texture, altuogh it should. // GO through the process of allocating the correct storage - /* if (GLEW_VERSION_4_2 && !texture.getTexelFormat().isCompressed()) { - glTexStorage2D(_target, _numLevels, texelFormat.internalFormat, width, height); - (void)CHECK_GL_ERROR(); - } else*/ { + /* if (GLEW_VERSION_4_2 && !texture.getTexelFormat().isCompressed()) { + glTexStorage2D(_target, _numLevels, texelFormat.internalFormat, width, height); + (void)CHECK_GL_ERROR(); + } else*/ + { glTexParameteri(_target, GL_TEXTURE_BASE_LEVEL, 0); glTexParameteri(_target, GL_TEXTURE_MAX_LEVEL, _numLevels - 1); - // for (int l = 0; l < _numLevels; l++) { + // for (int l = 0; l < _numLevels; l++) { { int l = 0; - if (texture.getType() == gpu::Texture::TEX_CUBE) { - for (size_t face = 0; face < CUBE_NUM_FACES; face++) { - glTexImage2D(CUBE_FACE_LAYOUT[face], l, texelFormat.internalFormat, width, height, 0, texelFormat.format, texelFormat.type, NULL); - } - } else { - glTexImage2D(_target, l, texelFormat.internalFormat, width, height, 0, texelFormat.format, texelFormat.type, NULL); + if (_gpuTexture.getType() == gpu::Texture::TEX_CUBE) { + for (size_t face = 0; face < CUBE_NUM_FACES; face++) { + glTexImage2D(CUBE_FACE_LAYOUT[face], l, texelFormat.internalFormat, width, height, 0, texelFormat.format, texelFormat.type, NULL); } - width = std::max(1, (width / 2)); - height = std::max(1, (height / 2)); + } else { + glTexImage2D(_target, l, texelFormat.internalFormat, width, height, 0, texelFormat.format, texelFormat.type, NULL); + } + width = std::max(1, (width / 2)); + height = std::max(1, (height / 2)); } (void)CHECK_GL_ERROR(); } - syncSampler(texture.getSampler(), texture.getType(), this); + syncSampler(_gpuTexture.getSampler(), _gpuTexture.getType(), this); (void)CHECK_GL_ERROR(); - GLuint virtualSize = _gpuTexture.evalTotalSize(); - setVirtualSize(virtualSize); - setSize(virtualSize); - (void)CHECK_GL_ERROR(); glBindTexture(_target, boundTex); (void)CHECK_GL_ERROR(); } GLBackend::GLTexture::~GLTexture() { - if (_secretTexture != 0) { - glDeleteTextures(1, &_secretTexture); + if (_privateTexture != 0) { + glDeleteTextures(1, &_privateTexture); } - /*if (_texture != 0) { - glDeleteTextures(1, &_texture); - }*/ + Backend::updateTextureGPUMemoryUsage(_size, 0); Backend::updateTextureGPUVirtualMemoryUsage(_virtualSize, 0); Backend::decrementTextureGPUCount(); @@ -148,37 +152,36 @@ void GLBackend::GLTexture::updateSize() { if (!_texture) { setSize(virtualSize); } - GLint gpuSize{ 0 }; - if (_target == GL_TEXTURE_CUBE_MAP) { - glGetTexLevelParameteriv(CUBE_FACE_LAYOUT[0], 0, GL_TEXTURE_COMPRESSED, &gpuSize); - } else { - glGetTexLevelParameteriv(_target, 0, GL_TEXTURE_COMPRESSED, &gpuSize); - } - (void)CHECK_GL_ERROR(); - if (gpuSize) { - GLint baseLevel; - GLint maxLevel; - glGetTexParameteriv(_target, GL_TEXTURE_BASE_LEVEL, &baseLevel); - glGetTexParameteriv(_target, GL_TEXTURE_MAX_LEVEL, &maxLevel); - - for (GLint level = baseLevel; level <= maxLevel; level++) { - GLint levelSize{ 0 }; - if (_target == GL_TEXTURE_CUBE_MAP) { - for (size_t face = 0; face < CUBE_NUM_FACES; face++) { - GLint faceSize{ 0 }; - glGetTexLevelParameteriv(CUBE_FACE_LAYOUT[face], level, GL_TEXTURE_COMPRESSED_IMAGE_SIZE, &faceSize); - levelSize += faceSize; - } - } else { - glGetTexLevelParameteriv(_target, level, GL_TEXTURE_COMPRESSED_IMAGE_SIZE, &levelSize); - } - if (levelSize <= 0) { - break; - } - gpuSize += levelSize; + if (_gpuTexture.getTexelFormat().isCompressed()) { + GLenum proxyType = GL_TEXTURE_2D; + GLuint numFaces = 1; + if (_gpuTexture.getType() == gpu::Texture::TEX_CUBE) { + proxyType = CUBE_FACE_LAYOUT[0]; + numFaces = CUBE_NUM_FACES; } - setSize(gpuSize); + GLint gpuSize{ 0 }; + glGetTexLevelParameteriv(proxyType, 0, GL_TEXTURE_COMPRESSED, &gpuSize); + (void)CHECK_GL_ERROR(); + + if (gpuSize) { + for (GLint level = 0; level < _numLevels; level++) { + GLint levelSize{ 0 }; + glGetTexLevelParameteriv(proxyType, level, GL_TEXTURE_COMPRESSED_IMAGE_SIZE, &levelSize); + levelSize *= numFaces; + + if (levelSize <= 0) { + break; + } + gpuSize += levelSize; + } + (void)CHECK_GL_ERROR(); + + setSize(gpuSize); + } else { + setSize(virtualSize); + } + } else { setSize(virtualSize); } @@ -210,27 +213,25 @@ bool GLBackend::GLTexture::isReady() const { return Idle == syncState; } - // Move content bits from the CPU to the GPU for a given mip / face void GLBackend::GLTexture::transferMip(GLenum target, const Texture::PixelsPointer& mip) const { GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(_gpuTexture.getTexelFormat(), mip->getFormat()); - - glTexSubImage2D(target, 0, 0, 0, _gpuTexture.getWidth(), _gpuTexture.getHeight(), texelFormat.format, texelFormat.type, mip->readData()); + glTexSubImage2D(target, 0, 0, 0, _gpuTexture.getWidth(), _gpuTexture.getHeight(), texelFormat.format, texelFormat.type, mip->readData()); glTexSubImage2D(target, 0, 0, 0, _gpuTexture.getWidth(), _gpuTexture.getHeight(), texelFormat.format, texelFormat.type, mip->readData()); (void)CHECK_GL_ERROR(); } // Move content bits from the CPU to the GPU void GLBackend::GLTexture::transfer() const { PROFILE_RANGE(__FUNCTION__); - qDebug() << "Transferring texture: " << _secretTexture; + //qDebug() << "Transferring texture: " << _privateTexture; // Need to update the content of the GPU object from the source sysmem of the texture if (_contentStamp >= _gpuTexture.getDataStamp()) { return; } //_secretTexture - glBindTexture(_target, _secretTexture); - // glBindTexture(_target, _texture); + glBindTexture(_target, _privateTexture); + // glBindTexture(_target, _texture); // GO through the process of allocating the correct storage and/or update the content switch (_gpuTexture.getType()) { case Texture::TEX_2D: @@ -262,7 +263,10 @@ void GLBackend::GLTexture::transfer() const { // Do any post-transfer operations that might be required on the main context / rendering thread void GLBackend::GLTexture::postTransfer() { setSyncState(GLTexture::Idle); - _texture = _secretTexture; + + // The public gltexture becaomes available + _texture = _privateTexture; + // At this point the mip pixels have been loaded, we can notify the gpu texture to abandon it's memory switch (_gpuTexture.getType()) { case Texture::TEX_2D: @@ -295,7 +299,7 @@ GLBackend::GLTexture* GLBackend::syncGPUObject(const TexturePointer& texturePoin } // Object isn't ready, check what we need to do... - + // Create the texture if need be (force re-creation if the storage stamp changes // for easier use of immutable storage) if (!object || object->isInvalid()) { @@ -305,6 +309,7 @@ GLBackend::GLTexture* GLBackend::syncGPUObject(const TexturePointer& texturePoin // Object maybe doens't neet to be tranasferred after creation if (!needTransfer) { + object->createTexture(); object->_contentStamp = texturePointer->getDataStamp(); object->postTransfer(); return object; diff --git a/libraries/gpu/src/gpu/GLBackendTextureTransfer.cpp b/libraries/gpu/src/gpu/GLBackendTextureTransfer.cpp index 657712490c..24aa9a9c4a 100644 --- a/libraries/gpu/src/gpu/GLBackendTextureTransfer.cpp +++ b/libraries/gpu/src/gpu/GLBackendTextureTransfer.cpp @@ -15,6 +15,7 @@ #include #include + #endif using namespace gpu; @@ -35,8 +36,7 @@ GLTextureTransferHelper::GLTextureTransferHelper() { void GLTextureTransferHelper::transferTexture(const gpu::TexturePointer& texturePointer) { GLBackend::GLTexture* object = Backend::getGPUObject(*texturePointer); #ifdef THREADED_TEXTURE_TRANSFER - TextureTransferPackage package { texturePointer, glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0) }; - glFlush(); + TextureTransferPackage package{ texturePointer, 0}; object->setSyncState(GLBackend::GLTexture::Pending); queueItem(package); #else @@ -53,8 +53,6 @@ void GLTextureTransferHelper::setup() { bool GLTextureTransferHelper::processQueueItems(const Queue& messages) { for (auto package : messages) { - glWaitSync(package.fence, 0, GL_TIMEOUT_IGNORED); - glDeleteSync(package.fence); TexturePointer texturePointer = package.texture.lock(); // Texture no longer exists, move on to the next if (!texturePointer) { @@ -62,13 +60,17 @@ bool GLTextureTransferHelper::processQueueItems(const Queue& messages) { } GLBackend::GLTexture* object = Backend::getGPUObject(*texturePointer); + object->createTexture(); + object->transfer(); - auto writeSync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); object->updateSize(); + glBindTexture(object->_target, 0); + auto writeSync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); glClientWaitSync(writeSync, GL_SYNC_FLUSH_COMMANDS_BIT, GL_TIMEOUT_IGNORED); glDeleteSync(writeSync); + object->_contentStamp = texturePointer->getDataStamp(); object->setSyncState(GLBackend::GLTexture::Transferred); } diff --git a/libraries/model/src/model/TextureMap.cpp b/libraries/model/src/model/TextureMap.cpp index 2906fe7abf..4d6ea82845 100755 --- a/libraries/model/src/model/TextureMap.cpp +++ b/libraries/model/src/model/TextureMap.cpp @@ -19,6 +19,9 @@ using namespace model; using namespace gpu; +// FIXME: Turn that define off to prevent compression +#define COMPRESS_TEXTURES + void TextureMap::setTextureSource(TextureSourcePointer& textureSource) { _textureSource = textureSource; @@ -49,10 +52,10 @@ void TextureMap::setLightmapOffsetScale(float offset, float scale) { _lightmapOffsetScale.y = scale; } -gpu::Texture* TextureUsage::process2DTextureColorFromImage(const QImage& srcImage, bool isLinear, bool doCompress, bool generateMips) { +const QImage TextureUsage::process2DImageColor(const QImage& srcImage, bool& validAlpha, bool& alphaAsMask) { QImage image = srcImage; - bool validAlpha = false; - bool alphaAsMask = true; + validAlpha = false; + alphaAsMask = true; const uint8 OPAQUE_ALPHA = 255; const uint8 TRANSPARENT_ALPHA = 0; if (image.hasAlphaChannel()) { @@ -87,53 +90,71 @@ gpu::Texture* TextureUsage::process2DTextureColorFromImage(const QImage& srcImag image = image.convertToFormat(QImage::Format_RGB888); } + return image; +} + +void TextureUsage::defineColorTexelFormats(gpu::Element& formatGPU, gpu::Element& formatMip, +const QImage& image, bool isLinear, bool doCompress) { + +#ifdef COMPRESS_TEXTURES +#else + doCompress = false; +#endif + + if (image.hasAlphaChannel()) { + gpu::Semantic gpuSemantic; + gpu::Semantic mipSemantic; + if (isLinear) { + mipSemantic = gpu::SBGRA; + if (doCompress) { + gpuSemantic = gpu::COMPRESSED_SRGBA; + } else { + gpuSemantic = gpu::SRGBA; + } + } else { + mipSemantic = gpu::BGRA; + if (doCompress) { + gpuSemantic = gpu::COMPRESSED_RGBA; + } else { + gpuSemantic = gpu::RGBA; + } + } + 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::SRGB; + if (doCompress) { + gpuSemantic = gpu::COMPRESSED_SRGB; + } else { + gpuSemantic = gpu::SRGB; + } + } else { + mipSemantic = gpu::RGB; + if (doCompress) { + gpuSemantic = gpu::COMPRESSED_RGB; + } else { + gpuSemantic = gpu::RGB; + } + } + formatGPU = gpu::Element(gpu::VEC3, gpu::NUINT8, gpuSemantic); + formatMip = gpu::Element(gpu::VEC3, gpu::NUINT8, mipSemantic); + } +} + +gpu::Texture* TextureUsage::process2DTextureColorFromImage(const QImage& srcImage, bool isLinear, bool doCompress, bool generateMips) { + bool validAlpha = false; + bool alphaAsMask = true; + QImage image = process2DImageColor(srcImage, validAlpha, alphaAsMask); + gpu::Texture* theTexture = nullptr; if ((image.width() > 0) && (image.height() > 0)) { gpu::Element formatGPU; gpu::Element formatMip; - - if (image.hasAlphaChannel()) { - gpu::Semantic gpuSemantic; - gpu::Semantic mipSemantic; - if (isLinear) { - mipSemantic = gpu::SBGRA; - if (doCompress) { - gpuSemantic = gpu::COMPRESSED_SRGBA; - } else { - gpuSemantic = gpu::SRGBA; - } - } else { - mipSemantic = gpu::BGRA; - if (doCompress) { - gpuSemantic = gpu::COMPRESSED_RGBA; - } else { - gpuSemantic = gpu::RGBA; - } - } - 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::SRGB; - if (doCompress) { - gpuSemantic = gpu::COMPRESSED_SRGB; - } else { - gpuSemantic = gpu::SRGB; - } - } else { - mipSemantic = gpu::RGB; - if (doCompress) { - gpuSemantic = gpu::COMPRESSED_RGB; - } else { - gpuSemantic = gpu::RGB; - } - } - formatGPU = gpu::Element(gpu::VEC3, gpu::NUINT8, gpuSemantic); - formatMip = gpu::Element(gpu::VEC3, gpu::NUINT8, mipSemantic); - } + defineColorTexelFormats(formatGPU, formatMip, image, isLinear, doCompress); theTexture = (gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR))); @@ -296,8 +317,11 @@ gpu::Texture* TextureUsage::createRoughnessTextureFromImage(const QImage& srcIma gpu::Texture* theTexture = nullptr; if ((image.width() > 0) && (image.height() > 0)) { - +#ifdef COMPRESS_TEXTURES gpu::Element formatGPU = gpu::Element(gpu::SCALAR, gpu::NUINT8, gpu::COMPRESSED_R); +#else + gpu::Element formatGPU = gpu::Element(gpu::SCALAR, gpu::NUINT8, gpu::RGB); +#endif gpu::Element formatMip = gpu::Element(gpu::SCALAR, gpu::NUINT8, gpu::RGB); theTexture = (gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR))); @@ -330,9 +354,13 @@ gpu::Texture* TextureUsage::createRoughnessTextureFromGlossImage(const QImage& s gpu::Texture* theTexture = nullptr; if ((image.width() > 0) && (image.height() > 0)) { +#ifdef COMPRESS_TEXTURES gpu::Element formatGPU = gpu::Element(gpu::SCALAR, gpu::NUINT8, gpu::COMPRESSED_R); +#else + gpu::Element formatGPU = gpu::Element(gpu::SCALAR, gpu::NUINT8, gpu::RGB); +#endif gpu::Element formatMip = gpu::Element(gpu::SCALAR, gpu::NUINT8, gpu::RGB); - + theTexture = (gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR))); theTexture->assignStoredMip(0, formatMip, image.byteCount(), image.constBits()); theTexture->autoGenerateMips(-1); @@ -360,7 +388,11 @@ gpu::Texture* TextureUsage::createMetallicTextureFromImage(const QImage& srcImag gpu::Texture* theTexture = nullptr; if ((image.width() > 0) && (image.height() > 0)) { +#ifdef COMPRESS_TEXTURES gpu::Element formatGPU = gpu::Element(gpu::SCALAR, gpu::NUINT8, gpu::COMPRESSED_R); +#else + gpu::Element formatGPU = gpu::Element(gpu::SCALAR, gpu::NUINT8, gpu::RGB); +#endif gpu::Element formatMip = gpu::Element(gpu::SCALAR, gpu::NUINT8, gpu::RGB); theTexture = (gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR))); @@ -405,229 +437,181 @@ public: _faceYNeg(fYN), _faceZPos(fZP), _faceZNeg(fZN) {} + + + static const CubeLayout CUBEMAP_LAYOUTS[]; + static const int NUM_CUBEMAP_LAYOUTS; + + static int findLayout(int width, int height) { + // Find the layout of the cubemap in the 2D image + int foundLayout = -1; + for (int i = 0; i < NUM_CUBEMAP_LAYOUTS; i++) { + if ((height * CUBEMAP_LAYOUTS[i]._widthRatio) == (width * CUBEMAP_LAYOUTS[i]._heightRatio)) { + foundLayout = i; + break; + } + } + return foundLayout; + } }; -gpu::Texture* TextureUsage::createCubeTextureFromImage(const QImage& srcImage, const std::string& srcImageName) { - QImage image = srcImage; - - int imageArea = image.width() * image.height(); - - - qCDebug(modelLog) << "Cube map size:" << QString(srcImageName.c_str()) << image.width() << image.height(); - - int opaquePixels = 0; - int translucentPixels = 0; - //bool isTransparent = false; - int redTotal = 0, greenTotal = 0, blueTotal = 0, alphaTotal = 0; - const int EIGHT_BIT_MAXIMUM = 255; - QColor averageColor(EIGHT_BIT_MAXIMUM, EIGHT_BIT_MAXIMUM, EIGHT_BIT_MAXIMUM); - - if (!image.hasAlphaChannel()) { - if (image.format() != QImage::Format_RGB888) { - image = image.convertToFormat(QImage::Format_RGB888); - } - // int redTotal = 0, greenTotal = 0, blueTotal = 0; - for (int y = 0; y < image.height(); y++) { - for (int x = 0; x < image.width(); x++) { - QRgb rgb = image.pixel(x, y); - redTotal += qRed(rgb); - greenTotal += qGreen(rgb); - blueTotal += qBlue(rgb); - } - } - if (imageArea > 0) { - averageColor.setRgb(redTotal / imageArea, greenTotal / imageArea, blueTotal / imageArea); - } - } else { - if (image.format() != QImage::Format_ARGB32) { - image = image.convertToFormat(QImage::Format_ARGB32); - } - - // check for translucency/false transparency - // int opaquePixels = 0; - // int translucentPixels = 0; - // int redTotal = 0, greenTotal = 0, blueTotal = 0, alphaTotal = 0; - for (int y = 0; y < image.height(); y++) { - for (int x = 0; x < image.width(); x++) { - QRgb rgb = image.pixel(x, y); - redTotal += qRed(rgb); - greenTotal += qGreen(rgb); - blueTotal += qBlue(rgb); - int alpha = qAlpha(rgb); - alphaTotal += alpha; - if (alpha == EIGHT_BIT_MAXIMUM) { - opaquePixels++; - } else if (alpha != 0) { - translucentPixels++; - } - } - } - if (opaquePixels == imageArea) { - qCDebug(modelLog) << "Image with alpha channel is completely opaque:" << QString(srcImageName.c_str()); - image = image.convertToFormat(QImage::Format_RGB888); - } - - averageColor = QColor(redTotal / imageArea, - greenTotal / imageArea, blueTotal / imageArea, alphaTotal / imageArea); - - //isTransparent = (translucentPixels >= imageArea / 2); +const CubeLayout CubeLayout::CUBEMAP_LAYOUTS[] = { + // Here is the expected layout for the faces in an image with the 1/6 aspect ratio: + // + // WIDTH + // <------> + // ^ +------+ + // | | | + // | | +X | + // | | | + // H +------+ + // E | | + // I | -X | + // G | | + // H +------+ + // T | | + // | | +Y | + // | | | + // | +------+ + // | | | + // | | -Y | + // | | | + // H +------+ + // E | | + // I | +Z | + // G | | + // H +------+ + // T | | + // | | -Z | + // | | | + // V +------+ + // + // FaceWidth = width = height / 6 + { 1, 6, + { 0, 0, true, false }, + { 0, 1, true, false }, + { 0, 2, false, true }, + { 0, 3, false, true }, + { 0, 4, true, false }, + { 0, 5, true, false } + }, + + // Here is the expected layout for the faces in an image with the 3/4 aspect ratio: + // + // <-----------WIDTH-----------> + // ^ +------+------+------+------+ + // | | | | | | + // | | | +Y | | | + // | | | | | | + // H +------+------+------+------+ + // E | | | | | + // I | -X | -Z | +X | +Z | + // G | | | | | + // H +------+------+------+------+ + // T | | | | | + // | | | -Y | | | + // | | | | | | + // V +------+------+------+------+ + // + // FaceWidth = width / 4 = height / 3 + { 4, 3, + { 2, 1, true, false }, + { 0, 1, true, false }, + { 1, 0, false, true }, + { 1, 2, false, true }, + { 3, 1, true, false }, + { 1, 1, true, false } + }, + + // Here is the expected layout for the faces in an image with the 4/3 aspect ratio: + // + // <-------WIDTH--------> + // ^ +------+------+------+ + // | | | | | + // | | | +Y | | + // | | | | | + // H +------+------+------+ + // E | | | | + // I | -X | -Z | +X | + // G | | | | + // H +------+------+------+ + // T | | | | + // | | | -Y | | + // | | | | | + // | +------+------+------+ + // | | | | | + // | | | +Z! | | <+Z is upside down! + // | | | | | + // V +------+------+------+ + // + // FaceWidth = width / 3 = height / 4 + { 3, 4, + { 2, 1, true, false }, + { 0, 1, true, false }, + { 1, 0, false, true }, + { 1, 2, false, true }, + { 1, 3, false, true }, + { 1, 1, true, false } } - +}; +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 doCompress, bool generateMips, bool generateIrradiance) { + + bool validAlpha = false; + bool alphaAsMask = true; + QImage image = process2DImageColor(srcImage, validAlpha, alphaAsMask); + gpu::Texture* theTexture = nullptr; if ((image.width() > 0) && (image.height() > 0)) { + + gpu::Element formatGPU; + gpu::Element formatMip; + defineColorTexelFormats(formatGPU, formatMip, image, isLinear, doCompress); + + // Find the layout of the cubemap in the 2D image + int foundLayout = CubeLayout::findLayout(image.width(), image.height()); - // bool isLinearRGB = true; //(_type == NORMAL_TEXTURE) || (_type == EMISSIVE_TEXTURE); - bool isLinearRGB = false; //(_type == NORMAL_TEXTURE) || (_type == EMISSIVE_TEXTURE); - - gpu::Element formatGPU = gpu::Element(gpu::VEC3, gpu::NUINT8, (isLinearRGB ? gpu::RGB : gpu::COMPRESSED_SRGB)); - gpu::Element formatMip = gpu::Element(gpu::VEC3, gpu::NUINT8, (isLinearRGB ? gpu::RGB : gpu::SRGB)); - if (image.hasAlphaChannel()) { - formatGPU = gpu::Element(gpu::VEC4, gpu::NUINT8, (isLinearRGB ? gpu::RGBA : gpu::COMPRESSED_SRGBA)); - formatMip = gpu::Element(gpu::VEC4, gpu::NUINT8, (isLinearRGB ? gpu::BGRA : gpu::SBGRA)); + std::vector faces; + // If found, go extract the faces as separate images + if (foundLayout >= 0) { + auto& layout = CubeLayout::CUBEMAP_LAYOUTS[foundLayout]; + int faceWidth = image.width() / layout._widthRatio; + + faces.push_back(image.copy(QRect(layout._faceXPos._x * faceWidth, layout._faceXPos._y * faceWidth, faceWidth, faceWidth)).mirrored(layout._faceXPos._horizontalMirror, layout._faceXPos._verticalMirror)); + faces.push_back(image.copy(QRect(layout._faceXNeg._x * faceWidth, layout._faceXNeg._y * faceWidth, faceWidth, faceWidth)).mirrored(layout._faceXNeg._horizontalMirror, layout._faceXNeg._verticalMirror)); + faces.push_back(image.copy(QRect(layout._faceYPos._x * faceWidth, layout._faceYPos._y * faceWidth, faceWidth, faceWidth)).mirrored(layout._faceYPos._horizontalMirror, layout._faceYPos._verticalMirror)); + faces.push_back(image.copy(QRect(layout._faceYNeg._x * faceWidth, layout._faceYNeg._y * faceWidth, faceWidth, faceWidth)).mirrored(layout._faceYNeg._horizontalMirror, layout._faceYNeg._verticalMirror)); + faces.push_back(image.copy(QRect(layout._faceZPos._x * faceWidth, layout._faceZPos._y * faceWidth, faceWidth, faceWidth)).mirrored(layout._faceZPos._horizontalMirror, layout._faceZPos._verticalMirror)); + faces.push_back(image.copy(QRect(layout._faceZNeg._x * faceWidth, layout._faceZNeg._y * faceWidth, faceWidth, faceWidth)).mirrored(layout._faceZNeg._horizontalMirror, layout._faceZNeg._verticalMirror)); + } else { + qCDebug(modelLog) << "Failed to find a known cube map layout from this image:" << QString(srcImageName.c_str()); + return nullptr; } - - const CubeLayout CUBEMAP_LAYOUTS[] = { - // Here is the expected layout for the faces in an image with the 1/6 aspect ratio: - // - // WIDTH - // <------> - // ^ +------+ - // | | | - // | | +X | - // | | | - // H +------+ - // E | | - // I | -X | - // G | | - // H +------+ - // T | | - // | | +Y | - // | | | - // | +------+ - // | | | - // | | -Y | - // | | | - // H +------+ - // E | | - // I | +Z | - // G | | - // H +------+ - // T | | - // | | -Z | - // | | | - // V +------+ - // - // FaceWidth = width = height / 6 - { 1, 6, - {0, 0, true, false}, - {0, 1, true, false}, - {0, 2, false, true}, - {0, 3, false, true}, - {0, 4, true, false}, - {0, 5, true, false} - }, - - // Here is the expected layout for the faces in an image with the 3/4 aspect ratio: - // - // <-----------WIDTH-----------> - // ^ +------+------+------+------+ - // | | | | | | - // | | | +Y | | | - // | | | | | | - // H +------+------+------+------+ - // E | | | | | - // I | -X | -Z | +X | +Z | - // G | | | | | - // H +------+------+------+------+ - // T | | | | | - // | | | -Y | | | - // | | | | | | - // V +------+------+------+------+ - // - // FaceWidth = width / 4 = height / 3 - { 4, 3, - {2, 1, true, false}, - {0, 1, true, false}, - {1, 0, false, true}, - {1, 2, false, true}, - {3, 1, true, false}, - {1, 1, true, false} - }, - - // Here is the expected layout for the faces in an image with the 4/3 aspect ratio: - // - // <-------WIDTH--------> - // ^ +------+------+------+ - // | | | | | - // | | | +Y | | - // | | | | | - // H +------+------+------+ - // E | | | | - // I | -X | -Z | +X | - // G | | | | - // H +------+------+------+ - // T | | | | - // | | | -Y | | - // | | | | | - // | +------+------+------+ - // | | | | | - // | | | +Z! | | <+Z is upside down! - // | | | | | - // V +------+------+------+ - // - // FaceWidth = width / 3 = height / 4 - { 3, 4, - {2, 1, true, false}, - {0, 1, true, false}, - {1, 0, false, true}, - {1, 2, false, true}, - {1, 3, false, true}, - {1, 1, true, false} - } - }; - const int NUM_CUBEMAP_LAYOUTS = sizeof(CUBEMAP_LAYOUTS) / sizeof(CubeLayout); - - // Find the layout of the cubemap in the 2D image - int foundLayout = -1; - for (int i = 0; i < NUM_CUBEMAP_LAYOUTS; i++) { - if ((image.height() * CUBEMAP_LAYOUTS[i]._widthRatio) == (image.width() * CUBEMAP_LAYOUTS[i]._heightRatio)) { - foundLayout = i; - break; - } + // If the 6 faces have been created go on and define the true Texture + if (faces.size() == gpu::Texture::NUM_FACES_PER_TYPE[gpu::Texture::TEX_CUBE]) { + theTexture = gpu::Texture::createCube(formatGPU, faces[0].width(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR, gpu::Sampler::WRAP_CLAMP)); + int f = 0; + for (auto& face : faces) { + theTexture->assignStoredMipFace(0, formatMip, face.byteCount(), face.constBits(), f); + f++; } - - std::vector faces; - // If found, go extract the faces as separate images - if (foundLayout >= 0) { - auto& layout = CUBEMAP_LAYOUTS[foundLayout]; - int faceWidth = image.width() / layout._widthRatio; - - faces.push_back(image.copy(QRect(layout._faceXPos._x * faceWidth, layout._faceXPos._y * faceWidth, faceWidth, faceWidth)).mirrored(layout._faceXPos._horizontalMirror, layout._faceXPos._verticalMirror)); - faces.push_back(image.copy(QRect(layout._faceXNeg._x * faceWidth, layout._faceXNeg._y * faceWidth, faceWidth, faceWidth)).mirrored(layout._faceXNeg._horizontalMirror, layout._faceXNeg._verticalMirror)); - faces.push_back(image.copy(QRect(layout._faceYPos._x * faceWidth, layout._faceYPos._y * faceWidth, faceWidth, faceWidth)).mirrored(layout._faceYPos._horizontalMirror, layout._faceYPos._verticalMirror)); - faces.push_back(image.copy(QRect(layout._faceYNeg._x * faceWidth, layout._faceYNeg._y * faceWidth, faceWidth, faceWidth)).mirrored(layout._faceYNeg._horizontalMirror, layout._faceYNeg._verticalMirror)); - faces.push_back(image.copy(QRect(layout._faceZPos._x * faceWidth, layout._faceZPos._y * faceWidth, faceWidth, faceWidth)).mirrored(layout._faceZPos._horizontalMirror, layout._faceZPos._verticalMirror)); - faces.push_back(image.copy(QRect(layout._faceZNeg._x * faceWidth, layout._faceZNeg._y * faceWidth, faceWidth, faceWidth)).mirrored(layout._faceZNeg._horizontalMirror, layout._faceZNeg._verticalMirror)); - } else { - qCDebug(modelLog) << "Failed to find a known cube map layout from this image:" << QString(srcImageName.c_str()); - return nullptr; - } - - // If the 6 faces have been created go on and define the true Texture - if (faces.size() == gpu::Texture::NUM_FACES_PER_TYPE[gpu::Texture::TEX_CUBE]) { - theTexture = gpu::Texture::createCube(formatGPU, faces[0].width(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR, gpu::Sampler::WRAP_CLAMP)); + + if (generateMips) { theTexture->autoGenerateMips(-1); - int f = 0; - for (auto& face : faces) { - theTexture->assignStoredMipFace(0, formatMip, face.byteCount(), face.constBits(), f); - f++; - } + } - // Generate irradiance while we are at it + // Generate irradiance while we are at it + if (generateIrradiance) { theTexture->generateIrradiance(); } + } } - + return theTexture; } + +gpu::Texture* TextureUsage::createCubeTextureFromImage(const QImage& srcImage, const std::string& srcImageName) { + return processCubeTextureColorFromImage(srcImage, srcImageName, false, true, true, true); +} diff --git a/libraries/model/src/model/TextureMap.h b/libraries/model/src/model/TextureMap.h index fa0eea55cb..daa4b0d7bb 100755 --- a/libraries/model/src/model/TextureMap.h +++ b/libraries/model/src/model/TextureMap.h @@ -43,7 +43,12 @@ public: static gpu::Texture* createLightmapTextureFromImage(const QImage& image, const std::string& srcImageName); - static gpu::Texture* process2DTextureColorFromImage(const QImage& imageSrc, bool isLinear, bool doCompress, bool generateMips); + static const QImage process2DImageColor(const QImage& srcImage, bool& validAlpha, bool& alphaAsMask); + static void defineColorTexelFormats(gpu::Element& formatGPU, gpu::Element& formatMip, + const QImage& srcImage, bool isLinear, bool doCompress); + static gpu::Texture* process2DTextureColorFromImage(const QImage& srcImage, bool isLinear, bool doCompress, bool generateMips); + static gpu::Texture* processCubeTextureColorFromImage(const QImage& srcImage, const std::string& srcImageName, bool isLinear, bool doCompress, bool generateMips, bool generateIrradiance); + }; From 04e71df3bcc3d09b338fd81681d2a4e00c4a1f87 Mon Sep 17 00:00:00 2001 From: samcake Date: Thu, 7 Apr 2016 23:05:50 -0700 Subject: [PATCH 10/12] fixing a stupid code and a warning --- libraries/gpu/src/gpu/GLBackendTexture.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/gpu/src/gpu/GLBackendTexture.cpp b/libraries/gpu/src/gpu/GLBackendTexture.cpp index 54d7fb27bb..b0b68c6a2c 100755 --- a/libraries/gpu/src/gpu/GLBackendTexture.cpp +++ b/libraries/gpu/src/gpu/GLBackendTexture.cpp @@ -49,7 +49,7 @@ const GLenum GLBackend::GLTexture::CUBE_FACE_LAYOUT[6] = { // Create the texture and allocate storage GLBackend::GLTexture::GLTexture(const Texture& texture) : _storageStamp(texture.getStamp()), - _privateTexture(allocateSingleTexture()), + _privateTexture(0), _target(gpuToGLTextureType(texture)), _size(0), _virtualSize(0), @@ -165,7 +165,7 @@ void GLBackend::GLTexture::updateSize() { (void)CHECK_GL_ERROR(); if (gpuSize) { - for (GLint level = 0; level < _numLevels; level++) { + for (GLuint level = 0; level < _numLevels; level++) { GLint levelSize{ 0 }; glGetTexLevelParameteriv(proxyType, level, GL_TEXTURE_COMPRESSED_IMAGE_SIZE, &levelSize); levelSize *= numFaces; From be178e9e0988a81076bc091bf38a45ee9a53ccf7 Mon Sep 17 00:00:00 2001 From: samcake Date: Thu, 7 Apr 2016 23:44:28 -0700 Subject: [PATCH 11/12] fixing warnings --- libraries/gpu/src/gpu/GLBackend.h | 8 +++++--- libraries/gpu/src/gpu/GLBackendTexture.cpp | 1 - 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/libraries/gpu/src/gpu/GLBackend.h b/libraries/gpu/src/gpu/GLBackend.h index 29256a322f..aabd84fbfb 100644 --- a/libraries/gpu/src/gpu/GLBackend.h +++ b/libraries/gpu/src/gpu/GLBackend.h @@ -76,9 +76,11 @@ public: class GLTexture : public GPUObject { public: + // The public gl texture object + GLuint _texture{ 0 }; + const Stamp _storageStamp; Stamp _contentStamp { 0 }; - GLuint _texture{ 0 }; const GLenum _target; GLTexture(const gpu::Texture& gpuTexture); @@ -124,11 +126,11 @@ public: static const size_t CUBE_NUM_FACES = 6; static const GLenum CUBE_FACE_LAYOUT[6]; - + private: // at creation the true texture is created in GL // it becomes public only when ready. - GLuint _privateTexture; + GLuint _privateTexture{ 0 }; void setSize(GLuint size); void setVirtualSize(GLuint size); diff --git a/libraries/gpu/src/gpu/GLBackendTexture.cpp b/libraries/gpu/src/gpu/GLBackendTexture.cpp index b0b68c6a2c..8da6b6d300 100755 --- a/libraries/gpu/src/gpu/GLBackendTexture.cpp +++ b/libraries/gpu/src/gpu/GLBackendTexture.cpp @@ -49,7 +49,6 @@ const GLenum GLBackend::GLTexture::CUBE_FACE_LAYOUT[6] = { // Create the texture and allocate storage GLBackend::GLTexture::GLTexture(const Texture& texture) : _storageStamp(texture.getStamp()), - _privateTexture(0), _target(gpuToGLTextureType(texture)), _size(0), _virtualSize(0), From 4374bd26ae210b448b3763f87038e6e950c252d4 Mon Sep 17 00:00:00 2001 From: samcake Date: Fri, 8 Apr 2016 01:37:27 -0700 Subject: [PATCH 12/12] Disabling COmpression --- libraries/model/src/model/TextureMap.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/model/src/model/TextureMap.cpp b/libraries/model/src/model/TextureMap.cpp index 4d6ea82845..014431619c 100755 --- a/libraries/model/src/model/TextureMap.cpp +++ b/libraries/model/src/model/TextureMap.cpp @@ -19,8 +19,8 @@ using namespace model; using namespace gpu; -// FIXME: Turn that define off to prevent compression -#define COMPRESS_TEXTURES +// FIXME: Declare this to enable compression +//#define COMPRESS_TEXTURES void TextureMap::setTextureSource(TextureSourcePointer& textureSource) {