Fixed synchronization issue on MacOS

Because of the way SwiftShader is integrated into Chromium on MacOS,
a synchronization issue exists when Chromium attempts to use an
IOSurface before SwiftShader is done rendering into it. In order to
solve this, all draw calls that end up rendering into an IOSurface
must be synchronized within SwiftShader and can't yield to Chromium
until rendering is complete.

Bug chromium:847094

Change-Id: If2dba4fa998e7437ec414d3b4aff9e8b19ecc128
Reviewed-on: https://swiftshader-review.googlesource.com/19188
Tested-by: Alexis Hétu <sugoi@google.com>
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
diff --git a/src/OpenGL/common/Image.cpp b/src/OpenGL/common/Image.cpp
index 601876e..447222c 100644
--- a/src/OpenGL/common/Image.cpp
+++ b/src/OpenGL/common/Image.cpp
@@ -1332,6 +1332,15 @@
 #endif
 	}
 
+	bool ClientBuffer::targetRequiresSync() const
+	{
+#if defined(__APPLE__)
+		return true;
+#else
+		return false;
+#endif
+	}
+
 	class ClientBufferImage : public egl::Image
 	{
 	public:
@@ -1422,6 +1431,11 @@
 			sw::Surface::unlockExternal();
 		}
 
+		bool targetRequiresSync() const override
+		{
+			return clientBuffer.targetRequiresSync();
+		}
+
 		void release() override
 		{
 			Image::release();
diff --git a/src/Renderer/Renderer.cpp b/src/Renderer/Renderer.cpp
index 7282e38..1334e70 100644
--- a/src/Renderer/Renderer.cpp
+++ b/src/Renderer/Renderer.cpp
@@ -224,6 +224,7 @@
 
 		int ss = context->getSuperSampleCount();
 		int ms = context->getMultiSampleCount();
+		bool targetRequiresSync = false;
 
 		for(int q = 0; q < ss; q++)
 		{
@@ -607,6 +608,7 @@
 					if(draw->renderTarget[index])
 					{
 						unsigned int layer = context->renderTargetLayer[index];
+						targetRequiresSync |= context->renderTarget[index]->targetRequiresSync();
 						data->colorBuffer[index] = (unsigned int*)context->renderTarget[index]->lockInternal(0, 0, layer, LOCK_READWRITE, MANAGED);
 						data->colorBuffer[index] += q * ms * context->renderTarget[index]->getSliceB(true);
 						data->colorPitchB[index] = context->renderTarget[index]->getInternalPitchB();
@@ -620,6 +622,7 @@
 				if(draw->depthBuffer)
 				{
 					unsigned int layer = context->depthBufferLayer;
+					targetRequiresSync |= context->depthBuffer->targetRequiresSync();
 					data->depthBuffer = (float*)context->depthBuffer->lockInternal(0, 0, layer, LOCK_READWRITE, MANAGED);
 					data->depthBuffer += q * ms * context->depthBuffer->getSliceB(true);
 					data->depthPitchB = context->depthBuffer->getInternalPitchB();
@@ -629,6 +632,7 @@
 				if(draw->stencilBuffer)
 				{
 					unsigned int layer = context->stencilBufferLayer;
+					targetRequiresSync |= context->stencilBuffer->targetRequiresSync();
 					data->stencilBuffer = (unsigned char*)context->stencilBuffer->lockStencil(0, 0, layer, MANAGED);
 					data->stencilBuffer += q * ms * context->stencilBuffer->getSliceB(true);
 					data->stencilPitchB = context->stencilBuffer->getStencilPitchB();
@@ -675,6 +679,12 @@
 				}
 			}
 		}
+
+		// TODO(sugoi): This is a temporary brute-force workaround to ensure IOSurface synchronization.
+		if(targetRequiresSync)
+		{
+			synchronize();
+		}
 	}
 
 	void Renderer::clear(void *value, Format format, Surface *dest, const Rect &clearRect, unsigned int rgbaMask)
diff --git a/src/Renderer/Surface.hpp b/src/Renderer/Surface.hpp
index eedffc2..2b1b906 100644
--- a/src/Renderer/Surface.hpp
+++ b/src/Renderer/Surface.hpp
@@ -321,6 +321,7 @@
 		inline int getStencilSliceB() const;
 
 		void sync();                      // Wait for lock(s) to be released.
+		virtual bool targetRequiresSync() const { return false; }
 		inline bool isUnlocked() const;   // Only reliable after sync().
 
 		inline int getSamples() const;