From 47e9668b8fb1f833b7081ec368f6cb727fd7c29a Mon Sep 17 00:00:00 2001 From: samcake Date: Thu, 30 Mar 2017 17:59:59 -0700 Subject: [PATCH] improving the gl41 backend to mimic the gl45 --- libraries/gpu-gl/src/gpu/gl41/GL41Backend.h | 50 +++- .../src/gpu/gl41/GL41BackendTexture.cpp | 220 +++++++++++++++--- 2 files changed, 233 insertions(+), 37 deletions(-) diff --git a/libraries/gpu-gl/src/gpu/gl41/GL41Backend.h b/libraries/gpu-gl/src/gpu/gl41/GL41Backend.h index 6d2f91c436..ab66a0a302 100644 --- a/libraries/gpu-gl/src/gpu/gl41/GL41Backend.h +++ b/libraries/gpu-gl/src/gpu/gl41/GL41Backend.h @@ -39,6 +39,54 @@ public: GL41Backend() : Parent() {} class GL41Texture : public GLTexture { + using Parent = GLTexture; + friend class GL41Backend; + static GLuint allocate(const Texture& texture); + protected: + GL41Texture(const std::weak_ptr& backend, const Texture& texture); + void generateMips() const override; + void copyMipFaceFromTexture(uint16_t sourceMip, uint16_t targetMip, uint8_t face) const; + void copyMipFaceLinesFromTexture(uint16_t mip, uint8_t face, const uvec3& size, uint32_t yOffset, GLenum format, GLenum type, const void* sourcePointer) const; + virtual void syncSampler() const; + + void withPreservedTexture(std::function f) const; + }; + + // + // Textures that have fixed allocation sizes and cannot be managed at runtime + // + + class GL41FixedAllocationTexture : public GL41Texture { + using Parent = GL41Texture; + friend class GL41Backend; + + public: + GL41FixedAllocationTexture(const std::weak_ptr& backend, const Texture& texture); + ~GL41FixedAllocationTexture(); + + protected: + uint32 size() const override { return _size; } + void allocateStorage() const; + void syncSampler() const override; + const uint32 _size { 0 }; + }; + + class GL41AttachmentTexture : public GL41FixedAllocationTexture { + using Parent = GL41FixedAllocationTexture; + friend class GL45Backend; + protected: + GL41AttachmentTexture(const std::weak_ptr& backend, const Texture& texture); + ~GL41AttachmentTexture(); + }; + + class GL41StrictResourceTexture : public GL41FixedAllocationTexture { + using Parent = GL41FixedAllocationTexture; + friend class GL41Backend; + protected: + GL41StrictResourceTexture(const std::weak_ptr& backend, const Texture& texture); + }; + + /* class GL41Texture : public GLTexture { using Parent = GLTexture; static GLuint allocate(); @@ -62,7 +110,7 @@ public: void withPreservedTexture(std::function f) const; void syncContent() const; void syncSampler() const; - }; + };*/ protected: diff --git a/libraries/gpu-gl/src/gpu/gl41/GL41BackendTexture.cpp b/libraries/gpu-gl/src/gpu/gl41/GL41BackendTexture.cpp index 61db54bf7b..092591a538 100644 --- a/libraries/gpu-gl/src/gpu/gl41/GL41BackendTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl41/GL41BackendTexture.cpp @@ -19,16 +19,197 @@ using namespace gpu; using namespace gpu::gl; using namespace gpu::gl41; -using GL41TexelFormat = GLTexelFormat; +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; + } + + GL41Texture* object = Backend::getGPUObject(texture); + if (!object) { + switch (texture.getUsageType()) { + case TextureUsageType::RENDERBUFFER: + object = new GL41AttachmentTexture(shared_from_this(), texture); + break; + + case TextureUsageType::STRICT_RESOURCE: + qCDebug(gpugllogging) << "Strict texture " << texture.source().c_str(); + object = new GL41StrictResourceTexture(shared_from_this(), texture); + break; + + case TextureUsageType::RESOURCE: { + qCDebug(gpugllogging) << "variable / Strict texture " << texture.source().c_str(); + object = new GL41StrictResourceTexture(shared_from_this(), texture); + break; + } + + default: + Q_UNREACHABLE(); + } + } + + return object; +} + using GL41Texture = GL41Backend::GL41Texture; -GLuint GL41Texture::allocate() { - Backend::incrementTextureGPUCount(); +GL41Texture::GL41Texture(const std::weak_ptr& backend, const Texture& texture) + : GLTexture(backend, texture, allocate(texture)) { + incrementTextureGPUCount(); +} + +GLuint GL41Texture::allocate(const Texture& texture) { GLuint result; glGenTextures(1, &result); return result; } + +void GL41Texture::withPreservedTexture(std::function f) const { + const GLint TRANSFER_TEXTURE_UNIT = 32; + glActiveTexture(GL_TEXTURE0 + TRANSFER_TEXTURE_UNIT); + glBindTexture(_target, _texture); + (void)CHECK_GL_ERROR(); + + f(); + glBindTexture(_target, 0); + (void)CHECK_GL_ERROR(); +} + + +void GL41Texture::generateMips() const { + withPreservedTexture([&] { + glGenerateMipmap(_target); + }); + (void)CHECK_GL_ERROR(); +} + +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); + } 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); + } + } else { + Q_ASSERT(false); + } + (void)CHECK_GL_ERROR(); +} + +void GL41Texture::copyMipFaceFromTexture(uint16_t sourceMip, uint16_t targetMip, uint8_t face) const { + if (!_gpuObject.isStoredMipFaceAvailable(sourceMip)) { + return; + } + auto size = _gpuObject.evalMipDimensions(sourceMip); + auto mipData = _gpuObject.accessStoredMipFace(sourceMip, face); + if (mipData) { + GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(_gpuObject.getTexelFormat(), _gpuObject.getStoredMipFormat()); + copyMipFaceLinesFromTexture(targetMip, face, size, 0, texelFormat.format, texelFormat.type, mipData->readData()); + } else { + qCDebug(gpugllogging) << "Missing mipData level=" << sourceMip << " face=" << (int)face << " for texture " << _gpuObject.source().c_str(); + } +} + +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; @@ -128,39 +309,6 @@ bool GL41Texture::isOutdated() const { return false; } -void GL41Texture::withPreservedTexture(std::function f) const { - GLint transferUnit = 32; - GLint boundTex = -1; - switch (_target) { - case GL_TEXTURE_2D: - glGetIntegerv(GL_TEXTURE_BINDING_2D, &boundTex); - break; - - case GL_TEXTURE_CUBE_MAP: - glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP, &boundTex); - break; - - default: - qFatal("Unsupported texture type"); - } - (void)CHECK_GL_ERROR(); - - glActiveTexture(GL_TEXTURE0 + transferUnit); - (void)CHECK_GL_ERROR(); - - glBindTexture(_target, _texture); - f(); - glBindTexture(_target, 0); - (void)CHECK_GL_ERROR(); -} - -void GL41Texture::generateMips() const { - withPreservedTexture([&] { - glGenerateMipmap(_target); - }); - (void)CHECK_GL_ERROR(); -} - void GL41Texture::syncContent() const { // FIXME actually copy the texture data _contentStamp = _gpuObject.getDataStamp() + 1;