+ case Graphics::TextureUpdateSourceInfo::Type::MEMORY:
+ case Graphics::TextureUpdateSourceInfo::Type::PIXEL_DATA:
+ {
+ // 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 srcType = GLES::GLTextureFormatType(info.srcFormat).type;
+ auto destInternalFormat = GLES::GLTextureFormatType(createInfo.format).internalFormat;
+ auto destFormat = GLES::GLTextureFormatType(createInfo.format).format;
+
+ // 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)));
+
+ uint8_t* sourceBuffer = nullptr;
+ bool sourceBufferReleaseRequired = false;
+ if(source.sourceType == Graphics::TextureUpdateSourceInfo::Type::MEMORY)
+ {
+ sourceBuffer = reinterpret_cast<uint8_t*>(source.memorySource.memory);
+ sourceBufferReleaseRequired = true;
+ }
+ else
+ {
+ Dali::Integration::PixelDataBuffer pixelBufferData = Dali::Integration::GetPixelDataBuffer(source.pixelDataSource.pixelData);
+
+ sourceBuffer = pixelBufferData.buffer + info.srcOffset;
+ sourceBufferReleaseRequired = Dali::Integration::IsPixelDataReleaseAfterUpload(source.pixelDataSource.pixelData) && info.srcOffset == 0u;
+ }
+
+ auto sourceStride = info.srcStride;
+ std::vector<uint8_t> tempBuffer;
+
+ if(mGlAbstraction->TextureRequiresConverting(srcFormat, destFormat, isSubImage))
+ {
+ // Convert RGB to RGBA if necessary.
+ if(texture->TryConvertPixelData(sourceBuffer, info.srcFormat, createInfo.format, info.srcSize, info.srcStride, info.srcExtent2D.width, info.srcExtent2D.height, tempBuffer))
+ {
+ sourceBuffer = &tempBuffer[0];
+ sourceStride = 0u; // Converted buffer compacted. make stride as 0.
+ srcFormat = destFormat;
+ srcType = GLES::GLTextureFormatType(createInfo.format).type;
+ }
+ }
+
+ // Calculate the maximum mipmap level for the texture
+ texture->SetMaxMipMapLevel(std::max(texture->GetMaxMipMapLevel(), info.level));
+
+ GLenum bindTarget{GL_TEXTURE_2D};
+ GLenum target{GL_TEXTURE_2D};
+
+ if(createInfo.textureType == Graphics::TextureType::TEXTURE_CUBEMAP)
+ {
+ bindTarget = GL_TEXTURE_CUBE_MAP;
+ target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + info.layer;
+ }
+
+ mGlAbstraction->PixelStorei(GL_UNPACK_ALIGNMENT, 1);
+ mGlAbstraction->PixelStorei(GL_UNPACK_ROW_LENGTH, sourceStride);
+
+ mCurrentContext->BindTexture(bindTarget, texture->GetTextureTypeId(), texture->GetGLTexture());
+
+ if(!isSubImage)
+ {
+ if(!texture->IsCompressed())
+ {
+ mGlAbstraction->TexImage2D(target,
+ info.level,
+ destInternalFormat,
+ info.srcExtent2D.width,
+ info.srcExtent2D.height,
+ 0,
+ srcFormat,
+ srcType,
+ sourceBuffer);
+ }
+ else
+ {
+ mGlAbstraction->CompressedTexImage2D(target,
+ info.level,
+ destInternalFormat,
+ info.srcExtent2D.width,
+ info.srcExtent2D.height,
+ 0,
+ info.srcSize,
+ sourceBuffer);
+ }
+ }
+ else
+ {
+ if(!texture->IsCompressed())
+ {
+ mGlAbstraction->TexSubImage2D(target,
+ info.level,
+ info.dstOffset2D.x,
+ info.dstOffset2D.y,
+ info.srcExtent2D.width,
+ info.srcExtent2D.height,
+ srcFormat,
+ srcType,
+ sourceBuffer);
+ }
+ else
+ {
+ mGlAbstraction->CompressedTexSubImage2D(target,
+ info.level,
+ info.dstOffset2D.x,
+ info.dstOffset2D.y,
+ info.srcExtent2D.width,
+ info.srcExtent2D.height,
+ srcFormat,
+ info.srcSize,
+ sourceBuffer);
+ }
+ }
+
+ if(sourceBufferReleaseRequired && sourceBuffer != nullptr)
+ {
+ if(source.sourceType == Graphics::TextureUpdateSourceInfo::Type::MEMORY)
+ {
+ free(reinterpret_cast<void*>(sourceBuffer));
+ }
+ else
+ {
+ Dali::Integration::ReleasePixelDataBuffer(source.pixelDataSource.pixelData);
+ }
+ }
+ break;
+ }
+ default:
+ {
+ // TODO: other sources
+ break;
+ }