<commit_before>/*
 * Copyright (c) 2020 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.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

#define EGL_EGLEXT_PROTOTYPES
#if __ANDROID_API__ < 26
#error "Unsupported Android API version, must be >= 26"
#endif

// CLASS HEADER
#include <dali/internal/imaging/android/native-image-source-impl-android.h>

// EXTERNAL INCLUDES
#include <EGL/egl.h>
#include <include/EGL/eglext.h>
#include <dali/integration-api/debug.h>

// INTERNAL INCLUDES
#include <dali/integration-api/adaptor-framework/render-surface-interface.h>
#include <dali/internal/graphics/common/egl-image-extensions.h>
#include <dali/internal/graphics/gles/egl-graphics.h>
#include <dali/internal/adaptor/common/adaptor-impl.h>


namespace
{
const char* FRAGMENT_PREFIX = "#extension GL_OES_EGL_image_external:require\n";
const char* SAMPLER_TYPE = "samplerExternalOES";
}


namespace Dali
{

namespace Internal
{

namespace Adaptor
{
using Dali::Integration::PixelBuffer;

NativeImageSourceAndroid* NativeImageSourceAndroid::New( uint32_t width, uint32_t height, Dali::NativeImageSource::ColorDepth depth, Any nativeImageSource )
{
  NativeImageSourceAndroid* image = new NativeImageSourceAndroid( width, height, depth, nativeImageSource );
  DALI_ASSERT_DEBUG( image && "NativeImageSource allocation failed." );

  // 2nd phase construction
  if( image ) //< Defensive in case we ever compile without exceptions.
  {
    image->Initialize();
  }

  return image;
}

NativeImageSourceAndroid::NativeImageSourceAndroid( uint32_t width, uint32_t height, Dali::NativeImageSource::ColorDepth depth, Any nativeImageSource )
: mWidth( width ),
  mHeight( height ),
  mOwnPixmap( true ),
  mPixmap( NULL ),
  mBlendingRequired( false ),
  mColorDepth( depth ),
  mEglImageKHR( NULL ),
  mEglImageExtensions( NULL )
{
  DALI_ASSERT_ALWAYS( Adaptor::IsAvailable() );

  GraphicsInterface* graphics = &( Adaptor::GetImplementation( Adaptor::Get() ).GetGraphicsInterface() );
  auto eglGraphics = static_cast<EglGraphics*>( graphics );

  mEglImageExtensions = eglGraphics->GetImageExtensions();

  DALI_ASSERT_DEBUG( mEglImageExtensions );

  // assign the pixmap
  mPixmap = static_cast<AHardwareBuffer*>( GetPixmapFromAny( nativeImageSource ) );
  if( !mPixmap )
  {
    AHardwareBuffer_Desc bufferDescription;
    memset( &bufferDescription, 0, sizeof( AHardwareBuffer_Desc ) );
    bufferDescription.width = width;
    bufferDescription.height = height;
    bufferDescription.layers = 1;
    bufferDescription.usage = AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN | AHARDWAREBUFFER_USAGE_CPU_READ_RARELY | AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE;
    switch( mColorDepth )
    {
      case Dali::NativeImageSource::COLOR_DEPTH_32:
      case Dali::NativeImageSource::COLOR_DEPTH_DEFAULT:
        bufferDescription.format = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
        break;
      case Dali::NativeImageSource::COLOR_DEPTH_24:
        bufferDescription.format = AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM;
        break;
      case Dali::NativeImageSource::COLOR_DEPTH_16:
        bufferDescription.format = AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM;
        break;
      case Dali::NativeImageSource::COLOR_DEPTH_8:
        bufferDescription.format = AHARDWAREBUFFER_FORMAT_BLOB;
        break;
    }

    int ret = AHardwareBuffer_allocate( &bufferDescription, &mPixmap );
    if( ret )
    {
      DALI_LOG_ERROR("Failed to allocate AHardwareBuffer %d", ret);
    }

    mOwnPixmap = true;
  }
}

void NativeImageSourceAndroid::Initialize()
{
  if( mPixmap && !mOwnPixmap )
  {
    AHardwareBuffer_acquire( mPixmap ) ;

    // find out the pixmap width / height and color depth
    GetPixmapDetails();
  }
}

NativeImageSourceAndroid::~NativeImageSourceAndroid()
{
  AHardwareBuffer_release( mPixmap );
  mPixmap = NULL;
}

Any NativeImageSourceAndroid::GetNativeImageSource() const
{
  return Any( mPixmap );
}

bool NativeImageSourceAndroid::GetPixels(std::vector<unsigned char>& pixbuf, unsigned& width, unsigned& height, Pixel::Format& pixelFormat) const
{
  DALI_ASSERT_DEBUG( sizeof(unsigned) == 4 );
  bool success = false;

  width  = mWidth;
  height = mHeight;

  AHardwareBuffer_Desc bufferDescription;
  memset( &bufferDescription, 0, sizeof( AHardwareBuffer_Desc ) );
  AHardwareBuffer_describe( mPixmap, &bufferDescription );
  switch( bufferDescription.format )
  {
    case AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM:
      pixelFormat = Pixel::Format::RGBA8888;
      break;
    case AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM:
      pixelFormat = Pixel::Format::RGB8888;
      break;
    case AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM:
      pixelFormat = Pixel::Format::RGB888;
      break;
    case AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM:
      pixelFormat = Pixel::Format::RGB565;
      break;
    case AHARDWAREBUFFER_FORMAT_BLOB:
    default:
      pixelFormat = Pixel::Format::A8;
      break;
  }

  void* buffer = NULL;
  int ret = AHardwareBuffer_lock( mPixmap, AHARDWAREBUFFER_USAGE_CPU_READ_RARELY, -1, NULL, &buffer );
  if( ret != 0 )
  {
    DALI_LOG_ERROR("Failed to AHardwareBuffer_lock %d", ret);
    return success;
  }

  uint32_t size = bufferDescription.stride * bufferDescription.height;
  pixbuf.resize( size );
  memcpy( pixbuf.data(), buffer, size );

  ret = AHardwareBuffer_unlock( mPixmap, NULL );
  if( ret != 0 )
  {
    DALI_LOG_ERROR("failed to AHardwareBuffer_unlock %d", ret);
    return success;
  }
  success = true;

  return success;
}

void NativeImageSourceAndroid::SetSource( Any source )
{
  if( mPixmap )
  {<commit_msg>Calulating stride for Android native image<commit_after>/*
 * Copyright (c) 2020 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.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

#define EGL_EGLEXT_PROTOTYPES
#if __ANDROID_API__ < 26
#error "Unsupported Android API version, must be >= 26"
#endif

// CLASS HEADER
#include <dali/internal/imaging/android/native-image-source-impl-android.h>

// EXTERNAL INCLUDES
#include <EGL/egl.h>
#include <include/EGL/eglext.h>
#include <dali/integration-api/debug.h>

// INTERNAL INCLUDES
#include <dali/integration-api/adaptor-framework/render-surface-interface.h>
#include <dali/internal/graphics/common/egl-image-extensions.h>
#include <dali/internal/graphics/gles/egl-graphics.h>
#include <dali/internal/adaptor/common/adaptor-impl.h>


namespace
{
const char* FRAGMENT_PREFIX = "#extension GL_OES_EGL_image_external:require\n";
const char* SAMPLER_TYPE = "samplerExternalOES";
}


namespace Dali
{

namespace Internal
{

namespace Adaptor
{
using Dali::Integration::PixelBuffer;

NativeImageSourceAndroid* NativeImageSourceAndroid::New( uint32_t width, uint32_t height, Dali::NativeImageSource::ColorDepth depth, Any nativeImageSource )
{
  NativeImageSourceAndroid* image = new NativeImageSourceAndroid( width, height, depth, nativeImageSource );
  DALI_ASSERT_DEBUG( image && "NativeImageSource allocation failed." );

  // 2nd phase construction
  if( image ) //< Defensive in case we ever compile without exceptions.
  {
    image->Initialize();
  }

  return image;
}

NativeImageSourceAndroid::NativeImageSourceAndroid( uint32_t width, uint32_t height, Dali::NativeImageSource::ColorDepth depth, Any nativeImageSource )
: mWidth( width ),
  mHeight( height ),
  mOwnPixmap( true ),
  mPixmap( NULL ),
  mBlendingRequired( false ),
  mColorDepth( depth ),
  mEglImageKHR( NULL ),
  mEglImageExtensions( NULL )
{
  DALI_ASSERT_ALWAYS( Adaptor::IsAvailable() );

  GraphicsInterface* graphics = &( Adaptor::GetImplementation( Adaptor::Get() ).GetGraphicsInterface() );
  auto eglGraphics = static_cast<EglGraphics*>( graphics );

  mEglImageExtensions = eglGraphics->GetImageExtensions();

  DALI_ASSERT_DEBUG( mEglImageExtensions );

  // assign the pixmap
  mPixmap = static_cast<AHardwareBuffer*>( GetPixmapFromAny( nativeImageSource ) );
  if( !mPixmap )
  {
    AHardwareBuffer_Desc bufferDescription;
    memset( &bufferDescription, 0, sizeof( AHardwareBuffer_Desc ) );
    bufferDescription.width = width;
    bufferDescription.height = height;
    bufferDescription.layers = 1;
    bufferDescription.usage = AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN | AHARDWAREBUFFER_USAGE_CPU_READ_RARELY | AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE;
    switch( mColorDepth )
    {
      case Dali::NativeImageSource::COLOR_DEPTH_32:
      case Dali::NativeImageSource::COLOR_DEPTH_DEFAULT:
        bufferDescription.format = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
        break;
      case Dali::NativeImageSource::COLOR_DEPTH_24:
        bufferDescription.format = AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM;
        break;
      case Dali::NativeImageSource::COLOR_DEPTH_16:
        bufferDescription.format = AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM;
        break;
      case Dali::NativeImageSource::COLOR_DEPTH_8:
        bufferDescription.format = AHARDWAREBUFFER_FORMAT_BLOB;
        break;
    }

    int ret = AHardwareBuffer_allocate( &bufferDescription, &mPixmap );
    if( ret )
    {
      DALI_LOG_ERROR("Failed to allocate AHardwareBuffer %d", ret);
    }

    mOwnPixmap = true;
  }
}

void NativeImageSourceAndroid::Initialize()
{
  if( mPixmap && !mOwnPixmap )
  {
    AHardwareBuffer_acquire( mPixmap ) ;

    // find out the pixmap width / height and color depth
    GetPixmapDetails();
  }
}

NativeImageSourceAndroid::~NativeImageSourceAndroid()
{
  AHardwareBuffer_release( mPixmap );
  mPixmap = NULL;
}

Any NativeImageSourceAndroid::GetNativeImageSource() const
{
  return Any( mPixmap );
}

bool NativeImageSourceAndroid::GetPixels(std::vector<unsigned char>& pixbuf, unsigned& width, unsigned& height, Pixel::Format& pixelFormat) const
{
  DALI_ASSERT_DEBUG( sizeof(unsigned) == 4 );
  bool success = false;

  width  = mWidth;
  height = mHeight;

  AHardwareBuffer_Desc bufferDescription;
  memset( &bufferDescription, 0, sizeof( AHardwareBuffer_Desc ) );
  AHardwareBuffer_describe( mPixmap, &bufferDescription );
  switch( bufferDescription.format )
  {
    case AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM:
      pixelFormat = Pixel::Format::RGBA8888;
      break;
    case AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM:
      pixelFormat = Pixel::Format::RGB8888;
      break;
    case AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM:
      pixelFormat = Pixel::Format::RGB888;
      break;
    case AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM:
      pixelFormat = Pixel::Format::RGB565;
      break;
    case AHARDWAREBUFFER_FORMAT_BLOB:
    default:
      pixelFormat = Pixel::Format::A8;
      break;
  }

  void* buffer = NULL;
  int ret = AHardwareBuffer_lock( mPixmap, AHARDWAREBUFFER_USAGE_CPU_READ_RARELY, -1, NULL, &buffer );
  if( ret != 0 )
  {
    DALI_LOG_ERROR("Failed to AHardwareBuffer_lock %d", ret);
    return success;
  }

  uint32_t pixelBytes = GetBytesPerPixel(pixelFormat);
  if ( bufferDescription.stride < (pixelBytes * bufferDescription.width) )
  {
    //On Android device, bufferDescription.stride doesn't seem to mean (width * pixelbytes)
    //in an actual case, (AHardwareBuffer_Desc) bufferDescription = (width = 1080, height = 1060, layers = 1, format = 1, usage = 306, stride = 1088, rfu0 = 0, rfu1 = 0)
    //deal with situation
    uint32_t dstStride = pixelBytes * bufferDescription.width;
    uint32_t srcStride = pixelBytes * bufferDescription.stride;
    uint32_t size = dstStride * bufferDescription.height;
    pixbuf.resize( size );
    //copy each row over
    const unsigned char* ptrSrc = reinterpret_cast<const unsigned char*>(buffer);
    unsigned char* ptrDst = pixbuf.data();
    for (int y=0; y < bufferDescription.height; y++, ptrSrc += srcStride, ptrDst += dstStride )
    {
      memcpy( ptrDst, ptrSrc, dstStride );
    }
  }
  else
  {
    uint32_t size = bufferDescription.stride * bufferDescription.height;
    pixbuf.resize( size );
    memcpy( pixbuf.data(), buffer, size );
  }

  ret = AHardwareBuffer_unlock( mPixmap, NULL );
  if( ret != 0 )
  {
    DALI_LOG_ERROR("failed to AHardwareBuffer_unlock %d", ret);
    return success;
  }
  success = true;

  return success;
}

void NativeImageSourceAndroid::SetSource( Any source )
{
  if( mPixmap )
  {
{'fraction_non_alphanumeric': 0.09873804971319311, 'fraction_numerical': 0.013919694072657744, 'mean_word_length': 4.412251655629139, 'pattern_counts': {'":': 0, '<': 32, '<?xml version=': 0, '>': 32, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1372898', 'n_tokens_mistral': 4407, 'n_tokens_neox': 4156, 'n_words': 943}