OSDN Git Service

Rename constant cache to snapshot cache
[android-x86/external-swiftshader.git] / src / Pipeline / SpirvShaderSampling.cpp
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 "SamplerCore.hpp"  // TODO: Figure out what's needed.
18 #include "Device/Config.hpp"
19 #include "System/Debug.hpp"
20 #include "System/Math.hpp"
21 #include "Vulkan/VkDescriptorSetLayout.hpp"
22 #include "Vulkan/VkDevice.hpp"
23 #include "Vulkan/VkImageView.hpp"
24 #include "Vulkan/VkSampler.hpp"
25
26 #include <spirv/unified1/spirv.hpp>
27
28 #include <climits>
29 #include <mutex>
30
31 namespace sw {
32
33 SpirvShader::ImageSampler *SpirvShader::getImageSampler(uint32_t inst, vk::SampledImageDescriptor const *imageDescriptor, const vk::Sampler *sampler)
34 {
35         ImageInstruction instruction(inst);
36         const auto samplerId = sampler ? sampler->id : 0;
37         ASSERT(imageDescriptor->imageViewId != 0 && (samplerId != 0 || instruction.samplerMethod == Fetch));
38
39         vk::Device::SamplingRoutineCache::Key key = { inst, imageDescriptor->imageViewId, samplerId };
40
41         ASSERT(imageDescriptor->device);
42
43         if(auto routine = imageDescriptor->device->querySnapshotCache(key))
44         {
45                 return (ImageSampler *)(routine->getEntry());
46         }
47
48         std::unique_lock<std::mutex> lock(imageDescriptor->device->getSamplingRoutineCacheMutex());
49         vk::Device::SamplingRoutineCache *cache = imageDescriptor->device->getSamplingRoutineCache();
50
51         auto routine = cache->query(key);
52         if(routine)
53         {
54                 return (ImageSampler *)(routine->getEntry());
55         }
56
57         auto type = imageDescriptor->type;
58
59         Sampler samplerState = {};
60         samplerState.textureType = type;
61         samplerState.textureFormat = imageDescriptor->format;
62
63         samplerState.addressingModeU = convertAddressingMode(0, sampler, type);
64         samplerState.addressingModeV = convertAddressingMode(1, sampler, type);
65         samplerState.addressingModeW = convertAddressingMode(2, sampler, type);
66         samplerState.addressingModeY = convertAddressingMode(3, sampler, type);
67
68         samplerState.mipmapFilter = convertMipmapMode(sampler);
69         samplerState.swizzle = imageDescriptor->swizzle;
70         samplerState.gatherComponent = instruction.gatherComponent;
71         samplerState.highPrecisionFiltering = false;
72         samplerState.largeTexture = (imageDescriptor->extent.width > SHRT_MAX) ||
73                                     (imageDescriptor->extent.height > SHRT_MAX) ||
74                                     (imageDescriptor->extent.depth > SHRT_MAX);
75
76         if(sampler)
77         {
78                 samplerState.textureFilter = (instruction.samplerMethod == Gather) ? FILTER_GATHER : convertFilterMode(sampler);
79                 samplerState.border = sampler->borderColor;
80
81                 samplerState.mipmapFilter = convertMipmapMode(sampler);
82
83                 samplerState.compareEnable = (sampler->compareEnable != VK_FALSE);
84                 samplerState.compareOp = sampler->compareOp;
85                 samplerState.unnormalizedCoordinates = (sampler->unnormalizedCoordinates != VK_FALSE);
86
87                 samplerState.ycbcrModel = sampler->ycbcrModel;
88                 samplerState.studioSwing = sampler->studioSwing;
89                 samplerState.swappedChroma = sampler->swappedChroma;
90
91                 samplerState.mipLodBias = sampler->mipLodBias;
92                 samplerState.maxAnisotropy = sampler->maxAnisotropy;
93                 samplerState.minLod = sampler->minLod;
94                 samplerState.maxLod = sampler->maxLod;
95         }
96
97         routine = emitSamplerRoutine(instruction, samplerState);
98
99         cache->add(key, routine);
100         return (ImageSampler *)(routine->getEntry());
101 }
102
103 std::shared_ptr<rr::Routine> SpirvShader::emitSamplerRoutine(ImageInstruction instruction, const Sampler &samplerState)
104 {
105         // TODO(b/129523279): Hold a separate mutex lock for the sampler being built.
106         rr::Function<Void(Pointer<Byte>, Pointer<SIMD::Float>, Pointer<SIMD::Float>, Pointer<Byte>)> function;
107         {
108                 Pointer<Byte> texture = function.Arg<0>();
109                 Pointer<SIMD::Float> in = function.Arg<1>();
110                 Pointer<SIMD::Float> out = function.Arg<2>();
111                 Pointer<Byte> constants = function.Arg<3>();
112
113                 SIMD::Float uvw[4] = { 0, 0, 0, 0 };
114                 SIMD::Float q = 0;
115                 SIMD::Float lodOrBias = 0;  // Explicit level-of-detail, or bias added to the implicit level-of-detail (depending on samplerMethod).
116                 Vector4f dsx = { 0, 0, 0, 0 };
117                 Vector4f dsy = { 0, 0, 0, 0 };
118                 Vector4f offset = { 0, 0, 0, 0 };
119                 SIMD::Int sampleId = 0;
120                 SamplerFunction samplerFunction = instruction.getSamplerFunction();
121
122                 uint32_t i = 0;
123                 for(; i < instruction.coordinates; i++)
124                 {
125                         uvw[i] = in[i];
126                 }
127
128                 if(instruction.isDref())
129                 {
130                         q = in[i];
131                         i++;
132                 }
133
134                 // TODO(b/134669567): Currently 1D textures are treated as 2D by setting the second coordinate to 0.
135                 // Implement optimized 1D sampling.
136                 if(samplerState.textureType == VK_IMAGE_VIEW_TYPE_1D)
137                 {
138                         uvw[1] = SIMD::Float(0);
139                 }
140                 else if(samplerState.textureType == VK_IMAGE_VIEW_TYPE_1D_ARRAY)
141                 {
142                         uvw[1] = SIMD::Float(0);
143                         uvw[2] = in[1];  // Move 1D layer coordinate to 2D layer coordinate index.
144                 }
145
146                 if(instruction.samplerMethod == Lod || instruction.samplerMethod == Bias || instruction.samplerMethod == Fetch)
147                 {
148                         lodOrBias = in[i];
149                         i++;
150                 }
151                 else if(instruction.samplerMethod == Grad)
152                 {
153                         for(uint32_t j = 0; j < instruction.grad; j++, i++)
154                         {
155                                 dsx[j] = in[i];
156                         }
157
158                         for(uint32_t j = 0; j < instruction.grad; j++, i++)
159                         {
160                                 dsy[j] = in[i];
161                         }
162                 }
163
164                 for(uint32_t j = 0; j < instruction.offset; j++, i++)
165                 {
166                         offset[j] = in[i];
167                 }
168
169                 if(instruction.sample)
170                 {
171                         sampleId = As<SIMD::Int>(in[i]);
172                 }
173
174                 SamplerCore s(constants, samplerState);
175
176                 // For explicit-lod instructions the LOD can be different per SIMD lane. SamplerCore currently assumes
177                 // a single LOD per four elements, so we sample the image again for each LOD separately.
178                 if(samplerFunction.method == Lod || samplerFunction.method == Grad)  // TODO(b/133868964): Also handle divergent Bias and Fetch with Lod.
179                 {
180                         auto lod = Pointer<Float>(&lodOrBias);
181
182                         For(Int i = 0, i < SIMD::Width, i++)
183                         {
184                                 SIMD::Float dPdx;
185                                 SIMD::Float dPdy;
186
187                                 dPdx.x = Pointer<Float>(&dsx.x)[i];
188                                 dPdx.y = Pointer<Float>(&dsx.y)[i];
189                                 dPdx.z = Pointer<Float>(&dsx.z)[i];
190
191                                 dPdy.x = Pointer<Float>(&dsy.x)[i];
192                                 dPdy.y = Pointer<Float>(&dsy.y)[i];
193                                 dPdy.z = Pointer<Float>(&dsy.z)[i];
194
195                                 // 1D textures are treated as 2D texture with second coordinate 0, so we also need to zero out the second grad component. TODO(b/134669567)
196                                 if(samplerState.textureType == VK_IMAGE_VIEW_TYPE_1D || samplerState.textureType == VK_IMAGE_VIEW_TYPE_1D_ARRAY)
197                                 {
198                                         dPdx.y = Float(0.0f);
199                                         dPdy.y = Float(0.0f);
200                                 }
201
202                                 Vector4f sample = s.sampleTexture(texture, uvw, q, lod[i], dPdx, dPdy, offset, sampleId, samplerFunction);
203
204                                 Pointer<Float> rgba = out;
205                                 rgba[0 * SIMD::Width + i] = Pointer<Float>(&sample.x)[i];
206                                 rgba[1 * SIMD::Width + i] = Pointer<Float>(&sample.y)[i];
207                                 rgba[2 * SIMD::Width + i] = Pointer<Float>(&sample.z)[i];
208                                 rgba[3 * SIMD::Width + i] = Pointer<Float>(&sample.w)[i];
209                         }
210                 }
211                 else
212                 {
213                         Vector4f sample = s.sampleTexture(texture, uvw, q, lodOrBias.x, (dsx.x), (dsy.x), offset, sampleId, samplerFunction);
214
215                         Pointer<SIMD::Float> rgba = out;
216                         rgba[0] = sample.x;
217                         rgba[1] = sample.y;
218                         rgba[2] = sample.z;
219                         rgba[3] = sample.w;
220                 }
221         }
222
223         return function("sampler");
224 }
225
226 sw::FilterType SpirvShader::convertFilterMode(const vk::Sampler *sampler)
227 {
228         if(sampler->anisotropyEnable != VK_FALSE)
229         {
230                 return FILTER_ANISOTROPIC;
231         }
232
233         switch(sampler->magFilter)
234         {
235                 case VK_FILTER_NEAREST:
236                         switch(sampler->minFilter)
237                         {
238                                 case VK_FILTER_NEAREST: return FILTER_POINT;
239                                 case VK_FILTER_LINEAR: return FILTER_MIN_LINEAR_MAG_POINT;
240                                 default:
241                                         UNSUPPORTED("minFilter %d", sampler->minFilter);
242                                         return FILTER_POINT;
243                         }
244                         break;
245                 case VK_FILTER_LINEAR:
246                         switch(sampler->minFilter)
247                         {
248                                 case VK_FILTER_NEAREST: return FILTER_MIN_POINT_MAG_LINEAR;
249                                 case VK_FILTER_LINEAR: return FILTER_LINEAR;
250                                 default:
251                                         UNSUPPORTED("minFilter %d", sampler->minFilter);
252                                         return FILTER_POINT;
253                         }
254                         break;
255                 default:
256                         break;
257         }
258
259         UNSUPPORTED("magFilter %d", sampler->magFilter);
260         return FILTER_POINT;
261 }
262
263 sw::MipmapType SpirvShader::convertMipmapMode(const vk::Sampler *sampler)
264 {
265         if(!sampler)
266         {
267                 return MIPMAP_POINT;  // Samplerless operations (OpImageFetch) can take an integer Lod operand.
268         }
269
270         if(sampler->ycbcrModel != VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY)
271         {
272                 // TODO(b/151263485): Check image view level count instead.
273                 return MIPMAP_NONE;
274         }
275
276         switch(sampler->mipmapMode)
277         {
278                 case VK_SAMPLER_MIPMAP_MODE_NEAREST: return MIPMAP_POINT;
279                 case VK_SAMPLER_MIPMAP_MODE_LINEAR: return MIPMAP_LINEAR;
280                 default:
281                         UNSUPPORTED("mipmapMode %d", sampler->mipmapMode);
282                         return MIPMAP_POINT;
283         }
284 }
285
286 sw::AddressingMode SpirvShader::convertAddressingMode(int coordinateIndex, const vk::Sampler *sampler, VkImageViewType imageViewType)
287 {
288         switch(imageViewType)
289         {
290                 case VK_IMAGE_VIEW_TYPE_CUBE_ARRAY:
291                         if(coordinateIndex == 3)
292                         {
293                                 return ADDRESSING_LAYER;
294                         }
295                         // Fall through to CUBE case:
296                 case VK_IMAGE_VIEW_TYPE_CUBE:
297                         if(coordinateIndex <= 1)  // Cube faces themselves are addressed as 2D images.
298                         {
299                                 // Vulkan 1.1 spec:
300                                 // "Cube images ignore the wrap modes specified in the sampler. Instead, if VK_FILTER_NEAREST is used within a mip level then
301                                 //  VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE is used, and if VK_FILTER_LINEAR is used within a mip level then sampling at the edges
302                                 //  is performed as described earlier in the Cube map edge handling section."
303                                 // This corresponds with our 'SEAMLESS' addressing mode.
304                                 return ADDRESSING_SEAMLESS;
305                         }
306                         else if(coordinateIndex == 2)
307                         {
308                                 // The cube face is an index into array layers.
309                                 return ADDRESSING_CUBEFACE;
310                         }
311                         else
312                         {
313                                 return ADDRESSING_UNUSED;
314                         }
315                         break;
316
317                 case VK_IMAGE_VIEW_TYPE_1D:  // Treated as 2D texture with second coordinate 0. TODO(b/134669567)
318                         if(coordinateIndex == 1)
319                         {
320                                 return ADDRESSING_WRAP;
321                         }
322                         else if(coordinateIndex >= 2)
323                         {
324                                 return ADDRESSING_UNUSED;
325                         }
326                         break;
327
328                 case VK_IMAGE_VIEW_TYPE_3D:
329                         if(coordinateIndex >= 3)
330                         {
331                                 return ADDRESSING_UNUSED;
332                         }
333                         break;
334
335                 case VK_IMAGE_VIEW_TYPE_1D_ARRAY:  // Treated as 2D texture with second coordinate 0. TODO(b/134669567)
336                         if(coordinateIndex == 1)
337                         {
338                                 return ADDRESSING_WRAP;
339                         }
340                         // Fall through to 2D_ARRAY case:
341                 case VK_IMAGE_VIEW_TYPE_2D_ARRAY:
342                         if(coordinateIndex == 2)
343                         {
344                                 return ADDRESSING_LAYER;
345                         }
346                         else if(coordinateIndex >= 3)
347                         {
348                                 return ADDRESSING_UNUSED;
349                         }
350                         // Fall through to 2D case:
351                 case VK_IMAGE_VIEW_TYPE_2D:
352                         if(coordinateIndex >= 2)
353                         {
354                                 return ADDRESSING_UNUSED;
355                         }
356                         break;
357
358                 default:
359                         UNSUPPORTED("imageViewType %d", imageViewType);
360                         return ADDRESSING_WRAP;
361         }
362
363         if(!sampler)
364         {
365                 // OpImageFetch does not take a sampler descriptor, but still needs a valid,
366                 // arbitrary addressing mode that prevents out-of-bounds accesses:
367                 // "The value returned by a read of an invalid texel is undefined, unless that
368                 //  read operation is from a buffer resource and the robustBufferAccess feature
369                 //  is enabled. In that case, an invalid texel is replaced as described by the
370                 //  robustBufferAccess feature." - Vulkan 1.1
371
372                 return ADDRESSING_WRAP;
373         }
374
375         VkSamplerAddressMode addressMode = VK_SAMPLER_ADDRESS_MODE_REPEAT;
376         switch(coordinateIndex)
377         {
378                 case 0: addressMode = sampler->addressModeU; break;
379                 case 1: addressMode = sampler->addressModeV; break;
380                 case 2: addressMode = sampler->addressModeW; break;
381                 default: UNSUPPORTED("coordinateIndex: %d", coordinateIndex);
382         }
383
384         switch(addressMode)
385         {
386                 case VK_SAMPLER_ADDRESS_MODE_REPEAT: return ADDRESSING_WRAP;
387                 case VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT: return ADDRESSING_MIRROR;
388                 case VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE: return ADDRESSING_CLAMP;
389                 case VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER: return ADDRESSING_BORDER;
390                 case VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE: return ADDRESSING_MIRRORONCE;
391                 default:
392                         UNSUPPORTED("addressMode %d", addressMode);
393                         return ADDRESSING_WRAP;
394         }
395 }
396
397 }  // namespace sw