From 61d78bc93131cc524e34a5bb28f6984cec6929f9 Mon Sep 17 00:00:00 2001 From: Sam Cake Date: Thu, 30 Mar 2017 23:29:37 -0700 Subject: [PATCH] BRinging the cool texture management of the gl45 backend to gl41, which fixes the broken ao on 41 among other things --- libraries/gpu-gl/src/gpu/gl/GLTexture.h | 4 +- libraries/gpu-gl/src/gpu/gl41/GL41Backend.h | 37 +-- .../src/gpu/gl41/GL41BackendTexture.cpp | 304 ++++++------------ libraries/gpu-gl/src/gpu/gl45/GL45Backend.h | 8 +- .../src/gpu/gl45/GL45BackendTexture.cpp | 5 +- .../gpu/gl45/GL45BackendVariableTexture.cpp | 2 +- libraries/gpu/src/gpu/Texture.cpp | 74 ++--- libraries/gpu/src/gpu/Texture.h | 73 ++--- 8 files changed, 177 insertions(+), 330 deletions(-) diff --git a/libraries/gpu-gl/src/gpu/gl/GLTexture.h b/libraries/gpu-gl/src/gpu/gl/GLTexture.h index 1f91e17157..b47aa3e8dd 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLTexture.h +++ b/libraries/gpu-gl/src/gpu/gl/GLTexture.h @@ -43,7 +43,7 @@ public: static const GLenum WRAP_MODES[Sampler::NUM_WRAP_MODES]; protected: - virtual uint32 size() const = 0; + virtual Size size() const = 0; virtual void generateMips() const = 0; GLTexture(const std::weak_ptr& backend, const Texture& texture, GLuint id); @@ -57,7 +57,7 @@ public: protected: GLExternalTexture(const std::weak_ptr& backend, const Texture& texture, GLuint id); void generateMips() const override {} - uint32 size() const override { return 0; } + Size size() const override { return 0; } }; diff --git a/libraries/gpu-gl/src/gpu/gl41/GL41Backend.h b/libraries/gpu-gl/src/gpu/gl41/GL41Backend.h index ab66a0a302..93d65b74dd 100644 --- a/libraries/gpu-gl/src/gpu/gl41/GL41Backend.h +++ b/libraries/gpu-gl/src/gpu/gl41/GL41Backend.h @@ -65,15 +65,15 @@ public: ~GL41FixedAllocationTexture(); protected: - uint32 size() const override { return _size; } + Size size() const override { return _size; } void allocateStorage() const; void syncSampler() const override; - const uint32 _size { 0 }; + const Size _size { 0 }; }; class GL41AttachmentTexture : public GL41FixedAllocationTexture { using Parent = GL41FixedAllocationTexture; - friend class GL45Backend; + friend class GL41Backend; protected: GL41AttachmentTexture(const std::weak_ptr& backend, const Texture& texture); ~GL41AttachmentTexture(); @@ -86,32 +86,13 @@ public: GL41StrictResourceTexture(const std::weak_ptr& backend, const Texture& texture); }; - /* class GL41Texture : public GLTexture { - using Parent = GLTexture; - static GLuint allocate(); - - public: - ~GL41Texture(); - - private: - GL41Texture(const std::weak_ptr& backend, const Texture& buffer); - - void generateMips() const override; - uint32 size() const override; - + class GL41ResourceTexture : public GL41FixedAllocationTexture { + using Parent = GL41FixedAllocationTexture; friend class GL41Backend; - const Stamp _storageStamp; - mutable Stamp _contentStamp { 0 }; - mutable Stamp _samplerStamp { 0 }; - const uint32 _size; - - - bool isOutdated() const; - void withPreservedTexture(std::function f) const; - void syncContent() const; - void syncSampler() const; - };*/ - + protected: + GL41ResourceTexture(const std::weak_ptr& backend, const Texture& texture); + ~GL41ResourceTexture(); + }; protected: GLuint getFramebufferID(const FramebufferPointer& framebuffer) override; diff --git a/libraries/gpu-gl/src/gpu/gl41/GL41BackendTexture.cpp b/libraries/gpu-gl/src/gpu/gl41/GL41BackendTexture.cpp index 092591a538..1a2652a950 100644 --- a/libraries/gpu-gl/src/gpu/gl41/GL41BackendTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl41/GL41BackendTexture.cpp @@ -48,7 +48,7 @@ GLTexture* GL41Backend::syncGPUObject(const TexturePointer& texturePointer) { case TextureUsageType::RESOURCE: { qCDebug(gpugllogging) << "variable / Strict texture " << texture.source().c_str(); - object = new GL41StrictResourceTexture(shared_from_this(), texture); + object = new GL41ResourceTexture(shared_from_this(), texture); break; } @@ -95,18 +95,12 @@ void GL41Texture::generateMips() const { void GL41Texture::copyMipFaceLinesFromTexture(uint16_t mip, uint8_t face, const uvec3& size, uint32_t yOffset, GLenum format, GLenum type, const void* sourcePointer) const { if (GL_TEXTURE_2D == _target) { - glTextureSubImage2D(_id, mip, 0, yOffset, size.x, size.y, format, type, sourcePointer); + glTexSubImage2D(_target, mip, 0, yOffset, size.x, size.y, format, type, sourcePointer); } else if (GL_TEXTURE_CUBE_MAP == _target) { - // DSA ARB does not work on AMD, so use EXT - // unless EXT is not available on the driver - if (glTextureSubImage2DEXT) { - auto target = GLTexture::CUBE_FACE_LAYOUT[face]; - glTextureSubImage2DEXT(_id, target, mip, 0, yOffset, size.x, size.y, format, type, sourcePointer); - } else { - glTextureSubImage3D(_id, mip, 0, yOffset, face, size.x, size.y, 1, format, type, sourcePointer); - } + auto target = GLTexture::CUBE_FACE_LAYOUT[face]; + glTexSubImage2D(target, mip, 0, yOffset, size.x, size.y, format, type, sourcePointer); } else { - Q_ASSERT(false); + assert(false); } (void)CHECK_GL_ERROR(); } @@ -128,194 +122,6 @@ void GL41Texture::copyMipFaceFromTexture(uint16_t sourceMip, uint16_t targetMip, void GL41Texture::syncSampler() const { const Sampler& sampler = _gpuObject.getSampler(); - const auto& fm = FILTER_MODES[sampler.getFilter()]; - glTextureParameteri(_id, GL_TEXTURE_MIN_FILTER, fm.minFilter); - glTextureParameteri(_id, GL_TEXTURE_MAG_FILTER, fm.magFilter); - - if (sampler.doComparison()) { - glTextureParameteri(_id, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE); - glTextureParameteri(_id, GL_TEXTURE_COMPARE_FUNC, COMPARISON_TO_GL[sampler.getComparisonFunction()]); - } else { - glTextureParameteri(_id, GL_TEXTURE_COMPARE_MODE, GL_NONE); - } - - glTextureParameteri(_id, GL_TEXTURE_WRAP_S, WRAP_MODES[sampler.getWrapModeU()]); - glTextureParameteri(_id, GL_TEXTURE_WRAP_T, WRAP_MODES[sampler.getWrapModeV()]); - glTextureParameteri(_id, GL_TEXTURE_WRAP_R, WRAP_MODES[sampler.getWrapModeW()]); - glTextureParameterf(_id, GL_TEXTURE_MAX_ANISOTROPY_EXT, sampler.getMaxAnisotropy()); - glTextureParameterfv(_id, GL_TEXTURE_BORDER_COLOR, (const float*)&sampler.getBorderColor()); - glTextureParameterf(_id, GL_TEXTURE_MIN_LOD, sampler.getMinMip()); - glTextureParameterf(_id, GL_TEXTURE_MAX_LOD, (sampler.getMaxMip() == Sampler::MAX_MIP_LEVEL ? 1000.f : sampler.getMaxMip())); -} - -using GL45FixedAllocationTexture = GL45Backend::GL45FixedAllocationTexture; - -GL41FixedAllocationTexture::GL41FixedAllocationTexture(const std::weak_ptr& backend, const Texture& texture) : GL45Texture(backend, texture), _size(texture.evalTotalSize()) { - allocateStorage(); - syncSampler(); -} - -GL41FixedAllocationTexture::~GL41FixedAllocationTexture() { -} - -void GL41FixedAllocationTexture::allocateStorage() const { - const GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(_gpuObject.getTexelFormat()); - const auto dimensions = _gpuObject.getDimensions(); - const auto mips = _gpuObject.getNumMips(); - - glTextureStorage2D(_id, mips, texelFormat.internalFormat, dimensions.x, dimensions.y); - glTextureParameteri(_id, GL_TEXTURE_BASE_LEVEL, 0); -} - -void GL41FixedAllocationTexture::syncSampler() const { - Parent::syncSampler(); - const Sampler& sampler = _gpuObject.getSampler(); - auto baseMip = std::max(sampler.getMipOffset(), sampler.getMinMip()); - glTextureParameteri(_id, GL_TEXTURE_BASE_LEVEL, baseMip); - glTextureParameterf(_id, GL_TEXTURE_MIN_LOD, (float)sampler.getMinMip()); - glTextureParameterf(_id, GL_TEXTURE_MAX_LOD, (sampler.getMaxMip() == Sampler::MAX_MIP_LEVEL ? 1000.f : sampler.getMaxMip())); -} - -// Renderbuffer attachment textures -using GL41AttachmentTexture = GL45Backend::GL41AttachmentTexture; - -GL41AttachmentTexture::GL41AttachmentTexture(const std::weak_ptr& backend, const Texture& texture) : GL45FixedAllocationTexture(backend, texture) { - Backend::updateTextureGPUFramebufferMemoryUsage(0, size()); -} - -GL41AttachmentTexture::~GL41AttachmentTexture() { - Backend::updateTextureGPUFramebufferMemoryUsage(size(), 0); -} - -// Strict resource textures -using GL41StrictResourceTexture = GL41Backend::GL41StrictResourceTexture; - -GL41StrictResourceTexture::GL41StrictResourceTexture(const std::weak_ptr& backend, const Texture& texture) : GL45FixedAllocationTexture(backend, texture) { - auto mipLevels = _gpuObject.getNumMips(); - for (uint16_t sourceMip = 0; sourceMip < mipLevels; ++sourceMip) { - uint16_t targetMip = sourceMip; - size_t maxFace = GLTexture::getFaceCount(_target); - for (uint8_t face = 0; face < maxFace; ++face) { - copyMipFaceFromTexture(sourceMip, targetMip, face); - } - } - if (texture.isAutogenerateMips()) { - generateMips(); - } -} - - -using GL41TexelFormat = GLTexelFormat; -using GL41Texture = GL41Backend::GL41Texture; - - - -GLTexture* GL41Backend::syncGPUObject(const TexturePointer& texturePointer) { - if (!texturePointer) { - return nullptr; - } - const Texture& texture = *texturePointer; - if (TextureUsageType::EXTERNAL == texture.getUsageType()) { - return Parent::syncGPUObject(texturePointer); - } - - if (!texture.isDefined()) { - // NO texture definition yet so let's avoid thinking - return nullptr; - } - - // If the object hasn't been created, or the object definition is out of date, drop and re-create - GL41Texture* object = Backend::getGPUObject(texture); - - if (!object || object->_storageStamp < texture.getStamp()) { - // This automatically any previous texture - object = new GL41Texture(shared_from_this(), texture); - object->withPreservedTexture([&] { - if (object->_contentStamp <= texture.getDataStamp()) { - // FIXME implement synchronous texture transfer here - object->syncContent(); - } - - if (object->_samplerStamp <= texture.getSamplerStamp()) { - object->syncSampler(); - } - }); - } - /* - // FIXME internalize to GL41Texture 'sync' function - if (object->isOutdated()) { - object->withPreservedTexture([&] { - if (object->_contentStamp <= texture.getDataStamp()) { - // FIXME implement synchronous texture transfer here - object->syncContent(); - } - - if (object->_samplerStamp <= texture.getSamplerStamp()) { - object->syncSampler(); - } - }); - }*/ - - return object; -} - -GL41Texture::GL41Texture(const std::weak_ptr& backend, const Texture& texture) - : GLTexture(backend, texture, allocate()), _storageStamp { texture.getStamp() }, _size(texture.evalTotalSize()) { - incrementTextureGPUCount(); - withPreservedTexture([&] { - GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(_gpuObject.getTexelFormat(), _gpuObject.getStoredMipFormat()); - auto numMips = _gpuObject.getNumMips(); - for (uint16_t mipLevel = 0; mipLevel < numMips; ++mipLevel) { - // Get the mip level dimensions, accounting for the downgrade level - Vec3u dimensions = _gpuObject.evalMipDimensions(mipLevel); - uint8_t face = 0; - for (GLenum target : getFaceTargets(_target)) { - const Byte* mipData = nullptr; - gpu::Texture::PixelsPointer mip; - if (_gpuObject.isStoredMipFaceAvailable(mipLevel, face)) { - mip = _gpuObject.accessStoredMipFace(mipLevel, face); - if (mip) { - mipData = mip->readData(); - } else { - mipData = nullptr; - } - } - glTexImage2D(target, mipLevel, texelFormat.internalFormat, dimensions.x, dimensions.y, 0, texelFormat.format, texelFormat.type, mipData); - (void)CHECK_GL_ERROR(); - ++face; - } - } - glTexParameteri(_target, GL_TEXTURE_BASE_LEVEL, 0); - glTexParameteri(_target, GL_TEXTURE_MAX_LEVEL, numMips - 1); - - if (texture.isAutogenerateMips()) { - glGenerateMipmap(_target); - (void)CHECK_GL_ERROR(); - } - }); -} - -GL41Texture::~GL41Texture() { - -} - -bool GL41Texture::isOutdated() const { - if (_samplerStamp <= _gpuObject.getSamplerStamp()) { - return true; - } - if (TextureUsageType::RESOURCE == _gpuObject.getUsageType() && _contentStamp <= _gpuObject.getDataStamp()) { - return true; - } - return false; -} - -void GL41Texture::syncContent() const { - // FIXME actually copy the texture data - _contentStamp = _gpuObject.getDataStamp() + 1; -} - -void GL41Texture::syncSampler() const { - const Sampler& sampler = _gpuObject.getSampler(); const auto& fm = FILTER_MODES[sampler.getFilter()]; glTexParameteri(_target, GL_TEXTURE_MIN_FILTER, fm.minFilter); glTexParameteri(_target, GL_TEXTURE_MAG_FILTER, fm.magFilter); @@ -333,12 +139,106 @@ void GL41Texture::syncSampler() const { glTexParameterfv(_target, GL_TEXTURE_BORDER_COLOR, (const float*)&sampler.getBorderColor()); glTexParameteri(_target, GL_TEXTURE_BASE_LEVEL, (uint16)sampler.getMipOffset()); + glTexParameterf(_target, GL_TEXTURE_MIN_LOD, (float)sampler.getMinMip()); glTexParameterf(_target, GL_TEXTURE_MAX_LOD, (sampler.getMaxMip() == Sampler::MAX_MIP_LEVEL ? 1000.f : sampler.getMaxMip())); + glTexParameterf(_target, GL_TEXTURE_MAX_ANISOTROPY_EXT, sampler.getMaxAnisotropy()); - _samplerStamp = _gpuObject.getSamplerStamp() + 1; } -uint32 GL41Texture::size() const { - return _size; +using GL41FixedAllocationTexture = GL41Backend::GL41FixedAllocationTexture; + +GL41FixedAllocationTexture::GL41FixedAllocationTexture(const std::weak_ptr& backend, const Texture& texture) : GL41Texture(backend, texture), _size(texture.evalTotalSize()) { + withPreservedTexture([&] { + allocateStorage(); + syncSampler(); + }); +} + +GL41FixedAllocationTexture::~GL41FixedAllocationTexture() { +} + +void GL41FixedAllocationTexture::allocateStorage() const { + const GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(_gpuObject.getTexelFormat()); + const auto numMips = _gpuObject.getNumMips(); + + // glTextureStorage2D(_id, mips, texelFormat.internalFormat, dimensions.x, dimensions.y); + for (GLint level = 0; level < numMips; ++level) { + Vec3u dimensions = _gpuObject.evalMipDimensions(level); + for (GLenum target : getFaceTargets(_target)) { + glTexImage2D(target, level, texelFormat.internalFormat, dimensions.x, dimensions.y, 0, texelFormat.format, texelFormat.type, nullptr); + } + } + + glTexParameteri(_target, GL_TEXTURE_BASE_LEVEL, 0); + glTexParameteri(_target, GL_TEXTURE_MAX_LEVEL, numMips - 1); +} + +void GL41FixedAllocationTexture::syncSampler() const { + Parent::syncSampler(); + const Sampler& sampler = _gpuObject.getSampler(); + auto baseMip = std::max(sampler.getMipOffset(), sampler.getMinMip()); + + glTexParameteri(_target, GL_TEXTURE_BASE_LEVEL, baseMip); + glTexParameterf(_target, GL_TEXTURE_MIN_LOD, (float)sampler.getMinMip()); + glTexParameterf(_target, GL_TEXTURE_MAX_LOD, (sampler.getMaxMip() == Sampler::MAX_MIP_LEVEL ? 1000.f : sampler.getMaxMip())); +} + +// Renderbuffer attachment textures +using GL41AttachmentTexture = GL41Backend::GL41AttachmentTexture; + +GL41AttachmentTexture::GL41AttachmentTexture(const std::weak_ptr& backend, const Texture& texture) : GL41FixedAllocationTexture(backend, texture) { + Backend::updateTextureGPUFramebufferMemoryUsage(0, size()); +} + +GL41AttachmentTexture::~GL41AttachmentTexture() { + Backend::updateTextureGPUFramebufferMemoryUsage(size(), 0); +} + +// Strict resource textures +using GL41StrictResourceTexture = GL41Backend::GL41StrictResourceTexture; + +GL41StrictResourceTexture::GL41StrictResourceTexture(const std::weak_ptr& backend, const Texture& texture) : GL41FixedAllocationTexture(backend, texture) { + withPreservedTexture([&] { + + auto mipLevels = _gpuObject.getNumMips(); + for (uint16_t sourceMip = 0; sourceMip < mipLevels; ++sourceMip) { + uint16_t targetMip = sourceMip; + size_t maxFace = GLTexture::getFaceCount(_target); + for (uint8_t face = 0; face < maxFace; ++face) { + copyMipFaceFromTexture(sourceMip, targetMip, face); + } + } + }); + + if (texture.isAutogenerateMips()) { + generateMips(); + } +} + +// resource textures +using GL41ResourceTexture = GL41Backend::GL41ResourceTexture; + +GL41ResourceTexture::GL41ResourceTexture(const std::weak_ptr& backend, const Texture& texture) : GL41FixedAllocationTexture(backend, texture) { + Backend::updateTextureGPUMemoryUsage(0, size()); + + withPreservedTexture([&] { + + auto mipLevels = _gpuObject.getNumMips(); + for (uint16_t sourceMip = 0; sourceMip < mipLevels; ++sourceMip) { + uint16_t targetMip = sourceMip; + size_t maxFace = GLTexture::getFaceCount(_target); + for (uint8_t face = 0; face < maxFace; ++face) { + copyMipFaceFromTexture(sourceMip, targetMip, face); + } + } + }); + + if (texture.isAutogenerateMips()) { + generateMips(); + } +} + +GL41ResourceTexture::~GL41ResourceTexture() { + Backend::updateTextureGPUMemoryUsage(size(), 0); } diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h b/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h index 6a9811b055..ca8028aff6 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h +++ b/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h @@ -58,10 +58,10 @@ public: ~GL45FixedAllocationTexture(); protected: - uint32 size() const override { return _size; } + Size size() const override { return _size; } void allocateStorage() const; void syncSampler() const override; - const uint32 _size { 0 }; + const Size _size { 0 }; }; class GL45AttachmentTexture : public GL45FixedAllocationTexture { @@ -173,7 +173,7 @@ public: bool canDemote() const { return _allocatedMip < _maxAllocatedMip; } bool hasPendingTransfers() const { return _populatedMip > _allocatedMip; } void executeNextTransfer(const TexturePointer& currentTexture); - uint32 size() const override { return _size; } + Size size() const override { return _size; } virtual void populateTransferQueue() = 0; virtual void promote() = 0; virtual void demote() = 0; @@ -188,7 +188,7 @@ public: // The highest (lowest resolution) mip that we will support, relative to the number // of mips in the gpu::Texture object uint16 _maxAllocatedMip { 0 }; - uint32 _size { 0 }; + Size _size { 0 }; // Contains a series of lambdas that when executed will transfer data to the GPU, modify // the _populatedMip and update the sampler in order to fully populate the allocated texture // until _populatedMip == _allocatedMip diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp index ae2a558a05..ab4153c04c 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp @@ -18,7 +18,6 @@ #include #include -#include #include #include "../gl/GLTexelFormat.h" @@ -167,8 +166,10 @@ void GL45Texture::syncSampler() const { glTextureParameteri(_id, GL_TEXTURE_WRAP_S, WRAP_MODES[sampler.getWrapModeU()]); glTextureParameteri(_id, GL_TEXTURE_WRAP_T, WRAP_MODES[sampler.getWrapModeV()]); glTextureParameteri(_id, GL_TEXTURE_WRAP_R, WRAP_MODES[sampler.getWrapModeW()]); + glTextureParameterf(_id, GL_TEXTURE_MAX_ANISOTROPY_EXT, sampler.getMaxAnisotropy()); glTextureParameterfv(_id, GL_TEXTURE_BORDER_COLOR, (const float*)&sampler.getBorderColor()); + glTextureParameterf(_id, GL_TEXTURE_MIN_LOD, sampler.getMinMip()); glTextureParameterf(_id, GL_TEXTURE_MAX_LOD, (sampler.getMaxMip() == Sampler::MAX_MIP_LEVEL ? 1000.f : sampler.getMaxMip())); } @@ -189,7 +190,9 @@ void GL45FixedAllocationTexture::allocateStorage() const { const auto mips = _gpuObject.getNumMips(); glTextureStorage2D(_id, mips, texelFormat.internalFormat, dimensions.x, dimensions.y); + glTextureParameteri(_id, GL_TEXTURE_BASE_LEVEL, 0); + glTextureParameteri(_id, GL_TEXTURE_MAX_LEVEL, mips - 1); } void GL45FixedAllocationTexture::syncSampler() const { diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendVariableTexture.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendVariableTexture.cpp index e1d3912660..a614d62221 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45BackendVariableTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendVariableTexture.cpp @@ -495,7 +495,7 @@ void GL45ResourceTexture::promote() { PROFILE_RANGE(render_gpu_gl, __FUNCTION__); Q_ASSERT(_allocatedMip > 0); GLuint oldId = _id; - uint32_t oldSize = _size; + auto oldSize = _size; // create new texture const_cast(_id) = allocate(_gpuObject); uint16_t oldAllocatedMip = _allocatedMip; diff --git a/libraries/gpu/src/gpu/Texture.cpp b/libraries/gpu/src/gpu/Texture.cpp index 6a4eb547c3..2f40ee20a2 100755 --- a/libraries/gpu/src/gpu/Texture.cpp +++ b/libraries/gpu/src/gpu/Texture.cpp @@ -318,15 +318,20 @@ Texture::Size Texture::resize(Type type, const Element& texelFormat, uint16 widt _depth = depth; changed = true; } - - // Evaluate the new size with the new format - uint32_t size = NUM_FACES_PER_TYPE[_type] *_width * _height * _depth * _numSamples * texelFormat.getSize(); if ((_maxMipLevel + 1) != numMips) { _maxMipLevel = safeNumMips(numMips) - 1; changed = true; } + if (texelFormat != _texelFormat) { + _texelFormat = texelFormat; + changed = true; + } + + // Evaluate the new size with the new format + Size size = NUM_FACES_PER_TYPE[_type] * _height * _depth * evalPaddedSize(_numSamples * _width * _texelFormat.getSize()); + // If size change then we need to reset if (changed || (size != getSize())) { _size = size; @@ -334,12 +339,6 @@ Texture::Size Texture::resize(Type type, const Element& texelFormat, uint16 widt _stamp++; } - // TexelFormat might have change, but it's mostly interpretation - if (texelFormat != _texelFormat) { - _texelFormat = texelFormat; - _stamp++; - } - // Here the Texture has been fully defined from the gpu point of view (size and format) _defined = true; } else { @@ -377,8 +376,6 @@ uint16 Texture::evalMaxNumMips() const { return evalMaxNumMips({ _width, _height, _depth }); } - - // Check a num of mips requested against the maximum possible specified // if passing -1 then answer the max // simply does (askedNumMips == 0 ? maxNumMips : (numstd::min(askedNumMips, maxNumMips)) @@ -395,7 +392,15 @@ uint16 Texture::safeNumMips(uint16 askedNumMips) const { return safeNumMips(askedNumMips, evalMaxNumMips()); } - +Size Texture::evalTotalSize(uint16 startingMip) const { + Size size = 0; + uint16 minMipLevel = std::max(getMinMip(), startingMip); + uint16 maxMipLevel = getMaxMip(); + for (uint16 l = minMipLevel; l <= maxMipLevel; l++) { + size += evalMipSize(l); + } + return size * getNumSlices(); +} void Texture::setStoredMipFormat(const Element& format) { _storage->setFormat(format); @@ -481,48 +486,19 @@ void Texture::setAutoGenerateMips(bool enable) { } } -uint16 Texture::getStoredMipWidth(uint16 level) const { +Size Texture::getStoredMipSize(uint16 level) const { PixelsPointer mipFace = accessStoredMipFace(level); + Size size = 0; if (mipFace && mipFace->getSize()) { - return evalMipWidth(level); + for (int face = 0; face < mipFace->getSize(); ++face) { + size += getStoredMipFaceSize(level, face); + } } - return 0; + return size; } -uint16 Texture::getStoredMipHeight(uint16 level) const { - PixelsPointer mip = accessStoredMipFace(level); - if (mip && mip->getSize()) { - return evalMipHeight(level); - } - return 0; -} - -uint16 Texture::getStoredMipDepth(uint16 level) const { - PixelsPointer mipFace = accessStoredMipFace(level); - if (mipFace && mipFace->getSize()) { - return evalMipDepth(level); - } - return 0; -} - -uint32 Texture::getStoredMipNumTexels(uint16 level) const { - PixelsPointer mipFace = accessStoredMipFace(level); - if (mipFace && mipFace->getSize()) { - return evalMipWidth(level) * evalMipHeight(level) * evalMipDepth(level); - } - return 0; -} - -uint32 Texture::getStoredMipSize(uint16 level) const { - PixelsPointer mipFace = accessStoredMipFace(level); - if (mipFace && mipFace->getSize()) { - return evalMipWidth(level) * evalMipHeight(level) * evalMipDepth(level) * getTexelFormat().getSize(); - } - return 0; -} - -gpu::Resource::Size Texture::getStoredSize() const { - auto size = 0; +Size Texture::getStoredSize() const { + Size size = 0; for (int level = 0; level < getNumMips(); ++level) { size += getStoredMipSize(level); } diff --git a/libraries/gpu/src/gpu/Texture.h b/libraries/gpu/src/gpu/Texture.h index 8a5bde9eb8..312381a7d4 100755 --- a/libraries/gpu/src/gpu/Texture.h +++ b/libraries/gpu/src/gpu/Texture.h @@ -232,9 +232,7 @@ public: bool operator!=(const Usage& usage) { return (_flags != usage._flags); } }; - using PixelsPointer = storage::StoragePointer; - - enum Type { + enum Type : uint8 { TEX_1D = 0, TEX_2D, TEX_3D, @@ -255,7 +253,13 @@ public: NUM_CUBE_FACES, // Not a valid vace index }; + // Lines of pixels are padded to be a multiple of "PACKING_SIZE" which is 4 bytes + static const uint32 PACKING_SIZE = 4; + static uint8 evalPaddingNumBytes(Size byteSize) { return (uint8) (3 - (byteSize + 3) % PACKING_SIZE); } + static Size evalPaddedSize(Size byteSize) { return byteSize + (Size) evalPaddingNumBytes(byteSize); } + + using PixelsPointer = storage::StoragePointer; class Storage { public: Storage() {} @@ -331,6 +335,9 @@ public: static Texture* createStrict(const Element& texelFormat, uint16 width, uint16 height, uint16 numMips = 1, const Sampler& sampler = Sampler()); static Texture* createExternal(const ExternalRecycler& recycler, const Sampler& sampler = Sampler()); + // After the texture has been created, it should be defined + bool isDefined() const { return _defined; } + Texture(TextureUsageType usageType); Texture(const Texture& buf); // deep copy of the sysmem texture Texture& operator=(const Texture& buf); // deep copy of the sysmem texture @@ -343,9 +350,6 @@ public: // For the master (level) first level of mip Size getSize() const override { return _size; } - // The actual size in bytes of data stored in the texture - Size getStoredSize() const; - // Size and format Type getType() const { return _type; } TextureUsageType getUsageType() const { return _usageType; } @@ -354,23 +358,18 @@ public: bool isDepthStencilRenderTarget() const; const Element& getTexelFormat() const { return _texelFormat; } - bool hasBorder() const { return false; } Vec3u getDimensions() const { return Vec3u(_width, _height, _depth); } uint16 getWidth() const { return _width; } uint16 getHeight() const { return _height; } uint16 getDepth() const { return _depth; } - uint32 getRowPitch() const { return getWidth() * getTexelFormat().getSize(); } - // The number of faces is mostly used for cube map, and maybe for stereo ? otherwise it's 1 // For cube maps, this means the pixels of the different faces are supposed to be packed back to back in a mip // as if the height was NUM_FACES time bigger. static uint8 NUM_FACES_PER_TYPE[NUM_TYPES]; uint8 getNumFaces() const { return NUM_FACES_PER_TYPE[getType()]; } - uint32 getNumTexels() const { return _width * _height * _depth * getNumFaces(); } - // 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. @@ -378,8 +377,6 @@ public: uint16 getNumSlices() const { return (isArray() ? _numSlices : 1); } uint16 getNumSamples() const { return _numSamples; } - - // NumSamples can only have certain values based on the hw static uint16 evalNumSamplesUsed(uint16 numSamplesTried); @@ -415,32 +412,30 @@ public: uint16 evalMipHeight(uint16 level) const { return std::max(_height >> level, 1); } uint16 evalMipDepth(uint16 level) const { return std::max(_depth >> level, 1); } + // The size of a face is a multiple of the padded line = (width * texelFormat_size + alignment padding) + Size evalMipLineSize(uint16 level) const { return evalPaddedSize(evalMipWidth(level) * getTexelFormat().getSize()); } + // Size for each face of a mip at a particular level uint32 evalMipFaceNumTexels(uint16 level) const { return evalMipWidth(level) * evalMipHeight(level) * evalMipDepth(level); } - uint32 evalMipFaceSize(uint16 level) const { return evalMipFaceNumTexels(level) * getTexelFormat().getSize(); } + Size evalMipFaceSize(uint16 level) const { return evalMipLineSize(level) * evalMipHeight(level) * evalMipDepth(level); } // Total size for the mip uint32 evalMipNumTexels(uint16 level) const { return evalMipFaceNumTexels(level) * getNumFaces(); } - uint32 evalMipSize(uint16 level) const { return evalMipNumTexels(level) * getTexelFormat().getSize(); } - - uint32 evalStoredMipFaceSize(uint16 level, const Element& format) const { return evalMipFaceNumTexels(level) * format.getSize(); } - uint32 evalStoredMipSize(uint16 level, const Element& format) const { return evalMipNumTexels(level) * format.getSize(); } - - uint32 evalTotalSize(uint16 startingMip = 0) const { - uint32 size = 0; - uint16 minMipLevel = std::max(getMinMip(), startingMip); - uint16 maxMipLevel = getMaxMip(); - for (uint16 l = minMipLevel; l <= maxMipLevel; l++) { - size += evalMipSize(l); - } - return size * getNumSlices(); - } - + Size evalMipSize(uint16 level) const { return evalMipFaceSize(level) * getNumFaces(); } + // Total size for all the mips of the texture + Size evalTotalSize(uint16 startingMip = 0) const; + // Compute the theorical size of the texture elements storage depending on the specified format + Size evalStoredMipLineSize(uint16 level, const Element& format) const { return evalPaddedSize(evalMipWidth(level) * format.getSize()); } + Size evalStoredMipFaceSize(uint16 level, const Element& format) const { return evalMipFaceNumTexels(level) * format.getSize(); } + Size evalStoredMipSize(uint16 level, const Element& format) const { return evalMipNumTexels(level) * format.getSize(); } + // For convenience assign a source name const std::string& source() const { return _source; } void setSource(const std::string& source) { _source = source; } + + // Potentially change the minimum mip (mostly for debugging purpose) bool setMinMip(uint16 newMinMip); bool incremementMinMip(uint16 count = 1); uint16 getMinMip() const { return _minMip; } @@ -463,30 +458,22 @@ public: // in case autoGen is on, this doesn't allocate // Explicitely assign mip data for a certain level // If Bytes is NULL then simply allocate the space so mip sysmem can be accessed - void assignStoredMip(uint16 level, Size size, const Byte* bytes); void assignStoredMipFace(uint16 level, uint8 face, Size size, const Byte* bytes); void assignStoredMip(uint16 level, storage::StoragePointer& storage); void assignStoredMipFace(uint16 level, uint8 face, storage::StoragePointer& storage); - // Access the the sub mips - bool isStoredMipFaceAvailable(uint16 level, uint8 face = 0) const { return _storage->isMipAvailable(level, face); } + // Access the stored mips and faces const PixelsPointer accessStoredMipFace(uint16 level, uint8 face = 0) const { return _storage->getMipFace(level, face); } + bool isStoredMipFaceAvailable(uint16 level, uint8 face = 0) const { return _storage->isMipAvailable(level, face); } Size getStoredMipFaceSize(uint16 level, uint8 face = 0) const { return _storage->getMipFaceSize(level, face); } + Size getStoredMipSize(uint16 level) const; + Size getStoredSize() const; void setStorage(std::unique_ptr& newStorage); void setKtxBacking(const std::string& filename); - // access sizes for the stored mips - uint16 getStoredMipWidth(uint16 level) const; - uint16 getStoredMipHeight(uint16 level) const; - uint16 getStoredMipDepth(uint16 level) const; - uint32 getStoredMipNumTexels(uint16 level) const; - uint32 getStoredMipSize(uint16 level) const; - - bool isDefined() const { return _defined; } - // Usage is a a set of flags providing Semantic about the usage of the Texture. void setUsage(const Usage& usage) { _usage = usage; } Usage getUsage() const { return _usage; } @@ -512,7 +499,7 @@ public: ExternalUpdates getUpdates() const; - // Textures can be serialized directly to ktx data file, here is how + // Textures can be serialized directly to ktx data file, here is how static ktx::KTXUniquePointer serialize(const Texture& texture); static Texture* unserialize(const std::string& ktxFile, TextureUsageType usageType = TextureUsageType::RESOURCE, Usage usage = Usage(), const Sampler::Desc& sampler = Sampler::Desc()); static bool evalKTXFormat(const Element& mipFormat, const Element& texelFormat, ktx::Header& header); @@ -537,7 +524,7 @@ protected: Sampler _sampler; Stamp _samplerStamp { 0 }; - uint32 _size { 0 }; + Size _size { 0 }; Element _texelFormat; uint16 _width { 1 };