New Buffers in OpenGL ES 3.0

Added new GLES 3.0 buffers:
- CopyReadBuffer
- CopyWriteBuffer
- PixelPackBuffer
- PixelUnpackBuffer
- UniformBuffer

Added related API function changes.
Note: I left TransformFeedback related buffer
changes out of this cl to avoid clashing with
other ongoing work and to keep this cl short.

Change-Id: Icb96f217e80a38f634c1735931dc37d53810d7f7
Reviewed-on: https://swiftshader-review.googlesource.com/2827
Tested-by: Alexis Hétu <sugoi@google.com>
Reviewed-by: Nicolas Capens <capn@google.com>
diff --git a/src/OpenGL/libGLESv2/Context.cpp b/src/OpenGL/libGLESv2/Context.cpp
index 923ee91..983914e 100644
--- a/src/OpenGL/libGLESv2/Context.cpp
+++ b/src/OpenGL/libGLESv2/Context.cpp
@@ -232,6 +232,11 @@
 

 	mState.arrayBuffer = NULL;

 	mState.elementArrayBuffer = NULL;

+	mState.copyReadBuffer = NULL;

+	mState.copyWriteBuffer = NULL;

+	mState.pixelPackBuffer = NULL;

+	mState.pixelUnpackBuffer = NULL;

+	mState.uniformBuffer = NULL;

 	mState.renderbuffer = NULL;

 

 	mState.vertexArray = NULL;

@@ -1059,6 +1064,41 @@
     mState.elementArrayBuffer = getBuffer(buffer);

 }

 

+void Context::bindCopyReadBuffer(GLuint buffer)

+{

+	mResourceManager->checkBufferAllocation(buffer);

+

+	mState.copyReadBuffer = getBuffer(buffer);

+}

+

+void Context::bindCopyWriteBuffer(GLuint buffer)

+{

+	mResourceManager->checkBufferAllocation(buffer);

+

+	mState.copyWriteBuffer = getBuffer(buffer);

+}

+

+void Context::bindPixelPackBuffer(GLuint buffer)

+{

+	mResourceManager->checkBufferAllocation(buffer);

+

+	mState.pixelPackBuffer = getBuffer(buffer);

+}

+

+void Context::bindPixelUnpackBuffer(GLuint buffer)

+{

+	mResourceManager->checkBufferAllocation(buffer);

+

+	mState.pixelUnpackBuffer = getBuffer(buffer);

+}

+

+void Context::bindUniformBuffer(GLuint buffer)

+{

+	mResourceManager->checkBufferAllocation(buffer);

+

+	mState.uniformBuffer = getBuffer(buffer);

+}

+

 void Context::bindTexture2D(GLuint texture)

 {

     mResourceManager->checkTextureAllocation(texture, TEXTURE_2D);

@@ -1348,6 +1388,89 @@
     return mState.elementArrayBuffer;

 }

 

+Buffer *Context::getCopyReadBuffer()

+{

+	return mState.copyReadBuffer;

+}

+

+Buffer *Context::getCopyWriteBuffer()

+{

+	return mState.copyWriteBuffer;

+}

+

+Buffer *Context::getPixelPackBuffer()

+{

+	return mState.pixelPackBuffer;

+}

+

+Buffer *Context::getPixelUnpackBuffer()

+{

+	return mState.pixelUnpackBuffer;

+}

+

+Buffer *Context::getUniformBuffer()

+{

+	return mState.uniformBuffer;

+}

+

+bool Context::getBuffer(GLenum target, es2::Buffer **buffer)

+{

+	switch(target)

+	{

+	case GL_ARRAY_BUFFER:

+		*buffer = getArrayBuffer();

+		break;

+	case GL_ELEMENT_ARRAY_BUFFER:

+		*buffer = getElementArrayBuffer();

+		break;

+	case GL_COPY_READ_BUFFER:

+		if(clientVersion >= 3)

+		{

+			*buffer = getCopyReadBuffer();

+			break;

+		}

+		else return false;

+	case GL_COPY_WRITE_BUFFER:

+		if(clientVersion >= 3)

+		{

+			*buffer = getCopyWriteBuffer();

+			break;

+		}

+		else return false;

+	case GL_PIXEL_PACK_BUFFER:

+		if(clientVersion >= 3)

+		{

+			*buffer = getPixelPackBuffer();

+			break;

+		}

+		else return false;

+	case GL_PIXEL_UNPACK_BUFFER:

+		if(clientVersion >= 3)

+		{

+			*buffer = getPixelUnpackBuffer();

+			break;

+		}

+		else return false;

+	case GL_TRANSFORM_FEEDBACK_BUFFER:

+		if(clientVersion >= 3)

+		{

+			UNIMPLEMENTED();

+			return false;

+		}

+		else return false;

+	case GL_UNIFORM_BUFFER:

+		if(clientVersion >= 3)

+		{

+			*buffer = getUniformBuffer();

+			break;

+		}

+		else return false;

+	default:

+		return false;

+	}

+	return true;

+}

+

 TransformFeedback *Context::getTransformFeedback()

 {

 	return getTransformFeedback(mState.transformFeedback);

@@ -1725,12 +1848,24 @@
 		}

 		break;

 	case GL_COPY_READ_BUFFER_BINDING: // name, initially 0

-		UNIMPLEMENTED();

-		*params = 0;

+		if(clientVersion >= 3)

+		{

+			*params = mState.copyReadBuffer.name();

+		}

+		else

+		{

+			return false;

+		}

 		break;

 	case GL_COPY_WRITE_BUFFER_BINDING: // name, initially 0

-		UNIMPLEMENTED();

-		*params = 0;

+		if(clientVersion >= 3)

+		{

+			*params = mState.copyWriteBuffer.name();

+		}

+		else

+		{

+			return false;

+		}

 		break;

 	case GL_DRAW_BUFFER0: // symbolic constant, initial value is GL_BACK​

 		UNIMPLEMENTED();

@@ -1888,12 +2023,24 @@
 		*params = 0;

 		break;

 	case GL_PIXEL_PACK_BUFFER_BINDING: // integer, initially 0

-		UNIMPLEMENTED();

-		*params = 0;

+		if(clientVersion >= 3)

+		{

+			*params = mState.pixelPackBuffer.name();

+		}

+		else

+		{

+			return false;

+		}

 		break;

 	case GL_PIXEL_UNPACK_BUFFER_BINDING: // integer, initially 0

-		UNIMPLEMENTED();

-		*params = 0;

+		if(clientVersion >= 3)

+		{

+			*params = mState.pixelUnpackBuffer.name();

+		}

+		else

+		{

+			return false;

+		}

 		break;

 	case GL_PROGRAM_BINARY_FORMATS: // integer[GL_NUM_PROGRAM_BINARY_FORMATS​]

 		UNIMPLEMENTED();

@@ -1908,8 +2055,14 @@
 		*params = 0;

 		break;

 	case GL_UNIFORM_BUFFER_BINDING: // name, initially 0

-		UNIMPLEMENTED();

-		*params = 0;

+		if(clientVersion >= 3)

+		{

+			*params = mState.uniformBuffer.name();

+		}

+		else

+		{

+			return false;

+		}

 		break;

 	case GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT: // integer, defaults to 1

 		UNIMPLEMENTED();

diff --git a/src/OpenGL/libGLESv2/Context.h b/src/OpenGL/libGLESv2/Context.h
index 56031f6..4da5a75 100644
--- a/src/OpenGL/libGLESv2/Context.h
+++ b/src/OpenGL/libGLESv2/Context.h
@@ -325,6 +325,12 @@
     unsigned int activeSampler;   // Active texture unit selector - GL_TEXTURE0

     gl::BindingPointer<Buffer> arrayBuffer;

     gl::BindingPointer<Buffer> elementArrayBuffer;

+	gl::BindingPointer<Buffer> copyReadBuffer;

+	gl::BindingPointer<Buffer> copyWriteBuffer;

+	gl::BindingPointer<Buffer> pixelPackBuffer;

+	gl::BindingPointer<Buffer> pixelUnpackBuffer;

+	gl::BindingPointer<Buffer> uniformBuffer;

+

     GLuint readFramebuffer;

     GLuint drawFramebuffer;

     gl::BindingPointer<Renderbuffer> renderbuffer;

@@ -479,6 +485,11 @@
 

     void bindArrayBuffer(GLuint buffer);

     void bindElementArrayBuffer(GLuint buffer);

+	void bindCopyReadBuffer(GLuint buffer);

+	void bindCopyWriteBuffer(GLuint buffer);

+	void bindPixelPackBuffer(GLuint buffer);

+	void bindPixelUnpackBuffer(GLuint buffer);

+	void bindUniformBuffer(GLuint buffer);

     void bindTexture2D(GLuint texture);

     void bindTextureCubeMap(GLuint texture);

     void bindTextureExternal(GLuint texture);

@@ -517,6 +528,12 @@
 

     Buffer *getArrayBuffer();

     Buffer *getElementArrayBuffer();

+	Buffer *getCopyReadBuffer();

+	Buffer *getCopyWriteBuffer();

+	Buffer *getPixelPackBuffer();

+	Buffer *getPixelUnpackBuffer();

+	Buffer *getUniformBuffer();

+	bool getBuffer(GLenum target, es2::Buffer **buffer);

     Program *getCurrentProgram();

     Texture2D *getTexture2D();

 	Texture3D *getTexture3D();

diff --git a/src/OpenGL/libGLESv2/libGLESv2.cpp b/src/OpenGL/libGLESv2/libGLESv2.cpp
index 4b025ef..13f6f6d 100644
--- a/src/OpenGL/libGLESv2/libGLESv2.cpp
+++ b/src/OpenGL/libGLESv2/libGLESv2.cpp
@@ -418,6 +418,8 @@
 

 	if(context)

 	{

+		egl::GLint clientVersion = egl::getClientVersion();

+

 		switch(target)

 		{

 		case GL_ARRAY_BUFFER:

@@ -426,6 +428,48 @@
 		case GL_ELEMENT_ARRAY_BUFFER:

 			context->bindElementArrayBuffer(buffer);

 			return;

+		case GL_COPY_READ_BUFFER:

+			if(clientVersion >= 3)

+			{

+				context->bindCopyReadBuffer(buffer);

+				return;

+			}

+			else return error(GL_INVALID_ENUM);

+		case GL_COPY_WRITE_BUFFER:

+			if(clientVersion >= 3)

+			{

+				context->bindCopyWriteBuffer(buffer);

+				return;

+			}

+			else return error(GL_INVALID_ENUM);

+		case GL_PIXEL_PACK_BUFFER:

+			if(clientVersion >= 3)

+			{

+				context->bindPixelPackBuffer(buffer);

+				return;

+			}

+			else return error(GL_INVALID_ENUM);

+		case GL_PIXEL_UNPACK_BUFFER:

+			if(clientVersion >= 3)

+			{

+				context->bindPixelUnpackBuffer(buffer);

+				return;

+			}

+			else return error(GL_INVALID_ENUM);

+		case GL_TRANSFORM_FEEDBACK_BUFFER:

+			if(clientVersion >= 3)

+			{

+				UNIMPLEMENTED();

+				return;

+			}

+			else return error(GL_INVALID_ENUM);

+		case GL_UNIFORM_BUFFER:

+			if(clientVersion >= 3)

+			{

+				context->bindUniformBuffer(buffer);

+				return;

+			}

+			else return error(GL_INVALID_ENUM);

 		default:

 			return error(GL_INVALID_ENUM);

 		}

@@ -729,16 +773,8 @@
 	if(context)

 	{

 		es2::Buffer *buffer;

-

-		switch(target)

+		if(!context->getBuffer(target, &buffer))

 		{

-		case GL_ARRAY_BUFFER:

-			buffer = context->getArrayBuffer();

-			break;

-		case GL_ELEMENT_ARRAY_BUFFER:

-			buffer = context->getElementArrayBuffer();

-			break;

-		default:

 			return error(GL_INVALID_ENUM);

 		}

 

@@ -775,16 +811,8 @@
 	if(context)

 	{

 		es2::Buffer *buffer;

-

-		switch(target)

+		if(!context->getBuffer(target, &buffer))

 		{

-		case GL_ARRAY_BUFFER:

-			buffer = context->getArrayBuffer();

-			break;

-		case GL_ELEMENT_ARRAY_BUFFER:

-			buffer = context->getElementArrayBuffer();

-			break;

-		default:

 			return error(GL_INVALID_ENUM);

 		}

 

@@ -2445,16 +2473,8 @@
 	if(context)

 	{

 		es2::Buffer *buffer;

-

-		switch(target)

+		if(!context->getBuffer(target, &buffer))

 		{

-		case GL_ARRAY_BUFFER:

-			buffer = context->getArrayBuffer();

-			break;

-		case GL_ELEMENT_ARRAY_BUFFER:

-			buffer = context->getElementArrayBuffer();

-			break;

-		default:

 			return error(GL_INVALID_ENUM);

 		}

 

diff --git a/src/OpenGL/libGLESv2/libGLESv3.cpp b/src/OpenGL/libGLESv2/libGLESv3.cpp
index 405645f..469bbe4 100644
--- a/src/OpenGL/libGLESv2/libGLESv3.cpp
+++ b/src/OpenGL/libGLESv2/libGLESv3.cpp
@@ -991,8 +991,26 @@
 {

 	TRACE("(GLenum target = 0x%X)", target);

 

-	UNIMPLEMENTED();

-	return GL_FALSE;

+	es2::Context *context = es2::getContext();

+

+	if(context)

+	{

+		es2::Buffer *buffer = nullptr;

+		if(!context->getBuffer(target, &buffer))

+		{

+			return error(GL_INVALID_ENUM, GL_TRUE);

+		}

+

+		if(!buffer)

+		{

+			// A null buffer means that "0" is bound to the requested buffer target

+			return error(GL_INVALID_OPERATION, GL_TRUE);

+		}

+

+		return buffer->unmap() ? GL_TRUE : GL_FALSE;

+	}

+

+	return GL_TRUE;

 }

 

 void GL_APIENTRY glGetBufferPointerv(GLenum target, GLenum pname, void **params)

@@ -1000,17 +1018,29 @@
 	TRACE("(GLenum target = 0x%X, GLenum pname = 0x%X, GLint *params = 0x%0.8p)",

 	      target, pname, params);

 

-	if(!ValidateBufferTarget(target))

-	{

-		return error(GL_INVALID_ENUM);

-	}

-

 	if(pname != GL_BUFFER_MAP_POINTER)

 	{

 		return error(GL_INVALID_ENUM);

 	}

 

-	UNIMPLEMENTED();

+	es2::Context *context = es2::getContext();

+

+	if(context)

+	{

+		es2::Buffer *buffer = nullptr;

+		if(!context->getBuffer(target, &buffer))

+		{

+			return error(GL_INVALID_ENUM);

+		}

+

+		if(!buffer)

+		{

+			// A null buffer means that "0" is bound to the requested buffer target

+			return error(GL_INVALID_OPERATION);

+		}

+

+		*params = buffer->isMapped() ? (void*)(((const char*)buffer->data()) + buffer->offset()) : nullptr;

+	}

 }

 

 void GL_APIENTRY glDrawBuffers(GLsizei n, const GLenum *bufs)

@@ -1397,12 +1427,27 @@
 	TRACE("(GLenum target = 0x%X,  GLintptr offset = %d, GLsizeiptr length = %d, GLbitfield access = %X)",

 	      target, offset, length, access);

 

-	GLint bufferSize;

-	glGetBufferParameteriv(target, GL_BUFFER_SIZE, &bufferSize);

-	if((offset < 0) || (length<0) || ((offset + length) > bufferSize))

+	es2::Context *context = es2::getContext();

+

+	if(context)

 	{

-		error(GL_INVALID_VALUE);

-	}

+		es2::Buffer *buffer = nullptr;

+		if(!context->getBuffer(target, &buffer))

+		{

+			return error(GL_INVALID_ENUM, nullptr);

+		}

+

+		if(!buffer)

+		{

+			// A null buffer means that "0" is bound to the requested buffer target

+			return error(GL_INVALID_OPERATION, nullptr);

+		}

+

+		GLint bufferSize = buffer->size();

+		if((offset < 0) || (length < 0) || ((offset + length) > bufferSize))

+		{

+			error(GL_INVALID_VALUE);

+		}

 

 		if((access & ~(GL_MAP_READ_BIT |

 		               GL_MAP_WRITE_BIT |

@@ -1414,7 +1459,9 @@
 			error(GL_INVALID_VALUE);

 		}

 

-	UNIMPLEMENTED();

+		return buffer->mapRange(offset, length, access);

+	}

+

 	return nullptr;

 }

 

@@ -1423,17 +1470,30 @@
 	TRACE("(GLenum target = 0x%X,  GLintptr offset = %d, GLsizeiptr length = %d)",

 	      target, offset, length);

 

-	if(!ValidateBufferTarget(target))

-	{

-		return error(GL_INVALID_ENUM);

-	}

+	es2::Context *context = es2::getContext();

 

-	if((offset < 0) || (length<0)) // FIXME: also check if offset + length exceeds the size of the mapping

+	if(context)

 	{

-		error(GL_INVALID_VALUE);

-	}

+		es2::Buffer *buffer = nullptr;

+		if(!context->getBuffer(target, &buffer))

+		{

+			return error(GL_INVALID_ENUM);

+		}

 

-	UNIMPLEMENTED();

+		if(!buffer)

+		{

+			// A null buffer means that "0" is bound to the requested buffer target

+			return error(GL_INVALID_OPERATION);

+		}

+

+		GLint bufferSize = buffer->size();

+		if((offset < 0) || (length < 0) || ((offset + length) > bufferSize))

+		{

+			error(GL_INVALID_VALUE);

+		}

+

+		buffer->flushMappedRange(offset, length);

+	}

 }

 

 void GL_APIENTRY glBindVertexArray(GLuint array)

@@ -2368,42 +2428,37 @@
 	TRACE("(GLenum readTarget = 0x%X, GLenum writeTarget = 0x%X,  GLintptr readOffset = %d, GLintptr writeOffset = %d, GLsizeiptr size = %d)",

 	      readTarget, writeTarget, readOffset, writeOffset, size);

 

-	switch(readTarget)

-	{

-	case GL_ARRAY_BUFFER:

-	case GL_COPY_READ_BUFFER:

-	case GL_COPY_WRITE_BUFFER:

-	case GL_ELEMENT_ARRAY_BUFFER:

-	case GL_PIXEL_PACK_BUFFER:

-	case GL_PIXEL_UNPACK_BUFFER:

-	case GL_TRANSFORM_FEEDBACK_BUFFER:

-	case GL_UNIFORM_BUFFER:

-		break;

-	default:

-		return error(GL_INVALID_ENUM);

-	}

-

-	switch(writeTarget)

-	{

-	case GL_ARRAY_BUFFER:

-	case GL_COPY_READ_BUFFER:

-	case GL_COPY_WRITE_BUFFER:

-	case GL_ELEMENT_ARRAY_BUFFER:

-	case GL_PIXEL_PACK_BUFFER:

-	case GL_PIXEL_UNPACK_BUFFER:

-	case GL_TRANSFORM_FEEDBACK_BUFFER:

-	case GL_UNIFORM_BUFFER:

-		break;

-	default:

-		return error(GL_INVALID_ENUM);

-	}

-

 	if(readOffset < 0 || writeOffset < 0 || size < 0)

 	{

 		return error(GL_INVALID_VALUE);

 	}

 

-	UNIMPLEMENTED();

+	es2::Context *context = es2::getContext();

+

+	if(context)

+	{

+		es2::Buffer *readBuffer = nullptr;

+		if(!context->getBuffer(readTarget, &readBuffer))

+		{

+			return error(GL_INVALID_ENUM);

+		}

+		if((readOffset + size) > readBuffer->size())

+		{

+			return error(GL_INVALID_VALUE);

+		}

+

+		es2::Buffer *writeBuffer = nullptr;

+		if(!context->getBuffer(writeTarget, &writeBuffer))

+		{

+			return error(GL_INVALID_ENUM);

+		}

+		if((writeOffset + size) > writeBuffer->size())

+		{

+			return error(GL_INVALID_VALUE);

+		}

+

+		writeBuffer->bufferSubData(((char*)readBuffer->data()) + readOffset, size, writeOffset);

+	}

 }

 

 void GL_APIENTRY glGetUniformIndices(GLuint program, GLsizei uniformCount, const GLchar *const*uniformNames, GLuint *uniformIndices)

@@ -2731,7 +2786,73 @@
 void GL_APIENTRY glGetBufferParameteri64v(GLenum target, GLenum pname, GLint64 *params)

 {

 	TRACE("(GLenum target = 0x%X, GLenum pname = 0x%X, GLint64 *params = 0x%0.8p)", target, pname, params);

-	UNIMPLEMENTED();

+

+	es2::Context *context = es2::getContext();

+

+	if(context)

+	{

+		es2::Buffer *buffer = nullptr;

+

+		switch(target)

+		{

+		case GL_ARRAY_BUFFER:

+			buffer = context->getArrayBuffer();

+			break;

+		case GL_ELEMENT_ARRAY_BUFFER:

+			buffer = context->getElementArrayBuffer();

+			break;

+		case GL_COPY_READ_BUFFER:

+			buffer = context->getCopyReadBuffer();

+			break;

+		case GL_COPY_WRITE_BUFFER:

+			buffer = context->getCopyWriteBuffer();

+			break;

+		case GL_PIXEL_PACK_BUFFER:

+			buffer = context->getPixelPackBuffer();

+			break;

+		case GL_PIXEL_UNPACK_BUFFER:

+			buffer = context->getPixelUnpackBuffer();

+			break;

+		case GL_TRANSFORM_FEEDBACK_BUFFER:

+			UNIMPLEMENTED();

+			break;

+		case GL_UNIFORM_BUFFER:

+			buffer = context->getUniformBuffer();

+			break;

+		default:

+			return error(GL_INVALID_ENUM);

+		}

+

+		if(!buffer)

+		{

+			// A null buffer means that "0" is bound to the requested buffer target

+			return error(GL_INVALID_OPERATION);

+		}

+

+		switch(pname)

+		{

+		case GL_BUFFER_USAGE:

+			*params = buffer->usage();

+			break;

+		case GL_BUFFER_SIZE:

+			*params = buffer->size();

+			break;

+		case GL_BUFFER_ACCESS_FLAGS:

+			*params = buffer->access();

+			break;

+		case GL_BUFFER_MAPPED:

+			*params = buffer->isMapped();

+			break;

+		case GL_BUFFER_MAP_LENGTH:

+			*params = buffer->length();

+			break;

+		case GL_BUFFER_MAP_OFFSET:

+			*params = buffer->offset();

+			break;

+		default:

+			return error(GL_INVALID_ENUM);

+		}

+	}

 }

 

 void GL_APIENTRY glGenSamplers(GLsizei count, GLuint *samplers)