Specialize 1D sampling LOD calculation

Instead of reusing the 2D mipmap LOD calculation, this change adds a
separate method for computing the LOD for 1D sampling operations.

This also revealed that we would perform the anisotropic filtering
calculations on 1D sampling operations if enabled, which makes no sense.
This change limits it to 2D sampling only.

Bug: b/134669567
Change-Id: I05dd3fe358eccfcd01ebcff35872f56c6f0b0b70
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/47488
Presubmit-Ready: Nicolas Capens <nicolascapens@google.com>
Tested-by: Nicolas Capens <nicolascapens@google.com>
Reviewed-by: Chris Forbes <chrisforbes@google.com>
Reviewed-by: Alexis Hétu <sugoi@google.com>
Kokoro-Result: kokoro <noreply+kokoro@google.com>
diff --git a/src/Pipeline/SamplerCore.cpp b/src/Pipeline/SamplerCore.cpp
index 7410af1..6336730 100644
--- a/src/Pipeline/SamplerCore.cpp
+++ b/src/Pipeline/SamplerCore.cpp
@@ -63,16 +63,17 @@
 
 	if(function == Implicit || function == Bias || function == Grad || function == Query)
 	{
-		if(state.textureType != VK_IMAGE_VIEW_TYPE_3D)
+		if(state.addressingModeV == ADDRESSING_UNUSED)
 		{
-			if(!isCube())
-			{
-				computeLod(texture, lod, anisotropy, uDelta, vDelta, u, v, dsx, dsy, function);
-			}
-			else
-			{
-				computeLodCube(texture, lod, uvwa[0], uvwa[1], uvwa[2], dsx, dsy, M, function);
-			}
+			computeLod1D(texture, lod, u, dsx, dsy, function);
+		}
+		else if(state.addressingModeW == ADDRESSING_UNUSED)
+		{
+			computeLod2D(texture, lod, anisotropy, uDelta, vDelta, u, v, dsx, dsy, function);
+		}
+		else if(isCube())
+		{
+			computeLodCube(texture, lod, uvwa[0], uvwa[1], uvwa[2], dsx, dsy, M, function);
 		}
 		else
 		{
@@ -423,7 +424,7 @@
 {
 	Vector4s c;
 
-	if(state.textureFilter != FILTER_ANISOTROPIC || function == Lod || function == Fetch)
+	if(state.textureFilter != FILTER_ANISOTROPIC)
 	{
 		c = sampleQuad(texture, u, v, w, a, offset, sample, lod, secondLOD, function);
 	}
@@ -895,7 +896,7 @@
 {
 	Vector4f c;
 
-	if(state.textureFilter != FILTER_ANISOTROPIC || function == Lod || function == Fetch)
+	if(state.textureFilter != FILTER_ANISOTROPIC)
 	{
 		c = sampleFloat(texture, u, v, w, a, dRef, offset, sample, lod, secondLOD, function);
 	}
@@ -1137,9 +1138,9 @@
 	return c;
 }
 
-Float SamplerCore::log2sqrt(Float lod)
+static Float log2sqrt(Float lod)
 {
-	// log2(sqrt(lod))                               // Equals 0.25 * log2(lod^2).
+	// log2(sqrt(lod))                              // Equals 0.25 * log2(lod^2).
 	lod *= lod;                                     // Squaring doubles the exponent and produces an extra bit of precision.
 	lod = Float(As<Int>(lod)) - Float(0x3F800000);  // Interpret as integer and subtract the exponent bias.
 	lod *= As<Float>(Int(0x33000000));              // Scale by 0.25 * 2^-23 (mantissa length).
@@ -1147,7 +1148,7 @@
 	return lod;
 }
 
-Float SamplerCore::log2(Float lod)
+static Float log2(Float lod)
 {
 	lod *= lod;                                     // Squaring doubles the exponent and produces an extra bit of precision.
 	lod = Float(As<Int>(lod)) - Float(0x3F800000);  // Interpret as integer and subtract the exponent bias.
@@ -1156,7 +1157,31 @@
 	return lod;
 }
 
-void SamplerCore::computeLod(Pointer<Byte> &texture, Float &lod, Float &anisotropy, Float4 &uDelta, Float4 &vDelta, Float4 &uuuu, Float4 &vvvv, Float4 &dsx, Float4 &dsy, SamplerFunction function)
+void SamplerCore::computeLod1D(Pointer<Byte> &texture, Float &lod, Float4 &uuuu, Float4 &dsx, Float4 &dsy, SamplerFunction function)
+{
+	Float4 dudxy;
+
+	if(function != Grad)  // Implicit
+	{
+		dudxy = uuuu.yz - uuuu.xx;
+	}
+	else
+	{
+		dudxy = UnpackLow(dsx, dsy);
+	}
+
+	// Scale by texture dimensions.
+	Float4 dUdxy = dudxy * *Pointer<Float4>(texture + OFFSET(Texture, widthWidthHeightHeight));
+
+	// Note we could take the absolute value here and omit the square root below,
+	// but this is more consistent with the 2D calculation and still cheap.
+	Float4 dU2dxy = dUdxy * dUdxy;
+
+	lod = Max(Float(dU2dxy.x), Float(dU2dxy.y));
+	lod = log2sqrt(lod);
+}
+
+void SamplerCore::computeLod2D(Pointer<Byte> &texture, Float &lod, Float &anisotropy, Float4 &uDelta, Float4 &vDelta, Float4 &uuuu, Float4 &vvvv, Float4 &dsx, Float4 &dsy, SamplerFunction function)
 {
 	Float4 duvdxy;
 
diff --git a/src/Pipeline/SamplerCore.hpp b/src/Pipeline/SamplerCore.hpp
index 1c029d3..a05bf75 100644
--- a/src/Pipeline/SamplerCore.hpp
+++ b/src/Pipeline/SamplerCore.hpp
@@ -73,9 +73,8 @@
 	Vector4f sampleFloat(Pointer<Byte> &texture, Float4 &u, Float4 &v, Float4 &w, const Float4 &a, Float4 &dRef, Vector4i &offset, const Int4 &sample, Float &lod, bool secondLOD, SamplerFunction function);
 	Vector4f sampleFloat2D(Pointer<Byte> &texture, Float4 &u, Float4 &v, Float4 &w, const Float4 &a, Float4 &dRef, Vector4i &offset, const Int4 &sample, Float &lod, bool secondLOD, SamplerFunction function);
 	Vector4f sampleFloat3D(Pointer<Byte> &texture, Float4 &u, Float4 &v, Float4 &w, Float4 &dRef, Vector4i &offset, const Int4 &sample, Float &lod, bool secondLOD, SamplerFunction function);
-	Float log2sqrt(Float lod);
-	Float log2(Float lod);
-	void computeLod(Pointer<Byte> &texture, Float &lod, Float &anisotropy, Float4 &uDelta, Float4 &vDelta, Float4 &u, Float4 &v, Float4 &dsx, Float4 &dsy, SamplerFunction function);
+	void computeLod1D(Pointer<Byte> &texture, Float &lod, Float4 &u, Float4 &dsx, Float4 &dsy, SamplerFunction function);
+	void computeLod2D(Pointer<Byte> &texture, Float &lod, Float &anisotropy, Float4 &uDelta, Float4 &vDelta, Float4 &u, Float4 &v, Float4 &dsx, Float4 &dsy, SamplerFunction function);
 	void computeLodCube(Pointer<Byte> &texture, Float &lod, Float4 &u, Float4 &v, Float4 &w, Float4 &dsx, Float4 &dsy, Float4 &M, SamplerFunction function);
 	void computeLod3D(Pointer<Byte> &texture, Float &lod, Float4 &u, Float4 &v, Float4 &w, Float4 &dsx, Float4 &dsy, SamplerFunction function);
 	Int4 cubeFace(Float4 &U, Float4 &V, Float4 &x, Float4 &y, Float4 &z, Float4 &M);
diff --git a/src/Pipeline/SpirvShader.hpp b/src/Pipeline/SpirvShader.hpp
index aa85d98..29248fa 100644
--- a/src/Pipeline/SpirvShader.hpp
+++ b/src/Pipeline/SpirvShader.hpp
@@ -1272,7 +1272,7 @@
 	static std::shared_ptr<rr::Routine> emitSamplerRoutine(ImageInstruction instruction, const Sampler &samplerState);
 
 	// TODO(b/129523279): Eliminate conversion and use vk::Sampler members directly.
-	static sw::FilterType convertFilterMode(const vk::Sampler *sampler);
+	static sw::FilterType convertFilterMode(const vk::Sampler *sampler, VkImageViewType imageViewType, ImageInstruction instruction);
 	static sw::MipmapType convertMipmapMode(const vk::Sampler *sampler);
 	static sw::AddressingMode convertAddressingMode(int coordinateIndex, const vk::Sampler *sampler, VkImageViewType imageViewType);
 
diff --git a/src/Pipeline/SpirvShaderSampling.cpp b/src/Pipeline/SpirvShaderSampling.cpp
index 53c7182..2e0858d 100644
--- a/src/Pipeline/SpirvShaderSampling.cpp
+++ b/src/Pipeline/SpirvShaderSampling.cpp
@@ -58,7 +58,7 @@
 
 		if(sampler)
 		{
-			samplerState.textureFilter = (instruction.samplerMethod == Gather) ? FILTER_GATHER : convertFilterMode(sampler);
+			samplerState.textureFilter = convertFilterMode(sampler, type, instruction);
 			samplerState.border = sampler->borderColor;
 
 			samplerState.mipmapFilter = convertMipmapMode(sampler);
@@ -185,13 +185,6 @@
 				dPdy.y = Pointer<Float>(&dsy.y)[i];
 				dPdy.z = Pointer<Float>(&dsy.z)[i];
 
-				// 1D textures are treated as 2D texture with second coordinate 0, so we also need to zero out the second grad component. TODO(b/134669567)
-				if(samplerState.textureType == VK_IMAGE_VIEW_TYPE_1D || samplerState.textureType == VK_IMAGE_VIEW_TYPE_1D_ARRAY)
-				{
-					dPdx.y = Float(0.0f);
-					dPdy.y = Float(0.0f);
-				}
-
 				Vector4f sample = s.sampleTexture(texture, uvwa, dRef, lod[i], dPdx, dPdy, offset, sampleId, samplerFunction);
 
 				Pointer<Float> rgba = out;
@@ -216,11 +209,27 @@
 	return function("sampler");
 }
 
-sw::FilterType SpirvShader::convertFilterMode(const vk::Sampler *sampler)
+sw::FilterType SpirvShader::convertFilterMode(const vk::Sampler *sampler, VkImageViewType imageViewType, ImageInstruction instruction)
 {
+	if(instruction.samplerMethod == Gather)
+	{
+		return FILTER_GATHER;
+	}
+
+	if(instruction.samplerMethod == Fetch)
+	{
+		return FILTER_POINT;
+	}
+
 	if(sampler->anisotropyEnable != VK_FALSE)
 	{
-		return FILTER_ANISOTROPIC;
+		if(imageViewType == VK_IMAGE_VIEW_TYPE_2D || imageViewType == VK_IMAGE_VIEW_TYPE_2D_ARRAY)
+		{
+			if(instruction.samplerMethod != Lod)  // TODO(b/162926129): Support anisotropic filtering with explicit LOD.
+			{
+				return FILTER_ANISOTROPIC;
+			}
+		}
 	}
 
 	switch(sampler->magFilter)