• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2019 The SwiftShader Authors. All Rights Reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //    http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "SpirvShader.hpp"
16 
17 #include "System/Types.hpp"
18 
19 #include "Vulkan/VkDescriptorSetLayout.hpp"
20 #include "Vulkan/VkPipelineLayout.hpp"
21 
22 #include <spirv/unified1/spirv.hpp>
23 
24 namespace {
25 
SpirvFormatToVulkanFormat(spv::ImageFormat format)26 VkFormat SpirvFormatToVulkanFormat(spv::ImageFormat format)
27 {
28 	switch(format)
29 	{
30 		case spv::ImageFormatRgba32f: return VK_FORMAT_R32G32B32A32_SFLOAT;
31 		case spv::ImageFormatRgba16f: return VK_FORMAT_R16G16B16A16_SFLOAT;
32 		case spv::ImageFormatR32f: return VK_FORMAT_R32_SFLOAT;
33 		case spv::ImageFormatRgba8: return VK_FORMAT_R8G8B8A8_UNORM;
34 		case spv::ImageFormatRgba8Snorm: return VK_FORMAT_R8G8B8A8_SNORM;
35 		case spv::ImageFormatRg32f: return VK_FORMAT_R32G32_SFLOAT;
36 		case spv::ImageFormatRg16f: return VK_FORMAT_R16G16_SFLOAT;
37 		case spv::ImageFormatR11fG11fB10f: return VK_FORMAT_B10G11R11_UFLOAT_PACK32;
38 		case spv::ImageFormatR16f: return VK_FORMAT_R16_SFLOAT;
39 		case spv::ImageFormatRgba16: return VK_FORMAT_R16G16B16A16_UNORM;
40 		case spv::ImageFormatRgb10A2: return VK_FORMAT_A2B10G10R10_UNORM_PACK32;
41 		case spv::ImageFormatRg16: return VK_FORMAT_R16G16_UNORM;
42 		case spv::ImageFormatRg8: return VK_FORMAT_R8G8_UNORM;
43 		case spv::ImageFormatR16: return VK_FORMAT_R16_UNORM;
44 		case spv::ImageFormatR8: return VK_FORMAT_R8_UNORM;
45 		case spv::ImageFormatRgba16Snorm: return VK_FORMAT_R16G16B16A16_SNORM;
46 		case spv::ImageFormatRg16Snorm: return VK_FORMAT_R16G16_SNORM;
47 		case spv::ImageFormatRg8Snorm: return VK_FORMAT_R8G8_SNORM;
48 		case spv::ImageFormatR16Snorm: return VK_FORMAT_R16_SNORM;
49 		case spv::ImageFormatR8Snorm: return VK_FORMAT_R8_SNORM;
50 		case spv::ImageFormatRgba32i: return VK_FORMAT_R32G32B32A32_SINT;
51 		case spv::ImageFormatRgba16i: return VK_FORMAT_R16G16B16A16_SINT;
52 		case spv::ImageFormatRgba8i: return VK_FORMAT_R8G8B8A8_SINT;
53 		case spv::ImageFormatR32i: return VK_FORMAT_R32_SINT;
54 		case spv::ImageFormatRg32i: return VK_FORMAT_R32G32_SINT;
55 		case spv::ImageFormatRg16i: return VK_FORMAT_R16G16_SINT;
56 		case spv::ImageFormatRg8i: return VK_FORMAT_R8G8_SINT;
57 		case spv::ImageFormatR16i: return VK_FORMAT_R16_SINT;
58 		case spv::ImageFormatR8i: return VK_FORMAT_R8_SINT;
59 		case spv::ImageFormatRgba32ui: return VK_FORMAT_R32G32B32A32_UINT;
60 		case spv::ImageFormatRgba16ui: return VK_FORMAT_R16G16B16A16_UINT;
61 		case spv::ImageFormatRgba8ui: return VK_FORMAT_R8G8B8A8_UINT;
62 		case spv::ImageFormatR32ui: return VK_FORMAT_R32_UINT;
63 		case spv::ImageFormatRgb10a2ui: return VK_FORMAT_A2B10G10R10_UINT_PACK32;
64 		case spv::ImageFormatRg32ui: return VK_FORMAT_R32G32_UINT;
65 		case spv::ImageFormatRg16ui: return VK_FORMAT_R16G16_UINT;
66 		case spv::ImageFormatRg8ui: return VK_FORMAT_R8G8_UINT;
67 		case spv::ImageFormatR16ui: return VK_FORMAT_R16_UINT;
68 		case spv::ImageFormatR8ui: return VK_FORMAT_R8_UINT;
69 
70 		default:
71 			UNSUPPORTED("SPIR-V ImageFormat %u", format);
72 			return VK_FORMAT_UNDEFINED;
73 	}
74 }
75 
sRGBtoLinear(sw::SIMD::Float c)76 sw::SIMD::Float sRGBtoLinear(sw::SIMD::Float c)
77 {
78 	sw::SIMD::Float lc = c * sw::SIMD::Float(1.0f / 12.92f);
79 	sw::SIMD::Float ec = sw::power((c + sw::SIMD::Float(0.055f)) * sw::SIMD::Float(1.0f / 1.055f), sw::SIMD::Float(2.4f));
80 
81 	sw::SIMD::Int linear = CmpLT(c, sw::SIMD::Float(0.04045f));
82 
83 	return rr::As<sw::SIMD::Float>((linear & rr::As<sw::SIMD::Int>(lc)) | (~linear & rr::As<sw::SIMD::Int>(ec)));  // TODO: IfThenElse()
84 }
85 
86 }  // anonymous namespace
87 
88 namespace sw {
89 
EmitImageSampleImplicitLod(Variant variant,InsnIterator insn,EmitState * state) const90 SpirvShader::EmitResult SpirvShader::EmitImageSampleImplicitLod(Variant variant, InsnIterator insn, EmitState *state) const
91 {
92 	return EmitImageSample({ variant, Implicit }, insn, state);
93 }
94 
EmitImageGather(Variant variant,InsnIterator insn,EmitState * state) const95 SpirvShader::EmitResult SpirvShader::EmitImageGather(Variant variant, InsnIterator insn, EmitState *state) const
96 {
97 	ImageInstruction instruction = { variant, Gather };
98 	instruction.gatherComponent = !instruction.isDref() ? getObject(insn.word(5)).constantValue[0] : 0;
99 
100 	return EmitImageSample(instruction, insn, state);
101 }
102 
EmitImageSampleExplicitLod(Variant variant,InsnIterator insn,EmitState * state) const103 SpirvShader::EmitResult SpirvShader::EmitImageSampleExplicitLod(Variant variant, InsnIterator insn, EmitState *state) const
104 {
105 	auto isDref = (variant == Dref) || (variant == ProjDref);
106 	uint32_t imageOperands = static_cast<spv::ImageOperandsMask>(insn.word(isDref ? 6 : 5));
107 	imageOperands &= ~spv::ImageOperandsConstOffsetMask;  // Dealt with later.
108 
109 	if((imageOperands & spv::ImageOperandsLodMask) == imageOperands)
110 	{
111 		return EmitImageSample({ variant, Lod }, insn, state);
112 	}
113 	else if((imageOperands & spv::ImageOperandsGradMask) == imageOperands)
114 	{
115 		return EmitImageSample({ variant, Grad }, insn, state);
116 	}
117 	else
118 		UNSUPPORTED("Image operands 0x%08X", imageOperands);
119 
120 	return EmitResult::Continue;
121 }
122 
EmitImageFetch(InsnIterator insn,EmitState * state) const123 SpirvShader::EmitResult SpirvShader::EmitImageFetch(InsnIterator insn, EmitState *state) const
124 {
125 	return EmitImageSample({ None, Fetch }, insn, state);
126 }
127 
EmitImageSample(ImageInstruction instruction,InsnIterator insn,EmitState * state) const128 SpirvShader::EmitResult SpirvShader::EmitImageSample(ImageInstruction instruction, InsnIterator insn, EmitState *state) const
129 {
130 	auto &resultType = getType(insn.resultTypeId());
131 	auto &result = state->createIntermediate(insn.resultId(), resultType.componentCount);
132 	Array<SIMD::Float> out(4);
133 
134 	// TODO(b/153380916): When we're in a code path that is always executed,
135 	// i.e. post-dominators of the entry block, we don't have to dynamically
136 	// check whether any lanes are active, and can elide the jump.
137 	If(AnyTrue(state->activeLaneMask()))
138 	{
139 		EmitImageSampleUnconditional(out, instruction, insn, state);
140 	}
141 
142 	for(auto i = 0u; i < resultType.componentCount; i++) { result.move(i, out[i]); }
143 
144 	return EmitResult::Continue;
145 }
146 
EmitImageSampleUnconditional(Array<SIMD::Float> & out,ImageInstruction instruction,InsnIterator insn,EmitState * state) const147 void SpirvShader::EmitImageSampleUnconditional(Array<SIMD::Float> &out, ImageInstruction instruction, InsnIterator insn, EmitState *state) const
148 {
149 	Object::ID sampledImageId = insn.word(3);  // For OpImageFetch this is just an Image, not a SampledImage.
150 	Object::ID coordinateId = insn.word(4);
151 
152 	auto imageDescriptor = state->getPointer(sampledImageId).base;  // vk::SampledImageDescriptor*
153 
154 	// If using a separate sampler, look through the OpSampledImage instruction to find the sampler descriptor
155 	auto &sampledImage = getObject(sampledImageId);
156 	auto samplerDescriptor = (sampledImage.opcode() == spv::OpSampledImage) ? state->getPointer(sampledImage.definition.word(4)).base : imageDescriptor;
157 
158 	auto coordinate = Operand(this, state, coordinateId);
159 
160 	Pointer<Byte> sampler = samplerDescriptor + OFFSET(vk::SampledImageDescriptor, sampler);  // vk::Sampler*
161 	Pointer<Byte> texture = imageDescriptor + OFFSET(vk::SampledImageDescriptor, texture);    // sw::Texture*
162 
163 	// Above we assumed that if the SampledImage operand is not the result of an OpSampledImage,
164 	// it must be a combined image sampler loaded straight from the descriptor set. For OpImageFetch
165 	// it's just an Image operand, so there's no sampler descriptor data.
166 	if(getType(sampledImage).opcode() != spv::OpTypeSampledImage)
167 	{
168 		sampler = Pointer<Byte>(nullptr);
169 	}
170 
171 	uint32_t imageOperands = spv::ImageOperandsMaskNone;
172 	bool lodOrBias = false;
173 	Object::ID lodOrBiasId = 0;
174 	bool grad = false;
175 	Object::ID gradDxId = 0;
176 	Object::ID gradDyId = 0;
177 	bool constOffset = false;
178 	Object::ID offsetId = 0;
179 	bool sample = false;
180 	Object::ID sampleId = 0;
181 
182 	uint32_t operand = (instruction.isDref() || instruction.samplerMethod == Gather) ? 6 : 5;
183 
184 	if(insn.wordCount() > operand)
185 	{
186 		imageOperands = static_cast<spv::ImageOperandsMask>(insn.word(operand++));
187 
188 		if(imageOperands & spv::ImageOperandsBiasMask)
189 		{
190 			lodOrBias = true;
191 			lodOrBiasId = insn.word(operand);
192 			operand++;
193 			imageOperands &= ~spv::ImageOperandsBiasMask;
194 
195 			ASSERT(instruction.samplerMethod == Implicit);
196 			instruction.samplerMethod = Bias;
197 		}
198 
199 		if(imageOperands & spv::ImageOperandsLodMask)
200 		{
201 			lodOrBias = true;
202 			lodOrBiasId = insn.word(operand);
203 			operand++;
204 			imageOperands &= ~spv::ImageOperandsLodMask;
205 		}
206 
207 		if(imageOperands & spv::ImageOperandsGradMask)
208 		{
209 			ASSERT(!lodOrBias);  // SPIR-V 1.3: "It is invalid to set both the Lod and Grad bits." Bias is for ImplicitLod, Grad for ExplicitLod.
210 			grad = true;
211 			gradDxId = insn.word(operand + 0);
212 			gradDyId = insn.word(operand + 1);
213 			operand += 2;
214 			imageOperands &= ~spv::ImageOperandsGradMask;
215 		}
216 
217 		if(imageOperands & spv::ImageOperandsConstOffsetMask)
218 		{
219 			constOffset = true;
220 			offsetId = insn.word(operand);
221 			operand++;
222 			imageOperands &= ~spv::ImageOperandsConstOffsetMask;
223 		}
224 
225 		if(imageOperands & spv::ImageOperandsSampleMask)
226 		{
227 			sample = true;
228 			sampleId = insn.word(operand);
229 			imageOperands &= ~spv::ImageOperandsSampleMask;
230 
231 			ASSERT(instruction.samplerMethod == Fetch);
232 			instruction.sample = true;
233 		}
234 
235 		if(imageOperands != 0)
236 		{
237 			UNSUPPORTED("Image operands 0x%08X", imageOperands);
238 		}
239 	}
240 
241 	Array<SIMD::Float> in(16);  // Maximum 16 input parameter components.
242 
243 	uint32_t coordinates = coordinate.componentCount - instruction.isProj();
244 	instruction.coordinates = coordinates;
245 
246 	uint32_t i = 0;
247 	for(; i < coordinates; i++)
248 	{
249 		if(instruction.isProj())
250 		{
251 			in[i] = coordinate.Float(i) / coordinate.Float(coordinates);  // TODO(b/129523279): Optimize using reciprocal.
252 		}
253 		else
254 		{
255 			in[i] = coordinate.Float(i);
256 		}
257 	}
258 
259 	if(instruction.isDref())
260 	{
261 		auto drefValue = Operand(this, state, insn.word(5));
262 
263 		if(instruction.isProj())
264 		{
265 			in[i] = drefValue.Float(0) / coordinate.Float(coordinates);  // TODO(b/129523279): Optimize using reciprocal.
266 		}
267 		else
268 		{
269 			in[i] = drefValue.Float(0);
270 		}
271 
272 		i++;
273 	}
274 
275 	if(lodOrBias)
276 	{
277 		auto lodValue = Operand(this, state, lodOrBiasId);
278 		in[i] = lodValue.Float(0);
279 		i++;
280 	}
281 	else if(grad)
282 	{
283 		auto dxValue = Operand(this, state, gradDxId);
284 		auto dyValue = Operand(this, state, gradDyId);
285 		ASSERT(dxValue.componentCount == dxValue.componentCount);
286 
287 		instruction.grad = dxValue.componentCount;
288 
289 		for(uint32_t j = 0; j < dxValue.componentCount; j++, i++)
290 		{
291 			in[i] = dxValue.Float(j);
292 		}
293 
294 		for(uint32_t j = 0; j < dxValue.componentCount; j++, i++)
295 		{
296 			in[i] = dyValue.Float(j);
297 		}
298 	}
299 	else if(instruction.samplerMethod == Fetch)
300 	{
301 		// The instruction didn't provide a lod operand, but the sampler's Fetch
302 		// function requires one to be present. If no lod is supplied, the default
303 		// is zero.
304 		in[i] = As<SIMD::Float>(SIMD::Int(0));
305 		i++;
306 	}
307 
308 	if(constOffset)
309 	{
310 		auto offsetValue = Operand(this, state, offsetId);
311 		instruction.offset = offsetValue.componentCount;
312 
313 		for(uint32_t j = 0; j < offsetValue.componentCount; j++, i++)
314 		{
315 			in[i] = As<SIMD::Float>(offsetValue.Int(j));  // Integer values, but transfered as float.
316 		}
317 	}
318 
319 	if(sample)
320 	{
321 		auto sampleValue = Operand(this, state, sampleId);
322 		in[i] = As<SIMD::Float>(sampleValue.Int(0));
323 	}
324 
325 	auto cacheIt = state->routine->samplerCache.find(insn.resultId());
326 	ASSERT(cacheIt != state->routine->samplerCache.end());
327 	auto &cache = cacheIt->second;
328 	auto cacheHit = cache.imageDescriptor == imageDescriptor && cache.sampler == sampler;
329 
330 	If(!cacheHit)
331 	{
332 		cache.function = Call(getImageSampler, instruction.parameters, imageDescriptor, sampler);
333 		cache.imageDescriptor = imageDescriptor;
334 		cache.sampler = sampler;
335 	}
336 
337 	Call<ImageSampler>(cache.function, texture, &in[0], &out[0], state->routine->constants);
338 }
339 
EmitImageQuerySizeLod(InsnIterator insn,EmitState * state) const340 SpirvShader::EmitResult SpirvShader::EmitImageQuerySizeLod(InsnIterator insn, EmitState *state) const
341 {
342 	auto &resultTy = getType(Type::ID(insn.resultTypeId()));
343 	auto imageId = Object::ID(insn.word(3));
344 	auto lodId = Object::ID(insn.word(4));
345 
346 	auto &dst = state->createIntermediate(insn.resultId(), resultTy.componentCount);
347 	GetImageDimensions(state, resultTy, imageId, lodId, dst);
348 
349 	return EmitResult::Continue;
350 }
351 
EmitImageQuerySize(InsnIterator insn,EmitState * state) const352 SpirvShader::EmitResult SpirvShader::EmitImageQuerySize(InsnIterator insn, EmitState *state) const
353 {
354 	auto &resultTy = getType(Type::ID(insn.resultTypeId()));
355 	auto imageId = Object::ID(insn.word(3));
356 	auto lodId = Object::ID(0);
357 
358 	auto &dst = state->createIntermediate(insn.resultId(), resultTy.componentCount);
359 	GetImageDimensions(state, resultTy, imageId, lodId, dst);
360 
361 	return EmitResult::Continue;
362 }
363 
EmitImageQueryLod(InsnIterator insn,EmitState * state) const364 SpirvShader::EmitResult SpirvShader::EmitImageQueryLod(InsnIterator insn, EmitState *state) const
365 {
366 	return EmitImageSample({ None, Query }, insn, state);
367 }
368 
GetImageDimensions(EmitState const * state,Type const & resultTy,Object::ID imageId,Object::ID lodId,Intermediate & dst) const369 void SpirvShader::GetImageDimensions(EmitState const *state, Type const &resultTy, Object::ID imageId, Object::ID lodId, Intermediate &dst) const
370 {
371 	auto routine = state->routine;
372 	auto &image = getObject(imageId);
373 	auto &imageType = getType(image);
374 
375 	ASSERT(imageType.definition.opcode() == spv::OpTypeImage);
376 	bool isArrayed = imageType.definition.word(5) != 0;
377 	uint32_t dimensions = resultTy.componentCount - (isArrayed ? 1 : 0);
378 
379 	const DescriptorDecorations &d = descriptorDecorations.at(imageId);
380 	auto descriptorType = routine->pipelineLayout->getDescriptorType(d.DescriptorSet, d.Binding);
381 
382 	Pointer<Byte> descriptor = state->getPointer(imageId).base;
383 
384 	Int width;
385 	Int height;
386 	Int depth;
387 
388 	switch(descriptorType)
389 	{
390 		case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
391 		case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
392 			width = *Pointer<Int>(descriptor + OFFSET(vk::StorageImageDescriptor, width));
393 			height = *Pointer<Int>(descriptor + OFFSET(vk::StorageImageDescriptor, height));
394 			depth = *Pointer<Int>(descriptor + OFFSET(vk::StorageImageDescriptor, depth));
395 			break;
396 		case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
397 		case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
398 		case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
399 			width = *Pointer<Int>(descriptor + OFFSET(vk::SampledImageDescriptor, width));
400 			height = *Pointer<Int>(descriptor + OFFSET(vk::SampledImageDescriptor, height));
401 			depth = *Pointer<Int>(descriptor + OFFSET(vk::SampledImageDescriptor, depth));
402 			break;
403 		default:
404 			UNREACHABLE("Image descriptorType: %d", int(descriptorType));
405 	}
406 
407 	if(lodId != 0)
408 	{
409 		auto lodVal = Operand(this, state, lodId);
410 		ASSERT(lodVal.componentCount == 1);
411 		auto lod = lodVal.Int(0);
412 		auto one = SIMD::Int(1);
413 
414 		if(dimensions >= 1) dst.move(0, Max(SIMD::Int(width) >> lod, one));
415 		if(dimensions >= 2) dst.move(1, Max(SIMD::Int(height) >> lod, one));
416 		if(dimensions >= 3) dst.move(2, Max(SIMD::Int(depth) >> lod, one));
417 	}
418 	else
419 	{
420 
421 		if(dimensions >= 1) dst.move(0, SIMD::Int(width));
422 		if(dimensions >= 2) dst.move(1, SIMD::Int(height));
423 		if(dimensions >= 3) dst.move(2, SIMD::Int(depth));
424 	}
425 
426 	if(isArrayed)
427 	{
428 		dst.move(dimensions, SIMD::Int(depth));
429 	}
430 }
431 
EmitImageQueryLevels(InsnIterator insn,EmitState * state) const432 SpirvShader::EmitResult SpirvShader::EmitImageQueryLevels(InsnIterator insn, EmitState *state) const
433 {
434 	auto &resultTy = getType(Type::ID(insn.resultTypeId()));
435 	ASSERT(resultTy.componentCount == 1);
436 	auto imageId = Object::ID(insn.word(3));
437 
438 	const DescriptorDecorations &d = descriptorDecorations.at(imageId);
439 	auto descriptorType = state->routine->pipelineLayout->getDescriptorType(d.DescriptorSet, d.Binding);
440 
441 	Pointer<Byte> descriptor = state->getPointer(imageId).base;
442 	Int mipLevels = 0;
443 	switch(descriptorType)
444 	{
445 		case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
446 		case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
447 		case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
448 			mipLevels = *Pointer<Int>(descriptor + OFFSET(vk::SampledImageDescriptor, mipLevels));  // uint32_t
449 			break;
450 		default:
451 			UNREACHABLE("Image descriptorType: %d", int(descriptorType));
452 	}
453 
454 	auto &dst = state->createIntermediate(insn.resultId(), 1);
455 	dst.move(0, SIMD::Int(mipLevels));
456 
457 	return EmitResult::Continue;
458 }
459 
EmitImageQuerySamples(InsnIterator insn,EmitState * state) const460 SpirvShader::EmitResult SpirvShader::EmitImageQuerySamples(InsnIterator insn, EmitState *state) const
461 {
462 	auto &resultTy = getType(Type::ID(insn.resultTypeId()));
463 	ASSERT(resultTy.componentCount == 1);
464 	auto imageId = Object::ID(insn.word(3));
465 	auto imageTy = getType(getObject(imageId));
466 	ASSERT(imageTy.definition.opcode() == spv::OpTypeImage);
467 	ASSERT(imageTy.definition.word(3) == spv::Dim2D);
468 	ASSERT(imageTy.definition.word(6 /* MS */) == 1);
469 
470 	const DescriptorDecorations &d = descriptorDecorations.at(imageId);
471 	auto descriptorType = state->routine->pipelineLayout->getDescriptorType(d.DescriptorSet, d.Binding);
472 
473 	Pointer<Byte> descriptor = state->getPointer(imageId).base;
474 	Int sampleCount = 0;
475 	switch(descriptorType)
476 	{
477 		case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
478 			sampleCount = *Pointer<Int>(descriptor + OFFSET(vk::StorageImageDescriptor, sampleCount));  // uint32_t
479 			break;
480 		case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
481 		case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
482 		case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
483 			sampleCount = *Pointer<Int>(descriptor + OFFSET(vk::SampledImageDescriptor, sampleCount));  // uint32_t
484 			break;
485 		default:
486 			UNREACHABLE("Image descriptorType: %d", int(descriptorType));
487 	}
488 
489 	auto &dst = state->createIntermediate(insn.resultId(), 1);
490 	dst.move(0, SIMD::Int(sampleCount));
491 
492 	return EmitResult::Continue;
493 }
494 
GetTexelAddress(EmitState const * state,Pointer<Byte> imageBase,Int imageSizeInBytes,Operand const & coordinate,Type const & imageType,Pointer<Byte> descriptor,int texelSize,Object::ID sampleId,bool useStencilAspect,OutOfBoundsBehavior outOfBoundsBehavior) const495 SIMD::Pointer SpirvShader::GetTexelAddress(EmitState const *state, Pointer<Byte> imageBase, Int imageSizeInBytes, Operand const &coordinate, Type const &imageType, Pointer<Byte> descriptor, int texelSize, Object::ID sampleId, bool useStencilAspect, OutOfBoundsBehavior outOfBoundsBehavior) const
496 {
497 	auto routine = state->routine;
498 	bool isArrayed = imageType.definition.word(5) != 0;
499 	auto dim = static_cast<spv::Dim>(imageType.definition.word(3));
500 	int dims = coordinate.componentCount - (isArrayed ? 1 : 0);
501 
502 	SIMD::Int u = coordinate.Int(0);
503 	SIMD::Int v = SIMD::Int(0);
504 
505 	if(coordinate.componentCount > 1)
506 	{
507 		v = coordinate.Int(1);
508 	}
509 
510 	if(dim == spv::DimSubpassData)
511 	{
512 		u += routine->windowSpacePosition[0];
513 		v += routine->windowSpacePosition[1];
514 	}
515 
516 	auto rowPitch = SIMD::Int(*Pointer<Int>(descriptor + (useStencilAspect
517 	                                                          ? OFFSET(vk::StorageImageDescriptor, stencilRowPitchBytes)
518 	                                                          : OFFSET(vk::StorageImageDescriptor, rowPitchBytes))));
519 	auto slicePitch = SIMD::Int(
520 	    *Pointer<Int>(descriptor + (useStencilAspect
521 	                                    ? OFFSET(vk::StorageImageDescriptor, stencilSlicePitchBytes)
522 	                                    : OFFSET(vk::StorageImageDescriptor, slicePitchBytes))));
523 	auto samplePitch = SIMD::Int(
524 	    *Pointer<Int>(descriptor + (useStencilAspect
525 	                                    ? OFFSET(vk::StorageImageDescriptor, stencilSamplePitchBytes)
526 	                                    : OFFSET(vk::StorageImageDescriptor, samplePitchBytes))));
527 
528 	SIMD::Int ptrOffset = u * SIMD::Int(texelSize);
529 
530 	if(dims > 1)
531 	{
532 		ptrOffset += v * rowPitch;
533 	}
534 
535 	SIMD::Int w = 0;
536 	if((dims > 2) || isArrayed)
537 	{
538 		if(dims > 2)
539 		{
540 			w += coordinate.Int(2);
541 		}
542 
543 		if(isArrayed)
544 		{
545 			w += coordinate.Int(dims);
546 		}
547 
548 		ptrOffset += w * slicePitch;
549 	}
550 
551 	if(dim == spv::DimSubpassData)
552 	{
553 		// Multiview input attachment access is to the layer corresponding to the current view
554 		ptrOffset += SIMD::Int(routine->viewID) * slicePitch;
555 	}
556 
557 	SIMD::Int n = 0;
558 	if(sampleId.value())
559 	{
560 		Operand sample(this, state, sampleId);
561 		if(!sample.isConstantZero())
562 		{
563 			n = sample.Int(0);
564 			ptrOffset += n * samplePitch;
565 		}
566 	}
567 
568 	// If the out-of-bounds behavior is set to nullify, then each coordinate must be tested individually.
569 	// Other out-of-bounds behaviors work properly by just comparing the offset against the total size.
570 	if(outOfBoundsBehavior == OutOfBoundsBehavior::Nullify)
571 	{
572 		SIMD::UInt width = *Pointer<UInt>(descriptor + OFFSET(vk::StorageImageDescriptor, width));
573 		SIMD::Int oobMask = As<SIMD::Int>(CmpNLT(As<SIMD::UInt>(u), width));
574 
575 		if(dims > 1)
576 		{
577 			SIMD::UInt height = *Pointer<UInt>(descriptor + OFFSET(vk::StorageImageDescriptor, height));
578 			oobMask |= As<SIMD::Int>(CmpNLT(As<SIMD::UInt>(v), height));
579 		}
580 
581 		if((dims > 2) || isArrayed)
582 		{
583 			UInt depth = *Pointer<UInt>(descriptor + OFFSET(vk::StorageImageDescriptor, depth));
584 			if(dim == spv::DimCube) { depth *= 6; }
585 			oobMask |= As<SIMD::Int>(CmpNLT(As<SIMD::UInt>(w), SIMD::UInt(depth)));
586 		}
587 
588 		if(sampleId.value())
589 		{
590 			Operand sample(this, state, sampleId);
591 			if(!sample.isConstantZero())
592 			{
593 				SIMD::UInt sampleCount = *Pointer<UInt>(descriptor + OFFSET(vk::StorageImageDescriptor, sampleCount));
594 				oobMask |= As<SIMD::Int>(CmpNLT(As<SIMD::UInt>(n), sampleCount));
595 			}
596 		}
597 
598 		constexpr int32_t OOB_OFFSET = 0x7FFFFFFF - 16;  // SIMD pointer offsets are signed 32-bit, so this is the largest offset (for 16-byte texels).
599 		static_assert(OOB_OFFSET >= MAX_MEMORY_ALLOCATION_SIZE, "the largest offset must be guaranteed to be out-of-bounds");
600 
601 		ptrOffset = (ptrOffset & ~oobMask) | (oobMask & SIMD::Int(OOB_OFFSET));  // oob ? OOB_OFFSET : ptrOffset  // TODO: IfThenElse()
602 	}
603 
604 	return SIMD::Pointer(imageBase, imageSizeInBytes, ptrOffset);
605 }
606 
EmitImageRead(InsnIterator insn,EmitState * state) const607 SpirvShader::EmitResult SpirvShader::EmitImageRead(InsnIterator insn, EmitState *state) const
608 {
609 	auto &resultType = getType(Type::ID(insn.word(1)));
610 	auto imageId = Object::ID(insn.word(3));
611 	auto &image = getObject(imageId);
612 	auto &imageType = getType(image);
613 
614 	Object::ID sampleId = 0;
615 
616 	if(insn.wordCount() > 5)
617 	{
618 		int operand = 6;
619 		uint32_t imageOperands = insn.word(5);
620 		if(imageOperands & spv::ImageOperandsSampleMask)
621 		{
622 			sampleId = insn.word(operand++);
623 			imageOperands &= ~spv::ImageOperandsSampleMask;
624 		}
625 		// TODO(b/174475384)
626 		if(imageOperands & spv::ImageOperandsZeroExtendMask)
627 		{
628 			imageOperands &= ~spv::ImageOperandsZeroExtendMask;
629 		}
630 		else if(imageOperands & spv::ImageOperandsSignExtendMask)
631 		{
632 			imageOperands &= ~spv::ImageOperandsSignExtendMask;
633 		}
634 
635 		// Should be no remaining image operands.
636 		if(imageOperands != 0)
637 		{
638 			UNSUPPORTED("Image operands 0x%08X", imageOperands);
639 		}
640 	}
641 
642 	ASSERT(imageType.definition.opcode() == spv::OpTypeImage);
643 	auto dim = static_cast<spv::Dim>(imageType.definition.word(3));
644 
645 	auto coordinate = Operand(this, state, insn.word(4));
646 	const DescriptorDecorations &d = descriptorDecorations.at(imageId);
647 
648 	// For subpass data, format in the instruction is spv::ImageFormatUnknown. Get it from
649 	// the renderpass data instead. In all other cases, we can use the format in the instruction.
650 	auto vkFormat = (dim == spv::DimSubpassData)
651 	                    ? inputAttachmentFormats[d.InputAttachmentIndex]
652 	                    : SpirvFormatToVulkanFormat(static_cast<spv::ImageFormat>(imageType.definition.word(8)));
653 
654 	// Depth+Stencil image attachments select aspect based on the Sampled Type of the
655 	// OpTypeImage. If float, then we want the depth aspect. If int, we want the stencil aspect.
656 	auto useStencilAspect = (vkFormat == VK_FORMAT_D32_SFLOAT_S8_UINT &&
657 	                         getType(imageType.definition.word(2)).opcode() == spv::OpTypeInt);
658 
659 	if(useStencilAspect)
660 	{
661 		vkFormat = VK_FORMAT_S8_UINT;
662 	}
663 
664 	auto pointer = state->getPointer(imageId);
665 	Pointer<Byte> binding = pointer.base;
666 	Pointer<Byte> imageBase = *Pointer<Pointer<Byte>>(binding + (useStencilAspect
667 	                                                                 ? OFFSET(vk::StorageImageDescriptor, stencilPtr)
668 	                                                                 : OFFSET(vk::StorageImageDescriptor, ptr)));
669 
670 	auto imageSizeInBytes = *Pointer<Int>(binding + OFFSET(vk::StorageImageDescriptor, sizeInBytes));
671 
672 	auto &dst = state->createIntermediate(insn.resultId(), resultType.componentCount);
673 
674 	// VK_EXT_image_robustness requires replacing out-of-bounds access with zero.
675 	// TODO(b/162327166): Only perform bounds checks when VK_EXT_image_robustness is enabled.
676 	auto robustness = OutOfBoundsBehavior::Nullify;
677 
678 	auto texelSize = vk::Format(vkFormat).bytes();
679 	auto texelPtr = GetTexelAddress(state, imageBase, imageSizeInBytes, coordinate, imageType, binding, texelSize, sampleId, useStencilAspect, robustness);
680 
681 	// Gather packed texel data. Texels larger than 4 bytes occupy multiple SIMD::Int elements.
682 	// TODO(b/160531165): Provide gather abstractions for various element sizes.
683 	SIMD::Int packed[4];
684 	if(texelSize == 4 || texelSize == 8 || texelSize == 16)
685 	{
686 		for(auto i = 0; i < texelSize / 4; i++)
687 		{
688 			packed[i] = texelPtr.Load<SIMD::Int>(robustness, state->activeLaneMask());
689 			texelPtr += sizeof(float);
690 		}
691 	}
692 	else if(texelSize == 2)
693 	{
694 		SIMD::Int offsets = texelPtr.offsets();
695 		SIMD::Int mask = state->activeLaneMask() & texelPtr.isInBounds(2, robustness);
696 
697 		for(int i = 0; i < SIMD::Width; i++)
698 		{
699 			If(Extract(mask, i) != 0)
700 			{
701 				packed[0] = Insert(packed[0], Int(*Pointer<Short>(texelPtr.base + Extract(offsets, i))), i);
702 			}
703 		}
704 	}
705 	else if(texelSize == 1)
706 	{
707 		SIMD::Int offsets = texelPtr.offsets();
708 		SIMD::Int mask = state->activeLaneMask() & texelPtr.isInBounds(1, robustness);
709 
710 		for(int i = 0; i < SIMD::Width; i++)
711 		{
712 			If(Extract(mask, i) != 0)
713 			{
714 				packed[0] = Insert(packed[0], Int(*Pointer<Byte>(texelPtr.base + Extract(offsets, i))), i);
715 			}
716 		}
717 	}
718 	else
719 		UNREACHABLE("texelSize: %d", int(texelSize));
720 
721 	// Format support requirements here come from two sources:
722 	// - Minimum required set of formats for loads from storage images
723 	// - Any format supported as a color or depth/stencil attachment, for input attachments
724 	switch(vkFormat)
725 	{
726 		case VK_FORMAT_R32G32B32A32_SFLOAT:
727 		case VK_FORMAT_R32G32B32A32_SINT:
728 		case VK_FORMAT_R32G32B32A32_UINT:
729 			dst.move(0, packed[0]);
730 			dst.move(1, packed[1]);
731 			dst.move(2, packed[2]);
732 			dst.move(3, packed[3]);
733 			break;
734 		case VK_FORMAT_R32_SINT:
735 		case VK_FORMAT_R32_UINT:
736 			dst.move(0, packed[0]);
737 			// Fill remaining channels with 0,0,1 (of the correct type)
738 			dst.move(1, SIMD::Int(0));
739 			dst.move(2, SIMD::Int(0));
740 			dst.move(3, SIMD::Int(1));
741 			break;
742 		case VK_FORMAT_R32_SFLOAT:
743 		case VK_FORMAT_D32_SFLOAT:
744 		case VK_FORMAT_D32_SFLOAT_S8_UINT:
745 			dst.move(0, packed[0]);
746 			// Fill remaining channels with 0,0,1 (of the correct type)
747 			dst.move(1, SIMD::Float(0.0f));
748 			dst.move(2, SIMD::Float(0.0f));
749 			dst.move(3, SIMD::Float(1.0f));
750 			break;
751 		case VK_FORMAT_D16_UNORM:
752 			dst.move(0, SIMD::Float(packed[0] & SIMD::Int(0xFFFF)) * SIMD::Float(1.0f / 0xFFFF));
753 			dst.move(1, SIMD::Float(0.0f));
754 			dst.move(2, SIMD::Float(0.0f));
755 			dst.move(3, SIMD::Float(1.0f));
756 			break;
757 		case VK_FORMAT_R16G16B16A16_UNORM:
758 			dst.move(0, SIMD::Float(packed[0] & SIMD::Int(0xFFFF)) * SIMD::Float(1.0f / 0xFFFF));
759 			dst.move(1, SIMD::Float((packed[0] >> 16) & SIMD::Int(0xFFFF)) * SIMD::Float(1.0f / 0xFFFF));
760 			dst.move(2, SIMD::Float(packed[1] & SIMD::Int(0xFFFF)) * SIMD::Float(1.0f / 0xFFFF));
761 			dst.move(3, SIMD::Float((packed[1] >> 16) & SIMD::Int(0xFFFF)) * SIMD::Float(1.0f / 0xFFFF));
762 			break;
763 		case VK_FORMAT_R16G16B16A16_SNORM:
764 			dst.move(0, Max(SIMD::Float((packed[0] << 16) & SIMD::Int(0xFFFF0000)) * SIMD::Float(1.0f / 0x7FFF0000), SIMD::Float(-1.0f)));
765 			dst.move(1, Max(SIMD::Float(packed[0] & SIMD::Int(0xFFFF0000)) * SIMD::Float(1.0f / 0x7FFF0000), SIMD::Float(-1.0f)));
766 			dst.move(2, Max(SIMD::Float((packed[1] << 16) & SIMD::Int(0xFFFF0000)) * SIMD::Float(1.0f / 0x7FFF0000), SIMD::Float(-1.0f)));
767 			dst.move(3, Max(SIMD::Float(packed[1] & SIMD::Int(0xFFFF0000)) * SIMD::Float(1.0f / 0x7FFF0000), SIMD::Float(-1.0f)));
768 			break;
769 		case VK_FORMAT_R16G16B16A16_SINT:
770 			dst.move(0, (packed[0] << 16) >> 16);
771 			dst.move(1, packed[0] >> 16);
772 			dst.move(2, (packed[1] << 16) >> 16);
773 			dst.move(3, packed[1] >> 16);
774 			break;
775 		case VK_FORMAT_R16G16B16A16_UINT:
776 			dst.move(0, packed[0] & SIMD::Int(0xFFFF));
777 			dst.move(1, (packed[0] >> 16) & SIMD::Int(0xFFFF));
778 			dst.move(2, packed[1] & SIMD::Int(0xFFFF));
779 			dst.move(3, (packed[1] >> 16) & SIMD::Int(0xFFFF));
780 			break;
781 		case VK_FORMAT_R16G16B16A16_SFLOAT:
782 			dst.move(0, halfToFloatBits(As<SIMD::UInt>(packed[0]) & SIMD::UInt(0x0000FFFF)));
783 			dst.move(1, halfToFloatBits((As<SIMD::UInt>(packed[0]) & SIMD::UInt(0xFFFF0000)) >> 16));
784 			dst.move(2, halfToFloatBits(As<SIMD::UInt>(packed[1]) & SIMD::UInt(0x0000FFFF)));
785 			dst.move(3, halfToFloatBits((As<SIMD::UInt>(packed[1]) & SIMD::UInt(0xFFFF0000)) >> 16));
786 			break;
787 		case VK_FORMAT_R8G8B8A8_SNORM:
788 		case VK_FORMAT_A8B8G8R8_SNORM_PACK32:
789 			dst.move(0, Max(SIMD::Float((packed[0] << 24) & SIMD::Int(0xFF000000)) * SIMD::Float(1.0f / 0x7F000000), SIMD::Float(-1.0f)));
790 			dst.move(1, Max(SIMD::Float((packed[0] << 16) & SIMD::Int(0xFF000000)) * SIMD::Float(1.0f / 0x7F000000), SIMD::Float(-1.0f)));
791 			dst.move(2, Max(SIMD::Float((packed[0] << 8) & SIMD::Int(0xFF000000)) * SIMD::Float(1.0f / 0x7F000000), SIMD::Float(-1.0f)));
792 			dst.move(3, Max(SIMD::Float((packed[0]) & SIMD::Int(0xFF000000)) * SIMD::Float(1.0f / 0x7F000000), SIMD::Float(-1.0f)));
793 			break;
794 		case VK_FORMAT_R8G8B8A8_UNORM:
795 		case VK_FORMAT_A8B8G8R8_UNORM_PACK32:
796 			dst.move(0, SIMD::Float(packed[0] & SIMD::Int(0xFF)) * SIMD::Float(1.0f / 0xFF));
797 			dst.move(1, SIMD::Float((packed[0] >> 8) & SIMD::Int(0xFF)) * SIMD::Float(1.0f / 0xFF));
798 			dst.move(2, SIMD::Float((packed[0] >> 16) & SIMD::Int(0xFF)) * SIMD::Float(1.0f / 0xFF));
799 			dst.move(3, SIMD::Float((packed[0] >> 24) & SIMD::Int(0xFF)) * SIMD::Float(1.0f / 0xFF));
800 			break;
801 		case VK_FORMAT_R8G8B8A8_SRGB:
802 		case VK_FORMAT_A8B8G8R8_SRGB_PACK32:
803 			dst.move(0, ::sRGBtoLinear(SIMD::Float(packed[0] & SIMD::Int(0xFF)) * SIMD::Float(1.0f / 0xFF)));
804 			dst.move(1, ::sRGBtoLinear(SIMD::Float((packed[0] >> 8) & SIMD::Int(0xFF)) * SIMD::Float(1.0f / 0xFF)));
805 			dst.move(2, ::sRGBtoLinear(SIMD::Float((packed[0] >> 16) & SIMD::Int(0xFF)) * SIMD::Float(1.0f / 0xFF)));
806 			dst.move(3, SIMD::Float((packed[0] >> 24) & SIMD::Int(0xFF)) * SIMD::Float(1.0f / 0xFF));
807 			break;
808 		case VK_FORMAT_B8G8R8A8_UNORM:
809 			dst.move(0, SIMD::Float((packed[0] >> 16) & SIMD::Int(0xFF)) * SIMD::Float(1.0f / 0xFF));
810 			dst.move(1, SIMD::Float((packed[0] >> 8) & SIMD::Int(0xFF)) * SIMD::Float(1.0f / 0xFF));
811 			dst.move(2, SIMD::Float(packed[0] & SIMD::Int(0xFF)) * SIMD::Float(1.0f / 0xFF));
812 			dst.move(3, SIMD::Float((packed[0] >> 24) & SIMD::Int(0xFF)) * SIMD::Float(1.0f / 0xFF));
813 			break;
814 		case VK_FORMAT_B8G8R8A8_SRGB:
815 			dst.move(0, ::sRGBtoLinear(SIMD::Float((packed[0] >> 16) & SIMD::Int(0xFF)) * SIMD::Float(1.0f / 0xFF)));
816 			dst.move(1, ::sRGBtoLinear(SIMD::Float((packed[0] >> 8) & SIMD::Int(0xFF)) * SIMD::Float(1.0f / 0xFF)));
817 			dst.move(2, ::sRGBtoLinear(SIMD::Float(packed[0] & SIMD::Int(0xFF)) * SIMD::Float(1.0f / 0xFF)));
818 			dst.move(3, SIMD::Float((packed[0] >> 24) & SIMD::Int(0xFF)) * SIMD::Float(1.0f / 0xFF));
819 			break;
820 		case VK_FORMAT_R8G8B8A8_UINT:
821 		case VK_FORMAT_A8B8G8R8_UINT_PACK32:
822 			dst.move(0, As<SIMD::UInt>(packed[0]) & SIMD::UInt(0xFF));
823 			dst.move(1, (As<SIMD::UInt>(packed[0]) >> 8) & SIMD::UInt(0xFF));
824 			dst.move(2, (As<SIMD::UInt>(packed[0]) >> 16) & SIMD::UInt(0xFF));
825 			dst.move(3, (As<SIMD::UInt>(packed[0]) >> 24) & SIMD::UInt(0xFF));
826 			break;
827 		case VK_FORMAT_R8G8B8A8_SINT:
828 		case VK_FORMAT_A8B8G8R8_SINT_PACK32:
829 			dst.move(0, (packed[0] << 24) >> 24);
830 			dst.move(1, (packed[0] << 16) >> 24);
831 			dst.move(2, (packed[0] << 8) >> 24);
832 			dst.move(3, packed[0] >> 24);
833 			break;
834 		case VK_FORMAT_R8_UNORM:
835 			dst.move(0, SIMD::Float((packed[0] & SIMD::Int(0xFF))) * SIMD::Float(1.0f / 0xFF));
836 			dst.move(1, SIMD::Float(0.0f));
837 			dst.move(2, SIMD::Float(0.0f));
838 			dst.move(3, SIMD::Float(1.0f));
839 			break;
840 		case VK_FORMAT_R8_SNORM:
841 			dst.move(0, Max(SIMD::Float((packed[0] << 24) & SIMD::Int(0xFF000000)) * SIMD::Float(1.0f / 0x7F000000), SIMD::Float(-1.0f)));
842 			dst.move(1, SIMD::Float(0.0f));
843 			dst.move(2, SIMD::Float(0.0f));
844 			dst.move(3, SIMD::Float(1.0f));
845 			break;
846 		case VK_FORMAT_R8_UINT:
847 		case VK_FORMAT_S8_UINT:
848 			dst.move(0, As<SIMD::UInt>(packed[0]) & SIMD::UInt(0xFF));
849 			dst.move(1, SIMD::UInt(0));
850 			dst.move(2, SIMD::UInt(0));
851 			dst.move(3, SIMD::UInt(1));
852 			break;
853 		case VK_FORMAT_R8_SINT:
854 			dst.move(0, (packed[0] << 24) >> 24);
855 			dst.move(1, SIMD::Int(0));
856 			dst.move(2, SIMD::Int(0));
857 			dst.move(3, SIMD::Int(1));
858 			break;
859 		case VK_FORMAT_R8G8_UNORM:
860 			dst.move(0, SIMD::Float(packed[0] & SIMD::Int(0xFF)) * SIMD::Float(1.0f / 0xFF));
861 			dst.move(1, SIMD::Float((packed[0] >> 8) & SIMD::Int(0xFF)) * SIMD::Float(1.0f / 0xFF));
862 			dst.move(2, SIMD::Float(0.0f));
863 			dst.move(3, SIMD::Float(1.0f));
864 			break;
865 		case VK_FORMAT_R8G8_SNORM:
866 			dst.move(0, Max(SIMD::Float((packed[0] << 24) & SIMD::Int(0xFF000000)) * SIMD::Float(1.0f / 0x7F000000), SIMD::Float(-1.0f)));
867 			dst.move(1, Max(SIMD::Float((packed[0] << 16) & SIMD::Int(0xFF000000)) * SIMD::Float(1.0f / 0x7F000000), SIMD::Float(-1.0f)));
868 			dst.move(2, SIMD::Float(0.0f));
869 			dst.move(3, SIMD::Float(1.0f));
870 			break;
871 		case VK_FORMAT_R8G8_UINT:
872 			dst.move(0, As<SIMD::UInt>(packed[0]) & SIMD::UInt(0xFF));
873 			dst.move(1, (As<SIMD::UInt>(packed[0]) >> 8) & SIMD::UInt(0xFF));
874 			dst.move(2, SIMD::UInt(0));
875 			dst.move(3, SIMD::UInt(1));
876 			break;
877 		case VK_FORMAT_R8G8_SINT:
878 			dst.move(0, (packed[0] << 24) >> 24);
879 			dst.move(1, (packed[0] << 16) >> 24);
880 			dst.move(2, SIMD::Int(0));
881 			dst.move(3, SIMD::Int(1));
882 			break;
883 		case VK_FORMAT_R16_SFLOAT:
884 			dst.move(0, halfToFloatBits(As<SIMD::UInt>(packed[0]) & SIMD::UInt(0x0000FFFF)));
885 			dst.move(1, SIMD::Float(0.0f));
886 			dst.move(2, SIMD::Float(0.0f));
887 			dst.move(3, SIMD::Float(1.0f));
888 			break;
889 		case VK_FORMAT_R16_UNORM:
890 			dst.move(0, SIMD::Float(packed[0] & SIMD::Int(0xFFFF)) * SIMD::Float(1.0f / 0xFFFF));
891 			dst.move(1, SIMD::Float(0.0f));
892 			dst.move(2, SIMD::Float(0.0f));
893 			dst.move(3, SIMD::Float(1.0f));
894 			break;
895 		case VK_FORMAT_R16_SNORM:
896 			dst.move(0, Max(SIMD::Float((packed[0] << 16) & SIMD::Int(0xFFFF0000)) * SIMD::Float(1.0f / 0x7FFF0000), SIMD::Float(-1.0f)));
897 			dst.move(1, SIMD::Float(0.0f));
898 			dst.move(2, SIMD::Float(0.0f));
899 			dst.move(3, SIMD::Float(1.0f));
900 			break;
901 		case VK_FORMAT_R16_UINT:
902 			dst.move(0, packed[0] & SIMD::Int(0xFFFF));
903 			dst.move(1, SIMD::UInt(0));
904 			dst.move(2, SIMD::UInt(0));
905 			dst.move(3, SIMD::UInt(1));
906 			break;
907 		case VK_FORMAT_R16_SINT:
908 			dst.move(0, (packed[0] << 16) >> 16);
909 			dst.move(1, SIMD::Int(0));
910 			dst.move(2, SIMD::Int(0));
911 			dst.move(3, SIMD::Int(1));
912 			break;
913 		case VK_FORMAT_R16G16_SFLOAT:
914 			dst.move(0, halfToFloatBits(As<SIMD::UInt>(packed[0]) & SIMD::UInt(0x0000FFFF)));
915 			dst.move(1, halfToFloatBits((As<SIMD::UInt>(packed[0]) & SIMD::UInt(0xFFFF0000)) >> 16));
916 			dst.move(2, SIMD::Float(0.0f));
917 			dst.move(3, SIMD::Float(1.0f));
918 			break;
919 		case VK_FORMAT_R16G16_UNORM:
920 			dst.move(0, SIMD::Float(packed[0] & SIMD::Int(0xFFFF)) * SIMD::Float(1.0f / 0xFFFF));
921 			dst.move(1, SIMD::Float(As<SIMD::UInt>(packed[0]) >> 16) * SIMD::Float(1.0f / 0xFFFF));
922 			dst.move(2, SIMD::Float(0.0f));
923 			dst.move(3, SIMD::Float(1.0f));
924 			break;
925 		case VK_FORMAT_R16G16_SNORM:
926 			dst.move(0, Max(SIMD::Float((packed[0] << 16) & SIMD::Int(0xFFFF0000)) * SIMD::Float(1.0f / 0x7FFF0000), SIMD::Float(-1.0f)));
927 			dst.move(1, Max(SIMD::Float(packed[0] & SIMD::Int(0xFFFF0000)) * SIMD::Float(1.0f / 0x7FFF0000), SIMD::Float(-1.0f)));
928 			dst.move(2, SIMD::Float(0.0f));
929 			dst.move(3, SIMD::Float(1.0f));
930 			break;
931 		case VK_FORMAT_R16G16_UINT:
932 			dst.move(0, packed[0] & SIMD::Int(0xFFFF));
933 			dst.move(1, (packed[0] >> 16) & SIMD::Int(0xFFFF));
934 			dst.move(2, SIMD::UInt(0));
935 			dst.move(3, SIMD::UInt(1));
936 			break;
937 		case VK_FORMAT_R16G16_SINT:
938 			dst.move(0, (packed[0] << 16) >> 16);
939 			dst.move(1, packed[0] >> 16);
940 			dst.move(2, SIMD::Int(0));
941 			dst.move(3, SIMD::Int(1));
942 			break;
943 		case VK_FORMAT_R32G32_SINT:
944 		case VK_FORMAT_R32G32_UINT:
945 			dst.move(0, packed[0]);
946 			dst.move(1, packed[1]);
947 			dst.move(2, SIMD::Int(0));
948 			dst.move(3, SIMD::Int(1));
949 			break;
950 		case VK_FORMAT_R32G32_SFLOAT:
951 			dst.move(0, packed[0]);
952 			dst.move(1, packed[1]);
953 			dst.move(2, SIMD::Float(0.0f));
954 			dst.move(3, SIMD::Float(1.0f));
955 			break;
956 		case VK_FORMAT_A2B10G10R10_UINT_PACK32:
957 			dst.move(0, packed[0] & SIMD::Int(0x3FF));
958 			dst.move(1, (packed[0] >> 10) & SIMD::Int(0x3FF));
959 			dst.move(2, (packed[0] >> 20) & SIMD::Int(0x3FF));
960 			dst.move(3, (packed[0] >> 30) & SIMD::Int(0x3));
961 			break;
962 		case VK_FORMAT_A2R10G10B10_UINT_PACK32:
963 			dst.move(2, packed[0] & SIMD::Int(0x3FF));
964 			dst.move(1, (packed[0] >> 10) & SIMD::Int(0x3FF));
965 			dst.move(0, (packed[0] >> 20) & SIMD::Int(0x3FF));
966 			dst.move(3, (packed[0] >> 30) & SIMD::Int(0x3));
967 			break;
968 		case VK_FORMAT_A2B10G10R10_UNORM_PACK32:
969 			dst.move(0, SIMD::Float((packed[0]) & SIMD::Int(0x3FF)) * SIMD::Float(1.0f / 0x3FF));
970 			dst.move(1, SIMD::Float((packed[0] >> 10) & SIMD::Int(0x3FF)) * SIMD::Float(1.0f / 0x3FF));
971 			dst.move(2, SIMD::Float((packed[0] >> 20) & SIMD::Int(0x3FF)) * SIMD::Float(1.0f / 0x3FF));
972 			dst.move(3, SIMD::Float((packed[0] >> 30) & SIMD::Int(0x3)) * SIMD::Float(1.0f / 0x3));
973 			break;
974 		case VK_FORMAT_A2R10G10B10_UNORM_PACK32:
975 			dst.move(2, SIMD::Float((packed[0]) & SIMD::Int(0x3FF)) * SIMD::Float(1.0f / 0x3FF));
976 			dst.move(1, SIMD::Float((packed[0] >> 10) & SIMD::Int(0x3FF)) * SIMD::Float(1.0f / 0x3FF));
977 			dst.move(0, SIMD::Float((packed[0] >> 20) & SIMD::Int(0x3FF)) * SIMD::Float(1.0f / 0x3FF));
978 			dst.move(3, SIMD::Float((packed[0] >> 30) & SIMD::Int(0x3)) * SIMD::Float(1.0f / 0x3));
979 			break;
980 		case VK_FORMAT_R5G6B5_UNORM_PACK16:
981 			dst.move(0, SIMD::Float((packed[0] >> 11) & SIMD::Int(0x1F)) * SIMD::Float(1.0f / 0x1F));
982 			dst.move(1, SIMD::Float((packed[0] >> 5) & SIMD::Int(0x3F)) * SIMD::Float(1.0f / 0x3F));
983 			dst.move(2, SIMD::Float((packed[0]) & SIMD::Int(0x1F)) * SIMD::Float(1.0f / 0x1F));
984 			dst.move(3, SIMD::Float(1.0f));
985 			break;
986 		case VK_FORMAT_A1R5G5B5_UNORM_PACK16:
987 			dst.move(0, SIMD::Float((packed[0] >> 10) & SIMD::Int(0x1F)) * SIMD::Float(1.0f / 0x1F));
988 			dst.move(1, SIMD::Float((packed[0] >> 5) & SIMD::Int(0x1F)) * SIMD::Float(1.0f / 0x1F));
989 			dst.move(2, SIMD::Float((packed[0]) & SIMD::Int(0x1F)) * SIMD::Float(1.0f / 0x1F));
990 			dst.move(3, SIMD::Float((packed[0] >> 15) & SIMD::Int(0x1)));
991 			break;
992 		case VK_FORMAT_B10G11R11_UFLOAT_PACK32:
993 			dst.move(0, halfToFloatBits((packed[0] << 4) & SIMD::Int(0x7FF0)));
994 			dst.move(1, halfToFloatBits((packed[0] >> 7) & SIMD::Int(0x7FF0)));
995 			dst.move(2, halfToFloatBits((packed[0] >> 17) & SIMD::Int(0x7FE0)));
996 			dst.move(3, SIMD::Float(1.0f));
997 			break;
998 		default:
999 			UNSUPPORTED("VkFormat %d", int(vkFormat));
1000 			break;
1001 	}
1002 
1003 	return EmitResult::Continue;
1004 }
1005 
EmitImageWrite(InsnIterator insn,EmitState * state) const1006 SpirvShader::EmitResult SpirvShader::EmitImageWrite(InsnIterator insn, EmitState *state) const
1007 {
1008 	imageWriteEmitted = true;
1009 
1010 	auto imageId = Object::ID(insn.word(1));
1011 	auto &image = getObject(imageId);
1012 	auto &imageType = getType(image);
1013 
1014 	ASSERT(imageType.definition.opcode() == spv::OpTypeImage);
1015 
1016 	Object::ID sampleId = 0;
1017 
1018 	if(insn.wordCount() > 4)
1019 	{
1020 		int operand = 5;
1021 		uint32_t imageOperands = insn.word(4);
1022 		if(imageOperands & spv::ImageOperandsSampleMask)
1023 		{
1024 			sampleId = insn.word(operand++);
1025 			imageOperands &= ~spv::ImageOperandsSampleMask;
1026 		}
1027 		// TODO(b/174475384)
1028 		if(imageOperands & spv::ImageOperandsZeroExtendMask)
1029 		{
1030 			imageOperands &= ~spv::ImageOperandsZeroExtendMask;
1031 		}
1032 		else if(imageOperands & spv::ImageOperandsSignExtendMask)
1033 		{
1034 			imageOperands &= ~spv::ImageOperandsSignExtendMask;
1035 		}
1036 
1037 		// Should be no remaining image operands.
1038 		if(imageOperands != 0)
1039 		{
1040 			UNSUPPORTED("Image operands 0x%08X", (int)imageOperands);
1041 		}
1042 	}
1043 
1044 	auto coordinate = Operand(this, state, insn.word(2));
1045 	auto texel = Operand(this, state, insn.word(3));
1046 
1047 	Pointer<Byte> binding = state->getPointer(imageId).base;
1048 	Pointer<Byte> imageBase = *Pointer<Pointer<Byte>>(binding + OFFSET(vk::StorageImageDescriptor, ptr));
1049 	auto imageSizeInBytes = *Pointer<Int>(binding + OFFSET(vk::StorageImageDescriptor, sizeInBytes));
1050 
1051 	SIMD::Int packed[4];
1052 	int texelSize = 0;
1053 	auto format = static_cast<spv::ImageFormat>(imageType.definition.word(8));
1054 	switch(format)
1055 	{
1056 		case spv::ImageFormatRgba32f:
1057 		case spv::ImageFormatRgba32i:
1058 		case spv::ImageFormatRgba32ui:
1059 			texelSize = 16;
1060 			packed[0] = texel.Int(0);
1061 			packed[1] = texel.Int(1);
1062 			packed[2] = texel.Int(2);
1063 			packed[3] = texel.Int(3);
1064 			break;
1065 		case spv::ImageFormatR32f:
1066 		case spv::ImageFormatR32i:
1067 		case spv::ImageFormatR32ui:
1068 			texelSize = 4;
1069 			packed[0] = texel.Int(0);
1070 			break;
1071 		case spv::ImageFormatRgba8:
1072 			texelSize = 4;
1073 			packed[0] = (SIMD::UInt(Round(Min(Max(texel.Float(0), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(255.0f)))) |
1074 			            ((SIMD::UInt(Round(Min(Max(texel.Float(1), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(255.0f)))) << 8) |
1075 			            ((SIMD::UInt(Round(Min(Max(texel.Float(2), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(255.0f)))) << 16) |
1076 			            ((SIMD::UInt(Round(Min(Max(texel.Float(3), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(255.0f)))) << 24);
1077 			break;
1078 		case spv::ImageFormatRgba8Snorm:
1079 			texelSize = 4;
1080 			packed[0] = (SIMD::Int(Round(Min(Max(texel.Float(0), SIMD::Float(-1.0f)), SIMD::Float(1.0f)) * SIMD::Float(127.0f))) &
1081 			             SIMD::Int(0xFF)) |
1082 			            ((SIMD::Int(Round(Min(Max(texel.Float(1), SIMD::Float(-1.0f)), SIMD::Float(1.0f)) * SIMD::Float(127.0f))) &
1083 			              SIMD::Int(0xFF))
1084 			             << 8) |
1085 			            ((SIMD::Int(Round(Min(Max(texel.Float(2), SIMD::Float(-1.0f)), SIMD::Float(1.0f)) * SIMD::Float(127.0f))) &
1086 			              SIMD::Int(0xFF))
1087 			             << 16) |
1088 			            ((SIMD::Int(Round(Min(Max(texel.Float(3), SIMD::Float(-1.0f)), SIMD::Float(1.0f)) * SIMD::Float(127.0f))) &
1089 			              SIMD::Int(0xFF))
1090 			             << 24);
1091 			break;
1092 		case spv::ImageFormatRgba8i:
1093 		case spv::ImageFormatRgba8ui:
1094 			texelSize = 4;
1095 			packed[0] = (SIMD::UInt(texel.UInt(0) & SIMD::UInt(0xff))) |
1096 			            (SIMD::UInt(texel.UInt(1) & SIMD::UInt(0xff)) << 8) |
1097 			            (SIMD::UInt(texel.UInt(2) & SIMD::UInt(0xff)) << 16) |
1098 			            (SIMD::UInt(texel.UInt(3) & SIMD::UInt(0xff)) << 24);
1099 			break;
1100 		case spv::ImageFormatRgba16f:
1101 			texelSize = 8;
1102 			packed[0] = floatToHalfBits(texel.UInt(0), false) | floatToHalfBits(texel.UInt(1), true);
1103 			packed[1] = floatToHalfBits(texel.UInt(2), false) | floatToHalfBits(texel.UInt(3), true);
1104 			break;
1105 		case spv::ImageFormatRgba16i:
1106 		case spv::ImageFormatRgba16ui:
1107 			texelSize = 8;
1108 			packed[0] = SIMD::UInt(texel.UInt(0) & SIMD::UInt(0xFFFF)) | (SIMD::UInt(texel.UInt(1) & SIMD::UInt(0xFFFF)) << 16);
1109 			packed[1] = SIMD::UInt(texel.UInt(2) & SIMD::UInt(0xFFFF)) | (SIMD::UInt(texel.UInt(3) & SIMD::UInt(0xFFFF)) << 16);
1110 			break;
1111 		case spv::ImageFormatRg32f:
1112 		case spv::ImageFormatRg32i:
1113 		case spv::ImageFormatRg32ui:
1114 			texelSize = 8;
1115 			packed[0] = texel.Int(0);
1116 			packed[1] = texel.Int(1);
1117 			break;
1118 		case spv::ImageFormatRg16f:
1119 			texelSize = 4;
1120 			packed[0] = floatToHalfBits(texel.UInt(0), false) | floatToHalfBits(texel.UInt(1), true);
1121 			break;
1122 		case spv::ImageFormatRg16i:
1123 		case spv::ImageFormatRg16ui:
1124 			texelSize = 4;
1125 			packed[0] = SIMD::UInt(texel.UInt(0) & SIMD::UInt(0xFFFF)) | (SIMD::UInt(texel.UInt(1) & SIMD::UInt(0xFFFF)) << 16);
1126 			break;
1127 		case spv::ImageFormatR11fG11fB10f:
1128 			texelSize = 4;
1129 			// Truncates instead of rounding. See b/147900455
1130 			packed[0] = ((floatToHalfBits(As<SIMD::UInt>(Max(texel.Float(0), SIMD::Float(0.0f))), false) & SIMD::UInt(0x7FF0)) >> 4) |
1131 			            ((floatToHalfBits(As<SIMD::UInt>(Max(texel.Float(1), SIMD::Float(0.0f))), false) & SIMD::UInt(0x7FF0)) << 7) |
1132 			            ((floatToHalfBits(As<SIMD::UInt>(Max(texel.Float(2), SIMD::Float(0.0f))), false) & SIMD::UInt(0x7FE0)) << 17);
1133 			break;
1134 		case spv::ImageFormatR16f:
1135 			texelSize = 2;
1136 			packed[0] = floatToHalfBits(texel.UInt(0), false);
1137 			break;
1138 		case spv::ImageFormatRgba16:
1139 			texelSize = 8;
1140 			packed[0] = SIMD::UInt(Round(Min(Max(texel.Float(0), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(0xFFFF))) |
1141 			            (SIMD::UInt(Round(Min(Max(texel.Float(1), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(0xFFFF))) << 16);
1142 			packed[1] = SIMD::UInt(Round(Min(Max(texel.Float(2), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(0xFFFF))) |
1143 			            (SIMD::UInt(Round(Min(Max(texel.Float(3), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(0xFFFF))) << 16);
1144 			break;
1145 		case spv::ImageFormatRgb10A2:
1146 			texelSize = 4;
1147 			packed[0] = (SIMD::UInt(Round(Min(Max(texel.Float(0), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(0x3FF)))) |
1148 			            ((SIMD::UInt(Round(Min(Max(texel.Float(1), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(0x3FF)))) << 10) |
1149 			            ((SIMD::UInt(Round(Min(Max(texel.Float(2), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(0x3FF)))) << 20) |
1150 			            ((SIMD::UInt(Round(Min(Max(texel.Float(3), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(0x3)))) << 30);
1151 			break;
1152 		case spv::ImageFormatRg16:
1153 			texelSize = 4;
1154 			packed[0] = SIMD::UInt(Round(Min(Max(texel.Float(0), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(0xFFFF))) |
1155 			            (SIMD::UInt(Round(Min(Max(texel.Float(1), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(0xFFFF))) << 16);
1156 			break;
1157 		case spv::ImageFormatRg8:
1158 			texelSize = 2;
1159 			packed[0] = SIMD::UInt(Round(Min(Max(texel.Float(0), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(0xFF))) |
1160 			            (SIMD::UInt(Round(Min(Max(texel.Float(1), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(0xFF))) << 8);
1161 			break;
1162 		case spv::ImageFormatR16:
1163 			texelSize = 2;
1164 			packed[0] = SIMD::UInt(Round(Min(Max(texel.Float(0), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(0xFFFF)));
1165 			break;
1166 		case spv::ImageFormatR8:
1167 			texelSize = 1;
1168 			packed[0] = SIMD::UInt(Round(Min(Max(texel.Float(0), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(0xFF)));
1169 			break;
1170 		case spv::ImageFormatRgba16Snorm:
1171 			texelSize = 8;
1172 			packed[0] = (SIMD::Int(Round(Min(Max(texel.Float(0), SIMD::Float(-1.0f)), SIMD::Float(1.0f)) * SIMD::Float(0x7FFF))) & SIMD::Int(0xFFFF)) |
1173 			            (SIMD::Int(Round(Min(Max(texel.Float(1), SIMD::Float(-1.0f)), SIMD::Float(1.0f)) * SIMD::Float(0x7FFF))) << 16);
1174 			packed[1] = (SIMD::Int(Round(Min(Max(texel.Float(2), SIMD::Float(-1.0f)), SIMD::Float(1.0f)) * SIMD::Float(0x7FFF))) & SIMD::Int(0xFFFF)) |
1175 			            (SIMD::Int(Round(Min(Max(texel.Float(3), SIMD::Float(-1.0f)), SIMD::Float(1.0f)) * SIMD::Float(0x7FFF))) << 16);
1176 			break;
1177 		case spv::ImageFormatRg16Snorm:
1178 			texelSize = 4;
1179 			packed[0] = (SIMD::Int(Round(Min(Max(texel.Float(0), SIMD::Float(-1.0f)), SIMD::Float(1.0f)) * SIMD::Float(0x7FFF))) & SIMD::Int(0xFFFF)) |
1180 			            (SIMD::Int(Round(Min(Max(texel.Float(1), SIMD::Float(-1.0f)), SIMD::Float(1.0f)) * SIMD::Float(0x7FFF))) << 16);
1181 			break;
1182 		case spv::ImageFormatRg8Snorm:
1183 			texelSize = 2;
1184 			packed[0] = (SIMD::Int(Round(Min(Max(texel.Float(0), SIMD::Float(-1.0f)), SIMD::Float(1.0f)) * SIMD::Float(0x7F))) & SIMD::Int(0xFF)) |
1185 			            (SIMD::Int(Round(Min(Max(texel.Float(1), SIMD::Float(-1.0f)), SIMD::Float(1.0f)) * SIMD::Float(0x7F))) << 8);
1186 			break;
1187 		case spv::ImageFormatR16Snorm:
1188 			texelSize = 2;
1189 			packed[0] = SIMD::Int(Round(Min(Max(texel.Float(0), SIMD::Float(-1.0f)), SIMD::Float(1.0f)) * SIMD::Float(0x7FFF)));
1190 			break;
1191 		case spv::ImageFormatR8Snorm:
1192 			texelSize = 1;
1193 			packed[0] = SIMD::Int(Round(Min(Max(texel.Float(0), SIMD::Float(-1.0f)), SIMD::Float(1.0f)) * SIMD::Float(0x7F)));
1194 			break;
1195 		case spv::ImageFormatRg8i:
1196 		case spv::ImageFormatRg8ui:
1197 			texelSize = 2;
1198 			packed[0] = SIMD::UInt(texel.UInt(0) & SIMD::UInt(0xFF)) | (SIMD::UInt(texel.UInt(1) & SIMD::UInt(0xFF)) << 8);
1199 			break;
1200 		case spv::ImageFormatR16i:
1201 		case spv::ImageFormatR16ui:
1202 			texelSize = 2;
1203 			packed[0] = SIMD::UInt(texel.UInt(0) & SIMD::UInt(0xFFFF));
1204 			break;
1205 		case spv::ImageFormatR8i:
1206 		case spv::ImageFormatR8ui:
1207 			texelSize = 1;
1208 			packed[0] = SIMD::UInt(texel.UInt(0) & SIMD::UInt(0xFF));
1209 			break;
1210 		case spv::ImageFormatRgb10a2ui:
1211 			texelSize = 4;
1212 			packed[0] = (SIMD::UInt(texel.UInt(0) & SIMD::UInt(0x3FF))) |
1213 			            (SIMD::UInt(texel.UInt(1) & SIMD::UInt(0x3FF)) << 10) |
1214 			            (SIMD::UInt(texel.UInt(2) & SIMD::UInt(0x3FF)) << 20) |
1215 			            (SIMD::UInt(texel.UInt(3) & SIMD::UInt(0x3)) << 30);
1216 			break;
1217 		default:
1218 			UNSUPPORTED("spv::ImageFormat %d", int(format));
1219 			break;
1220 	}
1221 
1222 	// "The integer texel coordinates are validated according to the same rules as for texel input coordinate
1223 	//  validation. If the texel fails integer texel coordinate validation, then the write has no effect."
1224 	// - https://www.khronos.org/registry/vulkan/specs/1.2/html/chap16.html#textures-output-coordinate-validation
1225 	auto robustness = OutOfBoundsBehavior::Nullify;
1226 
1227 	auto texelPtr = GetTexelAddress(state, imageBase, imageSizeInBytes, coordinate, imageType, binding, texelSize, sampleId, false, robustness);
1228 
1229 	// Scatter packed texel data.
1230 	// TODO(b/160531165): Provide scatter abstractions for various element sizes.
1231 	if(texelSize == 4 || texelSize == 8 || texelSize == 16)
1232 	{
1233 		for(auto i = 0; i < texelSize / 4; i++)
1234 		{
1235 			texelPtr.Store(packed[i], robustness, state->activeLaneMask());
1236 			texelPtr += sizeof(float);
1237 		}
1238 	}
1239 	else if(texelSize == 2)
1240 	{
1241 		SIMD::Int offsets = texelPtr.offsets();
1242 		SIMD::Int mask = state->activeLaneMask() & texelPtr.isInBounds(2, robustness);
1243 
1244 		for(int i = 0; i < SIMD::Width; i++)
1245 		{
1246 			If(Extract(mask, i) != 0)
1247 			{
1248 				*Pointer<Short>(texelPtr.base + Extract(offsets, i)) = Short(Extract(packed[0], i));
1249 			}
1250 		}
1251 	}
1252 	else if(texelSize == 1)
1253 	{
1254 		SIMD::Int offsets = texelPtr.offsets();
1255 		SIMD::Int mask = state->activeLaneMask() & texelPtr.isInBounds(1, robustness);
1256 
1257 		for(int i = 0; i < SIMD::Width; i++)
1258 		{
1259 			If(Extract(mask, i) != 0)
1260 			{
1261 				*Pointer<Byte>(texelPtr.base + Extract(offsets, i)) = Byte(Extract(packed[0], i));
1262 			}
1263 		}
1264 	}
1265 	else
1266 		UNREACHABLE("texelSize: %d", int(texelSize));
1267 
1268 	return EmitResult::Continue;
1269 }
1270 
EmitImageTexelPointer(InsnIterator insn,EmitState * state) const1271 SpirvShader::EmitResult SpirvShader::EmitImageTexelPointer(InsnIterator insn, EmitState *state) const
1272 {
1273 	auto &resultType = getType(Type::ID(insn.word(1)));
1274 	auto imageId = Object::ID(insn.word(3));
1275 	auto &image = getObject(imageId);
1276 	// Note: OpImageTexelPointer is unusual in that the image is passed by pointer.
1277 	// Look through to get the actual image type.
1278 	auto &imageType = getType(getType(image).element);
1279 	Object::ID resultId = insn.word(2);
1280 
1281 	ASSERT(imageType.opcode() == spv::OpTypeImage);
1282 	ASSERT(resultType.storageClass == spv::StorageClassImage);
1283 	ASSERT(getType(resultType.element).opcode() == spv::OpTypeInt);
1284 
1285 	auto coordinate = Operand(this, state, insn.word(4));
1286 	Object::ID sampleId = insn.word(5);
1287 
1288 	Pointer<Byte> binding = state->getPointer(imageId).base;
1289 	Pointer<Byte> imageBase = *Pointer<Pointer<Byte>>(binding + OFFSET(vk::StorageImageDescriptor, ptr));
1290 	auto imageSizeInBytes = *Pointer<Int>(binding + OFFSET(vk::StorageImageDescriptor, sizeInBytes));
1291 
1292 	// VK_EXT_image_robustness requires checking for out-of-bounds accesses.
1293 	// TODO(b/162327166): Only perform bounds checks when VK_EXT_image_robustness is enabled.
1294 	auto robustness = OutOfBoundsBehavior::Nullify;
1295 
1296 	auto ptr = GetTexelAddress(state, imageBase, imageSizeInBytes, coordinate, imageType, binding, sizeof(uint32_t), sampleId, false, robustness);
1297 
1298 	state->createPointer(resultId, ptr);
1299 
1300 	return EmitResult::Continue;
1301 }
1302 
EmitSampledImageCombineOrSplit(InsnIterator insn,EmitState * state) const1303 SpirvShader::EmitResult SpirvShader::EmitSampledImageCombineOrSplit(InsnIterator insn, EmitState *state) const
1304 {
1305 	// Propagate the image pointer in both cases.
1306 	// Consumers of OpSampledImage will look through to find the sampler pointer.
1307 
1308 	Object::ID resultId = insn.word(2);
1309 	Object::ID imageId = insn.word(3);
1310 
1311 	state->createPointer(resultId, state->getPointer(imageId));
1312 
1313 	return EmitResult::Continue;
1314 }
1315 
1316 }  // namespace sw