From 2f4be630c28bbcabb1201c77029915c47f9d0019 Mon Sep 17 00:00:00 2001 From: mwilsnd Date: Fri, 2 Jun 2023 15:35:32 -0500 Subject: [PATCH] Drawable Renderer (#1570), Texture2D storage allocation fixes, async image transfer --- include/mbgl/gfx/texture2d.hpp | 12 ++++++ include/mbgl/gl/texture2d.hpp | 14 ++++++- src/mbgl/gl/texture2d.cpp | 71 ++++++++++++++++++++++++---------- 3 files changed, 74 insertions(+), 23 deletions(-) diff --git a/include/mbgl/gfx/texture2d.hpp b/include/mbgl/gfx/texture2d.hpp index bd2345fcf..6e5c3d2e4 100644 --- a/include/mbgl/gfx/texture2d.hpp +++ b/include/mbgl/gfx/texture2d.hpp @@ -50,6 +50,10 @@ public: /// @return this virtual Texture2D& setSize(Size size_) noexcept = 0; + /// @brief Sets the internal image + /// @param image_ Image data to transfer + virtual Texture2D& setImage(std::shared_ptr image_) noexcept = 0; + /// @brief Get the size of the texture /// @return Size of the texture virtual Size getSize() const noexcept = 0; @@ -68,6 +72,7 @@ public: virtual size_t numChannels() const noexcept = 0; /// @brief Create the texture with default initialized memory. + /// @note Be sure to configure a valid size and format. virtual void create() noexcept = 0; /// @brief Upload image data to the texture resource @@ -93,10 +98,17 @@ public: uploadSubRegion(&img.data[0], img.size, xOffset, yOffset); } + /// @brief Upload staged image data if present and required. + /// @see needsUpload + virtual void upload() noexcept = 0; + /// @brief Get the underlying GL texture resource /// @note: Compat with legacy textures, to be refactored /// @return gfx::TextureResource virtual gfx::TextureResource& getResource() = 0; + + /// @brief Check whether the texture needs upload + virtual bool needsUpload() const noexcept = 0; }; } // namespace gfx diff --git a/include/mbgl/gl/texture2d.hpp b/include/mbgl/gl/texture2d.hpp index 306d16e48..eb94e3f1f 100644 --- a/include/mbgl/gl/texture2d.hpp +++ b/include/mbgl/gl/texture2d.hpp @@ -24,6 +24,8 @@ public: // gfx::Texture2D Texture2D& setSize(Size size_) noexcept override; + Texture2D& setImage(std::shared_ptr image_) noexcept override; + Size getSize() const noexcept override { return size; } size_t getDataSize() const noexcept override; @@ -36,12 +38,15 @@ public: // gfx::Texture2D void upload(const void* pixelData, const Size& size_) noexcept override; void uploadSubRegion(const void* pixelData, const Size& size, uint16_t xOffset, uint16_t yOffset) noexcept override; + void upload() noexcept override; gfx::TextureResource& getResource() override { assert(textureResource); return *textureResource; } + bool needsUpload() const noexcept override { return !!image; }; + public: /// @brief Get the OpenGL handle ID for the underlying resource /// @return GLuint @@ -58,14 +63,19 @@ public: /// @brief Unbind the texture, if it was bound void unbind() noexcept; +private: + void createObject() noexcept; + void createStorage(const void* data = nullptr) noexcept; + private: gl::Context& context; std::unique_ptr textureResource{nullptr}; SamplerState samplerState{}; - gfx::TexturePixelType pixelFormat; - gfx::TextureChannelDataType channelType; + gfx::TexturePixelType pixelFormat{gfx::TexturePixelType::RGBA}; + gfx::TextureChannelDataType channelType{gfx::TextureChannelDataType::UnsignedByte}; + std::shared_ptr image{nullptr}; Size size{0, 0}; bool samplerStateDirty{false}; diff --git a/src/mbgl/gl/texture2d.cpp b/src/mbgl/gl/texture2d.cpp index d786e57a6..d0b341420 100644 --- a/src/mbgl/gl/texture2d.cpp +++ b/src/mbgl/gl/texture2d.cpp @@ -38,6 +38,11 @@ Texture2D& Texture2D::setSize(mbgl::Size size_) noexcept { return *this; } +Texture2D& Texture2D::setImage(std::shared_ptr image_) noexcept { + image = std::move(image_); + return *this; +} + size_t Texture2D::getDataSize() const noexcept { return size.width * size.height * getPixelStride(); } @@ -64,9 +69,9 @@ size_t Texture2D::numChannels() const noexcept { } } -void Texture2D::create() noexcept { +void Texture2D::createObject() noexcept { + // Create a new texture object assert(!textureResource); - auto obj = context.createUniqueTexture(); const auto storageSize = gl::TextureResource::getStorageSize(size, pixelFormat, channelType); context.renderingStats().memTextures += storageSize; @@ -75,6 +80,32 @@ void Texture2D::create() noexcept { textureResource = std::make_unique(std::move(obj), storageSize); } +void Texture2D::createStorage(const void* data) noexcept { + assert(textureResource); + + // Create backing storage for our texture object + using namespace platform; + + // Bind to TU 0 and upload + context.activeTextureUnit = 0; + context.texture[0] = getTextureID(); + updateSamplerConfiguration(); + MBGL_CHECK_ERROR(glTexImage2D(GL_TEXTURE_2D, + 0, + Enum::to(pixelFormat), + size.width, + size.height, + 0, + Enum::to(pixelFormat), + Enum::to(channelType), + data)); +} + +void Texture2D::create() noexcept { + createObject(); + createStorage(); +} + platform::GLuint Texture2D::getTextureID() const noexcept { return static_cast(*textureResource).texture; } @@ -139,28 +170,18 @@ void Texture2D::unbind() noexcept { void Texture2D::upload(const void* pixelData, const Size& size_) noexcept { using namespace platform; - if (!textureResource) { - create(); - } - assert(textureResource); - // Bind to TU 0 and upload - context.activeTextureUnit = 0; - context.texture[0] = getTextureID(); - updateSamplerConfiguration(); + if (!textureResource || size_ == Size{0, 0} || size_ != size) { + // Create the texture object if we don't already have one + if (!textureResource) { + createObject(); + } - if (size_ == Size{0, 0} || size_ != size) { size = size_; - MBGL_CHECK_ERROR(glTexImage2D(GL_TEXTURE_2D, - 0, - Enum::to(pixelFormat), - size.width, - size.height, - 0, - Enum::to(pixelFormat), - Enum::to(channelType), - pixelData)); + createStorage(pixelData); + } else { + // Upload to existing memory uploadSubRegion(pixelData, size, 0, 0); } } @@ -174,7 +195,6 @@ void Texture2D::uploadSubRegion(const void* pixelData, const Size& size_, uint16 // Bind to TU 0 and upload context.activeTextureUnit = 0; context.texture[0] = getTextureID(); - MBGL_CHECK_ERROR(glTexSubImage2D(GL_TEXTURE_2D, 0, xOffset, @@ -186,5 +206,14 @@ void Texture2D::uploadSubRegion(const void* pixelData, const Size& size_, uint16 pixelData)); } +void Texture2D::upload() noexcept { + if (image && image->valid()) { + setFormat(gfx::TexturePixelType::RGBA, + gfx::TextureChannelDataType::UnsignedByte); + upload(&(*image).data[0], image->size); + image.reset(); + } +} + } // namespace gl } // namespace mbgl