BRinging the cool texture management of the gl45 backend to gl41, which fixes the broken ao on 41 among other things

This commit is contained in:
Sam Cake 2017-03-30 23:29:37 -07:00
parent 47e9668b8f
commit 61d78bc931
8 changed files with 177 additions and 330 deletions

View file

@ -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<gl::GLBackend>& backend, const Texture& texture, GLuint id);
@ -57,7 +57,7 @@ public:
protected:
GLExternalTexture(const std::weak_ptr<gl::GLBackend>& backend, const Texture& texture, GLuint id);
void generateMips() const override {}
uint32 size() const override { return 0; }
Size size() const override { return 0; }
};

View file

@ -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<GLBackend>& backend, const Texture& texture);
~GL41AttachmentTexture();
@ -86,32 +86,13 @@ public:
GL41StrictResourceTexture(const std::weak_ptr<GLBackend>& backend, const Texture& texture);
};
/* class GL41Texture : public GLTexture {
using Parent = GLTexture;
static GLuint allocate();
public:
~GL41Texture();
private:
GL41Texture(const std::weak_ptr<GLBackend>& 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<void()> f) const;
void syncContent() const;
void syncSampler() const;
};*/
protected:
GL41ResourceTexture(const std::weak_ptr<GLBackend>& backend, const Texture& texture);
~GL41ResourceTexture();
};
protected:
GLuint getFramebufferID(const FramebufferPointer& framebuffer) override;

View file

@ -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<GLBackend>& 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<uint16_t>(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<GLBackend>& 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<GLBackend>& 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<GL41Texture>(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<GLBackend>& 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<GLBackend>& 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<uint16_t>(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<GLBackend>& 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<GLBackend>& 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<GLBackend>& 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);
}

View file

@ -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

View file

@ -18,7 +18,6 @@
#include <glm/gtx/component_wise.hpp>
#include <QtCore/QDebug>
#include <QtCore/QThread>
#include <NumericalConstants.h>
#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 {

View file

@ -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<GLuint&>(_id) = allocate(_gpuObject);
uint16_t oldAllocatedMip = _allocatedMip;

View file

@ -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);
}

View file

@ -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<Storage>& 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 };