mirror of
https://github.com/overte-org/overte.git
synced 2025-04-08 08:14:48 +02:00
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:
parent
47e9668b8f
commit
61d78bc931
8 changed files with 177 additions and 330 deletions
|
@ -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; }
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 };
|
||||
|
|
Loading…
Reference in a new issue