xref: /aosp_15_r20/external/swiftshader/src/Pipeline/SpirvShaderImage.cpp (revision 03ce13f70fcc45d86ee91b7ee4cab1936a95046e)
1*03ce13f7SAndroid Build Coastguard Worker // Copyright 2019 The SwiftShader Authors. All Rights Reserved.
2*03ce13f7SAndroid Build Coastguard Worker //
3*03ce13f7SAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License");
4*03ce13f7SAndroid Build Coastguard Worker // you may not use this file except in compliance with the License.
5*03ce13f7SAndroid Build Coastguard Worker // You may obtain a copy of the License at
6*03ce13f7SAndroid Build Coastguard Worker //
7*03ce13f7SAndroid Build Coastguard Worker //    http://www.apache.org/licenses/LICENSE-2.0
8*03ce13f7SAndroid Build Coastguard Worker //
9*03ce13f7SAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*03ce13f7SAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
11*03ce13f7SAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*03ce13f7SAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
13*03ce13f7SAndroid Build Coastguard Worker // limitations under the License.
14*03ce13f7SAndroid Build Coastguard Worker 
15*03ce13f7SAndroid Build Coastguard Worker #include "SpirvShader.hpp"
16*03ce13f7SAndroid Build Coastguard Worker 
17*03ce13f7SAndroid Build Coastguard Worker #include "System/Types.hpp"
18*03ce13f7SAndroid Build Coastguard Worker 
19*03ce13f7SAndroid Build Coastguard Worker #include "Vulkan/VkDescriptorSetLayout.hpp"
20*03ce13f7SAndroid Build Coastguard Worker #include "Vulkan/VkPipelineLayout.hpp"
21*03ce13f7SAndroid Build Coastguard Worker 
22*03ce13f7SAndroid Build Coastguard Worker #include <spirv/unified1/spirv.hpp>
23*03ce13f7SAndroid Build Coastguard Worker 
24*03ce13f7SAndroid Build Coastguard Worker namespace sw {
25*03ce13f7SAndroid Build Coastguard Worker 
SpirvFormatToVulkanFormat(spv::ImageFormat format)26*03ce13f7SAndroid Build Coastguard Worker static vk::Format SpirvFormatToVulkanFormat(spv::ImageFormat format)
27*03ce13f7SAndroid Build Coastguard Worker {
28*03ce13f7SAndroid Build Coastguard Worker 	switch(format)
29*03ce13f7SAndroid Build Coastguard Worker 	{
30*03ce13f7SAndroid Build Coastguard Worker 	case spv::ImageFormatUnknown: return VK_FORMAT_UNDEFINED;
31*03ce13f7SAndroid Build Coastguard Worker 	case spv::ImageFormatRgba32f: return VK_FORMAT_R32G32B32A32_SFLOAT;
32*03ce13f7SAndroid Build Coastguard Worker 	case spv::ImageFormatRgba16f: return VK_FORMAT_R16G16B16A16_SFLOAT;
33*03ce13f7SAndroid Build Coastguard Worker 	case spv::ImageFormatR32f: return VK_FORMAT_R32_SFLOAT;
34*03ce13f7SAndroid Build Coastguard Worker 	case spv::ImageFormatRgba8: return VK_FORMAT_R8G8B8A8_UNORM;
35*03ce13f7SAndroid Build Coastguard Worker 	case spv::ImageFormatRgba8Snorm: return VK_FORMAT_R8G8B8A8_SNORM;
36*03ce13f7SAndroid Build Coastguard Worker 	case spv::ImageFormatRg32f: return VK_FORMAT_R32G32_SFLOAT;
37*03ce13f7SAndroid Build Coastguard Worker 	case spv::ImageFormatRg16f: return VK_FORMAT_R16G16_SFLOAT;
38*03ce13f7SAndroid Build Coastguard Worker 	case spv::ImageFormatR11fG11fB10f: return VK_FORMAT_B10G11R11_UFLOAT_PACK32;
39*03ce13f7SAndroid Build Coastguard Worker 	case spv::ImageFormatR16f: return VK_FORMAT_R16_SFLOAT;
40*03ce13f7SAndroid Build Coastguard Worker 	case spv::ImageFormatRgba16: return VK_FORMAT_R16G16B16A16_UNORM;
41*03ce13f7SAndroid Build Coastguard Worker 	case spv::ImageFormatRgb10A2: return VK_FORMAT_A2B10G10R10_UNORM_PACK32;
42*03ce13f7SAndroid Build Coastguard Worker 	case spv::ImageFormatRg16: return VK_FORMAT_R16G16_UNORM;
43*03ce13f7SAndroid Build Coastguard Worker 	case spv::ImageFormatRg8: return VK_FORMAT_R8G8_UNORM;
44*03ce13f7SAndroid Build Coastguard Worker 	case spv::ImageFormatR16: return VK_FORMAT_R16_UNORM;
45*03ce13f7SAndroid Build Coastguard Worker 	case spv::ImageFormatR8: return VK_FORMAT_R8_UNORM;
46*03ce13f7SAndroid Build Coastguard Worker 	case spv::ImageFormatRgba16Snorm: return VK_FORMAT_R16G16B16A16_SNORM;
47*03ce13f7SAndroid Build Coastguard Worker 	case spv::ImageFormatRg16Snorm: return VK_FORMAT_R16G16_SNORM;
48*03ce13f7SAndroid Build Coastguard Worker 	case spv::ImageFormatRg8Snorm: return VK_FORMAT_R8G8_SNORM;
49*03ce13f7SAndroid Build Coastguard Worker 	case spv::ImageFormatR16Snorm: return VK_FORMAT_R16_SNORM;
50*03ce13f7SAndroid Build Coastguard Worker 	case spv::ImageFormatR8Snorm: return VK_FORMAT_R8_SNORM;
51*03ce13f7SAndroid Build Coastguard Worker 	case spv::ImageFormatRgba32i: return VK_FORMAT_R32G32B32A32_SINT;
52*03ce13f7SAndroid Build Coastguard Worker 	case spv::ImageFormatRgba16i: return VK_FORMAT_R16G16B16A16_SINT;
53*03ce13f7SAndroid Build Coastguard Worker 	case spv::ImageFormatRgba8i: return VK_FORMAT_R8G8B8A8_SINT;
54*03ce13f7SAndroid Build Coastguard Worker 	case spv::ImageFormatR32i: return VK_FORMAT_R32_SINT;
55*03ce13f7SAndroid Build Coastguard Worker 	case spv::ImageFormatRg32i: return VK_FORMAT_R32G32_SINT;
56*03ce13f7SAndroid Build Coastguard Worker 	case spv::ImageFormatRg16i: return VK_FORMAT_R16G16_SINT;
57*03ce13f7SAndroid Build Coastguard Worker 	case spv::ImageFormatRg8i: return VK_FORMAT_R8G8_SINT;
58*03ce13f7SAndroid Build Coastguard Worker 	case spv::ImageFormatR16i: return VK_FORMAT_R16_SINT;
59*03ce13f7SAndroid Build Coastguard Worker 	case spv::ImageFormatR8i: return VK_FORMAT_R8_SINT;
60*03ce13f7SAndroid Build Coastguard Worker 	case spv::ImageFormatRgba32ui: return VK_FORMAT_R32G32B32A32_UINT;
61*03ce13f7SAndroid Build Coastguard Worker 	case spv::ImageFormatRgba16ui: return VK_FORMAT_R16G16B16A16_UINT;
62*03ce13f7SAndroid Build Coastguard Worker 	case spv::ImageFormatRgba8ui: return VK_FORMAT_R8G8B8A8_UINT;
63*03ce13f7SAndroid Build Coastguard Worker 	case spv::ImageFormatR32ui: return VK_FORMAT_R32_UINT;
64*03ce13f7SAndroid Build Coastguard Worker 	case spv::ImageFormatRgb10a2ui: return VK_FORMAT_A2B10G10R10_UINT_PACK32;
65*03ce13f7SAndroid Build Coastguard Worker 	case spv::ImageFormatRg32ui: return VK_FORMAT_R32G32_UINT;
66*03ce13f7SAndroid Build Coastguard Worker 	case spv::ImageFormatRg16ui: return VK_FORMAT_R16G16_UINT;
67*03ce13f7SAndroid Build Coastguard Worker 	case spv::ImageFormatRg8ui: return VK_FORMAT_R8G8_UINT;
68*03ce13f7SAndroid Build Coastguard Worker 	case spv::ImageFormatR16ui: return VK_FORMAT_R16_UINT;
69*03ce13f7SAndroid Build Coastguard Worker 	case spv::ImageFormatR8ui: return VK_FORMAT_R8_UINT;
70*03ce13f7SAndroid Build Coastguard Worker 
71*03ce13f7SAndroid Build Coastguard Worker 	default:
72*03ce13f7SAndroid Build Coastguard Worker 		UNSUPPORTED("SPIR-V ImageFormat %u", format);
73*03ce13f7SAndroid Build Coastguard Worker 		return VK_FORMAT_UNDEFINED;
74*03ce13f7SAndroid Build Coastguard Worker 	}
75*03ce13f7SAndroid Build Coastguard Worker }
76*03ce13f7SAndroid Build Coastguard Worker 
ImageInstruction(InsnIterator insn,const Spirv & shader,const SpirvEmitter & state)77*03ce13f7SAndroid Build Coastguard Worker SpirvEmitter::ImageInstruction::ImageInstruction(InsnIterator insn, const Spirv &shader, const SpirvEmitter &state)
78*03ce13f7SAndroid Build Coastguard Worker     : ImageInstructionSignature(parseVariantAndMethod(insn))
79*03ce13f7SAndroid Build Coastguard Worker     , position(insn.distanceFrom(shader.begin()))
80*03ce13f7SAndroid Build Coastguard Worker {
81*03ce13f7SAndroid Build Coastguard Worker 	if(samplerMethod == Write)
82*03ce13f7SAndroid Build Coastguard Worker 	{
83*03ce13f7SAndroid Build Coastguard Worker 		imageId = insn.word(1);
84*03ce13f7SAndroid Build Coastguard Worker 		coordinateId = insn.word(2);
85*03ce13f7SAndroid Build Coastguard Worker 		texelId = insn.word(3);
86*03ce13f7SAndroid Build Coastguard Worker 	}
87*03ce13f7SAndroid Build Coastguard Worker 	else
88*03ce13f7SAndroid Build Coastguard Worker 	{
89*03ce13f7SAndroid Build Coastguard Worker 		resultTypeId = insn.resultTypeId();  // word(1)
90*03ce13f7SAndroid Build Coastguard Worker 		resultId = insn.resultId();          // word(2)
91*03ce13f7SAndroid Build Coastguard Worker 
92*03ce13f7SAndroid Build Coastguard Worker 		if(samplerMethod == Fetch || samplerMethod == Read || samplerMethod == TexelPointer)  // Samplerless
93*03ce13f7SAndroid Build Coastguard Worker 		{
94*03ce13f7SAndroid Build Coastguard Worker 			imageId = insn.word(3);
95*03ce13f7SAndroid Build Coastguard Worker 		}
96*03ce13f7SAndroid Build Coastguard Worker 		else
97*03ce13f7SAndroid Build Coastguard Worker 		{
98*03ce13f7SAndroid Build Coastguard Worker 			// sampledImageId is either the result of an OpSampledImage instruction or
99*03ce13f7SAndroid Build Coastguard Worker 			// an externally combined sampler and image.
100*03ce13f7SAndroid Build Coastguard Worker 			Object::ID sampledImageId = insn.word(3);
101*03ce13f7SAndroid Build Coastguard Worker 
102*03ce13f7SAndroid Build Coastguard Worker 			if(state.isSampledImage(sampledImageId))  // Result of an OpSampledImage instruction
103*03ce13f7SAndroid Build Coastguard Worker 			{
104*03ce13f7SAndroid Build Coastguard Worker 				const SampledImagePointer &sampledImage = state.getSampledImage(sampledImageId);
105*03ce13f7SAndroid Build Coastguard Worker 				imageId = shader.getObject(sampledImageId).definition.word(3);
106*03ce13f7SAndroid Build Coastguard Worker 				samplerId = sampledImage.samplerId;
107*03ce13f7SAndroid Build Coastguard Worker 			}
108*03ce13f7SAndroid Build Coastguard Worker 			else  // Combined image/sampler
109*03ce13f7SAndroid Build Coastguard Worker 			{
110*03ce13f7SAndroid Build Coastguard Worker 				imageId = sampledImageId;
111*03ce13f7SAndroid Build Coastguard Worker 				samplerId = sampledImageId;
112*03ce13f7SAndroid Build Coastguard Worker 			}
113*03ce13f7SAndroid Build Coastguard Worker 		}
114*03ce13f7SAndroid Build Coastguard Worker 
115*03ce13f7SAndroid Build Coastguard Worker 		coordinateId = insn.word(4);
116*03ce13f7SAndroid Build Coastguard Worker 	}
117*03ce13f7SAndroid Build Coastguard Worker 
118*03ce13f7SAndroid Build Coastguard Worker 	// `imageId` can represent either a Sampled Image, a samplerless Image, or a pointer to an Image.
119*03ce13f7SAndroid Build Coastguard Worker 	// To get to the OpTypeImage operands, traverse the OpTypeSampledImage or OpTypePointer.
120*03ce13f7SAndroid Build Coastguard Worker 	const Type &imageObjectType = shader.getObjectType(imageId);
121*03ce13f7SAndroid Build Coastguard Worker 	const Type &imageReferenceType = (imageObjectType.opcode() == spv::OpTypeSampledImage)
122*03ce13f7SAndroid Build Coastguard Worker 	                                     ? shader.getType(imageObjectType.definition.word(2))
123*03ce13f7SAndroid Build Coastguard Worker 	                                     : imageObjectType;
124*03ce13f7SAndroid Build Coastguard Worker 	const Type &imageType = ((imageReferenceType.opcode() == spv::OpTypePointer)
125*03ce13f7SAndroid Build Coastguard Worker 	                             ? shader.getType(imageReferenceType.element)
126*03ce13f7SAndroid Build Coastguard Worker 	                             : imageReferenceType);
127*03ce13f7SAndroid Build Coastguard Worker 
128*03ce13f7SAndroid Build Coastguard Worker 	ASSERT(imageType.opcode() == spv::OpTypeImage);
129*03ce13f7SAndroid Build Coastguard Worker 	dim = imageType.definition.word(3);
130*03ce13f7SAndroid Build Coastguard Worker 	arrayed = imageType.definition.word(5);
131*03ce13f7SAndroid Build Coastguard Worker 	imageFormat = imageType.definition.word(8);
132*03ce13f7SAndroid Build Coastguard Worker 
133*03ce13f7SAndroid Build Coastguard Worker 	const Object &coordinateObject = shader.getObject(coordinateId);
134*03ce13f7SAndroid Build Coastguard Worker 	const Type &coordinateType = shader.getType(coordinateObject);
135*03ce13f7SAndroid Build Coastguard Worker 	coordinates = coordinateType.componentCount - (isProj() ? 1 : 0);
136*03ce13f7SAndroid Build Coastguard Worker 
137*03ce13f7SAndroid Build Coastguard Worker 	if(samplerMethod == TexelPointer)
138*03ce13f7SAndroid Build Coastguard Worker 	{
139*03ce13f7SAndroid Build Coastguard Worker 		sampleId = insn.word(5);
140*03ce13f7SAndroid Build Coastguard Worker 		sample = !shader.getObject(sampleId).isConstantZero();
141*03ce13f7SAndroid Build Coastguard Worker 	}
142*03ce13f7SAndroid Build Coastguard Worker 
143*03ce13f7SAndroid Build Coastguard Worker 	if(isDref())
144*03ce13f7SAndroid Build Coastguard Worker 	{
145*03ce13f7SAndroid Build Coastguard Worker 		drefId = insn.word(5);
146*03ce13f7SAndroid Build Coastguard Worker 	}
147*03ce13f7SAndroid Build Coastguard Worker 
148*03ce13f7SAndroid Build Coastguard Worker 	if(samplerMethod == Gather)
149*03ce13f7SAndroid Build Coastguard Worker 	{
150*03ce13f7SAndroid Build Coastguard Worker 		gatherComponent = !isDref() ? shader.getObject(insn.word(5)).constantValue[0] : 0;
151*03ce13f7SAndroid Build Coastguard Worker 	}
152*03ce13f7SAndroid Build Coastguard Worker 
153*03ce13f7SAndroid Build Coastguard Worker 	uint32_t operandsIndex = getImageOperandsIndex(insn);
154*03ce13f7SAndroid Build Coastguard Worker 	uint32_t imageOperands = (operandsIndex != 0) ? insn.word(operandsIndex) : 0;  // The mask which indicates which operands are provided.
155*03ce13f7SAndroid Build Coastguard Worker 
156*03ce13f7SAndroid Build Coastguard Worker 	operandsIndex += 1;  // Advance to the first actual operand <id> location.
157*03ce13f7SAndroid Build Coastguard Worker 
158*03ce13f7SAndroid Build Coastguard Worker 	if(imageOperands & spv::ImageOperandsBiasMask)
159*03ce13f7SAndroid Build Coastguard Worker 	{
160*03ce13f7SAndroid Build Coastguard Worker 		ASSERT(samplerMethod == Bias);
161*03ce13f7SAndroid Build Coastguard Worker 		lodOrBiasId = insn.word(operandsIndex);
162*03ce13f7SAndroid Build Coastguard Worker 		operandsIndex += 1;
163*03ce13f7SAndroid Build Coastguard Worker 		imageOperands &= ~spv::ImageOperandsBiasMask;
164*03ce13f7SAndroid Build Coastguard Worker 	}
165*03ce13f7SAndroid Build Coastguard Worker 
166*03ce13f7SAndroid Build Coastguard Worker 	if(imageOperands & spv::ImageOperandsLodMask)
167*03ce13f7SAndroid Build Coastguard Worker 	{
168*03ce13f7SAndroid Build Coastguard Worker 		ASSERT(samplerMethod == Lod || samplerMethod == Fetch);
169*03ce13f7SAndroid Build Coastguard Worker 		lodOrBiasId = insn.word(operandsIndex);
170*03ce13f7SAndroid Build Coastguard Worker 		operandsIndex += 1;
171*03ce13f7SAndroid Build Coastguard Worker 		imageOperands &= ~spv::ImageOperandsLodMask;
172*03ce13f7SAndroid Build Coastguard Worker 	}
173*03ce13f7SAndroid Build Coastguard Worker 
174*03ce13f7SAndroid Build Coastguard Worker 	if(imageOperands & spv::ImageOperandsGradMask)
175*03ce13f7SAndroid Build Coastguard Worker 	{
176*03ce13f7SAndroid Build Coastguard Worker 		ASSERT(samplerMethod == Grad);
177*03ce13f7SAndroid Build Coastguard Worker 		gradDxId = insn.word(operandsIndex + 0);
178*03ce13f7SAndroid Build Coastguard Worker 		gradDyId = insn.word(operandsIndex + 1);
179*03ce13f7SAndroid Build Coastguard Worker 		operandsIndex += 2;
180*03ce13f7SAndroid Build Coastguard Worker 		imageOperands &= ~spv::ImageOperandsGradMask;
181*03ce13f7SAndroid Build Coastguard Worker 
182*03ce13f7SAndroid Build Coastguard Worker 		grad = shader.getObjectType(gradDxId).componentCount;
183*03ce13f7SAndroid Build Coastguard Worker 	}
184*03ce13f7SAndroid Build Coastguard Worker 
185*03ce13f7SAndroid Build Coastguard Worker 	if(imageOperands & spv::ImageOperandsConstOffsetMask)
186*03ce13f7SAndroid Build Coastguard Worker 	{
187*03ce13f7SAndroid Build Coastguard Worker 		offsetId = insn.word(operandsIndex);
188*03ce13f7SAndroid Build Coastguard Worker 		operandsIndex += 1;
189*03ce13f7SAndroid Build Coastguard Worker 		imageOperands &= ~spv::ImageOperandsConstOffsetMask;
190*03ce13f7SAndroid Build Coastguard Worker 
191*03ce13f7SAndroid Build Coastguard Worker 		offset = shader.getObjectType(offsetId).componentCount;
192*03ce13f7SAndroid Build Coastguard Worker 	}
193*03ce13f7SAndroid Build Coastguard Worker 
194*03ce13f7SAndroid Build Coastguard Worker 	if(imageOperands & spv::ImageOperandsSampleMask)
195*03ce13f7SAndroid Build Coastguard Worker 	{
196*03ce13f7SAndroid Build Coastguard Worker 		ASSERT(samplerMethod == Fetch || samplerMethod == Read || samplerMethod == Write);
197*03ce13f7SAndroid Build Coastguard Worker 		sampleId = insn.word(operandsIndex);
198*03ce13f7SAndroid Build Coastguard Worker 		operandsIndex += 1;
199*03ce13f7SAndroid Build Coastguard Worker 		imageOperands &= ~spv::ImageOperandsSampleMask;
200*03ce13f7SAndroid Build Coastguard Worker 
201*03ce13f7SAndroid Build Coastguard Worker 		sample = !shader.getObject(sampleId).isConstantZero();
202*03ce13f7SAndroid Build Coastguard Worker 	}
203*03ce13f7SAndroid Build Coastguard Worker 
204*03ce13f7SAndroid Build Coastguard Worker 	// TODO(b/174475384)
205*03ce13f7SAndroid Build Coastguard Worker 	if(imageOperands & spv::ImageOperandsZeroExtendMask)
206*03ce13f7SAndroid Build Coastguard Worker 	{
207*03ce13f7SAndroid Build Coastguard Worker 		ASSERT(samplerMethod == Read || samplerMethod == Write);
208*03ce13f7SAndroid Build Coastguard Worker 		imageOperands &= ~spv::ImageOperandsZeroExtendMask;
209*03ce13f7SAndroid Build Coastguard Worker 	}
210*03ce13f7SAndroid Build Coastguard Worker 	else if(imageOperands & spv::ImageOperandsSignExtendMask)
211*03ce13f7SAndroid Build Coastguard Worker 	{
212*03ce13f7SAndroid Build Coastguard Worker 		ASSERT(samplerMethod == Read || samplerMethod == Write);
213*03ce13f7SAndroid Build Coastguard Worker 		imageOperands &= ~spv::ImageOperandsSignExtendMask;
214*03ce13f7SAndroid Build Coastguard Worker 	}
215*03ce13f7SAndroid Build Coastguard Worker 
216*03ce13f7SAndroid Build Coastguard Worker 	[[maybe_unused]] spv::Scope scope = spv::ScopeCrossDevice;  // "Whilst the CrossDevice scope is defined in SPIR-V, it is disallowed in Vulkan."
217*03ce13f7SAndroid Build Coastguard Worker 
218*03ce13f7SAndroid Build Coastguard Worker 	if(imageOperands & spv::ImageOperandsMakeTexelAvailableMask)
219*03ce13f7SAndroid Build Coastguard Worker 	{
220*03ce13f7SAndroid Build Coastguard Worker 		scope = static_cast<spv::Scope>(insn.word(operandsIndex));
221*03ce13f7SAndroid Build Coastguard Worker 		operandsIndex += 1;
222*03ce13f7SAndroid Build Coastguard Worker 		imageOperands &= ~spv::ImageOperandsMakeTexelAvailableMask;
223*03ce13f7SAndroid Build Coastguard Worker 	}
224*03ce13f7SAndroid Build Coastguard Worker 
225*03ce13f7SAndroid Build Coastguard Worker 	if(imageOperands & spv::ImageOperandsMakeTexelVisibleMask)
226*03ce13f7SAndroid Build Coastguard Worker 	{
227*03ce13f7SAndroid Build Coastguard Worker 		scope = static_cast<spv::Scope>(insn.word(operandsIndex));
228*03ce13f7SAndroid Build Coastguard Worker 		operandsIndex += 1;
229*03ce13f7SAndroid Build Coastguard Worker 		imageOperands &= ~spv::ImageOperandsMakeTexelVisibleMask;
230*03ce13f7SAndroid Build Coastguard Worker 	}
231*03ce13f7SAndroid Build Coastguard Worker 
232*03ce13f7SAndroid Build Coastguard Worker 	if(imageOperands & spv::ImageOperandsNonPrivateTexelMask)
233*03ce13f7SAndroid Build Coastguard Worker 	{
234*03ce13f7SAndroid Build Coastguard Worker 		imageOperands &= ~spv::ImageOperandsNonPrivateTexelMask;
235*03ce13f7SAndroid Build Coastguard Worker 	}
236*03ce13f7SAndroid Build Coastguard Worker 
237*03ce13f7SAndroid Build Coastguard Worker 	if(imageOperands & spv::ImageOperandsVolatileTexelMask)
238*03ce13f7SAndroid Build Coastguard Worker 	{
239*03ce13f7SAndroid Build Coastguard Worker 		UNIMPLEMENTED("b/176819536");
240*03ce13f7SAndroid Build Coastguard Worker 		imageOperands &= ~spv::ImageOperandsVolatileTexelMask;
241*03ce13f7SAndroid Build Coastguard Worker 	}
242*03ce13f7SAndroid Build Coastguard Worker 
243*03ce13f7SAndroid Build Coastguard Worker 	if(imageOperands & spv::ImageOperandsNontemporalMask)
244*03ce13f7SAndroid Build Coastguard Worker 	{
245*03ce13f7SAndroid Build Coastguard Worker 		// Hints that the accessed texels are not likely
246*03ce13f7SAndroid Build Coastguard Worker 		// to be accessed again in the near future.
247*03ce13f7SAndroid Build Coastguard Worker 		imageOperands &= ~spv::ImageOperandsNontemporalMask;
248*03ce13f7SAndroid Build Coastguard Worker 	}
249*03ce13f7SAndroid Build Coastguard Worker 
250*03ce13f7SAndroid Build Coastguard Worker 	// There should be no remaining image operands.
251*03ce13f7SAndroid Build Coastguard Worker 	if(imageOperands != 0)
252*03ce13f7SAndroid Build Coastguard Worker 	{
253*03ce13f7SAndroid Build Coastguard Worker 		UNSUPPORTED("Image operands 0x%08X", imageOperands);
254*03ce13f7SAndroid Build Coastguard Worker 	}
255*03ce13f7SAndroid Build Coastguard Worker }
256*03ce13f7SAndroid Build Coastguard Worker 
parseVariantAndMethod(InsnIterator insn)257*03ce13f7SAndroid Build Coastguard Worker SpirvEmitter::ImageInstructionSignature SpirvEmitter::ImageInstruction::parseVariantAndMethod(InsnIterator insn)
258*03ce13f7SAndroid Build Coastguard Worker {
259*03ce13f7SAndroid Build Coastguard Worker 	uint32_t imageOperands = getImageOperandsMask(insn);
260*03ce13f7SAndroid Build Coastguard Worker 	bool bias = imageOperands & spv::ImageOperandsBiasMask;
261*03ce13f7SAndroid Build Coastguard Worker 	bool grad = imageOperands & spv::ImageOperandsGradMask;
262*03ce13f7SAndroid Build Coastguard Worker 
263*03ce13f7SAndroid Build Coastguard Worker 	switch(insn.opcode())
264*03ce13f7SAndroid Build Coastguard Worker 	{
265*03ce13f7SAndroid Build Coastguard Worker 	case spv::OpImageSampleImplicitLod: return { None, bias ? Bias : Implicit };
266*03ce13f7SAndroid Build Coastguard Worker 	case spv::OpImageSampleExplicitLod: return { None, grad ? Grad : Lod };
267*03ce13f7SAndroid Build Coastguard Worker 	case spv::OpImageSampleDrefImplicitLod: return { Dref, bias ? Bias : Implicit };
268*03ce13f7SAndroid Build Coastguard Worker 	case spv::OpImageSampleDrefExplicitLod: return { Dref, grad ? Grad : Lod };
269*03ce13f7SAndroid Build Coastguard Worker 	case spv::OpImageSampleProjImplicitLod: return { Proj, bias ? Bias : Implicit };
270*03ce13f7SAndroid Build Coastguard Worker 	case spv::OpImageSampleProjExplicitLod: return { Proj, grad ? Grad : Lod };
271*03ce13f7SAndroid Build Coastguard Worker 	case spv::OpImageSampleProjDrefImplicitLod: return { ProjDref, bias ? Bias : Implicit };
272*03ce13f7SAndroid Build Coastguard Worker 	case spv::OpImageSampleProjDrefExplicitLod: return { ProjDref, grad ? Grad : Lod };
273*03ce13f7SAndroid Build Coastguard Worker 	case spv::OpImageGather: return { None, Gather };
274*03ce13f7SAndroid Build Coastguard Worker 	case spv::OpImageDrefGather: return { Dref, Gather };
275*03ce13f7SAndroid Build Coastguard Worker 	case spv::OpImageFetch: return { None, Fetch };
276*03ce13f7SAndroid Build Coastguard Worker 	case spv::OpImageQueryLod: return { None, Query };
277*03ce13f7SAndroid Build Coastguard Worker 	case spv::OpImageRead: return { None, Read };
278*03ce13f7SAndroid Build Coastguard Worker 	case spv::OpImageWrite: return { None, Write };
279*03ce13f7SAndroid Build Coastguard Worker 	case spv::OpImageTexelPointer: return { None, TexelPointer };
280*03ce13f7SAndroid Build Coastguard Worker 
281*03ce13f7SAndroid Build Coastguard Worker 	default:
282*03ce13f7SAndroid Build Coastguard Worker 		ASSERT(false);
283*03ce13f7SAndroid Build Coastguard Worker 		return { None, Implicit };
284*03ce13f7SAndroid Build Coastguard Worker 	}
285*03ce13f7SAndroid Build Coastguard Worker }
286*03ce13f7SAndroid Build Coastguard Worker 
287*03ce13f7SAndroid Build Coastguard Worker // Returns the instruction word index at which the Image Operands mask is located, or 0 if not present.
getImageOperandsIndex(InsnIterator insn)288*03ce13f7SAndroid Build Coastguard Worker uint32_t SpirvEmitter::ImageInstruction::getImageOperandsIndex(InsnIterator insn)
289*03ce13f7SAndroid Build Coastguard Worker {
290*03ce13f7SAndroid Build Coastguard Worker 	switch(insn.opcode())
291*03ce13f7SAndroid Build Coastguard Worker 	{
292*03ce13f7SAndroid Build Coastguard Worker 	case spv::OpImageSampleImplicitLod:
293*03ce13f7SAndroid Build Coastguard Worker 	case spv::OpImageSampleProjImplicitLod:
294*03ce13f7SAndroid Build Coastguard Worker 		return insn.wordCount() > 5 ? 5 : 0;  // Optional
295*03ce13f7SAndroid Build Coastguard Worker 	case spv::OpImageSampleExplicitLod:
296*03ce13f7SAndroid Build Coastguard Worker 	case spv::OpImageSampleProjExplicitLod:
297*03ce13f7SAndroid Build Coastguard Worker 		return 5;  // "Either Lod or Grad image operands must be present."
298*03ce13f7SAndroid Build Coastguard Worker 	case spv::OpImageSampleDrefImplicitLod:
299*03ce13f7SAndroid Build Coastguard Worker 	case spv::OpImageSampleProjDrefImplicitLod:
300*03ce13f7SAndroid Build Coastguard Worker 		return insn.wordCount() > 6 ? 6 : 0;  // Optional
301*03ce13f7SAndroid Build Coastguard Worker 	case spv::OpImageSampleDrefExplicitLod:
302*03ce13f7SAndroid Build Coastguard Worker 	case spv::OpImageSampleProjDrefExplicitLod:
303*03ce13f7SAndroid Build Coastguard Worker 		return 6;  // "Either Lod or Grad image operands must be present."
304*03ce13f7SAndroid Build Coastguard Worker 	case spv::OpImageGather:
305*03ce13f7SAndroid Build Coastguard Worker 	case spv::OpImageDrefGather:
306*03ce13f7SAndroid Build Coastguard Worker 		return insn.wordCount() > 6 ? 6 : 0;  // Optional
307*03ce13f7SAndroid Build Coastguard Worker 	case spv::OpImageFetch:
308*03ce13f7SAndroid Build Coastguard Worker 		return insn.wordCount() > 5 ? 5 : 0;  // Optional
309*03ce13f7SAndroid Build Coastguard Worker 	case spv::OpImageQueryLod:
310*03ce13f7SAndroid Build Coastguard Worker 		ASSERT(insn.wordCount() == 5);
311*03ce13f7SAndroid Build Coastguard Worker 		return 0;  // No image operands.
312*03ce13f7SAndroid Build Coastguard Worker 	case spv::OpImageRead:
313*03ce13f7SAndroid Build Coastguard Worker 		return insn.wordCount() > 5 ? 5 : 0;  // Optional
314*03ce13f7SAndroid Build Coastguard Worker 	case spv::OpImageWrite:
315*03ce13f7SAndroid Build Coastguard Worker 		return insn.wordCount() > 4 ? 4 : 0;  // Optional
316*03ce13f7SAndroid Build Coastguard Worker 	case spv::OpImageTexelPointer:
317*03ce13f7SAndroid Build Coastguard Worker 		ASSERT(insn.wordCount() == 6);
318*03ce13f7SAndroid Build Coastguard Worker 		return 0;  // No image operands.
319*03ce13f7SAndroid Build Coastguard Worker 
320*03ce13f7SAndroid Build Coastguard Worker 	default:
321*03ce13f7SAndroid Build Coastguard Worker 		ASSERT(false);
322*03ce13f7SAndroid Build Coastguard Worker 		return 0;
323*03ce13f7SAndroid Build Coastguard Worker 	}
324*03ce13f7SAndroid Build Coastguard Worker }
325*03ce13f7SAndroid Build Coastguard Worker 
getImageOperandsMask(InsnIterator insn)326*03ce13f7SAndroid Build Coastguard Worker uint32_t SpirvEmitter::ImageInstruction::getImageOperandsMask(InsnIterator insn)
327*03ce13f7SAndroid Build Coastguard Worker {
328*03ce13f7SAndroid Build Coastguard Worker 	uint32_t operandsIndex = getImageOperandsIndex(insn);
329*03ce13f7SAndroid Build Coastguard Worker 	return (operandsIndex != 0) ? insn.word(operandsIndex) : 0;
330*03ce13f7SAndroid Build Coastguard Worker }
331*03ce13f7SAndroid Build Coastguard Worker 
EmitImageSample(const ImageInstruction & instruction)332*03ce13f7SAndroid Build Coastguard Worker void SpirvEmitter::EmitImageSample(const ImageInstruction &instruction)
333*03ce13f7SAndroid Build Coastguard Worker {
334*03ce13f7SAndroid Build Coastguard Worker 	auto &resultType = shader.getType(instruction.resultTypeId);
335*03ce13f7SAndroid Build Coastguard Worker 	auto &result = createIntermediate(instruction.resultId, resultType.componentCount);
336*03ce13f7SAndroid Build Coastguard Worker 	Array<SIMD::Float> out(4);
337*03ce13f7SAndroid Build Coastguard Worker 
338*03ce13f7SAndroid Build Coastguard Worker 	// TODO(b/153380916): When we're in a code path that is always executed,
339*03ce13f7SAndroid Build Coastguard Worker 	// i.e. post-dominators of the entry block, we don't have to dynamically
340*03ce13f7SAndroid Build Coastguard Worker 	// check whether any lanes are active, and can elide the jump.
341*03ce13f7SAndroid Build Coastguard Worker 	If(AnyTrue(activeLaneMask()))
342*03ce13f7SAndroid Build Coastguard Worker 	{
343*03ce13f7SAndroid Build Coastguard Worker 		EmitImageSampleUnconditional(out, instruction);
344*03ce13f7SAndroid Build Coastguard Worker 	}
345*03ce13f7SAndroid Build Coastguard Worker 
346*03ce13f7SAndroid Build Coastguard Worker 	for(auto i = 0u; i < resultType.componentCount; i++) { result.move(i, out[i]); }
347*03ce13f7SAndroid Build Coastguard Worker }
348*03ce13f7SAndroid Build Coastguard Worker 
EmitImageSampleUnconditional(Array<SIMD::Float> & out,const ImageInstruction & instruction) const349*03ce13f7SAndroid Build Coastguard Worker void SpirvEmitter::EmitImageSampleUnconditional(Array<SIMD::Float> &out, const ImageInstruction &instruction) const
350*03ce13f7SAndroid Build Coastguard Worker {
351*03ce13f7SAndroid Build Coastguard Worker 	auto decorations = shader.GetDecorationsForId(instruction.imageId);
352*03ce13f7SAndroid Build Coastguard Worker 
353*03ce13f7SAndroid Build Coastguard Worker 	if(decorations.NonUniform)
354*03ce13f7SAndroid Build Coastguard Worker 	{
355*03ce13f7SAndroid Build Coastguard Worker 		SIMD::Int activeLaneMask = this->activeLaneMask();
356*03ce13f7SAndroid Build Coastguard Worker 		SIMD::Pointer imagePointer = getImage(instruction.imageId);
357*03ce13f7SAndroid Build Coastguard Worker 		// PerLane output
358*03ce13f7SAndroid Build Coastguard Worker 		for(int laneIdx = 0; laneIdx < SIMD::Width; laneIdx++)
359*03ce13f7SAndroid Build Coastguard Worker 		{
360*03ce13f7SAndroid Build Coastguard Worker 			Array<SIMD::Float> laneOut(out.getArraySize());
361*03ce13f7SAndroid Build Coastguard Worker 			If(Extract(activeLaneMask, laneIdx) != 0)
362*03ce13f7SAndroid Build Coastguard Worker 			{
363*03ce13f7SAndroid Build Coastguard Worker 				Pointer<Byte> imageDescriptor = imagePointer.getPointerForLane(laneIdx);  // vk::SampledImageDescriptor*
364*03ce13f7SAndroid Build Coastguard Worker 				Pointer<Byte> samplerDescriptor = getSamplerDescriptor(imageDescriptor, instruction, laneIdx);
365*03ce13f7SAndroid Build Coastguard Worker 
366*03ce13f7SAndroid Build Coastguard Worker 				Pointer<Byte> samplerFunction = lookupSamplerFunction(imageDescriptor, samplerDescriptor, instruction);
367*03ce13f7SAndroid Build Coastguard Worker 
368*03ce13f7SAndroid Build Coastguard Worker 				callSamplerFunction(samplerFunction, laneOut, imageDescriptor, instruction);
369*03ce13f7SAndroid Build Coastguard Worker 			}
370*03ce13f7SAndroid Build Coastguard Worker 
371*03ce13f7SAndroid Build Coastguard Worker 			for(int outIdx = 0; outIdx < out.getArraySize(); outIdx++)
372*03ce13f7SAndroid Build Coastguard Worker 			{
373*03ce13f7SAndroid Build Coastguard Worker 				out[outIdx] = Insert(out[outIdx], Extract(laneOut[outIdx], laneIdx), laneIdx);
374*03ce13f7SAndroid Build Coastguard Worker 			}
375*03ce13f7SAndroid Build Coastguard Worker 		}
376*03ce13f7SAndroid Build Coastguard Worker 	}
377*03ce13f7SAndroid Build Coastguard Worker 	else
378*03ce13f7SAndroid Build Coastguard Worker 	{
379*03ce13f7SAndroid Build Coastguard Worker 		Pointer<Byte> imageDescriptor = getImage(instruction.imageId).getUniformPointer();  // vk::SampledImageDescriptor*
380*03ce13f7SAndroid Build Coastguard Worker 		Pointer<Byte> samplerDescriptor = getSamplerDescriptor(imageDescriptor, instruction);
381*03ce13f7SAndroid Build Coastguard Worker 
382*03ce13f7SAndroid Build Coastguard Worker 		Pointer<Byte> samplerFunction = lookupSamplerFunction(imageDescriptor, samplerDescriptor, instruction);
383*03ce13f7SAndroid Build Coastguard Worker 
384*03ce13f7SAndroid Build Coastguard Worker 		callSamplerFunction(samplerFunction, out, imageDescriptor, instruction);
385*03ce13f7SAndroid Build Coastguard Worker 	}
386*03ce13f7SAndroid Build Coastguard Worker }
387*03ce13f7SAndroid Build Coastguard Worker 
getSamplerDescriptor(Pointer<Byte> imageDescriptor,const ImageInstruction & instruction) const388*03ce13f7SAndroid Build Coastguard Worker Pointer<Byte> SpirvEmitter::getSamplerDescriptor(Pointer<Byte> imageDescriptor, const ImageInstruction &instruction) const
389*03ce13f7SAndroid Build Coastguard Worker {
390*03ce13f7SAndroid Build Coastguard Worker 	return ((instruction.samplerId == instruction.imageId) || (instruction.samplerId == 0)) ? imageDescriptor : getImage(instruction.samplerId).getUniformPointer();
391*03ce13f7SAndroid Build Coastguard Worker }
392*03ce13f7SAndroid Build Coastguard Worker 
getSamplerDescriptor(Pointer<Byte> imageDescriptor,const ImageInstruction & instruction,int laneIdx) const393*03ce13f7SAndroid Build Coastguard Worker Pointer<Byte> SpirvEmitter::getSamplerDescriptor(Pointer<Byte> imageDescriptor, const ImageInstruction &instruction, int laneIdx) const
394*03ce13f7SAndroid Build Coastguard Worker {
395*03ce13f7SAndroid Build Coastguard Worker 	return ((instruction.samplerId == instruction.imageId) || (instruction.samplerId == 0)) ? imageDescriptor : getImage(instruction.samplerId).getPointerForLane(laneIdx);
396*03ce13f7SAndroid Build Coastguard Worker }
397*03ce13f7SAndroid Build Coastguard Worker 
lookupSamplerFunction(Pointer<Byte> imageDescriptor,Pointer<Byte> samplerDescriptor,const ImageInstruction & instruction) const398*03ce13f7SAndroid Build Coastguard Worker Pointer<Byte> SpirvEmitter::lookupSamplerFunction(Pointer<Byte> imageDescriptor, Pointer<Byte> samplerDescriptor, const ImageInstruction &instruction) const
399*03ce13f7SAndroid Build Coastguard Worker {
400*03ce13f7SAndroid Build Coastguard Worker 	Int samplerId = (instruction.samplerId != 0) ? *Pointer<rr::Int>(samplerDescriptor + OFFSET(vk::SampledImageDescriptor, samplerId)) : Int(0);
401*03ce13f7SAndroid Build Coastguard Worker 
402*03ce13f7SAndroid Build Coastguard Worker 	auto &cache = routine->samplerCache.at(instruction.position);
403*03ce13f7SAndroid Build Coastguard Worker 	Bool cacheHit = (cache.imageDescriptor == imageDescriptor) && (cache.samplerId == samplerId);  // TODO(b/205566405): Skip sampler ID check for samplerless instructions.
404*03ce13f7SAndroid Build Coastguard Worker 
405*03ce13f7SAndroid Build Coastguard Worker 	If(!cacheHit)
406*03ce13f7SAndroid Build Coastguard Worker 	{
407*03ce13f7SAndroid Build Coastguard Worker 		rr::Int imageViewId = *Pointer<rr::Int>(imageDescriptor + OFFSET(vk::ImageDescriptor, imageViewId));
408*03ce13f7SAndroid Build Coastguard Worker 		cache.function = Call(getImageSampler, routine->device, instruction.signature, samplerId, imageViewId);
409*03ce13f7SAndroid Build Coastguard Worker 		cache.imageDescriptor = imageDescriptor;
410*03ce13f7SAndroid Build Coastguard Worker 		cache.samplerId = samplerId;
411*03ce13f7SAndroid Build Coastguard Worker 	}
412*03ce13f7SAndroid Build Coastguard Worker 
413*03ce13f7SAndroid Build Coastguard Worker 	return cache.function;
414*03ce13f7SAndroid Build Coastguard Worker }
415*03ce13f7SAndroid Build Coastguard Worker 
callSamplerFunction(Pointer<Byte> samplerFunction,Array<SIMD::Float> & out,Pointer<Byte> imageDescriptor,const ImageInstruction & instruction) const416*03ce13f7SAndroid Build Coastguard Worker void SpirvEmitter::callSamplerFunction(Pointer<Byte> samplerFunction, Array<SIMD::Float> &out, Pointer<Byte> imageDescriptor, const ImageInstruction &instruction) const
417*03ce13f7SAndroid Build Coastguard Worker {
418*03ce13f7SAndroid Build Coastguard Worker 	Array<SIMD::Float> in(16);  // Maximum 16 input parameter components.
419*03ce13f7SAndroid Build Coastguard Worker 
420*03ce13f7SAndroid Build Coastguard Worker 	auto coordinate = Operand(shader, *this, instruction.coordinateId);
421*03ce13f7SAndroid Build Coastguard Worker 
422*03ce13f7SAndroid Build Coastguard Worker 	uint32_t i = 0;
423*03ce13f7SAndroid Build Coastguard Worker 	for(; i < instruction.coordinates; i++)
424*03ce13f7SAndroid Build Coastguard Worker 	{
425*03ce13f7SAndroid Build Coastguard Worker 		if(instruction.isProj())
426*03ce13f7SAndroid Build Coastguard Worker 		{
427*03ce13f7SAndroid Build Coastguard Worker 			in[i] = coordinate.Float(i) / coordinate.Float(instruction.coordinates);  // TODO(b/129523279): Optimize using reciprocal.
428*03ce13f7SAndroid Build Coastguard Worker 		}
429*03ce13f7SAndroid Build Coastguard Worker 		else
430*03ce13f7SAndroid Build Coastguard Worker 		{
431*03ce13f7SAndroid Build Coastguard Worker 			in[i] = coordinate.Float(i);
432*03ce13f7SAndroid Build Coastguard Worker 		}
433*03ce13f7SAndroid Build Coastguard Worker 	}
434*03ce13f7SAndroid Build Coastguard Worker 
435*03ce13f7SAndroid Build Coastguard Worker 	if(instruction.isDref())
436*03ce13f7SAndroid Build Coastguard Worker 	{
437*03ce13f7SAndroid Build Coastguard Worker 		auto drefValue = Operand(shader, *this, instruction.drefId);
438*03ce13f7SAndroid Build Coastguard Worker 
439*03ce13f7SAndroid Build Coastguard Worker 		if(instruction.isProj())
440*03ce13f7SAndroid Build Coastguard Worker 		{
441*03ce13f7SAndroid Build Coastguard Worker 			in[i] = drefValue.Float(0) / coordinate.Float(instruction.coordinates);  // TODO(b/129523279): Optimize using reciprocal.
442*03ce13f7SAndroid Build Coastguard Worker 		}
443*03ce13f7SAndroid Build Coastguard Worker 		else
444*03ce13f7SAndroid Build Coastguard Worker 		{
445*03ce13f7SAndroid Build Coastguard Worker 			in[i] = drefValue.Float(0);
446*03ce13f7SAndroid Build Coastguard Worker 		}
447*03ce13f7SAndroid Build Coastguard Worker 
448*03ce13f7SAndroid Build Coastguard Worker 		i++;
449*03ce13f7SAndroid Build Coastguard Worker 	}
450*03ce13f7SAndroid Build Coastguard Worker 
451*03ce13f7SAndroid Build Coastguard Worker 	if(instruction.lodOrBiasId != 0)
452*03ce13f7SAndroid Build Coastguard Worker 	{
453*03ce13f7SAndroid Build Coastguard Worker 		auto lodValue = Operand(shader, *this, instruction.lodOrBiasId);
454*03ce13f7SAndroid Build Coastguard Worker 		in[i] = lodValue.Float(0);
455*03ce13f7SAndroid Build Coastguard Worker 		i++;
456*03ce13f7SAndroid Build Coastguard Worker 	}
457*03ce13f7SAndroid Build Coastguard Worker 	else if(instruction.gradDxId != 0)
458*03ce13f7SAndroid Build Coastguard Worker 	{
459*03ce13f7SAndroid Build Coastguard Worker 		auto dxValue = Operand(shader, *this, instruction.gradDxId);
460*03ce13f7SAndroid Build Coastguard Worker 		auto dyValue = Operand(shader, *this, instruction.gradDyId);
461*03ce13f7SAndroid Build Coastguard Worker 		ASSERT(dxValue.componentCount == dxValue.componentCount);
462*03ce13f7SAndroid Build Coastguard Worker 
463*03ce13f7SAndroid Build Coastguard Worker 		for(uint32_t j = 0; j < dxValue.componentCount; j++, i++)
464*03ce13f7SAndroid Build Coastguard Worker 		{
465*03ce13f7SAndroid Build Coastguard Worker 			in[i] = dxValue.Float(j);
466*03ce13f7SAndroid Build Coastguard Worker 		}
467*03ce13f7SAndroid Build Coastguard Worker 
468*03ce13f7SAndroid Build Coastguard Worker 		for(uint32_t j = 0; j < dxValue.componentCount; j++, i++)
469*03ce13f7SAndroid Build Coastguard Worker 		{
470*03ce13f7SAndroid Build Coastguard Worker 			in[i] = dyValue.Float(j);
471*03ce13f7SAndroid Build Coastguard Worker 		}
472*03ce13f7SAndroid Build Coastguard Worker 	}
473*03ce13f7SAndroid Build Coastguard Worker 	else if(instruction.samplerMethod == Fetch)
474*03ce13f7SAndroid Build Coastguard Worker 	{
475*03ce13f7SAndroid Build Coastguard Worker 		// The instruction didn't provide a lod operand, but the sampler's Fetch
476*03ce13f7SAndroid Build Coastguard Worker 		// function requires one to be present. If no lod is supplied, the default
477*03ce13f7SAndroid Build Coastguard Worker 		// is zero.
478*03ce13f7SAndroid Build Coastguard Worker 		in[i] = As<SIMD::Float>(SIMD::Int(0));
479*03ce13f7SAndroid Build Coastguard Worker 		i++;
480*03ce13f7SAndroid Build Coastguard Worker 	}
481*03ce13f7SAndroid Build Coastguard Worker 
482*03ce13f7SAndroid Build Coastguard Worker 	if(instruction.offsetId != 0)
483*03ce13f7SAndroid Build Coastguard Worker 	{
484*03ce13f7SAndroid Build Coastguard Worker 		auto offsetValue = Operand(shader, *this, instruction.offsetId);
485*03ce13f7SAndroid Build Coastguard Worker 
486*03ce13f7SAndroid Build Coastguard Worker 		for(uint32_t j = 0; j < offsetValue.componentCount; j++, i++)
487*03ce13f7SAndroid Build Coastguard Worker 		{
488*03ce13f7SAndroid Build Coastguard Worker 			in[i] = As<SIMD::Float>(offsetValue.Int(j));  // Integer values, but transfered as float.
489*03ce13f7SAndroid Build Coastguard Worker 		}
490*03ce13f7SAndroid Build Coastguard Worker 	}
491*03ce13f7SAndroid Build Coastguard Worker 
492*03ce13f7SAndroid Build Coastguard Worker 	if(instruction.sample)
493*03ce13f7SAndroid Build Coastguard Worker 	{
494*03ce13f7SAndroid Build Coastguard Worker 		auto sampleValue = Operand(shader, *this, instruction.sampleId);
495*03ce13f7SAndroid Build Coastguard Worker 		in[i] = As<SIMD::Float>(sampleValue.Int(0));
496*03ce13f7SAndroid Build Coastguard Worker 	}
497*03ce13f7SAndroid Build Coastguard Worker 
498*03ce13f7SAndroid Build Coastguard Worker 	Pointer<Byte> texture = imageDescriptor + OFFSET(vk::SampledImageDescriptor, texture);  // sw::Texture*
499*03ce13f7SAndroid Build Coastguard Worker 
500*03ce13f7SAndroid Build Coastguard Worker 	Call<ImageSampler>(samplerFunction, texture, &in, &out, routine->constants);
501*03ce13f7SAndroid Build Coastguard Worker }
502*03ce13f7SAndroid Build Coastguard Worker 
EmitImageQuerySizeLod(InsnIterator insn)503*03ce13f7SAndroid Build Coastguard Worker void SpirvEmitter::EmitImageQuerySizeLod(InsnIterator insn)
504*03ce13f7SAndroid Build Coastguard Worker {
505*03ce13f7SAndroid Build Coastguard Worker 	auto &resultTy = shader.getType(insn.resultTypeId());
506*03ce13f7SAndroid Build Coastguard Worker 	auto imageId = Object::ID(insn.word(3));
507*03ce13f7SAndroid Build Coastguard Worker 	auto lodId = Object::ID(insn.word(4));
508*03ce13f7SAndroid Build Coastguard Worker 
509*03ce13f7SAndroid Build Coastguard Worker 	auto &dst = createIntermediate(insn.resultId(), resultTy.componentCount);
510*03ce13f7SAndroid Build Coastguard Worker 	GetImageDimensions(resultTy, imageId, lodId, dst);
511*03ce13f7SAndroid Build Coastguard Worker }
512*03ce13f7SAndroid Build Coastguard Worker 
EmitImageQuerySize(InsnIterator insn)513*03ce13f7SAndroid Build Coastguard Worker void SpirvEmitter::EmitImageQuerySize(InsnIterator insn)
514*03ce13f7SAndroid Build Coastguard Worker {
515*03ce13f7SAndroid Build Coastguard Worker 	auto &resultTy = shader.getType(insn.resultTypeId());
516*03ce13f7SAndroid Build Coastguard Worker 	auto imageId = Object::ID(insn.word(3));
517*03ce13f7SAndroid Build Coastguard Worker 	auto lodId = Object::ID(0);
518*03ce13f7SAndroid Build Coastguard Worker 
519*03ce13f7SAndroid Build Coastguard Worker 	auto &dst = createIntermediate(insn.resultId(), resultTy.componentCount);
520*03ce13f7SAndroid Build Coastguard Worker 	GetImageDimensions(resultTy, imageId, lodId, dst);
521*03ce13f7SAndroid Build Coastguard Worker }
522*03ce13f7SAndroid Build Coastguard Worker 
GetImageDimensions(const Type & resultTy,Object::ID imageId,Object::ID lodId,Intermediate & dst) const523*03ce13f7SAndroid Build Coastguard Worker void SpirvEmitter::GetImageDimensions(const Type &resultTy, Object::ID imageId, Object::ID lodId, Intermediate &dst) const
524*03ce13f7SAndroid Build Coastguard Worker {
525*03ce13f7SAndroid Build Coastguard Worker 	auto &image = shader.getObject(imageId);
526*03ce13f7SAndroid Build Coastguard Worker 	auto &imageType = shader.getType(image);
527*03ce13f7SAndroid Build Coastguard Worker 
528*03ce13f7SAndroid Build Coastguard Worker 	ASSERT(imageType.definition.opcode() == spv::OpTypeImage);
529*03ce13f7SAndroid Build Coastguard Worker 	bool isArrayed = imageType.definition.word(5) != 0;
530*03ce13f7SAndroid Build Coastguard Worker 	uint32_t dimensions = resultTy.componentCount - (isArrayed ? 1 : 0);
531*03ce13f7SAndroid Build Coastguard Worker 
532*03ce13f7SAndroid Build Coastguard Worker 	const Spirv::DescriptorDecorations &d = shader.descriptorDecorations.at(imageId);
533*03ce13f7SAndroid Build Coastguard Worker 	auto descriptorType = routine->pipelineLayout->getDescriptorType(d.DescriptorSet, d.Binding);
534*03ce13f7SAndroid Build Coastguard Worker 
535*03ce13f7SAndroid Build Coastguard Worker 	Pointer<Byte> descriptor = getPointer(imageId).getUniformPointer();
536*03ce13f7SAndroid Build Coastguard Worker 
537*03ce13f7SAndroid Build Coastguard Worker 	Int width;
538*03ce13f7SAndroid Build Coastguard Worker 	Int height;
539*03ce13f7SAndroid Build Coastguard Worker 	Int depth;
540*03ce13f7SAndroid Build Coastguard Worker 
541*03ce13f7SAndroid Build Coastguard Worker 	switch(descriptorType)
542*03ce13f7SAndroid Build Coastguard Worker 	{
543*03ce13f7SAndroid Build Coastguard Worker 	case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
544*03ce13f7SAndroid Build Coastguard Worker 	case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
545*03ce13f7SAndroid Build Coastguard Worker 		width = *Pointer<Int>(descriptor + OFFSET(vk::StorageImageDescriptor, width));
546*03ce13f7SAndroid Build Coastguard Worker 		height = *Pointer<Int>(descriptor + OFFSET(vk::StorageImageDescriptor, height));
547*03ce13f7SAndroid Build Coastguard Worker 		depth = *Pointer<Int>(descriptor + OFFSET(vk::StorageImageDescriptor, depth));
548*03ce13f7SAndroid Build Coastguard Worker 		break;
549*03ce13f7SAndroid Build Coastguard Worker 	case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
550*03ce13f7SAndroid Build Coastguard Worker 	case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
551*03ce13f7SAndroid Build Coastguard Worker 	case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
552*03ce13f7SAndroid Build Coastguard Worker 		width = *Pointer<Int>(descriptor + OFFSET(vk::SampledImageDescriptor, width));
553*03ce13f7SAndroid Build Coastguard Worker 		height = *Pointer<Int>(descriptor + OFFSET(vk::SampledImageDescriptor, height));
554*03ce13f7SAndroid Build Coastguard Worker 		depth = *Pointer<Int>(descriptor + OFFSET(vk::SampledImageDescriptor, depth));
555*03ce13f7SAndroid Build Coastguard Worker 		break;
556*03ce13f7SAndroid Build Coastguard Worker 	default:
557*03ce13f7SAndroid Build Coastguard Worker 		UNREACHABLE("Image descriptorType: %d", int(descriptorType));
558*03ce13f7SAndroid Build Coastguard Worker 	}
559*03ce13f7SAndroid Build Coastguard Worker 
560*03ce13f7SAndroid Build Coastguard Worker 	if(lodId != 0)
561*03ce13f7SAndroid Build Coastguard Worker 	{
562*03ce13f7SAndroid Build Coastguard Worker 		auto lodVal = Operand(shader, *this, lodId);
563*03ce13f7SAndroid Build Coastguard Worker 		ASSERT(lodVal.componentCount == 1);
564*03ce13f7SAndroid Build Coastguard Worker 		auto lod = lodVal.Int(0);
565*03ce13f7SAndroid Build Coastguard Worker 		auto one = SIMD::Int(1);
566*03ce13f7SAndroid Build Coastguard Worker 
567*03ce13f7SAndroid Build Coastguard Worker 		if(dimensions >= 1) dst.move(0, Max(SIMD::Int(width) >> lod, one));
568*03ce13f7SAndroid Build Coastguard Worker 		if(dimensions >= 2) dst.move(1, Max(SIMD::Int(height) >> lod, one));
569*03ce13f7SAndroid Build Coastguard Worker 		if(dimensions >= 3) dst.move(2, Max(SIMD::Int(depth) >> lod, one));
570*03ce13f7SAndroid Build Coastguard Worker 	}
571*03ce13f7SAndroid Build Coastguard Worker 	else
572*03ce13f7SAndroid Build Coastguard Worker 	{
573*03ce13f7SAndroid Build Coastguard Worker 
574*03ce13f7SAndroid Build Coastguard Worker 		if(dimensions >= 1) dst.move(0, SIMD::Int(width));
575*03ce13f7SAndroid Build Coastguard Worker 		if(dimensions >= 2) dst.move(1, SIMD::Int(height));
576*03ce13f7SAndroid Build Coastguard Worker 		if(dimensions >= 3) dst.move(2, SIMD::Int(depth));
577*03ce13f7SAndroid Build Coastguard Worker 	}
578*03ce13f7SAndroid Build Coastguard Worker 
579*03ce13f7SAndroid Build Coastguard Worker 	if(isArrayed)
580*03ce13f7SAndroid Build Coastguard Worker 	{
581*03ce13f7SAndroid Build Coastguard Worker 		dst.move(dimensions, SIMD::Int(depth));
582*03ce13f7SAndroid Build Coastguard Worker 	}
583*03ce13f7SAndroid Build Coastguard Worker }
584*03ce13f7SAndroid Build Coastguard Worker 
EmitImageQueryLevels(InsnIterator insn)585*03ce13f7SAndroid Build Coastguard Worker void SpirvEmitter::EmitImageQueryLevels(InsnIterator insn)
586*03ce13f7SAndroid Build Coastguard Worker {
587*03ce13f7SAndroid Build Coastguard Worker 	auto &resultTy = shader.getType(insn.resultTypeId());
588*03ce13f7SAndroid Build Coastguard Worker 	ASSERT(resultTy.componentCount == 1);
589*03ce13f7SAndroid Build Coastguard Worker 	auto imageId = Object::ID(insn.word(3));
590*03ce13f7SAndroid Build Coastguard Worker 
591*03ce13f7SAndroid Build Coastguard Worker 	const Spirv::DescriptorDecorations &d = shader.descriptorDecorations.at(imageId);
592*03ce13f7SAndroid Build Coastguard Worker 	auto descriptorType = routine->pipelineLayout->getDescriptorType(d.DescriptorSet, d.Binding);
593*03ce13f7SAndroid Build Coastguard Worker 
594*03ce13f7SAndroid Build Coastguard Worker 	Pointer<Byte> descriptor = getPointer(imageId).getUniformPointer();
595*03ce13f7SAndroid Build Coastguard Worker 	Int mipLevels = 0;
596*03ce13f7SAndroid Build Coastguard Worker 	switch(descriptorType)
597*03ce13f7SAndroid Build Coastguard Worker 	{
598*03ce13f7SAndroid Build Coastguard Worker 	case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
599*03ce13f7SAndroid Build Coastguard Worker 	case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
600*03ce13f7SAndroid Build Coastguard Worker 	case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
601*03ce13f7SAndroid Build Coastguard Worker 		mipLevels = *Pointer<Int>(descriptor + OFFSET(vk::SampledImageDescriptor, mipLevels));  // uint32_t
602*03ce13f7SAndroid Build Coastguard Worker 		break;
603*03ce13f7SAndroid Build Coastguard Worker 	default:
604*03ce13f7SAndroid Build Coastguard Worker 		UNREACHABLE("Image descriptorType: %d", int(descriptorType));
605*03ce13f7SAndroid Build Coastguard Worker 	}
606*03ce13f7SAndroid Build Coastguard Worker 
607*03ce13f7SAndroid Build Coastguard Worker 	auto &dst = createIntermediate(insn.resultId(), 1);
608*03ce13f7SAndroid Build Coastguard Worker 	dst.move(0, SIMD::Int(mipLevels));
609*03ce13f7SAndroid Build Coastguard Worker }
610*03ce13f7SAndroid Build Coastguard Worker 
EmitImageQuerySamples(InsnIterator insn)611*03ce13f7SAndroid Build Coastguard Worker void SpirvEmitter::EmitImageQuerySamples(InsnIterator insn)
612*03ce13f7SAndroid Build Coastguard Worker {
613*03ce13f7SAndroid Build Coastguard Worker 	auto &resultTy = shader.getType(insn.resultTypeId());
614*03ce13f7SAndroid Build Coastguard Worker 	ASSERT(resultTy.componentCount == 1);
615*03ce13f7SAndroid Build Coastguard Worker 	auto imageId = Object::ID(insn.word(3));
616*03ce13f7SAndroid Build Coastguard Worker 	auto imageTy = shader.getObjectType(imageId);
617*03ce13f7SAndroid Build Coastguard Worker 	ASSERT(imageTy.definition.opcode() == spv::OpTypeImage);
618*03ce13f7SAndroid Build Coastguard Worker 	ASSERT(imageTy.definition.word(3) == spv::Dim2D);
619*03ce13f7SAndroid Build Coastguard Worker 	ASSERT(imageTy.definition.word(6 /* MS */) == 1);
620*03ce13f7SAndroid Build Coastguard Worker 
621*03ce13f7SAndroid Build Coastguard Worker 	const Spirv::DescriptorDecorations &d = shader.descriptorDecorations.at(imageId);
622*03ce13f7SAndroid Build Coastguard Worker 	auto descriptorType = routine->pipelineLayout->getDescriptorType(d.DescriptorSet, d.Binding);
623*03ce13f7SAndroid Build Coastguard Worker 
624*03ce13f7SAndroid Build Coastguard Worker 	Pointer<Byte> descriptor = getPointer(imageId).getUniformPointer();
625*03ce13f7SAndroid Build Coastguard Worker 	Int sampleCount = 0;
626*03ce13f7SAndroid Build Coastguard Worker 	switch(descriptorType)
627*03ce13f7SAndroid Build Coastguard Worker 	{
628*03ce13f7SAndroid Build Coastguard Worker 	case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
629*03ce13f7SAndroid Build Coastguard Worker 		sampleCount = *Pointer<Int>(descriptor + OFFSET(vk::StorageImageDescriptor, sampleCount));  // uint32_t
630*03ce13f7SAndroid Build Coastguard Worker 		break;
631*03ce13f7SAndroid Build Coastguard Worker 	case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
632*03ce13f7SAndroid Build Coastguard Worker 	case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
633*03ce13f7SAndroid Build Coastguard Worker 	case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
634*03ce13f7SAndroid Build Coastguard Worker 		sampleCount = *Pointer<Int>(descriptor + OFFSET(vk::SampledImageDescriptor, sampleCount));  // uint32_t
635*03ce13f7SAndroid Build Coastguard Worker 		break;
636*03ce13f7SAndroid Build Coastguard Worker 	default:
637*03ce13f7SAndroid Build Coastguard Worker 		UNREACHABLE("Image descriptorType: %d", int(descriptorType));
638*03ce13f7SAndroid Build Coastguard Worker 	}
639*03ce13f7SAndroid Build Coastguard Worker 
640*03ce13f7SAndroid Build Coastguard Worker 	auto &dst = createIntermediate(insn.resultId(), 1);
641*03ce13f7SAndroid Build Coastguard Worker 	dst.move(0, SIMD::Int(sampleCount));
642*03ce13f7SAndroid Build Coastguard Worker }
643*03ce13f7SAndroid Build Coastguard Worker 
setupTexelAddressData(SIMD::Int rowPitch,SIMD::Int slicePitch,SIMD::Int samplePitch,ImageInstructionSignature instruction,SIMD::Int coordinate[],SIMD::Int sample,vk::Format imageFormat,const SpirvRoutine * routine)644*03ce13f7SAndroid Build Coastguard Worker SpirvEmitter::TexelAddressData SpirvEmitter::setupTexelAddressData(SIMD::Int rowPitch, SIMD::Int slicePitch, SIMD::Int samplePitch, ImageInstructionSignature instruction, SIMD::Int coordinate[], SIMD::Int sample, vk::Format imageFormat, const SpirvRoutine *routine)
645*03ce13f7SAndroid Build Coastguard Worker {
646*03ce13f7SAndroid Build Coastguard Worker 	TexelAddressData data;
647*03ce13f7SAndroid Build Coastguard Worker 
648*03ce13f7SAndroid Build Coastguard Worker 	data.isArrayed = instruction.arrayed;
649*03ce13f7SAndroid Build Coastguard Worker 	data.dim = static_cast<spv::Dim>(instruction.dim);
650*03ce13f7SAndroid Build Coastguard Worker 	data.texelSize = imageFormat.bytes();
651*03ce13f7SAndroid Build Coastguard Worker 	data.dims = instruction.coordinates - (data.isArrayed ? 1 : 0);
652*03ce13f7SAndroid Build Coastguard Worker 
653*03ce13f7SAndroid Build Coastguard Worker 	data.u = coordinate[0];
654*03ce13f7SAndroid Build Coastguard Worker 	data.v = SIMD::Int(0);
655*03ce13f7SAndroid Build Coastguard Worker 
656*03ce13f7SAndroid Build Coastguard Worker 	if(data.dims > 1)
657*03ce13f7SAndroid Build Coastguard Worker 	{
658*03ce13f7SAndroid Build Coastguard Worker 		data.v = coordinate[1];
659*03ce13f7SAndroid Build Coastguard Worker 	}
660*03ce13f7SAndroid Build Coastguard Worker 
661*03ce13f7SAndroid Build Coastguard Worker 	if(data.dim == spv::DimSubpassData)
662*03ce13f7SAndroid Build Coastguard Worker 	{
663*03ce13f7SAndroid Build Coastguard Worker 		data.u += routine->windowSpacePosition[0];
664*03ce13f7SAndroid Build Coastguard Worker 		data.v += routine->windowSpacePosition[1];
665*03ce13f7SAndroid Build Coastguard Worker 	}
666*03ce13f7SAndroid Build Coastguard Worker 
667*03ce13f7SAndroid Build Coastguard Worker 	data.ptrOffset = data.u * SIMD::Int(data.texelSize);
668*03ce13f7SAndroid Build Coastguard Worker 
669*03ce13f7SAndroid Build Coastguard Worker 	if(data.dims > 1)
670*03ce13f7SAndroid Build Coastguard Worker 	{
671*03ce13f7SAndroid Build Coastguard Worker 		data.ptrOffset += data.v * rowPitch;
672*03ce13f7SAndroid Build Coastguard Worker 	}
673*03ce13f7SAndroid Build Coastguard Worker 
674*03ce13f7SAndroid Build Coastguard Worker 	data.w = 0;
675*03ce13f7SAndroid Build Coastguard Worker 	if((data.dims > 2) || data.isArrayed)
676*03ce13f7SAndroid Build Coastguard Worker 	{
677*03ce13f7SAndroid Build Coastguard Worker 		if(data.dims > 2)
678*03ce13f7SAndroid Build Coastguard Worker 		{
679*03ce13f7SAndroid Build Coastguard Worker 			data.w += coordinate[2];
680*03ce13f7SAndroid Build Coastguard Worker 		}
681*03ce13f7SAndroid Build Coastguard Worker 
682*03ce13f7SAndroid Build Coastguard Worker 		if(data.isArrayed)
683*03ce13f7SAndroid Build Coastguard Worker 		{
684*03ce13f7SAndroid Build Coastguard Worker 			data.w += coordinate[data.dims];
685*03ce13f7SAndroid Build Coastguard Worker 		}
686*03ce13f7SAndroid Build Coastguard Worker 
687*03ce13f7SAndroid Build Coastguard Worker 		data.ptrOffset += data.w * slicePitch;
688*03ce13f7SAndroid Build Coastguard Worker 	}
689*03ce13f7SAndroid Build Coastguard Worker 
690*03ce13f7SAndroid Build Coastguard Worker 	if(data.dim == spv::DimSubpassData)
691*03ce13f7SAndroid Build Coastguard Worker 	{
692*03ce13f7SAndroid Build Coastguard Worker 		// Multiview input attachment access is to the layer corresponding to the current view
693*03ce13f7SAndroid Build Coastguard Worker 		data.ptrOffset += SIMD::Int(routine->layer) * slicePitch;
694*03ce13f7SAndroid Build Coastguard Worker 	}
695*03ce13f7SAndroid Build Coastguard Worker 
696*03ce13f7SAndroid Build Coastguard Worker 	if(instruction.sample)
697*03ce13f7SAndroid Build Coastguard Worker 	{
698*03ce13f7SAndroid Build Coastguard Worker 		data.ptrOffset += sample * samplePitch;
699*03ce13f7SAndroid Build Coastguard Worker 	}
700*03ce13f7SAndroid Build Coastguard Worker 
701*03ce13f7SAndroid Build Coastguard Worker 	return data;
702*03ce13f7SAndroid Build Coastguard Worker }
703*03ce13f7SAndroid Build Coastguard Worker 
GetNonUniformTexelAddress(ImageInstructionSignature instruction,SIMD::Pointer descriptor,SIMD::Int coordinate[],SIMD::Int sample,vk::Format imageFormat,OutOfBoundsBehavior outOfBoundsBehavior,SIMD::Int activeLaneMask,const SpirvRoutine * routine)704*03ce13f7SAndroid Build Coastguard Worker SIMD::Pointer SpirvEmitter::GetNonUniformTexelAddress(ImageInstructionSignature instruction, SIMD::Pointer descriptor, SIMD::Int coordinate[], SIMD::Int sample, vk::Format imageFormat, OutOfBoundsBehavior outOfBoundsBehavior, SIMD::Int activeLaneMask, const SpirvRoutine *routine)
705*03ce13f7SAndroid Build Coastguard Worker {
706*03ce13f7SAndroid Build Coastguard Worker 	const bool useStencilAspect = (imageFormat == VK_FORMAT_S8_UINT);
707*03ce13f7SAndroid Build Coastguard Worker 	auto rowPitch = (descriptor + (useStencilAspect
708*03ce13f7SAndroid Build Coastguard Worker 	                                   ? OFFSET(vk::StorageImageDescriptor, stencilRowPitchBytes)
709*03ce13f7SAndroid Build Coastguard Worker 	                                   : OFFSET(vk::StorageImageDescriptor, rowPitchBytes)))
710*03ce13f7SAndroid Build Coastguard Worker 	                    .Load<SIMD::Int>(outOfBoundsBehavior, activeLaneMask);
711*03ce13f7SAndroid Build Coastguard Worker 	auto slicePitch = (descriptor + (useStencilAspect
712*03ce13f7SAndroid Build Coastguard Worker 	                                     ? OFFSET(vk::StorageImageDescriptor, stencilSlicePitchBytes)
713*03ce13f7SAndroid Build Coastguard Worker 	                                     : OFFSET(vk::StorageImageDescriptor, slicePitchBytes)))
714*03ce13f7SAndroid Build Coastguard Worker 	                      .Load<SIMD::Int>(outOfBoundsBehavior, activeLaneMask);
715*03ce13f7SAndroid Build Coastguard Worker 	auto samplePitch = (descriptor + (useStencilAspect
716*03ce13f7SAndroid Build Coastguard Worker 	                                      ? OFFSET(vk::StorageImageDescriptor, stencilSamplePitchBytes)
717*03ce13f7SAndroid Build Coastguard Worker 	                                      : OFFSET(vk::StorageImageDescriptor, samplePitchBytes)))
718*03ce13f7SAndroid Build Coastguard Worker 	                       .Load<SIMD::Int>(outOfBoundsBehavior, activeLaneMask);
719*03ce13f7SAndroid Build Coastguard Worker 
720*03ce13f7SAndroid Build Coastguard Worker 	auto texelData = setupTexelAddressData(rowPitch, slicePitch, samplePitch, instruction, coordinate, sample, imageFormat, routine);
721*03ce13f7SAndroid Build Coastguard Worker 
722*03ce13f7SAndroid Build Coastguard Worker 	// If the out-of-bounds behavior is set to nullify, then each coordinate must be tested individually.
723*03ce13f7SAndroid Build Coastguard Worker 	// Other out-of-bounds behaviors work properly by just comparing the offset against the total size.
724*03ce13f7SAndroid Build Coastguard Worker 	if(outOfBoundsBehavior == OutOfBoundsBehavior::Nullify)
725*03ce13f7SAndroid Build Coastguard Worker 	{
726*03ce13f7SAndroid Build Coastguard Worker 		SIMD::UInt width = (descriptor + OFFSET(vk::StorageImageDescriptor, width)).Load<SIMD::Int>(outOfBoundsBehavior, activeLaneMask);
727*03ce13f7SAndroid Build Coastguard Worker 		SIMD::Int oobMask = As<SIMD::Int>(CmpNLT(As<SIMD::UInt>(texelData.u), width));
728*03ce13f7SAndroid Build Coastguard Worker 
729*03ce13f7SAndroid Build Coastguard Worker 		if(texelData.dims > 1)
730*03ce13f7SAndroid Build Coastguard Worker 		{
731*03ce13f7SAndroid Build Coastguard Worker 			SIMD::UInt height = As<SIMD::UInt>((descriptor + OFFSET(vk::StorageImageDescriptor, height)).Load<SIMD::Int>(outOfBoundsBehavior, activeLaneMask));
732*03ce13f7SAndroid Build Coastguard Worker 			oobMask |= As<SIMD::Int>(CmpNLT(As<SIMD::UInt>(texelData.v), height));
733*03ce13f7SAndroid Build Coastguard Worker 		}
734*03ce13f7SAndroid Build Coastguard Worker 
735*03ce13f7SAndroid Build Coastguard Worker 		if((texelData.dims > 2) || texelData.isArrayed)
736*03ce13f7SAndroid Build Coastguard Worker 		{
737*03ce13f7SAndroid Build Coastguard Worker 			SIMD::UInt depth = As<SIMD::UInt>((descriptor + OFFSET(vk::StorageImageDescriptor, depth)).Load<SIMD::Int>(outOfBoundsBehavior, activeLaneMask));
738*03ce13f7SAndroid Build Coastguard Worker 			if(texelData.dim == spv::DimCube) { depth *= 6; }
739*03ce13f7SAndroid Build Coastguard Worker 			oobMask |= As<SIMD::Int>(CmpNLT(As<SIMD::UInt>(texelData.w), depth));
740*03ce13f7SAndroid Build Coastguard Worker 		}
741*03ce13f7SAndroid Build Coastguard Worker 
742*03ce13f7SAndroid Build Coastguard Worker 		if(instruction.sample)
743*03ce13f7SAndroid Build Coastguard Worker 		{
744*03ce13f7SAndroid Build Coastguard Worker 			SIMD::UInt sampleCount = As<SIMD::UInt>((descriptor + OFFSET(vk::StorageImageDescriptor, sampleCount)).Load<SIMD::Int>(outOfBoundsBehavior, activeLaneMask));
745*03ce13f7SAndroid Build Coastguard Worker 			oobMask |= As<SIMD::Int>(CmpNLT(As<SIMD::UInt>(sample), sampleCount));
746*03ce13f7SAndroid Build Coastguard Worker 		}
747*03ce13f7SAndroid Build Coastguard Worker 
748*03ce13f7SAndroid Build Coastguard Worker 		constexpr int32_t OOB_OFFSET = 0x7FFFFFFF - 16;  // SIMD pointer offsets are signed 32-bit, so this is the largest offset (for 16-byte texels).
749*03ce13f7SAndroid Build Coastguard Worker 		static_assert(OOB_OFFSET >= vk::MAX_MEMORY_ALLOCATION_SIZE, "the largest offset must be guaranteed to be out-of-bounds");
750*03ce13f7SAndroid Build Coastguard Worker 
751*03ce13f7SAndroid Build Coastguard Worker 		texelData.ptrOffset = (texelData.ptrOffset & ~oobMask) | (oobMask & SIMD::Int(OOB_OFFSET));  // oob ? OOB_OFFSET : ptrOffset  // TODO: IfThenElse()
752*03ce13f7SAndroid Build Coastguard Worker 	}
753*03ce13f7SAndroid Build Coastguard Worker 
754*03ce13f7SAndroid Build Coastguard Worker 	std::vector<Pointer<Byte>> imageBase(SIMD::Width);
755*03ce13f7SAndroid Build Coastguard Worker 	for(int i = 0; i < SIMD::Width; i++)
756*03ce13f7SAndroid Build Coastguard Worker 	{
757*03ce13f7SAndroid Build Coastguard Worker 		imageBase[i] = *Pointer<Pointer<Byte>>(descriptor.getPointerForLane(i) + (useStencilAspect
758*03ce13f7SAndroid Build Coastguard Worker 		                                                                              ? OFFSET(vk::StorageImageDescriptor, stencilPtr)
759*03ce13f7SAndroid Build Coastguard Worker 		                                                                              : OFFSET(vk::StorageImageDescriptor, ptr)));
760*03ce13f7SAndroid Build Coastguard Worker 	}
761*03ce13f7SAndroid Build Coastguard Worker 
762*03ce13f7SAndroid Build Coastguard Worker 	return SIMD::Pointer(imageBase) + texelData.ptrOffset;
763*03ce13f7SAndroid Build Coastguard Worker }
764*03ce13f7SAndroid Build Coastguard Worker 
GetTexelAddress(ImageInstructionSignature instruction,Pointer<Byte> descriptor,SIMD::Int coordinate[],SIMD::Int sample,vk::Format imageFormat,OutOfBoundsBehavior outOfBoundsBehavior,const SpirvRoutine * routine)765*03ce13f7SAndroid Build Coastguard Worker SIMD::Pointer SpirvEmitter::GetTexelAddress(ImageInstructionSignature instruction, Pointer<Byte> descriptor, SIMD::Int coordinate[], SIMD::Int sample, vk::Format imageFormat, OutOfBoundsBehavior outOfBoundsBehavior, const SpirvRoutine *routine)
766*03ce13f7SAndroid Build Coastguard Worker {
767*03ce13f7SAndroid Build Coastguard Worker 	const bool useStencilAspect = (imageFormat == VK_FORMAT_S8_UINT);
768*03ce13f7SAndroid Build Coastguard Worker 	auto rowPitch = SIMD::Int(*Pointer<Int>(descriptor + (useStencilAspect
769*03ce13f7SAndroid Build Coastguard Worker 	                                                          ? OFFSET(vk::StorageImageDescriptor, stencilRowPitchBytes)
770*03ce13f7SAndroid Build Coastguard Worker 	                                                          : OFFSET(vk::StorageImageDescriptor, rowPitchBytes))));
771*03ce13f7SAndroid Build Coastguard Worker 	auto slicePitch = SIMD::Int(
772*03ce13f7SAndroid Build Coastguard Worker 	    *Pointer<Int>(descriptor + (useStencilAspect
773*03ce13f7SAndroid Build Coastguard Worker 	                                    ? OFFSET(vk::StorageImageDescriptor, stencilSlicePitchBytes)
774*03ce13f7SAndroid Build Coastguard Worker 	                                    : OFFSET(vk::StorageImageDescriptor, slicePitchBytes))));
775*03ce13f7SAndroid Build Coastguard Worker 	auto samplePitch = SIMD::Int(
776*03ce13f7SAndroid Build Coastguard Worker 	    *Pointer<Int>(descriptor + (useStencilAspect
777*03ce13f7SAndroid Build Coastguard Worker 	                                    ? OFFSET(vk::StorageImageDescriptor, stencilSamplePitchBytes)
778*03ce13f7SAndroid Build Coastguard Worker 	                                    : OFFSET(vk::StorageImageDescriptor, samplePitchBytes))));
779*03ce13f7SAndroid Build Coastguard Worker 
780*03ce13f7SAndroid Build Coastguard Worker 	auto texelData = setupTexelAddressData(rowPitch, slicePitch, samplePitch, instruction, coordinate, sample, imageFormat, routine);
781*03ce13f7SAndroid Build Coastguard Worker 
782*03ce13f7SAndroid Build Coastguard Worker 	// If the out-of-bounds behavior is set to nullify, then each coordinate must be tested individually.
783*03ce13f7SAndroid Build Coastguard Worker 	// Other out-of-bounds behaviors work properly by just comparing the offset against the total size.
784*03ce13f7SAndroid Build Coastguard Worker 	if(outOfBoundsBehavior == OutOfBoundsBehavior::Nullify)
785*03ce13f7SAndroid Build Coastguard Worker 	{
786*03ce13f7SAndroid Build Coastguard Worker 		SIMD::UInt width = *Pointer<UInt>(descriptor + OFFSET(vk::StorageImageDescriptor, width));
787*03ce13f7SAndroid Build Coastguard Worker 		SIMD::Int oobMask = As<SIMD::Int>(CmpNLT(As<SIMD::UInt>(texelData.u), width));
788*03ce13f7SAndroid Build Coastguard Worker 
789*03ce13f7SAndroid Build Coastguard Worker 		if(texelData.dims > 1)
790*03ce13f7SAndroid Build Coastguard Worker 		{
791*03ce13f7SAndroid Build Coastguard Worker 			SIMD::UInt height = *Pointer<UInt>(descriptor + OFFSET(vk::StorageImageDescriptor, height));
792*03ce13f7SAndroid Build Coastguard Worker 			oobMask |= As<SIMD::Int>(CmpNLT(As<SIMD::UInt>(texelData.v), height));
793*03ce13f7SAndroid Build Coastguard Worker 		}
794*03ce13f7SAndroid Build Coastguard Worker 
795*03ce13f7SAndroid Build Coastguard Worker 		if((texelData.dims > 2) || texelData.isArrayed)
796*03ce13f7SAndroid Build Coastguard Worker 		{
797*03ce13f7SAndroid Build Coastguard Worker 			UInt depth = *Pointer<UInt>(descriptor + OFFSET(vk::StorageImageDescriptor, depth));
798*03ce13f7SAndroid Build Coastguard Worker 			if(texelData.dim == spv::DimCube) { depth *= 6; }
799*03ce13f7SAndroid Build Coastguard Worker 			oobMask |= As<SIMD::Int>(CmpNLT(As<SIMD::UInt>(texelData.w), SIMD::UInt(depth)));
800*03ce13f7SAndroid Build Coastguard Worker 		}
801*03ce13f7SAndroid Build Coastguard Worker 
802*03ce13f7SAndroid Build Coastguard Worker 		if(instruction.sample)
803*03ce13f7SAndroid Build Coastguard Worker 		{
804*03ce13f7SAndroid Build Coastguard Worker 			SIMD::UInt sampleCount = *Pointer<UInt>(descriptor + OFFSET(vk::StorageImageDescriptor, sampleCount));
805*03ce13f7SAndroid Build Coastguard Worker 			oobMask |= As<SIMD::Int>(CmpNLT(As<SIMD::UInt>(sample), sampleCount));
806*03ce13f7SAndroid Build Coastguard Worker 		}
807*03ce13f7SAndroid Build Coastguard Worker 
808*03ce13f7SAndroid Build Coastguard Worker 		constexpr int32_t OOB_OFFSET = 0x7FFFFFFF - 16;  // SIMD pointer offsets are signed 32-bit, so this is the largest offset (for 16-byte texels).
809*03ce13f7SAndroid Build Coastguard Worker 		static_assert(OOB_OFFSET >= vk::MAX_MEMORY_ALLOCATION_SIZE, "the largest offset must be guaranteed to be out-of-bounds");
810*03ce13f7SAndroid Build Coastguard Worker 
811*03ce13f7SAndroid Build Coastguard Worker 		texelData.ptrOffset = (texelData.ptrOffset & ~oobMask) | (oobMask & SIMD::Int(OOB_OFFSET));  // oob ? OOB_OFFSET : ptrOffset  // TODO: IfThenElse()
812*03ce13f7SAndroid Build Coastguard Worker 	}
813*03ce13f7SAndroid Build Coastguard Worker 
814*03ce13f7SAndroid Build Coastguard Worker 	Pointer<Byte> imageBase = *Pointer<Pointer<Byte>>(descriptor + (useStencilAspect
815*03ce13f7SAndroid Build Coastguard Worker 	                                                                    ? OFFSET(vk::StorageImageDescriptor, stencilPtr)
816*03ce13f7SAndroid Build Coastguard Worker 	                                                                    : OFFSET(vk::StorageImageDescriptor, ptr)));
817*03ce13f7SAndroid Build Coastguard Worker 
818*03ce13f7SAndroid Build Coastguard Worker 	Int imageSizeInBytes = *Pointer<Int>(descriptor + OFFSET(vk::StorageImageDescriptor, sizeInBytes));
819*03ce13f7SAndroid Build Coastguard Worker 
820*03ce13f7SAndroid Build Coastguard Worker 	return SIMD::Pointer(imageBase, imageSizeInBytes, texelData.ptrOffset);
821*03ce13f7SAndroid Build Coastguard Worker }
822*03ce13f7SAndroid Build Coastguard Worker 
EmitImageRead(const ImageInstruction & instruction)823*03ce13f7SAndroid Build Coastguard Worker void SpirvEmitter::EmitImageRead(const ImageInstruction &instruction)
824*03ce13f7SAndroid Build Coastguard Worker {
825*03ce13f7SAndroid Build Coastguard Worker 	auto &resultType = shader.getObjectType(instruction.resultId);
826*03ce13f7SAndroid Build Coastguard Worker 	auto &image = shader.getObject(instruction.imageId);
827*03ce13f7SAndroid Build Coastguard Worker 	auto &imageType = shader.getType(image);
828*03ce13f7SAndroid Build Coastguard Worker 
829*03ce13f7SAndroid Build Coastguard Worker 	ASSERT(imageType.definition.opcode() == spv::OpTypeImage);
830*03ce13f7SAndroid Build Coastguard Worker 	auto dim = static_cast<spv::Dim>(instruction.dim);
831*03ce13f7SAndroid Build Coastguard Worker 
832*03ce13f7SAndroid Build Coastguard Worker 	auto coordinate = Operand(shader, *this, instruction.coordinateId);
833*03ce13f7SAndroid Build Coastguard Worker 	const Spirv::DescriptorDecorations &d = shader.descriptorDecorations.at(instruction.imageId);
834*03ce13f7SAndroid Build Coastguard Worker 
835*03ce13f7SAndroid Build Coastguard Worker 	// For subpass data, format in the instruction is spv::ImageFormatUnknown. Get it from
836*03ce13f7SAndroid Build Coastguard Worker 	// the renderpass data instead. In all other cases, we can use the format in the instruction.
837*03ce13f7SAndroid Build Coastguard Worker 	ASSERT(dim != spv::DimSubpassData || attachments != nullptr);
838*03ce13f7SAndroid Build Coastguard Worker 	vk::Format imageFormat = (dim == spv::DimSubpassData)
839*03ce13f7SAndroid Build Coastguard Worker 	                             ? shader.getInputAttachmentFormat(*attachments, d.InputAttachmentIndex)
840*03ce13f7SAndroid Build Coastguard Worker 	                             : SpirvFormatToVulkanFormat(static_cast<spv::ImageFormat>(instruction.imageFormat));
841*03ce13f7SAndroid Build Coastguard Worker 
842*03ce13f7SAndroid Build Coastguard Worker 	// Depth+Stencil image attachments select aspect based on the Sampled Type of the
843*03ce13f7SAndroid Build Coastguard Worker 	// OpTypeImage. If float, then we want the depth aspect. If int, we want the stencil aspect.
844*03ce13f7SAndroid Build Coastguard Worker 	bool useStencilAspect = (imageFormat == VK_FORMAT_D32_SFLOAT_S8_UINT &&
845*03ce13f7SAndroid Build Coastguard Worker 	                         shader.getType(imageType.definition.word(2)).opcode() == spv::OpTypeInt);
846*03ce13f7SAndroid Build Coastguard Worker 
847*03ce13f7SAndroid Build Coastguard Worker 	if(useStencilAspect)
848*03ce13f7SAndroid Build Coastguard Worker 	{
849*03ce13f7SAndroid Build Coastguard Worker 		imageFormat = VK_FORMAT_S8_UINT;
850*03ce13f7SAndroid Build Coastguard Worker 	}
851*03ce13f7SAndroid Build Coastguard Worker 
852*03ce13f7SAndroid Build Coastguard Worker 	auto &dst = createIntermediate(instruction.resultId, resultType.componentCount);
853*03ce13f7SAndroid Build Coastguard Worker 	SIMD::Pointer ptr = getPointer(instruction.imageId);
854*03ce13f7SAndroid Build Coastguard Worker 
855*03ce13f7SAndroid Build Coastguard Worker 	SIMD::Int uvwa[4];
856*03ce13f7SAndroid Build Coastguard Worker 	SIMD::Int sample;
857*03ce13f7SAndroid Build Coastguard Worker 	const int texelSize = imageFormat.bytes();
858*03ce13f7SAndroid Build Coastguard Worker 	// VK_EXT_image_robustness requires replacing out-of-bounds access with zero.
859*03ce13f7SAndroid Build Coastguard Worker 	// TODO(b/162327166): Only perform bounds checks when VK_EXT_image_robustness is enabled.
860*03ce13f7SAndroid Build Coastguard Worker 	auto robustness = OutOfBoundsBehavior::Nullify;
861*03ce13f7SAndroid Build Coastguard Worker 
862*03ce13f7SAndroid Build Coastguard Worker 	for(uint32_t i = 0; i < instruction.coordinates; i++)
863*03ce13f7SAndroid Build Coastguard Worker 	{
864*03ce13f7SAndroid Build Coastguard Worker 		uvwa[i] = coordinate.Int(i);
865*03ce13f7SAndroid Build Coastguard Worker 	}
866*03ce13f7SAndroid Build Coastguard Worker 	if(instruction.sample)
867*03ce13f7SAndroid Build Coastguard Worker 	{
868*03ce13f7SAndroid Build Coastguard Worker 		sample = Operand(shader, *this, instruction.sampleId).Int(0);
869*03ce13f7SAndroid Build Coastguard Worker 	}
870*03ce13f7SAndroid Build Coastguard Worker 
871*03ce13f7SAndroid Build Coastguard Worker 	// Gather packed texel data. Texels larger than 4 bytes occupy multiple SIMD::Int elements.
872*03ce13f7SAndroid Build Coastguard Worker 	// TODO(b/160531165): Provide gather abstractions for various element sizes.
873*03ce13f7SAndroid Build Coastguard Worker 	SIMD::Int packed[4];
874*03ce13f7SAndroid Build Coastguard Worker 
875*03ce13f7SAndroid Build Coastguard Worker 	SIMD::Pointer texelPtr = ptr.isBasePlusOffset
876*03ce13f7SAndroid Build Coastguard Worker 	                             ? GetTexelAddress(instruction, ptr.getUniformPointer(), uvwa, sample, imageFormat, robustness, routine)
877*03ce13f7SAndroid Build Coastguard Worker 	                             : GetNonUniformTexelAddress(instruction, ptr, uvwa, sample, imageFormat, robustness, activeLaneMask(), routine);
878*03ce13f7SAndroid Build Coastguard Worker 	if(texelSize == 4 || texelSize == 8 || texelSize == 16)
879*03ce13f7SAndroid Build Coastguard Worker 	{
880*03ce13f7SAndroid Build Coastguard Worker 		for(auto i = 0; i < texelSize / 4; i++)
881*03ce13f7SAndroid Build Coastguard Worker 		{
882*03ce13f7SAndroid Build Coastguard Worker 			packed[i] = texelPtr.Load<SIMD::Int>(robustness, activeLaneMask());
883*03ce13f7SAndroid Build Coastguard Worker 			texelPtr += sizeof(float);
884*03ce13f7SAndroid Build Coastguard Worker 		}
885*03ce13f7SAndroid Build Coastguard Worker 	}
886*03ce13f7SAndroid Build Coastguard Worker 	else if(texelSize == 2)
887*03ce13f7SAndroid Build Coastguard Worker 	{
888*03ce13f7SAndroid Build Coastguard Worker 		SIMD::Int mask = activeLaneMask() & texelPtr.isInBounds(2, robustness);
889*03ce13f7SAndroid Build Coastguard Worker 
890*03ce13f7SAndroid Build Coastguard Worker 		for(int i = 0; i < SIMD::Width; i++)
891*03ce13f7SAndroid Build Coastguard Worker 		{
892*03ce13f7SAndroid Build Coastguard Worker 			If(Extract(mask, i) != 0)
893*03ce13f7SAndroid Build Coastguard Worker 			{
894*03ce13f7SAndroid Build Coastguard Worker 				packed[0] = Insert(packed[0], Int(*Pointer<Short>(texelPtr.getPointerForLane(i))), i);
895*03ce13f7SAndroid Build Coastguard Worker 			}
896*03ce13f7SAndroid Build Coastguard Worker 		}
897*03ce13f7SAndroid Build Coastguard Worker 	}
898*03ce13f7SAndroid Build Coastguard Worker 	else if(texelSize == 1)
899*03ce13f7SAndroid Build Coastguard Worker 	{
900*03ce13f7SAndroid Build Coastguard Worker 		SIMD::Int mask = activeLaneMask() & texelPtr.isInBounds(1, robustness);
901*03ce13f7SAndroid Build Coastguard Worker 		for(int i = 0; i < SIMD::Width; i++)
902*03ce13f7SAndroid Build Coastguard Worker 		{
903*03ce13f7SAndroid Build Coastguard Worker 			If(Extract(mask, i) != 0)
904*03ce13f7SAndroid Build Coastguard Worker 			{
905*03ce13f7SAndroid Build Coastguard Worker 				packed[0] = Insert(packed[0], Int(*Pointer<Byte>(texelPtr.getPointerForLane(i))), i);
906*03ce13f7SAndroid Build Coastguard Worker 			}
907*03ce13f7SAndroid Build Coastguard Worker 		}
908*03ce13f7SAndroid Build Coastguard Worker 	}
909*03ce13f7SAndroid Build Coastguard Worker 	else
910*03ce13f7SAndroid Build Coastguard Worker 		UNREACHABLE("texelSize: %d", int(texelSize));
911*03ce13f7SAndroid Build Coastguard Worker 
912*03ce13f7SAndroid Build Coastguard Worker 	// Format support requirements here come from two sources:
913*03ce13f7SAndroid Build Coastguard Worker 	// - Minimum required set of formats for loads from storage images
914*03ce13f7SAndroid Build Coastguard Worker 	// - Any format supported as a color or depth/stencil attachment, for input attachments
915*03ce13f7SAndroid Build Coastguard Worker 	switch(imageFormat)
916*03ce13f7SAndroid Build Coastguard Worker 	{
917*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R32G32B32A32_SFLOAT:
918*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R32G32B32A32_SINT:
919*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R32G32B32A32_UINT:
920*03ce13f7SAndroid Build Coastguard Worker 		dst.move(0, packed[0]);
921*03ce13f7SAndroid Build Coastguard Worker 		dst.move(1, packed[1]);
922*03ce13f7SAndroid Build Coastguard Worker 		dst.move(2, packed[2]);
923*03ce13f7SAndroid Build Coastguard Worker 		dst.move(3, packed[3]);
924*03ce13f7SAndroid Build Coastguard Worker 		break;
925*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R32_SINT:
926*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R32_UINT:
927*03ce13f7SAndroid Build Coastguard Worker 		dst.move(0, packed[0]);
928*03ce13f7SAndroid Build Coastguard Worker 		// Fill remaining channels with 0,0,1 (of the correct type)
929*03ce13f7SAndroid Build Coastguard Worker 		dst.move(1, SIMD::Int(0));
930*03ce13f7SAndroid Build Coastguard Worker 		dst.move(2, SIMD::Int(0));
931*03ce13f7SAndroid Build Coastguard Worker 		dst.move(3, SIMD::Int(1));
932*03ce13f7SAndroid Build Coastguard Worker 		break;
933*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R32_SFLOAT:
934*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_D32_SFLOAT:
935*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_D32_SFLOAT_S8_UINT:
936*03ce13f7SAndroid Build Coastguard Worker 		dst.move(0, packed[0]);
937*03ce13f7SAndroid Build Coastguard Worker 		// Fill remaining channels with 0,0,1 (of the correct type)
938*03ce13f7SAndroid Build Coastguard Worker 		dst.move(1, SIMD::Float(0.0f));
939*03ce13f7SAndroid Build Coastguard Worker 		dst.move(2, SIMD::Float(0.0f));
940*03ce13f7SAndroid Build Coastguard Worker 		dst.move(3, SIMD::Float(1.0f));
941*03ce13f7SAndroid Build Coastguard Worker 		break;
942*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_D16_UNORM:
943*03ce13f7SAndroid Build Coastguard Worker 		dst.move(0, SIMD::Float(packed[0] & SIMD::Int(0xFFFF)) * SIMD::Float(1.0f / 0xFFFF));
944*03ce13f7SAndroid Build Coastguard Worker 		dst.move(1, SIMD::Float(0.0f));
945*03ce13f7SAndroid Build Coastguard Worker 		dst.move(2, SIMD::Float(0.0f));
946*03ce13f7SAndroid Build Coastguard Worker 		dst.move(3, SIMD::Float(1.0f));
947*03ce13f7SAndroid Build Coastguard Worker 		break;
948*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16G16B16A16_UNORM:
949*03ce13f7SAndroid Build Coastguard Worker 		dst.move(0, SIMD::Float(packed[0] & SIMD::Int(0xFFFF)) * SIMD::Float(1.0f / 0xFFFF));
950*03ce13f7SAndroid Build Coastguard Worker 		dst.move(1, SIMD::Float((packed[0] >> 16) & SIMD::Int(0xFFFF)) * SIMD::Float(1.0f / 0xFFFF));
951*03ce13f7SAndroid Build Coastguard Worker 		dst.move(2, SIMD::Float(packed[1] & SIMD::Int(0xFFFF)) * SIMD::Float(1.0f / 0xFFFF));
952*03ce13f7SAndroid Build Coastguard Worker 		dst.move(3, SIMD::Float((packed[1] >> 16) & SIMD::Int(0xFFFF)) * SIMD::Float(1.0f / 0xFFFF));
953*03ce13f7SAndroid Build Coastguard Worker 		break;
954*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16G16B16A16_SNORM:
955*03ce13f7SAndroid Build Coastguard Worker 		dst.move(0, Max(SIMD::Float((packed[0] << 16) & SIMD::Int(0xFFFF0000)) * SIMD::Float(1.0f / 0x7FFF0000), SIMD::Float(-1.0f)));
956*03ce13f7SAndroid Build Coastguard Worker 		dst.move(1, Max(SIMD::Float(packed[0] & SIMD::Int(0xFFFF0000)) * SIMD::Float(1.0f / 0x7FFF0000), SIMD::Float(-1.0f)));
957*03ce13f7SAndroid Build Coastguard Worker 		dst.move(2, Max(SIMD::Float((packed[1] << 16) & SIMD::Int(0xFFFF0000)) * SIMD::Float(1.0f / 0x7FFF0000), SIMD::Float(-1.0f)));
958*03ce13f7SAndroid Build Coastguard Worker 		dst.move(3, Max(SIMD::Float(packed[1] & SIMD::Int(0xFFFF0000)) * SIMD::Float(1.0f / 0x7FFF0000), SIMD::Float(-1.0f)));
959*03ce13f7SAndroid Build Coastguard Worker 		break;
960*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16G16B16A16_SINT:
961*03ce13f7SAndroid Build Coastguard Worker 		dst.move(0, (packed[0] << 16) >> 16);
962*03ce13f7SAndroid Build Coastguard Worker 		dst.move(1, packed[0] >> 16);
963*03ce13f7SAndroid Build Coastguard Worker 		dst.move(2, (packed[1] << 16) >> 16);
964*03ce13f7SAndroid Build Coastguard Worker 		dst.move(3, packed[1] >> 16);
965*03ce13f7SAndroid Build Coastguard Worker 		break;
966*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16G16B16A16_UINT:
967*03ce13f7SAndroid Build Coastguard Worker 		dst.move(0, packed[0] & SIMD::Int(0xFFFF));
968*03ce13f7SAndroid Build Coastguard Worker 		dst.move(1, (packed[0] >> 16) & SIMD::Int(0xFFFF));
969*03ce13f7SAndroid Build Coastguard Worker 		dst.move(2, packed[1] & SIMD::Int(0xFFFF));
970*03ce13f7SAndroid Build Coastguard Worker 		dst.move(3, (packed[1] >> 16) & SIMD::Int(0xFFFF));
971*03ce13f7SAndroid Build Coastguard Worker 		break;
972*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16G16B16A16_SFLOAT:
973*03ce13f7SAndroid Build Coastguard Worker 		dst.move(0, halfToFloatBits(As<SIMD::UInt>(packed[0]) & SIMD::UInt(0x0000FFFF)));
974*03ce13f7SAndroid Build Coastguard Worker 		dst.move(1, halfToFloatBits((As<SIMD::UInt>(packed[0]) & SIMD::UInt(0xFFFF0000)) >> 16));
975*03ce13f7SAndroid Build Coastguard Worker 		dst.move(2, halfToFloatBits(As<SIMD::UInt>(packed[1]) & SIMD::UInt(0x0000FFFF)));
976*03ce13f7SAndroid Build Coastguard Worker 		dst.move(3, halfToFloatBits((As<SIMD::UInt>(packed[1]) & SIMD::UInt(0xFFFF0000)) >> 16));
977*03ce13f7SAndroid Build Coastguard Worker 		break;
978*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8G8B8A8_SNORM:
979*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_A8B8G8R8_SNORM_PACK32:
980*03ce13f7SAndroid Build Coastguard Worker 		dst.move(0, Max(SIMD::Float((packed[0] << 24) & SIMD::Int(0xFF000000)) * SIMD::Float(1.0f / 0x7F000000), SIMD::Float(-1.0f)));
981*03ce13f7SAndroid Build Coastguard Worker 		dst.move(1, Max(SIMD::Float((packed[0] << 16) & SIMD::Int(0xFF000000)) * SIMD::Float(1.0f / 0x7F000000), SIMD::Float(-1.0f)));
982*03ce13f7SAndroid Build Coastguard Worker 		dst.move(2, Max(SIMD::Float((packed[0] << 8) & SIMD::Int(0xFF000000)) * SIMD::Float(1.0f / 0x7F000000), SIMD::Float(-1.0f)));
983*03ce13f7SAndroid Build Coastguard Worker 		dst.move(3, Max(SIMD::Float((packed[0]) & SIMD::Int(0xFF000000)) * SIMD::Float(1.0f / 0x7F000000), SIMD::Float(-1.0f)));
984*03ce13f7SAndroid Build Coastguard Worker 		break;
985*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8G8B8A8_UNORM:
986*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_A8B8G8R8_UNORM_PACK32:
987*03ce13f7SAndroid Build Coastguard Worker 		dst.move(0, SIMD::Float(packed[0] & SIMD::Int(0xFF)) * SIMD::Float(1.0f / 0xFF));
988*03ce13f7SAndroid Build Coastguard Worker 		dst.move(1, SIMD::Float((packed[0] >> 8) & SIMD::Int(0xFF)) * SIMD::Float(1.0f / 0xFF));
989*03ce13f7SAndroid Build Coastguard Worker 		dst.move(2, SIMD::Float((packed[0] >> 16) & SIMD::Int(0xFF)) * SIMD::Float(1.0f / 0xFF));
990*03ce13f7SAndroid Build Coastguard Worker 		dst.move(3, SIMD::Float((packed[0] >> 24) & SIMD::Int(0xFF)) * SIMD::Float(1.0f / 0xFF));
991*03ce13f7SAndroid Build Coastguard Worker 		break;
992*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8G8B8A8_SRGB:
993*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_A8B8G8R8_SRGB_PACK32:
994*03ce13f7SAndroid Build Coastguard Worker 		dst.move(0, sRGBtoLinear(SIMD::Float(packed[0] & SIMD::Int(0xFF)) * SIMD::Float(1.0f / 0xFF)));
995*03ce13f7SAndroid Build Coastguard Worker 		dst.move(1, sRGBtoLinear(SIMD::Float((packed[0] >> 8) & SIMD::Int(0xFF)) * SIMD::Float(1.0f / 0xFF)));
996*03ce13f7SAndroid Build Coastguard Worker 		dst.move(2, sRGBtoLinear(SIMD::Float((packed[0] >> 16) & SIMD::Int(0xFF)) * SIMD::Float(1.0f / 0xFF)));
997*03ce13f7SAndroid Build Coastguard Worker 		dst.move(3, SIMD::Float((packed[0] >> 24) & SIMD::Int(0xFF)) * SIMD::Float(1.0f / 0xFF));
998*03ce13f7SAndroid Build Coastguard Worker 		break;
999*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_B8G8R8A8_UNORM:
1000*03ce13f7SAndroid Build Coastguard Worker 		dst.move(0, SIMD::Float((packed[0] >> 16) & SIMD::Int(0xFF)) * SIMD::Float(1.0f / 0xFF));
1001*03ce13f7SAndroid Build Coastguard Worker 		dst.move(1, SIMD::Float((packed[0] >> 8) & SIMD::Int(0xFF)) * SIMD::Float(1.0f / 0xFF));
1002*03ce13f7SAndroid Build Coastguard Worker 		dst.move(2, SIMD::Float(packed[0] & SIMD::Int(0xFF)) * SIMD::Float(1.0f / 0xFF));
1003*03ce13f7SAndroid Build Coastguard Worker 		dst.move(3, SIMD::Float((packed[0] >> 24) & SIMD::Int(0xFF)) * SIMD::Float(1.0f / 0xFF));
1004*03ce13f7SAndroid Build Coastguard Worker 		break;
1005*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_B8G8R8A8_SRGB:
1006*03ce13f7SAndroid Build Coastguard Worker 		dst.move(0, sRGBtoLinear(SIMD::Float((packed[0] >> 16) & SIMD::Int(0xFF)) * SIMD::Float(1.0f / 0xFF)));
1007*03ce13f7SAndroid Build Coastguard Worker 		dst.move(1, sRGBtoLinear(SIMD::Float((packed[0] >> 8) & SIMD::Int(0xFF)) * SIMD::Float(1.0f / 0xFF)));
1008*03ce13f7SAndroid Build Coastguard Worker 		dst.move(2, sRGBtoLinear(SIMD::Float(packed[0] & SIMD::Int(0xFF)) * SIMD::Float(1.0f / 0xFF)));
1009*03ce13f7SAndroid Build Coastguard Worker 		dst.move(3, SIMD::Float((packed[0] >> 24) & SIMD::Int(0xFF)) * SIMD::Float(1.0f / 0xFF));
1010*03ce13f7SAndroid Build Coastguard Worker 		break;
1011*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8G8B8A8_UINT:
1012*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_A8B8G8R8_UINT_PACK32:
1013*03ce13f7SAndroid Build Coastguard Worker 		dst.move(0, As<SIMD::UInt>(packed[0]) & SIMD::UInt(0xFF));
1014*03ce13f7SAndroid Build Coastguard Worker 		dst.move(1, (As<SIMD::UInt>(packed[0]) >> 8) & SIMD::UInt(0xFF));
1015*03ce13f7SAndroid Build Coastguard Worker 		dst.move(2, (As<SIMD::UInt>(packed[0]) >> 16) & SIMD::UInt(0xFF));
1016*03ce13f7SAndroid Build Coastguard Worker 		dst.move(3, (As<SIMD::UInt>(packed[0]) >> 24) & SIMD::UInt(0xFF));
1017*03ce13f7SAndroid Build Coastguard Worker 		break;
1018*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8G8B8A8_SINT:
1019*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_A8B8G8R8_SINT_PACK32:
1020*03ce13f7SAndroid Build Coastguard Worker 		dst.move(0, (packed[0] << 24) >> 24);
1021*03ce13f7SAndroid Build Coastguard Worker 		dst.move(1, (packed[0] << 16) >> 24);
1022*03ce13f7SAndroid Build Coastguard Worker 		dst.move(2, (packed[0] << 8) >> 24);
1023*03ce13f7SAndroid Build Coastguard Worker 		dst.move(3, packed[0] >> 24);
1024*03ce13f7SAndroid Build Coastguard Worker 		break;
1025*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8_UNORM:
1026*03ce13f7SAndroid Build Coastguard Worker 		dst.move(0, SIMD::Float((packed[0] & SIMD::Int(0xFF))) * SIMD::Float(1.0f / 0xFF));
1027*03ce13f7SAndroid Build Coastguard Worker 		dst.move(1, SIMD::Float(0.0f));
1028*03ce13f7SAndroid Build Coastguard Worker 		dst.move(2, SIMD::Float(0.0f));
1029*03ce13f7SAndroid Build Coastguard Worker 		dst.move(3, SIMD::Float(1.0f));
1030*03ce13f7SAndroid Build Coastguard Worker 		break;
1031*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8_SNORM:
1032*03ce13f7SAndroid Build Coastguard Worker 		dst.move(0, Max(SIMD::Float((packed[0] << 24) & SIMD::Int(0xFF000000)) * SIMD::Float(1.0f / 0x7F000000), SIMD::Float(-1.0f)));
1033*03ce13f7SAndroid Build Coastguard Worker 		dst.move(1, SIMD::Float(0.0f));
1034*03ce13f7SAndroid Build Coastguard Worker 		dst.move(2, SIMD::Float(0.0f));
1035*03ce13f7SAndroid Build Coastguard Worker 		dst.move(3, SIMD::Float(1.0f));
1036*03ce13f7SAndroid Build Coastguard Worker 		break;
1037*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8_UINT:
1038*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_S8_UINT:
1039*03ce13f7SAndroid Build Coastguard Worker 		dst.move(0, As<SIMD::UInt>(packed[0]) & SIMD::UInt(0xFF));
1040*03ce13f7SAndroid Build Coastguard Worker 		dst.move(1, SIMD::UInt(0));
1041*03ce13f7SAndroid Build Coastguard Worker 		dst.move(2, SIMD::UInt(0));
1042*03ce13f7SAndroid Build Coastguard Worker 		dst.move(3, SIMD::UInt(1));
1043*03ce13f7SAndroid Build Coastguard Worker 		break;
1044*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8_SINT:
1045*03ce13f7SAndroid Build Coastguard Worker 		dst.move(0, (packed[0] << 24) >> 24);
1046*03ce13f7SAndroid Build Coastguard Worker 		dst.move(1, SIMD::Int(0));
1047*03ce13f7SAndroid Build Coastguard Worker 		dst.move(2, SIMD::Int(0));
1048*03ce13f7SAndroid Build Coastguard Worker 		dst.move(3, SIMD::Int(1));
1049*03ce13f7SAndroid Build Coastguard Worker 		break;
1050*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8G8_UNORM:
1051*03ce13f7SAndroid Build Coastguard Worker 		dst.move(0, SIMD::Float(packed[0] & SIMD::Int(0xFF)) * SIMD::Float(1.0f / 0xFF));
1052*03ce13f7SAndroid Build Coastguard Worker 		dst.move(1, SIMD::Float((packed[0] >> 8) & SIMD::Int(0xFF)) * SIMD::Float(1.0f / 0xFF));
1053*03ce13f7SAndroid Build Coastguard Worker 		dst.move(2, SIMD::Float(0.0f));
1054*03ce13f7SAndroid Build Coastguard Worker 		dst.move(3, SIMD::Float(1.0f));
1055*03ce13f7SAndroid Build Coastguard Worker 		break;
1056*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8G8_SNORM:
1057*03ce13f7SAndroid Build Coastguard Worker 		dst.move(0, Max(SIMD::Float((packed[0] << 24) & SIMD::Int(0xFF000000)) * SIMD::Float(1.0f / 0x7F000000), SIMD::Float(-1.0f)));
1058*03ce13f7SAndroid Build Coastguard Worker 		dst.move(1, Max(SIMD::Float((packed[0] << 16) & SIMD::Int(0xFF000000)) * SIMD::Float(1.0f / 0x7F000000), SIMD::Float(-1.0f)));
1059*03ce13f7SAndroid Build Coastguard Worker 		dst.move(2, SIMD::Float(0.0f));
1060*03ce13f7SAndroid Build Coastguard Worker 		dst.move(3, SIMD::Float(1.0f));
1061*03ce13f7SAndroid Build Coastguard Worker 		break;
1062*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8G8_UINT:
1063*03ce13f7SAndroid Build Coastguard Worker 		dst.move(0, As<SIMD::UInt>(packed[0]) & SIMD::UInt(0xFF));
1064*03ce13f7SAndroid Build Coastguard Worker 		dst.move(1, (As<SIMD::UInt>(packed[0]) >> 8) & SIMD::UInt(0xFF));
1065*03ce13f7SAndroid Build Coastguard Worker 		dst.move(2, SIMD::UInt(0));
1066*03ce13f7SAndroid Build Coastguard Worker 		dst.move(3, SIMD::UInt(1));
1067*03ce13f7SAndroid Build Coastguard Worker 		break;
1068*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8G8_SINT:
1069*03ce13f7SAndroid Build Coastguard Worker 		dst.move(0, (packed[0] << 24) >> 24);
1070*03ce13f7SAndroid Build Coastguard Worker 		dst.move(1, (packed[0] << 16) >> 24);
1071*03ce13f7SAndroid Build Coastguard Worker 		dst.move(2, SIMD::Int(0));
1072*03ce13f7SAndroid Build Coastguard Worker 		dst.move(3, SIMD::Int(1));
1073*03ce13f7SAndroid Build Coastguard Worker 		break;
1074*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16_SFLOAT:
1075*03ce13f7SAndroid Build Coastguard Worker 		dst.move(0, halfToFloatBits(As<SIMD::UInt>(packed[0]) & SIMD::UInt(0x0000FFFF)));
1076*03ce13f7SAndroid Build Coastguard Worker 		dst.move(1, SIMD::Float(0.0f));
1077*03ce13f7SAndroid Build Coastguard Worker 		dst.move(2, SIMD::Float(0.0f));
1078*03ce13f7SAndroid Build Coastguard Worker 		dst.move(3, SIMD::Float(1.0f));
1079*03ce13f7SAndroid Build Coastguard Worker 		break;
1080*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16_UNORM:
1081*03ce13f7SAndroid Build Coastguard Worker 		dst.move(0, SIMD::Float(packed[0] & SIMD::Int(0xFFFF)) * SIMD::Float(1.0f / 0xFFFF));
1082*03ce13f7SAndroid Build Coastguard Worker 		dst.move(1, SIMD::Float(0.0f));
1083*03ce13f7SAndroid Build Coastguard Worker 		dst.move(2, SIMD::Float(0.0f));
1084*03ce13f7SAndroid Build Coastguard Worker 		dst.move(3, SIMD::Float(1.0f));
1085*03ce13f7SAndroid Build Coastguard Worker 		break;
1086*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16_SNORM:
1087*03ce13f7SAndroid Build Coastguard Worker 		dst.move(0, Max(SIMD::Float((packed[0] << 16) & SIMD::Int(0xFFFF0000)) * SIMD::Float(1.0f / 0x7FFF0000), SIMD::Float(-1.0f)));
1088*03ce13f7SAndroid Build Coastguard Worker 		dst.move(1, SIMD::Float(0.0f));
1089*03ce13f7SAndroid Build Coastguard Worker 		dst.move(2, SIMD::Float(0.0f));
1090*03ce13f7SAndroid Build Coastguard Worker 		dst.move(3, SIMD::Float(1.0f));
1091*03ce13f7SAndroid Build Coastguard Worker 		break;
1092*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16_UINT:
1093*03ce13f7SAndroid Build Coastguard Worker 		dst.move(0, packed[0] & SIMD::Int(0xFFFF));
1094*03ce13f7SAndroid Build Coastguard Worker 		dst.move(1, SIMD::UInt(0));
1095*03ce13f7SAndroid Build Coastguard Worker 		dst.move(2, SIMD::UInt(0));
1096*03ce13f7SAndroid Build Coastguard Worker 		dst.move(3, SIMD::UInt(1));
1097*03ce13f7SAndroid Build Coastguard Worker 		break;
1098*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16_SINT:
1099*03ce13f7SAndroid Build Coastguard Worker 		dst.move(0, (packed[0] << 16) >> 16);
1100*03ce13f7SAndroid Build Coastguard Worker 		dst.move(1, SIMD::Int(0));
1101*03ce13f7SAndroid Build Coastguard Worker 		dst.move(2, SIMD::Int(0));
1102*03ce13f7SAndroid Build Coastguard Worker 		dst.move(3, SIMD::Int(1));
1103*03ce13f7SAndroid Build Coastguard Worker 		break;
1104*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16G16_SFLOAT:
1105*03ce13f7SAndroid Build Coastguard Worker 		dst.move(0, halfToFloatBits(As<SIMD::UInt>(packed[0]) & SIMD::UInt(0x0000FFFF)));
1106*03ce13f7SAndroid Build Coastguard Worker 		dst.move(1, halfToFloatBits((As<SIMD::UInt>(packed[0]) & SIMD::UInt(0xFFFF0000)) >> 16));
1107*03ce13f7SAndroid Build Coastguard Worker 		dst.move(2, SIMD::Float(0.0f));
1108*03ce13f7SAndroid Build Coastguard Worker 		dst.move(3, SIMD::Float(1.0f));
1109*03ce13f7SAndroid Build Coastguard Worker 		break;
1110*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16G16_UNORM:
1111*03ce13f7SAndroid Build Coastguard Worker 		dst.move(0, SIMD::Float(packed[0] & SIMD::Int(0xFFFF)) * SIMD::Float(1.0f / 0xFFFF));
1112*03ce13f7SAndroid Build Coastguard Worker 		dst.move(1, SIMD::Float(As<SIMD::UInt>(packed[0]) >> 16) * SIMD::Float(1.0f / 0xFFFF));
1113*03ce13f7SAndroid Build Coastguard Worker 		dst.move(2, SIMD::Float(0.0f));
1114*03ce13f7SAndroid Build Coastguard Worker 		dst.move(3, SIMD::Float(1.0f));
1115*03ce13f7SAndroid Build Coastguard Worker 		break;
1116*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16G16_SNORM:
1117*03ce13f7SAndroid Build Coastguard Worker 		dst.move(0, Max(SIMD::Float((packed[0] << 16) & SIMD::Int(0xFFFF0000)) * SIMD::Float(1.0f / 0x7FFF0000), SIMD::Float(-1.0f)));
1118*03ce13f7SAndroid Build Coastguard Worker 		dst.move(1, Max(SIMD::Float(packed[0] & SIMD::Int(0xFFFF0000)) * SIMD::Float(1.0f / 0x7FFF0000), SIMD::Float(-1.0f)));
1119*03ce13f7SAndroid Build Coastguard Worker 		dst.move(2, SIMD::Float(0.0f));
1120*03ce13f7SAndroid Build Coastguard Worker 		dst.move(3, SIMD::Float(1.0f));
1121*03ce13f7SAndroid Build Coastguard Worker 		break;
1122*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16G16_UINT:
1123*03ce13f7SAndroid Build Coastguard Worker 		dst.move(0, packed[0] & SIMD::Int(0xFFFF));
1124*03ce13f7SAndroid Build Coastguard Worker 		dst.move(1, (packed[0] >> 16) & SIMD::Int(0xFFFF));
1125*03ce13f7SAndroid Build Coastguard Worker 		dst.move(2, SIMD::UInt(0));
1126*03ce13f7SAndroid Build Coastguard Worker 		dst.move(3, SIMD::UInt(1));
1127*03ce13f7SAndroid Build Coastguard Worker 		break;
1128*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16G16_SINT:
1129*03ce13f7SAndroid Build Coastguard Worker 		dst.move(0, (packed[0] << 16) >> 16);
1130*03ce13f7SAndroid Build Coastguard Worker 		dst.move(1, packed[0] >> 16);
1131*03ce13f7SAndroid Build Coastguard Worker 		dst.move(2, SIMD::Int(0));
1132*03ce13f7SAndroid Build Coastguard Worker 		dst.move(3, SIMD::Int(1));
1133*03ce13f7SAndroid Build Coastguard Worker 		break;
1134*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R32G32_SINT:
1135*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R32G32_UINT:
1136*03ce13f7SAndroid Build Coastguard Worker 		dst.move(0, packed[0]);
1137*03ce13f7SAndroid Build Coastguard Worker 		dst.move(1, packed[1]);
1138*03ce13f7SAndroid Build Coastguard Worker 		dst.move(2, SIMD::Int(0));
1139*03ce13f7SAndroid Build Coastguard Worker 		dst.move(3, SIMD::Int(1));
1140*03ce13f7SAndroid Build Coastguard Worker 		break;
1141*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R32G32_SFLOAT:
1142*03ce13f7SAndroid Build Coastguard Worker 		dst.move(0, packed[0]);
1143*03ce13f7SAndroid Build Coastguard Worker 		dst.move(1, packed[1]);
1144*03ce13f7SAndroid Build Coastguard Worker 		dst.move(2, SIMD::Float(0.0f));
1145*03ce13f7SAndroid Build Coastguard Worker 		dst.move(3, SIMD::Float(1.0f));
1146*03ce13f7SAndroid Build Coastguard Worker 		break;
1147*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_A2B10G10R10_UINT_PACK32:
1148*03ce13f7SAndroid Build Coastguard Worker 		dst.move(0, packed[0] & SIMD::Int(0x3FF));
1149*03ce13f7SAndroid Build Coastguard Worker 		dst.move(1, (packed[0] >> 10) & SIMD::Int(0x3FF));
1150*03ce13f7SAndroid Build Coastguard Worker 		dst.move(2, (packed[0] >> 20) & SIMD::Int(0x3FF));
1151*03ce13f7SAndroid Build Coastguard Worker 		dst.move(3, (packed[0] >> 30) & SIMD::Int(0x3));
1152*03ce13f7SAndroid Build Coastguard Worker 		break;
1153*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_A2R10G10B10_UINT_PACK32:
1154*03ce13f7SAndroid Build Coastguard Worker 		dst.move(2, packed[0] & SIMD::Int(0x3FF));
1155*03ce13f7SAndroid Build Coastguard Worker 		dst.move(1, (packed[0] >> 10) & SIMD::Int(0x3FF));
1156*03ce13f7SAndroid Build Coastguard Worker 		dst.move(0, (packed[0] >> 20) & SIMD::Int(0x3FF));
1157*03ce13f7SAndroid Build Coastguard Worker 		dst.move(3, (packed[0] >> 30) & SIMD::Int(0x3));
1158*03ce13f7SAndroid Build Coastguard Worker 		break;
1159*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_A2B10G10R10_UNORM_PACK32:
1160*03ce13f7SAndroid Build Coastguard Worker 		dst.move(0, SIMD::Float((packed[0]) & SIMD::Int(0x3FF)) * SIMD::Float(1.0f / 0x3FF));
1161*03ce13f7SAndroid Build Coastguard Worker 		dst.move(1, SIMD::Float((packed[0] >> 10) & SIMD::Int(0x3FF)) * SIMD::Float(1.0f / 0x3FF));
1162*03ce13f7SAndroid Build Coastguard Worker 		dst.move(2, SIMD::Float((packed[0] >> 20) & SIMD::Int(0x3FF)) * SIMD::Float(1.0f / 0x3FF));
1163*03ce13f7SAndroid Build Coastguard Worker 		dst.move(3, SIMD::Float((packed[0] >> 30) & SIMD::Int(0x3)) * SIMD::Float(1.0f / 0x3));
1164*03ce13f7SAndroid Build Coastguard Worker 		break;
1165*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_A2R10G10B10_UNORM_PACK32:
1166*03ce13f7SAndroid Build Coastguard Worker 		dst.move(2, SIMD::Float((packed[0]) & SIMD::Int(0x3FF)) * SIMD::Float(1.0f / 0x3FF));
1167*03ce13f7SAndroid Build Coastguard Worker 		dst.move(1, SIMD::Float((packed[0] >> 10) & SIMD::Int(0x3FF)) * SIMD::Float(1.0f / 0x3FF));
1168*03ce13f7SAndroid Build Coastguard Worker 		dst.move(0, SIMD::Float((packed[0] >> 20) & SIMD::Int(0x3FF)) * SIMD::Float(1.0f / 0x3FF));
1169*03ce13f7SAndroid Build Coastguard Worker 		dst.move(3, SIMD::Float((packed[0] >> 30) & SIMD::Int(0x3)) * SIMD::Float(1.0f / 0x3));
1170*03ce13f7SAndroid Build Coastguard Worker 		break;
1171*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R4G4B4A4_UNORM_PACK16:
1172*03ce13f7SAndroid Build Coastguard Worker 		dst.move(0, SIMD::Float((packed[0] >> 12) & SIMD::Int(0xF)) * SIMD::Float(1.0f / 0xF));
1173*03ce13f7SAndroid Build Coastguard Worker 		dst.move(1, SIMD::Float((packed[0] >> 8) & SIMD::Int(0xF)) * SIMD::Float(1.0f / 0xF));
1174*03ce13f7SAndroid Build Coastguard Worker 		dst.move(2, SIMD::Float((packed[0] >> 4) & SIMD::Int(0xF)) * SIMD::Float(1.0f / 0xF));
1175*03ce13f7SAndroid Build Coastguard Worker 		dst.move(3, SIMD::Float((packed[0]) & SIMD::Int(0xF)) * SIMD::Float(1.0f / 0xF));
1176*03ce13f7SAndroid Build Coastguard Worker 		break;
1177*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_B4G4R4A4_UNORM_PACK16:
1178*03ce13f7SAndroid Build Coastguard Worker 		dst.move(0, SIMD::Float((packed[0] >> 4) & SIMD::Int(0xF)) * SIMD::Float(1.0f / 0xF));
1179*03ce13f7SAndroid Build Coastguard Worker 		dst.move(1, SIMD::Float((packed[0] >> 8) & SIMD::Int(0xF)) * SIMD::Float(1.0f / 0xF));
1180*03ce13f7SAndroid Build Coastguard Worker 		dst.move(2, SIMD::Float((packed[0] >> 12) & SIMD::Int(0xF)) * SIMD::Float(1.0f / 0xF));
1181*03ce13f7SAndroid Build Coastguard Worker 		dst.move(3, SIMD::Float((packed[0]) & SIMD::Int(0xF)) * SIMD::Float(1.0f / 0xF));
1182*03ce13f7SAndroid Build Coastguard Worker 		break;
1183*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_A4R4G4B4_UNORM_PACK16:
1184*03ce13f7SAndroid Build Coastguard Worker 		dst.move(0, SIMD::Float((packed[0] >> 8) & SIMD::Int(0xF)) * SIMD::Float(1.0f / 0xF));
1185*03ce13f7SAndroid Build Coastguard Worker 		dst.move(1, SIMD::Float((packed[0] >> 4) & SIMD::Int(0xF)) * SIMD::Float(1.0f / 0xF));
1186*03ce13f7SAndroid Build Coastguard Worker 		dst.move(2, SIMD::Float((packed[0]) & SIMD::Int(0xF)) * SIMD::Float(1.0f / 0xF));
1187*03ce13f7SAndroid Build Coastguard Worker 		dst.move(3, SIMD::Float((packed[0] >> 12) & SIMD::Int(0xF)) * SIMD::Float(1.0f / 0xF));
1188*03ce13f7SAndroid Build Coastguard Worker 		break;
1189*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_A4B4G4R4_UNORM_PACK16:
1190*03ce13f7SAndroid Build Coastguard Worker 		dst.move(0, SIMD::Float((packed[0]) & SIMD::Int(0xF)) * SIMD::Float(1.0f / 0xF));
1191*03ce13f7SAndroid Build Coastguard Worker 		dst.move(1, SIMD::Float((packed[0] >> 4) & SIMD::Int(0xF)) * SIMD::Float(1.0f / 0xF));
1192*03ce13f7SAndroid Build Coastguard Worker 		dst.move(2, SIMD::Float((packed[0] >> 8) & SIMD::Int(0xF)) * SIMD::Float(1.0f / 0xF));
1193*03ce13f7SAndroid Build Coastguard Worker 		dst.move(3, SIMD::Float((packed[0] >> 12) & SIMD::Int(0xF)) * SIMD::Float(1.0f / 0xF));
1194*03ce13f7SAndroid Build Coastguard Worker 		break;
1195*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R5G6B5_UNORM_PACK16:
1196*03ce13f7SAndroid Build Coastguard Worker 		dst.move(0, SIMD::Float((packed[0] >> 11) & SIMD::Int(0x1F)) * SIMD::Float(1.0f / 0x1F));
1197*03ce13f7SAndroid Build Coastguard Worker 		dst.move(1, SIMD::Float((packed[0] >> 5) & SIMD::Int(0x3F)) * SIMD::Float(1.0f / 0x3F));
1198*03ce13f7SAndroid Build Coastguard Worker 		dst.move(2, SIMD::Float((packed[0]) & SIMD::Int(0x1F)) * SIMD::Float(1.0f / 0x1F));
1199*03ce13f7SAndroid Build Coastguard Worker 		dst.move(3, SIMD::Float(1.0f));
1200*03ce13f7SAndroid Build Coastguard Worker 		break;
1201*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_B5G6R5_UNORM_PACK16:
1202*03ce13f7SAndroid Build Coastguard Worker 		dst.move(0, SIMD::Float((packed[0]) & SIMD::Int(0x1F)) * SIMD::Float(1.0f / 0x1F));
1203*03ce13f7SAndroid Build Coastguard Worker 		dst.move(1, SIMD::Float((packed[0] >> 5) & SIMD::Int(0x3F)) * SIMD::Float(1.0f / 0x3F));
1204*03ce13f7SAndroid Build Coastguard Worker 		dst.move(2, SIMD::Float((packed[0] >> 11) & SIMD::Int(0x1F)) * SIMD::Float(1.0f / 0x1F));
1205*03ce13f7SAndroid Build Coastguard Worker 		dst.move(3, SIMD::Float(1.0f));
1206*03ce13f7SAndroid Build Coastguard Worker 		break;
1207*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R5G5B5A1_UNORM_PACK16:
1208*03ce13f7SAndroid Build Coastguard Worker 		dst.move(0, SIMD::Float((packed[0] >> 11) & SIMD::Int(0x1F)) * SIMD::Float(1.0f / 0x1F));
1209*03ce13f7SAndroid Build Coastguard Worker 		dst.move(1, SIMD::Float((packed[0] >> 6) & SIMD::Int(0x1F)) * SIMD::Float(1.0f / 0x1F));
1210*03ce13f7SAndroid Build Coastguard Worker 		dst.move(2, SIMD::Float((packed[0] >> 1) & SIMD::Int(0x1F)) * SIMD::Float(1.0f / 0x1F));
1211*03ce13f7SAndroid Build Coastguard Worker 		dst.move(3, SIMD::Float((packed[0]) & SIMD::Int(0x1)));
1212*03ce13f7SAndroid Build Coastguard Worker 		break;
1213*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_B5G5R5A1_UNORM_PACK16:
1214*03ce13f7SAndroid Build Coastguard Worker 		dst.move(0, SIMD::Float((packed[0] >> 1) & SIMD::Int(0x1F)) * SIMD::Float(1.0f / 0x1F));
1215*03ce13f7SAndroid Build Coastguard Worker 		dst.move(1, SIMD::Float((packed[0] >> 6) & SIMD::Int(0x1F)) * SIMD::Float(1.0f / 0x1F));
1216*03ce13f7SAndroid Build Coastguard Worker 		dst.move(2, SIMD::Float((packed[0] >> 11) & SIMD::Int(0x1F)) * SIMD::Float(1.0f / 0x1F));
1217*03ce13f7SAndroid Build Coastguard Worker 		dst.move(3, SIMD::Float((packed[0]) & SIMD::Int(0x1)));
1218*03ce13f7SAndroid Build Coastguard Worker 		break;
1219*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_A1R5G5B5_UNORM_PACK16:
1220*03ce13f7SAndroid Build Coastguard Worker 		dst.move(0, SIMD::Float((packed[0] >> 10) & SIMD::Int(0x1F)) * SIMD::Float(1.0f / 0x1F));
1221*03ce13f7SAndroid Build Coastguard Worker 		dst.move(1, SIMD::Float((packed[0] >> 5) & SIMD::Int(0x1F)) * SIMD::Float(1.0f / 0x1F));
1222*03ce13f7SAndroid Build Coastguard Worker 		dst.move(2, SIMD::Float((packed[0]) & SIMD::Int(0x1F)) * SIMD::Float(1.0f / 0x1F));
1223*03ce13f7SAndroid Build Coastguard Worker 		dst.move(3, SIMD::Float((packed[0] >> 15) & SIMD::Int(0x1)));
1224*03ce13f7SAndroid Build Coastguard Worker 		break;
1225*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_B10G11R11_UFLOAT_PACK32:
1226*03ce13f7SAndroid Build Coastguard Worker 		dst.move(0, halfToFloatBits((packed[0] << 4) & SIMD::Int(0x7FF0)));
1227*03ce13f7SAndroid Build Coastguard Worker 		dst.move(1, halfToFloatBits((packed[0] >> 7) & SIMD::Int(0x7FF0)));
1228*03ce13f7SAndroid Build Coastguard Worker 		dst.move(2, halfToFloatBits((packed[0] >> 17) & SIMD::Int(0x7FE0)));
1229*03ce13f7SAndroid Build Coastguard Worker 		dst.move(3, SIMD::Float(1.0f));
1230*03ce13f7SAndroid Build Coastguard Worker 		break;
1231*03ce13f7SAndroid Build Coastguard Worker 	default:
1232*03ce13f7SAndroid Build Coastguard Worker 		UNSUPPORTED("VkFormat %d", int(imageFormat));
1233*03ce13f7SAndroid Build Coastguard Worker 		break;
1234*03ce13f7SAndroid Build Coastguard Worker 	}
1235*03ce13f7SAndroid Build Coastguard Worker }
1236*03ce13f7SAndroid Build Coastguard Worker 
EmitImageWrite(const ImageInstruction & instruction)1237*03ce13f7SAndroid Build Coastguard Worker void SpirvEmitter::EmitImageWrite(const ImageInstruction &instruction)
1238*03ce13f7SAndroid Build Coastguard Worker {
1239*03ce13f7SAndroid Build Coastguard Worker 	auto &image = shader.getObject(instruction.imageId);
1240*03ce13f7SAndroid Build Coastguard Worker 	auto &imageType = shader.getType(image);
1241*03ce13f7SAndroid Build Coastguard Worker 
1242*03ce13f7SAndroid Build Coastguard Worker 	ASSERT(imageType.definition.opcode() == spv::OpTypeImage);
1243*03ce13f7SAndroid Build Coastguard Worker 	ASSERT(static_cast<spv::Dim>(instruction.dim) != spv::DimSubpassData);  // "Its Dim operand must not be SubpassData."
1244*03ce13f7SAndroid Build Coastguard Worker 
1245*03ce13f7SAndroid Build Coastguard Worker 	auto coordinate = Operand(shader, *this, instruction.coordinateId);
1246*03ce13f7SAndroid Build Coastguard Worker 	auto texel = Operand(shader, *this, instruction.texelId);
1247*03ce13f7SAndroid Build Coastguard Worker 
1248*03ce13f7SAndroid Build Coastguard Worker 	Array<SIMD::Int> coord(5);  // uvwa & sample
1249*03ce13f7SAndroid Build Coastguard Worker 
1250*03ce13f7SAndroid Build Coastguard Worker 	uint32_t i = 0;
1251*03ce13f7SAndroid Build Coastguard Worker 	for(; i < instruction.coordinates; i++)
1252*03ce13f7SAndroid Build Coastguard Worker 	{
1253*03ce13f7SAndroid Build Coastguard Worker 		coord[i] = coordinate.Int(i);
1254*03ce13f7SAndroid Build Coastguard Worker 	}
1255*03ce13f7SAndroid Build Coastguard Worker 
1256*03ce13f7SAndroid Build Coastguard Worker 	if(instruction.sample)
1257*03ce13f7SAndroid Build Coastguard Worker 	{
1258*03ce13f7SAndroid Build Coastguard Worker 		coord[i] = Operand(shader, *this, instruction.sampleId).Int(0);
1259*03ce13f7SAndroid Build Coastguard Worker 	}
1260*03ce13f7SAndroid Build Coastguard Worker 
1261*03ce13f7SAndroid Build Coastguard Worker 	Array<SIMD::Int> texelAndMask(5);
1262*03ce13f7SAndroid Build Coastguard Worker 	for(uint32_t i = 0; i < texel.componentCount; ++i)
1263*03ce13f7SAndroid Build Coastguard Worker 	{
1264*03ce13f7SAndroid Build Coastguard Worker 		texelAndMask[i] = texel.Int(i);
1265*03ce13f7SAndroid Build Coastguard Worker 	}
1266*03ce13f7SAndroid Build Coastguard Worker 	for(uint32_t i = texel.componentCount; i < 4; ++i)
1267*03ce13f7SAndroid Build Coastguard Worker 	{
1268*03ce13f7SAndroid Build Coastguard Worker 		texelAndMask[i] = SIMD::Int(0);
1269*03ce13f7SAndroid Build Coastguard Worker 	}
1270*03ce13f7SAndroid Build Coastguard Worker 	texelAndMask[4] = activeStoresAndAtomicsMask();
1271*03ce13f7SAndroid Build Coastguard Worker 
1272*03ce13f7SAndroid Build Coastguard Worker 	vk::Format imageFormat = SpirvFormatToVulkanFormat(static_cast<spv::ImageFormat>(instruction.imageFormat));
1273*03ce13f7SAndroid Build Coastguard Worker 
1274*03ce13f7SAndroid Build Coastguard Worker 	SIMD::Pointer ptr = getPointer(instruction.imageId);
1275*03ce13f7SAndroid Build Coastguard Worker 	if(ptr.isBasePlusOffset)
1276*03ce13f7SAndroid Build Coastguard Worker 	{
1277*03ce13f7SAndroid Build Coastguard Worker 		Pointer<Byte> imageDescriptor = ptr.getUniformPointer();  // vk::StorageImageDescriptor* or vk::SampledImageDescriptor*
1278*03ce13f7SAndroid Build Coastguard Worker 		Pointer<Byte> samplerDescriptor = getSamplerDescriptor(imageDescriptor, instruction);
1279*03ce13f7SAndroid Build Coastguard Worker 
1280*03ce13f7SAndroid Build Coastguard Worker 		if(imageFormat == VK_FORMAT_UNDEFINED)  // spv::ImageFormatUnknown
1281*03ce13f7SAndroid Build Coastguard Worker 		{
1282*03ce13f7SAndroid Build Coastguard Worker 			Pointer<Byte> samplerFunction = lookupSamplerFunction(imageDescriptor, samplerDescriptor, instruction);
1283*03ce13f7SAndroid Build Coastguard Worker 
1284*03ce13f7SAndroid Build Coastguard Worker 			Call<ImageSampler>(samplerFunction, imageDescriptor, &coord, &texelAndMask, routine->constants);
1285*03ce13f7SAndroid Build Coastguard Worker 		}
1286*03ce13f7SAndroid Build Coastguard Worker 		else
1287*03ce13f7SAndroid Build Coastguard Worker 		{
1288*03ce13f7SAndroid Build Coastguard Worker 			WriteImage(instruction, imageDescriptor, &coord, &texelAndMask, imageFormat);
1289*03ce13f7SAndroid Build Coastguard Worker 		}
1290*03ce13f7SAndroid Build Coastguard Worker 	}
1291*03ce13f7SAndroid Build Coastguard Worker 	else
1292*03ce13f7SAndroid Build Coastguard Worker 	{
1293*03ce13f7SAndroid Build Coastguard Worker 		for(int j = 0; j < SIMD::Width; j++)
1294*03ce13f7SAndroid Build Coastguard Worker 		{
1295*03ce13f7SAndroid Build Coastguard Worker 			SIMD::Int singleLaneMask = 0;
1296*03ce13f7SAndroid Build Coastguard Worker 			singleLaneMask = Insert(singleLaneMask, 0xffffffff, j);
1297*03ce13f7SAndroid Build Coastguard Worker 			texelAndMask[4] = activeStoresAndAtomicsMask() & singleLaneMask;
1298*03ce13f7SAndroid Build Coastguard Worker 			Pointer<Byte> imageDescriptor = ptr.getPointerForLane(j);
1299*03ce13f7SAndroid Build Coastguard Worker 			Pointer<Byte> samplerDescriptor = getSamplerDescriptor(imageDescriptor, instruction, j);
1300*03ce13f7SAndroid Build Coastguard Worker 
1301*03ce13f7SAndroid Build Coastguard Worker 			if(imageFormat == VK_FORMAT_UNDEFINED)  // spv::ImageFormatUnknown
1302*03ce13f7SAndroid Build Coastguard Worker 			{
1303*03ce13f7SAndroid Build Coastguard Worker 				Pointer<Byte> samplerFunction = lookupSamplerFunction(imageDescriptor, samplerDescriptor, instruction);
1304*03ce13f7SAndroid Build Coastguard Worker 
1305*03ce13f7SAndroid Build Coastguard Worker 				Call<ImageSampler>(samplerFunction, imageDescriptor, &coord, &texelAndMask, routine->constants);
1306*03ce13f7SAndroid Build Coastguard Worker 			}
1307*03ce13f7SAndroid Build Coastguard Worker 			else
1308*03ce13f7SAndroid Build Coastguard Worker 			{
1309*03ce13f7SAndroid Build Coastguard Worker 				WriteImage(instruction, imageDescriptor, &coord, &texelAndMask, imageFormat);
1310*03ce13f7SAndroid Build Coastguard Worker 			}
1311*03ce13f7SAndroid Build Coastguard Worker 		}
1312*03ce13f7SAndroid Build Coastguard Worker 	}
1313*03ce13f7SAndroid Build Coastguard Worker }
1314*03ce13f7SAndroid Build Coastguard Worker 
WriteImage(ImageInstructionSignature instruction,Pointer<Byte> descriptor,const Pointer<SIMD::Int> & coord,const Pointer<SIMD::Int> & texelAndMask,vk::Format imageFormat)1315*03ce13f7SAndroid Build Coastguard Worker void SpirvEmitter::WriteImage(ImageInstructionSignature instruction, Pointer<Byte> descriptor, const Pointer<SIMD::Int> &coord, const Pointer<SIMD::Int> &texelAndMask, vk::Format imageFormat)
1316*03ce13f7SAndroid Build Coastguard Worker {
1317*03ce13f7SAndroid Build Coastguard Worker 	SIMD::Int texel[4];
1318*03ce13f7SAndroid Build Coastguard Worker 	texel[0] = texelAndMask[0];
1319*03ce13f7SAndroid Build Coastguard Worker 	texel[1] = texelAndMask[1];
1320*03ce13f7SAndroid Build Coastguard Worker 	texel[2] = texelAndMask[2];
1321*03ce13f7SAndroid Build Coastguard Worker 	texel[3] = texelAndMask[3];
1322*03ce13f7SAndroid Build Coastguard Worker 	SIMD::Int mask = texelAndMask[4];
1323*03ce13f7SAndroid Build Coastguard Worker 
1324*03ce13f7SAndroid Build Coastguard Worker 	SIMD::Int packed[4];
1325*03ce13f7SAndroid Build Coastguard Worker 	switch(imageFormat)
1326*03ce13f7SAndroid Build Coastguard Worker 	{
1327*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R32G32B32A32_SFLOAT:
1328*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R32G32B32A32_SINT:
1329*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R32G32B32A32_UINT:
1330*03ce13f7SAndroid Build Coastguard Worker 		packed[0] = texel[0];
1331*03ce13f7SAndroid Build Coastguard Worker 		packed[1] = texel[1];
1332*03ce13f7SAndroid Build Coastguard Worker 		packed[2] = texel[2];
1333*03ce13f7SAndroid Build Coastguard Worker 		packed[3] = texel[3];
1334*03ce13f7SAndroid Build Coastguard Worker 		break;
1335*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R32_SFLOAT:
1336*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R32_SINT:
1337*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R32_UINT:
1338*03ce13f7SAndroid Build Coastguard Worker 		packed[0] = texel[0];
1339*03ce13f7SAndroid Build Coastguard Worker 		break;
1340*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8G8B8A8_UNORM:
1341*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_A8B8G8R8_UNORM_PACK32:
1342*03ce13f7SAndroid Build Coastguard Worker 		packed[0] = (SIMD::UInt(Round(Min(Max(As<SIMD::Float>(texel[0]), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(255.0f)))) |
1343*03ce13f7SAndroid Build Coastguard Worker 		            ((SIMD::UInt(Round(Min(Max(As<SIMD::Float>(texel[1]), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(255.0f)))) << 8) |
1344*03ce13f7SAndroid Build Coastguard Worker 		            ((SIMD::UInt(Round(Min(Max(As<SIMD::Float>(texel[2]), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(255.0f)))) << 16) |
1345*03ce13f7SAndroid Build Coastguard Worker 		            ((SIMD::UInt(Round(Min(Max(As<SIMD::Float>(texel[3]), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(255.0f)))) << 24);
1346*03ce13f7SAndroid Build Coastguard Worker 		break;
1347*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_B8G8R8A8_UNORM:
1348*03ce13f7SAndroid Build Coastguard Worker 		packed[0] = (SIMD::UInt(Round(Min(Max(As<SIMD::Float>(texel[2]), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(255.0f)))) |
1349*03ce13f7SAndroid Build Coastguard Worker 		            ((SIMD::UInt(Round(Min(Max(As<SIMD::Float>(texel[1]), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(255.0f)))) << 8) |
1350*03ce13f7SAndroid Build Coastguard Worker 		            ((SIMD::UInt(Round(Min(Max(As<SIMD::Float>(texel[0]), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(255.0f)))) << 16) |
1351*03ce13f7SAndroid Build Coastguard Worker 		            ((SIMD::UInt(Round(Min(Max(As<SIMD::Float>(texel[3]), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(255.0f)))) << 24);
1352*03ce13f7SAndroid Build Coastguard Worker 		break;
1353*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_B8G8R8A8_SRGB:
1354*03ce13f7SAndroid Build Coastguard Worker 		packed[0] = (SIMD::UInt(Round(Min(Max(linearToSRGB(As<SIMD::Float>(texel[2])), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(255.0f)))) |
1355*03ce13f7SAndroid Build Coastguard Worker 		            ((SIMD::UInt(Round(Min(Max(linearToSRGB(As<SIMD::Float>(texel[1])), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(255.0f)))) << 8) |
1356*03ce13f7SAndroid Build Coastguard Worker 		            ((SIMD::UInt(Round(Min(Max(linearToSRGB(As<SIMD::Float>(texel[0])), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(255.0f)))) << 16) |
1357*03ce13f7SAndroid Build Coastguard Worker 		            ((SIMD::UInt(Round(Min(Max(As<SIMD::Float>(texel[3]), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(255.0f)))) << 24);
1358*03ce13f7SAndroid Build Coastguard Worker 		break;
1359*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8G8B8A8_SNORM:
1360*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_A8B8G8R8_SNORM_PACK32:
1361*03ce13f7SAndroid Build Coastguard Worker 		packed[0] = (SIMD::Int(Round(Min(Max(As<SIMD::Float>(texel[0]), SIMD::Float(-1.0f)), SIMD::Float(1.0f)) * SIMD::Float(127.0f))) &
1362*03ce13f7SAndroid Build Coastguard Worker 		             SIMD::Int(0xFF)) |
1363*03ce13f7SAndroid Build Coastguard Worker 		            ((SIMD::Int(Round(Min(Max(As<SIMD::Float>(texel[1]), SIMD::Float(-1.0f)), SIMD::Float(1.0f)) * SIMD::Float(127.0f))) &
1364*03ce13f7SAndroid Build Coastguard Worker 		              SIMD::Int(0xFF))
1365*03ce13f7SAndroid Build Coastguard Worker 		             << 8) |
1366*03ce13f7SAndroid Build Coastguard Worker 		            ((SIMD::Int(Round(Min(Max(As<SIMD::Float>(texel[2]), SIMD::Float(-1.0f)), SIMD::Float(1.0f)) * SIMD::Float(127.0f))) &
1367*03ce13f7SAndroid Build Coastguard Worker 		              SIMD::Int(0xFF))
1368*03ce13f7SAndroid Build Coastguard Worker 		             << 16) |
1369*03ce13f7SAndroid Build Coastguard Worker 		            ((SIMD::Int(Round(Min(Max(As<SIMD::Float>(texel[3]), SIMD::Float(-1.0f)), SIMD::Float(1.0f)) * SIMD::Float(127.0f))) &
1370*03ce13f7SAndroid Build Coastguard Worker 		              SIMD::Int(0xFF))
1371*03ce13f7SAndroid Build Coastguard Worker 		             << 24);
1372*03ce13f7SAndroid Build Coastguard Worker 		break;
1373*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8G8B8A8_SINT:
1374*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8G8B8A8_UINT:
1375*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_A8B8G8R8_SINT_PACK32:
1376*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_A8B8G8R8_UINT_PACK32:
1377*03ce13f7SAndroid Build Coastguard Worker 		packed[0] = (SIMD::UInt(As<SIMD::UInt>(texel[0]) & SIMD::UInt(0xff))) |
1378*03ce13f7SAndroid Build Coastguard Worker 		            (SIMD::UInt(As<SIMD::UInt>(texel[1]) & SIMD::UInt(0xff)) << 8) |
1379*03ce13f7SAndroid Build Coastguard Worker 		            (SIMD::UInt(As<SIMD::UInt>(texel[2]) & SIMD::UInt(0xff)) << 16) |
1380*03ce13f7SAndroid Build Coastguard Worker 		            (SIMD::UInt(As<SIMD::UInt>(texel[3]) & SIMD::UInt(0xff)) << 24);
1381*03ce13f7SAndroid Build Coastguard Worker 		break;
1382*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16G16B16A16_SFLOAT:
1383*03ce13f7SAndroid Build Coastguard Worker 		packed[0] = floatToHalfBits(As<SIMD::UInt>(texel[0]), false) | floatToHalfBits(As<SIMD::UInt>(texel[1]), true);
1384*03ce13f7SAndroid Build Coastguard Worker 		packed[1] = floatToHalfBits(As<SIMD::UInt>(texel[2]), false) | floatToHalfBits(As<SIMD::UInt>(texel[3]), true);
1385*03ce13f7SAndroid Build Coastguard Worker 		break;
1386*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16G16B16A16_SINT:
1387*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16G16B16A16_UINT:
1388*03ce13f7SAndroid Build Coastguard Worker 		packed[0] = SIMD::UInt(As<SIMD::UInt>(texel[0]) & SIMD::UInt(0xFFFF)) | (SIMD::UInt(As<SIMD::UInt>(texel[1]) & SIMD::UInt(0xFFFF)) << 16);
1389*03ce13f7SAndroid Build Coastguard Worker 		packed[1] = SIMD::UInt(As<SIMD::UInt>(texel[2]) & SIMD::UInt(0xFFFF)) | (SIMD::UInt(As<SIMD::UInt>(texel[3]) & SIMD::UInt(0xFFFF)) << 16);
1390*03ce13f7SAndroid Build Coastguard Worker 		break;
1391*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R32G32_SFLOAT:
1392*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R32G32_SINT:
1393*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R32G32_UINT:
1394*03ce13f7SAndroid Build Coastguard Worker 		packed[0] = texel[0];
1395*03ce13f7SAndroid Build Coastguard Worker 		packed[1] = texel[1];
1396*03ce13f7SAndroid Build Coastguard Worker 		break;
1397*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16G16_SFLOAT:
1398*03ce13f7SAndroid Build Coastguard Worker 		packed[0] = floatToHalfBits(As<SIMD::UInt>(texel[0]), false) | floatToHalfBits(As<SIMD::UInt>(texel[1]), true);
1399*03ce13f7SAndroid Build Coastguard Worker 		break;
1400*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16G16_SINT:
1401*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16G16_UINT:
1402*03ce13f7SAndroid Build Coastguard Worker 		packed[0] = SIMD::UInt(As<SIMD::UInt>(texel[0]) & SIMD::UInt(0xFFFF)) | (SIMD::UInt(As<SIMD::UInt>(texel[1]) & SIMD::UInt(0xFFFF)) << 16);
1403*03ce13f7SAndroid Build Coastguard Worker 		break;
1404*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_B10G11R11_UFLOAT_PACK32:
1405*03ce13f7SAndroid Build Coastguard Worker 		// Truncates instead of rounding. See b/147900455
1406*03ce13f7SAndroid Build Coastguard Worker 		packed[0] = ((floatToHalfBits(As<SIMD::UInt>(Max(As<SIMD::Float>(texel[0]), SIMD::Float(0.0f))), false) & SIMD::UInt(0x7FF0)) >> 4) |
1407*03ce13f7SAndroid Build Coastguard Worker 		            ((floatToHalfBits(As<SIMD::UInt>(Max(As<SIMD::Float>(texel[1]), SIMD::Float(0.0f))), false) & SIMD::UInt(0x7FF0)) << 7) |
1408*03ce13f7SAndroid Build Coastguard Worker 		            ((floatToHalfBits(As<SIMD::UInt>(Max(As<SIMD::Float>(texel[2]), SIMD::Float(0.0f))), false) & SIMD::UInt(0x7FE0)) << 17);
1409*03ce13f7SAndroid Build Coastguard Worker 		break;
1410*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16_SFLOAT:
1411*03ce13f7SAndroid Build Coastguard Worker 		packed[0] = floatToHalfBits(As<SIMD::UInt>(texel[0]), false);
1412*03ce13f7SAndroid Build Coastguard Worker 		break;
1413*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16G16B16A16_UNORM:
1414*03ce13f7SAndroid Build Coastguard Worker 		packed[0] = SIMD::UInt(Round(Min(Max(As<SIMD::Float>(texel[0]), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(0xFFFF))) |
1415*03ce13f7SAndroid Build Coastguard Worker 		            (SIMD::UInt(Round(Min(Max(As<SIMD::Float>(texel[1]), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(0xFFFF))) << 16);
1416*03ce13f7SAndroid Build Coastguard Worker 		packed[1] = SIMD::UInt(Round(Min(Max(As<SIMD::Float>(texel[2]), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(0xFFFF))) |
1417*03ce13f7SAndroid Build Coastguard Worker 		            (SIMD::UInt(Round(Min(Max(As<SIMD::Float>(texel[3]), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(0xFFFF))) << 16);
1418*03ce13f7SAndroid Build Coastguard Worker 		break;
1419*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_A2B10G10R10_UNORM_PACK32:
1420*03ce13f7SAndroid Build Coastguard Worker 		packed[0] = (SIMD::UInt(Round(Min(Max(As<SIMD::Float>(texel[0]), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(0x3FF)))) |
1421*03ce13f7SAndroid Build Coastguard Worker 		            ((SIMD::UInt(Round(Min(Max(As<SIMD::Float>(texel[1]), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(0x3FF)))) << 10) |
1422*03ce13f7SAndroid Build Coastguard Worker 		            ((SIMD::UInt(Round(Min(Max(As<SIMD::Float>(texel[2]), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(0x3FF)))) << 20) |
1423*03ce13f7SAndroid Build Coastguard Worker 		            ((SIMD::UInt(Round(Min(Max(As<SIMD::Float>(texel[3]), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(0x3)))) << 30);
1424*03ce13f7SAndroid Build Coastguard Worker 		break;
1425*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16G16_UNORM:
1426*03ce13f7SAndroid Build Coastguard Worker 		packed[0] = SIMD::UInt(Round(Min(Max(As<SIMD::Float>(texel[0]), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(0xFFFF))) |
1427*03ce13f7SAndroid Build Coastguard Worker 		            (SIMD::UInt(Round(Min(Max(As<SIMD::Float>(texel[1]), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(0xFFFF))) << 16);
1428*03ce13f7SAndroid Build Coastguard Worker 		break;
1429*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8G8_UNORM:
1430*03ce13f7SAndroid Build Coastguard Worker 		packed[0] = SIMD::UInt(Round(Min(Max(As<SIMD::Float>(texel[0]), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(0xFF))) |
1431*03ce13f7SAndroid Build Coastguard Worker 		            (SIMD::UInt(Round(Min(Max(As<SIMD::Float>(texel[1]), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(0xFF))) << 8);
1432*03ce13f7SAndroid Build Coastguard Worker 		break;
1433*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16_UNORM:
1434*03ce13f7SAndroid Build Coastguard Worker 		packed[0] = SIMD::UInt(Round(Min(Max(As<SIMD::Float>(texel[0]), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(0xFFFF)));
1435*03ce13f7SAndroid Build Coastguard Worker 		break;
1436*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8_UNORM:
1437*03ce13f7SAndroid Build Coastguard Worker 		packed[0] = SIMD::UInt(Round(Min(Max(As<SIMD::Float>(texel[0]), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(0xFF)));
1438*03ce13f7SAndroid Build Coastguard Worker 		break;
1439*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16G16B16A16_SNORM:
1440*03ce13f7SAndroid Build Coastguard Worker 		packed[0] = (SIMD::Int(Round(Min(Max(As<SIMD::Float>(texel[0]), SIMD::Float(-1.0f)), SIMD::Float(1.0f)) * SIMD::Float(0x7FFF))) & SIMD::Int(0xFFFF)) |
1441*03ce13f7SAndroid Build Coastguard Worker 		            (SIMD::Int(Round(Min(Max(As<SIMD::Float>(texel[1]), SIMD::Float(-1.0f)), SIMD::Float(1.0f)) * SIMD::Float(0x7FFF))) << 16);
1442*03ce13f7SAndroid Build Coastguard Worker 		packed[1] = (SIMD::Int(Round(Min(Max(As<SIMD::Float>(texel[2]), SIMD::Float(-1.0f)), SIMD::Float(1.0f)) * SIMD::Float(0x7FFF))) & SIMD::Int(0xFFFF)) |
1443*03ce13f7SAndroid Build Coastguard Worker 		            (SIMD::Int(Round(Min(Max(As<SIMD::Float>(texel[3]), SIMD::Float(-1.0f)), SIMD::Float(1.0f)) * SIMD::Float(0x7FFF))) << 16);
1444*03ce13f7SAndroid Build Coastguard Worker 		break;
1445*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16G16_SNORM:
1446*03ce13f7SAndroid Build Coastguard Worker 		packed[0] = (SIMD::Int(Round(Min(Max(As<SIMD::Float>(texel[0]), SIMD::Float(-1.0f)), SIMD::Float(1.0f)) * SIMD::Float(0x7FFF))) & SIMD::Int(0xFFFF)) |
1447*03ce13f7SAndroid Build Coastguard Worker 		            (SIMD::Int(Round(Min(Max(As<SIMD::Float>(texel[1]), SIMD::Float(-1.0f)), SIMD::Float(1.0f)) * SIMD::Float(0x7FFF))) << 16);
1448*03ce13f7SAndroid Build Coastguard Worker 		break;
1449*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8G8_SNORM:
1450*03ce13f7SAndroid Build Coastguard Worker 		packed[0] = (SIMD::Int(Round(Min(Max(As<SIMD::Float>(texel[0]), SIMD::Float(-1.0f)), SIMD::Float(1.0f)) * SIMD::Float(0x7F))) & SIMD::Int(0xFF)) |
1451*03ce13f7SAndroid Build Coastguard Worker 		            (SIMD::Int(Round(Min(Max(As<SIMD::Float>(texel[1]), SIMD::Float(-1.0f)), SIMD::Float(1.0f)) * SIMD::Float(0x7F))) << 8);
1452*03ce13f7SAndroid Build Coastguard Worker 		break;
1453*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16_SNORM:
1454*03ce13f7SAndroid Build Coastguard Worker 		packed[0] = SIMD::Int(Round(Min(Max(As<SIMD::Float>(texel[0]), SIMD::Float(-1.0f)), SIMD::Float(1.0f)) * SIMD::Float(0x7FFF)));
1455*03ce13f7SAndroid Build Coastguard Worker 		break;
1456*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8_SNORM:
1457*03ce13f7SAndroid Build Coastguard Worker 		packed[0] = SIMD::Int(Round(Min(Max(As<SIMD::Float>(texel[0]), SIMD::Float(-1.0f)), SIMD::Float(1.0f)) * SIMD::Float(0x7F)));
1458*03ce13f7SAndroid Build Coastguard Worker 		break;
1459*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8G8_SINT:
1460*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8G8_UINT:
1461*03ce13f7SAndroid Build Coastguard Worker 		packed[0] = SIMD::UInt(As<SIMD::UInt>(texel[0]) & SIMD::UInt(0xFF)) | (SIMD::UInt(As<SIMD::UInt>(texel[1]) & SIMD::UInt(0xFF)) << 8);
1462*03ce13f7SAndroid Build Coastguard Worker 		break;
1463*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16_SINT:
1464*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R16_UINT:
1465*03ce13f7SAndroid Build Coastguard Worker 		packed[0] = SIMD::UInt(As<SIMD::UInt>(texel[0]) & SIMD::UInt(0xFFFF));
1466*03ce13f7SAndroid Build Coastguard Worker 		break;
1467*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8_SINT:
1468*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_R8_UINT:
1469*03ce13f7SAndroid Build Coastguard Worker 		packed[0] = SIMD::UInt(As<SIMD::UInt>(texel[0]) & SIMD::UInt(0xFF));
1470*03ce13f7SAndroid Build Coastguard Worker 		break;
1471*03ce13f7SAndroid Build Coastguard Worker 	case VK_FORMAT_A2B10G10R10_UINT_PACK32:
1472*03ce13f7SAndroid Build Coastguard Worker 		packed[0] = (SIMD::UInt(As<SIMD::UInt>(texel[0]) & SIMD::UInt(0x3FF))) |
1473*03ce13f7SAndroid Build Coastguard Worker 		            (SIMD::UInt(As<SIMD::UInt>(texel[1]) & SIMD::UInt(0x3FF)) << 10) |
1474*03ce13f7SAndroid Build Coastguard Worker 		            (SIMD::UInt(As<SIMD::UInt>(texel[2]) & SIMD::UInt(0x3FF)) << 20) |
1475*03ce13f7SAndroid Build Coastguard Worker 		            (SIMD::UInt(As<SIMD::UInt>(texel[3]) & SIMD::UInt(0x3)) << 30);
1476*03ce13f7SAndroid Build Coastguard Worker 		break;
1477*03ce13f7SAndroid Build Coastguard Worker 	default:
1478*03ce13f7SAndroid Build Coastguard Worker 		UNSUPPORTED("VkFormat %d", int(imageFormat));
1479*03ce13f7SAndroid Build Coastguard Worker 		break;
1480*03ce13f7SAndroid Build Coastguard Worker 	}
1481*03ce13f7SAndroid Build Coastguard Worker 
1482*03ce13f7SAndroid Build Coastguard Worker 	// "The integer texel coordinates are validated according to the same rules as for texel input coordinate
1483*03ce13f7SAndroid Build Coastguard Worker 	//  validation. If the texel fails integer texel coordinate validation, then the write has no effect."
1484*03ce13f7SAndroid Build Coastguard Worker 	// - https://www.khronos.org/registry/vulkan/specs/1.2/html/chap16.html#textures-output-coordinate-validation
1485*03ce13f7SAndroid Build Coastguard Worker 	auto robustness = OutOfBoundsBehavior::Nullify;
1486*03ce13f7SAndroid Build Coastguard Worker 	// GetTexelAddress() only needs the SpirvRoutine* for SubpassData accesses (i.e. input attachments).
1487*03ce13f7SAndroid Build Coastguard Worker 	const SpirvRoutine *routine = nullptr;
1488*03ce13f7SAndroid Build Coastguard Worker 
1489*03ce13f7SAndroid Build Coastguard Worker 	SIMD::Int uvwa[4];
1490*03ce13f7SAndroid Build Coastguard Worker 	SIMD::Int sample;
1491*03ce13f7SAndroid Build Coastguard Worker 
1492*03ce13f7SAndroid Build Coastguard Worker 	uint32_t i = 0;
1493*03ce13f7SAndroid Build Coastguard Worker 	for(; i < instruction.coordinates; i++)
1494*03ce13f7SAndroid Build Coastguard Worker 	{
1495*03ce13f7SAndroid Build Coastguard Worker 		uvwa[i] = As<SIMD::Int>(coord[i]);
1496*03ce13f7SAndroid Build Coastguard Worker 	}
1497*03ce13f7SAndroid Build Coastguard Worker 
1498*03ce13f7SAndroid Build Coastguard Worker 	if(instruction.sample)
1499*03ce13f7SAndroid Build Coastguard Worker 	{
1500*03ce13f7SAndroid Build Coastguard Worker 		sample = As<SIMD::Int>(coord[i]);
1501*03ce13f7SAndroid Build Coastguard Worker 	}
1502*03ce13f7SAndroid Build Coastguard Worker 
1503*03ce13f7SAndroid Build Coastguard Worker 	auto texelPtr = GetTexelAddress(instruction, descriptor, uvwa, sample, imageFormat, robustness, routine);
1504*03ce13f7SAndroid Build Coastguard Worker 
1505*03ce13f7SAndroid Build Coastguard Worker 	const int texelSize = imageFormat.bytes();
1506*03ce13f7SAndroid Build Coastguard Worker 
1507*03ce13f7SAndroid Build Coastguard Worker 	// Scatter packed texel data.
1508*03ce13f7SAndroid Build Coastguard Worker 	// TODO(b/160531165): Provide scatter abstractions for various element sizes.
1509*03ce13f7SAndroid Build Coastguard Worker 	if(texelSize == 4 || texelSize == 8 || texelSize == 16)
1510*03ce13f7SAndroid Build Coastguard Worker 	{
1511*03ce13f7SAndroid Build Coastguard Worker 		for(auto i = 0; i < texelSize / 4; i++)
1512*03ce13f7SAndroid Build Coastguard Worker 		{
1513*03ce13f7SAndroid Build Coastguard Worker 			texelPtr.Store(packed[i], robustness, mask);
1514*03ce13f7SAndroid Build Coastguard Worker 			texelPtr += sizeof(float);
1515*03ce13f7SAndroid Build Coastguard Worker 		}
1516*03ce13f7SAndroid Build Coastguard Worker 	}
1517*03ce13f7SAndroid Build Coastguard Worker 	else if(texelSize == 2)
1518*03ce13f7SAndroid Build Coastguard Worker 	{
1519*03ce13f7SAndroid Build Coastguard Worker 		mask = mask & texelPtr.isInBounds(2, robustness);
1520*03ce13f7SAndroid Build Coastguard Worker 
1521*03ce13f7SAndroid Build Coastguard Worker 		for(int i = 0; i < SIMD::Width; i++)
1522*03ce13f7SAndroid Build Coastguard Worker 		{
1523*03ce13f7SAndroid Build Coastguard Worker 			If(Extract(mask, i) != 0)
1524*03ce13f7SAndroid Build Coastguard Worker 			{
1525*03ce13f7SAndroid Build Coastguard Worker 				*Pointer<Short>(texelPtr.getPointerForLane(i)) = Short(Extract(packed[0], i));
1526*03ce13f7SAndroid Build Coastguard Worker 			}
1527*03ce13f7SAndroid Build Coastguard Worker 		}
1528*03ce13f7SAndroid Build Coastguard Worker 	}
1529*03ce13f7SAndroid Build Coastguard Worker 	else if(texelSize == 1)
1530*03ce13f7SAndroid Build Coastguard Worker 	{
1531*03ce13f7SAndroid Build Coastguard Worker 		mask = mask & texelPtr.isInBounds(1, robustness);
1532*03ce13f7SAndroid Build Coastguard Worker 
1533*03ce13f7SAndroid Build Coastguard Worker 		for(int i = 0; i < SIMD::Width; i++)
1534*03ce13f7SAndroid Build Coastguard Worker 		{
1535*03ce13f7SAndroid Build Coastguard Worker 			If(Extract(mask, i) != 0)
1536*03ce13f7SAndroid Build Coastguard Worker 			{
1537*03ce13f7SAndroid Build Coastguard Worker 				*Pointer<Byte>(texelPtr.getPointerForLane(i)) = Byte(Extract(packed[0], i));
1538*03ce13f7SAndroid Build Coastguard Worker 			}
1539*03ce13f7SAndroid Build Coastguard Worker 		}
1540*03ce13f7SAndroid Build Coastguard Worker 	}
1541*03ce13f7SAndroid Build Coastguard Worker 	else
1542*03ce13f7SAndroid Build Coastguard Worker 		UNREACHABLE("texelSize: %d", int(texelSize));
1543*03ce13f7SAndroid Build Coastguard Worker }
1544*03ce13f7SAndroid Build Coastguard Worker 
EmitImageTexelPointer(const ImageInstruction & instruction)1545*03ce13f7SAndroid Build Coastguard Worker void SpirvEmitter::EmitImageTexelPointer(const ImageInstruction &instruction)
1546*03ce13f7SAndroid Build Coastguard Worker {
1547*03ce13f7SAndroid Build Coastguard Worker 	auto coordinate = Operand(shader, *this, instruction.coordinateId);
1548*03ce13f7SAndroid Build Coastguard Worker 
1549*03ce13f7SAndroid Build Coastguard Worker 	SIMD::Pointer ptr = getPointer(instruction.imageId);
1550*03ce13f7SAndroid Build Coastguard Worker 
1551*03ce13f7SAndroid Build Coastguard Worker 	// VK_EXT_image_robustness requires checking for out-of-bounds accesses.
1552*03ce13f7SAndroid Build Coastguard Worker 	// TODO(b/162327166): Only perform bounds checks when VK_EXT_image_robustness is enabled.
1553*03ce13f7SAndroid Build Coastguard Worker 	auto robustness = OutOfBoundsBehavior::Nullify;
1554*03ce13f7SAndroid Build Coastguard Worker 	vk::Format imageFormat = SpirvFormatToVulkanFormat(static_cast<spv::ImageFormat>(instruction.imageFormat));
1555*03ce13f7SAndroid Build Coastguard Worker 
1556*03ce13f7SAndroid Build Coastguard Worker 	SIMD::Int uvwa[4];
1557*03ce13f7SAndroid Build Coastguard Worker 
1558*03ce13f7SAndroid Build Coastguard Worker 	for(uint32_t i = 0; i < instruction.coordinates; i++)
1559*03ce13f7SAndroid Build Coastguard Worker 	{
1560*03ce13f7SAndroid Build Coastguard Worker 		uvwa[i] = coordinate.Int(i);
1561*03ce13f7SAndroid Build Coastguard Worker 	}
1562*03ce13f7SAndroid Build Coastguard Worker 
1563*03ce13f7SAndroid Build Coastguard Worker 	SIMD::Int sample = Operand(shader, *this, instruction.sampleId).Int(0);
1564*03ce13f7SAndroid Build Coastguard Worker 
1565*03ce13f7SAndroid Build Coastguard Worker 	auto texelPtr = ptr.isBasePlusOffset
1566*03ce13f7SAndroid Build Coastguard Worker 	                    ? GetTexelAddress(instruction, ptr.getUniformPointer(), uvwa, sample, imageFormat, robustness, routine)
1567*03ce13f7SAndroid Build Coastguard Worker 	                    : GetNonUniformTexelAddress(instruction, ptr, uvwa, sample, imageFormat, robustness, activeLaneMask(), routine);
1568*03ce13f7SAndroid Build Coastguard Worker 
1569*03ce13f7SAndroid Build Coastguard Worker 	createPointer(instruction.resultId, texelPtr);
1570*03ce13f7SAndroid Build Coastguard Worker }
1571*03ce13f7SAndroid Build Coastguard Worker 
EmitSampledImage(InsnIterator insn)1572*03ce13f7SAndroid Build Coastguard Worker void SpirvEmitter::EmitSampledImage(InsnIterator insn)
1573*03ce13f7SAndroid Build Coastguard Worker {
1574*03ce13f7SAndroid Build Coastguard Worker 	Object::ID resultId = insn.word(2);
1575*03ce13f7SAndroid Build Coastguard Worker 	Object::ID imageId = insn.word(3);
1576*03ce13f7SAndroid Build Coastguard Worker 	Object::ID samplerId = insn.word(4);
1577*03ce13f7SAndroid Build Coastguard Worker 
1578*03ce13f7SAndroid Build Coastguard Worker 	// Create a sampled image, containing both a sampler and an image
1579*03ce13f7SAndroid Build Coastguard Worker 	createSampledImage(resultId, { getPointer(imageId), samplerId });
1580*03ce13f7SAndroid Build Coastguard Worker }
1581*03ce13f7SAndroid Build Coastguard Worker 
EmitImage(InsnIterator insn)1582*03ce13f7SAndroid Build Coastguard Worker void SpirvEmitter::EmitImage(InsnIterator insn)
1583*03ce13f7SAndroid Build Coastguard Worker {
1584*03ce13f7SAndroid Build Coastguard Worker 	Object::ID resultId = insn.word(2);
1585*03ce13f7SAndroid Build Coastguard Worker 	Object::ID imageId = insn.word(3);
1586*03ce13f7SAndroid Build Coastguard Worker 
1587*03ce13f7SAndroid Build Coastguard Worker 	// Extract the image from a sampled image.
1588*03ce13f7SAndroid Build Coastguard Worker 	createPointer(resultId, getImage(imageId));
1589*03ce13f7SAndroid Build Coastguard Worker }
1590*03ce13f7SAndroid Build Coastguard Worker 
1591*03ce13f7SAndroid Build Coastguard Worker }  // namespace sw
1592