blob: daa2a4b273f58afaad0b02f6e55fb5761ec1461a [file] [log] [blame]
Ben Clayton5e51cfc2019-11-28 13:49:29 +00001// 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>
Ben Clayton5e51cfc2019-11-28 13:49:29 +000023
24namespace {
25
26VkFormat SpirvFormatToVulkanFormat(spv::ImageFormat format)
27{
Nicolas Capens81bc9d92019-12-16 15:05:57 -050028 switch(format)
Ben Clayton5e51cfc2019-11-28 13:49:29 +000029 {
Ben Claytonbc1c0672019-12-17 20:37:37 +000030 case spv::ImageFormatRgba32f: return VK_FORMAT_R32G32B32A32_SFLOAT;
Nicolas Capensf6f11212020-07-01 00:27:23 -040031 case spv::ImageFormatRgba16f: return VK_FORMAT_R16G16B16A16_SFLOAT;
Ben Claytonbc1c0672019-12-17 20:37:37 +000032 case spv::ImageFormatR32f: return VK_FORMAT_R32_SFLOAT;
Ben Claytonbc1c0672019-12-17 20:37:37 +000033 case spv::ImageFormatRgba8: return VK_FORMAT_R8G8B8A8_UNORM;
34 case spv::ImageFormatRgba8Snorm: return VK_FORMAT_R8G8B8A8_SNORM;
Ben Claytonbc1c0672019-12-17 20:37:37 +000035 case spv::ImageFormatRg32f: return VK_FORMAT_R32G32_SFLOAT;
Chris Forbes57977c12019-12-19 16:09:18 -080036 case spv::ImageFormatRg16f: return VK_FORMAT_R16G16_SFLOAT;
Nicolas Capensf6f11212020-07-01 00:27:23 -040037 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;
Chris Forbes57977c12019-12-19 16:09:18 -080055 case spv::ImageFormatRg16i: return VK_FORMAT_R16G16_SINT;
Nicolas Capensf6f11212020-07-01 00:27:23 -040056 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;
Chris Forbes57977c12019-12-19 16:09:18 -080065 case spv::ImageFormatRg16ui: return VK_FORMAT_R16G16_UINT;
Nicolas Capensf6f11212020-07-01 00:27:23 -040066 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;
Ben Clayton5e51cfc2019-11-28 13:49:29 +000069
Ben Claytonbc1c0672019-12-17 20:37:37 +000070 default:
Nicolas Capens865f8892020-01-21 14:27:10 -050071 UNSUPPORTED("SPIR-V ImageFormat %u", format);
Ben Claytonbc1c0672019-12-17 20:37:37 +000072 return VK_FORMAT_UNDEFINED;
Ben Clayton5e51cfc2019-11-28 13:49:29 +000073 }
74}
75
76sw::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
Ben Claytonbc1c0672019-12-17 20:37:37 +000083 return rr::As<sw::SIMD::Float>((linear & rr::As<sw::SIMD::Int>(lc)) | (~linear & rr::As<sw::SIMD::Int>(ec))); // TODO: IfThenElse()
Ben Clayton5e51cfc2019-11-28 13:49:29 +000084}
85
Ben Claytonbc1c0672019-12-17 20:37:37 +000086} // anonymous namespace
Ben Clayton5e51cfc2019-11-28 13:49:29 +000087
88namespace sw {
89
90SpirvShader::EmitResult SpirvShader::EmitImageSampleImplicitLod(Variant variant, InsnIterator insn, EmitState *state) const
91{
Ben Claytonbc1c0672019-12-17 20:37:37 +000092 return EmitImageSample({ variant, Implicit }, insn, state);
Ben Clayton5e51cfc2019-11-28 13:49:29 +000093}
94
95SpirvShader::EmitResult SpirvShader::EmitImageGather(Variant variant, InsnIterator insn, EmitState *state) const
96{
Ben Claytonbc1c0672019-12-17 20:37:37 +000097 ImageInstruction instruction = { variant, Gather };
Ben Clayton5e51cfc2019-11-28 13:49:29 +000098 instruction.gatherComponent = !instruction.isDref() ? getObject(insn.word(5)).constantValue[0] : 0;
99
100 return EmitImageSample(instruction, insn, state);
101}
102
103SpirvShader::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 {
Ben Claytonbc1c0672019-12-17 20:37:37 +0000111 return EmitImageSample({ variant, Lod }, insn, state);
Ben Clayton5e51cfc2019-11-28 13:49:29 +0000112 }
113 else if((imageOperands & spv::ImageOperandsGradMask) == imageOperands)
114 {
Ben Claytonbc1c0672019-12-17 20:37:37 +0000115 return EmitImageSample({ variant, Grad }, insn, state);
Ben Clayton5e51cfc2019-11-28 13:49:29 +0000116 }
Ben Claytonbc1c0672019-12-17 20:37:37 +0000117 else
Nicolas Capens865f8892020-01-21 14:27:10 -0500118 UNSUPPORTED("Image Operands %x", imageOperands);
119
Ben Clayton5e51cfc2019-11-28 13:49:29 +0000120 return EmitResult::Continue;
121}
122
123SpirvShader::EmitResult SpirvShader::EmitImageFetch(InsnIterator insn, EmitState *state) const
124{
Ben Claytonbc1c0672019-12-17 20:37:37 +0000125 return EmitImageSample({ None, Fetch }, insn, state);
Ben Clayton5e51cfc2019-11-28 13:49:29 +0000126}
127
128SpirvShader::EmitResult SpirvShader::EmitImageSample(ImageInstruction instruction, InsnIterator insn, EmitState *state) const
129{
Nicolas Capens9b83ddb2020-04-06 15:54:03 -0400130 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
147void SpirvShader::EmitImageSampleUnconditional(Array<SIMD::Float> &out, ImageInstruction instruction, InsnIterator insn, EmitState *state) const
148{
Ben Clayton5e51cfc2019-11-28 13:49:29 +0000149 Object::ID sampledImageId = insn.word(3); // For OpImageFetch this is just an Image, not a SampledImage.
150 Object::ID coordinateId = insn.word(4);
Ben Clayton5e51cfc2019-11-28 13:49:29 +0000151
Ben Claytonbc1c0672019-12-17 20:37:37 +0000152 auto imageDescriptor = state->getPointer(sampledImageId).base; // vk::SampledImageDescriptor*
Ben Clayton5e51cfc2019-11-28 13:49:29 +0000153
154 // If using a separate sampler, look through the OpSampledImage instruction to find the sampler descriptor
155 auto &sampledImage = getObject(sampledImageId);
Ben Claytonbc1c0672019-12-17 20:37:37 +0000156 auto samplerDescriptor = (sampledImage.opcode() == spv::OpSampledImage) ? state->getPointer(sampledImage.definition.word(4)).base : imageDescriptor;
Ben Clayton5e51cfc2019-11-28 13:49:29 +0000157
Nicolas Capense6f65d92020-04-08 21:55:43 -0400158 auto coordinate = Operand(this, state, coordinateId);
Ben Clayton5e51cfc2019-11-28 13:49:29 +0000159
Ben Claytonbc1c0672019-12-17 20:37:37 +0000160 Pointer<Byte> sampler = samplerDescriptor + OFFSET(vk::SampledImageDescriptor, sampler); // vk::Sampler*
161 Pointer<Byte> texture = imageDescriptor + OFFSET(vk::SampledImageDescriptor, texture); // sw::Texture*
Ben Clayton5e51cfc2019-11-28 13:49:29 +0000162
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.
Nicolas Capens72f089c2020-04-08 23:37:08 -0400166 if(getType(sampledImage).opcode() != spv::OpTypeSampledImage)
Ben Clayton5e51cfc2019-11-28 13:49:29 +0000167 {
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 operand %x", imageOperands);
238 }
239 }
240
241 Array<SIMD::Float> in(16); // Maximum 16 input parameter components.
242
Nicolas Capens2f4b6032020-04-09 02:01:50 -0400243 uint32_t coordinates = coordinate.componentCount - instruction.isProj();
Ben Clayton5e51cfc2019-11-28 13:49:29 +0000244 instruction.coordinates = coordinates;
245
246 uint32_t i = 0;
Ben Claytonbc1c0672019-12-17 20:37:37 +0000247 for(; i < coordinates; i++)
Ben Clayton5e51cfc2019-11-28 13:49:29 +0000248 {
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 {
Nicolas Capense6f65d92020-04-08 21:55:43 -0400261 auto drefValue = Operand(this, state, insn.word(5));
Ben Clayton5e51cfc2019-11-28 13:49:29 +0000262
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 {
Nicolas Capense6f65d92020-04-08 21:55:43 -0400277 auto lodValue = Operand(this, state, lodOrBiasId);
Ben Clayton5e51cfc2019-11-28 13:49:29 +0000278 in[i] = lodValue.Float(0);
279 i++;
280 }
281 else if(grad)
282 {
Nicolas Capense6f65d92020-04-08 21:55:43 -0400283 auto dxValue = Operand(this, state, gradDxId);
284 auto dyValue = Operand(this, state, gradDyId);
Nicolas Capens2f4b6032020-04-09 02:01:50 -0400285 ASSERT(dxValue.componentCount == dxValue.componentCount);
Ben Clayton5e51cfc2019-11-28 13:49:29 +0000286
Nicolas Capens2f4b6032020-04-09 02:01:50 -0400287 instruction.grad = dxValue.componentCount;
Ben Clayton5e51cfc2019-11-28 13:49:29 +0000288
Nicolas Capens2f4b6032020-04-09 02:01:50 -0400289 for(uint32_t j = 0; j < dxValue.componentCount; j++, i++)
Ben Clayton5e51cfc2019-11-28 13:49:29 +0000290 {
291 in[i] = dxValue.Float(j);
292 }
293
Nicolas Capens2f4b6032020-04-09 02:01:50 -0400294 for(uint32_t j = 0; j < dxValue.componentCount; j++, i++)
Ben Clayton5e51cfc2019-11-28 13:49:29 +0000295 {
296 in[i] = dyValue.Float(j);
297 }
298 }
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500299 else if(instruction.samplerMethod == Fetch)
Ben Clayton5e51cfc2019-11-28 13:49:29 +0000300 {
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 {
Nicolas Capense6f65d92020-04-08 21:55:43 -0400310 auto offsetValue = Operand(this, state, offsetId);
Nicolas Capens2f4b6032020-04-09 02:01:50 -0400311 instruction.offset = offsetValue.componentCount;
Ben Clayton5e51cfc2019-11-28 13:49:29 +0000312
Nicolas Capens2f4b6032020-04-09 02:01:50 -0400313 for(uint32_t j = 0; j < offsetValue.componentCount; j++, i++)
Ben Clayton5e51cfc2019-11-28 13:49:29 +0000314 {
315 in[i] = As<SIMD::Float>(offsetValue.Int(j)); // Integer values, but transfered as float.
316 }
317 }
318
319 if(sample)
320 {
Nicolas Capense6f65d92020-04-08 21:55:43 -0400321 auto sampleValue = Operand(this, state, sampleId);
Ben Clayton5e51cfc2019-11-28 13:49:29 +0000322 in[i] = As<SIMD::Float>(sampleValue.Int(0));
323 }
324
Nicolas Capens71186752020-04-09 01:05:31 -0400325 auto cacheIt = state->routine->samplerCache.find(insn.resultId());
Ben Clayton5e51cfc2019-11-28 13:49:29 +0000326 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
Nicolas Capens6c11cf22020-03-19 15:21:13 -0400337 Call<ImageSampler>(cache.function, texture, &in[0], &out[0], state->routine->constants);
Ben Clayton5e51cfc2019-11-28 13:49:29 +0000338}
339
340SpirvShader::EmitResult SpirvShader::EmitImageQuerySizeLod(InsnIterator insn, EmitState *state) const
341{
Nicolas Capens71186752020-04-09 01:05:31 -0400342 auto &resultTy = getType(Type::ID(insn.resultTypeId()));
Ben Clayton5e51cfc2019-11-28 13:49:29 +0000343 auto imageId = Object::ID(insn.word(3));
344 auto lodId = Object::ID(insn.word(4));
345
Nicolas Capensff9f9b52020-04-14 00:46:38 -0400346 auto &dst = state->createIntermediate(insn.resultId(), resultTy.componentCount);
Ben Clayton5e51cfc2019-11-28 13:49:29 +0000347 GetImageDimensions(state, resultTy, imageId, lodId, dst);
348
349 return EmitResult::Continue;
350}
351
352SpirvShader::EmitResult SpirvShader::EmitImageQuerySize(InsnIterator insn, EmitState *state) const
353{
Nicolas Capens71186752020-04-09 01:05:31 -0400354 auto &resultTy = getType(Type::ID(insn.resultTypeId()));
Ben Clayton5e51cfc2019-11-28 13:49:29 +0000355 auto imageId = Object::ID(insn.word(3));
356 auto lodId = Object::ID(0);
357
Nicolas Capensff9f9b52020-04-14 00:46:38 -0400358 auto &dst = state->createIntermediate(insn.resultId(), resultTy.componentCount);
Ben Clayton5e51cfc2019-11-28 13:49:29 +0000359 GetImageDimensions(state, resultTy, imageId, lodId, dst);
360
361 return EmitResult::Continue;
362}
363
364SpirvShader::EmitResult SpirvShader::EmitImageQueryLod(InsnIterator insn, EmitState *state) const
365{
Ben Claytonbc1c0672019-12-17 20:37:37 +0000366 return EmitImageSample({ None, Query }, insn, state);
Ben Clayton5e51cfc2019-11-28 13:49:29 +0000367}
368
369void 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);
Nicolas Capens72f089c2020-04-08 23:37:08 -0400373 auto &imageType = getType(image);
Ben Clayton5e51cfc2019-11-28 13:49:29 +0000374
375 ASSERT(imageType.definition.opcode() == spv::OpTypeImage);
376 bool isArrayed = imageType.definition.word(5) != 0;
377 bool isCubeMap = imageType.definition.word(3) == spv::DimCube;
378
379 const DescriptorDecorations &d = descriptorDecorations.at(imageId);
Nicolas Capensc7d5ec32020-04-22 01:11:37 -0400380 auto descriptorType = routine->pipelineLayout->getDescriptorType(d.DescriptorSet, d.Binding);
Ben Clayton5e51cfc2019-11-28 13:49:29 +0000381
382 Pointer<Byte> descriptor = state->getPointer(imageId).base;
383
384 Pointer<Int> extent;
385 Int arrayLayers;
386
Nicolas Capens93613e12020-04-16 00:05:28 -0400387 switch(descriptorType)
Ben Clayton5e51cfc2019-11-28 13:49:29 +0000388 {
Ben Claytonbc1c0672019-12-17 20:37:37 +0000389 case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
390 case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
391 {
392 extent = descriptor + OFFSET(vk::StorageImageDescriptor, extent); // int[3]*
393 arrayLayers = *Pointer<Int>(descriptor + OFFSET(vk::StorageImageDescriptor, arrayLayers)); // uint32_t
394 break;
395 }
396 case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
397 case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
398 case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
399 {
400 extent = descriptor + OFFSET(vk::SampledImageDescriptor, extent); // int[3]*
401 arrayLayers = *Pointer<Int>(descriptor + OFFSET(vk::SampledImageDescriptor, arrayLayers)); // uint32_t
402 break;
403 }
404 default:
Nicolas Capens93613e12020-04-16 00:05:28 -0400405 UNREACHABLE("Image descriptorType: %d", int(descriptorType));
Ben Clayton5e51cfc2019-11-28 13:49:29 +0000406 }
407
Nicolas Capensff9f9b52020-04-14 00:46:38 -0400408 auto dimensions = resultTy.componentCount - (isArrayed ? 1 : 0);
Ben Clayton5e51cfc2019-11-28 13:49:29 +0000409 std::vector<Int> out;
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500410 if(lodId != 0)
Ben Clayton5e51cfc2019-11-28 13:49:29 +0000411 {
Nicolas Capense6f65d92020-04-08 21:55:43 -0400412 auto lodVal = Operand(this, state, lodId);
Nicolas Capens2f4b6032020-04-09 02:01:50 -0400413 ASSERT(lodVal.componentCount == 1);
Ben Clayton5e51cfc2019-11-28 13:49:29 +0000414 auto lod = lodVal.Int(0);
415 auto one = SIMD::Int(1);
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500416 for(uint32_t i = 0; i < dimensions; i++)
Ben Clayton5e51cfc2019-11-28 13:49:29 +0000417 {
418 dst.move(i, Max(SIMD::Int(extent[i]) >> lod, one));
419 }
420 }
421 else
422 {
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500423 for(uint32_t i = 0; i < dimensions; i++)
Ben Clayton5e51cfc2019-11-28 13:49:29 +0000424 {
425 dst.move(i, SIMD::Int(extent[i]));
426 }
427 }
428
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500429 if(isArrayed)
Ben Clayton5e51cfc2019-11-28 13:49:29 +0000430 {
431 auto numElements = isCubeMap ? (arrayLayers / 6) : RValue<Int>(arrayLayers);
432 dst.move(dimensions, SIMD::Int(numElements));
433 }
434}
435
436SpirvShader::EmitResult SpirvShader::EmitImageQueryLevels(InsnIterator insn, EmitState *state) const
437{
Nicolas Capens71186752020-04-09 01:05:31 -0400438 auto &resultTy = getType(Type::ID(insn.resultTypeId()));
Nicolas Capensff9f9b52020-04-14 00:46:38 -0400439 ASSERT(resultTy.componentCount == 1);
Ben Clayton5e51cfc2019-11-28 13:49:29 +0000440 auto imageId = Object::ID(insn.word(3));
441
442 const DescriptorDecorations &d = descriptorDecorations.at(imageId);
Nicolas Capensc7d5ec32020-04-22 01:11:37 -0400443 auto descriptorType = state->routine->pipelineLayout->getDescriptorType(d.DescriptorSet, d.Binding);
Ben Clayton5e51cfc2019-11-28 13:49:29 +0000444
445 Pointer<Byte> descriptor = state->getPointer(imageId).base;
446 Int mipLevels = 0;
Nicolas Capens93613e12020-04-16 00:05:28 -0400447 switch(descriptorType)
Ben Clayton5e51cfc2019-11-28 13:49:29 +0000448 {
Ben Claytonbc1c0672019-12-17 20:37:37 +0000449 case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
450 case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
451 case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
452 mipLevels = *Pointer<Int>(descriptor + OFFSET(vk::SampledImageDescriptor, mipLevels)); // uint32_t
453 break;
454 default:
Nicolas Capens93613e12020-04-16 00:05:28 -0400455 UNREACHABLE("Image descriptorType: %d", int(descriptorType));
Ben Clayton5e51cfc2019-11-28 13:49:29 +0000456 }
457
Nicolas Capens71186752020-04-09 01:05:31 -0400458 auto &dst = state->createIntermediate(insn.resultId(), 1);
Ben Clayton5e51cfc2019-11-28 13:49:29 +0000459 dst.move(0, SIMD::Int(mipLevels));
460
461 return EmitResult::Continue;
462}
463
464SpirvShader::EmitResult SpirvShader::EmitImageQuerySamples(InsnIterator insn, EmitState *state) const
465{
Nicolas Capens71186752020-04-09 01:05:31 -0400466 auto &resultTy = getType(Type::ID(insn.resultTypeId()));
Nicolas Capensff9f9b52020-04-14 00:46:38 -0400467 ASSERT(resultTy.componentCount == 1);
Ben Clayton5e51cfc2019-11-28 13:49:29 +0000468 auto imageId = Object::ID(insn.word(3));
Nicolas Capens72f089c2020-04-08 23:37:08 -0400469 auto imageTy = getType(getObject(imageId));
Ben Clayton5e51cfc2019-11-28 13:49:29 +0000470 ASSERT(imageTy.definition.opcode() == spv::OpTypeImage);
471 ASSERT(imageTy.definition.word(3) == spv::Dim2D);
472 ASSERT(imageTy.definition.word(6 /* MS */) == 1);
473
474 const DescriptorDecorations &d = descriptorDecorations.at(imageId);
Nicolas Capensc7d5ec32020-04-22 01:11:37 -0400475 auto descriptorType = state->routine->pipelineLayout->getDescriptorType(d.DescriptorSet, d.Binding);
Ben Clayton5e51cfc2019-11-28 13:49:29 +0000476
477 Pointer<Byte> descriptor = state->getPointer(imageId).base;
478 Int sampleCount = 0;
Nicolas Capens93613e12020-04-16 00:05:28 -0400479 switch(descriptorType)
Ben Clayton5e51cfc2019-11-28 13:49:29 +0000480 {
Ben Claytonbc1c0672019-12-17 20:37:37 +0000481 case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
482 sampleCount = *Pointer<Int>(descriptor + OFFSET(vk::StorageImageDescriptor, sampleCount)); // uint32_t
483 break;
484 case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
485 case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
486 case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
487 sampleCount = *Pointer<Int>(descriptor + OFFSET(vk::SampledImageDescriptor, sampleCount)); // uint32_t
488 break;
489 default:
Nicolas Capens93613e12020-04-16 00:05:28 -0400490 UNREACHABLE("Image descriptorType: %d", int(descriptorType));
Ben Clayton5e51cfc2019-11-28 13:49:29 +0000491 }
492
Nicolas Capens71186752020-04-09 01:05:31 -0400493 auto &dst = state->createIntermediate(insn.resultId(), 1);
Ben Clayton5e51cfc2019-11-28 13:49:29 +0000494 dst.move(0, SIMD::Int(sampleCount));
495
496 return EmitResult::Continue;
497}
498
Nicolas Capens4a65df12020-05-07 10:06:46 -0400499SIMD::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
Ben Clayton5e51cfc2019-11-28 13:49:29 +0000500{
501 auto routine = state->routine;
502 bool isArrayed = imageType.definition.word(5) != 0;
503 auto dim = static_cast<spv::Dim>(imageType.definition.word(3));
Nicolas Capens2f4b6032020-04-09 02:01:50 -0400504 int dims = coordinate.componentCount - (isArrayed ? 1 : 0);
Ben Clayton5e51cfc2019-11-28 13:49:29 +0000505
506 SIMD::Int u = coordinate.Int(0);
507 SIMD::Int v = SIMD::Int(0);
508
Nicolas Capens2f4b6032020-04-09 02:01:50 -0400509 if(coordinate.componentCount > 1)
Ben Clayton5e51cfc2019-11-28 13:49:29 +0000510 {
511 v = coordinate.Int(1);
512 }
513
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500514 if(dim == spv::DimSubpassData)
Ben Clayton5e51cfc2019-11-28 13:49:29 +0000515 {
516 u += routine->windowSpacePosition[0];
517 v += routine->windowSpacePosition[1];
518 }
519
520 auto rowPitch = SIMD::Int(*Pointer<Int>(descriptor + (useStencilAspect
Ben Claytonbc1c0672019-12-17 20:37:37 +0000521 ? OFFSET(vk::StorageImageDescriptor, stencilRowPitchBytes)
522 : OFFSET(vk::StorageImageDescriptor, rowPitchBytes))));
Ben Clayton5e51cfc2019-11-28 13:49:29 +0000523 auto slicePitch = SIMD::Int(
Ben Claytonbc1c0672019-12-17 20:37:37 +0000524 *Pointer<Int>(descriptor + (useStencilAspect
525 ? OFFSET(vk::StorageImageDescriptor, stencilSlicePitchBytes)
526 : OFFSET(vk::StorageImageDescriptor, slicePitchBytes))));
Ben Clayton5e51cfc2019-11-28 13:49:29 +0000527 auto samplePitch = SIMD::Int(
Ben Claytonbc1c0672019-12-17 20:37:37 +0000528 *Pointer<Int>(descriptor + (useStencilAspect
529 ? OFFSET(vk::StorageImageDescriptor, stencilSamplePitchBytes)
530 : OFFSET(vk::StorageImageDescriptor, samplePitchBytes))));
Ben Clayton5e51cfc2019-11-28 13:49:29 +0000531
Nicolas Capens974cfa92020-05-12 17:19:45 -0400532 SIMD::Int ptrOffset = u * SIMD::Int(texelSize);
Alexis Hetu60727de2020-04-15 15:26:14 -0400533
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500534 if(dims > 1)
Ben Clayton5e51cfc2019-11-28 13:49:29 +0000535 {
Alexis Hetu60727de2020-04-15 15:26:14 -0400536 ptrOffset += v * rowPitch;
Ben Clayton5e51cfc2019-11-28 13:49:29 +0000537 }
Nicolas Capens974cfa92020-05-12 17:19:45 -0400538
539 SIMD::Int w = 0;
Alexis Hetu60727de2020-04-15 15:26:14 -0400540 if((dims > 2) || isArrayed)
Ben Clayton5e51cfc2019-11-28 13:49:29 +0000541 {
Alexis Hetu60727de2020-04-15 15:26:14 -0400542 if(dims > 2)
543 {
544 w += coordinate.Int(2);
545 }
Nicolas Capens974cfa92020-05-12 17:19:45 -0400546
Alexis Hetu60727de2020-04-15 15:26:14 -0400547 if(isArrayed)
548 {
549 w += coordinate.Int(dims);
550 }
Nicolas Capens974cfa92020-05-12 17:19:45 -0400551
Alexis Hetu60727de2020-04-15 15:26:14 -0400552 ptrOffset += w * slicePitch;
Ben Clayton5e51cfc2019-11-28 13:49:29 +0000553 }
554
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500555 if(dim == spv::DimSubpassData)
Ben Clayton5e51cfc2019-11-28 13:49:29 +0000556 {
557 // Multiview input attachment access is to the layer corresponding to the current view
Alexis Hetu60727de2020-04-15 15:26:14 -0400558 ptrOffset += SIMD::Int(routine->viewID) * slicePitch;
Ben Clayton5e51cfc2019-11-28 13:49:29 +0000559 }
560
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500561 if(sampleId.value())
Ben Clayton5e51cfc2019-11-28 13:49:29 +0000562 {
Nicolas Capense6f65d92020-04-08 21:55:43 -0400563 Operand sample(this, state, sampleId);
Alexis Hetu60727de2020-04-15 15:26:14 -0400564 ptrOffset += sample.Int(0) * samplePitch;
Ben Clayton5e51cfc2019-11-28 13:49:29 +0000565 }
566
Nicolas Capens974cfa92020-05-12 17:19:45 -0400567 // If the out-of-bounds behavior is set to nullify, then each coordinate must be tested individually.
568 // Other out-of-bounds behaviors work properly by just comparing the offset against the total size.
569 if(outOfBoundsBehavior == OutOfBoundsBehavior::Nullify)
Alexis Hetu60727de2020-04-15 15:26:14 -0400570 {
Nicolas Capens974cfa92020-05-12 17:19:45 -0400571 auto width = SIMD::UInt(*Pointer<UInt>(descriptor + OFFSET(vk::StorageImageDescriptor, extent.width)));
572 SIMD::Int oobMask = As<SIMD::Int>(CmpNLT(As<SIMD::UInt>(u), width));
573
574 if(dims > 1)
575 {
576 auto height = SIMD::UInt(*Pointer<UInt>(descriptor + OFFSET(vk::StorageImageDescriptor, extent.height)));
577 oobMask |= As<SIMD::Int>(CmpNLT(As<SIMD::UInt>(v), height));
578 }
579
580 if((dims > 2) || isArrayed)
581 {
582 auto depth = *Pointer<UInt>(descriptor + OFFSET(vk::StorageImageDescriptor, extent.depth));
583 auto arrayLayers = *Pointer<UInt>(descriptor + OFFSET(vk::StorageImageDescriptor, arrayLayers));
584 oobMask |= As<SIMD::Int>(CmpNLT(As<SIMD::UInt>(w), SIMD::UInt(depth * arrayLayers)));
585 }
586
Nicolas Capens4a65df12020-05-07 10:06:46 -0400587 constexpr int32_t OOB_OFFSET = 0x7FFFFFFF - 16; // SIMD pointer offsets are signed 32-bit, so this is the largest offset (for 16-byte texels).
588 static_assert(OOB_OFFSET >= MAX_MEMORY_ALLOCATION_SIZE, "the largest offset must be guaranteed to be out-of-bounds");
589
590 ptrOffset = (ptrOffset & ~oobMask) | (oobMask & SIMD::Int(OOB_OFFSET)); // oob ? OOB_OFFSET : ptrOffset // TODO: IfThenElse()
Alexis Hetu60727de2020-04-15 15:26:14 -0400591 }
592
Nicolas Capens4a65df12020-05-07 10:06:46 -0400593 return SIMD::Pointer(imageBase, imageSizeInBytes, ptrOffset);
Ben Clayton5e51cfc2019-11-28 13:49:29 +0000594}
595
596SpirvShader::EmitResult SpirvShader::EmitImageRead(InsnIterator insn, EmitState *state) const
597{
598 auto &resultType = getType(Type::ID(insn.word(1)));
599 auto imageId = Object::ID(insn.word(3));
600 auto &image = getObject(imageId);
Nicolas Capens72f089c2020-04-08 23:37:08 -0400601 auto &imageType = getType(image);
Ben Clayton5e51cfc2019-11-28 13:49:29 +0000602
603 Object::ID sampleId = 0;
604
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500605 if(insn.wordCount() > 5)
Ben Clayton5e51cfc2019-11-28 13:49:29 +0000606 {
607 int operand = 6;
608 auto imageOperands = insn.word(5);
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500609 if(imageOperands & spv::ImageOperandsSampleMask)
Ben Clayton5e51cfc2019-11-28 13:49:29 +0000610 {
611 sampleId = insn.word(operand++);
612 imageOperands &= ~spv::ImageOperandsSampleMask;
613 }
614
615 // Should be no remaining image operands.
616 ASSERT(!imageOperands);
617 }
618
619 ASSERT(imageType.definition.opcode() == spv::OpTypeImage);
620 auto dim = static_cast<spv::Dim>(imageType.definition.word(3));
621
Nicolas Capense6f65d92020-04-08 21:55:43 -0400622 auto coordinate = Operand(this, state, insn.word(4));
Ben Clayton5e51cfc2019-11-28 13:49:29 +0000623 const DescriptorDecorations &d = descriptorDecorations.at(imageId);
624
625 // For subpass data, format in the instruction is spv::ImageFormatUnknown. Get it from
626 // the renderpass data instead. In all other cases, we can use the format in the instruction.
627 auto vkFormat = (dim == spv::DimSubpassData)
Ben Claytonbc1c0672019-12-17 20:37:37 +0000628 ? inputAttachmentFormats[d.InputAttachmentIndex]
629 : SpirvFormatToVulkanFormat(static_cast<spv::ImageFormat>(imageType.definition.word(8)));
Ben Clayton5e51cfc2019-11-28 13:49:29 +0000630
631 // Depth+Stencil image attachments select aspect based on the Sampled Type of the
632 // OpTypeImage. If float, then we want the depth aspect. If int, we want the stencil aspect.
633 auto useStencilAspect = (vkFormat == VK_FORMAT_D32_SFLOAT_S8_UINT &&
Ben Claytonbc1c0672019-12-17 20:37:37 +0000634 getType(imageType.definition.word(2)).opcode() == spv::OpTypeInt);
Ben Clayton5e51cfc2019-11-28 13:49:29 +0000635
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500636 if(useStencilAspect)
Ben Clayton5e51cfc2019-11-28 13:49:29 +0000637 {
638 vkFormat = VK_FORMAT_S8_UINT;
639 }
640
641 auto pointer = state->getPointer(imageId);
642 Pointer<Byte> binding = pointer.base;
643 Pointer<Byte> imageBase = *Pointer<Pointer<Byte>>(binding + (useStencilAspect
Ben Claytonbc1c0672019-12-17 20:37:37 +0000644 ? OFFSET(vk::StorageImageDescriptor, stencilPtr)
645 : OFFSET(vk::StorageImageDescriptor, ptr)));
Ben Clayton5e51cfc2019-11-28 13:49:29 +0000646
647 auto imageSizeInBytes = *Pointer<Int>(binding + OFFSET(vk::StorageImageDescriptor, sizeInBytes));
648
Nicolas Capensff9f9b52020-04-14 00:46:38 -0400649 auto &dst = state->createIntermediate(insn.resultId(), resultType.componentCount);
Ben Clayton5e51cfc2019-11-28 13:49:29 +0000650
Ben Clayton5e51cfc2019-11-28 13:49:29 +0000651 // "The value returned by a read of an invalid texel is undefined,
652 // unless that read operation is from a buffer resource and the robustBufferAccess feature is enabled."
653 // TODO: Don't always assume a buffer resource.
Alexis Hetu60727de2020-04-15 15:26:14 -0400654 //
655 // While we could be using OutOfBoundsBehavior::RobustBufferAccess for read operations from buffer resources,
656 // emulating the glsl function loadImage() requires that this function returns 0 when used with out of bounds
657 // coordinates, so we have to use OutOfBoundsBehavior::Nullify in that case.
Nicolas Capensf6f11212020-07-01 00:27:23 -0400658 // TODO(b/159329067): Claim VK_EXT_image_robustness
Alexis Hetu60727de2020-04-15 15:26:14 -0400659 auto robustness = OutOfBoundsBehavior::Nullify;
660
661 auto texelSize = vk::Format(vkFormat).bytes();
Nicolas Capens4a65df12020-05-07 10:06:46 -0400662 auto texelPtr = GetTexelAddress(state, imageBase, imageSizeInBytes, coordinate, imageType, binding, texelSize, sampleId, useStencilAspect, robustness);
Ben Clayton5e51cfc2019-11-28 13:49:29 +0000663
Nicolas Capens8d75c102020-07-05 23:08:13 -0400664 // Gather packed texel data. Texels larger than 4 bytes occupy multiple SIMD::Int elements.
665 // TODO(b/160531165): Provide gather abstractions for various element sizes.
Ben Clayton5e51cfc2019-11-28 13:49:29 +0000666 SIMD::Int packed[4];
Nicolas Capens8d75c102020-07-05 23:08:13 -0400667 if(texelSize == 4 || texelSize == 8 || texelSize == 16)
Ben Clayton5e51cfc2019-11-28 13:49:29 +0000668 {
Nicolas Capens8d75c102020-07-05 23:08:13 -0400669 for(auto i = 0; i < texelSize / 4; i++)
670 {
671 packed[i] = texelPtr.Load<SIMD::Int>(robustness, state->activeLaneMask());
672 texelPtr += sizeof(float);
673 }
Ben Clayton5e51cfc2019-11-28 13:49:29 +0000674 }
Nicolas Capens8d75c102020-07-05 23:08:13 -0400675 else if(texelSize == 2)
676 {
677 SIMD::Int offsets = texelPtr.offsets();
678 SIMD::Int mask = state->activeLaneMask() & texelPtr.isInBounds(2, robustness);
679
680 for(int i = 0; i < SIMD::Width; i++)
681 {
682 If(Extract(mask, i) != 0)
683 {
684 packed[0] = Insert(packed[0], Int(*Pointer<Short>(texelPtr.base + Extract(offsets, i))), i);
685 }
686 }
687 }
688 else if(texelSize == 1)
689 {
690 SIMD::Int offsets = texelPtr.offsets();
691 SIMD::Int mask = state->activeLaneMask() & texelPtr.isInBounds(1, robustness);
692
693 for(int i = 0; i < SIMD::Width; i++)
694 {
695 If(Extract(mask, i) != 0)
696 {
697 packed[0] = Insert(packed[0], Int(*Pointer<Byte>(texelPtr.base + Extract(offsets, i))), i);
698 }
699 }
700 }
701 else
702 UNREACHABLE("texelSize: %d", int(texelSize));
Ben Clayton5e51cfc2019-11-28 13:49:29 +0000703
704 // Format support requirements here come from two sources:
705 // - Minimum required set of formats for loads from storage images
706 // - Any format supported as a color or depth/stencil attachment, for input attachments
707 switch(vkFormat)
708 {
Ben Claytonbc1c0672019-12-17 20:37:37 +0000709 case VK_FORMAT_R32G32B32A32_SFLOAT:
710 case VK_FORMAT_R32G32B32A32_SINT:
711 case VK_FORMAT_R32G32B32A32_UINT:
712 dst.move(0, packed[0]);
713 dst.move(1, packed[1]);
714 dst.move(2, packed[2]);
715 dst.move(3, packed[3]);
716 break;
717 case VK_FORMAT_R32_SINT:
718 case VK_FORMAT_R32_UINT:
719 dst.move(0, packed[0]);
720 // Fill remaining channels with 0,0,1 (of the correct type)
721 dst.move(1, SIMD::Int(0));
722 dst.move(2, SIMD::Int(0));
723 dst.move(3, SIMD::Int(1));
724 break;
725 case VK_FORMAT_R32_SFLOAT:
726 case VK_FORMAT_D32_SFLOAT:
727 case VK_FORMAT_D32_SFLOAT_S8_UINT:
728 dst.move(0, packed[0]);
729 // Fill remaining channels with 0,0,1 (of the correct type)
Nicolas Capens7bc71202020-06-24 02:21:47 -0400730 dst.move(1, SIMD::Float(0.0f));
731 dst.move(2, SIMD::Float(0.0f));
732 dst.move(3, SIMD::Float(1.0f));
Ben Claytonbc1c0672019-12-17 20:37:37 +0000733 break;
734 case VK_FORMAT_D16_UNORM:
Nicolas Capens7bc71202020-06-24 02:21:47 -0400735 dst.move(0, SIMD::Float(packed[0] & SIMD::Int(0xFFFF)) * SIMD::Float(1.0f / 0xFFFF));
736 dst.move(1, SIMD::Float(0.0f));
737 dst.move(2, SIMD::Float(0.0f));
738 dst.move(3, SIMD::Float(1.0f));
Ben Claytonbc1c0672019-12-17 20:37:37 +0000739 break;
Nicolas Capensf6f11212020-07-01 00:27:23 -0400740 case VK_FORMAT_R16G16B16A16_UNORM:
741 dst.move(0, SIMD::Float(packed[0] & SIMD::Int(0xFFFF)) * SIMD::Float(1.0f / 0xFFFF));
742 dst.move(1, SIMD::Float((packed[0] >> 16) & SIMD::Int(0xFFFF)) * SIMD::Float(1.0f / 0xFFFF));
743 dst.move(2, SIMD::Float(packed[1] & SIMD::Int(0xFFFF)) * SIMD::Float(1.0f / 0xFFFF));
744 dst.move(3, SIMD::Float((packed[1] >> 16) & SIMD::Int(0xFFFF)) * SIMD::Float(1.0f / 0xFFFF));
745 break;
746 case VK_FORMAT_R16G16B16A16_SNORM:
747 dst.move(0, Max(SIMD::Float((packed[0] << 16) & SIMD::Int(0xFFFF0000)) * SIMD::Float(1.0f / 0x7FFF0000), SIMD::Float(-1.0f)));
748 dst.move(1, Max(SIMD::Float(packed[0] & SIMD::Int(0xFFFF0000)) * SIMD::Float(1.0f / 0x7FFF0000), SIMD::Float(-1.0f)));
749 dst.move(2, Max(SIMD::Float((packed[1] << 16) & SIMD::Int(0xFFFF0000)) * SIMD::Float(1.0f / 0x7FFF0000), SIMD::Float(-1.0f)));
750 dst.move(3, Max(SIMD::Float(packed[1] & SIMD::Int(0xFFFF0000)) * SIMD::Float(1.0f / 0x7FFF0000), SIMD::Float(-1.0f)));
751 break;
Ben Claytonbc1c0672019-12-17 20:37:37 +0000752 case VK_FORMAT_R16G16B16A16_SINT:
753 dst.move(0, (packed[0] << 16) >> 16);
Nicolas Capens7bc71202020-06-24 02:21:47 -0400754 dst.move(1, packed[0] >> 16);
Ben Claytonbc1c0672019-12-17 20:37:37 +0000755 dst.move(2, (packed[1] << 16) >> 16);
Nicolas Capens7bc71202020-06-24 02:21:47 -0400756 dst.move(3, packed[1] >> 16);
Ben Claytonbc1c0672019-12-17 20:37:37 +0000757 break;
758 case VK_FORMAT_R16G16B16A16_UINT:
Nicolas Capens7bc71202020-06-24 02:21:47 -0400759 dst.move(0, packed[0] & SIMD::Int(0xFFFF));
760 dst.move(1, (packed[0] >> 16) & SIMD::Int(0xFFFF));
761 dst.move(2, packed[1] & SIMD::Int(0xFFFF));
762 dst.move(3, (packed[1] >> 16) & SIMD::Int(0xFFFF));
Ben Claytonbc1c0672019-12-17 20:37:37 +0000763 break;
764 case VK_FORMAT_R16G16B16A16_SFLOAT:
765 dst.move(0, halfToFloatBits(As<SIMD::UInt>(packed[0]) & SIMD::UInt(0x0000FFFF)));
766 dst.move(1, halfToFloatBits((As<SIMD::UInt>(packed[0]) & SIMD::UInt(0xFFFF0000)) >> 16));
767 dst.move(2, halfToFloatBits(As<SIMD::UInt>(packed[1]) & SIMD::UInt(0x0000FFFF)));
768 dst.move(3, halfToFloatBits((As<SIMD::UInt>(packed[1]) & SIMD::UInt(0xFFFF0000)) >> 16));
769 break;
770 case VK_FORMAT_R8G8B8A8_SNORM:
Nicolas Capensc9a291a2020-06-24 02:06:17 -0400771 case VK_FORMAT_A8B8G8R8_SNORM_PACK32:
Nicolas Capens7bc71202020-06-24 02:21:47 -0400772 dst.move(0, Max(SIMD::Float((packed[0] << 24) & SIMD::Int(0xFF000000)) * SIMD::Float(1.0f / 0x7F000000), SIMD::Float(-1.0f)));
773 dst.move(1, Max(SIMD::Float((packed[0] << 16) & SIMD::Int(0xFF000000)) * SIMD::Float(1.0f / 0x7F000000), SIMD::Float(-1.0f)));
774 dst.move(2, Max(SIMD::Float((packed[0] << 8) & SIMD::Int(0xFF000000)) * SIMD::Float(1.0f / 0x7F000000), SIMD::Float(-1.0f)));
775 dst.move(3, Max(SIMD::Float((packed[0]) & SIMD::Int(0xFF000000)) * SIMD::Float(1.0f / 0x7F000000), SIMD::Float(-1.0f)));
Ben Claytonbc1c0672019-12-17 20:37:37 +0000776 break;
777 case VK_FORMAT_R8G8B8A8_UNORM:
778 case VK_FORMAT_A8B8G8R8_UNORM_PACK32:
Nicolas Capens7bc71202020-06-24 02:21:47 -0400779 dst.move(0, SIMD::Float(packed[0] & SIMD::Int(0xFF)) * SIMD::Float(1.0f / 0xFF));
780 dst.move(1, SIMD::Float((packed[0] >> 8) & SIMD::Int(0xFF)) * SIMD::Float(1.0f / 0xFF));
781 dst.move(2, SIMD::Float((packed[0] >> 16) & SIMD::Int(0xFF)) * SIMD::Float(1.0f / 0xFF));
782 dst.move(3, SIMD::Float((packed[0] >> 24) & SIMD::Int(0xFF)) * SIMD::Float(1.0f / 0xFF));
Ben Claytonbc1c0672019-12-17 20:37:37 +0000783 break;
784 case VK_FORMAT_R8G8B8A8_SRGB:
785 case VK_FORMAT_A8B8G8R8_SRGB_PACK32:
Nicolas Capens7bc71202020-06-24 02:21:47 -0400786 dst.move(0, ::sRGBtoLinear(SIMD::Float(packed[0] & SIMD::Int(0xFF)) * SIMD::Float(1.0f / 0xFF)));
787 dst.move(1, ::sRGBtoLinear(SIMD::Float((packed[0] >> 8) & SIMD::Int(0xFF)) * SIMD::Float(1.0f / 0xFF)));
788 dst.move(2, ::sRGBtoLinear(SIMD::Float((packed[0] >> 16) & SIMD::Int(0xFF)) * SIMD::Float(1.0f / 0xFF)));
789 dst.move(3, SIMD::Float((packed[0] >> 24) & SIMD::Int(0xFF)) * SIMD::Float(1.0f / 0xFF));
Ben Claytonbc1c0672019-12-17 20:37:37 +0000790 break;
791 case VK_FORMAT_B8G8R8A8_UNORM:
Nicolas Capens7bc71202020-06-24 02:21:47 -0400792 dst.move(0, SIMD::Float((packed[0] >> 16) & SIMD::Int(0xFF)) * SIMD::Float(1.0f / 0xFF));
793 dst.move(1, SIMD::Float((packed[0] >> 8) & SIMD::Int(0xFF)) * SIMD::Float(1.0f / 0xFF));
794 dst.move(2, SIMD::Float(packed[0] & SIMD::Int(0xFF)) * SIMD::Float(1.0f / 0xFF));
795 dst.move(3, SIMD::Float((packed[0] >> 24) & SIMD::Int(0xFF)) * SIMD::Float(1.0f / 0xFF));
Ben Claytonbc1c0672019-12-17 20:37:37 +0000796 break;
797 case VK_FORMAT_B8G8R8A8_SRGB:
Nicolas Capens7bc71202020-06-24 02:21:47 -0400798 dst.move(0, ::sRGBtoLinear(SIMD::Float((packed[0] >> 16) & SIMD::Int(0xFF)) * SIMD::Float(1.0f / 0xFF)));
799 dst.move(1, ::sRGBtoLinear(SIMD::Float((packed[0] >> 8) & SIMD::Int(0xFF)) * SIMD::Float(1.0f / 0xFF)));
800 dst.move(2, ::sRGBtoLinear(SIMD::Float(packed[0] & SIMD::Int(0xFF)) * SIMD::Float(1.0f / 0xFF)));
801 dst.move(3, SIMD::Float((packed[0] >> 24) & SIMD::Int(0xFF)) * SIMD::Float(1.0f / 0xFF));
Ben Claytonbc1c0672019-12-17 20:37:37 +0000802 break;
803 case VK_FORMAT_R8G8B8A8_UINT:
804 case VK_FORMAT_A8B8G8R8_UINT_PACK32:
Nicolas Capens7bc71202020-06-24 02:21:47 -0400805 dst.move(0, As<SIMD::UInt>(packed[0]) & SIMD::UInt(0xFF));
806 dst.move(1, (As<SIMD::UInt>(packed[0]) >> 8) & SIMD::UInt(0xFF));
807 dst.move(2, (As<SIMD::UInt>(packed[0]) >> 16) & SIMD::UInt(0xFF));
808 dst.move(3, (As<SIMD::UInt>(packed[0]) >> 24) & SIMD::UInt(0xFF));
Ben Claytonbc1c0672019-12-17 20:37:37 +0000809 break;
810 case VK_FORMAT_R8G8B8A8_SINT:
811 case VK_FORMAT_A8B8G8R8_SINT_PACK32:
812 dst.move(0, (packed[0] << 24) >> 24);
813 dst.move(1, (packed[0] << 16) >> 24);
814 dst.move(2, (packed[0] << 8) >> 24);
Nicolas Capens7bc71202020-06-24 02:21:47 -0400815 dst.move(3, packed[0] >> 24);
Ben Claytonbc1c0672019-12-17 20:37:37 +0000816 break;
817 case VK_FORMAT_R8_UNORM:
Nicolas Capens7bc71202020-06-24 02:21:47 -0400818 dst.move(0, SIMD::Float((packed[0] & SIMD::Int(0xFF))) * SIMD::Float(1.0f / 0xFF));
819 dst.move(1, SIMD::Float(0.0f));
820 dst.move(2, SIMD::Float(0.0f));
821 dst.move(3, SIMD::Float(1.0f));
Ben Claytonbc1c0672019-12-17 20:37:37 +0000822 break;
Nicolas Capensc9a291a2020-06-24 02:06:17 -0400823 case VK_FORMAT_R8_SNORM:
824 dst.move(0, Max(SIMD::Float((packed[0] << 24) & SIMD::Int(0xFF000000)) * SIMD::Float(1.0f / 0x7F000000), SIMD::Float(-1.0f)));
Nicolas Capens7bc71202020-06-24 02:21:47 -0400825 dst.move(1, SIMD::Float(0.0f));
826 dst.move(2, SIMD::Float(0.0f));
827 dst.move(3, SIMD::Float(1.0f));
Nicolas Capensc9a291a2020-06-24 02:06:17 -0400828 break;
Ben Claytonbc1c0672019-12-17 20:37:37 +0000829 case VK_FORMAT_R8_UINT:
830 case VK_FORMAT_S8_UINT:
Nicolas Capens7bc71202020-06-24 02:21:47 -0400831 dst.move(0, As<SIMD::UInt>(packed[0]) & SIMD::UInt(0xFF));
Ben Claytonbc1c0672019-12-17 20:37:37 +0000832 dst.move(1, SIMD::UInt(0));
833 dst.move(2, SIMD::UInt(0));
834 dst.move(3, SIMD::UInt(1));
835 break;
836 case VK_FORMAT_R8_SINT:
837 dst.move(0, (packed[0] << 24) >> 24);
838 dst.move(1, SIMD::Int(0));
839 dst.move(2, SIMD::Int(0));
840 dst.move(3, SIMD::Int(1));
841 break;
842 case VK_FORMAT_R8G8_UNORM:
Nicolas Capens7bc71202020-06-24 02:21:47 -0400843 dst.move(0, SIMD::Float(packed[0] & SIMD::Int(0xFF)) * SIMD::Float(1.0f / 0xFF));
844 dst.move(1, SIMD::Float((packed[0] >> 8) & SIMD::Int(0xFF)) * SIMD::Float(1.0f / 0xFF));
845 dst.move(2, SIMD::Float(0.0f));
846 dst.move(3, SIMD::Float(1.0f));
Ben Claytonbc1c0672019-12-17 20:37:37 +0000847 break;
Nicolas Capensc9a291a2020-06-24 02:06:17 -0400848 case VK_FORMAT_R8G8_SNORM:
849 dst.move(0, Max(SIMD::Float((packed[0] << 24) & SIMD::Int(0xFF000000)) * SIMD::Float(1.0f / 0x7F000000), SIMD::Float(-1.0f)));
850 dst.move(1, Max(SIMD::Float((packed[0] << 16) & SIMD::Int(0xFF000000)) * SIMD::Float(1.0f / 0x7F000000), SIMD::Float(-1.0f)));
Nicolas Capens7bc71202020-06-24 02:21:47 -0400851 dst.move(2, SIMD::Float(0.0f));
852 dst.move(3, SIMD::Float(1.0f));
Nicolas Capensc9a291a2020-06-24 02:06:17 -0400853 break;
Ben Claytonbc1c0672019-12-17 20:37:37 +0000854 case VK_FORMAT_R8G8_UINT:
Nicolas Capens7bc71202020-06-24 02:21:47 -0400855 dst.move(0, As<SIMD::UInt>(packed[0]) & SIMD::UInt(0xFF));
856 dst.move(1, (As<SIMD::UInt>(packed[0]) >> 8) & SIMD::UInt(0xFF));
Ben Claytonbc1c0672019-12-17 20:37:37 +0000857 dst.move(2, SIMD::UInt(0));
858 dst.move(3, SIMD::UInt(1));
859 break;
860 case VK_FORMAT_R8G8_SINT:
861 dst.move(0, (packed[0] << 24) >> 24);
862 dst.move(1, (packed[0] << 16) >> 24);
863 dst.move(2, SIMD::Int(0));
864 dst.move(3, SIMD::Int(1));
865 break;
866 case VK_FORMAT_R16_SFLOAT:
867 dst.move(0, halfToFloatBits(As<SIMD::UInt>(packed[0]) & SIMD::UInt(0x0000FFFF)));
Nicolas Capens7bc71202020-06-24 02:21:47 -0400868 dst.move(1, SIMD::Float(0.0f));
869 dst.move(2, SIMD::Float(0.0f));
870 dst.move(3, SIMD::Float(1.0f));
Ben Claytonbc1c0672019-12-17 20:37:37 +0000871 break;
Nicolas Capensf6f11212020-07-01 00:27:23 -0400872 case VK_FORMAT_R16_UNORM:
873 dst.move(0, SIMD::Float(packed[0] & SIMD::Int(0xFFFF)) * SIMD::Float(1.0f / 0xFFFF));
874 dst.move(1, SIMD::Float(0.0f));
875 dst.move(2, SIMD::Float(0.0f));
876 dst.move(3, SIMD::Float(1.0f));
877 break;
878 case VK_FORMAT_R16_SNORM:
879 dst.move(0, Max(SIMD::Float((packed[0] << 16) & SIMD::Int(0xFFFF0000)) * SIMD::Float(1.0f / 0x7FFF0000), SIMD::Float(-1.0f)));
880 dst.move(1, SIMD::Float(0.0f));
881 dst.move(2, SIMD::Float(0.0f));
882 dst.move(3, SIMD::Float(1.0f));
883 break;
Ben Claytonbc1c0672019-12-17 20:37:37 +0000884 case VK_FORMAT_R16_UINT:
Nicolas Capens7bc71202020-06-24 02:21:47 -0400885 dst.move(0, packed[0] & SIMD::Int(0xFFFF));
Ben Claytonbc1c0672019-12-17 20:37:37 +0000886 dst.move(1, SIMD::UInt(0));
887 dst.move(2, SIMD::UInt(0));
888 dst.move(3, SIMD::UInt(1));
889 break;
890 case VK_FORMAT_R16_SINT:
891 dst.move(0, (packed[0] << 16) >> 16);
892 dst.move(1, SIMD::Int(0));
893 dst.move(2, SIMD::Int(0));
894 dst.move(3, SIMD::Int(1));
895 break;
896 case VK_FORMAT_R16G16_SFLOAT:
897 dst.move(0, halfToFloatBits(As<SIMD::UInt>(packed[0]) & SIMD::UInt(0x0000FFFF)));
898 dst.move(1, halfToFloatBits((As<SIMD::UInt>(packed[0]) & SIMD::UInt(0xFFFF0000)) >> 16));
Nicolas Capens7bc71202020-06-24 02:21:47 -0400899 dst.move(2, SIMD::Float(0.0f));
900 dst.move(3, SIMD::Float(1.0f));
Ben Claytonbc1c0672019-12-17 20:37:37 +0000901 break;
Nicolas Capensf6f11212020-07-01 00:27:23 -0400902 case VK_FORMAT_R16G16_UNORM:
903 dst.move(0, SIMD::Float(packed[0] & SIMD::Int(0xFFFF)) * SIMD::Float(1.0f / 0xFFFF));
904 dst.move(1, SIMD::Float(As<SIMD::UInt>(packed[0]) >> 16) * SIMD::Float(1.0f / 0xFFFF));
905 dst.move(2, SIMD::Float(0.0f));
906 dst.move(3, SIMD::Float(1.0f));
907 break;
908 case VK_FORMAT_R16G16_SNORM:
909 dst.move(0, Max(SIMD::Float((packed[0] << 16) & SIMD::Int(0xFFFF0000)) * SIMD::Float(1.0f / 0x7FFF0000), SIMD::Float(-1.0f)));
910 dst.move(1, Max(SIMD::Float(packed[0] & SIMD::Int(0xFFFF0000)) * SIMD::Float(1.0f / 0x7FFF0000), SIMD::Float(-1.0f)));
911 dst.move(2, SIMD::Float(0.0f));
912 dst.move(3, SIMD::Float(1.0f));
913 break;
Ben Claytonbc1c0672019-12-17 20:37:37 +0000914 case VK_FORMAT_R16G16_UINT:
Nicolas Capens7bc71202020-06-24 02:21:47 -0400915 dst.move(0, packed[0] & SIMD::Int(0xFFFF));
916 dst.move(1, (packed[0] >> 16) & SIMD::Int(0xFFFF));
Ben Claytonbc1c0672019-12-17 20:37:37 +0000917 dst.move(2, SIMD::UInt(0));
918 dst.move(3, SIMD::UInt(1));
919 break;
920 case VK_FORMAT_R16G16_SINT:
921 dst.move(0, (packed[0] << 16) >> 16);
Nicolas Capens7bc71202020-06-24 02:21:47 -0400922 dst.move(1, packed[0] >> 16);
Ben Claytonbc1c0672019-12-17 20:37:37 +0000923 dst.move(2, SIMD::Int(0));
924 dst.move(3, SIMD::Int(1));
925 break;
926 case VK_FORMAT_R32G32_SINT:
927 case VK_FORMAT_R32G32_UINT:
928 dst.move(0, packed[0]);
929 dst.move(1, packed[1]);
930 dst.move(2, SIMD::Int(0));
931 dst.move(3, SIMD::Int(1));
932 break;
933 case VK_FORMAT_R32G32_SFLOAT:
934 dst.move(0, packed[0]);
935 dst.move(1, packed[1]);
Nicolas Capens7bc71202020-06-24 02:21:47 -0400936 dst.move(2, SIMD::Float(0.0f));
937 dst.move(3, SIMD::Float(1.0f));
Ben Claytonbc1c0672019-12-17 20:37:37 +0000938 break;
939 case VK_FORMAT_A2B10G10R10_UINT_PACK32:
Nicolas Capens7bc71202020-06-24 02:21:47 -0400940 dst.move(0, packed[0] & SIMD::Int(0x3FF));
Ben Claytonbc1c0672019-12-17 20:37:37 +0000941 dst.move(1, (packed[0] >> 10) & SIMD::Int(0x3FF));
942 dst.move(2, (packed[0] >> 20) & SIMD::Int(0x3FF));
943 dst.move(3, (packed[0] >> 30) & SIMD::Int(0x3));
944 break;
Alexis Hetub8a61bf2020-01-09 15:26:34 -0500945 case VK_FORMAT_A2R10G10B10_UINT_PACK32:
Nicolas Capens7bc71202020-06-24 02:21:47 -0400946 dst.move(2, packed[0] & SIMD::Int(0x3FF));
Alexis Hetub8a61bf2020-01-09 15:26:34 -0500947 dst.move(1, (packed[0] >> 10) & SIMD::Int(0x3FF));
948 dst.move(0, (packed[0] >> 20) & SIMD::Int(0x3FF));
949 dst.move(3, (packed[0] >> 30) & SIMD::Int(0x3));
950 break;
Ben Claytonbc1c0672019-12-17 20:37:37 +0000951 case VK_FORMAT_A2B10G10R10_UNORM_PACK32:
952 dst.move(0, SIMD::Float((packed[0]) & SIMD::Int(0x3FF)) * SIMD::Float(1.0f / 0x3FF));
953 dst.move(1, SIMD::Float((packed[0] >> 10) & SIMD::Int(0x3FF)) * SIMD::Float(1.0f / 0x3FF));
954 dst.move(2, SIMD::Float((packed[0] >> 20) & SIMD::Int(0x3FF)) * SIMD::Float(1.0f / 0x3FF));
955 dst.move(3, SIMD::Float((packed[0] >> 30) & SIMD::Int(0x3)) * SIMD::Float(1.0f / 0x3));
956 break;
Alexis Hetub8a61bf2020-01-09 15:26:34 -0500957 case VK_FORMAT_A2R10G10B10_UNORM_PACK32:
958 dst.move(2, SIMD::Float((packed[0]) & SIMD::Int(0x3FF)) * SIMD::Float(1.0f / 0x3FF));
959 dst.move(1, SIMD::Float((packed[0] >> 10) & SIMD::Int(0x3FF)) * SIMD::Float(1.0f / 0x3FF));
960 dst.move(0, SIMD::Float((packed[0] >> 20) & SIMD::Int(0x3FF)) * SIMD::Float(1.0f / 0x3FF));
961 dst.move(3, SIMD::Float((packed[0] >> 30) & SIMD::Int(0x3)) * SIMD::Float(1.0f / 0x3));
962 break;
Ben Claytonbc1c0672019-12-17 20:37:37 +0000963 case VK_FORMAT_R5G6B5_UNORM_PACK16:
964 dst.move(0, SIMD::Float((packed[0] >> 11) & SIMD::Int(0x1F)) * SIMD::Float(1.0f / 0x1F));
965 dst.move(1, SIMD::Float((packed[0] >> 5) & SIMD::Int(0x3F)) * SIMD::Float(1.0f / 0x3F));
966 dst.move(2, SIMD::Float((packed[0]) & SIMD::Int(0x1F)) * SIMD::Float(1.0f / 0x1F));
Nicolas Capens7bc71202020-06-24 02:21:47 -0400967 dst.move(3, SIMD::Float(1.0f));
Ben Claytonbc1c0672019-12-17 20:37:37 +0000968 break;
969 case VK_FORMAT_A1R5G5B5_UNORM_PACK16:
970 dst.move(0, SIMD::Float((packed[0] >> 10) & SIMD::Int(0x1F)) * SIMD::Float(1.0f / 0x1F));
971 dst.move(1, SIMD::Float((packed[0] >> 5) & SIMD::Int(0x1F)) * SIMD::Float(1.0f / 0x1F));
972 dst.move(2, SIMD::Float((packed[0]) & SIMD::Int(0x1F)) * SIMD::Float(1.0f / 0x1F));
973 dst.move(3, SIMD::Float((packed[0] >> 15) & SIMD::Int(0x1)));
974 break;
Nicolas Capens2e7cdd82020-06-24 01:29:59 -0400975 case VK_FORMAT_B10G11R11_UFLOAT_PACK32:
976 dst.move(0, halfToFloatBits((packed[0] << 4) & SIMD::Int(0x7FF0)));
977 dst.move(1, halfToFloatBits((packed[0] >> 7) & SIMD::Int(0x7FF0)));
978 dst.move(2, halfToFloatBits((packed[0] >> 17) & SIMD::Int(0x7FE0)));
Nicolas Capens7bc71202020-06-24 02:21:47 -0400979 dst.move(3, SIMD::Float(1.0f));
Nicolas Capens2e7cdd82020-06-24 01:29:59 -0400980 break;
Ben Claytonbc1c0672019-12-17 20:37:37 +0000981 default:
Nicolas Capens865f8892020-01-21 14:27:10 -0500982 UNSUPPORTED("VkFormat %d", int(vkFormat));
Ben Claytonbc1c0672019-12-17 20:37:37 +0000983 break;
Ben Clayton5e51cfc2019-11-28 13:49:29 +0000984 }
985
986 return EmitResult::Continue;
987}
988
989SpirvShader::EmitResult SpirvShader::EmitImageWrite(InsnIterator insn, EmitState *state) const
990{
Alexis Hetu4f438a52020-06-15 16:13:51 -0400991 imageWriteEmitted = true;
992
Ben Clayton5e51cfc2019-11-28 13:49:29 +0000993 auto imageId = Object::ID(insn.word(1));
994 auto &image = getObject(imageId);
Nicolas Capens72f089c2020-04-08 23:37:08 -0400995 auto &imageType = getType(image);
Ben Clayton5e51cfc2019-11-28 13:49:29 +0000996
997 ASSERT(imageType.definition.opcode() == spv::OpTypeImage);
998
999 // TODO(b/131171141): Not handling any image operands yet.
1000 ASSERT(insn.wordCount() == 4);
1001
Nicolas Capense6f65d92020-04-08 21:55:43 -04001002 auto coordinate = Operand(this, state, insn.word(2));
1003 auto texel = Operand(this, state, insn.word(3));
Ben Clayton5e51cfc2019-11-28 13:49:29 +00001004
1005 Pointer<Byte> binding = state->getPointer(imageId).base;
1006 Pointer<Byte> imageBase = *Pointer<Pointer<Byte>>(binding + OFFSET(vk::StorageImageDescriptor, ptr));
1007 auto imageSizeInBytes = *Pointer<Int>(binding + OFFSET(vk::StorageImageDescriptor, sizeInBytes));
1008
1009 SIMD::Int packed[4];
Ben Clayton5e51cfc2019-11-28 13:49:29 +00001010 int texelSize = 0;
1011 auto format = static_cast<spv::ImageFormat>(imageType.definition.word(8));
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001012 switch(format)
Ben Clayton5e51cfc2019-11-28 13:49:29 +00001013 {
Ben Claytonbc1c0672019-12-17 20:37:37 +00001014 case spv::ImageFormatRgba32f:
1015 case spv::ImageFormatRgba32i:
1016 case spv::ImageFormatRgba32ui:
1017 texelSize = 16;
1018 packed[0] = texel.Int(0);
1019 packed[1] = texel.Int(1);
1020 packed[2] = texel.Int(2);
1021 packed[3] = texel.Int(3);
Ben Claytonbc1c0672019-12-17 20:37:37 +00001022 break;
1023 case spv::ImageFormatR32f:
1024 case spv::ImageFormatR32i:
1025 case spv::ImageFormatR32ui:
1026 texelSize = 4;
1027 packed[0] = texel.Int(0);
Ben Claytonbc1c0672019-12-17 20:37:37 +00001028 break;
1029 case spv::ImageFormatRgba8:
1030 texelSize = 4;
1031 packed[0] = (SIMD::UInt(Round(Min(Max(texel.Float(0), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(255.0f)))) |
1032 ((SIMD::UInt(Round(Min(Max(texel.Float(1), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(255.0f)))) << 8) |
1033 ((SIMD::UInt(Round(Min(Max(texel.Float(2), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(255.0f)))) << 16) |
1034 ((SIMD::UInt(Round(Min(Max(texel.Float(3), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(255.0f)))) << 24);
Ben Claytonbc1c0672019-12-17 20:37:37 +00001035 break;
1036 case spv::ImageFormatRgba8Snorm:
1037 texelSize = 4;
1038 packed[0] = (SIMD::Int(Round(Min(Max(texel.Float(0), SIMD::Float(-1.0f)), SIMD::Float(1.0f)) * SIMD::Float(127.0f))) &
1039 SIMD::Int(0xFF)) |
1040 ((SIMD::Int(Round(Min(Max(texel.Float(1), SIMD::Float(-1.0f)), SIMD::Float(1.0f)) * SIMD::Float(127.0f))) &
1041 SIMD::Int(0xFF))
1042 << 8) |
1043 ((SIMD::Int(Round(Min(Max(texel.Float(2), SIMD::Float(-1.0f)), SIMD::Float(1.0f)) * SIMD::Float(127.0f))) &
1044 SIMD::Int(0xFF))
1045 << 16) |
1046 ((SIMD::Int(Round(Min(Max(texel.Float(3), SIMD::Float(-1.0f)), SIMD::Float(1.0f)) * SIMD::Float(127.0f))) &
1047 SIMD::Int(0xFF))
1048 << 24);
Ben Claytonbc1c0672019-12-17 20:37:37 +00001049 break;
1050 case spv::ImageFormatRgba8i:
1051 case spv::ImageFormatRgba8ui:
1052 texelSize = 4;
1053 packed[0] = (SIMD::UInt(texel.UInt(0) & SIMD::UInt(0xff))) |
1054 (SIMD::UInt(texel.UInt(1) & SIMD::UInt(0xff)) << 8) |
1055 (SIMD::UInt(texel.UInt(2) & SIMD::UInt(0xff)) << 16) |
1056 (SIMD::UInt(texel.UInt(3) & SIMD::UInt(0xff)) << 24);
Ben Claytonbc1c0672019-12-17 20:37:37 +00001057 break;
1058 case spv::ImageFormatRgba16f:
1059 texelSize = 8;
1060 packed[0] = floatToHalfBits(texel.UInt(0), false) | floatToHalfBits(texel.UInt(1), true);
1061 packed[1] = floatToHalfBits(texel.UInt(2), false) | floatToHalfBits(texel.UInt(3), true);
Ben Claytonbc1c0672019-12-17 20:37:37 +00001062 break;
1063 case spv::ImageFormatRgba16i:
1064 case spv::ImageFormatRgba16ui:
1065 texelSize = 8;
Nicolas Capens7bc71202020-06-24 02:21:47 -04001066 packed[0] = SIMD::UInt(texel.UInt(0) & SIMD::UInt(0xFFFF)) | (SIMD::UInt(texel.UInt(1) & SIMD::UInt(0xFFFF)) << 16);
1067 packed[1] = SIMD::UInt(texel.UInt(2) & SIMD::UInt(0xFFFF)) | (SIMD::UInt(texel.UInt(3) & SIMD::UInt(0xFFFF)) << 16);
Ben Claytonbc1c0672019-12-17 20:37:37 +00001068 break;
1069 case spv::ImageFormatRg32f:
1070 case spv::ImageFormatRg32i:
1071 case spv::ImageFormatRg32ui:
1072 texelSize = 8;
1073 packed[0] = texel.Int(0);
1074 packed[1] = texel.Int(1);
Ben Claytonbc1c0672019-12-17 20:37:37 +00001075 break;
Ben Claytonbc1c0672019-12-17 20:37:37 +00001076 case spv::ImageFormatRg16f:
Chris Forbes57977c12019-12-19 16:09:18 -08001077 texelSize = 4;
1078 packed[0] = floatToHalfBits(texel.UInt(0), false) | floatToHalfBits(texel.UInt(1), true);
Chris Forbes57977c12019-12-19 16:09:18 -08001079 break;
1080 case spv::ImageFormatRg16i:
1081 case spv::ImageFormatRg16ui:
1082 texelSize = 4;
Nicolas Capens7bc71202020-06-24 02:21:47 -04001083 packed[0] = SIMD::UInt(texel.UInt(0) & SIMD::UInt(0xFFFF)) | (SIMD::UInt(texel.UInt(1) & SIMD::UInt(0xFFFF)) << 16);
Chris Forbes57977c12019-12-19 16:09:18 -08001084 break;
Ben Claytonbc1c0672019-12-17 20:37:37 +00001085 case spv::ImageFormatR11fG11fB10f:
Nicolas Capensf6f11212020-07-01 00:27:23 -04001086 texelSize = 4;
1087 // Truncates instead of rounding. See b/147900455
1088 packed[0] = ((floatToHalfBits(As<SIMD::UInt>(Max(texel.Float(0), SIMD::Float(0.0f))), false) & SIMD::UInt(0x7FF0)) >> 4) |
1089 ((floatToHalfBits(As<SIMD::UInt>(Max(texel.Float(1), SIMD::Float(0.0f))), false) & SIMD::UInt(0x7FF0)) << 7) |
1090 ((floatToHalfBits(As<SIMD::UInt>(Max(texel.Float(2), SIMD::Float(0.0f))), false) & SIMD::UInt(0x7FE0)) << 17);
Ben Claytonbc1c0672019-12-17 20:37:37 +00001091 break;
Nicolas Capensf6f11212020-07-01 00:27:23 -04001092 case spv::ImageFormatR16f:
1093 texelSize = 2;
1094 packed[0] = floatToHalfBits(texel.UInt(0), false);
1095 break;
1096 case spv::ImageFormatRgba16:
1097 texelSize = 8;
1098 packed[0] = SIMD::UInt(Round(Min(Max(texel.Float(0), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(0xFFFF))) |
1099 (SIMD::UInt(Round(Min(Max(texel.Float(1), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(0xFFFF))) << 16);
1100 packed[1] = SIMD::UInt(Round(Min(Max(texel.Float(2), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(0xFFFF))) |
1101 (SIMD::UInt(Round(Min(Max(texel.Float(3), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(0xFFFF))) << 16);
1102 break;
1103 case spv::ImageFormatRgb10A2:
1104 texelSize = 4;
1105 packed[0] = (SIMD::UInt(Round(Min(Max(texel.Float(0), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(0x3FF)))) |
1106 ((SIMD::UInt(Round(Min(Max(texel.Float(1), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(0x3FF)))) << 10) |
1107 ((SIMD::UInt(Round(Min(Max(texel.Float(2), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(0x3FF)))) << 20) |
1108 ((SIMD::UInt(Round(Min(Max(texel.Float(3), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(0x3)))) << 30);
1109 break;
1110 case spv::ImageFormatRg16:
1111 texelSize = 4;
1112 packed[0] = SIMD::UInt(Round(Min(Max(texel.Float(0), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(0xFFFF))) |
1113 (SIMD::UInt(Round(Min(Max(texel.Float(1), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(0xFFFF))) << 16);
1114 break;
1115 case spv::ImageFormatRg8:
1116 texelSize = 2;
1117 packed[0] = SIMD::UInt(Round(Min(Max(texel.Float(0), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(0xFF))) |
1118 (SIMD::UInt(Round(Min(Max(texel.Float(1), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(0xFF))) << 8);
1119 break;
1120 case spv::ImageFormatR16:
1121 texelSize = 2;
1122 packed[0] = SIMD::UInt(Round(Min(Max(texel.Float(0), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(0xFFFF)));
1123 break;
1124 case spv::ImageFormatR8:
1125 texelSize = 1;
1126 packed[0] = SIMD::UInt(Round(Min(Max(texel.Float(0), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(0xFF)));
1127 break;
1128 case spv::ImageFormatRgba16Snorm:
1129 texelSize = 8;
1130 packed[0] = (SIMD::Int(Round(Min(Max(texel.Float(0), SIMD::Float(-1.0f)), SIMD::Float(1.0f)) * SIMD::Float(0x7FFF))) & SIMD::Int(0xFFFF)) |
1131 (SIMD::Int(Round(Min(Max(texel.Float(1), SIMD::Float(-1.0f)), SIMD::Float(1.0f)) * SIMD::Float(0x7FFF))) << 16);
1132 packed[1] = (SIMD::Int(Round(Min(Max(texel.Float(2), SIMD::Float(-1.0f)), SIMD::Float(1.0f)) * SIMD::Float(0x7FFF))) & SIMD::Int(0xFFFF)) |
1133 (SIMD::Int(Round(Min(Max(texel.Float(3), SIMD::Float(-1.0f)), SIMD::Float(1.0f)) * SIMD::Float(0x7FFF))) << 16);
1134 break;
1135 case spv::ImageFormatRg16Snorm:
1136 texelSize = 4;
1137 packed[0] = (SIMD::Int(Round(Min(Max(texel.Float(0), SIMD::Float(-1.0f)), SIMD::Float(1.0f)) * SIMD::Float(0x7FFF))) & SIMD::Int(0xFFFF)) |
1138 (SIMD::Int(Round(Min(Max(texel.Float(1), SIMD::Float(-1.0f)), SIMD::Float(1.0f)) * SIMD::Float(0x7FFF))) << 16);
1139 break;
1140 case spv::ImageFormatRg8Snorm:
1141 texelSize = 2;
1142 packed[0] = (SIMD::Int(Round(Min(Max(texel.Float(0), SIMD::Float(-1.0f)), SIMD::Float(1.0f)) * SIMD::Float(0x7F))) & SIMD::Int(0xFF)) |
1143 (SIMD::Int(Round(Min(Max(texel.Float(1), SIMD::Float(-1.0f)), SIMD::Float(1.0f)) * SIMD::Float(0x7F))) << 8);
1144 break;
1145 case spv::ImageFormatR16Snorm:
1146 texelSize = 2;
1147 packed[0] = SIMD::Int(Round(Min(Max(texel.Float(0), SIMD::Float(-1.0f)), SIMD::Float(1.0f)) * SIMD::Float(0x7FFF)));
1148 break;
1149 case spv::ImageFormatR8Snorm:
1150 texelSize = 1;
1151 packed[0] = SIMD::Int(Round(Min(Max(texel.Float(0), SIMD::Float(-1.0f)), SIMD::Float(1.0f)) * SIMD::Float(0x7F)));
1152 break;
1153 case spv::ImageFormatRg8i:
1154 case spv::ImageFormatRg8ui:
1155 texelSize = 2;
1156 packed[0] = SIMD::UInt(texel.UInt(0) & SIMD::UInt(0xFF)) | (SIMD::UInt(texel.UInt(1) & SIMD::UInt(0xFF)) << 8);
1157 break;
1158 case spv::ImageFormatR16i:
1159 case spv::ImageFormatR16ui:
1160 texelSize = 2;
1161 packed[0] = SIMD::UInt(texel.UInt(0) & SIMD::UInt(0xFFFF));
1162 break;
1163 case spv::ImageFormatR8i:
1164 case spv::ImageFormatR8ui:
1165 texelSize = 1;
1166 packed[0] = SIMD::UInt(texel.UInt(0) & SIMD::UInt(0xFF));
1167 break;
1168 case spv::ImageFormatRgb10a2ui:
1169 texelSize = 4;
1170 packed[0] = (SIMD::UInt(texel.UInt(0) & SIMD::UInt(0x3FF))) |
1171 (SIMD::UInt(texel.UInt(1) & SIMD::UInt(0x3FF)) << 10) |
1172 (SIMD::UInt(texel.UInt(2) & SIMD::UInt(0x3FF)) << 20) |
1173 (SIMD::UInt(texel.UInt(3) & SIMD::UInt(0x3)) << 30);
1174 break;
Ben Claytonbc1c0672019-12-17 20:37:37 +00001175 default:
Nicolas Capensf6f11212020-07-01 00:27:23 -04001176 UNSUPPORTED("spv::ImageFormat %d", int(format));
Ben Claytonbc1c0672019-12-17 20:37:37 +00001177 break;
Ben Clayton5e51cfc2019-11-28 13:49:29 +00001178 }
1179
Ben Clayton5e51cfc2019-11-28 13:49:29 +00001180 // SPIR-V 1.4: "If the coordinates are outside the image, the memory location that is accessed is undefined."
Alexis Hetu08afdde2020-05-06 15:06:01 -04001181
1182 // Emulating the glsl function imageStore() requires that this function is noop when used with out of bounds
1183 // coordinates, so we have to use OutOfBoundsBehavior::Nullify in that case.
Nicolas Capensf6f11212020-07-01 00:27:23 -04001184 // TODO(b/159329067): Claim VK_EXT_image_robustness
Alexis Hetu08afdde2020-05-06 15:06:01 -04001185 auto robustness = OutOfBoundsBehavior::Nullify;
Ben Clayton5e51cfc2019-11-28 13:49:29 +00001186
Nicolas Capens4a65df12020-05-07 10:06:46 -04001187 auto texelPtr = GetTexelAddress(state, imageBase, imageSizeInBytes, coordinate, imageType, binding, texelSize, 0, false, robustness);
Alexis Hetu60727de2020-04-15 15:26:14 -04001188
Nicolas Capens8d75c102020-07-05 23:08:13 -04001189 // Scatter packed texel data.
1190 // TODO(b/160531165): Provide scatter abstractions for various element sizes.
1191 if(texelSize == 4 || texelSize == 8 || texelSize == 16)
Ben Clayton5e51cfc2019-11-28 13:49:29 +00001192 {
Nicolas Capens8d75c102020-07-05 23:08:13 -04001193 for(auto i = 0; i < texelSize / 4; i++)
1194 {
1195 texelPtr.Store(packed[i], robustness, state->activeLaneMask());
1196 texelPtr += sizeof(float);
1197 }
Ben Clayton5e51cfc2019-11-28 13:49:29 +00001198 }
Nicolas Capens8d75c102020-07-05 23:08:13 -04001199 else if(texelSize == 2)
1200 {
1201 SIMD::Int offsets = texelPtr.offsets();
1202 SIMD::Int mask = state->activeLaneMask() & texelPtr.isInBounds(2, robustness);
1203
1204 for(int i = 0; i < SIMD::Width; i++)
1205 {
1206 If(Extract(mask, i) != 0)
1207 {
1208 *Pointer<Short>(texelPtr.base + Extract(offsets, i)) = Short(Extract(packed[0], i));
1209 }
1210 }
1211 }
1212 else if(texelSize == 1)
1213 {
1214 SIMD::Int offsets = texelPtr.offsets();
1215 SIMD::Int mask = state->activeLaneMask() & texelPtr.isInBounds(1, robustness);
1216
1217 for(int i = 0; i < SIMD::Width; i++)
1218 {
1219 If(Extract(mask, i) != 0)
1220 {
1221 *Pointer<Byte>(texelPtr.base + Extract(offsets, i)) = Byte(Extract(packed[0], i));
1222 }
1223 }
1224 }
1225 else
1226 UNREACHABLE("texelSize: %d", int(texelSize));
Ben Clayton5e51cfc2019-11-28 13:49:29 +00001227
1228 return EmitResult::Continue;
1229}
1230
1231SpirvShader::EmitResult SpirvShader::EmitImageTexelPointer(InsnIterator insn, EmitState *state) const
1232{
1233 auto &resultType = getType(Type::ID(insn.word(1)));
1234 auto imageId = Object::ID(insn.word(3));
1235 auto &image = getObject(imageId);
1236 // Note: OpImageTexelPointer is unusual in that the image is passed by pointer.
1237 // Look through to get the actual image type.
Nicolas Capens72f089c2020-04-08 23:37:08 -04001238 auto &imageType = getType(getType(image).element);
Ben Clayton5e51cfc2019-11-28 13:49:29 +00001239 Object::ID resultId = insn.word(2);
1240
1241 ASSERT(imageType.opcode() == spv::OpTypeImage);
1242 ASSERT(resultType.storageClass == spv::StorageClassImage);
1243 ASSERT(getType(resultType.element).opcode() == spv::OpTypeInt);
1244
Nicolas Capense6f65d92020-04-08 21:55:43 -04001245 auto coordinate = Operand(this, state, insn.word(4));
Ben Clayton5e51cfc2019-11-28 13:49:29 +00001246
1247 Pointer<Byte> binding = state->getPointer(imageId).base;
1248 Pointer<Byte> imageBase = *Pointer<Pointer<Byte>>(binding + OFFSET(vk::StorageImageDescriptor, ptr));
1249 auto imageSizeInBytes = *Pointer<Int>(binding + OFFSET(vk::StorageImageDescriptor, sizeInBytes));
1250
Nicolas Capens4a65df12020-05-07 10:06:46 -04001251 auto ptr = GetTexelAddress(state, imageBase, imageSizeInBytes, coordinate, imageType, binding, sizeof(uint32_t), 0, false, OutOfBoundsBehavior::UndefinedValue);
Ben Clayton5e51cfc2019-11-28 13:49:29 +00001252
1253 state->createPointer(resultId, ptr);
1254
1255 return EmitResult::Continue;
1256}
1257
1258SpirvShader::EmitResult SpirvShader::EmitSampledImageCombineOrSplit(InsnIterator insn, EmitState *state) const
1259{
1260 // Propagate the image pointer in both cases.
1261 // Consumers of OpSampledImage will look through to find the sampler pointer.
1262
1263 Object::ID resultId = insn.word(2);
1264 Object::ID imageId = insn.word(3);
1265
1266 state->createPointer(resultId, state->getPointer(imageId));
1267
1268 return EmitResult::Continue;
1269}
1270
1271} // namespace sw