Renderer side code to lock/unlock transform feedback data

Added variables and function calls to lock/unlock transform
feedback data used for reading the selected transform
feedback varying variables out of the vertex shader.

Also fixed uniform buffer unlocking potential race condition.

Change-Id: I98790fc36fdf8674506d924b2f21b3e68892811a
Reviewed-on: https://swiftshader-review.googlesource.com/5060
Tested-by: Alexis Hétu <sugoi@google.com>
Reviewed-by: Nicolas Capens <capn@google.com>
diff --git a/src/Renderer/PixelProcessor.cpp b/src/Renderer/PixelProcessor.cpp
index f736233..02d4c56 100644
--- a/src/Renderer/PixelProcessor.cpp
+++ b/src/Renderer/PixelProcessor.cpp
@@ -58,6 +58,12 @@
 		return memcmp(static_cast<const States*>(this), static_cast<const States*>(&state), sizeof(States)) == 0;
 	}
 
+	PixelProcessor::UniformBufferInfo::UniformBufferInfo()
+	{
+		buffer = nullptr;
+		offset = 0;
+	}
+
 	PixelProcessor::PixelProcessor(Context *context) : context(context)
 	{
 		setGlobalMipmapBias(0.0f);   // Round to highest LOD [0.5, 1.0]: -0.5
@@ -66,11 +72,6 @@
 
 		routineCache = 0;
 		setRoutineCacheSize(1024);
-
-		for(int i = 0; i < MAX_UNIFORM_BUFFER_BINDINGS; i++)
-		{
-			uniformBuffer[i] = nullptr;
-		}
 	}
 
 	PixelProcessor::~PixelProcessor()
@@ -143,27 +144,16 @@
 
 	void PixelProcessor::setUniformBuffer(int index, sw::Resource* buffer, int offset)
 	{
-		uniformBuffer[index] = buffer;
-		uniformBufferOffset[index] = offset;
+		uniformBufferInfo[index].buffer = buffer;
+		uniformBufferInfo[index].offset = offset;
 	}
 
-	void PixelProcessor::lockUniformBuffers(byte** u)
+	void PixelProcessor::lockUniformBuffers(byte** u, sw::Resource* uniformBuffers[])
 	{
 		for(int i = 0; i < MAX_UNIFORM_BUFFER_BINDINGS; ++i)
 		{
-			u[i] = uniformBuffer[i] ? static_cast<byte*>(uniformBuffer[i]->lock(PUBLIC, PRIVATE)) + uniformBufferOffset[i] : nullptr;
-		}
-	}
-
-	void PixelProcessor::unlockUniformBuffers()
-	{
-		for(int i = 0; i < MAX_UNIFORM_BUFFER_BINDINGS; ++i)
-		{
-			if(uniformBuffer[i])
-			{
-				uniformBuffer[i]->unlock();
-				uniformBuffer[i] = nullptr;
-			}
+			u[i] = uniformBufferInfo[i].buffer ? static_cast<byte*>(uniformBufferInfo[i].buffer->lock(PUBLIC, PRIVATE)) + uniformBufferInfo[i].offset : nullptr;
+			uniformBuffers[i] = uniformBufferInfo[i].buffer;
 		}
 	}
 
diff --git a/src/Renderer/PixelProcessor.hpp b/src/Renderer/PixelProcessor.hpp
index 2308d8f..571e860 100644
--- a/src/Renderer/PixelProcessor.hpp
+++ b/src/Renderer/PixelProcessor.hpp
@@ -192,8 +192,7 @@
 		virtual void setBooleanConstant(unsigned int index, int boolean);

 

 		virtual void setUniformBuffer(int index, sw::Resource* buffer, int offset);

-		virtual void lockUniformBuffers(byte** u);

-		virtual void unlockUniformBuffers();

+		virtual void lockUniformBuffers(byte** u, sw::Resource* uniformBuffers[]);

 

 		virtual void setRenderTarget(int index, Surface *renderTarget);

 		virtual void setDepthBuffer(Surface *depthBuffer);

@@ -304,8 +303,6 @@
 		float4 c[FRAGMENT_UNIFORM_VECTORS];

 		int4 i[16];

 		bool b[16];

-		Resource* uniformBuffer[MAX_UNIFORM_BUFFER_BINDINGS];

-		int uniformBufferOffset[MAX_UNIFORM_BUFFER_BINDINGS];

 

 		// Other semi-constants

 		Stencil stencil;

@@ -314,6 +311,15 @@
 		Factor factor;

 

 	private:

+		struct UniformBufferInfo

+		{

+			UniformBufferInfo();

+

+			Resource* buffer;

+			int offset;

+		};

+		UniformBufferInfo uniformBufferInfo[MAX_UNIFORM_BUFFER_BINDINGS];

+

 		void setFogRanges(float start, float end);

 

 		Context *const context;

diff --git a/src/Renderer/Renderer.cpp b/src/Renderer/Renderer.cpp
index a5e8760..71c50e9 100644
--- a/src/Renderer/Renderer.cpp
+++ b/src/Renderer/Renderer.cpp
@@ -388,7 +388,14 @@
 					draw->psDirtyConstB = 0;
 				}
 
-				PixelProcessor::lockUniformBuffers(data->ps.u);
+				PixelProcessor::lockUniformBuffers(data->ps.u, draw->pUniformBuffers);
+			}
+			else
+			{
+				for(int i = 0; i < MAX_UNIFORM_BUFFER_BINDINGS; i++)
+				{
+					draw->pUniformBuffers[i] = nullptr;
+				}
 			}
 			
 			if(context->pixelShaderVersion() <= 0x0104)
@@ -442,7 +449,8 @@
 					data->instanceID = context->instanceID;
 				}
 
-				VertexProcessor::lockUniformBuffers(data->vs.u);
+				VertexProcessor::lockUniformBuffers(data->vs.u, draw->vUniformBuffers);
+				VertexProcessor::lockTransformFeedbackBuffers(data->vs.t, data->vs.reg, data->vs.row, data->vs.col, data->vs.str, draw->transformFeedbackBuffers);
 			}
 			else
 			{
@@ -451,6 +459,16 @@
 				draw->vsDirtyConstF = VERTEX_UNIFORM_VECTORS + 1;
 				draw->vsDirtyConstI = 16;
 				draw->vsDirtyConstB = 16;
+
+				for(int i = 0; i < MAX_UNIFORM_BUFFER_BINDINGS; i++)
+				{
+					draw->vUniformBuffers[i] = nullptr;
+				}
+
+				for(int i = 0; i < MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS; i++)
+				{
+					draw->transformFeedbackBuffers[i] = nullptr;
+				}
 			}
 
 			if(pixelState.stencilActive)
@@ -981,8 +999,25 @@
 					draw.indexBuffer->unlock();
 				}
 
-				PixelProcessor::unlockUniformBuffers();
-				VertexProcessor::unlockUniformBuffers();
+				for(int i = 0; i < MAX_UNIFORM_BUFFER_BINDINGS; i++)
+				{
+					if(draw.pUniformBuffers[i])
+					{
+						draw.pUniformBuffers[i]->unlock();
+					}
+					if(draw.vUniformBuffers[i])
+					{
+						draw.vUniformBuffers[i]->unlock();
+					}
+				}
+
+				for(int i = 0; i < MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS; i++)
+				{
+					if(draw.transformFeedbackBuffers[i])
+					{
+						draw.transformFeedbackBuffers[i]->unlock();
+					}
+				}
 
 				draw.vertexRoutine->unbind();
 				draw.setupRoutine->unbind();
diff --git a/src/Renderer/Renderer.hpp b/src/Renderer/Renderer.hpp
index 3f0c931..e0b9141 100644
--- a/src/Renderer/Renderer.hpp
+++ b/src/Renderer/Renderer.hpp
@@ -123,6 +123,11 @@
 		{
 			float4 c[VERTEX_UNIFORM_VECTORS + 1];   // One extra for indices out of range, c[VERTEX_UNIFORM_VECTORS] = {0, 0, 0, 0}
 			byte* u[MAX_UNIFORM_BUFFER_BINDINGS];
+			byte* t[MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS];
+			unsigned int reg[MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS]; // Offset used when reading from registers, in components
+			unsigned int row[MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS]; // Number of rows to read
+			unsigned int col[MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS]; // Number of columns to read
+			unsigned int str[MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS]; // Number of components between each varying in output buffer
 			int4 i[16];
 			bool b[16];
 		};
@@ -222,6 +227,9 @@
 		Surface *depthBuffer;
 		Surface *stencilBuffer;
 		Resource *texture[TOTAL_IMAGE_UNITS];
+		Resource* pUniformBuffers[MAX_UNIFORM_BUFFER_BINDINGS];
+		Resource* vUniformBuffers[MAX_UNIFORM_BUFFER_BINDINGS];
+		Resource* transformFeedbackBuffers[MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS];
 
 		int vsDirtyConstF;
 		int vsDirtyConstI;
diff --git a/src/Renderer/VertexProcessor.cpp b/src/Renderer/VertexProcessor.cpp
index 01f6f14..24f40cc 100644
--- a/src/Renderer/VertexProcessor.cpp
+++ b/src/Renderer/VertexProcessor.cpp
@@ -63,11 +63,6 @@
 
 	VertexProcessor::TransformFeedbackInfo::TransformFeedbackInfo()
 	{
-		clear();
-	}
-
-	void VertexProcessor::TransformFeedbackInfo::clear()
-	{
 		buffer = nullptr;
 		offset = 0;
 		reg = 0;
@@ -76,6 +71,12 @@
 		stride = 0;
 	}
 
+	VertexProcessor::UniformBufferInfo::UniformBufferInfo()
+	{
+		buffer = nullptr;
+		offset = 0;
+	}
+
 	VertexProcessor::VertexProcessor(Context *context) : context(context)
 	{
 		for(int i = 0; i < 12; i++)
@@ -116,11 +117,6 @@
 
 		routineCache = 0;
 		setRoutineCacheSize(1024);
-
-		for(int i = 0; i < MAX_UNIFORM_BUFFER_BINDINGS; i++)
-		{
-			uniformBuffer[i] = nullptr;
-		}
 	}
 
 	VertexProcessor::~VertexProcessor()
@@ -179,27 +175,16 @@
 
 	void VertexProcessor::setUniformBuffer(int index, sw::Resource* buffer, int offset)
 	{
-		uniformBuffer[index] = buffer;
-		uniformBufferOffset[index] = offset;
+		uniformBufferInfo[index].buffer = buffer;
+		uniformBufferInfo[index].offset = offset;
 	}
 
-	void VertexProcessor::lockUniformBuffers(byte** u)
+	void VertexProcessor::lockUniformBuffers(byte** u, sw::Resource* uniformBuffers[])
 	{
 		for(int i = 0; i < MAX_UNIFORM_BUFFER_BINDINGS; ++i)
 		{
-			u[i] = uniformBuffer[i] ? static_cast<byte*>(uniformBuffer[i]->lock(PUBLIC, PRIVATE)) + uniformBufferOffset[i] : nullptr;
-		}
-	}
-
-	void VertexProcessor::unlockUniformBuffers()
-	{
-		for(int i = 0; i < MAX_UNIFORM_BUFFER_BINDINGS; ++i)
-		{
-			if(uniformBuffer[i])
-			{
-				uniformBuffer[i]->unlock();
-				uniformBuffer[i] = nullptr;
-			}
+			u[i] = uniformBufferInfo[i].buffer ? static_cast<byte*>(uniformBufferInfo[i].buffer->lock(PUBLIC, PRIVATE)) + uniformBufferInfo[i].offset : nullptr;
+			uniformBuffers[i] = uniformBufferInfo[i].buffer;
 		}
 	}
 
@@ -213,11 +198,12 @@
 		transformFeedbackInfo[index].stride = stride;
 	}
 
-	void VertexProcessor::lockTransformFeedbackBuffers(byte** t, unsigned int* v, unsigned int* r, unsigned int* c, unsigned int* s)
+	void VertexProcessor::lockTransformFeedbackBuffers(byte** t, unsigned int* v, unsigned int* r, unsigned int* c, unsigned int* s, sw::Resource* transformFeedbackBuffers[])
 	{
 		for(int i = 0; i < MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS; ++i)
 		{
 			t[i] = transformFeedbackInfo[i].buffer ? static_cast<byte*>(transformFeedbackInfo[i].buffer->lock(PUBLIC, PRIVATE)) + transformFeedbackInfo[i].offset : nullptr;
+			transformFeedbackBuffers[i] = transformFeedbackInfo[i].buffer;
 			v[i] = transformFeedbackInfo[i].reg;
 			r[i] = transformFeedbackInfo[i].row;
 			c[i] = transformFeedbackInfo[i].col;
@@ -225,18 +211,6 @@
 		}
 	}
 
-	void VertexProcessor::unlockTransformFeedbackBuffers()
-	{
-		for(int i = 0; i < MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS; ++i)
-		{
-			if(transformFeedbackInfo[i].buffer)
-			{
-				transformFeedbackInfo[i].buffer->unlock();
-			}
-			transformFeedbackInfo[i].clear();
-		}
-	}
-
 	void VertexProcessor::setModelMatrix(const Matrix &M, int i)
 	{
 		if(i < 12)
diff --git a/src/Renderer/VertexProcessor.hpp b/src/Renderer/VertexProcessor.hpp
index 9fb400a..1f1ccb7 100644
--- a/src/Renderer/VertexProcessor.hpp
+++ b/src/Renderer/VertexProcessor.hpp
@@ -188,12 +188,10 @@
 		virtual void setBooleanConstant(unsigned int index, int boolean);

 

 		virtual void setUniformBuffer(int index, sw::Resource* uniformBuffer, int offset);

-		virtual void lockUniformBuffers(byte** u);

-		virtual void unlockUniformBuffers();

+		virtual void lockUniformBuffers(byte** u, sw::Resource* uniformBuffers[]);

 

 		virtual void setTransformFeedbackBuffer(int index, sw::Resource* transformFeedbackBuffer, int offset, unsigned int reg, unsigned int row, unsigned int col, size_t stride);

-		virtual void lockTransformFeedbackBuffers(byte** t, unsigned int* v, unsigned int* r, unsigned int* c, unsigned int* s);

-		virtual void unlockTransformFeedbackBuffers();

+		virtual void lockTransformFeedbackBuffers(byte** t, unsigned int* v, unsigned int* r, unsigned int* c, unsigned int* s, sw::Resource* transformFeedbackBuffers[]);

 

 		// Transformations

 		virtual void setModelMatrix(const Matrix &M, int i = 0);

@@ -282,18 +280,23 @@
 		float4 c[VERTEX_UNIFORM_VECTORS + 1];   // One extra for indices out of range, c[VERTEX_UNIFORM_VECTORS] = {0, 0, 0, 0}

 		int4 i[16];

 		bool b[16];

-		Resource* uniformBuffer[MAX_UNIFORM_BUFFER_BINDINGS];

-		int uniformBufferOffset[MAX_UNIFORM_BUFFER_BINDINGS];

 

 		PointSprite point;

 		FixedFunction ff;

 

 	private:

-		void updateTransform();

+		struct UniformBufferInfo

+		{

+			UniformBufferInfo();

+

+			Resource* buffer;

+			int offset;

+		};

+		UniformBufferInfo uniformBufferInfo[MAX_UNIFORM_BUFFER_BINDINGS];

+

 		struct TransformFeedbackInfo

 		{

 			TransformFeedbackInfo();

-			void clear();

 

 			Resource* buffer;

 			int offset;

@@ -304,6 +307,7 @@
 		};

 		TransformFeedbackInfo transformFeedbackInfo[MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS];

 

+		void updateTransform();

 		void setTransform(const Matrix &M, int i);

 		void setCameraTransform(const Matrix &M, int i);

 		void setNormalTransform(const Matrix &M, int i);