Allow to allocate texture's GPU memory at upload timing
[platform/core/uifw/dali-adaptor.git] / dali / internal / graphics / gles-impl / gles-graphics-texture.cpp
index 7cd0d02..5435a97 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -51,18 +51,29 @@ struct ColorConversion
   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)
+inline void WriteRGB32ToRGBA32(const void* __restrict__ pData, uint32_t sizeInBytes, uint32_t width, uint32_t height, uint32_t rowStride, void* __restrict__ 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)
+  const uint8_t* __restrict__ inData = reinterpret_cast<const uint8_t*>(pData);
+  uint8_t* __restrict__ outData      = reinterpret_cast<uint8_t*>(pOutput);
+  if(rowStride == 0u)
   {
-    outData[outIdx]     = inData[i];
-    outData[outIdx + 1] = inData[i + 1];
-    outData[outIdx + 2] = inData[i + 2];
-    outData[outIdx + 3] = 0xff;
-    outIdx += 4;
+    rowStride = width;
+  }
+  for(auto y = 0u; y < height; ++y)
+  {
+    auto inIdx  = 0u;
+    auto outIdx = 0u;
+    for(auto x = 0u; x < width; ++x)
+    {
+      outData[outIdx]     = inData[inIdx];
+      outData[outIdx + 1] = inData[inIdx + 1];
+      outData[outIdx + 2] = inData[inIdx + 2];
+      outData[outIdx + 3] = 0xff;
+      outIdx += 4;
+      inIdx += 3;
+    }
+    inData += rowStride * 3u;
+    outData += width * 4u;
   }
 }
 
@@ -80,8 +91,12 @@ inline std::vector<uint8_t> ConvertRGB32ToRGBA32(const void* pData, uint32_t siz
 /**
  * Format conversion table
  */
-static const std::vector<ColorConversion> COLOR_CONVERSION_TABLE = {
-  {Format::R8G8B8_UNORM, Format::R8G8B8A8_UNORM, ConvertRGB32ToRGBA32, WriteRGB32ToRGBA32}};
+const std::vector<ColorConversion>& GetColorConversionTable()
+{
+  static const std::vector<ColorConversion> COLOR_CONVERSION_TABLE = {
+    {Format::R8G8B8_UNORM, Format::R8G8B8A8_UNORM, ConvertRGB32ToRGBA32, WriteRGB32ToRGBA32}};
+  return COLOR_CONVERSION_TABLE;
+}
 
 /**
  * Constructor
@@ -113,10 +128,11 @@ bool Texture::InitializeResource()
 
 bool Texture::InitializeNativeImage()
 {
-  auto   gl = mController.GetGL();
+  auto   context = mController.GetCurrentContext();
+  auto   gl      = mController.GetGL();
   GLuint texture{0};
 
-  if(!gl)
+  if(!gl || !context)
   {
     // Do nothing during shutdown
     return false;
@@ -128,15 +144,15 @@ bool Texture::InitializeNativeImage()
   if(created)
   {
     gl->GenTextures(1, &texture);
-    gl->BindTexture(mGlTarget, texture);
+    context->BindTexture(mGlTarget, GetTextureTypeId(), texture);
 
     gl->PixelStorei(GL_UNPACK_ALIGNMENT, 1); // We always use tightly packed data
 
     // Apply default sampling parameters
-    gl->TexParameteri(mGlTarget, GL_TEXTURE_MIN_FILTER, DALI_MINIFY_DEFAULT);
-    gl->TexParameteri(mGlTarget, GL_TEXTURE_MAG_FILTER, DALI_MAGNIFY_DEFAULT);
-    gl->TexParameteri(mGlTarget, GL_TEXTURE_WRAP_S, GL_WRAP_DEFAULT);
-    gl->TexParameteri(mGlTarget, GL_TEXTURE_WRAP_T, GL_WRAP_DEFAULT);
+    SetSamplerParameter(GL_TEXTURE_MIN_FILTER, mDefaultSamplerState.minFilter, DALI_MINIFY_DEFAULT);
+    SetSamplerParameter(GL_TEXTURE_MAG_FILTER, mDefaultSamplerState.magFilter, DALI_MAGNIFY_DEFAULT);
+    SetSamplerParameter(GL_TEXTURE_WRAP_S, mDefaultSamplerState.wrapS, GL_WRAP_DEFAULT);
+    SetSamplerParameter(GL_TEXTURE_WRAP_T, mDefaultSamplerState.wrapT, GL_WRAP_DEFAULT);
 
     // platform specific implementation decides on what GL extension to use
     if(nativeImage->TargetTexture() != 0u)
@@ -161,8 +177,9 @@ bool Texture::InitializeNativeImage()
 
 bool Texture::InitializeTexture()
 {
-  auto gl = mController.GetGL();
-  if(!gl)
+  auto context = mController.GetCurrentContext();
+  auto gl      = mController.GetGL();
+  if(!gl || !context)
   {
     // Do nothing during shutdown
     return false;
@@ -170,7 +187,8 @@ bool Texture::InitializeTexture()
 
   GLuint texture{0};
 
-  mGlTarget = GLTextureTarget(mCreateInfo.textureType).target;
+  mGlTarget     = GLTextureTarget(mCreateInfo.textureType).target;
+  mIsCompressed = Graphics::GLES::FormatCompression(mCreateInfo.format).compressed;
 
   switch(mCreateInfo.textureType)
   {
@@ -184,28 +202,44 @@ bool Texture::InitializeTexture()
       {
         // Bind texture
         gl->GenTextures(1, &texture);
-        gl->BindTexture(GL_TEXTURE_2D, texture);
-
-        // Allocate memory for the texture
-        gl->TexImage2D(GL_TEXTURE_2D,
-                       0,
-                       format.format,
-                       mCreateInfo.size.width,
-                       mCreateInfo.size.height,
-                       0,
-                       format.format,
-                       format.type,
-                       (mCreateInfo.data ? mStagingBuffer.data() : nullptr));
+        context->BindTexture(GL_TEXTURE_2D, GetTextureTypeId(), texture);
+
+        if(mCreateInfo.allocationPolicy == Graphics::TextureAllocationPolicy::CREATION || mCreateInfo.data)
+        {
+          // Allocate memory for the texture
+          if(!mIsCompressed)
+          {
+            gl->TexImage2D(GL_TEXTURE_2D,
+                           0,
+                           format.internalFormat,
+                           mCreateInfo.size.width,
+                           mCreateInfo.size.height,
+                           0,
+                           format.format,
+                           format.type,
+                           (mCreateInfo.data ? mStagingBuffer.data() : nullptr));
+          }
+          else
+          {
+            gl->CompressedTexImage2D(GL_TEXTURE_2D,
+                                     0,
+                                     format.internalFormat,
+                                     mCreateInfo.size.width,
+                                     mCreateInfo.size.height,
+                                     0,
+                                     mCreateInfo.dataSize,
+                                     (mCreateInfo.data ? mStagingBuffer.data() : nullptr));
+          }
+        }
 
         // Clear staging buffer if there was any
         mStagingBuffer.clear();
         mTextureId = texture;
-
         // Default texture filtering (to be set later via command buffer binding)
-        gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, Graphics::GLES::GLSamplerFilterAndMipMapMode(Graphics::SamplerFilter::LINEAR, SamplerMipmapMode::NONE));
-        gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, Graphics::GLES::GLSamplerFilterAndMipMapMode(Graphics::SamplerFilter::LINEAR, SamplerMipmapMode::NONE));
-        gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_WRAP_DEFAULT);
-        gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_WRAP_DEFAULT);
+        SetSamplerParameter(GL_TEXTURE_MIN_FILTER, mDefaultSamplerState.minFilter, Graphics::GLES::GLSamplerFilterAndMipMapMode(Graphics::SamplerFilter::LINEAR, SamplerMipmapMode::NONE));
+        SetSamplerParameter(GL_TEXTURE_MAG_FILTER, mDefaultSamplerState.magFilter, Graphics::GLES::GLSamplerFilterAndMipMapMode(Graphics::SamplerFilter::LINEAR, SamplerMipmapMode::NONE));
+        SetSamplerParameter(GL_TEXTURE_WRAP_S, mDefaultSamplerState.wrapS, GL_WRAP_DEFAULT);
+        SetSamplerParameter(GL_TEXTURE_WRAP_T, mDefaultSamplerState.wrapT, GL_WRAP_DEFAULT);
       }
       break;
     }
@@ -218,26 +252,43 @@ bool Texture::InitializeTexture()
       {
         // Bind texture
         gl->GenTextures(1, &texture);
-        gl->BindTexture(GL_TEXTURE_CUBE_MAP, texture);
+        context->BindTexture(GL_TEXTURE_CUBE_MAP, GetTextureTypeId(), texture);
         gl->PixelStorei(GL_UNPACK_ALIGNMENT, 1); // We always use tightly packed data
 
-        gl->TexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, Graphics::GLES::GLSamplerFilterAndMipMapMode(Graphics::SamplerFilter::LINEAR, SamplerMipmapMode::NONE));
-        gl->TexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, Graphics::GLES::GLSamplerFilterAndMipMapMode(Graphics::SamplerFilter::LINEAR, SamplerMipmapMode::NONE));
-        gl->TexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_WRAP_DEFAULT);
-        gl->TexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_WRAP_DEFAULT);
+        SetSamplerParameter(GL_TEXTURE_MIN_FILTER, mDefaultSamplerState.minFilter, Graphics::GLES::GLSamplerFilterAndMipMapMode(Graphics::SamplerFilter::LINEAR, SamplerMipmapMode::NONE));
+        SetSamplerParameter(GL_TEXTURE_MAG_FILTER, mDefaultSamplerState.magFilter, Graphics::GLES::GLSamplerFilterAndMipMapMode(Graphics::SamplerFilter::LINEAR, SamplerMipmapMode::NONE));
+        SetSamplerParameter(GL_TEXTURE_WRAP_S, mDefaultSamplerState.wrapS, GL_WRAP_DEFAULT);
+        SetSamplerParameter(GL_TEXTURE_WRAP_T, mDefaultSamplerState.wrapT, GL_WRAP_DEFAULT);
 
-        // Allocate memory for the texture
-        for(uint32_t i = 0; i < 6; ++i)
+        if(mCreateInfo.allocationPolicy == Graphics::TextureAllocationPolicy::CREATION || mCreateInfo.data)
         {
-          gl->TexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i,
-                         0,
-                         format.format,
-                         mCreateInfo.size.width,
-                         mCreateInfo.size.height,
-                         0,
-                         format.format,
-                         format.type,
-                         (mCreateInfo.data ? mStagingBuffer.data() : nullptr));
+          // Allocate memory for the texture
+          for(uint32_t i = 0; i < 6; ++i)
+          {
+            if(!mIsCompressed)
+            {
+              gl->TexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i,
+                             0,
+                             format.internalFormat,
+                             mCreateInfo.size.width,
+                             mCreateInfo.size.height,
+                             0,
+                             format.format,
+                             format.type,
+                             (mCreateInfo.data ? mStagingBuffer.data() : nullptr));
+            }
+            else
+            {
+              gl->CompressedTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i,
+                                       0,
+                                       format.internalFormat,
+                                       mCreateInfo.size.width,
+                                       mCreateInfo.size.height,
+                                       0,
+                                       mCreateInfo.dataSize,
+                                       (mCreateInfo.data ? mStagingBuffer.data() : nullptr));
+            }
+          }
         }
 
         // Clear staging buffer if there was any
@@ -245,7 +296,7 @@ bool Texture::InitializeTexture()
 
         mTextureId = texture;
 
-        gl->TexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_WRAP_DEFAULT);
+        SetSamplerParameter(GL_TEXTURE_WRAP_R, mDefaultSamplerState.wrapR, GL_WRAP_DEFAULT);
       }
       break;
     }
@@ -283,49 +334,49 @@ void Texture::DiscardResource()
 
 void Texture::Bind(const TextureBinding& binding) const
 {
-  auto gl = mController.GetGL();
-  if(!gl)
+  auto context = mController.GetCurrentContext();
+  auto gl      = mController.GetGL();
+  if(!gl || !context)
   {
     // Do nothing during shutdown
     return;
   }
 
-  gl->ActiveTexture(GL_TEXTURE0 + binding.binding);
-  gl->BindTexture(mGlTarget, mTextureId);
+  context->ActiveTexture(binding.binding);
+  context->BindTexture(mGlTarget, GetTextureTypeId(), mTextureId);
 
   // For GLES2 if there is a sampler set in the binding
   if(binding.sampler)
   {
-    // Non-default.
-    auto*       sampler           = static_cast<const GLES::Sampler*>(binding.sampler);
-    const auto& samplerCreateInfo = sampler->GetCreateInfo();
+    const auto& samplerCreateInfo = static_cast<const GLES::Sampler*>(binding.sampler)->GetCreateInfo();
 
     auto mipMapMode = samplerCreateInfo.mipMapMode;
 
-    gl->TexParameteri(mGlTarget, GL_TEXTURE_MIN_FILTER, GLSamplerFilterAndMipMapMode(samplerCreateInfo.minFilter, mipMapMode).glFilter);
-    gl->TexParameteri(mGlTarget, GL_TEXTURE_MAG_FILTER, GLSamplerFilter(samplerCreateInfo.magFilter).glFilter);
-    gl->TexParameteri(mGlTarget, GL_TEXTURE_WRAP_S, GLAddressMode(samplerCreateInfo.addressModeU).texParameter);
-    gl->TexParameteri(mGlTarget, GL_TEXTURE_WRAP_T, GLAddressMode(samplerCreateInfo.addressModeV).texParameter);
+    SetSamplerParameter(GL_TEXTURE_MIN_FILTER, mDefaultSamplerState.minFilter, GLSamplerFilterAndMipMapMode(samplerCreateInfo.minFilter, mipMapMode).glFilter);
+    SetSamplerParameter(GL_TEXTURE_MAG_FILTER, mDefaultSamplerState.magFilter, GLSamplerFilter(samplerCreateInfo.magFilter).glFilter);
+    SetSamplerParameter(GL_TEXTURE_WRAP_S, mDefaultSamplerState.wrapS, GLAddressMode(samplerCreateInfo.addressModeU).texParameter);
+    SetSamplerParameter(GL_TEXTURE_WRAP_T, mDefaultSamplerState.wrapT, GLAddressMode(samplerCreateInfo.addressModeV).texParameter);
+
     if(mGlTarget == GL_TEXTURE_CUBE_MAP)
     {
-      gl->TexParameteri(mGlTarget, GL_TEXTURE_WRAP_R, GLAddressMode(samplerCreateInfo.addressModeW).texParameter);
+      SetSamplerParameter(GL_TEXTURE_WRAP_R, mDefaultSamplerState.wrapR, GLAddressMode(samplerCreateInfo.addressModeW).texParameter);
     }
   }
   else
   {
-    gl->TexParameteri(mGlTarget, GL_TEXTURE_MIN_FILTER, DALI_MINIFY_DEFAULT);
-    gl->TexParameteri(mGlTarget, GL_TEXTURE_MAG_FILTER, DALI_MAGNIFY_DEFAULT);
-    gl->TexParameteri(mGlTarget, GL_TEXTURE_WRAP_S, GL_WRAP_DEFAULT);
-    gl->TexParameteri(mGlTarget, GL_TEXTURE_WRAP_T, GL_WRAP_DEFAULT);
+    SetSamplerParameter(GL_TEXTURE_MIN_FILTER, mDefaultSamplerState.minFilter, DALI_MINIFY_DEFAULT);
+    SetSamplerParameter(GL_TEXTURE_MAG_FILTER, mDefaultSamplerState.magFilter, DALI_MAGNIFY_DEFAULT);
+    SetSamplerParameter(GL_TEXTURE_WRAP_S, mDefaultSamplerState.wrapS, GL_WRAP_DEFAULT);
+    SetSamplerParameter(GL_TEXTURE_WRAP_T, mDefaultSamplerState.wrapT, GL_WRAP_DEFAULT);
     if(mGlTarget == GL_TEXTURE_CUBE_MAP)
     {
-      gl->TexParameteri(mGlTarget, GL_TEXTURE_WRAP_R, GL_WRAP_DEFAULT);
+      SetSamplerParameter(GL_TEXTURE_WRAP_R, mDefaultSamplerState.wrapR, GL_WRAP_DEFAULT);
     }
   }
 
   if(mMaxMipMapLevel)
   {
-    gl->TexParameteri(mGlTarget, GL_TEXTURE_MAX_LEVEL, mMaxMipMapLevel);
+    SetSamplerParameter(GL_TEXTURE_MAX_LEVEL, mDefaultSamplerState.maxLevel, mMaxMipMapLevel);
   }
 }
 
@@ -334,14 +385,6 @@ void Texture::Prepare()
   NativeImageInterfacePtr nativeImage = mCreateInfo.nativeImagePtr;
   if(nativeImage)
   {
-    if(nativeImage->SourceChanged())
-    {
-      // Update size
-      uint32_t width  = mCreateInfo.nativeImagePtr->GetWidth();
-      uint32_t height = mCreateInfo.nativeImagePtr->GetHeight();
-      mCreateInfo.SetSize({width, height}); // Size may change
-    }
-
     nativeImage->PrepareTexture();
   }
 }
@@ -350,7 +393,7 @@ 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<uint8_t>& outputBuffer)
+bool Texture::TryConvertPixelData(const void* pData, Graphics::Format srcFormat, Graphics::Format destFormat, uint32_t sizeInBytes, uint32_t inStride, uint32_t width, uint32_t height, std::vector<uint8_t>& outputBuffer)
 {
   // No need to convert
   if(srcFormat == destFormat)
@@ -358,19 +401,29 @@ bool Texture::TryConvertPixelData(const void* pData, Graphics::Format srcFormat,
     return false;
   }
 
-  auto it = std::find_if(COLOR_CONVERSION_TABLE.begin(), COLOR_CONVERSION_TABLE.end(), [&](auto& item) {
+  auto it = std::find_if(GetColorConversionTable().begin(), GetColorConversionTable().end(), [&](auto& item) {
     return item.srcFormat == srcFormat && item.destFormat == destFormat;
   });
 
   // No suitable format, return empty array
-  if(it == COLOR_CONVERSION_TABLE.end())
+  if(it == GetColorConversionTable().end())
   {
     return false;
   }
   auto begin = reinterpret_cast<const uint8_t*>(pData);
 
-  outputBuffer = std::move(it->pConversionFunc(begin, sizeInBytes, width, height, 0u));
+  outputBuffer = std::move(it->pConversionFunc(begin, sizeInBytes, width, height, inStride));
   return !outputBuffer.empty();
 }
 
+void Texture::SetSamplerParameter(uint32_t param, uint32_t& cacheValue, uint32_t value) const
+{
+  if(cacheValue != value)
+  {
+    auto gl = mController.GetGL();
+    gl->TexParameteri(mGlTarget, param, value);
+    cacheValue = value;
+  }
+}
+
 } // namespace Dali::Graphics::GLES