From 18be6f0d2f3a845881aab6366148868b47881176 Mon Sep 17 00:00:00 2001 From: David Steele Date: Fri, 30 Apr 2021 14:02:02 +0100 Subject: [PATCH] Adding texture conversion on upload Change-Id: I92173724636d535bbe550c45e5d1affb8b47b507 --- .../graphics/gles-impl/egl-graphics-controller.cpp | 28 +++++++-- .../graphics/gles-impl/gles-graphics-texture.cpp | 71 +++++++++++++++++++++- .../graphics/gles-impl/gles-graphics-texture.h | 20 +++++- 3 files changed, 111 insertions(+), 8 deletions(-) diff --git a/dali/internal/graphics/gles-impl/egl-graphics-controller.cpp b/dali/internal/graphics/gles-impl/egl-graphics-controller.cpp index 7ef6162..5546800 100644 --- a/dali/internal/graphics/gles-impl/egl-graphics-controller.cpp +++ b/dali/internal/graphics/gles-impl/egl-graphics-controller.cpp @@ -560,22 +560,42 @@ void EglGraphicsController::ProcessTextureUpdateQueue() if(source.sourceType == Graphics::TextureUpdateSourceInfo::Type::MEMORY) { - // GPU memory must be already allocated (glTexImage2D()) + // GPU memory must be already allocated. + + // Check if it needs conversion auto* texture = static_cast(info.dstTexture); const auto& createInfo = texture->GetCreateInfo(); + auto srcFormat = GLES::GLTextureFormatType(info.srcFormat).format; + auto destFormat = GLES::GLTextureFormatType(createInfo.format).format; + auto destType = GLES::GLTextureFormatType(createInfo.format).type; + + // From render-texture.cpp + const bool isSubImage(info.dstOffset2D.x != 0 || info.dstOffset2D.y != 0 || + info.srcExtent2D.width != (createInfo.size.width / (1 << info.level)) || + info.srcExtent2D.height != (createInfo.size.height / (1 << info.level))); + + auto* sourceBuffer = reinterpret_cast(source.memorySource.memory); + std::vector tempBuffer; + if(mGlAbstraction->TextureRequiresConverting(srcFormat, destFormat, isSubImage)) + { + // Convert RGB to RGBA if necessary. + texture->TryConvertPixelData(source.memorySource.memory, info.srcFormat, createInfo.format, info.srcSize, info.srcExtent2D.width, info.srcExtent2D.height, tempBuffer); + sourceBuffer = &tempBuffer[0]; + } mGlAbstraction->PixelStorei(GL_UNPACK_ALIGNMENT, 1); mGlAbstraction->BindTexture(GL_TEXTURE_2D, texture->GetGLTexture()); + mGlAbstraction->TexSubImage2D(GL_TEXTURE_2D, info.level, info.dstOffset2D.x, info.dstOffset2D.y, info.srcExtent2D.width, info.srcExtent2D.height, - GLES::GLTextureFormatType(createInfo.format).format, - GLES::GLTextureFormatType(createInfo.format).type, - source.memorySource.memory); + destFormat, + destType, + sourceBuffer); // free staging memory free(source.memorySource.memory); diff --git a/dali/internal/graphics/gles-impl/gles-graphics-texture.cpp b/dali/internal/graphics/gles-impl/gles-graphics-texture.cpp index cf91080..7e84495 100644 --- a/dali/internal/graphics/gles-impl/gles-graphics-texture.cpp +++ b/dali/internal/graphics/gles-impl/gles-graphics-texture.cpp @@ -43,6 +43,49 @@ const int32_t DALI_MAGNIFY_DEFAULT = GL_LINEAR; namespace Dali::Graphics::GLES { +struct ColorConversion +{ + Format srcFormat; + Format destFormat; + std::vector (*pConversionFunc)(const void*, uint32_t, uint32_t, uint32_t, uint32_t); + void (*pConversionWriteFunc)(const void*, uint32_t, uint32_t, uint32_t, uint32_t, void*); +}; + +inline void WriteRGB32ToRGBA32(const void* pData, uint32_t sizeInBytes, uint32_t width, uint32_t height, uint32_t rowStride, void* pOutput) +{ + auto inData = reinterpret_cast(pData); + auto outData = reinterpret_cast(pOutput); + auto outIdx = 0u; + for(auto i = 0u; i < sizeInBytes; i += 3) + { + outData[outIdx] = inData[i]; + outData[outIdx + 1] = inData[i + 1]; + outData[outIdx + 2] = inData[i + 2]; + outData[outIdx + 3] = 0xff; + outIdx += 4; + } +} + +/** + * Converts RGB to RGBA + */ +inline std::vector ConvertRGB32ToRGBA32(const void* pData, uint32_t sizeInBytes, uint32_t width, uint32_t height, uint32_t rowStride) +{ + std::vector rgbaBuffer{}; + rgbaBuffer.resize(width * height * 4); + WriteRGB32ToRGBA32(pData, sizeInBytes, width, height, rowStride, &rgbaBuffer[0]); + return rgbaBuffer; +} + +/** + * Format conversion table + */ +static const std::vector COLOR_CONVERSION_TABLE = { + {Format::R8G8B8_UNORM, Format::R8G8B8A8_UNORM, ConvertRGB32ToRGBA32, WriteRGB32ToRGBA32}}; + +/** + * Constructor + */ Texture::Texture(const Graphics::TextureCreateInfo& createInfo, Graphics::EglGraphicsController& controller) : TextureResource(createInfo, controller) { @@ -156,7 +199,6 @@ bool Texture::InitializeTexture() // Clear staging buffer if there was any mStagingBuffer.clear(); - mTextureId = texture; // Default texture filtering (to be set later via command buffer binding) @@ -258,4 +300,31 @@ void Texture::Prepare() } } +/** + * This function tests whether format is supported by the driver. If possible it applies + * format conversion to suitable supported pixel format. + */ +bool Texture::TryConvertPixelData(const void* pData, Graphics::Format srcFormat, Graphics::Format destFormat, uint32_t sizeInBytes, uint32_t width, uint32_t height, std::vector& outputBuffer) +{ + // No need to convert + if(srcFormat == destFormat) + { + return false; + } + + auto it = std::find_if(COLOR_CONVERSION_TABLE.begin(), COLOR_CONVERSION_TABLE.end(), [&](auto& item) { + return item.srcFormat == srcFormat && item.destFormat == destFormat; + }); + + // No suitable format, return empty array + if(it == COLOR_CONVERSION_TABLE.end()) + { + return false; + } + auto begin = reinterpret_cast(pData); + + outputBuffer = std::move(it->pConversionFunc(begin, sizeInBytes, width, height, 0u)); + return !outputBuffer.empty(); +} + } // namespace Dali::Graphics::GLES diff --git a/dali/internal/graphics/gles-impl/gles-graphics-texture.h b/dali/internal/graphics/gles-impl/gles-graphics-texture.h index f094fe0..6bbe0f0 100644 --- a/dali/internal/graphics/gles-impl/gles-graphics-texture.h +++ b/dali/internal/graphics/gles-impl/gles-graphics-texture.h @@ -97,15 +97,29 @@ public: return mGlTarget; } -protected: + /** + * @param pData Input data + * @param sizeInBytes Size of the input data in bytes + * @param width Width of the output buffer + * @param height height of the output buffer + * @param outputBuffer The buffer to write to + * @return true if converted, or false otherwise + */ + bool TryConvertPixelData(const void* pData, Graphics::Format srcFormat, Graphics::Format destFormat, uint32_t sizeInBytes, uint32_t width, uint32_t height, std::vector& outputBuffer); + + bool InitializeNativeImage(); + + bool InitializeTexture(); + + Format ValidateFormat(Format sourceFormat); + private: std::vector mStagingBuffer; uint32_t mTextureId{0u}; GLenum mGlTarget{0u}; void* mGLOwnerContext{nullptr}; - bool InitializeNativeImage(); - bool InitializeTexture(); }; + } // namespace Dali::Graphics::GLES #endif -- 2.7.4