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