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" << ssboFunction.type.getNominalSize()
74 << "(loc));\n";
75 }
76 }
77 else if (ssboFunction.type.isMatrix())
78 {
79 if (ssboFunction.rowMajor)
80 {
81 out << ";";
82 out << " float" << ssboFunction.type.getRows() << "x" << ssboFunction.type.getCols()
83 << " tmp_ = {";
84 for (int rowIndex = 0; rowIndex < ssboFunction.type.getRows(); rowIndex++)
85 {
86 out << "asfloat(buffer.Load" << ssboFunction.type.getCols() << "(loc + "
87 << rowIndex * ssboFunction.matrixStride << ")), ";
88 }
89 out << "};\n";
90 out << " result = transpose(tmp_);\n";
91 }
92 else
93 {
94 out << " = {";
95 for (int columnIndex = 0; columnIndex < ssboFunction.type.getCols(); columnIndex++)
96 {
97 out << "asfloat(buffer.Load" << ssboFunction.type.getRows() << "(loc + "
98 << 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" << ssboFunction.type.getNominalSize() << " _value;\n";
135 if (ssboFunction.type.getBasicType() == EbtBool)
136 {
137 out << " _value = uint" << ssboFunction.type.getNominalSize() << "(value);\n";
138 }
139 else
140 {
141 out << " _value = asuint(value);\n";
142 }
143
144 if (ssboFunction.rowMajor || !ssboFunction.isDefaultSwizzle)
145 {
146 size_t componentStride = bytesPerComponent;
147 if (ssboFunction.rowMajor)
148 {
149 componentStride = ssboFunction.matrixStride;
150 }
151 const TVector<int> &swizzleOffsets = ssboFunction.swizzleOffsets;
152 for (int index = 0; index < static_cast<int>(swizzleOffsets.size()); index++)
153 {
154 size_t offsetInBytes = swizzleOffsets[index] * componentStride;
155 out << "buffer.Store(loc + " << offsetInBytes << ", _value[" << index << "]);\n";
156 }
157 }
158 else
159 {
160 out << " buffer.Store" << ssboFunction.type.getNominalSize() << "(loc, _value);\n";
161 }
162 }
163 else if (ssboFunction.type.isMatrix())
164 {
165 if (ssboFunction.rowMajor)
166 {
167 out << " float" << ssboFunction.type.getRows() << "x" << ssboFunction.type.getCols()
168 << " tmp_ = transpose(value);\n";
169 for (int rowIndex = 0; rowIndex < ssboFunction.type.getRows(); rowIndex++)
170 {
171 out << " buffer.Store" << ssboFunction.type.getCols() << "(loc + "
172 << rowIndex * ssboFunction.matrixStride << ", asuint(tmp_[" << rowIndex
173 << "]));\n";
174 }
175 }
176 else
177 {
178 for (int columnIndex = 0; columnIndex < ssboFunction.type.getCols(); columnIndex++)
179 {
180 out << " buffer.Store" << ssboFunction.type.getRows() << "(loc + "
181 << columnIndex * ssboFunction.matrixStride << ", asuint(value[" << columnIndex
182 << "]));\n";
183 }
184 }
185 }
186 else
187 {
188 // TODO(jiajia.qin@intel.com): Process all possible return types. http://anglebug.com/1951
189 }
190 }
191
192 // static
OutputSSBOLengthFunctionBody(TInfoSinkBase & out,int unsizedArrayStride)193 void ShaderStorageBlockFunctionHLSL::OutputSSBOLengthFunctionBody(TInfoSinkBase &out,
194 int unsizedArrayStride)
195 {
196 out << " uint dim = 0;\n";
197 out << " buffer.GetDimensions(dim);\n";
198 out << " return int((dim - loc)/uint(" << unsizedArrayStride << "));\n";
199 }
200
201 // static
OutputSSBOAtomicMemoryFunctionBody(TInfoSinkBase & out,const ShaderStorageBlockFunction & ssboFunction)202 void ShaderStorageBlockFunctionHLSL::OutputSSBOAtomicMemoryFunctionBody(
203 TInfoSinkBase &out,
204 const ShaderStorageBlockFunction &ssboFunction)
205 {
206 out << " " << ssboFunction.typeString << " original_value;\n";
207 switch (ssboFunction.method)
208 {
209 case SSBOMethod::ATOMIC_ADD:
210 out << " buffer.InterlockedAdd(loc, value, original_value);\n";
211 break;
212 case SSBOMethod::ATOMIC_MIN:
213 out << " buffer.InterlockedMin(loc, value, original_value);\n";
214 break;
215 case SSBOMethod::ATOMIC_MAX:
216 out << " buffer.InterlockedMax(loc, value, original_value);\n";
217 break;
218 case SSBOMethod::ATOMIC_AND:
219 out << " buffer.InterlockedAnd(loc, value, original_value);\n";
220 break;
221 case SSBOMethod::ATOMIC_OR:
222 out << " buffer.InterlockedOr(loc, value, original_value);\n";
223 break;
224 case SSBOMethod::ATOMIC_XOR:
225 out << " buffer.InterlockedXor(loc, value, original_value);\n";
226 break;
227 case SSBOMethod::ATOMIC_EXCHANGE:
228 out << " buffer.InterlockedExchange(loc, value, original_value);\n";
229 break;
230 case SSBOMethod::ATOMIC_COMPSWAP:
231 out << " buffer.InterlockedCompareExchange(loc, compare_value, value, "
232 "original_value);\n";
233 break;
234 default:
235 UNREACHABLE();
236 }
237 out << " return original_value;\n";
238 }
239
operator <(const ShaderStorageBlockFunction & rhs) const240 bool ShaderStorageBlockFunctionHLSL::ShaderStorageBlockFunction::operator<(
241 const ShaderStorageBlockFunction &rhs) const
242 {
243 return functionName < rhs.functionName;
244 }
245
registerShaderStorageBlockFunction(const TType & type,SSBOMethod method,TLayoutBlockStorage storage,bool rowMajor,int matrixStride,int unsizedArrayStride,TIntermSwizzle * swizzleNode)246 TString ShaderStorageBlockFunctionHLSL::registerShaderStorageBlockFunction(
247 const TType &type,
248 SSBOMethod method,
249 TLayoutBlockStorage storage,
250 bool rowMajor,
251 int matrixStride,
252 int unsizedArrayStride,
253 TIntermSwizzle *swizzleNode)
254 {
255 ShaderStorageBlockFunction ssboFunction;
256 ssboFunction.typeString = TypeString(type);
257 ssboFunction.method = method;
258 switch (method)
259 {
260 case SSBOMethod::LOAD:
261 ssboFunction.functionName = "_Load_";
262 break;
263 case SSBOMethod::STORE:
264 ssboFunction.functionName = "_Store_";
265 break;
266 case SSBOMethod::LENGTH:
267 ssboFunction.unsizedArrayStride = unsizedArrayStride;
268 ssboFunction.functionName = "_Length_" + str(unsizedArrayStride);
269 mRegisteredShaderStorageBlockFunctions.insert(ssboFunction);
270 return ssboFunction.functionName;
271 case SSBOMethod::ATOMIC_ADD:
272 ssboFunction.functionName = "_ssbo_atomicAdd_" + ssboFunction.typeString;
273 mRegisteredShaderStorageBlockFunctions.insert(ssboFunction);
274 return ssboFunction.functionName;
275 case SSBOMethod::ATOMIC_MIN:
276 ssboFunction.functionName = "_ssbo_atomicMin_" + ssboFunction.typeString;
277 mRegisteredShaderStorageBlockFunctions.insert(ssboFunction);
278 return ssboFunction.functionName;
279 case SSBOMethod::ATOMIC_MAX:
280 ssboFunction.functionName = "_ssbo_atomicMax_" + ssboFunction.typeString;
281 mRegisteredShaderStorageBlockFunctions.insert(ssboFunction);
282 return ssboFunction.functionName;
283 case SSBOMethod::ATOMIC_AND:
284 ssboFunction.functionName = "_ssbo_atomicAnd_" + ssboFunction.typeString;
285 mRegisteredShaderStorageBlockFunctions.insert(ssboFunction);
286 return ssboFunction.functionName;
287 case SSBOMethod::ATOMIC_OR:
288 ssboFunction.functionName = "_ssbo_atomicOr_" + ssboFunction.typeString;
289 mRegisteredShaderStorageBlockFunctions.insert(ssboFunction);
290 return ssboFunction.functionName;
291 case SSBOMethod::ATOMIC_XOR:
292 ssboFunction.functionName = "_ssbo_atomicXor_" + ssboFunction.typeString;
293 mRegisteredShaderStorageBlockFunctions.insert(ssboFunction);
294 return ssboFunction.functionName;
295 case SSBOMethod::ATOMIC_EXCHANGE:
296 ssboFunction.functionName = "_ssbo_atomicExchange_" + ssboFunction.typeString;
297 mRegisteredShaderStorageBlockFunctions.insert(ssboFunction);
298 return ssboFunction.functionName;
299 case SSBOMethod::ATOMIC_COMPSWAP:
300 ssboFunction.functionName = "_ssbo_atomicCompSwap_" + ssboFunction.typeString;
301 mRegisteredShaderStorageBlockFunctions.insert(ssboFunction);
302 return ssboFunction.functionName;
303 default:
304 UNREACHABLE();
305 }
306
307 ssboFunction.functionName += ssboFunction.typeString;
308 ssboFunction.type = type;
309 if (swizzleNode != nullptr)
310 {
311 ssboFunction.swizzleOffsets = swizzleNode->getSwizzleOffsets();
312 ssboFunction.isDefaultSwizzle = false;
313 }
314 else
315 {
316 if (ssboFunction.type.getNominalSize() > 1)
317 {
318 for (int index = 0; index < ssboFunction.type.getNominalSize(); index++)
319 {
320 ssboFunction.swizzleOffsets.push_back(index);
321 }
322 }
323 else
324 {
325 ssboFunction.swizzleOffsets.push_back(0);
326 }
327
328 ssboFunction.isDefaultSwizzle = true;
329 }
330 ssboFunction.rowMajor = rowMajor;
331 ssboFunction.matrixStride = matrixStride;
332 ssboFunction.functionName += "_" + TString(getBlockStorageString(storage));
333
334 if (rowMajor)
335 {
336 ssboFunction.functionName += "_rm_";
337 }
338 else
339 {
340 ssboFunction.functionName += "_cm_";
341 }
342
343 for (const int offset : ssboFunction.swizzleOffsets)
344 {
345 switch (offset)
346 {
347 case 0:
348 ssboFunction.functionName += "x";
349 break;
350 case 1:
351 ssboFunction.functionName += "y";
352 break;
353 case 2:
354 ssboFunction.functionName += "z";
355 break;
356 case 3:
357 ssboFunction.functionName += "w";
358 break;
359 default:
360 UNREACHABLE();
361 }
362 }
363
364 mRegisteredShaderStorageBlockFunctions.insert(ssboFunction);
365 return ssboFunction.functionName;
366 }
367
shaderStorageBlockFunctionHeader(TInfoSinkBase & out)368 void ShaderStorageBlockFunctionHLSL::shaderStorageBlockFunctionHeader(TInfoSinkBase &out)
369 {
370 for (const ShaderStorageBlockFunction &ssboFunction : mRegisteredShaderStorageBlockFunctions)
371 {
372 switch (ssboFunction.method)
373 {
374 case SSBOMethod::LOAD:
375 {
376 // Function header
377 out << ssboFunction.typeString << " " << ssboFunction.functionName
378 << "(RWByteAddressBuffer buffer, uint loc)\n";
379 out << "{\n";
380 OutputSSBOLoadFunctionBody(out, ssboFunction);
381 break;
382 }
383 case SSBOMethod::STORE:
384 {
385 // Function header
386 out << "void " << ssboFunction.functionName
387 << "(RWByteAddressBuffer buffer, uint loc, " << ssboFunction.typeString
388 << " value)\n";
389 out << "{\n";
390 OutputSSBOStoreFunctionBody(out, ssboFunction);
391 break;
392 }
393 case SSBOMethod::LENGTH:
394 {
395 out << "int " << ssboFunction.functionName
396 << "(RWByteAddressBuffer buffer, uint loc)\n";
397 out << "{\n";
398 OutputSSBOLengthFunctionBody(out, ssboFunction.unsizedArrayStride);
399 break;
400 }
401 case SSBOMethod::ATOMIC_ADD:
402 case SSBOMethod::ATOMIC_MIN:
403 case SSBOMethod::ATOMIC_MAX:
404 case SSBOMethod::ATOMIC_AND:
405 case SSBOMethod::ATOMIC_OR:
406 case SSBOMethod::ATOMIC_XOR:
407 case SSBOMethod::ATOMIC_EXCHANGE:
408 {
409 out << ssboFunction.typeString << " " << ssboFunction.functionName
410 << "(RWByteAddressBuffer buffer, uint loc, " << ssboFunction.typeString
411 << " value)\n";
412 out << "{\n";
413
414 OutputSSBOAtomicMemoryFunctionBody(out, ssboFunction);
415 break;
416 }
417 case SSBOMethod::ATOMIC_COMPSWAP:
418 {
419 out << ssboFunction.typeString << " " << ssboFunction.functionName
420 << "(RWByteAddressBuffer buffer, uint loc, " << ssboFunction.typeString
421 << " compare_value, " << ssboFunction.typeString << " value)\n";
422 out << "{\n";
423 OutputSSBOAtomicMemoryFunctionBody(out, ssboFunction);
424 break;
425 }
426 default:
427 UNREACHABLE();
428 }
429
430 out << "}\n"
431 "\n";
432 }
433 }
434
435 } // namespace sh
436