[3.0] Fix for texture Upload()
[platform/core/uifw/dali-core.git] / dali / internal / render / renderers / render-texture.cpp
index 3c87296..689d53b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2017 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.
 
 // CLASS HEADER
 #include <dali/internal/render/renderers/render-texture.h>
+#include <dali/devel-api/images/native-image-interface-extension.h>
 
 // EXTERNAL INCLUDES
 #include <math.h>   //floor, log2
 
-//INTERNAL INCLUDES
-#include <dali/devel-api/rendering/texture.h>  // Dali::Texture
-
 namespace Dali
 {
 namespace Internal
@@ -511,12 +509,89 @@ void PixelFormatToGl( Pixel::Format pixelformat, unsigned& pixelDataType, unsign
   }
 }
 
+/**
+ * @brief Whether specified pixel format is compressed.
+ *
+ * @param [in] pixelformat Pixel format
+ * @return true if format is compressed, false otherwise
+ */
+bool IsCompressedFormat(Pixel::Format pixelFormat)
+{
+  switch (pixelFormat)
+  {
+    case Pixel::L8:
+    case Pixel::A8:
+    case Pixel::LA88:
+    case Pixel::RGB565:
+    case Pixel::RGBA4444:
+    case Pixel::RGBA5551:
+    case Pixel::BGR565:
+    case Pixel::BGRA4444:
+    case Pixel::BGRA5551:
+    case Pixel::RGB888:
+    case Pixel::RGB8888:
+    case Pixel::BGR8888:
+    case Pixel::RGBA8888:
+    case Pixel::BGRA8888:
+    case Pixel::INVALID:
+    {
+      return false;
+    }
+
+    case Pixel::COMPRESSED_R11_EAC:
+    case Pixel::COMPRESSED_SIGNED_R11_EAC:
+    case Pixel::COMPRESSED_RG11_EAC:
+    case Pixel::COMPRESSED_SIGNED_RG11_EAC:
+    case Pixel::COMPRESSED_RGB8_ETC2:
+    case Pixel::COMPRESSED_SRGB8_ETC2:
+    case Pixel::COMPRESSED_RGB8_ETC1:
+    case Pixel::COMPRESSED_RGB_PVRTC_4BPPV1:
+    case Pixel::COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2:
+    case Pixel::COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2:
+    case Pixel::COMPRESSED_RGBA8_ETC2_EAC:
+    case Pixel::COMPRESSED_SRGB8_ALPHA8_ETC2_EAC:
+    case Pixel::COMPRESSED_RGBA_ASTC_4x4_KHR:
+    case Pixel::COMPRESSED_RGBA_ASTC_5x4_KHR:
+    case Pixel::COMPRESSED_RGBA_ASTC_5x5_KHR:
+    case Pixel::COMPRESSED_RGBA_ASTC_6x5_KHR:
+    case Pixel::COMPRESSED_RGBA_ASTC_6x6_KHR:
+    case Pixel::COMPRESSED_RGBA_ASTC_8x5_KHR:
+    case Pixel::COMPRESSED_RGBA_ASTC_8x6_KHR:
+    case Pixel::COMPRESSED_RGBA_ASTC_8x8_KHR:
+    case Pixel::COMPRESSED_RGBA_ASTC_10x5_KHR:
+    case Pixel::COMPRESSED_RGBA_ASTC_10x6_KHR:
+    case Pixel::COMPRESSED_RGBA_ASTC_10x8_KHR:
+    case Pixel::COMPRESSED_RGBA_ASTC_10x10_KHR:
+    case Pixel::COMPRESSED_RGBA_ASTC_12x10_KHR:
+    case Pixel::COMPRESSED_RGBA_ASTC_12x12_KHR:
+    case Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR:
+    case Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR:
+    case Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR:
+    case Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR:
+    case Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR:
+    case Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR:
+    case Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR:
+    case Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR:
+    case Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR:
+    case Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR:
+    case Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR:
+    case Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR:
+    case Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR:
+    case Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR:
+    {
+      return true;
+    }
+  }
+
+  return false;
+}
 
 } //Unnamed namespace
 
 
 NewTexture::NewTexture( Type type, Pixel::Format format, unsigned int width, unsigned int height )
 :mId( 0 ),
+ mTarget( (type == TextureType::TEXTURE_2D)? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP ),
  mType( type ),
  mSampler(),
  mNativeImage(),
@@ -524,13 +599,16 @@ NewTexture::NewTexture( Type type, Pixel::Format format, unsigned int width, uns
  mPixelDataType(GL_UNSIGNED_BYTE),
  mWidth( width ),
  mHeight( height ),
- mHasAlpha( HasAlpha( format ) )
+ mMaxMipMapLevel(0),
+ mHasAlpha( HasAlpha( format ) ),
+ mIsCompressed( IsCompressedFormat( format ) )
 {
   PixelFormatToGl( format, mPixelDataType, mInternalFormat );
 }
 
 NewTexture::NewTexture( NativeImageInterfacePtr nativeImageInterface )
 :mId( 0 ),
+ mTarget( GL_TEXTURE_2D ),
  mType( TextureType::TEXTURE_2D ),
  mSampler(),
  mNativeImage( nativeImageInterface ),
@@ -538,7 +616,9 @@ NewTexture::NewTexture( NativeImageInterfacePtr nativeImageInterface )
  mPixelDataType(GL_UNSIGNED_BYTE),
  mWidth( nativeImageInterface->GetWidth() ),
  mHeight( nativeImageInterface->GetHeight() ),
- mHasAlpha( nativeImageInterface->RequiresBlending() )
+ mMaxMipMapLevel(0),
+ mHasAlpha( nativeImageInterface->RequiresBlending() ),
+ mIsCompressed( false )
 {
 }
 
@@ -550,108 +630,183 @@ void NewTexture::Destroy( Context& context )
   if( mId )
   {
     context.DeleteTextures( 1, &mId );
+
+    if( mNativeImage )
+    {
+      mNativeImage->GlExtensionDestroy();
+    }
   }
 }
 
+void NewTexture::GlContextDestroyed()
+{
+  mId = 0u;
+}
+
 void NewTexture::Initialize(Context& context)
 {
   if( mNativeImage )
   {
     if( mNativeImage->GlExtensionCreate() )
     {
+      NativeImageInterface::Extension* extension = mNativeImage->GetExtension();
+      if( extension )
+      {
+        mTarget = extension->GetEglImageTextureTarget();
+      }
+
       context.GenTextures( 1, &mId );
-      context.Bind2dTexture( mId );
+      context.BindTexture( mTarget, mId );
       context.PixelStorei( GL_UNPACK_ALIGNMENT, 1 ); // We always use tightly packed data
 
       //Apply default sampling parameters
-      context.TexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, DALI_MINIFY_DEFAULT );
-      context.TexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, DALI_MAGNIFY_DEFAULT );
-      context.TexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_WRAP_DEFAULT );
-      context.TexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_WRAP_DEFAULT );
+      context.TexParameteri( mTarget, GL_TEXTURE_MIN_FILTER, DALI_MINIFY_DEFAULT );
+      context.TexParameteri( mTarget, GL_TEXTURE_MAG_FILTER, DALI_MAGNIFY_DEFAULT );
+      context.TexParameteri( mTarget, GL_TEXTURE_WRAP_S, GL_WRAP_DEFAULT );
+      context.TexParameteri( mTarget, GL_TEXTURE_WRAP_T, GL_WRAP_DEFAULT );
 
       // platform specific implementation decides on what GL extension to use
-      mNativeImage->TargetTexture();
+      if( mNativeImage->TargetTexture() != 0u )
+      {
+        context.DeleteTextures( 1, &mId );
+        mNativeImage->GlExtensionDestroy();
+        mId = 0u;
+      }
     }
   }
   else
   {
+    //Create the texture and reserve memory for the first mipmap level.
     context.GenTextures( 1, &mId );
+    context.BindTexture( mTarget, mId );
+    context.PixelStorei( GL_UNPACK_ALIGNMENT, 1 ); // We always use tightly packed data
+
+    //Apply default sampling parameters
+    context.TexParameteri( mTarget, GL_TEXTURE_MIN_FILTER, DALI_MINIFY_DEFAULT );
+    context.TexParameteri( mTarget, GL_TEXTURE_MAG_FILTER, DALI_MAGNIFY_DEFAULT );
+    context.TexParameteri( mTarget, GL_TEXTURE_WRAP_S, GL_WRAP_DEFAULT );
+    context.TexParameteri( mTarget, GL_TEXTURE_WRAP_T, GL_WRAP_DEFAULT );
 
     if( mType == TextureType::TEXTURE_2D )
     {
-      //Creates the texture and reserves memory for the first mipmap level.
-      context.Bind2dTexture( mId );
-      context.TexImage2D(GL_TEXTURE_2D, 0, mInternalFormat, mWidth, mHeight, 0, mInternalFormat, mPixelDataType, 0 );
-
-      //Apply default sampling parameters
-      context.TexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, DALI_MINIFY_DEFAULT );
-      context.TexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, DALI_MAGNIFY_DEFAULT );
-      context.TexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_WRAP_DEFAULT );
-      context.TexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_WRAP_DEFAULT );
+      if( !mIsCompressed )
+      {
+        context.TexImage2D(GL_TEXTURE_2D, 0, mInternalFormat, mWidth, mHeight, 0, mInternalFormat, mPixelDataType, 0 );
+      }
+      else
+      {
+        context.CompressedTexImage2D(GL_TEXTURE_2D, 0, mInternalFormat, mWidth, mHeight, 0, 0, 0 );
+      }
     }
     else if( mType == TextureType::TEXTURE_CUBE )
     {
-      //Creates the texture and reserves memory for the first mipmap level.
-      context.BindCubeMapTexture( mId );
-      for( unsigned int i(0); i<6; ++i )
+      if( !mIsCompressed )
       {
-        context.TexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, mInternalFormat, mWidth, mHeight, 0, mInternalFormat, mPixelDataType, 0 );
+        for( unsigned int i(0); i<6; ++i )
+        {
+          context.TexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, mInternalFormat, mWidth, mHeight, 0, mInternalFormat, mPixelDataType, 0 );
+        }
       }
-
-      //Apply default sampling parameters
-      context.TexParameteri( GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, DALI_MINIFY_DEFAULT );
-      context.TexParameteri( GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, DALI_MAGNIFY_DEFAULT );
-      context.TexParameteri( GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_WRAP_DEFAULT );
-      context.TexParameteri( GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_WRAP_DEFAULT );
-      context.TexParameteri( GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_WRAP_DEFAULT );
+      else
+      {
+        for( unsigned int i(0); i<6; ++i )
+        {
+          context.CompressedTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, mInternalFormat, mWidth, mHeight, 0, 0, 0 );
+        }
+      }
+      context.TexParameteri( mTarget, GL_TEXTURE_WRAP_R, GL_WRAP_DEFAULT );
     }
   }
 }
 
-void NewTexture::Upload( Context& context, Vector<unsigned char>& buffer, const Internal::NewTexture::UploadParams& params  )
+void NewTexture::Upload( Context& context, PixelDataPtr pixelData, const Internal::NewTexture::UploadParams& params  )
 {
   DALI_ASSERT_ALWAYS( mNativeImage == NULL );
 
-  if( mType == TextureType::TEXTURE_2D )
+  //Get pointer to the data of the PixelData object
+  unsigned char* buffer( pixelData->GetBuffer() );
+
+  //This buffer is only used if manually converting from RGB to RGBA
+  unsigned char* tempBuffer(0);
+
+  //Get pixel format and data type of the data contained in the PixelData object
+  GLenum pixelDataFormat, pixelDataElementType;
+  PixelFormatToGl( pixelData->GetPixelFormat(), pixelDataElementType, pixelDataFormat );
+
+  //Get the maximum mipmap level to set GL_TEXTURE_MAX_LEVEL parameter in GLES3x because is not
+  //necessary to upload all the mipmap levels
+  mMaxMipMapLevel = ( mMaxMipMapLevel > params.mipmap ) ? mMaxMipMapLevel : params.mipmap;
+
+  const bool isSubImage = ( ( params.xOffset != 0 ) ||
+                            ( params.yOffset != 0 ) ||
+                            ( params.width  != ( mWidth  / ( 1 << params.mipmap ) ) ) ||
+                            ( params.height != ( mHeight / ( 1 << params.mipmap ) ) ) );
+
+  bool convert = ( ( pixelDataFormat == GL_RGB ) && ( mInternalFormat == GL_RGBA ) );
+#if DALI_GLES_VERSION >= 30
+  // Don't convert manually from RGB to RGBA if GLES >= 3.0 and a sub-image is uploaded.
+  convert = convert && !isSubImage;
+#endif
+
+  if( convert )
+  {
+    size_t dataSize = static_cast< size_t >( params.width ) * params.height;
+    tempBuffer = new unsigned char[dataSize*4u];
+    for( size_t i(0u); i<dataSize; i++ )
+    {
+      tempBuffer[i*4u]   = buffer[i*3u];
+      tempBuffer[i*4u+1] = buffer[i*3u+1];
+      tempBuffer[i*4u+2] = buffer[i*3u+2];
+      tempBuffer[i*4u+3] = 0xFF;
+    }
+
+    buffer = tempBuffer;
+    pixelDataFormat = mInternalFormat;
+  }
+
+  //Upload data to the texture
+
+  context.BindTexture( mTarget, mId );
+  GLenum target( mTarget );
+  if( mType == TextureType::TEXTURE_CUBE )
   {
-    context.Bind2dTexture( mId );
-    context.PixelStorei( GL_UNPACK_ALIGNMENT, 1 );
+    target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + params.layer;
+  }
 
-    if( params.xOffset == 0 && params.yOffset == 0 &&
-        params.width == (unsigned int)(mWidth / (1<<params.mipmap)) &&
-        params.height == (unsigned int)(mHeight / (1<<params.mipmap)) )
+  context.PixelStorei( GL_UNPACK_ALIGNMENT, 1 );
+
+  if( !isSubImage )
+  {
+    //Specifying the whole image for the mipmap. We cannot assume that storage for that mipmap has been created so we need to use TexImage2D
+    if( !mIsCompressed )
     {
-      //Specifying the whole image for the mipmap. We cannot assume that storage for that mipmap has been created so we need to use TexImage2D
-      context.TexImage2D(GL_TEXTURE_2D, params.mipmap, mInternalFormat, params.width, params.height, 0, mInternalFormat, mPixelDataType, &buffer[0]  );
+      context.TexImage2D( target, params.mipmap, mInternalFormat, params.width, params.height, 0, pixelDataFormat, pixelDataElementType, buffer );
     }
     else
     {
-      //Specifying part of the image for the mipmap
-      context.TexSubImage2D( GL_TEXTURE_2D, params.mipmap, params.xOffset, params.yOffset, params.width, params.height, mInternalFormat, mPixelDataType, &buffer[0] );
+      context.CompressedTexImage2D( target, params.mipmap, mInternalFormat, params.width, params.height, 0, pixelData->GetBufferSize(), buffer );
     }
   }
-  else if( mType == TextureType::TEXTURE_CUBE )
+  else
   {
-    context.BindCubeMapTexture( mId );
-    context.PixelStorei( GL_UNPACK_ALIGNMENT, 1 );
-
-    if( params.xOffset == 0 && params.yOffset == 0 &&
-        params.width  == static_cast<unsigned int>(mWidth  / (1<<params.mipmap)) &&
-        params.height == static_cast<unsigned int>(mHeight / (1<<params.mipmap)) )
+    //Specifying part of the image for the mipmap
+    if( !mIsCompressed )
     {
-      //Specifying the whole image for the mipmap. We cannot assume that storage for that mipmap has been created so we need to use TexImage2D
-      context.TexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + params.layer, params.mipmap, mInternalFormat,
-                         params.width, params.height, 0,
-                         mInternalFormat, mPixelDataType, &buffer[0] );
+      context.TexSubImage2D( target, params.mipmap,
+                             params.xOffset, params.yOffset, params.width, params.height,
+                             pixelDataFormat, pixelDataElementType, buffer );
     }
     else
     {
-      //Specifying part of the image for the mipmap
-      context.TexSubImage2D( GL_TEXTURE_CUBE_MAP_POSITIVE_X + params.layer, params.mipmap,
-                             params.xOffset, params.yOffset, params.width, params.height,
-                             mInternalFormat, mPixelDataType, &buffer[0] );
+      context.CompressedTexSubImage2D( target, params.mipmap,
+                                       params.xOffset, params.yOffset, params.width, params.height,
+                                       pixelDataFormat, pixelData->GetBufferSize(), buffer );
     }
   }
+
+
+  //Destroy temp buffer used for conversion RGB->RGBA
+  delete[] tempBuffer;
 }
 
 bool NewTexture::Bind( Context& context, unsigned int textureUnit, Render::Sampler* sampler )
@@ -659,17 +814,13 @@ bool NewTexture::Bind( Context& context, unsigned int textureUnit, Render::Sampl
   if( mId != 0 )
   {
     context.ActiveTexture( static_cast<TextureUnit>(textureUnit) );
+    context.BindTexture( mTarget, mId );
+    ApplySampler( context, sampler );
 
-    if( mType == TextureType::TEXTURE_2D )
+    if( mNativeImage )
     {
-      context.Bind2dTexture( mId );
+      mNativeImage->PrepareTexture();
     }
-    else if( mType == TextureType::TEXTURE_CUBE )
-    {
-      context.BindCubeMapTexture( mId );
-    }
-
-    ApplySampler( context, sampler );
 
     return true;
   }
@@ -680,42 +831,48 @@ bool NewTexture::Bind( Context& context, unsigned int textureUnit, Render::Sampl
 void NewTexture::ApplySampler( Context& context, Render::Sampler* sampler )
 {
   Render::Sampler oldSampler = mSampler;
-  if( sampler )
-  {
-    mSampler = *sampler;
-  }
+  mSampler = sampler ? *sampler : Sampler();
 
   if( mSampler.mBitfield != oldSampler.mBitfield )
   {
     if( mSampler.mMinificationFilter != oldSampler.mMinificationFilter )
     {
       GLint glFilterMode = FilterModeToGL( mSampler.mMinificationFilter, DALI_MINIFY_DEFAULT, GL_MINIFY_DEFAULT );
-      context.TexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, glFilterMode );
+      context.TexParameteri( mTarget, GL_TEXTURE_MIN_FILTER, glFilterMode );
     }
 
     if( mSampler.mMagnificationFilter != oldSampler.mMagnificationFilter )
     {
       GLint glFilterMode = FilterModeToGL( mSampler.mMagnificationFilter, DALI_MAGNIFY_DEFAULT, GL_MAGNIFY_DEFAULT );
-      context.TexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, glFilterMode );
+      context.TexParameteri( mTarget, GL_TEXTURE_MAG_FILTER, glFilterMode );
     }
 
     if( mSampler.mSWrapMode != oldSampler.mSWrapMode )
     {
       GLint glWrapMode = WrapModeToGL( mSampler.mSWrapMode, GL_WRAP_DEFAULT );
-      context.TexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, glWrapMode );
+      context.TexParameteri( mTarget, GL_TEXTURE_WRAP_S, glWrapMode );
     }
 
     if( mSampler.mTWrapMode != oldSampler.mTWrapMode )
     {
       GLint glWrapMode = WrapModeToGL( mSampler.mTWrapMode, GL_WRAP_DEFAULT );
-      context.TexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, glWrapMode );
+      context.TexParameteri( mTarget, GL_TEXTURE_WRAP_T, glWrapMode );
     }
 
     if( mType == TextureType::TEXTURE_CUBE && mSampler.mRWrapMode != oldSampler.mRWrapMode )
     {
       GLint glWrapMode = WrapModeToGL( mSampler.mRWrapMode, GL_WRAP_DEFAULT );
-      context.TexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, glWrapMode );
+      context.TexParameteri( mTarget, GL_TEXTURE_WRAP_R, glWrapMode );
+    }
+
+#if DALI_GLES_VERSION >= 30
+    //In GLES 3.0 we do not need to upload all of the mipmap levels, but GL_TEXTURE_MAX_LEVEL must be set
+    if(mMaxMipMapLevel)
+    {
+      context.TexParameteri( mTarget, GL_TEXTURE_MAX_LEVEL, mMaxMipMapLevel );
     }
+#endif
+
   }
 }
 
@@ -726,16 +883,10 @@ bool NewTexture::HasAlphaChannel()
 
 void NewTexture::GenerateMipmaps( Context& context )
 {
-  if( mType == TextureType::TEXTURE_2D )
-  {
-    context.Bind2dTexture( mId );
-    context.GenerateMipmap( GL_TEXTURE_2D );
-  }
-  else if( mType == TextureType::TEXTURE_CUBE )
-  {
-    context.BindCubeMapTexture( mId );
-    context.GenerateMipmap( GL_TEXTURE_CUBE_MAP );
-  }
+  //GL_TEXTURE_MAX_LEVEL does not need to be set when mipmaps are generated by GL
+  mMaxMipMapLevel = 0;
+  context.BindTexture( mTarget, mId );
+  context.GenerateMipmap( mTarget );
 }
 
 } //Render