1 //
2 // Copyright 2018 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // ShaderStorageBlockFunctionHLSL: Wrapper functions for RWByteAddressBuffer Load/Store functions.
7 //
8
9 #include "compiler/translator/ShaderStorageBlockFunctionHLSL.h"
10
11 #include "common/utilities.h"
12 #include "compiler/translator/UtilsHLSL.h"
13 #include "compiler/translator/blocklayout.h"
14 #include "compiler/translator/blocklayoutHLSL.h"
15 #include "compiler/translator/util.h"
16
17 namespace sh
18 {
19
20 // static
OutputSSBOLoadFunctionBody(TInfoSinkBase & out,const ShaderStorageBlockFunction & ssboFunction)21 void ShaderStorageBlockFunctionHLSL::OutputSSBOLoadFunctionBody(
22 TInfoSinkBase &out,
23 const ShaderStorageBlockFunction &ssboFunction)
24 {
25 const char *convertString;
26 switch (ssboFunction.type.getBasicType())
27 {
28 case EbtFloat:
29 convertString = "asfloat(";
30 break;
31 case EbtInt:
32 convertString = "asint(";
33 break;
34 case EbtUInt:
35 convertString = "asuint(";
36 break;
37 case EbtBool:
38 convertString = "asint(";
39 break;
40 default:
41 UNREACHABLE();
42 return;
43 }
44
45 size_t bytesPerComponent =
46 gl::VariableComponentSize(gl::VariableComponentType(GLVariableType(ssboFunction.type)));
47 out << " " << ssboFunction.typeString << " result";
48 if (ssboFunction.type.isScalar())
49 {
50 size_t offset = ssboFunction.swizzleOffsets[0] * bytesPerComponent;
51 out << " = " << convertString << "buffer.Load(loc + " << offset << "));\n ";
52 }
53 else if (ssboFunction.type.isVector())
54 {
55 if (ssboFunction.rowMajor || !ssboFunction.isDefaultSwizzle)
56 {
57 size_t componentStride = bytesPerComponent;
58 if (ssboFunction.rowMajor)
59 {
60 componentStride = ssboFunction.matrixStride;
61 }
62
63 out << " = {";
64 for (const int offset : ssboFunction.swizzleOffsets)
65 {
66 size_t offsetInBytes = offset * componentStride;
67 out << convertString << "buffer.Load(loc + " << offsetInBytes << ")),";
68 }
69 out << "};\n";
70 }
71 else
72 {
73 out << " = " << convertString << "buffer.Load"
74 << static_cast<uint32_t>(ssboFunction.type.getNominalSize()) << "(loc));\n";
75 }
76 }
77 else if (ssboFunction.type.isMatrix())
78 {
79 if (ssboFunction.rowMajor)
80 {
81 out << ";";
82 out << " float" << static_cast<uint32_t>(ssboFunction.type.getRows()) << "x"
83 << static_cast<uint32_t>(ssboFunction.type.getCols()) << " tmp_ = {";
84 for (uint8_t rowIndex = 0; rowIndex < ssboFunction.type.getRows(); rowIndex++)
85 {
86 out << "asfloat(buffer.Load" << static_cast<uint32_t>(ssboFunction.type.getCols())
87 << "(loc + " << rowIndex * ssboFunction.matrixStride << ")), ";
88 }
89 out << "};\n";
90 out << " result = transpose(tmp_);\n";
91 }
92 else
93 {
94 out << " = {";
95 for (uint8_t columnIndex = 0; columnIndex < ssboFunction.type.getCols(); columnIndex++)
96 {
97 out << "asfloat(buffer.Load" << static_cast<uint32_t>(ssboFunction.type.getRows())
98 << "(loc + " << columnIndex * ssboFunction.matrixStride << ")), ";
99 }
100 out << "};\n";
101 }
102 }
103 else
104 {
105 // TODO(jiajia.qin@intel.com): Process all possible return types. http://anglebug.com/1951
106 out << ";\n";
107 }
108
109 out << " return result;\n";
110 return;
111 }
112
113 // static
OutputSSBOStoreFunctionBody(TInfoSinkBase & out,const ShaderStorageBlockFunction & ssboFunction)114 void ShaderStorageBlockFunctionHLSL::OutputSSBOStoreFunctionBody(
115 TInfoSinkBase &out,
116 const ShaderStorageBlockFunction &ssboFunction)
117 {
118 size_t bytesPerComponent =
119 gl::VariableComponentSize(gl::VariableComponentType(GLVariableType(ssboFunction.type)));
120 if (ssboFunction.type.isScalar())
121 {
122 size_t offset = ssboFunction.swizzleOffsets[0] * bytesPerComponent;
123 if (ssboFunction.type.getBasicType() == EbtBool)
124 {
125 out << " buffer.Store(loc + " << offset << ", uint(value));\n";
126 }
127 else
128 {
129 out << " buffer.Store(loc + " << offset << ", asuint(value));\n";
130 }
131 }
132 else if (ssboFunction.type.isVector())
133 {
134 out << " uint" << static_cast<uint32_t>(ssboFunction.type.getNominalSize())
135 << " _value;\n";
136 if (ssboFunction.type.getBasicType() == EbtBool)
137 {
138 out << " _value = uint" << static_cast<uint32_t>(ssboFunction.type.getNominalSize())
139 << "(value);\n";
140 }
141 else
142 {
143 out << " _value = asuint(value);\n";
144 }
145
146 if (ssboFunction.rowMajor || !ssboFunction.isDefaultSwizzle)
147 {
148 size_t componentStride = bytesPerComponent;
149 if (ssboFunction.rowMajor)
150 {
151 componentStride = ssboFunction.matrixStride;
152 }
153 const TVector<int> &swizzleOffsets = ssboFunction.swizzleOffsets;
154 for (int index = 0; index < static_cast<int>(swizzleOffsets.size()); index++)
155 {
156 size_t offsetInBytes = swizzleOffsets[index] * componentStride;
157 out << "buffer.Store(loc + " << offsetInBytes << ", _value[" << index << "]);\n";
158 }
159 }
160 else
161 {
162 out << " buffer.Store" << static_cast<uint32_t>(ssboFunction.type.getNominalSize())
163 << "(loc, _value);\n";
164 }
165 }
166 else if (ssboFunction.type.isMatrix())
167 {
168 if (ssboFunction.rowMajor)
169 {
170 out << " float" << static_cast<uint32_t>(ssboFunction.type.getRows()) << "x"
171 << static_cast<uint32_t>(ssboFunction.type.getCols())
172 << " tmp_ = transpose(value);\n";
173 for (uint8_t rowIndex = 0; rowIndex < ssboFunction.type.getRows(); rowIndex++)
174 {
175 out << " buffer.Store" << static_cast<uint32_t>(ssboFunction.type.getCols())
176 << "(loc + " << rowIndex * ssboFunction.matrixStride << ", asuint(tmp_["
177 << static_cast<uint32_t>(rowIndex) << "]));\n";
178 }
179 }
180 else
181 {
182 for (uint8_t columnIndex = 0; columnIndex < ssboFunction.type.getCols(); columnIndex++)
183 {
184 out << " buffer.Store" << static_cast<uint32_t>(ssboFunction.type.getRows())
185 << "(loc + " << columnIndex * ssboFunction.matrixStride << ", asuint(value["
186 << static_cast<uint32_t>(columnIndex) << "]));\n";
187 }
188 }
189 }
190 else
191 {
192 // TODO(jiajia.qin@intel.com): Process all possible return types. http://anglebug.com/1951
193 }
194 }
195
196 // static
OutputSSBOLengthFunctionBody(TInfoSinkBase & out,int unsizedArrayStride)197 void ShaderStorageBlockFunctionHLSL::OutputSSBOLengthFunctionBody(TInfoSinkBase &out,
198 int unsizedArrayStride)
199 {
200 out << " uint dim = 0;\n";
201 out << " buffer.GetDimensions(dim);\n";
202 out << " return int((dim - loc)/uint(" << unsizedArrayStride << "));\n";
203 }
204
205 // static
OutputSSBOAtomicMemoryFunctionBody(TInfoSinkBase & out,const ShaderStorageBlockFunction & ssboFunction)206 void ShaderStorageBlockFunctionHLSL::OutputSSBOAtomicMemoryFunctionBody(
207 TInfoSinkBase &out,
208 const ShaderStorageBlockFunction &ssboFunction)
209 {
210 out << " " << ssboFunction.typeString << " original_value;\n";
211 switch (ssboFunction.method)
212 {
213 case SSBOMethod::ATOMIC_ADD:
214 out << " buffer.InterlockedAdd(loc, value, original_value);\n";
215 break;
216 case SSBOMethod::ATOMIC_MIN:
217 out << " buffer.InterlockedMin(loc, value, original_value);\n";
218 break;
219 case SSBOMethod::ATOMIC_MAX:
220 out << " buffer.InterlockedMax(loc, value, original_value);\n";
221 break;
222 case SSBOMethod::ATOMIC_AND:
223 out << " buffer.InterlockedAnd(loc, value, original_value);\n";
224 break;
225 case SSBOMethod::ATOMIC_OR:
226 out << " buffer.InterlockedOr(loc, value, original_value);\n";
227 break;
228 case SSBOMethod::ATOMIC_XOR:
229 out << " buffer.InterlockedXor(loc, value, original_value);\n";
230 break;
231 case SSBOMethod::ATOMIC_EXCHANGE:
232 out << " buffer.InterlockedExchange(loc, value, original_value);\n";
233 break;
234 case SSBOMethod::ATOMIC_COMPSWAP:
235 out << " buffer.InterlockedCompareExchange(loc, compare_value, value, "
236 "original_value);\n";
237 break;
238 default:
239 UNREACHABLE();
240 }
241 out << " return original_value;\n";
242 }
243
operator <(const ShaderStorageBlockFunction & rhs) const244 bool ShaderStorageBlockFunctionHLSL::ShaderStorageBlockFunction::operator<(
245 const ShaderStorageBlockFunction &rhs) const
246 {
247 return functionName < rhs.functionName;
248 }
249
registerShaderStorageBlockFunction(const TType & type,SSBOMethod method,TLayoutBlockStorage storage,bool rowMajor,int matrixStride,int unsizedArrayStride,TIntermSwizzle * swizzleNode)250 TString ShaderStorageBlockFunctionHLSL::registerShaderStorageBlockFunction(
251 const TType &type,
252 SSBOMethod method,
253 TLayoutBlockStorage storage,
254 bool rowMajor,
255 int matrixStride,
256 int unsizedArrayStride,
257 TIntermSwizzle *swizzleNode)
258 {
259 ShaderStorageBlockFunction ssboFunction;
260 ssboFunction.typeString = TypeString(type);
261 ssboFunction.method = method;
262 switch (method)
263 {
264 case SSBOMethod::LOAD:
265 ssboFunction.functionName = "_Load_";
266 break;
267 case SSBOMethod::STORE:
268 ssboFunction.functionName = "_Store_";
269 break;
270 case SSBOMethod::LENGTH:
271 ssboFunction.unsizedArrayStride = unsizedArrayStride;
272 ssboFunction.functionName = "_Length_" + str(unsizedArrayStride);
273 mRegisteredShaderStorageBlockFunctions.insert(ssboFunction);
274 return ssboFunction.functionName;
275 case SSBOMethod::ATOMIC_ADD:
276 ssboFunction.functionName = "_ssbo_atomicAdd_" + ssboFunction.typeString;
277 mRegisteredShaderStorageBlockFunctions.insert(ssboFunction);
278 return ssboFunction.functionName;
279 case SSBOMethod::ATOMIC_MIN:
280 ssboFunction.functionName = "_ssbo_atomicMin_" + ssboFunction.typeString;
281 mRegisteredShaderStorageBlockFunctions.insert(ssboFunction);
282 return ssboFunction.functionName;
283 case SSBOMethod::ATOMIC_MAX:
284 ssboFunction.functionName = "_ssbo_atomicMax_" + ssboFunction.typeString;
285 mRegisteredShaderStorageBlockFunctions.insert(ssboFunction);
286 return ssboFunction.functionName;
287 case SSBOMethod::ATOMIC_AND:
288 ssboFunction.functionName = "_ssbo_atomicAnd_" + ssboFunction.typeString;
289 mRegisteredShaderStorageBlockFunctions.insert(ssboFunction);
290 return ssboFunction.functionName;
291 case SSBOMethod::ATOMIC_OR:
292 ssboFunction.functionName = "_ssbo_atomicOr_" + ssboFunction.typeString;
293 mRegisteredShaderStorageBlockFunctions.insert(ssboFunction);
294 return ssboFunction.functionName;
295 case SSBOMethod::ATOMIC_XOR:
296 ssboFunction.functionName = "_ssbo_atomicXor_" + ssboFunction.typeString;
297 mRegisteredShaderStorageBlockFunctions.insert(ssboFunction);
298 return ssboFunction.functionName;
299 case SSBOMethod::ATOMIC_EXCHANGE:
300 ssboFunction.functionName = "_ssbo_atomicExchange_" + ssboFunction.typeString;
301 mRegisteredShaderStorageBlockFunctions.insert(ssboFunction);
302 return ssboFunction.functionName;
303 case SSBOMethod::ATOMIC_COMPSWAP:
304 ssboFunction.functionName = "_ssbo_atomicCompSwap_" + ssboFunction.typeString;
305 mRegisteredShaderStorageBlockFunctions.insert(ssboFunction);
306 return ssboFunction.functionName;
307 default:
308 UNREACHABLE();
309 }
310
311 ssboFunction.functionName += ssboFunction.typeString;
312 ssboFunction.type = type;
313 if (swizzleNode != nullptr)
314 {
315 ssboFunction.swizzleOffsets = swizzleNode->getSwizzleOffsets();
316 ssboFunction.isDefaultSwizzle = false;
317 }
318 else
319 {
320 if (ssboFunction.type.getNominalSize() > 1)
321 {
322 for (uint8_t index = 0; index < ssboFunction.type.getNominalSize(); index++)
323 {
324 ssboFunction.swizzleOffsets.push_back(index);
325 }
326 }
327 else
328 {
329 ssboFunction.swizzleOffsets.push_back(0);
330 }
331
332 ssboFunction.isDefaultSwizzle = true;
333 }
334 ssboFunction.rowMajor = rowMajor;
335 ssboFunction.matrixStride = matrixStride;
336 ssboFunction.functionName += "_" + TString(getBlockStorageString(storage));
337
338 if (rowMajor)
339 {
340 ssboFunction.functionName += "_rm_";
341 }
342 else
343 {
344 ssboFunction.functionName += "_cm_";
345 }
346
347 for (const int offset : ssboFunction.swizzleOffsets)
348 {
349 switch (offset)
350 {
351 case 0:
352 ssboFunction.functionName += "x";
353 break;
354 case 1:
355 ssboFunction.functionName += "y";
356 break;
357 case 2:
358 ssboFunction.functionName += "z";
359 break;
360 case 3:
361 ssboFunction.functionName += "w";
362 break;
363 default:
364 UNREACHABLE();
365 }
366 }
367
368 mRegisteredShaderStorageBlockFunctions.insert(ssboFunction);
369 return ssboFunction.functionName;
370 }
371
shaderStorageBlockFunctionHeader(TInfoSinkBase & out)372 void ShaderStorageBlockFunctionHLSL::shaderStorageBlockFunctionHeader(TInfoSinkBase &out)
373 {
374 for (const ShaderStorageBlockFunction &ssboFunction : mRegisteredShaderStorageBlockFunctions)
375 {
376 switch (ssboFunction.method)
377 {
378 case SSBOMethod::LOAD:
379 {
380 // Function header
381 out << ssboFunction.typeString << " " << ssboFunction.functionName
382 << "(RWByteAddressBuffer buffer, uint loc)\n";
383 out << "{\n";
384 OutputSSBOLoadFunctionBody(out, ssboFunction);
385 break;
386 }
387 case SSBOMethod::STORE:
388 {
389 // Function header
390 out << "void " << ssboFunction.functionName
391 << "(RWByteAddressBuffer buffer, uint loc, " << ssboFunction.typeString
392 << " value)\n";
393 out << "{\n";
394 OutputSSBOStoreFunctionBody(out, ssboFunction);
395 break;
396 }
397 case SSBOMethod::LENGTH:
398 {
399 out << "int " << ssboFunction.functionName
400 << "(RWByteAddressBuffer buffer, uint loc)\n";
401 out << "{\n";
402 OutputSSBOLengthFunctionBody(out, ssboFunction.unsizedArrayStride);
403 break;
404 }
405 case SSBOMethod::ATOMIC_ADD:
406 case SSBOMethod::ATOMIC_MIN:
407 case SSBOMethod::ATOMIC_MAX:
408 case SSBOMethod::ATOMIC_AND:
409 case SSBOMethod::ATOMIC_OR:
410 case SSBOMethod::ATOMIC_XOR:
411 case SSBOMethod::ATOMIC_EXCHANGE:
412 {
413 out << ssboFunction.typeString << " " << ssboFunction.functionName
414 << "(RWByteAddressBuffer buffer, uint loc, " << ssboFunction.typeString
415 << " value)\n";
416 out << "{\n";
417
418 OutputSSBOAtomicMemoryFunctionBody(out, ssboFunction);
419 break;
420 }
421 case SSBOMethod::ATOMIC_COMPSWAP:
422 {
423 out << ssboFunction.typeString << " " << ssboFunction.functionName
424 << "(RWByteAddressBuffer buffer, uint loc, " << ssboFunction.typeString
425 << " compare_value, " << ssboFunction.typeString << " value)\n";
426 out << "{\n";
427 OutputSSBOAtomicMemoryFunctionBody(out, ssboFunction);
428 break;
429 }
430 default:
431 UNREACHABLE();
432 }
433
434 out << "}\n"
435 "\n";
436 }
437 }
438
439 } // namespace sh
440