From 56d11206541c93fef18eecd9fd4ce4d9e1fc28d3 Mon Sep 17 00:00:00 2001 From: sam Date: Fri, 17 Feb 2017 01:15:27 -0800 Subject: [PATCH] progressing on io with ktx --- libraries/gpu/src/gpu/Texture.cpp | 20 ++-- libraries/gpu/src/gpu/Texture.h | 17 ++-- libraries/gpu/src/gpu/Texture_ktx.cpp | 84 ++++++++++++++-- libraries/ktx/src/ktx/KTX.h | 19 +++- libraries/model/src/model/TextureMap.cpp | 120 +++++++++++++---------- 5 files changed, 183 insertions(+), 77 deletions(-) diff --git a/libraries/gpu/src/gpu/Texture.cpp b/libraries/gpu/src/gpu/Texture.cpp index d7ae202e7d..ba7723001a 100755 --- a/libraries/gpu/src/gpu/Texture.cpp +++ b/libraries/gpu/src/gpu/Texture.cpp @@ -264,19 +264,19 @@ Texture* Texture::createExternal2D(const ExternalRecycler& recycler, const Sampl } Texture* Texture::create1D(const Element& texelFormat, uint16 width, const Sampler& sampler) { - return create(TEX_1D, texelFormat, width, 1, 1, 1, 1, sampler); + return create(TEX_1D, texelFormat, width, 1, 1, 1, 0, sampler); } Texture* Texture::create2D(const Element& texelFormat, uint16 width, uint16 height, const Sampler& sampler) { - return create(TEX_2D, texelFormat, width, height, 1, 1, 1, sampler); + return create(TEX_2D, texelFormat, width, height, 1, 1, 0, sampler); } Texture* Texture::create3D(const Element& texelFormat, uint16 width, uint16 height, uint16 depth, const Sampler& sampler) { - return create(TEX_3D, texelFormat, width, height, depth, 1, 1, sampler); + return create(TEX_3D, texelFormat, width, height, depth, 1, 0, sampler); } Texture* Texture::createCube(const Element& texelFormat, uint16 width, const Sampler& sampler) { - return create(TEX_CUBE, texelFormat, width, width, 1, 1, 1, sampler); + return create(TEX_CUBE, texelFormat, width, width, 1, 1, 0, sampler); } Texture* Texture::create(Type type, const Element& texelFormat, uint16 width, uint16 height, uint16 depth, uint16 numSamples, uint16 numSlices, const Sampler& sampler) @@ -321,7 +321,7 @@ Texture::~Texture() } Texture::Size Texture::resize(Type type, const Element& texelFormat, uint16 width, uint16 height, uint16 depth, uint16 numSamples, uint16 numSlices) { - if (width && height && depth && numSamples && numSlices) { + if (width && height && depth && numSamples) { bool changed = false; if ( _type != type) { @@ -382,20 +382,20 @@ Texture::Size Texture::resize(Type type, const Element& texelFormat, uint16 widt } Texture::Size Texture::resize1D(uint16 width, uint16 numSamples) { - return resize(TEX_1D, getTexelFormat(), width, 1, 1, numSamples, 1); + return resize(TEX_1D, getTexelFormat(), width, 1, 1, numSamples, 0); } Texture::Size Texture::resize2D(uint16 width, uint16 height, uint16 numSamples) { - return resize(TEX_2D, getTexelFormat(), width, height, 1, numSamples, 1); + return resize(TEX_2D, getTexelFormat(), width, height, 1, numSamples, 0); } Texture::Size Texture::resize3D(uint16 width, uint16 height, uint16 depth, uint16 numSamples) { - return resize(TEX_3D, getTexelFormat(), width, height, depth, numSamples, 1); + return resize(TEX_3D, getTexelFormat(), width, height, depth, numSamples, 0); } Texture::Size Texture::resizeCube(uint16 width, uint16 numSamples) { - return resize(TEX_CUBE, getTexelFormat(), width, 1, 1, numSamples, 1); + return resize(TEX_CUBE, getTexelFormat(), width, 1, 1, numSamples, 0); } Texture::Size Texture::reformat(const Element& texelFormat) { - return resize(_type, texelFormat, getWidth(), getHeight(), getDepth(), getNumSamples(), getNumSlices()); + return resize(_type, texelFormat, getWidth(), getHeight(), getDepth(), getNumSamples(), _numSlices); } bool Texture::isColorRenderTarget() const { diff --git a/libraries/gpu/src/gpu/Texture.h b/libraries/gpu/src/gpu/Texture.h index b99e9da371..fb8d94150d 100755 --- a/libraries/gpu/src/gpu/Texture.h +++ b/libraries/gpu/src/gpu/Texture.h @@ -352,7 +352,12 @@ public: uint32 getNumTexels() const { return _width * _height * _depth * getNumFaces(); } - uint16 getNumSlices() const { return _numSlices; } + // The texture is an array if the _numSlices is not 0. + // otherwise, if _numSLices is 0, then the texture is NOT an array + // The number of slices returned is 1 at the minimum (if not an array) or the actual _numSlices. + bool isArray() const { return _numSlices > 0; } + uint16 getNumSlices() const { return (isArray() ? _numSlices : 1); } + uint16 getNumSamples() const { return _numSamples; } @@ -502,12 +507,12 @@ protected: uint32 _size = 0; Element _texelFormat; - uint16 _width = 1; - uint16 _height = 1; - uint16 _depth = 1; + uint16 _width { 1 }; + uint16 _height { 1 }; + uint16 _depth { 1 }; - uint16 _numSamples = 1; - uint16 _numSlices = 1; + uint16 _numSamples { 1 }; + uint16 _numSlices { 0 }; // if _numSlices is 0, the texture is not an "Array", the getNumSlices reported is 1 uint16 _maxMip { 0 }; uint16 _minMip { 0 }; diff --git a/libraries/gpu/src/gpu/Texture_ktx.cpp b/libraries/gpu/src/gpu/Texture_ktx.cpp index 623a3493da..c36c0f14d8 100644 --- a/libraries/gpu/src/gpu/Texture_ktx.cpp +++ b/libraries/gpu/src/gpu/Texture_ktx.cpp @@ -16,12 +16,57 @@ using namespace gpu; ktx::KTXUniquePointer Texture::serialize(const Texture& texture) { - ktx::Header header; + + // From texture format to ktx format description + auto texelFormat = texture.getTexelFormat(); + if ( !( (texelFormat == Format::COLOR_RGBA_32) + || (texelFormat == Format::COLOR_SRGBA_32) + )) + return nullptr; + header.setUncompressed(ktx::GLType::UNSIGNED_BYTE, 4, ktx::GLFormat::BGRA, ktx::GLInternalFormat_Uncompressed::RGBA8, ktx::GLBaseInternalFormat::RGBA); - header.pixelWidth = texture.getWidth(); - header.pixelHeight = texture.getHeight(); - header.numberOfMipmapLevels = texture.mipLevels(); + + // Set Dimensions + switch (texture.getType()) { + case TEX_1D: { + if (texture.isArray()) { + header.set1DArray(texture.getWidth(), texture.getNumSlices()); + } else { + header.set1D(texture.getWidth()); + } + break; + } + case TEX_2D: { + if (texture.isArray()) { + header.set2DArray(texture.getWidth(), texture.getHeight(), texture.getNumSlices()); + } else { + header.set2D(texture.getWidth(), texture.getHeight()); + } + break; + } + case TEX_3D: { + if (texture.isArray()) { + header.set3DArray(texture.getWidth(), texture.getHeight(), texture.getDepth(), texture.getNumSlices()); + } else { + header.set3D(texture.getWidth(), texture.getHeight(), texture.getDepth()); + } + break; + } + case TEX_CUBE: { + if (texture.isArray()) { + header.setCubeArray(texture.getWidth(), texture.getHeight(), texture.getNumSlices()); + } else { + header.setCube(texture.getWidth(), texture.getHeight()); + } + break; + } + default: + return nullptr; + } + + // Number level of mips coming + header.numberOfMipmapLevels = texture.maxMip(); ktx::Images images; for (uint32_t level = 0; level < header.numberOfMipmapLevels; level++) { @@ -34,17 +79,42 @@ ktx::KTXUniquePointer Texture::serialize(const Texture& texture) { auto ktxBuffer = ktx::KTX::create(header, images); return ktxBuffer; } + Texture* Texture::unserialize(const ktx::KTXUniquePointer& srcData) { if (!srcData) { return nullptr; } - const auto& header = *srcData->getHeader(); Format mipFormat = Format::COLOR_SBGRA_32; - Format pixelFormat = Format::COLOR_SRGBA_32; + Format texelFormat = Format::COLOR_SRGBA_32; - auto tex = Texture::create2D(pixelFormat, header.getPixelWidth(), header.getPixelHeight()); + // Find Texture Type based on dimensions + Type type = TEX_1D; + if (header.pixelWidth == 0) { + return nullptr; + } else if (header.pixelHeight == 0) { + type = TEX_1D; + } else if (header.pixelDepth == 0) { + if (header.numberOfFaces == ktx::NUM_CUBEMAPFACES) { + type = TEX_CUBE; + } else { + type = TEX_2D; + } + } else { + type = TEX_3D; + } + + auto tex = Texture::create( type, + texelFormat, + header.getPixelWidth(), + header.getPixelHeight(), + header.getPixelDepth(), + 1, // num Samples + header.getNumberOfSlices(), + Sampler()); + + // Assing the mips availables uint16_t level = 0; for (auto& image : srcData->_images) { tex->assignStoredMip(level, mipFormat, image._imageSize, image._bytes); diff --git a/libraries/ktx/src/ktx/KTX.h b/libraries/ktx/src/ktx/KTX.h index 3a4c19971a..8e79d90dc0 100644 --- a/libraries/ktx/src/ktx/KTX.h +++ b/libraries/ktx/src/ktx/KTX.h @@ -353,7 +353,7 @@ namespace ktx { uint32_t glInternalFormat; uint32_t glBaseInternalFormat; - uint32_t pixelWidth { 0 }; + uint32_t pixelWidth { 1 }; uint32_t pixelHeight { 0 }; uint32_t pixelDepth { 0 }; uint32_t numberOfArrayElements { 0 }; @@ -393,6 +393,23 @@ namespace ktx { glInternalFormat = (uint32_t) internalFormat; glBaseInternalFormat = (uint32_t) baseInternalFormat; } + + void setDimensions(uint32_t width, uint32_t height = 0, uint32_t depth = 0, uint32_t numSlices = 0, uint32_t numFaces = 1) { + pixelWidth = (width > 0 ? width : 1); + pixelHeight = height; + pixelDepth = depth; + numberOfArrayElements = numSlices; + numberOfFaces = ((numFaces == 1) || (numFaces == NUM_CUBEMAPFACES) ? numFaces : 1); + } + void set1D(uint32_t width) { setDimensions(width); } + void set1DArray(uint32_t width, uint32_t numSlices) { setDimensions(width, 0, 0, (numSlices > 0 ? numSlices : 1)); } + void set2D(uint32_t width, uint32_t height) { setDimensions(width, height); } + void set2DArray(uint32_t width, uint32_t height, uint32_t numSlices) { setDimensions(width, height, 0, (numSlices > 0 ? numSlices : 1)); } + void set3D(uint32_t width, uint32_t height, uint32_t depth) { setDimensions(width, height, depth); } + void set3DArray(uint32_t width, uint32_t height, uint32_t depth, uint32_t numSlices) { setDimensions(width, height, depth, (numSlices > 0 ? numSlices : 1)); } + void setCube(uint32_t width, uint32_t height) { setDimensions(width, height, 0, 0, NUM_CUBEMAPFACES); } + void setCubeArray(uint32_t width, uint32_t height, uint32_t numSlices) { setDimensions(width, height, 0, (numSlices > 0 ? numSlices : 1), NUM_CUBEMAPFACES); } + }; // Key Values diff --git a/libraries/model/src/model/TextureMap.cpp b/libraries/model/src/model/TextureMap.cpp index 0416c22d5e..8e27c4f4f0 100755 --- a/libraries/model/src/model/TextureMap.cpp +++ b/libraries/model/src/model/TextureMap.cpp @@ -85,6 +85,61 @@ QImage processSourceImage(const QImage& srcImage, bool cubemap) { return srcImage; } +gpu::Texture* cacheTexture(const std::string& name, gpu::Texture* srcTexture, bool write = true, bool read = true) { + if (!srcTexture) { + return nullptr; + } + gpu::Texture* returnedTexture = srcTexture; + + auto theKTX = Texture::serialize(*srcTexture); + if (theKTX) { + // Prepare cache directory + QString path("hifi_ktx/"); + QFileInfo originalFileInfo(path); + QString docsLocation = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation); + path = docsLocation + "/" + path; + QFileInfo info(path); + if (!info.absoluteDir().exists()) { + QString originalRelativePath = originalFileInfo.path(); + QDir(docsLocation).mkpath(originalRelativePath); + } + std::string filename(path.toStdString()); + filename += name; + filename += ".ktx"; + + if (write) { + FILE* file = fopen (filename.c_str(),"wb"); + if (file != nullptr) { + fwrite(theKTX->_storage->data(), 1, theKTX->_storage->size(), file); + fclose (file); + } + } + + if (read) { + FILE* file = fopen (filename.c_str(),"rb"); + if (file != nullptr) { + // obtain file size: + fseek (file , 0 , SEEK_END); + auto size = ftell(file); + rewind(file); + + std::unique_ptr storage(new ktx::Storage(size)); + fread(storage->_bytes, 1, storage->_size, file); + fclose (file); + + //then create a new texture out of the ktx + auto theNewTexure = Texture::unserialize(ktx::KTX::create(storage)); + + if (theNewTexure) { + returnedTexture = theNewTexure; + delete srcTexture; + } + } + } + } + return returnedTexture; +} + void TextureMap::setTextureSource(TextureSourcePointer& textureSource) { _textureSource = textureSource; } @@ -269,57 +324,10 @@ gpu::Texture* TextureUsage::process2DTextureColorFromImage(const QImage& srcImag if (generateMips) { ::generateMips(theTexture, image, formatMip, false); } - auto theKTX = Texture::serialize(*theTexture); - if (theKTX) { - // save that! - QString path("hifi_ktx/"); - QFileInfo originalFileInfo(path); - QString docsLocation = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation); - path = docsLocation + "/" + path; - QFileInfo info(path); - if (!info.absoluteDir().exists()) { - QString originalRelativePath = originalFileInfo.path(); - QDir(docsLocation).mkpath(originalRelativePath); - } - std::string filename(path.toStdString()); - filename += std::to_string((size_t) theTexture); - filename += ".ktx"; - - { - FILE* file = fopen (filename.c_str(),"wb"); - if (file != nullptr) { - fwrite(theKTX->_storage->data(), 1, theKTX->_storage->size(), file); - fclose (file); - } - } - - { - FILE* file = fopen (filename.c_str(),"rb"); - if (file != nullptr) { - // obtain file size: - fseek (file , 0 , SEEK_END); - auto size = ftell(file); - rewind(file); - - std::unique_ptr storage(new ktx::Storage(size)); - fread(storage->_bytes, 1, storage->_size, file); - fclose (file); - - //then create a new texture out of the ktx - auto theNewTexure = Texture::unserialize(ktx::KTX::create(storage)); - - if (theNewTexure) { - auto srcTexture = theTexture; - theTexture = theNewTexure; - delete srcTexture; - } - } - } - } + theTexture = cacheTexture(std::to_string((size_t) theTexture), theTexture); } - return theTexture; } @@ -360,6 +368,8 @@ gpu::Texture* TextureUsage::createNormalTextureFromNormalImage(const QImage& src theTexture->setSource(srcImageName); theTexture->assignStoredMip(0, formatMip, image.byteCount(), image.constBits()); generateMips(theTexture, image, formatMip, true); + + theTexture = cacheTexture(std::to_string((size_t) theTexture), theTexture); } return theTexture; @@ -446,6 +456,8 @@ gpu::Texture* TextureUsage::createNormalTextureFromBumpImage(const QImage& srcIm theTexture->setSource(srcImageName); theTexture->assignStoredMip(0, formatMip, image.byteCount(), image.constBits()); generateMips(theTexture, image, formatMip, true); + + theTexture = cacheTexture(std::to_string((size_t) theTexture), theTexture); } return theTexture; @@ -479,8 +491,8 @@ gpu::Texture* TextureUsage::createRoughnessTextureFromImage(const QImage& srcIma theTexture->setSource(srcImageName); theTexture->assignStoredMip(0, formatMip, image.byteCount(), image.constBits()); generateMips(theTexture, image, formatMip, true); - - // FIXME queue for transfer to GPU and block on completion + + theTexture = cacheTexture(std::to_string((size_t) theTexture), theTexture); } return theTexture; @@ -518,8 +530,8 @@ gpu::Texture* TextureUsage::createRoughnessTextureFromGlossImage(const QImage& s theTexture->setSource(srcImageName); theTexture->assignStoredMip(0, formatMip, image.byteCount(), image.constBits()); generateMips(theTexture, image, formatMip, true); - - // FIXME queue for transfer to GPU and block on completion + + theTexture = cacheTexture(std::to_string((size_t) theTexture), theTexture); } return theTexture; @@ -555,7 +567,7 @@ gpu::Texture* TextureUsage::createMetallicTextureFromImage(const QImage& srcImag theTexture->assignStoredMip(0, formatMip, image.byteCount(), image.constBits()); generateMips(theTexture, image, formatMip, true); - // FIXME queue for transfer to GPU and block on completion + theTexture = cacheTexture(std::to_string((size_t) theTexture), theTexture); } return theTexture; @@ -886,6 +898,8 @@ gpu::Texture* TextureUsage::processCubeTextureColorFromImage(const QImage& srcIm PROFILE_RANGE(resource_parse, "generateIrradiance"); theTexture->generateIrradiance(); } + + theTexture = cacheTexture(std::to_string((size_t) theTexture), theTexture); } }