From 7c15609136372e27696a0f3c64f87c9f542b13d3 Mon Sep 17 00:00:00 2001 From: samcake Date: Thu, 27 Apr 2017 17:28:10 -0700 Subject: [PATCH] Fixing the broken texture copy (during texture streaming) for compressed format in GL41Backend --- libraries/gpu-gl/src/gpu/gl/GLBackend.cpp | 2 +- libraries/gpu-gl/src/gpu/gl/GLTexture.cpp | 3 +- libraries/gpu-gl/src/gpu/gl/GLTexture.h | 1 + libraries/gpu-gl/src/gpu/gl41/GL41Backend.h | 1 - .../src/gpu/gl41/GL41BackendTexture.cpp | 192 ++++++++++++++---- libraries/gpu/src/gpu/Texture.cpp | 8 +- libraries/gpu/src/gpu/Texture.h | 4 +- 7 files changed, 160 insertions(+), 51 deletions(-) diff --git a/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp b/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp index c5c9b90eb2..1210112a78 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp @@ -48,7 +48,7 @@ BackendPointer GLBackend::createBackend() { // Where the gpuContext is initialized and where the TRUE Backend is created and assigned auto version = QOpenGLContextWrapper::currentContextVersion(); std::shared_ptr result; - if (false && !disableOpenGL45 && version >= 0x0405) { + if (!disableOpenGL45 && version >= 0x0405) { qCDebug(gpugllogging) << "Using OpenGL 4.5 backend"; result = std::make_shared(); } else { diff --git a/libraries/gpu-gl/src/gpu/gl/GLTexture.cpp b/libraries/gpu-gl/src/gpu/gl/GLTexture.cpp index 7f075a1698..95815993c2 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLTexture.cpp @@ -102,7 +102,8 @@ const std::vector& GLTexture::getFaceTargets(GLenum target) { GLTexture::GLTexture(const std::weak_ptr& backend, const Texture& texture, GLuint id) : GLObject(backend, texture, id), _source(texture.source()), - _target(getGLTextureType(texture)) + _target(getGLTextureType(texture)), + _texelFormat(GLTexelFormat::evalGLTexelFormat(texture.getTexelFormat(), texture.getStoredMipFormat())) { Backend::setGPUObject(texture, this); } diff --git a/libraries/gpu-gl/src/gpu/gl/GLTexture.h b/libraries/gpu-gl/src/gpu/gl/GLTexture.h index e0b8a63a99..99df5d94cf 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLTexture.h +++ b/libraries/gpu-gl/src/gpu/gl/GLTexture.h @@ -153,6 +153,7 @@ public: const GLuint& _texture { _id }; const std::string _source; const GLenum _target; + GLTexelFormat _texelFormat; static const std::vector& getFaceTargets(GLenum textureType); static uint8_t getFaceCount(GLenum textureType); diff --git a/libraries/gpu-gl/src/gpu/gl41/GL41Backend.h b/libraries/gpu-gl/src/gpu/gl41/GL41Backend.h index ef409d37f4..3662253a66 100644 --- a/libraries/gpu-gl/src/gpu/gl41/GL41Backend.h +++ b/libraries/gpu-gl/src/gpu/gl41/GL41Backend.h @@ -110,7 +110,6 @@ public: Size size() const override { return _size; } Size _size { 0 }; - GLTexelFormat _texelFormat; }; class GL41ResourceTexture : public GL41VariableAllocationTexture { diff --git a/libraries/gpu-gl/src/gpu/gl41/GL41BackendTexture.cpp b/libraries/gpu-gl/src/gpu/gl41/GL41BackendTexture.cpp index d9fa2ad067..f199d210b3 100644 --- a/libraries/gpu-gl/src/gpu/gl41/GL41BackendTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl41/GL41BackendTexture.cpp @@ -241,8 +241,7 @@ GL41StrictResourceTexture::GL41StrictResourceTexture(const std::weak_ptr& backend, const Texture& texture) : - GL41Texture(backend, texture), - _texelFormat(GLTexelFormat::evalGLTexelFormat(texture.getTexelFormat(), texture.getStoredMipFormat())) + GL41Texture(backend, texture) { auto mipLevels = texture.getNumMips(); _allocatedMip = mipLevels; @@ -325,25 +324,87 @@ void GL41VariableAllocationTexture::promote() { // allocate storage for new level allocateStorage(targetAllocatedMip); - withPreservedTexture([&] { - if (false && _texelFormat.isCompressed()) { - uint16_t mips = _gpuObject.getNumMips(); - // copy pre-existing mips - for (uint16_t mip = _populatedMip; mip < mips; ++mip) { - auto mipDimensions = _gpuObject.evalMipDimensions(mip); - uint16_t targetMip = mip - _allocatedMip; - uint16_t sourceMip = mip - oldAllocatedMip; - auto faces = getFaceCount(_target); - for (uint8_t face = 0; face < faces; ++face) { - glCopyImageSubData( - oldId, _target, sourceMip, 0, 0, face, - _id, _target, targetMip, 0, 0, face, - mipDimensions.x, mipDimensions.y, 1 - ); - (void)CHECK_GL_ERROR(); + if (_texelFormat.isCompressed()) { + GLuint pbo { 0 }; + glGenBuffers(1, &pbo); + glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo); + uint16_t numMips = _gpuObject.getNumMips(); + struct MipDesc { + GLint _faceSize; + GLint _size; + GLint _offset; + gpu::Vec3u _dims; + }; + std::vector sourceMips(numMips); + + glActiveTexture(GL_TEXTURE0 + GL41Backend::RESOURCE_TRANSFER_EXTRA_TEX_UNIT); + glBindTexture(_target, oldId); + const auto& faceTargets = getFaceTargets(_target); + GLint internalFormat { 0 }; + (void)CHECK_GL_ERROR(); + + // Collect the mip description from the source texture + GLint bufferOffset { 0 }; + for (uint16_t mip = _populatedMip; mip < numMips; ++mip) { + auto& sourceMip = sourceMips[mip]; + sourceMip._dims = _gpuObject.evalMipDimensions(mip); + + uint16_t sourceLevel = mip - oldAllocatedMip; + + // Grab internal format once + if (internalFormat == 0) { + glGetTexLevelParameteriv(faceTargets[0], sourceLevel, GL_TEXTURE_INTERNAL_FORMAT, &internalFormat); + } + + // Collect the size of the first face, and then compute the total size offset needed for this mip level + glGetTexLevelParameteriv(faceTargets.front(), sourceLevel, GL_TEXTURE_COMPRESSED_IMAGE_SIZE, &sourceMip._faceSize); + sourceMip._size = faceTargets.size() * sourceMip._faceSize; + sourceMip._offset = bufferOffset; + bufferOffset += sourceMip._size; + } + (void)CHECK_GL_ERROR(); + + // Allocate the PBO to accomodate for all the mips to copy + glBufferData(GL_PIXEL_PACK_BUFFER, bufferOffset, nullptr, GL_STREAM_COPY); + (void)CHECK_GL_ERROR(); + + // Transfer from source texture to pbo + for (uint16_t mip = _populatedMip; mip < numMips; ++mip) { + auto& sourceMip = sourceMips[mip]; + + uint16_t sourceLevel = mip - oldAllocatedMip; + + for (GLint f = 0; f < faceTargets.size(); f++) { + glGetCompressedTexImage(faceTargets[f], sourceLevel, (void*)(sourceMip._offset + f * sourceMip._faceSize)); + } + (void)CHECK_GL_ERROR(); + + } + + // Now populate the new texture from the pbo + glBindTexture(_target, 0); + glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo); + + withPreservedTexture([&] { + // Transfer from pbo to new texture + for (uint16_t mip = _populatedMip; mip < numMips; ++mip) { + auto& sourceMip = sourceMips[mip]; + + uint16_t destLevel = mip - _allocatedMip; + + for (GLint f = 0; f < faceTargets.size(); f++) { + glCompressedTexSubImage2D(faceTargets[f], destLevel, 0, 0, sourceMip._dims.x, sourceMip._dims.y, internalFormat, + sourceMip._faceSize, (void*)(sourceMip._offset + f * sourceMip._faceSize)); } } - } else { + syncSampler(); + }); + + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); + glDeleteBuffers(1, &pbo); + } else { + withPreservedTexture([&] { GLuint fbo { 0 }; glGenFramebuffers(1, &fbo); glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo); @@ -365,9 +426,10 @@ void GL41VariableAllocationTexture::promote() { // destroy the transfer framebuffer glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); glDeleteFramebuffers(1, &fbo); - } - syncSampler(); - }); + + syncSampler(); + }); + } // destroy the old texture glDeleteTextures(1, &oldId); @@ -383,44 +445,86 @@ void GL41VariableAllocationTexture::demote() { auto oldSize = _size; const_cast(_id) = allocate(_gpuObject); uint16_t oldAllocatedMip = _allocatedMip; + uint16_t oldPopulatedMip = _populatedMip; allocateStorage(_allocatedMip + 1); _populatedMip = std::max(_populatedMip, _allocatedMip); if (_texelFormat.isCompressed()) { GLuint pbo { 0 }; glGenBuffers(1, &pbo); - glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo); glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo); + uint16_t numMips = _gpuObject.getNumMips(); + struct MipDesc { + GLint _faceSize; + GLint _size; + GLint _offset; + gpu::Vec3u _dims; + }; + std::vector sourceMips(numMips); glActiveTexture(GL_TEXTURE0 + GL41Backend::RESOURCE_TRANSFER_EXTRA_TEX_UNIT); glBindTexture(_target, oldId); + const auto& faceTargets = getFaceTargets(_target); + GLint internalFormat { 0 }; - glGetTexLevelParameteriv(_target, sourceMip, GL_TEXTURE_COMPRESSED_IMAGE_SIZE, &size); + // Collect the mip description from the source texture + GLint bufferOffset { 0 }; + for (uint16_t mip = oldPopulatedMip; mip < numMips; ++mip) { + auto& sourceMip = sourceMips[mip]; + sourceMip._dims = _gpuObject.evalMipDimensions(mip); - // copy pre-existing mips - uint16_t mips = _gpuObject.getNumMips(); - for (uint16_t mip = _populatedMip; mip < mips; ++mip) { - auto mipDimensions = _gpuObject.evalMipDimensions(mip); - uint16_t targetMip = mip - _allocatedMip; - uint16_t sourceMip = targetMip + 1; - GLint size { 0 }; - GLint internalFormat; - glGetTexLevelParameteriv(_target, sourceMip, GL_TEXTURE_COMPRESSED_IMAGE_SIZE, &size); + uint16_t sourceLevel = mip - oldAllocatedMip; - auto faces = getFaceCount(_target); - for (uint8_t face = 0; face < faces; ++face) { - glCopyImageSubData( - oldId, _target, sourceMip, 0, 0, face, - _id, _target, targetMip, 0, 0, face, - mipDimensions.x, mipDimensions.y, 1 - ); - (void)CHECK_GL_ERROR(); + // Grab internal format once + if (internalFormat != 0) { + glGetTexLevelParameteriv(faceTargets[0], sourceLevel, GL_TEXTURE_INTERNAL_FORMAT, &internalFormat); } + + // Collect the size of the first face, and then compute the total size offset needed for this mip level + glGetTexLevelParameteriv(faceTargets.front(), sourceLevel, GL_TEXTURE_COMPRESSED_IMAGE_SIZE, &sourceMip._faceSize); + sourceMip._size = faceTargets.size() * sourceMip._faceSize; + sourceMip._offset = bufferOffset; + bufferOffset += sourceMip._size; + } + (void)CHECK_GL_ERROR(); + + // Allocate the PBO to accomodate for all the mips to copy + glBufferData(GL_PIXEL_PACK_BUFFER, bufferOffset, nullptr, GL_STREAM_COPY); + (void)CHECK_GL_ERROR(); + + // Transfer from source texture to pbo + for (uint16_t mip = oldPopulatedMip; mip < numMips; ++mip) { + auto& sourceMip = sourceMips[mip]; + + uint16_t sourceLevel = mip - oldAllocatedMip; + + for (GLint f = 0; f < faceTargets.size(); f++) { + glGetCompressedTexImage(faceTargets[f], sourceLevel, (void*) (sourceMip._offset + f * sourceMip._faceSize)); + } + (void)CHECK_GL_ERROR(); } + // Now populate the new texture from the pbo + glBindTexture(_target, 0); + glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo); + + withPreservedTexture([&] { + // Transfer from pbo to new texture + for (uint16_t mip = _populatedMip; mip < numMips; ++mip) { + auto& sourceMip = sourceMips[mip]; + + uint16_t destLevel = mip - _allocatedMip; + + for (GLint f = 0; f < faceTargets.size(); f++) { + glCompressedTexSubImage2D(faceTargets[f], destLevel, 0, 0, sourceMip._dims.x, sourceMip._dims.y, internalFormat, + sourceMip._faceSize, (void*)(sourceMip._offset + f * sourceMip._faceSize)); + } + } + syncSampler(); + }); glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); - glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); glDeleteBuffers(1, &pbo); } else { @@ -429,9 +533,9 @@ void GL41VariableAllocationTexture::demote() { glGenFramebuffers(1, &fbo); glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo); - uint16_t mips = _gpuObject.getNumMips(); + uint16_t numMips = _gpuObject.getNumMips(); // copy pre-existing mips - for (uint16_t mip = _populatedMip; mip < mips; ++mip) { + for (uint16_t mip = _populatedMip; mip < numMips; ++mip) { auto mipDimensions = _gpuObject.evalMipDimensions(mip); uint16_t targetMip = mip - _allocatedMip; uint16_t sourceMip = targetMip + 1; diff --git a/libraries/gpu/src/gpu/Texture.cpp b/libraries/gpu/src/gpu/Texture.cpp index 3e6ed166a7..353bcbc8f1 100755 --- a/libraries/gpu/src/gpu/Texture.cpp +++ b/libraries/gpu/src/gpu/Texture.cpp @@ -407,8 +407,12 @@ void Texture::setStoredMipFormat(const Element& format) { _storage->setFormat(format); } -const Element& Texture::getStoredMipFormat() const { - return _storage->getFormat(); +const Element Texture::getStoredMipFormat() const { + if (_storage) { + return _storage->getFormat(); + } else { + return Element(); + } } void Texture::assignStoredMip(uint16 level, Size size, const Byte* bytes) { diff --git a/libraries/gpu/src/gpu/Texture.h b/libraries/gpu/src/gpu/Texture.h index 9b23b4e695..21a1b0ec57 100755 --- a/libraries/gpu/src/gpu/Texture.h +++ b/libraries/gpu/src/gpu/Texture.h @@ -372,7 +372,7 @@ public: bool isColorRenderTarget() const; bool isDepthStencilRenderTarget() const; - const Element& getTexelFormat() const { return _texelFormat; } + const Element getTexelFormat() const { return _texelFormat; } Vec3u getDimensions() const { return Vec3u(_width, _height, _depth); } uint16 getWidth() const { return _width; } @@ -468,7 +468,7 @@ public: // Mip storage format is constant across all mips void setStoredMipFormat(const Element& format); - const Element& getStoredMipFormat() const; + const Element getStoredMipFormat() const; // Manually allocate the mips down until the specified maxMip // this is just allocating the sysmem version of it