eglCreatePbufferFromClientBuffer implementation

Added support for eglCreatePbufferFromClientBuffer(), using an
IOSurface on MacOS, or just a straight buffer pointer on other
platforms.

Added new unit tests (IOSurfaceClientBufferTest class), which
pass on both Windows and MacOS.

Change-Id: I79a6b420d85fb1f3ae505e0c0067bad2e27510d4
Reviewed-on: https://swiftshader-review.googlesource.com/17168
Tested-by: Alexis Hétu <sugoi@google.com>
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
diff --git a/src/OpenGL/libEGL/Surface.cpp b/src/OpenGL/libEGL/Surface.cpp
index d373990..ead75a6 100644
--- a/src/OpenGL/libEGL/Surface.cpp
+++ b/src/OpenGL/libEGL/Surface.cpp
@@ -63,6 +63,10 @@
 	swapBehavior = EGL_BUFFER_PRESERVED;
 	textureFormat = EGL_NO_TEXTURE;
 	textureTarget = EGL_NO_TEXTURE;
+	clientBufferFormat = EGL_NO_TEXTURE;
+	clientBufferType = EGL_NO_TEXTURE;
+	clientBuffer = nullptr;
+	clientBufferPlane = -1;
 	swapInterval = -1;
 	setSwapInterval(1);
 }
@@ -78,7 +82,15 @@
 
 	if(libGLESv2)
 	{
-		backBuffer = libGLESv2->createBackBuffer(width, height, config->mRenderTargetFormat, config->mSamples);
+		if(clientBuffer)
+		{
+			backBuffer = libGLESv2->createBackBufferFromClientBuffer(
+				egl::ClientBuffer(width, height, getClientBufferFormat(), clientBuffer, clientBufferPlane));
+		}
+		else
+		{
+			backBuffer = libGLESv2->createBackBuffer(width, height, config->mRenderTargetFormat, config->mSamples);
+		}
 	}
 	else if(libGLES_CM)
 	{
@@ -222,6 +234,51 @@
 	return largestPBuffer;
 }
 
+sw::Format Surface::getClientBufferFormat() const
+{
+	switch(clientBufferType)
+	{
+	case GL_UNSIGNED_BYTE:
+		switch(clientBufferFormat)
+		{
+		case GL_RED:
+			return sw::FORMAT_R8;
+		case GL_RG:
+			return sw::FORMAT_G8R8;
+		case GL_BGRA_EXT:
+			return sw::FORMAT_A8R8G8B8;
+		default:
+			UNREACHABLE(clientBufferFormat);
+			break;
+		}
+		break;
+	case GL_UNSIGNED_SHORT:
+		switch(clientBufferFormat)
+		{
+		case GL_R16UI:
+			return sw::FORMAT_R16UI;
+		default:
+			UNREACHABLE(clientBufferFormat);
+			break;
+		}
+		break;
+	case GL_HALF_FLOAT:
+		switch(clientBufferFormat)
+		{
+		case GL_RGBA:
+			return sw::FORMAT_A16B16G16R16F;
+		default:
+			UNREACHABLE(clientBufferFormat);
+			break;
+		}
+	default:
+		UNREACHABLE(clientBufferType);
+		break;
+	}
+
+	return sw::FORMAT_NULL;
+}
+
 void Surface::setBoundTexture(egl::Texture *texture)
 {
 	this->texture = texture;
@@ -356,12 +413,21 @@
 	return Surface::initialize();
 }
 
-PBufferSurface::PBufferSurface(Display *display, const Config *config, EGLint width, EGLint height, EGLenum textureFormat, EGLenum textureType, EGLBoolean largestPBuffer)
+PBufferSurface::PBufferSurface(Display *display, const Config *config, EGLint width, EGLint height,
+                               EGLenum textureFormat, EGLenum textureTarget, EGLenum clientBufferFormat,
+                               EGLenum clientBufferType, EGLBoolean largestPBuffer, EGLClientBuffer clientBuffer,
+                               EGLint clientBufferPlane)
 	: Surface(display, config)
 {
 	this->width = width;
 	this->height = height;
 	this->largestPBuffer = largestPBuffer;
+	this->textureFormat = textureFormat;
+	this->textureTarget = textureTarget;
+	this->clientBufferFormat = clientBufferFormat;
+	this->clientBufferType = clientBufferType;
+	this->clientBuffer = clientBuffer;
+	this->clientBufferPlane = clientBufferPlane;
 }
 
 PBufferSurface::~PBufferSurface()