Adding multisampling to texture3D test

Required adding X and Y flipping to blitter.

Change-Id: Icaac4045ae9419296112464d7ccdde7babb76eb3
Reviewed-on: https://swiftshader-review.googlesource.com/2180
Reviewed-by: Alexis Hétu <sugoi@google.com>
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 14808e7..253264a 100644
--- a/src/OpenGL/libGLESv2/Context.cpp
+++ b/src/OpenGL/libGLESv2/Context.cpp
@@ -2877,38 +2877,54 @@
 

     sw::SliceRect sourceRect;

     sw::SliceRect destRect;

+	bool flipX = (srcX0 < srcX1) ^ (dstX0 < dstX1);

+	bool flipy = (srcY0 < srcY1) ^ (dstY0 < dstY1);

 

     if(srcX0 < srcX1)

     {

         sourceRect.x0 = srcX0;

         sourceRect.x1 = srcX1;

-        destRect.x0 = dstX0;

-        destRect.x1 = dstX1;

     }

     else

     {

         sourceRect.x0 = srcX1;

-        destRect.x0 = dstX1;

         sourceRect.x1 = srcX0;

-        destRect.x1 = dstX0;

     }

 

+	if(dstX0 < dstX1)

+	{

+		destRect.x0 = dstX0;

+		destRect.x1 = dstX1;

+	}

+	else

+	{

+		destRect.x0 = dstX1;

+		destRect.x1 = dstX0;

+	}

+	

     if(srcY0 < srcY1)

     {

         sourceRect.y0 = srcY0;

-        destRect.y0 = dstY0;

         sourceRect.y1 = srcY1;

-        destRect.y1 = dstY1;

     }

     else

     {

         sourceRect.y0 = srcY1;

-        destRect.y0 = dstY1;

         sourceRect.y1 = srcY0;

-        destRect.y1 = dstY0;

     }

 

-    sw::Rect sourceScissoredRect = sourceRect;

+	if(dstY0 < dstY1)

+	{

+		destRect.y0 = dstY0;

+		destRect.y1 = dstY1;

+	}

+	else

+	{

+		destRect.y0 = dstY1;

+		destRect.y1 = dstY0;

+	}

+

+	sw::Rect sourceScissoredRect = sourceRect;

     sw::Rect destScissoredRect = destRect;

 

     if(mState.scissorTest)   // Only write to parts of the destination framebuffer which pass the scissor test

@@ -3023,10 +3039,8 @@
                                    readFramebuffer->getColorbufferType() == GL_RENDERBUFFER;

         const bool validDrawType = drawFramebuffer->getColorbufferType() == GL_TEXTURE_2D ||

                                    drawFramebuffer->getColorbufferType() == GL_RENDERBUFFER;

-        if(!validReadType || !validDrawType ||

-           readFramebuffer->getColorbuffer()->getInternalFormat() != drawFramebuffer->getColorbuffer()->getInternalFormat())

+        if(!validReadType || !validDrawType)

         {

-            ERR("Color buffer format conversion in BlitFramebufferANGLE not supported by this implementation");

             return error(GL_INVALID_OPERATION);

         }

         

@@ -3050,8 +3064,7 @@
         {

             if(readFramebuffer->getDepthbuffer() && drawFramebuffer->getDepthbuffer())

             {

-                if(readFramebuffer->getDepthbufferType() != drawFramebuffer->getDepthbufferType() ||

-                   readFramebuffer->getDepthbuffer()->getInternalFormat() != drawFramebuffer->getDepthbuffer()->getInternalFormat())

+                if(readFramebuffer->getDepthbufferType() != drawFramebuffer->getDepthbufferType())

                 {

                     return error(GL_INVALID_OPERATION);

                 }

@@ -3066,8 +3079,7 @@
         {

             if(readFramebuffer->getStencilbuffer() && drawFramebuffer->getStencilbuffer())

             {

-                if(readFramebuffer->getStencilbufferType() != drawFramebuffer->getStencilbufferType() ||

-                   readFramebuffer->getStencilbuffer()->getInternalFormat() != drawFramebuffer->getStencilbuffer()->getInternalFormat())

+                if(readFramebuffer->getStencilbufferType() != drawFramebuffer->getStencilbufferType())

                 {

                     return error(GL_INVALID_OPERATION);

                 }

@@ -3098,6 +3110,15 @@
             egl::Image *readRenderTarget = readFramebuffer->getRenderTarget();

             egl::Image *drawRenderTarget = drawFramebuffer->getRenderTarget();

  

+			if(flipX)

+			{

+				swap(destRect.x0, destRect.x1);

+			}

+			if(flipy)

+			{

+				swap(destRect.y0, destRect.y1);

+			}

+

             bool success = device->stretchRect(readRenderTarget, &sourceRect, drawRenderTarget, &destRect, false);

 

             readRenderTarget->release();

@@ -3105,7 +3126,7 @@
 

             if(!success)

             {

-                ERR("BlitFramebufferANGLE failed.");

+                ERR("BlitFramebuffer failed.");

                 return;

             }

         }

@@ -3116,7 +3137,7 @@
 

             if(!success)

             {

-                ERR("BlitFramebufferANGLE failed.");

+                ERR("BlitFramebuffer failed.");

                 return;

             }

         }

diff --git a/src/OpenGL/libGLESv2/Device.cpp b/src/OpenGL/libGLESv2/Device.cpp
index edeb0d7..e9d8fbe 100644
--- a/src/OpenGL/libGLESv2/Device.cpp
+++ b/src/OpenGL/libGLESv2/Device.cpp
@@ -470,9 +470,58 @@
 		this->viewport = viewport;

 	}

 

+	void Device::copyBuffer(sw::byte *sourceBuffer, sw::byte *destBuffer, unsigned int width, unsigned int height, unsigned int sourcePitch, unsigned int destPitch, unsigned int bytes, bool flipX, bool flipY)

+	{

+		unsigned int widthB = width * bytes;

+		unsigned int widthMaxB = widthB - 1;

+

+		if(flipX)

+		{

+			if(flipY)

+			{

+				sourceBuffer += (height - 1) * sourcePitch;

+				for(unsigned int y = 0; y < height; ++y, sourceBuffer -= sourcePitch, destBuffer += destPitch)

+				{

+					for(unsigned int x = 0; x < widthB; ++x)

+					{

+						destBuffer[x] = sourceBuffer[widthMaxB - x];

+					}

+				}

+			}

+			else

+			{

+				for(unsigned int y = 0; y < height; ++y, sourceBuffer += sourcePitch, destBuffer += destPitch)

+				{

+					for(unsigned int x = 0; x < widthB; ++x)

+					{

+						destBuffer[x] = sourceBuffer[widthMaxB - x];

+					}

+				}

+			}

+		}

+		else

+		{

+			if(flipY)

+			{

+				sourceBuffer += (height - 1) * sourcePitch;

+				for(unsigned int y = 0; y < height; ++y, sourceBuffer -= sourcePitch, destBuffer += destPitch)

+				{

+					memcpy(destBuffer, sourceBuffer, widthB);

+				}

+			}

+			else

+			{

+				for(unsigned int y = 0; y < height; ++y, sourceBuffer += sourcePitch, destBuffer += destPitch)

+				{

+					memcpy(destBuffer, sourceBuffer, widthB);

+				}

+			}

+		}

+	}

+

 	bool Device::stretchRect(egl::Image *source, const sw::SliceRect *sourceRect, egl::Image *dest, const sw::SliceRect *destRect, bool filter)

 	{

-		if(!source || !dest || !validRectangle(sourceRect, source) || !validRectangle(destRect, dest))

+		if(!source || !dest)

 		{

 			ERR("Invalid parameters");

 			return false;

@@ -483,12 +532,40 @@
 		int dWidth = dest->getExternalWidth();

 		int dHeight = dest->getExternalHeight();

 

+		bool flipX = false;

+		bool flipY = false;

+		if(sourceRect && destRect)

+		{

+			flipX = (sourceRect->x0 < sourceRect->x1) ^ (destRect->x0 < destRect->x1);

+			flipY = (sourceRect->y0 < sourceRect->y1) ^ (destRect->y0 < destRect->y1);

+		}

+		else if(sourceRect)

+		{

+			flipX = (sourceRect->x0 > sourceRect->x1);

+			flipY = (sourceRect->y0 > sourceRect->y1);

+		}

+		else if(destRect)

+		{

+			flipX = (destRect->x0 > destRect->x1);

+			flipY = (destRect->y0 > destRect->y1);

+		}

+

 		SliceRect sRect;

 		SliceRect dRect;

 

 		if(sourceRect)

 		{

 			sRect = *sourceRect;

+

+			if(sRect.x0 > sRect.x1)

+			{

+				swap(sRect.x0, sRect.x1);

+			}

+

+			if(sRect.y0 > sRect.y1)

+			{

+				swap(sRect.y0, sRect.y1);

+			}

 		}

 		else

 		{

@@ -501,6 +578,16 @@
 		if(destRect)

 		{

 			dRect = *destRect;

+

+			if(dRect.x0 > dRect.x1)

+			{

+				swap(dRect.x0, dRect.x1);

+			}

+

+			if(dRect.y0 > dRect.y1)

+			{

+				swap(dRect.y0, dRect.y1);

+			}

 		}

 		else

 		{

@@ -510,6 +597,12 @@
 			dRect.x1 = dWidth;

 		}

 

+		if(!validRectangle(&sRect, source) || !validRectangle(&dRect, dest))

+		{

+			ERR("Invalid parameters");

+			return false;

+		}

+

 		bool scaling = (sRect.x1 - sRect.x0 != dRect.x1 - dRect.x0) || (sRect.y1 - sRect.y0 != dRect.y1 - dRect.y0);

 		bool equalFormats = source->getInternalFormat() == dest->getInternalFormat();

 		bool depthStencil = Image::isDepth(source->getInternalFormat()) || Image::isStencil(source->getInternalFormat());

@@ -529,17 +622,7 @@
 				sw::byte *sourceBuffer = (sw::byte*)source->lockInternal(0, 0, sourceRect->slice, LOCK_READONLY, PUBLIC);

 				sw::byte *destBuffer = (sw::byte*)dest->lockInternal(0, 0, destRect->slice, LOCK_DISCARD, PUBLIC);

 

-				unsigned int width = source->getInternalWidth();

-				unsigned int height = source->getInternalHeight();

-				unsigned int pitch = source->getInternalPitchB();

-

-				for(unsigned int y = 0; y < height; y++)

-				{

-					memcpy(destBuffer, sourceBuffer, pitch);   // FIXME: Only copy width * bytes

-

-					sourceBuffer += pitch;

-					destBuffer += pitch;

-				}

+				copyBuffer(sourceBuffer, destBuffer, source->getInternalWidth(), source->getInternalHeight(), source->getInternalPitchB(), dest->getInternalPitchB(), Image::bytes(source->getInternalFormat()), flipX, flipY);

 

 				source->unlockInternal();

 				dest->unlockInternal();

@@ -550,17 +633,7 @@
 				sw::byte *sourceBuffer = (sw::byte*)source->lockStencil(0, PUBLIC);

 				sw::byte *destBuffer = (sw::byte*)dest->lockStencil(0, PUBLIC);

 

-				unsigned int width = source->getInternalWidth();

-				unsigned int height = source->getInternalHeight();

-				unsigned int pitch = source->getStencilPitchB();

-

-				for(unsigned int y = 0; y < height; y++)

-				{

-					memcpy(destBuffer, sourceBuffer, pitch);   // FIXME: Only copy width * bytes

-

-					sourceBuffer += pitch;

-					destBuffer += pitch;

-				}

+				copyBuffer(sourceBuffer, destBuffer, source->getInternalWidth(), source->getInternalHeight(), source->getInternalPitchB(), dest->getInternalPitchB(), Image::bytes(source->getInternalFormat()), flipX, flipY);

 

 				source->unlockStencil();

 				dest->unlockStencil();

@@ -575,22 +648,18 @@
 

 			unsigned int width = dRect.x1 - dRect.x0;

 			unsigned int height = dRect.y1 - dRect.y0;

-			unsigned int bytes = width * Image::bytes(source->getInternalFormat());

 

-			for(unsigned int y = 0; y < height; y++)

+			copyBuffer(sourceBytes, destBytes, width, height, sourcePitch, destPitch, Image::bytes(source->getInternalFormat()), flipX, flipY);

+

+			if(alpha0xFF)

 			{

-				memcpy(destBytes, sourceBytes, bytes);

-

-				if(alpha0xFF)

+				for(unsigned int y = 0; y < height; ++y, destBytes += destPitch)

 				{

-					for(unsigned int x = 0; x < width; x++)

+					for(unsigned int x = 0; x < width; ++x)

 					{

 						destBytes[4 * x + 3] = 0xFF;

 					}

 				}

-				

-				sourceBytes += sourcePitch;

-				destBytes += destPitch;

 			}

 

 			source->unlockInternal();

@@ -598,6 +667,14 @@
 		}

 		else

 		{

+			if(flipX)

+			{

+				swap(dRect.x0, dRect.x1);

+			}

+			if(flipY)

+			{

+				swap(dRect.y0, dRect.y1);

+			}

 			blit(source, sRect, dest, dRect, scaling && filter);

 		}

 

diff --git a/src/OpenGL/libGLESv2/Device.hpp b/src/OpenGL/libGLESv2/Device.hpp
index 4dbe2e5..cbdb8bb 100644
--- a/src/OpenGL/libGLESv2/Device.hpp
+++ b/src/OpenGL/libGLESv2/Device.hpp
@@ -81,6 +81,8 @@
 

 		bool validRectangle(const sw::Rect *rect, egl::Image *surface);

 

+		void copyBuffer(sw::byte *sourceBuffer, sw::byte *destBuffer, unsigned int width, unsigned int height, unsigned int sourcePitch, unsigned int destPitch, unsigned int bytes, bool flipX, bool flipY);

+

 		Viewport viewport;

 		sw::Rect scissorRect;

 		bool scissorEnable;

diff --git a/src/OpenGL/libGLESv2/libGLESv2.cpp b/src/OpenGL/libGLESv2/libGLESv2.cpp
index 951a019..7e1526a 100644
--- a/src/OpenGL/libGLESv2/libGLESv2.cpp
+++ b/src/OpenGL/libGLESv2/libGLESv2.cpp
@@ -2974,6 +2974,7 @@
 			"GL_EXT_texture_filter_anisotropic "

 			"GL_EXT_texture_format_BGRA8888 "

 			"GL_ANGLE_framebuffer_blit "

+			"GL_NV_framebuffer_blit "

 			"GL_ANGLE_framebuffer_multisample "

 			#if (S3TC_SUPPORT)

 			"GL_ANGLE_texture_compression_dxt3 "

@@ -5129,8 +5130,7 @@
 	}

 }

 

-void GL_APIENTRY glBlitFramebufferANGLE(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,

-                                        GLbitfield mask, GLenum filter)

+void GL_APIENTRY glBlitFramebufferNV(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter)

 {

 	TRACE("(GLint srcX0 = %d, GLint srcY0 = %d, GLint srcX1 = %d, GLint srcY1 = %d, "

 	      "GLint dstX0 = %d, GLint dstY0 = %d, GLint dstX1 = %d, GLint dstY1 = %d, "

@@ -5150,12 +5150,6 @@
 		return error(GL_INVALID_VALUE);

 	}

 

-	if(srcX1 - srcX0 != dstX1 - dstX0 || srcY1 - srcY0 != dstY1 - dstY0)

-	{

-		ERR("Scaling and flipping in BlitFramebufferANGLE not supported by this implementation");

-		return error(GL_INVALID_OPERATION);

-	}

-

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

 

 	if(context)

@@ -5170,6 +5164,18 @@
 	}

 }

 

+void GL_APIENTRY glBlitFramebufferANGLE(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,

+	GLbitfield mask, GLenum filter)

+{

+	if(srcX1 - srcX0 != dstX1 - dstX0 || srcY1 - srcY0 != dstY1 - dstY0)

+	{

+		ERR("Scaling and flipping in BlitFramebufferANGLE not supported by this implementation");

+		return error(GL_INVALID_OPERATION);

+	}

+

+	glBlitFramebufferNV(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);

+}

+

 void GL_APIENTRY glTexImage3DOES(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth,

                                  GLint border, GLenum format, GLenum type, const GLvoid* pixels)

 {

@@ -5614,6 +5620,7 @@
 

 		EXTENSION(glTexImage3DOES),

 		EXTENSION(glBlitFramebufferANGLE),

+		EXTENSION(glBlitFramebufferNV),

 		EXTENSION(glRenderbufferStorageMultisampleANGLE),

 		EXTENSION(glDeleteFencesNV),

 		EXTENSION(glGenFencesNV),

diff --git a/src/OpenGL/libGLESv2/mathutil.h b/src/OpenGL/libGLESv2/mathutil.h
index 6ac1f37..8e62a06 100644
--- a/src/OpenGL/libGLESv2/mathutil.h
+++ b/src/OpenGL/libGLESv2/mathutil.h
@@ -51,6 +51,14 @@
     return x < min ? min : (x > max ? max : x);
 }
 
+template<class T>

+inline void swap(T &a, T &b)

+{

+	T t = a;

+	a = b;

+	b = t;

+}
+
 inline float clamp01(float x)
 {
     return clamp(x, 0.0f, 1.0f);
diff --git a/src/Renderer/Blitter.cpp b/src/Renderer/Blitter.cpp
index 3bf1f39..6b893fc 100644
--- a/src/Renderer/Blitter.cpp
+++ b/src/Renderer/Blitter.cpp
@@ -26,24 +26,42 @@
 		delete blitCache;
 	}
 
-	void Blitter::blit(Surface *source, const SliceRect &sRect, Surface *dest, const SliceRect &dRect, bool filter)
+	void Blitter::blit(Surface *source, const SliceRect &sourceRect, Surface *dest, const SliceRect &destRect, bool filter)
 	{
-		if(blitReactor(source, sRect, dest, dRect, filter))
+		if(blitReactor(source, sourceRect, dest, destRect, filter))
 		{
 			return;
 		}
 
+		SliceRect sRect = sourceRect;
+		SliceRect dRect = destRect;
+
+		bool flipX = destRect.x0 > destRect.x1;
+		bool flipY = destRect.y0 > destRect.y1;
+
+		if(flipX)

+		{

+			swap(dRect.x0, dRect.x1);

+			swap(sRect.x0, sRect.x1);

+		}

+		if(flipY)

+		{

+			swap(dRect.y0, dRect.y1);

+			swap(sRect.y0, sRect.y1);

+		}
+
 		source->lockInternal(sRect.x0, sRect.y0, sRect.slice, sw::LOCK_READONLY, sw::PUBLIC);
 		dest->lockInternal(dRect.x0, dRect.y0, dRect.slice, sw::LOCK_WRITEONLY, sw::PUBLIC);
 
 		float w = 1.0f / (dRect.x1 - dRect.x0) * (sRect.x1 - sRect.x0);
 		float h = 1.0f / (dRect.y1 - dRect.y0) * (sRect.y1 - sRect.y0);
 
+		const float xStart = (float)sRect.x0 + 0.5f * w;
 		float y = (float)sRect.y0 + 0.5f * h;
 
 		for(int j = dRect.y0; j < dRect.y1; j++)
 		{
-			float x = (float)sRect.x0 + 0.5f * w;
+			float x = xStart;
 
 			for(int i = dRect.x0; i < dRect.x1; i++)
 			{
@@ -115,8 +133,21 @@
 		return true;
 	}
 
-	bool Blitter::blitReactor(Surface *source, const SliceRect &sRect, Surface *dest, const SliceRect &dRect, bool filter)
+	bool Blitter::blitReactor(Surface *source, const SliceRect &sourceRect, Surface *dest, const SliceRect &destRect, bool filter)
 	{
+		Rect dRect = destRect;
+		Rect sRect = sourceRect;
+		if(destRect.x0 > destRect.x1)

+		{

+			swap(dRect.x0, dRect.x1);

+			swap(sRect.x0, sRect.x1);

+		}

+		if(destRect.y0 > destRect.y1)

+		{

+			swap(dRect.y0, dRect.y1);

+			swap(sRect.y0, sRect.y1);

+		}
+
 		BlitState state;
 
 		state.sourceFormat = source->getInternalFormat();
@@ -154,6 +185,7 @@
 				For(Int j = y0d, j < y1d, j++)
 				{
 					Float x = x0;
+					Pointer<Byte> destLine = dest + j * dPitchB;
 
 					For(Int i = x0d, i < x1d, i++)
 					{
@@ -262,7 +294,7 @@
 													  Surface::isUnsignedComponent(state.destFormat, 3) ? 0.0f : -1.0f));
 						}
 
-						Pointer<Byte> d = dest + j * dPitchB + i * Surface::bytes(state.destFormat);
+						Pointer<Byte> d = destLine + i * Surface::bytes(state.destFormat);
 
 						switch(state.destFormat)
 						{
@@ -321,8 +353,8 @@
 
 		BlitData data;
 
-		data.source = source->lockInternal(0, 0, sRect.slice, sw::LOCK_READONLY, sw::PUBLIC);
-		data.dest = dest->lockInternal(0, 0, dRect.slice, sw::LOCK_WRITEONLY, sw::PUBLIC);
+		data.source = source->lockInternal(0, 0, sourceRect.slice, sw::LOCK_READONLY, sw::PUBLIC);
+		data.dest = dest->lockInternal(0, 0, destRect.slice, sw::LOCK_WRITEONLY, sw::PUBLIC);
 		data.sPitchB = source->getInternalPitchB();
 		data.dPitchB = dest->getInternalPitchB();