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<GLES::Texture*>(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<uint8_t*>(source.memorySource.memory);
+ std::vector<uint8_t> 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);
namespace Dali::Graphics::GLES
{
+struct ColorConversion
+{
+ Format srcFormat;
+ Format destFormat;
+ std::vector<uint8_t> (*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<const uint8_t*>(pData);
+ auto outData = reinterpret_cast<uint8_t*>(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<uint8_t> ConvertRGB32ToRGBA32(const void* pData, uint32_t sizeInBytes, uint32_t width, uint32_t height, uint32_t rowStride)
+{
+ std::vector<uint8_t> rgbaBuffer{};
+ rgbaBuffer.resize(width * height * 4);
+ WriteRGB32ToRGBA32(pData, sizeInBytes, width, height, rowStride, &rgbaBuffer[0]);
+ return rgbaBuffer;
+}
+
+/**
+ * Format conversion table
+ */
+static const std::vector<ColorConversion> COLOR_CONVERSION_TABLE = {
+ {Format::R8G8B8_UNORM, Format::R8G8B8A8_UNORM, ConvertRGB32ToRGBA32, WriteRGB32ToRGBA32}};
+
+/**
+ * Constructor
+ */
Texture::Texture(const Graphics::TextureCreateInfo& createInfo, Graphics::EglGraphicsController& controller)
: TextureResource(createInfo, controller)
{
// Clear staging buffer if there was any
mStagingBuffer.clear();
-
mTextureId = texture;
// Default texture filtering (to be set later via command buffer binding)
}
}
+/**
+ * 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<uint8_t>& 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<const uint8_t*>(pData);
+
+ outputBuffer = std::move(it->pConversionFunc(begin, sizeInBytes, width, height, 0u));
+ return !outputBuffer.empty();
+}
+
} // namespace Dali::Graphics::GLES
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<uint8_t>& outputBuffer);
+
+ bool InitializeNativeImage();
+
+ bool InitializeTexture();
+
+ Format ValidateFormat(Format sourceFormat);
+
private:
std::vector<char> mStagingBuffer;
uint32_t mTextureId{0u};
GLenum mGlTarget{0u};
void* mGLOwnerContext{nullptr};
- bool InitializeNativeImage();
- bool InitializeTexture();
};
+
} // namespace Dali::Graphics::GLES
#endif