Implement basic ANDROID_image_native_buffer support.

Change-Id: I7e844eb7c313455d48cd2fc09440f10d639b4c77
Reviewed-on: https://swiftshader-review.googlesource.com/2758
Tested-by: Nicolas Capens <capn@google.com>
Reviewed-by: Greg Hartman <ghartman@google.com>
Reviewed-by: Ping-Hao Wu <pinghao@google.com>
Reviewed-by: Nicolas Capens <capn@google.com>
diff --git a/src/OpenGL/libEGL/Image.hpp b/src/OpenGL/libEGL/Image.hpp
index f612c57..071cf7d 100644
--- a/src/OpenGL/libEGL/Image.hpp
+++ b/src/OpenGL/libEGL/Image.hpp
@@ -3,6 +3,11 @@
 

 #include "Renderer/Surface.hpp"

 

+#if defined(__ANDROID__)

+#include <hardware/gralloc.h>

+#include <system/window.h>

+#endif

+

 #include <assert.h>

 

 namespace egl

@@ -23,6 +28,11 @@
 		, sw::Surface(resource, width, height, depth, internalFormat, true, true)

 	{

 		shared = false;

+

+		#if defined(__ANDROID__)

+			nativeBuffer = 0;

+			gralloc = 0;

+		#endif

 	}

 

 	Image(sw::Resource *resource, int width, int height, int depth, sw::Format internalFormat, bool lockable, bool renderTarget)

@@ -30,6 +40,11 @@
 		, sw::Surface(resource, width, height, depth, internalFormat, lockable, renderTarget)

 	{

 		shared = false;

+

+		#if defined(__ANDROID__)

+			nativeBuffer = 0;

+			gralloc = 0;

+		#endif

 	}

 

 	GLsizei getWidth() const

@@ -76,6 +91,13 @@
 

 	void *lock(unsigned int left, unsigned int top, sw::Lock lock)

 	{

+		#if defined(__ANDROID__)

+			if(nativeBuffer)   // Lock the buffer from ANativeWindowBuffer

+			{

+				return lockNativeBuffer(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN);

+			}

+		#endif

+

 		return lockExternal(left, top, 0, lock, sw::PUBLIC);

 	}

 

@@ -86,6 +108,13 @@
 

 	void unlock()

 	{

+		#if defined(__ANDROID__)

+			if(nativeBuffer)   // Unlock the buffer from ANativeWindowBuffer

+			{

+				return unlockNativeBuffer();

+			}

+		#endif

+

 		unlockExternal();

 	}

 

@@ -94,15 +123,48 @@
 	virtual void unbind(const Texture *parent) = 0;   // Break parent ownership and release

 

 	void destroyShared()   // Release a shared image

-    {

+	{

+		#if defined(__ANDROID__)

+			if(nativeBuffer)

+			{

+				nativeBuffer->common.decRef(&nativeBuffer->common);

+			}

+		#endif

+

 		assert(shared);

-        shared = false;

+		shared = false;

 		release();

-    }

+	}

 

 	virtual void loadImageData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLint unpackAlignment, const void *input) = 0;

 	virtual void loadCompressedData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels) = 0;

 

+	#if defined(__ANDROID__)

+	void setNativeBuffer(ANativeWindowBuffer* buffer)

+	{

+		nativeBuffer = buffer;

+		nativeBuffer->common.incRef(&nativeBuffer->common);

+	}

+

+	virtual void *lockInternal(int x, int y, int z, sw::Lock lock, sw::Accessor client)

+	{

+		if(nativeBuffer)   // Lock the buffer from ANativeWindowBuffer

+		{

+			return lockNativeBuffer(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN);

+		}

+		return sw::Surface::lockInternal(x, y, z, lock, client);

+	}

+

+	virtual void unlockInternal()

+	{

+		if(nativeBuffer)   // Unlock the buffer from ANativeWindowBuffer

+		{

+			return unlockNativeBuffer();

+		}

+		return sw::Surface::unlockInternal();

+	}

+	#endif

+

 protected:

 	virtual ~Image()

 	{

@@ -116,6 +178,40 @@
 	const int depth;

 

 	bool shared;   // Used as an EGLImage

+

+	#if defined(__ANDROID__)

+	ANativeWindowBuffer *nativeBuffer;

+	gralloc_module_t const *gralloc;

+

+	void initGralloc()

+	{

+		hw_module_t const *module;

+		hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module);

+		gralloc = reinterpret_cast<gralloc_module_t const*>(module);

+	}

+

+	void* lockNativeBuffer(int usage)

+	{

+		if(!gralloc)

+		{

+			initGralloc();

+		}

+

+		void *buffer = 0;

+		gralloc->lock(gralloc, nativeBuffer->handle, usage, 0, 0, nativeBuffer->width, nativeBuffer->height, &buffer);

+		return buffer;

+	}

+

+	void unlockNativeBuffer()

+	{

+		if(!gralloc)

+		{

+			initGralloc();

+		}

+

+		gralloc->unlock(gralloc, nativeBuffer->handle);

+	}

+	#endif

 };

 }

 

diff --git a/src/OpenGL/libEGL/libEGL.cpp b/src/OpenGL/libEGL/libEGL.cpp
index e016390..b053c94 100644
--- a/src/OpenGL/libEGL/libEGL.cpp
+++ b/src/OpenGL/libEGL/libEGL.cpp
@@ -20,6 +20,10 @@
 #include "common/debug.h"

 #include "Common/Version.h"

 

+#if defined(__ANDROID__)

+#include <system/window.h>

+#endif

+

 #include <string.h>

 

 static bool validateDisplay(egl::Display *display)

@@ -870,6 +874,15 @@
 		return error(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR);

 	}

 

+	#if defined(__ANDROID__)

+		if(target == EGL_NATIVE_BUFFER_ANDROID)

+		{

+			// When target is EGL_NATIVE_BUFFER_ANDROID, ctx is always EGL_NO_CONTEXT.

+			// Get the current context so that we can validate and create shared image

+			context = static_cast<egl::Context*>(egl::getCurrentContext());

+		}

+	#endif

+

 	EGLenum validationResult = context->validateSharedImage(target, name, textureLevel);

 

 	if(validationResult != EGL_SUCCESS)

diff --git a/src/OpenGL/libGLES_CM/Context.cpp b/src/OpenGL/libGLES_CM/Context.cpp
index c91f1dc..a784ded 100644
--- a/src/OpenGL/libGLES_CM/Context.cpp
+++ b/src/OpenGL/libGLES_CM/Context.cpp
@@ -2561,6 +2561,10 @@
         break;

     case EGL_GL_RENDERBUFFER_KHR:

         break;

+    #if defined(__ANDROID__)

+    case EGL_NATIVE_BUFFER_ANDROID:

+        break;

+    #endif

     default:

         return EGL_BAD_PARAMETER;

     }

@@ -2608,6 +2612,32 @@
             return EGL_BAD_ACCESS;

         }

     }

+    #if defined(__ANDROID__)

+    else if(target == EGL_NATIVE_BUFFER_ANDROID)

+    {

+        ANativeWindowBuffer *nativeBuffer = reinterpret_cast<ANativeWindowBuffer*>(name);

+

+        if(nativeBuffer->common.magic != ANDROID_NATIVE_BUFFER_MAGIC)

+        {

+            return EGL_BAD_PARAMETER;

+        }

+

+        if(nativeBuffer->common.version != sizeof(ANativeWindowBuffer))

+        {

+            return EGL_BAD_PARAMETER;

+        }

+

+        switch(nativeBuffer->format)

+		{

+        case HAL_PIXEL_FORMAT_RGBA_8888:

+        case HAL_PIXEL_FORMAT_RGBX_8888:

+        case HAL_PIXEL_FORMAT_RGB_565:

+            break;

+        default:

+            return EGL_BAD_PARAMETER;

+        }

+    }

+    #endif

     else UNREACHABLE();

 

 	return EGL_SUCCESS;

@@ -2627,6 +2657,22 @@
 

         return renderbuffer->createSharedImage();

     }

+    #if defined(__ANDROID__)

+    else if(target == EGL_NATIVE_BUFFER_ANDROID)

+    {

+        ANativeWindowBuffer *nativeBuffer = reinterpret_cast<ANativeWindowBuffer*>(name);

+        nativeBuffer->common.incRef(&nativeBuffer->common);

+

+        GLenum format = Image::getColorFormatFromAndroid(nativeBuffer->format);

+        GLenum type = Image::getPixelFormatFromAndroid(nativeBuffer->format);

+

+        es1::Image *image = new Image(0, nativeBuffer->width, nativeBuffer->height, format, type);

+        image->setNativeBuffer(nativeBuffer);

+        image->markShared();

+

+        return image;

+    }

+    #endif

     else UNREACHABLE();

 

 	return 0;

diff --git a/src/OpenGL/libGLES_CM/Image.cpp b/src/OpenGL/libGLES_CM/Image.cpp
index 416b6b4..e025169 100644
--- a/src/OpenGL/libGLES_CM/Image.cpp
+++ b/src/OpenGL/libGLES_CM/Image.cpp
@@ -544,4 +544,46 @@
 
 		unlock();
 	}
-}
\ No newline at end of file
+
+	#if defined(__ANDROID__)
+	GLenum Image::getColorFormatFromAndroid(int format)
+	{
+		switch(format)
+		{
+		case HAL_PIXEL_FORMAT_RGBA_8888:
+		case HAL_PIXEL_FORMAT_RGBX_8888:
+			return GL_RGBA;
+		case HAL_PIXEL_FORMAT_RGB_888:
+			return GL_RGB;
+		case HAL_PIXEL_FORMAT_RGB_565:
+			return GL_RGB565_OES;
+		case HAL_PIXEL_FORMAT_BGRA_8888:
+			return GL_BGRA_EXT;
+		#if GCE_PLATFORM_SDK_VERSION >= 19
+		case HAL_PIXEL_FORMAT_sRGB_A_8888:
+		case HAL_PIXEL_FORMAT_sRGB_X_8888:
+		#endif
+		case HAL_PIXEL_FORMAT_YV12:
+		case HAL_PIXEL_FORMAT_Y8:
+		case HAL_PIXEL_FORMAT_Y16:
+		case HAL_PIXEL_FORMAT_RAW_SENSOR:
+		case HAL_PIXEL_FORMAT_BLOB:
+		case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED:
+		case HAL_PIXEL_FORMAT_YCbCr_420_888:
+		default:
+			UNIMPLEMENTED();
+		}
+		return GL_RGBA;
+	}
+
+	GLenum Image::getPixelFormatFromAndroid(int format)
+	{
+		if(format == HAL_PIXEL_FORMAT_Y16)
+		{
+			return GL_UNSIGNED_SHORT;
+		}
+
+		return GL_UNSIGNED_BYTE;
+	}
+	#endif
+}
diff --git a/src/OpenGL/libGLES_CM/Image.hpp b/src/OpenGL/libGLES_CM/Image.hpp
index a5b0251..223d6ce 100644
--- a/src/OpenGL/libGLES_CM/Image.hpp
+++ b/src/OpenGL/libGLES_CM/Image.hpp
@@ -37,6 +37,11 @@
 
 		static sw::Format selectInternalFormat(GLenum format, GLenum type);
 
+		#if defined(__ANDROID__)
+		static GLenum getColorFormatFromAndroid(int format);
+		static GLenum getPixelFormatFromAndroid(int format);
+		#endif
+
 	private:
 		virtual ~Image();
 
diff --git a/src/OpenGL/libGLESv2/Context.cpp b/src/OpenGL/libGLESv2/Context.cpp
index 8692d16..2b099a2 100644
--- a/src/OpenGL/libGLESv2/Context.cpp
+++ b/src/OpenGL/libGLESv2/Context.cpp
@@ -3522,6 +3522,10 @@
         break;

     case EGL_GL_RENDERBUFFER_KHR:

         break;

+    #if defined(__ANDROID__)

+    case EGL_NATIVE_BUFFER_ANDROID:

+        break;

+    #endif

     default:

         return EGL_BAD_PARAMETER;

     }

@@ -3569,6 +3573,32 @@
             return EGL_BAD_ACCESS;

         }

     }

+    #if defined(__ANDROID__)

+    else if(target == EGL_NATIVE_BUFFER_ANDROID)

+    {

+        ANativeWindowBuffer *nativeBuffer = reinterpret_cast<ANativeWindowBuffer*>(name);

+        

+		if(nativeBuffer->common.magic != ANDROID_NATIVE_BUFFER_MAGIC)

+        {

+            return EGL_BAD_PARAMETER;

+        }

+

+        if(nativeBuffer->common.version != sizeof(ANativeWindowBuffer))

+        {

+            return EGL_BAD_PARAMETER;

+        }

+

+        switch(nativeBuffer->format)

+		{

+        case HAL_PIXEL_FORMAT_RGBA_8888:

+        case HAL_PIXEL_FORMAT_RGBX_8888:

+        case HAL_PIXEL_FORMAT_RGB_565:

+            break;

+        default:

+            return EGL_BAD_PARAMETER;

+        }

+    }

+    #endif

     else UNREACHABLE();

 

 	return EGL_SUCCESS;

@@ -3601,6 +3631,22 @@
 

         return renderbuffer->createSharedImage();

     }

+    #if defined(__ANDROID__)

+    else if(target == EGL_NATIVE_BUFFER_ANDROID)

+    {

+        ANativeWindowBuffer *nativeBuffer = reinterpret_cast<ANativeWindowBuffer*>(name);

+        nativeBuffer->common.incRef(&nativeBuffer->common);

+

+        GLenum format = Image::getColorFormatFromAndroid(nativeBuffer->format);

+        GLenum type = Image::getPixelFormatFromAndroid(nativeBuffer->format);

+

+        es2::Image *image = new Image(0, nativeBuffer->width, nativeBuffer->height, format, type);

+        image->setNativeBuffer(nativeBuffer);

+        image->markShared();

+

+        return image;

+    }

+    #endif

     else UNREACHABLE();

 

 	return 0;

diff --git a/src/OpenGL/libGLESv2/Image.cpp b/src/OpenGL/libGLESv2/Image.cpp
index 6a36db5..dd8acd7 100644
--- a/src/OpenGL/libGLESv2/Image.cpp
+++ b/src/OpenGL/libGLESv2/Image.cpp
@@ -53,13 +53,13 @@
 		UNIMPLEMENTED();
 	}
 
-	template<>

+	template<>
 	void LoadImageRow<Alpha>(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width)
 	{
 		memcpy(dest + xoffset, source, width);
 	}
 
-	template<>

+	template<>
 	void LoadImageRow<AlphaFloat>(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width)
 	{
 		const float *sourceF = reinterpret_cast<const float*>(source);
@@ -74,7 +74,7 @@
 		}
 	}
 
-	template<>

+	template<>
 	void LoadImageRow<AlphaHalfFloat>(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width)
 	{
 		const unsigned short *sourceH = reinterpret_cast<const unsigned short*>(source);
@@ -89,13 +89,13 @@
 		}
 	}
 
-	template<>

+	template<>
 	void LoadImageRow<Luminance>(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width)
 	{
 		memcpy(dest + xoffset, source, width);
 	}
 
-	template<>

+	template<>
 	void LoadImageRow<LuminanceFloat>(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width)
 	{
 		const float *sourceF = reinterpret_cast<const float*>(source);
@@ -110,7 +110,7 @@
 		}
 	}
 
-	template<>

+	template<>
 	void LoadImageRow<LuminanceHalfFloat>(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width)
 	{
 		const unsigned short *sourceH = reinterpret_cast<const unsigned short*>(source);
@@ -125,13 +125,13 @@
 		}
 	}
 
-	template<>

+	template<>
 	void LoadImageRow<LuminanceAlpha>(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width)
 	{
 		memcpy(dest + xoffset * 2, source, width * 2);
 	}
 
-	template<>

+	template<>
 	void LoadImageRow<LuminanceAlphaFloat>(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width)
 	{
 		const float *sourceF = reinterpret_cast<const float*>(source);
@@ -146,7 +146,7 @@
 		}
 	}
 
-	template<>

+	template<>
 	void LoadImageRow<LuminanceAlphaHalfFloat>(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width)
 	{
 		const unsigned short *sourceH = reinterpret_cast<const unsigned short*>(source);
@@ -161,7 +161,7 @@
 		}
 	}
 
-	template<>

+	template<>
 	void LoadImageRow<RGBUByte>(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width)
 	{
 		unsigned char *destB = dest + xoffset * 4;
@@ -175,7 +175,7 @@
 		}
 	}
 
-	template<>

+	template<>
 	void LoadImageRow<RGB565>(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width)
 	{
 		const unsigned short *source565 = reinterpret_cast<const unsigned short*>(source);
@@ -191,7 +191,7 @@
 		}
 	}
 
-	template<>

+	template<>
 	void LoadImageRow<RGBFloat>(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width)
 	{
 		const float *sourceF = reinterpret_cast<const float*>(source);
@@ -206,7 +206,7 @@
 		}
 	}
 
-	template<>

+	template<>
 	void LoadImageRow<RGBHalfFloat>(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width)
 	{
 		const unsigned short *sourceH = reinterpret_cast<const unsigned short*>(source);
@@ -221,7 +221,7 @@
 		}
 	}
 
-	template<>

+	template<>
 	void LoadImageRow<RGBAUByte>(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width)
 	{
 		const unsigned int *sourceI = reinterpret_cast<const unsigned int*>(source);
@@ -234,7 +234,7 @@
 		}
 	}
 
-	template<>

+	template<>
 	void LoadImageRow<RGBA4444>(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width)
 	{
 		const unsigned short *source4444 = reinterpret_cast<const unsigned short*>(source);
@@ -250,7 +250,7 @@
 		}
 	}
 
-	template<>

+	template<>
 	void LoadImageRow<RGBA5551>(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width)
 	{
 		const unsigned short *source5551 = reinterpret_cast<const unsigned short*>(source);
@@ -266,25 +266,25 @@
 		}
 	}
 
-	template<>

+	template<>
 	void LoadImageRow<RGBAFloat>(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width)
 	{
 		memcpy(dest + xoffset * 16, source, width * 16);
 	}
 
-	template<>

+	template<>
 	void LoadImageRow<RGBAHalfFloat>(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width)
 	{
 		memcpy(dest + xoffset * 8, source, width * 8);
 	}
 
-	template<>

+	template<>
 	void LoadImageRow<BGRA>(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width)
 	{
 		memcpy(dest + xoffset * 4, source, width * 4);
 	}
 
-	template<>

+	template<>
 	void LoadImageRow<D16>(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width)
 	{
 		const unsigned short *sourceD16 = reinterpret_cast<const unsigned short*>(source);
@@ -296,7 +296,7 @@
 		}
 	}
 
-	template<>

+	template<>
 	void LoadImageRow<D24>(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width)
 	{
 		const unsigned int *sourceD24 = reinterpret_cast<const unsigned int*>(source);
@@ -308,7 +308,7 @@
 		}
 	}
 
-	template<>

+	template<>
 	void LoadImageRow<D32>(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width)
 	{
 		const unsigned int *sourceD32 = reinterpret_cast<const unsigned int*>(source);
@@ -320,7 +320,7 @@
 		}
 	}
 
-	template<>

+	template<>
 	void LoadImageRow<S8>(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width)
 	{
 		const unsigned int *sourceI = reinterpret_cast<const unsigned int*>(source);
@@ -670,4 +670,44 @@
 
 		unlock();
 	}
-}
\ No newline at end of file
+
+	#if defined(__ANDROID__)
+	GLenum Image::getColorFormatFromAndroid(int format)
+	{
+		switch(format)
+		{
+		case HAL_PIXEL_FORMAT_RGBA_8888:
+		case HAL_PIXEL_FORMAT_RGBX_8888:
+			return GL_RGBA;
+		case HAL_PIXEL_FORMAT_RGB_888:
+			return GL_RGB;
+		case HAL_PIXEL_FORMAT_RGB_565:
+			return GL_RGB565_OES;
+		case HAL_PIXEL_FORMAT_BGRA_8888:
+			return GL_BGRA_EXT;
+		case HAL_PIXEL_FORMAT_sRGB_A_8888:
+		case HAL_PIXEL_FORMAT_sRGB_X_8888:
+		case HAL_PIXEL_FORMAT_YV12:
+		case HAL_PIXEL_FORMAT_Y8:
+		case HAL_PIXEL_FORMAT_Y16:
+		case HAL_PIXEL_FORMAT_RAW_SENSOR:
+		case HAL_PIXEL_FORMAT_BLOB:
+		case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED:
+		case HAL_PIXEL_FORMAT_YCbCr_420_888:
+		default:
+			UNIMPLEMENTED();
+		}
+		return GL_RGBA;
+	}
+
+	GLenum Image::getPixelFormatFromAndroid(int format)
+	{
+		if(format == HAL_PIXEL_FORMAT_Y16)
+		{
+			return GL_UNSIGNED_SHORT;
+		}
+
+		return GL_UNSIGNED_BYTE;
+	}
+	#endif
+}
diff --git a/src/OpenGL/libGLESv2/Image.hpp b/src/OpenGL/libGLESv2/Image.hpp
index 3824a8f..5cb9533 100644
--- a/src/OpenGL/libGLESv2/Image.hpp
+++ b/src/OpenGL/libGLESv2/Image.hpp
@@ -38,6 +38,11 @@
 
 		static sw::Format selectInternalFormat(GLenum format, GLenum type);
 
+		#if defined(__ANDROID__)
+		static GLenum getColorFormatFromAndroid(int format);
+		static GLenum getPixelFormatFromAndroid(int format);
+		#endif
+
 	private:
 		virtual ~Image();