Improve color clear precision.

Change-Id: Ib9dadf3d8fee0f63deb10e6754856c0530c928ab
Reviewed-on: https://swiftshader-review.googlesource.com/3995
Reviewed-by: Alexis Hétu <sugoi@google.com>
Reviewed-by: Nicolas Capens <capn@google.com>
Tested-by: Nicolas Capens <capn@google.com>
diff --git a/src/D3D9/Direct3DDevice9.cpp b/src/D3D9/Direct3DDevice9.cpp
index 30d8ea3..ffb7021 100644
--- a/src/D3D9/Direct3DDevice9.cpp
+++ b/src/D3D9/Direct3DDevice9.cpp
@@ -435,24 +435,19 @@
 						D3DSURFACE_DESC description;
 						renderTarget[index]->GetDesc(&description);
 
+						float r = (float)(color & 0x00FF0000) / 0x00FF0000;
+						float g = (float)(color & 0x0000FF00) / 0x0000FF00;
+						float b = (float)(color & 0x000000FF) / 0x000000FF;
+						float a = (float)(color & 0xFF000000) / 0xFF000000;
+
 						if(renderState[D3DRS_SRGBWRITEENABLE] != FALSE && index == 0 && Capabilities::isSRGBwritable(description.Format))
 						{
-							float r = (float)(color & 0x00FF0000) / 0x00FF0000;
-							float g = (float)(color & 0x0000FF00) / 0x0000FF00;
-							float b = (float)(color & 0x000000FF) / 0x000000FF;
-							float a = (float)(color & 0xFF000000) / 0xFF000000;
-
 							r = sw::linearToSRGB(r);
 							g = sw::linearToSRGB(g);
 							b = sw::linearToSRGB(b);
-
-							color = ((int)(a * 255) << 24) |
-									((int)(r * 255) << 16) |
-									((int)(g * 255) << 8) |
-									((int)(b * 255) << 0);
 						}
 
-						renderTarget[index]->clearColorBuffer(color, 0xF, rect.x1, rect.y1, rect.x2 - rect.x1, rect.y2 - rect.y1);
+						renderTarget[index]->clearColorBuffer(r, g, b, a, 0xF, rect.x1, rect.y1, rect.x2 - rect.x1, rect.y2 - rect.y1);
 					}
 				}
 			}
diff --git a/src/OpenGL/libGL/Context.cpp b/src/OpenGL/libGL/Context.cpp
index 5ca3b5e..0c718a4 100644
--- a/src/OpenGL/libGL/Context.cpp
+++ b/src/OpenGL/libGL/Context.cpp
@@ -2454,11 +2454,7 @@
     {

         return;

     }

-	

-	unsigned int color = (unorm<8>(mState.colorClearValue.alpha) << 24) |

-                         (unorm<8>(mState.colorClearValue.red) << 16) |

-                         (unorm<8>(mState.colorClearValue.green) << 8) | 

-                         (unorm<8>(mState.colorClearValue.blue) << 0);

+

     float depth = clamp01(mState.depthClearValue);

     int stencil = mState.stencilClearValue & 0x000000FF;

 

@@ -2471,7 +2467,7 @@
 

 		if(rgbaMask != 0)

 		{

-			device->clearColor(color, rgbaMask);

+			device->clearColor(mState.colorClearValue.red, mState.colorClearValue.green, mState.colorClearValue.blue, mState.colorClearValue.alpha, rgbaMask);

 		}

 	}

 

diff --git a/src/OpenGL/libGL/Device.cpp b/src/OpenGL/libGL/Device.cpp
index f9250bd..c4b1318 100644
--- a/src/OpenGL/libGL/Device.cpp
+++ b/src/OpenGL/libGL/Device.cpp
@@ -178,7 +178,7 @@
 		delete context;

 	}

 

-	void Device::clearColor(unsigned int color, unsigned int rgbaMask)

+	void Device::clearColor(float red, float green, float blue, float alpha, unsigned int rgbaMask)

 	{

 		if(!renderTarget)

 		{

@@ -198,7 +198,7 @@
 			if(height > scissorRect.y1 - scissorRect.y0) height = scissorRect.y1 - scissorRect.y0;

 		}

 

-		renderTarget->clearColorBuffer(color, rgbaMask, x0, y0, width, height);

+		renderTarget->clearColorBuffer(red, green, blue, alpha, rgbaMask, x0, y0, width, height);

 	}

 

 	void Device::clearDepth(float z)

diff --git a/src/OpenGL/libGL/Device.hpp b/src/OpenGL/libGL/Device.hpp
index dec8dfb..a3e2274 100644
--- a/src/OpenGL/libGL/Device.hpp
+++ b/src/OpenGL/libGL/Device.hpp
@@ -48,7 +48,7 @@
 

 		virtual ~Device();

 

-		virtual void clearColor(unsigned int color, unsigned int rgbaMask);

+		virtual void clearColor(float red, float green, float blue, float alpha, unsigned int rgbaMask);

 		virtual void clearDepth(float z);

 		virtual void clearStencil(unsigned int stencil, unsigned int mask);

 		virtual Image *createDepthStencilSurface(unsigned int width, unsigned int height, sw::Format format, int multiSampleDepth, bool discard);

diff --git a/src/OpenGL/libGLES_CM/Context.cpp b/src/OpenGL/libGLES_CM/Context.cpp
index e54ee16..435b716 100644
--- a/src/OpenGL/libGLES_CM/Context.cpp
+++ b/src/OpenGL/libGLES_CM/Context.cpp
@@ -2659,10 +2659,6 @@
         return;

     }

 

-	unsigned int color = (unorm<8>(mState.colorClearValue.alpha) << 24) |

-                         (unorm<8>(mState.colorClearValue.red) << 16) |

-                         (unorm<8>(mState.colorClearValue.green) << 8) |

-                         (unorm<8>(mState.colorClearValue.blue) << 0);

     float depth = clamp01(mState.depthClearValue);

     int stencil = mState.stencilClearValue & 0x000000FF;

 

@@ -2675,7 +2671,7 @@
 

 		if(rgbaMask != 0)

 		{

-			device->clearColor(color, rgbaMask);

+			device->clearColor(mState.colorClearValue.red, mState.colorClearValue.green, mState.colorClearValue.blue, mState.colorClearValue.alpha, rgbaMask);

 		}

 	}

 

diff --git a/src/OpenGL/libGLES_CM/Device.cpp b/src/OpenGL/libGLES_CM/Device.cpp
index 043afdf..6b4fa9f 100644
--- a/src/OpenGL/libGLES_CM/Device.cpp
+++ b/src/OpenGL/libGLES_CM/Device.cpp
@@ -136,7 +136,7 @@
 		delete context;

 	}

 

-	void Device::clearColor(unsigned int color, unsigned int rgbaMask)

+	void Device::clearColor(float red, float green, float blue, float alpha, unsigned int rgbaMask)

 	{

 		if(!renderTarget)

 		{

@@ -156,7 +156,7 @@
 			if(height > scissorRect.y1 - scissorRect.y0) height = scissorRect.y1 - scissorRect.y0;

 		}

 

-		renderTarget->clearColorBuffer(color, rgbaMask, x0, y0, width, height);

+		renderTarget->clearColorBuffer(red, green, blue, alpha, rgbaMask, x0, y0, width, height);

 	}

 

 	void Device::clearDepth(float z)

diff --git a/src/OpenGL/libGLES_CM/Device.hpp b/src/OpenGL/libGLES_CM/Device.hpp
index 699cc51..abfbd13 100644
--- a/src/OpenGL/libGLES_CM/Device.hpp
+++ b/src/OpenGL/libGLES_CM/Device.hpp
@@ -51,7 +51,7 @@
 

 		virtual ~Device();

 

-		virtual void clearColor(unsigned int color, unsigned int rgbaMask);

+		virtual void clearColor(float red, float green, float blue, float alpha, unsigned int rgbaMask);

 		virtual void clearDepth(float z);

 		virtual void clearStencil(unsigned int stencil, unsigned int mask);

 		virtual egl::Image *createDepthStencilSurface(unsigned int width, unsigned int height, sw::Format format, int multiSampleDepth, bool discard);

diff --git a/src/OpenGL/libGLESv2/Context.cpp b/src/OpenGL/libGLESv2/Context.cpp
index e4f71f3..0411a68 100644
--- a/src/OpenGL/libGLESv2/Context.cpp
+++ b/src/OpenGL/libGLESv2/Context.cpp
@@ -3538,11 +3538,7 @@
 

 		if(rgbaMask != 0)

 		{

-			unsigned int color = (unorm<8>(mState.colorClearValue.alpha) << 24) |

-			                     (unorm<8>(mState.colorClearValue.red) << 16) |

-			                     (unorm<8>(mState.colorClearValue.green) << 8) |

-			                     (unorm<8>(mState.colorClearValue.blue) << 0);

-			device->clearColor(color, rgbaMask);

+			device->clearColor(mState.colorClearValue.red, mState.colorClearValue.green, mState.colorClearValue.blue, mState.colorClearValue.alpha, rgbaMask);

 		}

 	}

 

@@ -3573,11 +3569,12 @@
 		int x0(0), y0(0), width(0), height(0);

 		egl::Image* image = getScissoredImage(drawbuffer, x0, y0, width, height, false);

 

-		unsigned int color = (value[0] < 0 ? 0 : (value[0] & 0x7F800000) << 1) |

-		                     (value[1] < 0 ? 0 : (value[1] & 0x7F800000) >> 7) |

-		                     (value[2] < 0 ? 0 : (value[2] & 0x7F800000) >> 15) |

-		                     (value[3] < 0 ? 0 : (value[3] & 0x7F800000) >> 23);

-		image->clearColorBuffer(color, rgbaMask, x0, y0, width, height);

+		float red = clamp01((float)value[0] / 0x7FFFFFFF);

+		float green = clamp01((float)value[1] / 0x7FFFFFFF);

+		float blue = clamp01((float)value[2] / 0x7FFFFFFF);

+		float alpha = clamp01((float)value[3] / 0x7FFFFFFF);

+

+		image->clearColorBuffer(red, green, blue, alpha, rgbaMask, x0, y0, width, height);

 	}

 }

 

@@ -3589,11 +3586,12 @@
 		int x0(0), y0(0), width(0), height(0);

 		egl::Image* image = getScissoredImage(drawbuffer, x0, y0, width, height, false);

 

-		unsigned int color = (value[0] & 0xFF000000) >> 0 |

-		                     (value[1] & 0xFF000000) >> 8 |

-		                     (value[2] & 0xFF000000) >> 16 |

-		                     (value[3] & 0xFF000000) >> 24;

-		image->clearColorBuffer(color, rgbaMask, x0, y0, width, height);

+		float red = (float)value[0] / 0xFFFFFFFF;

+		float green = (float)value[1] / 0xFFFFFFFF;

+		float blue = (float)value[2] / 0xFFFFFFFF;

+		float alpha = (float)value[3] / 0xFFFFFFFF;

+

+		image->clearColorBuffer(red, green, blue, alpha, rgbaMask, x0, y0, width, height);

 	}

 }

 

@@ -3605,11 +3603,12 @@
 		int x0(0), y0(0), width(0), height(0);

 		egl::Image* image = getScissoredImage(drawbuffer, x0, y0, width, height, false);

 

-		unsigned int color = (unorm<8>(value[0]) << 24) |

-		                     (unorm<8>(value[1]) << 16) |

-		                     (unorm<8>(value[2]) << 8) |

-		                     (unorm<8>(value[3]) << 0);

-		image->clearColorBuffer(color, rgbaMask, x0, y0, width, height);

+		float red = clamp01(value[0]);

+		float green = clamp01(value[1]);

+		float blue = clamp01(value[2]);

+		float alpha = clamp01(value[3]);

+

+		image->clearColorBuffer(red, green, blue, alpha, rgbaMask, x0, y0, width, height);

 	}

 }

 

diff --git a/src/OpenGL/libGLESv2/Device.cpp b/src/OpenGL/libGLESv2/Device.cpp
index f162dcd..5b77c27 100644
--- a/src/OpenGL/libGLESv2/Device.cpp
+++ b/src/OpenGL/libGLESv2/Device.cpp
@@ -175,7 +175,7 @@
 		}

 	}

 

-	void Device::clearColor(unsigned int color, unsigned int rgbaMask)

+	void Device::clearColor(float red, float green, float blue, float alpha, unsigned int rgbaMask)

 	{

 		if(!renderTarget)

 		{

@@ -185,7 +185,7 @@
 		int x0(0), y0(0), width(0), height(0);

 		getScissoredRegion(renderTarget, x0, y0, width, height);

 

-		renderTarget->clearColorBuffer(color, rgbaMask, x0, y0, width, height);

+		renderTarget->clearColorBuffer(red, green, blue, alpha, rgbaMask, x0, y0, width, height);

 	}

 

 	void Device::clearDepth(float z)

diff --git a/src/OpenGL/libGLESv2/Device.hpp b/src/OpenGL/libGLESv2/Device.hpp
index b6bb533..3d6f552c 100644
--- a/src/OpenGL/libGLESv2/Device.hpp
+++ b/src/OpenGL/libGLESv2/Device.hpp
@@ -51,7 +51,7 @@
 

 		virtual ~Device();

 

-		virtual void clearColor(unsigned int color, unsigned int rgbaMask);

+		virtual void clearColor(float red, float green, float blue, float alpha, unsigned int rgbaMask);

 		virtual void clearDepth(float z);

 		virtual void clearStencil(unsigned int stencil, unsigned int mask);

 		virtual egl::Image *createDepthStencilSurface(unsigned int width, unsigned int height, sw::Format format, int multiSampleDepth, bool discard);

diff --git a/src/Renderer/Surface.cpp b/src/Renderer/Surface.cpp
index 3a72601..0919066 100644
--- a/src/Renderer/Surface.cpp
+++ b/src/Renderer/Surface.cpp
@@ -2797,7 +2797,7 @@
 		}
 	}
 
-	void Surface::clearColorBuffer(unsigned int colorARGB, unsigned int rgbaMask, int x0, int y0, int width, int height)
+	void Surface::clearColorBuffer(float red, float green, float blue, float alpha, unsigned int rgbaMask, int x0, int y0, int width, int height)
 	{
 		// FIXME: Also clear buffers in other formats?
 
@@ -2837,30 +2837,39 @@
 					case FORMAT_A8R8G8B8:
 				//	case FORMAT_X8G8R8B8Q:   // FIXME
 				//	case FORMAT_A8G8R8B8Q:   // FIXME
-						if(rgbaMask == 0xF || (internal.format == FORMAT_X8R8G8B8 && rgbaMask == 0x7))
 						{
-							memfill4(target, colorARGB, 4 * (x1 - x0));
-						}
-						else
-						{
-							unsigned int bgraMask = (rgbaMask & 0x1 ? 0x00FF0000 : 0) | (rgbaMask & 0x2 ? 0x0000FF00 : 0) | (rgbaMask & 0x4 ? 0x000000FF : 0) | (rgbaMask & 0x8 ? 0xFF000000 : 0);
-							unsigned int invMask = ~bgraMask;
-							unsigned int maskedColor = colorARGB & bgraMask;
-							unsigned int *target32 = (unsigned int*)target;
+							unsigned char r8 = iround(red * 0xFF);
+							unsigned char g8 = iround(green * 0xFF);
+							unsigned char b8 = iround(blue * 0xFF);
+							unsigned char a8 = iround(alpha * 0xFF);
+							unsigned char a8r8g8b8[4] = {b8, g8, r8, a8};
+							unsigned int colorARGB = (unsigned int&)a8r8g8b8;
 
-							for(int x = 0; x < width; x++)
+							if(rgbaMask == 0xF || (internal.format == FORMAT_X8R8G8B8 && rgbaMask == 0x7))
 							{
-								target32[x] = maskedColor | (target32[x] & invMask);
+								memfill4(target, colorARGB, 4 * (x1 - x0));
+							}
+							else
+							{
+								unsigned int bgraMask = (rgbaMask & 0x1 ? 0x00FF0000 : 0) | (rgbaMask & 0x2 ? 0x0000FF00 : 0) | (rgbaMask & 0x4 ? 0x000000FF : 0) | (rgbaMask & 0x8 ? 0xFF000000 : 0);
+								unsigned int invMask = ~bgraMask;
+								unsigned int maskedColor = colorARGB & bgraMask;
+								unsigned int *target32 = (unsigned int*)target;
+
+								for(int x = 0; x < width; x++)
+								{
+									target32[x] = maskedColor | (target32[x] & invMask);
+								}
 							}
 						}
 						break;
 					case FORMAT_X8B8G8R8:
 					case FORMAT_A8B8G8R8:
 						{
-							unsigned char r8 = (colorARGB & 0x00FF0000) >> 16;
-							unsigned char g8 = (colorARGB & 0x0000FF00) >> 8;
-							unsigned char b8 = (colorARGB & 0x000000FF) >> 0;
-							unsigned char a8 = (colorARGB & 0xFF000000) >> 24;
+							unsigned char r8 = iround(red * 0xFF);
+							unsigned char g8 = iround(green * 0xFF);
+							unsigned char b8 = iround(blue * 0xFF);
+							unsigned char a8 = iround(alpha * 0xFF);
 							unsigned char a8b8g8r8[4] = {r8, g8, b8, a8};
 							unsigned int colorABGR = (unsigned int&)a8b8g8r8;
 
@@ -2884,8 +2893,8 @@
 						break;
 					case FORMAT_G8R8:
 						{
-							unsigned char r8 = (colorARGB & 0x00FF0000) >> 16;
-							unsigned char g8 = (colorARGB & 0x0000FF00) >> 8;
+							unsigned char r8 = iround(red * 0xFF);
+							unsigned char g8 = iround(green * 0xFF);
 							unsigned char g8r8[4] = {r8, g8, r8, g8};
 
 							if((rgbaMask & 0x3) == 0x3)
@@ -2908,10 +2917,8 @@
 						break;
 					case FORMAT_G16R16:
 						{
-							unsigned char r8 = (colorARGB & 0x00FF0000) >> 16;
-							unsigned char g8 = (colorARGB & 0x0000FF00) >> 8;
-							unsigned short r16 = (r8 << 8) | r8;
-							unsigned short g16 = (g8 << 8) | g8;
+							unsigned char r16 = iround(red * 0xFFFF);
+							unsigned char g16 = iround(green * 0xFFFF);
 							unsigned short g16r16[2] = {r16, g16};
 
 							if((rgbaMask & 0x3) == 0x3)
@@ -2934,14 +2941,10 @@
 						break;
 					case FORMAT_A16B16G16R16:
 						{
-							unsigned char r8 = (colorARGB & 0x00FF0000) >> 16;
-							unsigned char g8 = (colorARGB & 0x0000FF00) >> 8;
-							unsigned char b8 = (colorARGB & 0x000000FF) >> 0;
-							unsigned char a8 = (colorARGB & 0xFF000000) >> 24;
-							unsigned short r16 = (r8 << 8) | r8;
-							unsigned short g16 = (g8 << 8) | g8;
-							unsigned short b16 = (b8 << 8) | b8;
-							unsigned short a16 = (a8 << 8) | a8;
+							unsigned char r16 = iround(red * 0xFFFF);
+							unsigned char g16 = iround(green * 0xFFFF);
+							unsigned char b16 = iround(blue * 0xFFFF);
+							unsigned char a16 = iround(alpha * 0xFFFF);
 
 							if(rgbaMask == 0xF)
 							{
@@ -2965,63 +2968,52 @@
 					case FORMAT_R32F:
 						if(rgbaMask & 0x1)
 						{
-							float r32f = (float)(colorARGB & 0x00FF0000) / 0x00FF0000;
-
 							for(int x = 0; x < width; x++)
 							{
-								((float*)target)[x] = r32f;
+								((float*)target)[x] = red;
 							}
 						}
 						break;
 					case FORMAT_G32R32F:
+						if((rgbaMask & 0x3) == 0x3)
 						{
-							float r32f = (float)(colorARGB & 0x00FF0000) / 0x00FF0000;
-							float g32f = (float)(colorARGB & 0x0000FF00) / 0x0000FF00;
-
-							if((rgbaMask & 0x3) == 0x3)
+							for(int x = 0; x < width; x++)
 							{
-								for(int x = 0; x < width; x++)
-								{
-									((float*)target)[2 * x + 0] = r32f;
-									((float*)target)[2 * x + 1] = g32f;
-								}
+								((float*)target)[2 * x + 0] = red;
+								((float*)target)[2 * x + 1] = green;
 							}
-							else
-							{
-								if(rgbaMask & 0x1) for(int x = 0; x < width; x++) ((float*)target)[2 * x + 0] = r32f;
-								if(rgbaMask & 0x2) for(int x = 0; x < width; x++) ((float*)target)[2 * x + 1] = g32f;
-							}
+						}
+						else
+						{
+							if(rgbaMask & 0x1) for(int x = 0; x < width; x++) ((float*)target)[2 * x + 0] = red;
+							if(rgbaMask & 0x2) for(int x = 0; x < width; x++) ((float*)target)[2 * x + 1] = green;
 						}
 						break;
 					case FORMAT_A32B32G32R32F:
+						if(rgbaMask == 0xF)
 						{
-							float r32f = (float)(colorARGB & 0x00FF0000) / 0x00FF0000;
-							float g32f = (float)(colorARGB & 0x0000FF00) / 0x0000FF00;
-							float b32f = (float)(colorARGB & 0x000000FF) / 0x000000FF;
-							float a32f = (float)(colorARGB & 0xFF000000) / 0xFF000000;
-
-							if(rgbaMask == 0xF)
+							for(int x = 0; x < width; x++)
 							{
-								for(int x = 0; x < width; x++)
-								{
-									((float*)target)[4 * x + 0] = r32f;
-									((float*)target)[4 * x + 1] = g32f;
-									((float*)target)[4 * x + 2] = b32f;
-									((float*)target)[4 * x + 3] = a32f;
-								}
+								((float*)target)[4 * x + 0] = red;
+								((float*)target)[4 * x + 1] = green;
+								((float*)target)[4 * x + 2] = blue;
+								((float*)target)[4 * x + 3] = alpha;
 							}
-							else
-							{
-								if(rgbaMask & 0x1) for(int x = 0; x < width; x++) ((float*)target)[4 * x + 0] = r32f;
-								if(rgbaMask & 0x2) for(int x = 0; x < width; x++) ((float*)target)[4 * x + 1] = g32f;
-								if(rgbaMask & 0x4) for(int x = 0; x < width; x++) ((float*)target)[4 * x + 2] = b32f;
-								if(rgbaMask & 0x8) for(int x = 0; x < width; x++) ((float*)target)[4 * x + 3] = a32f;
-							}
+						}
+						else
+						{
+							if(rgbaMask & 0x1) for(int x = 0; x < width; x++) ((float*)target)[4 * x + 0] = red;
+							if(rgbaMask & 0x2) for(int x = 0; x < width; x++) ((float*)target)[4 * x + 1] = green;
+							if(rgbaMask & 0x4) for(int x = 0; x < width; x++) ((float*)target)[4 * x + 2] = blue;
+							if(rgbaMask & 0x8) for(int x = 0; x < width; x++) ((float*)target)[4 * x + 3] = alpha;
 						}
 						break;
 					case FORMAT_R5G6B5:
 						{
-							unsigned int r5g6b5 = ((colorARGB >> 8) & 0xF800) | ((colorARGB >> 5) & 0x07E0) | ((colorARGB >> 3) & 0x001F);
+							unsigned int r5 = iround(red * 0x1F);
+							unsigned int g6 = iround(green * 0x3F);
+							unsigned int b5 = iround(blue * 0x1F);
+							unsigned int r5g6b5 = (r5 << 11) | (g6 << 5) | b5;
 
 							if((rgbaMask & 0x7) == 0x7)
 							{
diff --git a/src/Renderer/Surface.hpp b/src/Renderer/Surface.hpp
index 48502c4..9860b6d 100644
--- a/src/Renderer/Surface.hpp
+++ b/src/Renderer/Surface.hpp
@@ -254,7 +254,7 @@
 		inline int getMultiSampleCount() const;

 		inline int getSuperSampleCount() const;

 

-		void clearColorBuffer(unsigned int colorARGB, unsigned int rgbaMask, int x0, int y0, int width, int height);

+		void clearColorBuffer(float red, float green, float blue, float alpha, unsigned int rgbaMask, int x0, int y0, int width, int height);

 		void clearDepthBuffer(float depth, int x0, int y0, int width, int height);

 		void clearStencilBuffer(unsigned char stencil, unsigned char mask, int x0, int y0, int width, int height);

 		void fill(const Color<float> &color, int x0, int y0, int width, int height);