Remove idle Blitter fallbacks

For Vulkan we must support all blittable formats natively, so there's
no fallback to C++ code. Also, if by error an unsupported format is
used we don't have to immediately abort routine generation but can
continue with something that's benign.

This change simplifies the code, makes it more readable/maintainable,
and marks other formats as unsupported instead of unimplemented.

Bug: b/138944025
Bug: b/131243109
Change-Id: I4d246cdd280c5a352f18341996c92111a5144d96
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/34588
Presubmit-Ready: Nicolas Capens <nicolascapens@google.com>
Tested-by: Nicolas Capens <nicolascapens@google.com>
Kokoro-Presubmit: kokoro <noreply+kokoro@google.com>
Reviewed-by: Ben Clayton <bclayton@google.com>
diff --git a/src/Device/Blitter.cpp b/src/Device/Blitter.cpp
index f6b483e..198f108 100644
--- a/src/Device/Blitter.cpp
+++ b/src/Device/Blitter.cpp
@@ -257,9 +257,9 @@
 		return true;
 	}
 
-	bool Blitter::read(Float4 &c, Pointer<Byte> element, const State &state)
+	Float4 Blitter::readFloat4(Pointer<Byte> element, const State &state)
 	{
-		c = Float4(0.0f, 0.0f, 0.0f, 1.0f);
+		Float4 c(0.0f, 0.0f, 0.0f, 1.0f);
 
 		switch(state.sourceFormat)
 		{
@@ -448,13 +448,13 @@
 			c.x = Float(Int(*Pointer<Byte>(element)));
 			break;
 		default:
-			return false;
+			UNSUPPORTED("Blitter source format %d", (int)state.sourceFormat);
 		}
 
-		return true;
+		return c;
 	}
 
-	bool Blitter::write(Float4 &c, Pointer<Byte> element, const State &state)
+	void Blitter::write(Float4 &c, Pointer<Byte> element, const State &state)
 	{
 		bool writeR = state.writeRed;
 		bool writeG = state.writeGreen;
@@ -983,14 +983,14 @@
 			*Pointer<Byte>(element) = Byte(RoundInt(Float(c.x)));
 			break;
 		default:
-			return false;
+			UNSUPPORTED("Blitter destination format %d", (int)state.destFormat);
+			break;
 		}
-		return true;
 	}
 
-	bool Blitter::read(Int4 &c, Pointer<Byte> element, const State &state)
+	Int4 Blitter::readInt4(Pointer<Byte> element, const State &state)
 	{
-		c = Int4(0, 0, 0, 1);
+		Int4 c(0, 0, 0, 1);
 
 		switch(state.sourceFormat)
 		{
@@ -1046,13 +1046,13 @@
 			c = Insert(c, *Pointer<Int>(element), 0);
 			break;
 		default:
-			return false;
+			UNSUPPORTED("Blitter source format %d", (int)state.sourceFormat);
 		}
 
-		return true;
+		return c;
 	}
 
-	bool Blitter::write(Int4 &c, Pointer<Byte> element, const State &state)
+	void Blitter::write(Int4 &c, Pointer<Byte> element, const State &state)
 	{
 		bool writeR = state.writeRed;
 		bool writeG = state.writeGreen;
@@ -1273,15 +1273,14 @@
 			if(writeR) { *Pointer<UInt>(element) = As<UInt>(Extract(c, 0)); }
 			break;
 		default:
-			return false;
+			UNSUPPORTED("Blitter destination format %d", (int)state.destFormat);
 		}
-
-		return true;
 	}
 
-	bool Blitter::ApplyScaleAndClamp(Float4 &value, const State &state, bool preScaled)
+	void Blitter::ApplyScaleAndClamp(Float4 &value, const State &state, bool preScaled)
 	{
 		float4 scale, unscale;
+
 		if(state.clearOperation &&
 		   state.sourceFormat.isNonNormalizedInteger() &&
 		   !state.destFormat.isNonNormalizedInteger())
@@ -1297,18 +1296,15 @@
 				unscale = replicate(static_cast<float>(0xFFFFFFFF));
 				break;
 			default:
-				return false;
+				UNSUPPORTED("Blitter source format %d", (int)state.sourceFormat);
 			}
 		}
-		else if(!state.sourceFormat.getScale(unscale))
+		else
 		{
-			return false;
+			unscale = state.sourceFormat.getScale();
 		}
 
-		if(!state.destFormat.getScale(scale))
-		{
-			return false;
-		}
+		scale = state.destFormat.getScale();
 
 		bool srcSRGB = state.sourceFormat.isSRGBformat();
 		bool dstSRGB = state.destFormat.isSRGBformat();
@@ -1334,8 +1330,6 @@
 			                          state.destFormat.isUnsignedComponent(2) ? 0.0f : -scale.z,
 			                          state.destFormat.isUnsignedComponent(3) ? 0.0f : -scale.w));
 		}
-
-		return true;
 	}
 
 	Int Blitter::ComputeOffset(Int &x, Int &y, Int &pitchB, int bytes, bool quadLayout)
@@ -1416,24 +1410,15 @@
 			{
 				if(intBoth) // Integer types
 				{
-					if(!read(constantColorI, source, state))
-					{
-						return nullptr;
-					}
+					constantColorI = readInt4(source, state);
 					hasConstantColorI = true;
 				}
 				else
 				{
-					if(!read(constantColorF, source, state))
-					{
-						return nullptr;
-					}
+					constantColorF = readFloat4(source, state);
 					hasConstantColorF = true;
 
-					if(!ApplyScaleAndClamp(constantColorF, state))
-					{
-						return nullptr;
-					}
+					ApplyScaleAndClamp(constantColorF, state);
 				}
 			}
 
@@ -1449,26 +1434,19 @@
 
 					if(hasConstantColorI)
 					{
-						if(!write(constantColorI, d, state))
-						{
-							return nullptr;
-						}
+						write(constantColorI, d, state);
 					}
 					else if(hasConstantColorF)
 					{
 						for(int s = 0; s < state.destSamples; s++)
 						{
-							if(!write(constantColorF, d, state))
-							{
-								return nullptr;
-							}
+							write(constantColorF, d, state);
 
 							d += *Pointer<Int>(blit + OFFSET(BlitData, dSliceB));
 						}
 					}
 					else if(intBoth) // Integer types do not support filtering
 					{
-						Int4 color; // When both formats are true integer types, we don't go to float to avoid losing precision
 						Int X = Int(x);
 						Int Y = Int(y);
 
@@ -1480,15 +1458,9 @@
 
 						Pointer<Byte> s = source + ComputeOffset(X, Y, sPitchB, srcBytes, srcQuadLayout);
 
-						if(!read(color, s, state))
-						{
-							return nullptr;
-						}
-
-						if(!write(color, d, state))
-						{
-							return nullptr;
-						}
+						// When both formats are true integer types, we don't go to float to avoid losing precision
+						Int4 color = readInt4(s, state);
+						write(color, d, state);
 					}
 					else
 					{
@@ -1508,29 +1480,24 @@
 
 							Pointer<Byte> s = source + ComputeOffset(X, Y, sPitchB, srcBytes, srcQuadLayout);
 
-							if(!read(color, s, state))
-							{
-								return nullptr;
-							}
+							color = readFloat4(s, state);
 
 							if(state.srcSamples > 1) // Resolve multisampled source
 							{
 								if(state.convertSRGB && state.sourceFormat.isSRGBformat()) // sRGB -> RGB
 								{
-									if(!ApplyScaleAndClamp(color, state)) return nullptr;
+									ApplyScaleAndClamp(color, state);
 									preScaled = true;
 								}
 								Float4 accum = color;
 								for(int sample = 1; sample < state.srcSamples; sample++)
 								{
 									s += *Pointer<Int>(blit + OFFSET(BlitData, sSliceB));
-									if(!read(color, s, state))
-									{
-										return nullptr;
-									}
+									color = readFloat4(s, state);
+
 									if(state.convertSRGB && state.sourceFormat.isSRGBformat()) // sRGB -> RGB
 									{
-										if(!ApplyScaleAndClamp(color, state)) return nullptr;
+										ApplyScaleAndClamp(color, state);
 										preScaled = true;
 									}
 									accum += color;
@@ -1565,17 +1532,17 @@
 							Pointer<Byte> s10 = source + ComputeOffset(X0, Y1, sPitchB, srcBytes, srcQuadLayout);
 							Pointer<Byte> s11 = source + ComputeOffset(X1, Y1, sPitchB, srcBytes, srcQuadLayout);
 
-							Float4 c00; if(!read(c00, s00, state)) return nullptr;
-							Float4 c01; if(!read(c01, s01, state)) return nullptr;
-							Float4 c10; if(!read(c10, s10, state)) return nullptr;
-							Float4 c11; if(!read(c11, s11, state)) return nullptr;
+							Float4 c00 = readFloat4(s00, state);
+							Float4 c01 = readFloat4(s01, state);
+							Float4 c10 = readFloat4(s10, state);
+							Float4 c11 = readFloat4(s11, state);
 
 							if(state.convertSRGB && state.sourceFormat.isSRGBformat()) // sRGB -> RGB
 							{
-								if(!ApplyScaleAndClamp(c00, state)) return nullptr;
-								if(!ApplyScaleAndClamp(c01, state)) return nullptr;
-								if(!ApplyScaleAndClamp(c10, state)) return nullptr;
-								if(!ApplyScaleAndClamp(c11, state)) return nullptr;
+								ApplyScaleAndClamp(c00, state);
+								ApplyScaleAndClamp(c01, state);
+								ApplyScaleAndClamp(c10, state);
+								ApplyScaleAndClamp(c11, state);
 								preScaled = true;
 							}
 
@@ -1588,17 +1555,11 @@
 							        (c10 * ix + c11 * fx) * fy;
 						}
 
-						if(!ApplyScaleAndClamp(color, state, preScaled))
-						{
-							return nullptr;
-						}
+						ApplyScaleAndClamp(color, state, preScaled);
 
 						for(int s = 0; s < state.destSamples; s++)
 						{
-							if(!write(color, d, state))
-							{
-								return nullptr;
-							}
+							write(color, d, state);
 
 							d += *Pointer<Int>(blit + OFFSET(BlitData,dSliceB));
 						}
@@ -1618,13 +1579,6 @@
 		if(!blitRoutine)
 		{
 			blitRoutine = generate(state);
-
-			if(!blitRoutine)
-			{
-				UNIMPLEMENTED("blitRoutine");
-				return nullptr;
-			}
-
 			blitCache.add(state, blitRoutine);
 		}
 
@@ -1639,13 +1593,6 @@
 		if(!cornerUpdateRoutine)
 		{
 			cornerUpdateRoutine = generateCornerUpdate(state);
-
-			if(!cornerUpdateRoutine)
-			{
-				UNIMPLEMENTED("cornerUpdateRoutine");
-				return nullptr;
-			}
-
 			cornerUpdateCache.add(state, cornerUpdateRoutine);
 		}
 
@@ -1918,15 +1865,13 @@
 		int bytes = state.sourceFormat.bytes();
 		bool quadLayout = state.sourceFormat.hasQuadLayout();
 
-		Float4 c0;
-		read(c0, layer + ComputeOffset(x0, y1, pitchB, bytes, quadLayout), state);
-		Float4 c1;
-		read(c1, layer + ComputeOffset(x1, y0, pitchB, bytes, quadLayout), state);
-		c0 += c1;
-		read(c1, layer + ComputeOffset(x1, y1, pitchB, bytes, quadLayout), state);
-		c0 += c1;
-		c0 *= Float4(1.0f / 3.0f);
-		write(c0, layer + ComputeOffset(x0, y0, pitchB, bytes, quadLayout), state);
+		Float4 c = readFloat4(layer + ComputeOffset(x0, y1, pitchB, bytes, quadLayout), state) +
+		           readFloat4(layer + ComputeOffset(x1, y0, pitchB, bytes, quadLayout), state) +
+		           readFloat4(layer + ComputeOffset(x1, y1, pitchB, bytes, quadLayout), state);
+
+		c *= Float4(1.0f / 3.0f);
+
+		write(c, layer + ComputeOffset(x0, y0, pitchB, bytes, quadLayout), state);
 	}
 
 	std::shared_ptr<Routine> Blitter::generateCornerUpdate(const State& state)
@@ -2082,7 +2027,7 @@
 		int h = extent.height;
 		if(w != h)
 		{
-			UNIMPLEMENTED("Cube doesn't have square faces : (%d, %d)", w, h);
+			UNSUPPORTED("Cube doesn't have square faces : (%d, %d)", w, h);
 		}
 
 		// Src is expressed in the regular [0, width-1], [0, height-1] space
diff --git a/src/Device/Blitter.hpp b/src/Device/Blitter.hpp
index c8cddf3..849bcc2 100644
--- a/src/Device/Blitter.hpp
+++ b/src/Device/Blitter.hpp
@@ -126,11 +126,11 @@
 
 		bool fastClear(void *pixel, vk::Format format, vk::Image *dest, const vk::Format& viewFormat, const VkImageSubresourceRange& subresourceRange, const VkRect2D* renderArea);
 
-		bool read(Float4 &color, Pointer<Byte> element, const State &state);
-		bool write(Float4 &color, Pointer<Byte> element, const State &state);
-		bool read(Int4 &color, Pointer<Byte> element, const State &state);
-		bool write(Int4 &color, Pointer<Byte> element, const State &state);
-		static bool ApplyScaleAndClamp(Float4 &value, const State &state, bool preScaled = false);
+		Float4 readFloat4(Pointer<Byte> element, const State &state);
+		void write(Float4 &color, Pointer<Byte> element, const State &state);
+		Int4 readInt4(Pointer<Byte> element, const State &state);
+		void write(Int4 &color, Pointer<Byte> element, const State &state);
+		static void ApplyScaleAndClamp(Float4 &value, const State &state, bool preScaled = false);
 		static Int ComputeOffset(Int &x, Int &y, Int &pitchB, int bytes, bool quadLayout);
 		static Float4 LinearToSRGB(Float4 &color);
 		static Float4 sRGBtoLinear(Float4 &color);
diff --git a/src/Reactor/LLVMReactor.cpp b/src/Reactor/LLVMReactor.cpp
index 7bf902e..9ada8ee 100644
--- a/src/Reactor/LLVMReactor.cpp
+++ b/src/Reactor/LLVMReactor.cpp
@@ -3508,6 +3508,18 @@
 		return T(Type_v2f32);
 	}
 
+	RValue<Float> Exp2(RValue<Float> v)
+	{
+		auto func = llvm::Intrinsic::getDeclaration(jit->module.get(), llvm::Intrinsic::exp2, { T(Float::getType()) } );
+		return RValue<Float>(V(jit->builder->CreateCall(func, V(v.value))));
+	}
+
+	RValue<Float> Log2(RValue<Float> v)
+	{
+		auto func = llvm::Intrinsic::getDeclaration(jit->module.get(), llvm::Intrinsic::log2, { T(Float::getType()) } );
+		return RValue<Float>(V(jit->builder->CreateCall(func, V(v.value))));
+	}
+
 	Float4::Float4(RValue<Float> rhs) : XYZW(this)
 	{
 		RR_DEBUG_INFO_UPDATE_LOC();
diff --git a/src/Reactor/Reactor.hpp b/src/Reactor/Reactor.hpp
index d6a2f4a..d269fec 100644
--- a/src/Reactor/Reactor.hpp
+++ b/src/Reactor/Reactor.hpp
@@ -2092,11 +2092,38 @@
 	RValue<Float> Rcp_pp(RValue<Float> val, bool exactAtPow2 = false);
 	RValue<Float> RcpSqrt_pp(RValue<Float> val);
 	RValue<Float> Sqrt(RValue<Float> x);
-	RValue<Float> Round(RValue<Float> val);
-	RValue<Float> Trunc(RValue<Float> val);
-	RValue<Float> Frac(RValue<Float> val);
-	RValue<Float> Floor(RValue<Float> val);
-	RValue<Float> Ceil(RValue<Float> val);
+
+//	RValue<Int4> IsInf(RValue<Float> x);
+//	RValue<Int4> IsNan(RValue<Float> x);
+	RValue<Float> Round(RValue<Float> x);
+	RValue<Float> Trunc(RValue<Float> x);
+	RValue<Float> Frac(RValue<Float> x);
+	RValue<Float> Floor(RValue<Float> x);
+	RValue<Float> Ceil(RValue<Float> x);
+
+	// Trigonometric functions
+	// TODO: Currently unimplemented for Subzero.
+//	RValue<Float> Sin(RValue<Float> x);
+//	RValue<Float> Cos(RValue<Float> x);
+//	RValue<Float> Tan(RValue<Float> x);
+//	RValue<Float> Asin(RValue<Float> x);
+//	RValue<Float> Acos(RValue<Float> x);
+//	RValue<Float> Atan(RValue<Float> x);
+//	RValue<Float> Sinh(RValue<Float> x);
+//	RValue<Float> Cosh(RValue<Float> x);
+//	RValue<Float> Tanh(RValue<Float> x);
+//	RValue<Float> Asinh(RValue<Float> x);
+//	RValue<Float> Acosh(RValue<Float> x);
+//	RValue<Float> Atanh(RValue<Float> x);
+//	RValue<Float> Atan2(RValue<Float> x, RValue<Float> y);
+
+	// Exponential functions
+	// TODO: Currently unimplemented for Subzero.
+//	RValue<Float> Pow(RValue<Float> x, RValue<Float> y);
+//	RValue<Float> Exp(RValue<Float> x);
+//	RValue<Float> Log(RValue<Float> x);
+	RValue<Float> Exp2(RValue<Float> x);
+	RValue<Float> Log2(RValue<Float> x);
 
 	class Float2 : public LValue<Float2>
 	{
@@ -2264,7 +2291,7 @@
 	RValue<Float4> Ceil(RValue<Float4> x);
 
 	// Trigonometric functions
-	// TODO: Currentlhy unimplemented for Subzero.
+	// TODO: Currently unimplemented for Subzero.
 	RValue<Float4> Sin(RValue<Float4> x);
 	RValue<Float4> Cos(RValue<Float4> x);
 	RValue<Float4> Tan(RValue<Float4> x);
@@ -2280,7 +2307,7 @@
 	RValue<Float4> Atan2(RValue<Float4> x, RValue<Float4> y);
 
 	// Exponential functions
-	// TODO: Currentlhy unimplemented for Subzero.
+	// TODO: Currently unimplemented for Subzero.
 	RValue<Float4> Pow(RValue<Float4> x, RValue<Float4> y);
 	RValue<Float4> Exp(RValue<Float4> x);
 	RValue<Float4> Log(RValue<Float4> x);
@@ -2288,7 +2315,7 @@
 	RValue<Float4> Log2(RValue<Float4> x);
 
 	// Bit Manipulation functions.
-	// TODO: Currentlhy unimplemented for Subzero.
+	// TODO: Currently unimplemented for Subzero.
 
 	// Count leading zeros.
 	// Returns 32 when: isZeroUndef && x == 0.
diff --git a/src/Reactor/SubzeroReactor.cpp b/src/Reactor/SubzeroReactor.cpp
index a1894ce..2099688 100644
--- a/src/Reactor/SubzeroReactor.cpp
+++ b/src/Reactor/SubzeroReactor.cpp
@@ -3522,6 +3522,8 @@
 	void Nucleus::createMaskedStore(Value *ptr, Value *val, Value *mask, unsigned int alignment) { UNIMPLEMENTED("Subzero createMaskedStore()"); }
 	Value *Nucleus::createGather(Value *base, Type *elTy, Value *offsets, Value *mask, unsigned int alignment, bool zeroMaskedLanes) { UNIMPLEMENTED("Subzero createGather()"); return nullptr; }
 	void Nucleus::createScatter(Value *base, Value *val, Value *offsets, Value *mask, unsigned int alignment) { UNIMPLEMENTED("Subzero createScatter()"); }
+	RValue<Float> Exp2(RValue<Float> x) { UNIMPLEMENTED("Subzero Exp2()"); return Float(0); }
+	RValue<Float> Log2(RValue<Float> x) { UNIMPLEMENTED("Subzero Log2()"); return Float(0); }
 	RValue<Float4> Sin(RValue<Float4> x) { UNIMPLEMENTED("Subzero Sin()"); return Float4(0); }
 	RValue<Float4> Cos(RValue<Float4> x) { UNIMPLEMENTED("Subzero Cos()"); return Float4(0); }
 	RValue<Float4> Tan(RValue<Float4> x) { UNIMPLEMENTED("Subzero Tan()"); return Float4(0); }
diff --git a/src/Vulkan/VkFormat.cpp b/src/Vulkan/VkFormat.cpp
index 9dad667..e980ea3 100644
--- a/src/Vulkan/VkFormat.cpp
+++ b/src/Vulkan/VkFormat.cpp
@@ -1724,15 +1724,14 @@
 	return sw::align<16>(sliceBUnpadded(width, height, border, target) + 15);
 }
 
-bool Format::getScale(sw::float4 &scale) const
+sw::float4 Format::getScale() const
 {
 	switch(format)
 	{
 	case VK_FORMAT_R4G4_UNORM_PACK8:
 	case VK_FORMAT_R4G4B4A4_UNORM_PACK16:
 	case VK_FORMAT_B4G4R4A4_UNORM_PACK16:
-		scale = sw::vector(0xF, 0xF, 0xF, 0xF);
-		break;
+		return sw::vector(0xF, 0xF, 0xF, 0xF);
 	case VK_FORMAT_R8_UNORM:
 	case VK_FORMAT_R8G8_UNORM:
 	case VK_FORMAT_R8G8B8_UNORM:
@@ -1747,8 +1746,7 @@
 	case VK_FORMAT_A8B8G8R8_SRGB_PACK32:
 	case VK_FORMAT_R8G8B8A8_SRGB:
 	case VK_FORMAT_B8G8R8A8_SRGB:
-		scale = sw::vector(0xFF, 0xFF, 0xFF, 0xFF);
-		break;
+		return sw::vector(0xFF, 0xFF, 0xFF, 0xFF);
 	case VK_FORMAT_R8_SNORM:
 	case VK_FORMAT_R8G8_SNORM:
 	case VK_FORMAT_R8G8B8_SNORM:
@@ -1756,20 +1754,17 @@
 	case VK_FORMAT_A8B8G8R8_SNORM_PACK32:
 	case VK_FORMAT_R8G8B8A8_SNORM:
 	case VK_FORMAT_B8G8R8A8_SNORM:
-		scale = sw::vector(0x7F, 0x7F, 0x7F, 0x7F);
-		break;
+		return sw::vector(0x7F, 0x7F, 0x7F, 0x7F);
 	case VK_FORMAT_R16_UNORM:
 	case VK_FORMAT_R16G16_UNORM:
 	case VK_FORMAT_R16G16B16_UNORM:
 	case VK_FORMAT_R16G16B16A16_UNORM:
-		scale = sw::vector(0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF);
-		break;
+		return sw::vector(0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF);
 	case VK_FORMAT_R16_SNORM:
 	case VK_FORMAT_R16G16_SNORM:
 	case VK_FORMAT_R16G16B16_SNORM:
 	case VK_FORMAT_R16G16B16A16_SNORM:
-		scale = sw::vector(0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF);
-		break;
+		return sw::vector(0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF);
 	case VK_FORMAT_R8_SINT:
 	case VK_FORMAT_R8_UINT:
 	case VK_FORMAT_R8G8_SINT:
@@ -1838,42 +1833,35 @@
 	case VK_FORMAT_A2B10G10R10_SSCALED_PACK32:
 	case VK_FORMAT_A2B10G10R10_UINT_PACK32:
 	case VK_FORMAT_A2B10G10R10_SINT_PACK32:
-		scale = sw::vector(1.0f, 1.0f, 1.0f, 1.0f);
-		break;
+		return sw::vector(1.0f, 1.0f, 1.0f, 1.0f);
 	case VK_FORMAT_R5G5B5A1_UNORM_PACK16:
 	case VK_FORMAT_B5G5R5A1_UNORM_PACK16:
 	case VK_FORMAT_A1R5G5B5_UNORM_PACK16:
-		scale = sw::vector(0x1F, 0x1F, 0x1F, 0x01);
-		break;
+		return sw::vector(0x1F, 0x1F, 0x1F, 0x01);
 	case VK_FORMAT_R5G6B5_UNORM_PACK16:
 	case VK_FORMAT_B5G6R5_UNORM_PACK16:
-		scale = sw::vector(0x1F, 0x3F, 0x1F, 1.0f);
-		break;
+		return sw::vector(0x1F, 0x3F, 0x1F, 1.0f);
 	case VK_FORMAT_A2R10G10B10_UNORM_PACK32:
 	case VK_FORMAT_A2B10G10R10_UNORM_PACK32:
-		scale = sw::vector(0x3FF, 0x3FF, 0x3FF, 0x03);
-		break;
+		return sw::vector(0x3FF, 0x3FF, 0x3FF, 0x03);
 	case VK_FORMAT_A2R10G10B10_SNORM_PACK32:
 	case VK_FORMAT_A2B10G10R10_SNORM_PACK32:
-		scale = sw::vector(0x1FF, 0x1FF, 0x1FF, 0x01);
-		break;
+		return sw::vector(0x1FF, 0x1FF, 0x1FF, 0x01);
 	case VK_FORMAT_D16_UNORM:
-		scale = sw::vector(0xFFFF, 0.0f, 0.0f, 0.0f);
-		break;
+		return sw::vector(0xFFFF, 0.0f, 0.0f, 0.0f);
 	case VK_FORMAT_D24_UNORM_S8_UINT:
 	case VK_FORMAT_X8_D24_UNORM_PACK32:
-		scale = sw::vector(0xFFFFFF, 0.0f, 0.0f, 0.0f);
-		break;
+		return sw::vector(0xFFFFFF, 0.0f, 0.0f, 0.0f);
 	case VK_FORMAT_D32_SFLOAT:
 	case VK_FORMAT_D32_SFLOAT_S8_UINT:
 	case VK_FORMAT_S8_UINT:
-		scale = sw::vector(1.0f, 1.0f, 1.0f, 1.0f);
-		break;
+		return sw::vector(1.0f, 1.0f, 1.0f, 1.0f);
 	default:
-		return false;
+		UNSUPPORTED("format %d", int(format));
+		break;
 	}
 
-	return true;
+	return sw::vector(1.0f, 1.0f, 1.0f, 1.0f);
 }
 
 bool Format::has16bitTextureFormat() const
diff --git a/src/Vulkan/VkFormat.h b/src/Vulkan/VkFormat.h
index 15385f4..8770c39 100644
--- a/src/Vulkan/VkFormat.h
+++ b/src/Vulkan/VkFormat.h
@@ -60,7 +60,7 @@
 	int pitchB(int width, int border, bool target) const;
 	int sliceB(int width, int height, int border, bool target) const;
 
-	bool getScale(sw::float4 &scale) const;
+	sw::float4 getScale() const;
 
 	// Texture sampling utilities
 	bool has16bitTextureFormat() const;