diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index 22ed01fd00..e0c35b7148 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -291,18 +291,6 @@ AssetServer::AssetServer(ReceivedMessage& message) : _bakingTaskPool(this), _filesizeLimit(AssetUtils::MAX_UPLOAD_SIZE) { - // store the current state of image compression so we can reset it when this assignment is complete - _wasColorTextureCompressionEnabled = image::isColorTexturesCompressionEnabled(); - _wasGrayscaleTextureCompressionEnabled = image::isGrayscaleTexturesCompressionEnabled(); - _wasNormalTextureCompressionEnabled = image::isNormalTexturesCompressionEnabled(); - _wasCubeTextureCompressionEnabled = image::isCubeTexturesCompressionEnabled(); - - // enable compression in image library - image::setColorTexturesCompressionEnabled(true); - image::setGrayscaleTexturesCompressionEnabled(true); - image::setNormalTexturesCompressionEnabled(true); - image::setCubeTexturesCompressionEnabled(true); - BAKEABLE_TEXTURE_EXTENSIONS = image::getSupportedFormats(); qDebug() << "Supported baking texture formats:" << BAKEABLE_MODEL_EXTENSIONS; @@ -354,12 +342,6 @@ void AssetServer::aboutToFinish() { while (_pendingBakes.size() > 0) { QCoreApplication::processEvents(); } - - // re-set defaults in image library - image::setColorTexturesCompressionEnabled(_wasCubeTextureCompressionEnabled); - image::setGrayscaleTexturesCompressionEnabled(_wasGrayscaleTextureCompressionEnabled); - image::setNormalTexturesCompressionEnabled(_wasNormalTextureCompressionEnabled); - image::setCubeTexturesCompressionEnabled(_wasCubeTextureCompressionEnabled); } void AssetServer::run() { diff --git a/assignment-client/src/assets/AssetServer.h b/assignment-client/src/assets/AssetServer.h index 96a220d64d..b3d0f18a8f 100644 --- a/assignment-client/src/assets/AssetServer.h +++ b/assignment-client/src/assets/AssetServer.h @@ -167,11 +167,6 @@ private: using RequestQueue = QVector, SharedNodePointer>>; RequestQueue _queuedRequests; - bool _wasColorTextureCompressionEnabled { false }; - bool _wasGrayscaleTextureCompressionEnabled { false }; - bool _wasNormalTextureCompressionEnabled { false }; - bool _wasCubeTextureCompressionEnabled { false }; - uint64_t _filesizeLimit; }; diff --git a/libraries/baking/src/TextureBaker.cpp b/libraries/baking/src/TextureBaker.cpp index 2b50f6be97..ecfe724441 100644 --- a/libraries/baking/src/TextureBaker.cpp +++ b/libraries/baking/src/TextureBaker.cpp @@ -22,12 +22,16 @@ #include #include +#include + #include "ModelBakingLoggingCategory.h" const QString BAKED_TEXTURE_KTX_EXT = ".ktx"; const QString BAKED_TEXTURE_BCN_SUFFIX = "_bcn.ktx"; const QString BAKED_META_TEXTURE_SUFFIX = ".texmeta.json"; +bool TextureBaker::_compressionEnabled = true; + TextureBaker::TextureBaker(const QUrl& textureURL, image::TextureUsage::Type textureType, const QDir& outputDirectory, const QString& metaTexturePathPrefix, const QString& baseFilename, const QByteArray& textureContent) : @@ -124,42 +128,45 @@ void TextureBaker::processTexture() { TextureMeta meta; + auto originalCopyFilePath = _outputDirectory.absoluteFilePath(_textureURL.fileName()); { - auto filePath = _outputDirectory.absoluteFilePath(_textureURL.fileName()); - QFile file { filePath }; + QFile file { originalCopyFilePath }; if (!file.open(QIODevice::WriteOnly) || file.write(_originalTexture) == -1) { handleError("Could not write original texture for " + _textureURL.toString()); return; } - _outputFiles.push_back(filePath); + // IMPORTANT: _originalTexture is empty past this point + _originalTexture.clear(); + _outputFiles.push_back(originalCopyFilePath); meta.original = _metaTexturePathPrefix +_textureURL.fileName(); } - // IMPORTANT: _originalTexture is empty past this point - auto processedTexture = image::processImage(std::move(_originalTexture), _textureURL.toString().toStdString(), - ABSOLUTE_MAX_TEXTURE_NUM_PIXELS, _textureType, _abortProcessing); - processedTexture->setSourceHash(hash); - - if (shouldStop()) { + auto buffer = std::static_pointer_cast(std::make_shared(originalCopyFilePath)); + if (!buffer->open(QIODevice::ReadOnly)) { + handleError("Could not open original file at " + originalCopyFilePath); return; } - if (!processedTexture) { - handleError("Could not process texture " + _textureURL.toString()); - return; - } + // Compressed KTX + if (_compressionEnabled) { + auto processedTexture = image::processImage(buffer, _textureURL.toString().toStdString(), + ABSOLUTE_MAX_TEXTURE_NUM_PIXELS, _textureType, true, _abortProcessing); + if (!processedTexture) { + handleError("Could not process texture " + _textureURL.toString()); + return; + } + processedTexture->setSourceHash(hash); - - auto memKTX = gpu::Texture::serialize(*processedTexture); + if (shouldStop()) { + return; + } - if (!memKTX) { - handleError("Could not serialize " + _textureURL.toString() + " to KTX"); - return; - } + auto memKTX = gpu::Texture::serialize(*processedTexture); + if (!memKTX) { + handleError("Could not serialize " + _textureURL.toString() + " to KTX"); + return; + } - - // attempt to write the baked texture to the destination file path - if (memKTX->_header.isCompressed()) { const char* name = khronos::gl::texture::toString(memKTX->_header.getGLInternaFormat()); if (name == nullptr) { handleError("Could not determine internal format for compressed KTX: " + _textureURL.toString()); @@ -178,21 +185,45 @@ void TextureBaker::processTexture() { } _outputFiles.push_back(filePath); meta.availableTextureTypes[memKTX->_header.getGLInternaFormat()] = _metaTexturePathPrefix + fileName; - } else { + } + + // Uncompressed KTX + if (_textureType == image::TextureUsage::Type::CUBE_TEXTURE) { + buffer->reset(); + auto processedTexture = image::processImage(std::move(buffer), _textureURL.toString().toStdString(), + ABSOLUTE_MAX_TEXTURE_NUM_PIXELS, _textureType, false, _abortProcessing); + if (!processedTexture) { + handleError("Could not process texture " + _textureURL.toString()); + return; + } + processedTexture->setSourceHash(hash); + + if (shouldStop()) { + return; + } + + auto memKTX = gpu::Texture::serialize(*processedTexture); + if (!memKTX) { + handleError("Could not serialize " + _textureURL.toString() + " to KTX"); + return; + } + const char* data = reinterpret_cast(memKTX->_storage->data()); const size_t length = memKTX->_storage->size(); auto fileName = _baseFilename + ".ktx"; auto filePath = _outputDirectory.absoluteFilePath(fileName); - QFile ktxTextureFile { filePath }; - if (!ktxTextureFile.open(QIODevice::WriteOnly) || ktxTextureFile.write(data, length) == -1) { - handleError("Could not write ktx texture for " + _textureURL.toString()); + QFile bakedTextureFile { filePath }; + if (!bakedTextureFile.open(QIODevice::WriteOnly) || bakedTextureFile.write(data, length) == -1) { + handleError("Could not write baked texture for " + _textureURL.toString()); return; } _outputFiles.push_back(filePath); + meta.uncompressed = _metaTexturePathPrefix + fileName; + } else { + buffer.reset(); } - { auto data = meta.serialize(); _metaTextureFileName = _outputDirectory.absoluteFilePath(_baseFilename + BAKED_META_TEXTURE_SUFFIX); diff --git a/libraries/baking/src/TextureBaker.h b/libraries/baking/src/TextureBaker.h index 54839c001a..c8c4fb73b8 100644 --- a/libraries/baking/src/TextureBaker.h +++ b/libraries/baking/src/TextureBaker.h @@ -41,6 +41,8 @@ public: virtual void setWasAborted(bool wasAborted) override; + static void setCompressionEnabled(bool enabled) { _compressionEnabled = enabled; } + public slots: virtual void bake() override; virtual void abort() override; @@ -65,6 +67,8 @@ private: QString _metaTexturePathPrefix; std::atomic _abortProcessing { false }; + + static bool _compressionEnabled; }; #endif // hifi_TextureBaker_h diff --git a/libraries/image/src/image/Image.cpp b/libraries/image/src/image/Image.cpp index dc45257d2b..7fc3a73f87 100644 --- a/libraries/image/src/image/Image.cpp +++ b/libraries/image/src/image/Image.cpp @@ -50,11 +50,6 @@ std::atomic RECTIFIED_TEXTURE_COUNT{ 0 }; // possibly causing the element not to be constructed yet static const auto& HDR_FORMAT = gpu::Element::COLOR_R11G11B10; -static std::atomic compressColorTextures { false }; -static std::atomic compressNormalTextures { false }; -static std::atomic compressGrayscaleTextures { false }; -static std::atomic compressCubeTextures { false }; - uint rectifyDimension(const uint& dimension) { if (dimension == 0) { return 0; @@ -128,112 +123,63 @@ TextureUsage::TextureLoader TextureUsage::getTextureLoaderForType(Type type, con } gpu::TexturePointer TextureUsage::createStrict2DTextureFromImage(QImage&& srcImage, const std::string& srcImageName, - const std::atomic& abortProcessing) { - return process2DTextureColorFromImage(std::move(srcImage), srcImageName, true, abortProcessing); + bool compress, const std::atomic& abortProcessing) { + return process2DTextureColorFromImage(std::move(srcImage), srcImageName, compress, true, abortProcessing); } gpu::TexturePointer TextureUsage::create2DTextureFromImage(QImage&& srcImage, const std::string& srcImageName, - const std::atomic& abortProcessing) { - return process2DTextureColorFromImage(std::move(srcImage), srcImageName, false, abortProcessing); + bool compress, const std::atomic& abortProcessing) { + return process2DTextureColorFromImage(std::move(srcImage), srcImageName, compress, false, abortProcessing); } gpu::TexturePointer TextureUsage::createAlbedoTextureFromImage(QImage&& srcImage, const std::string& srcImageName, - const std::atomic& abortProcessing) { - return process2DTextureColorFromImage(std::move(srcImage), srcImageName, false, abortProcessing); + bool compress, const std::atomic& abortProcessing) { + return process2DTextureColorFromImage(std::move(srcImage), srcImageName, compress, false, abortProcessing); } gpu::TexturePointer TextureUsage::createEmissiveTextureFromImage(QImage&& srcImage, const std::string& srcImageName, - const std::atomic& abortProcessing) { - return process2DTextureColorFromImage(std::move(srcImage), srcImageName, false, abortProcessing); + bool compress, const std::atomic& abortProcessing) { + return process2DTextureColorFromImage(std::move(srcImage), srcImageName, compress, false, abortProcessing); } gpu::TexturePointer TextureUsage::createLightmapTextureFromImage(QImage&& srcImage, const std::string& srcImageName, - const std::atomic& abortProcessing) { - return process2DTextureColorFromImage(std::move(srcImage), srcImageName, false, abortProcessing); + bool compress, const std::atomic& abortProcessing) { + return process2DTextureColorFromImage(std::move(srcImage), srcImageName, compress, false, abortProcessing); } gpu::TexturePointer TextureUsage::createNormalTextureFromNormalImage(QImage&& srcImage, const std::string& srcImageName, - const std::atomic& abortProcessing) { - return process2DTextureNormalMapFromImage(std::move(srcImage), srcImageName, false, abortProcessing); + bool compress, const std::atomic& abortProcessing) { + return process2DTextureNormalMapFromImage(std::move(srcImage), srcImageName, compress, false, abortProcessing); } gpu::TexturePointer TextureUsage::createNormalTextureFromBumpImage(QImage&& srcImage, const std::string& srcImageName, - const std::atomic& abortProcessing) { - return process2DTextureNormalMapFromImage(std::move(srcImage), srcImageName, true, abortProcessing); + bool compress, const std::atomic& abortProcessing) { + return process2DTextureNormalMapFromImage(std::move(srcImage), srcImageName, compress, true, abortProcessing); } gpu::TexturePointer TextureUsage::createRoughnessTextureFromImage(QImage&& srcImage, const std::string& srcImageName, - const std::atomic& abortProcessing) { - return process2DTextureGrayscaleFromImage(std::move(srcImage), srcImageName, false, abortProcessing); + bool compress, const std::atomic& abortProcessing) { + return process2DTextureGrayscaleFromImage(std::move(srcImage), srcImageName, compress, false, abortProcessing); } gpu::TexturePointer TextureUsage::createRoughnessTextureFromGlossImage(QImage&& srcImage, const std::string& srcImageName, - const std::atomic& abortProcessing) { - return process2DTextureGrayscaleFromImage(std::move(srcImage), srcImageName, true, abortProcessing); + bool compress, const std::atomic& abortProcessing) { + return process2DTextureGrayscaleFromImage(std::move(srcImage), srcImageName, compress, true, abortProcessing); } gpu::TexturePointer TextureUsage::createMetallicTextureFromImage(QImage&& srcImage, const std::string& srcImageName, - const std::atomic& abortProcessing) { - return process2DTextureGrayscaleFromImage(std::move(srcImage), srcImageName, false, abortProcessing); + bool compress, const std::atomic& abortProcessing) { + return process2DTextureGrayscaleFromImage(std::move(srcImage), srcImageName, compress, false, abortProcessing); } gpu::TexturePointer TextureUsage::createCubeTextureFromImage(QImage&& srcImage, const std::string& srcImageName, - const std::atomic& abortProcessing) { - return processCubeTextureColorFromImage(std::move(srcImage), srcImageName, true, abortProcessing); + bool compress, const std::atomic& abortProcessing) { + return processCubeTextureColorFromImage(std::move(srcImage), srcImageName, compress, true, abortProcessing); } gpu::TexturePointer TextureUsage::createCubeTextureFromImageWithoutIrradiance(QImage&& srcImage, const std::string& srcImageName, - const std::atomic& abortProcessing) { - return processCubeTextureColorFromImage(std::move(srcImage), srcImageName, false, abortProcessing); -} - - -bool isColorTexturesCompressionEnabled() { -#if CPU_MIPMAPS - return compressColorTextures.load(); -#else - return false; -#endif -} - -bool isNormalTexturesCompressionEnabled() { -#if CPU_MIPMAPS - return compressNormalTextures.load(); -#else - return false; -#endif -} - -bool isGrayscaleTexturesCompressionEnabled() { -#if CPU_MIPMAPS - return compressGrayscaleTextures.load(); -#else - return false; -#endif -} - -bool isCubeTexturesCompressionEnabled() { -#if CPU_MIPMAPS - return compressCubeTextures.load(); -#else - return false; -#endif -} - -void setColorTexturesCompressionEnabled(bool enabled) { - compressColorTextures.store(enabled); -} - -void setNormalTexturesCompressionEnabled(bool enabled) { - compressNormalTextures.store(enabled); -} - -void setGrayscaleTexturesCompressionEnabled(bool enabled) { - compressGrayscaleTextures.store(enabled); -} - -void setCubeTexturesCompressionEnabled(bool enabled) { - compressCubeTextures.store(enabled); + bool compress, const std::atomic& abortProcessing) { + return processCubeTextureColorFromImage(std::move(srcImage), srcImageName, compress, false, abortProcessing); } static float denormalize(float value, const float minValue) { @@ -255,17 +201,11 @@ uint32 packR11G11B10F(const glm::vec3& color) { return glm::packF2x11_1x10(ucolor); } -QImage processRawImageData(QByteArray&& content, const std::string& filename) { - // Take a local copy to force move construction - // https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#f18-for-consume-parameters-pass-by-x-and-stdmove-the-parameter - QByteArray localCopy = std::move(content); - +QImage processRawImageData(QIODevice& content, const std::string& filename) { // Help the QImage loader by extracting the image file format from the url filename ext. // Some tga are not created properly without it. auto filenameExtension = filename.substr(filename.find_last_of('.') + 1); - QBuffer buffer; - buffer.setData(localCopy); - QImageReader imageReader(&buffer, filenameExtension.c_str()); + QImageReader imageReader(&content, filenameExtension.c_str()); if (imageReader.canRead()) { return imageReader.read(); @@ -273,8 +213,8 @@ QImage processRawImageData(QByteArray&& content, const std::string& filename) { // Extension could be incorrect, try to detect the format from the content QImageReader newImageReader; newImageReader.setDecideFormatFromContent(true); - buffer.setData(localCopy); - newImageReader.setDevice(&buffer); + content.reset(); + newImageReader.setDevice(&content); if (newImageReader.canRead()) { qCWarning(imagelogging) << "Image file" << filename.c_str() << "has extension" << filenameExtension.c_str() @@ -286,11 +226,14 @@ QImage processRawImageData(QByteArray&& content, const std::string& filename) { return QImage(); } -gpu::TexturePointer processImage(QByteArray&& content, const std::string& filename, +gpu::TexturePointer processImage(std::shared_ptr content, const std::string& filename, int maxNumPixels, TextureUsage::Type textureType, - const std::atomic& abortProcessing) { + bool compress, const std::atomic& abortProcessing) { - QImage image = processRawImageData(std::move(content), filename); + QImage image = processRawImageData(*content.get(), filename); + // Texture content can take up a lot of memory. Here we release our ownership of that content + // in case it can be released. + content.reset(); int imageWidth = image.width(); int imageHeight = image.height(); @@ -316,7 +259,7 @@ gpu::TexturePointer processImage(QByteArray&& content, const std::string& filena } auto loader = TextureUsage::getTextureLoaderForType(textureType); - auto texture = loader(std::move(image), filename, abortProcessing); + auto texture = loader(std::move(image), filename, compress, abortProcessing); return texture; } @@ -806,7 +749,7 @@ void processTextureAlpha(const QImage& srcImage, bool& validAlpha, bool& alphaAs validAlpha = (numOpaques != NUM_PIXELS); } -gpu::TexturePointer TextureUsage::process2DTextureColorFromImage(QImage&& srcImage, const std::string& srcImageName, +gpu::TexturePointer TextureUsage::process2DTextureColorFromImage(QImage&& srcImage, const std::string& srcImageName, bool compress, bool isStrict, const std::atomic& abortProcessing) { PROFILE_RANGE(resource_parse, "process2DTextureColorFromImage"); QImage image = processSourceImage(std::move(srcImage), false); @@ -827,7 +770,7 @@ gpu::TexturePointer TextureUsage::process2DTextureColorFromImage(QImage&& srcIma if ((image.width() > 0) && (image.height() > 0)) { gpu::Element formatMip; gpu::Element formatGPU; - if (isColorTexturesCompressionEnabled()) { + if (compress) { if (validAlpha) { // NOTE: This disables BC1a compression because it was producing odd artifacts on text textures // for the tutorial. Instead we use BC3 (which is larger) but doesn't produce the same artifacts). @@ -944,7 +887,8 @@ QImage processBumpMap(QImage&& image) { return result; } gpu::TexturePointer TextureUsage::process2DTextureNormalMapFromImage(QImage&& srcImage, const std::string& srcImageName, - bool isBumpMap, const std::atomic& abortProcessing) { + bool compress, bool isBumpMap, + const std::atomic& abortProcessing) { PROFILE_RANGE(resource_parse, "process2DTextureNormalMapFromImage"); QImage image = processSourceImage(std::move(srcImage), false); @@ -961,7 +905,7 @@ gpu::TexturePointer TextureUsage::process2DTextureNormalMapFromImage(QImage&& sr if ((image.width() > 0) && (image.height() > 0)) { gpu::Element formatMip; gpu::Element formatGPU; - if (isNormalTexturesCompressionEnabled()) { + if (compress) { formatGPU = gpu::Element::COLOR_COMPRESSED_BCX_XY; } else { #ifdef USE_GLES @@ -983,7 +927,7 @@ gpu::TexturePointer TextureUsage::process2DTextureNormalMapFromImage(QImage&& sr } gpu::TexturePointer TextureUsage::process2DTextureGrayscaleFromImage(QImage&& srcImage, const std::string& srcImageName, - bool isInvertedPixels, + bool compress, bool isInvertedPixels, const std::atomic& abortProcessing) { PROFILE_RANGE(resource_parse, "process2DTextureGrayscaleFromImage"); QImage image = processSourceImage(std::move(srcImage), false); @@ -1001,7 +945,7 @@ gpu::TexturePointer TextureUsage::process2DTextureGrayscaleFromImage(QImage&& sr if ((image.width() > 0) && (image.height() > 0)) { gpu::Element formatMip; gpu::Element formatGPU; - if (isGrayscaleTexturesCompressionEnabled()) { + if (compress) { formatGPU = gpu::Element::COLOR_COMPRESSED_BCX_RED; } else { #ifdef USE_GLES @@ -1348,7 +1292,7 @@ QImage convertToHDRFormat(QImage&& srcImage, gpu::Element format) { } gpu::TexturePointer TextureUsage::processCubeTextureColorFromImage(QImage&& srcImage, const std::string& srcImageName, - bool generateIrradiance, + bool compress, bool generateIrradiance, const std::atomic& abortProcessing) { PROFILE_RANGE(resource_parse, "processCubeTextureColorFromImage"); @@ -1376,7 +1320,7 @@ gpu::TexturePointer TextureUsage::processCubeTextureColorFromImage(QImage&& srcI gpu::Element formatMip; gpu::Element formatGPU; - if (isCubeTexturesCompressionEnabled()) { + if (compress) { formatGPU = gpu::Element::COLOR_COMPRESSED_BCX_HDR_RGB; } else { #ifdef USE_GLES diff --git a/libraries/image/src/image/Image.h b/libraries/image/src/image/Image.h index 39f5ea3bab..ccf4845fca 100644 --- a/libraries/image/src/image/Image.h +++ b/libraries/image/src/image/Image.h @@ -41,60 +41,50 @@ enum Type { UNUSED_TEXTURE }; -using TextureLoader = std::function&)>; +using TextureLoader = std::function&)>; TextureLoader getTextureLoaderForType(Type type, const QVariantMap& options = QVariantMap()); gpu::TexturePointer create2DTextureFromImage(QImage&& image, const std::string& srcImageName, - const std::atomic& abortProcessing); + bool compress, const std::atomic& abortProcessing); gpu::TexturePointer createStrict2DTextureFromImage(QImage&& image, const std::string& srcImageName, - const std::atomic& abortProcessing); + bool compress, const std::atomic& abortProcessing); gpu::TexturePointer createAlbedoTextureFromImage(QImage&& image, const std::string& srcImageName, - const std::atomic& abortProcessing); + bool compress, const std::atomic& abortProcessing); gpu::TexturePointer createEmissiveTextureFromImage(QImage&& image, const std::string& srcImageName, - const std::atomic& abortProcessing); + bool compress, const std::atomic& abortProcessing); gpu::TexturePointer createNormalTextureFromNormalImage(QImage&& image, const std::string& srcImageName, - const std::atomic& abortProcessing); + bool compress, const std::atomic& abortProcessing); gpu::TexturePointer createNormalTextureFromBumpImage(QImage&& image, const std::string& srcImageName, - const std::atomic& abortProcessing); + bool compress, const std::atomic& abortProcessing); gpu::TexturePointer createRoughnessTextureFromImage(QImage&& image, const std::string& srcImageName, - const std::atomic& abortProcessing); + bool compress, const std::atomic& abortProcessing); gpu::TexturePointer createRoughnessTextureFromGlossImage(QImage&& image, const std::string& srcImageName, - const std::atomic& abortProcessing); + bool compress, const std::atomic& abortProcessing); gpu::TexturePointer createMetallicTextureFromImage(QImage&& image, const std::string& srcImageName, - const std::atomic& abortProcessing); + bool compress, const std::atomic& abortProcessing); gpu::TexturePointer createCubeTextureFromImage(QImage&& image, const std::string& srcImageName, - const std::atomic& abortProcessing); + bool compress, const std::atomic& abortProcessing); gpu::TexturePointer createCubeTextureFromImageWithoutIrradiance(QImage&& image, const std::string& srcImageName, - const std::atomic& abortProcessing); + bool compress, const std::atomic& abortProcessing); gpu::TexturePointer createLightmapTextureFromImage(QImage&& image, const std::string& srcImageName, - const std::atomic& abortProcessing); + bool compress, const std::atomic& abortProcessing); -gpu::TexturePointer process2DTextureColorFromImage(QImage&& srcImage, const std::string& srcImageName, bool isStrict, - const std::atomic& abortProcessing); -gpu::TexturePointer process2DTextureNormalMapFromImage(QImage&& srcImage, const std::string& srcImageName, bool isBumpMap, - const std::atomic& abortProcessing); -gpu::TexturePointer process2DTextureGrayscaleFromImage(QImage&& srcImage, const std::string& srcImageName, bool isInvertedPixels, - const std::atomic& abortProcessing); -gpu::TexturePointer processCubeTextureColorFromImage(QImage&& srcImage, const std::string& srcImageName, bool generateIrradiance, - const std::atomic& abortProcessing); +gpu::TexturePointer process2DTextureColorFromImage(QImage&& srcImage, const std::string& srcImageName, bool compress, + bool isStrict, const std::atomic& abortProcessing); +gpu::TexturePointer process2DTextureNormalMapFromImage(QImage&& srcImage, const std::string& srcImageName, bool compress, + bool isBumpMap, const std::atomic& abortProcessing); +gpu::TexturePointer process2DTextureGrayscaleFromImage(QImage&& srcImage, const std::string& srcImageName, bool compress, + bool isInvertedPixels, const std::atomic& abortProcessing); +gpu::TexturePointer processCubeTextureColorFromImage(QImage&& srcImage, const std::string& srcImageName, bool compress, + bool generateIrradiance, const std::atomic& abortProcessing); } // namespace TextureUsage const QStringList getSupportedFormats(); -bool isColorTexturesCompressionEnabled(); -bool isNormalTexturesCompressionEnabled(); -bool isGrayscaleTexturesCompressionEnabled(); -bool isCubeTexturesCompressionEnabled(); - -void setColorTexturesCompressionEnabled(bool enabled); -void setNormalTexturesCompressionEnabled(bool enabled); -void setGrayscaleTexturesCompressionEnabled(bool enabled); -void setCubeTexturesCompressionEnabled(bool enabled); - -gpu::TexturePointer processImage(QByteArray&& content, const std::string& url, +gpu::TexturePointer processImage(std::shared_ptr content, const std::string& url, int maxNumPixels, TextureUsage::Type textureType, - const std::atomic& abortProcessing = false); + bool compress = false, const std::atomic& abortProcessing = false); } // namespace image diff --git a/libraries/ktx/src/TextureMeta.cpp b/libraries/ktx/src/TextureMeta.cpp index 3a2abf24c4..c8427c1f60 100644 --- a/libraries/ktx/src/TextureMeta.cpp +++ b/libraries/ktx/src/TextureMeta.cpp @@ -33,6 +33,9 @@ bool TextureMeta::deserialize(const QByteArray& data, TextureMeta* meta) { if (root.contains("original")) { meta->original = root["original"].toString(); } + if (root.contains("uncompressed")) { + meta->uncompressed = root["uncompressed"].toString(); + } if (root.contains("compressed")) { auto compressed = root["compressed"].toObject(); for (auto it = compressed.constBegin(); it != compressed.constEnd(); it++) { @@ -57,6 +60,7 @@ QByteArray TextureMeta::serialize() { compressed[name] = kv.second.toString(); } root["original"] = original.toString(); + root["uncompressed"] = uncompressed.toString(); root["compressed"] = compressed; doc.setObject(root); diff --git a/libraries/ktx/src/TextureMeta.h b/libraries/ktx/src/TextureMeta.h index 6582c29e70..5450fee110 100644 --- a/libraries/ktx/src/TextureMeta.h +++ b/libraries/ktx/src/TextureMeta.h @@ -35,6 +35,7 @@ struct TextureMeta { QByteArray serialize(); QUrl original; + QUrl uncompressed; std::unordered_map availableTextureTypes; }; diff --git a/libraries/model-networking/src/model-networking/TextureCache.cpp b/libraries/model-networking/src/model-networking/TextureCache.cpp index ed21fd35bc..40b31cac53 100644 --- a/libraries/model-networking/src/model-networking/TextureCache.cpp +++ b/libraries/model-networking/src/model-networking/TextureCache.cpp @@ -50,6 +50,8 @@ #include +#include + Q_LOGGING_CATEGORY(trace_resource_parse_image, "trace.resource.parse.image") Q_LOGGING_CATEGORY(trace_resource_parse_image_raw, "trace.resource.parse.image.raw") Q_LOGGING_CATEGORY(trace_resource_parse_image_ktx, "trace.resource.parse.image.ktx") @@ -277,7 +279,7 @@ gpu::TexturePointer TextureCache::getImageTexture(const QString& path, image::Te return nullptr; } auto loader = image::TextureUsage::getTextureLoaderForType(type, options); - return gpu::TexturePointer(loader(std::move(image), path.toStdString(), false)); + return gpu::TexturePointer(loader(std::move(image), path.toStdString(), false, false)); } QSharedPointer TextureCache::createResource(const QUrl& url, const QSharedPointer& fallback, @@ -964,7 +966,6 @@ void NetworkTexture::loadMetaContent(const QByteArray& content) { return; } - auto& backend = DependencyManager::get()->getGPUContext()->getBackend(); for (auto pair : meta.availableTextureTypes) { gpu::Element elFormat; @@ -990,6 +991,21 @@ void NetworkTexture::loadMetaContent(const QByteArray& content) { } } +#ifndef Q_OS_ANDROID + if (!meta.uncompressed.isEmpty()) { + _currentlyLoadingResourceType = ResourceType::KTX; + _activeUrl = _activeUrl.resolved(meta.uncompressed); + + auto textureCache = DependencyManager::get(); + auto self = _self.lock(); + if (!self) { + return; + } + QMetaObject::invokeMethod(this, "attemptRequest", Qt::QueuedConnection); + return; + } +#endif + if (!meta.original.isEmpty()) { _currentlyLoadingResourceType = ResourceType::ORIGINAL; _activeUrl = _activeUrl.resolved(meta.original); @@ -1143,7 +1159,8 @@ void ImageReader::read() { PROFILE_RANGE_EX(resource_parse_image_raw, __FUNCTION__, 0xffff0000, 0); // IMPORTANT: _content is empty past this point - texture = image::processImage(std::move(_content), _url.toString().toStdString(), _maxNumPixels, networkTexture->getTextureType()); + auto buffer = std::shared_ptr((QIODevice*)new OwningBuffer(std::move(_content))); + texture = image::processImage(std::move(buffer), _url.toString().toStdString(), _maxNumPixels, networkTexture->getTextureType()); if (!texture) { qCWarning(modelnetworking) << "Could not process:" << _url; diff --git a/libraries/shared/src/OwningBuffer.h b/libraries/shared/src/OwningBuffer.h new file mode 100644 index 0000000000..80184286bc --- /dev/null +++ b/libraries/shared/src/OwningBuffer.h @@ -0,0 +1,29 @@ +// +// OwningBuffer.h +// shared/src +// +// Created by Ryan Huffman on 5/31/2018. +// Copyright 2018 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_OwningBuffer_h +#define hifi_OwningBuffer_h + +#include +class OwningBuffer : public QBuffer { +public: + OwningBuffer(const QByteArray& content) : _content(content) { + setData(_content); + } + OwningBuffer(QByteArray&& content) : _content(std::move(content)) { + setData(_content); + } + +private: + QByteArray _content; +}; + +#endif // hifi_OwningBuffer_h diff --git a/tools/oven/src/Oven.cpp b/tools/oven/src/Oven.cpp index c3fec2d15e..52b6db1aa5 100644 --- a/tools/oven/src/Oven.cpp +++ b/tools/oven/src/Oven.cpp @@ -25,12 +25,6 @@ Oven* Oven::_staticInstance { nullptr }; Oven::Oven() { _staticInstance = this; - // enable compression in image library - image::setColorTexturesCompressionEnabled(true); - image::setGrayscaleTexturesCompressionEnabled(true); - image::setNormalTexturesCompressionEnabled(true); - image::setCubeTexturesCompressionEnabled(true); - // setup our worker threads setupWorkerThreads(QThread::idealThreadCount()); diff --git a/tools/oven/src/OvenCLIApplication.cpp b/tools/oven/src/OvenCLIApplication.cpp index 6f87359134..c405c5f4a0 100644 --- a/tools/oven/src/OvenCLIApplication.cpp +++ b/tools/oven/src/OvenCLIApplication.cpp @@ -15,6 +15,7 @@ #include #include +#include #include "BakerCLI.h" @@ -47,10 +48,7 @@ OvenCLIApplication::OvenCLIApplication(int argc, char* argv[]) : if (parser.isSet(CLI_DISABLE_TEXTURE_COMPRESSION_PARAMETER)) { qDebug() << "Disabling texture compression"; - image::setColorTexturesCompressionEnabled(false); - image::setGrayscaleTexturesCompressionEnabled(false); - image::setNormalTexturesCompressionEnabled(false); - image::setCubeTexturesCompressionEnabled(false); + TextureBaker::setCompressionEnabled(false); } QMetaObject::invokeMethod(cli, "bakeFile", Qt::QueuedConnection, Q_ARG(QUrl, inputUrl),