xref: /aosp_15_r20/external/angle/src/compiler/translator/hlsl/ResourcesHLSL.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1 //
2 // Copyright 2014 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 // ResourcesHLSL.cpp:
7 //   Methods for GLSL to HLSL translation for uniforms and interface blocks.
8 //
9 
10 #include "compiler/translator/hlsl/ResourcesHLSL.h"
11 
12 #include "common/utilities.h"
13 #include "compiler/translator/ImmutableStringBuilder.h"
14 #include "compiler/translator/hlsl/AtomicCounterFunctionHLSL.h"
15 #include "compiler/translator/hlsl/StructureHLSL.h"
16 #include "compiler/translator/hlsl/UtilsHLSL.h"
17 #include "compiler/translator/hlsl/blocklayoutHLSL.h"
18 #include "compiler/translator/util.h"
19 
20 namespace sh
21 {
22 
23 namespace
24 {
25 
26 constexpr const ImmutableString kAngleDecorString("angle_");
27 
UniformRegisterPrefix(const TType & type)28 static const char *UniformRegisterPrefix(const TType &type)
29 {
30     if (IsSampler(type.getBasicType()))
31     {
32         return "s";
33     }
34     else
35     {
36         return "c";
37     }
38 }
39 
InterfaceBlockFieldTypeString(const TField & field,TLayoutBlockStorage blockStorage,bool usedStructuredbuffer)40 static TString InterfaceBlockFieldTypeString(const TField &field,
41                                              TLayoutBlockStorage blockStorage,
42                                              bool usedStructuredbuffer)
43 {
44     const TType &fieldType                   = *field.type();
45     const TLayoutMatrixPacking matrixPacking = fieldType.getLayoutQualifier().matrixPacking;
46     ASSERT(matrixPacking != EmpUnspecified);
47     const TStructure *structure = fieldType.getStruct();
48 
49     if (fieldType.isMatrix())
50     {
51         // Use HLSL row-major packing for GLSL column-major matrices
52         const TString &matrixPackString =
53             (matrixPacking == EmpRowMajor ? "column_major" : "row_major");
54         return matrixPackString + " " + TypeString(fieldType);
55     }
56     else if (structure)
57     {
58         // If uniform block's layout is std140 and translating it to StructuredBuffer,
59         // should pack structure in the end, in order to fit API buffer.
60         bool forcePackingEnd = usedStructuredbuffer && (blockStorage == EbsStd140);
61         // Use HLSL row-major packing for GLSL column-major matrices
62         return QualifiedStructNameString(*structure, matrixPacking == EmpColumnMajor,
63                                          blockStorage == EbsStd140, forcePackingEnd);
64     }
65     else
66     {
67         return TypeString(fieldType);
68     }
69 }
70 
InterfaceBlockStructName(const TInterfaceBlock & interfaceBlock)71 static TString InterfaceBlockStructName(const TInterfaceBlock &interfaceBlock)
72 {
73     return DecoratePrivate(interfaceBlock.name()) + "_type";
74 }
75 
OutputUniformIndexArrayInitializer(TInfoSinkBase & out,const TType & type,unsigned int startIndex)76 void OutputUniformIndexArrayInitializer(TInfoSinkBase &out,
77                                         const TType &type,
78                                         unsigned int startIndex)
79 {
80     out << "{";
81     TType elementType(type);
82     elementType.toArrayElementType();
83     for (unsigned int i = 0u; i < type.getOutermostArraySize(); ++i)
84     {
85         if (i > 0u)
86         {
87             out << ", ";
88         }
89         if (elementType.isArray())
90         {
91             OutputUniformIndexArrayInitializer(out, elementType,
92                                                startIndex + i * elementType.getArraySizeProduct());
93         }
94         else
95         {
96             out << (startIndex + i);
97         }
98     }
99     out << "}";
100 }
101 
InterfaceBlockScalarVectorFieldPaddingString(const TType & type)102 static TString InterfaceBlockScalarVectorFieldPaddingString(const TType &type)
103 {
104     switch (type.getBasicType())
105     {
106         case EbtFloat:
107             switch (type.getNominalSize())
108             {
109                 case 1:
110                     return "float3 padding;";
111                 case 2:
112                     return "float2 padding;";
113                 case 3:
114                     return "float padding;";
115                 default:
116                     break;
117             }
118             break;
119         case EbtInt:
120             switch (type.getNominalSize())
121             {
122                 case 1:
123                     return "int3 padding;";
124                 case 2:
125                     return "int2 padding;";
126                 case 3:
127                     return "int padding";
128                 default:
129                     break;
130             }
131             break;
132         case EbtUInt:
133             switch (type.getNominalSize())
134             {
135                 case 1:
136                     return "uint3 padding;";
137                 case 2:
138                     return "uint2 padding;";
139                 case 3:
140                     return "uint padding;";
141                 default:
142                     break;
143             }
144             break;
145         case EbtBool:
146             switch (type.getNominalSize())
147             {
148                 case 1:
149                     return "bool3 padding;";
150                 case 2:
151                     return "bool2 padding;";
152                 case 3:
153                     return "bool padding;";
154                 default:
155                     break;
156             }
157             break;
158         default:
159             break;
160     }
161     return "";
162 }
163 
IsAnyRasterOrdered(const TVector<const TVariable * > & imageVars)164 static bool IsAnyRasterOrdered(const TVector<const TVariable *> &imageVars)
165 {
166     for (const TVariable *imageVar : imageVars)
167     {
168         if (imageVar->getType().getLayoutQualifier().rasterOrdered)
169         {
170             return true;
171         }
172     }
173     return false;
174 }
175 
176 }  // anonymous namespace
177 
ResourcesHLSL(StructureHLSL * structureHLSL,ShShaderOutput outputType,const std::vector<ShaderVariable> & uniforms,unsigned int firstUniformRegister)178 ResourcesHLSL::ResourcesHLSL(StructureHLSL *structureHLSL,
179                              ShShaderOutput outputType,
180                              const std::vector<ShaderVariable> &uniforms,
181                              unsigned int firstUniformRegister)
182     : mUniformRegister(firstUniformRegister),
183       mUniformBlockRegister(0),
184       mSRVRegister(0),
185       mUAVRegister(0),
186       mSamplerCount(0),
187       mStructureHLSL(structureHLSL),
188       mOutputType(outputType),
189       mUniforms(uniforms)
190 {}
191 
reserveUniformRegisters(unsigned int registerCount)192 void ResourcesHLSL::reserveUniformRegisters(unsigned int registerCount)
193 {
194     mUniformRegister = registerCount;
195 }
196 
reserveUniformBlockRegisters(unsigned int registerCount)197 void ResourcesHLSL::reserveUniformBlockRegisters(unsigned int registerCount)
198 {
199     mUniformBlockRegister = registerCount;
200 }
201 
findUniformByName(const ImmutableString & name) const202 const ShaderVariable *ResourcesHLSL::findUniformByName(const ImmutableString &name) const
203 {
204     for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); ++uniformIndex)
205     {
206         if (name == mUniforms[uniformIndex].name)
207         {
208             return &mUniforms[uniformIndex];
209         }
210     }
211 
212     return nullptr;
213 }
214 
assignUniformRegister(const TType & type,const ImmutableString & name,unsigned int * outRegisterCount)215 unsigned int ResourcesHLSL::assignUniformRegister(const TType &type,
216                                                   const ImmutableString &name,
217                                                   unsigned int *outRegisterCount)
218 {
219     unsigned int registerIndex;
220     const ShaderVariable *uniform = findUniformByName(name);
221     ASSERT(uniform);
222 
223     if (IsSampler(type.getBasicType()) ||
224         (IsImage(type.getBasicType()) && type.getMemoryQualifier().readonly))
225     {
226         registerIndex = mSRVRegister;
227     }
228     else if (IsImage(type.getBasicType()))
229     {
230         registerIndex = mUAVRegister;
231     }
232     else
233     {
234         registerIndex = mUniformRegister;
235     }
236 
237     if (uniform->name == "angle_DrawID" && uniform->mappedName == "angle_DrawID")
238     {
239         mUniformRegisterMap["gl_DrawID"] = registerIndex;
240     }
241     else
242     {
243         mUniformRegisterMap[uniform->name] = registerIndex;
244     }
245 
246     if (uniform->name == "angle_BaseVertex" && uniform->mappedName == "angle_BaseVertex")
247     {
248         mUniformRegisterMap["gl_BaseVertex"] = registerIndex;
249     }
250     else
251     {
252         mUniformRegisterMap[uniform->name] = registerIndex;
253     }
254 
255     if (uniform->name == "angle_BaseInstance" && uniform->mappedName == "angle_BaseInstance")
256     {
257         mUniformRegisterMap["gl_BaseInstance"] = registerIndex;
258     }
259     else
260     {
261         mUniformRegisterMap[uniform->name] = registerIndex;
262     }
263 
264     unsigned int registerCount = HLSLVariableRegisterCount(*uniform, mOutputType);
265 
266     if (IsSampler(type.getBasicType()) ||
267         (IsImage(type.getBasicType()) && type.getMemoryQualifier().readonly))
268     {
269         mSRVRegister += registerCount;
270     }
271     else if (IsImage(type.getBasicType()))
272     {
273         mUAVRegister += registerCount;
274     }
275     else
276     {
277         mUniformRegister += registerCount;
278     }
279     if (outRegisterCount)
280     {
281         *outRegisterCount = registerCount;
282     }
283     return registerIndex;
284 }
285 
assignSamplerInStructUniformRegister(const TType & type,const TString & name,unsigned int * outRegisterCount)286 unsigned int ResourcesHLSL::assignSamplerInStructUniformRegister(const TType &type,
287                                                                  const TString &name,
288                                                                  unsigned int *outRegisterCount)
289 {
290     // Sampler that is a field of a uniform structure.
291     ASSERT(IsSampler(type.getBasicType()));
292     unsigned int registerIndex                     = mSRVRegister;
293     mUniformRegisterMap[std::string(name.c_str())] = registerIndex;
294     unsigned int registerCount = type.isArray() ? type.getArraySizeProduct() : 1u;
295     mSRVRegister += registerCount;
296     if (outRegisterCount)
297     {
298         *outRegisterCount = registerCount;
299     }
300     return registerIndex;
301 }
302 
outputHLSLSamplerUniformGroup(TInfoSinkBase & out,const HLSLTextureGroup textureGroup,const TVector<const TVariable * > & group,const TMap<const TVariable *,TString> & samplerInStructSymbolsToAPINames,unsigned int * groupTextureRegisterIndex)303 void ResourcesHLSL::outputHLSLSamplerUniformGroup(
304     TInfoSinkBase &out,
305     const HLSLTextureGroup textureGroup,
306     const TVector<const TVariable *> &group,
307     const TMap<const TVariable *, TString> &samplerInStructSymbolsToAPINames,
308     unsigned int *groupTextureRegisterIndex)
309 {
310     if (group.empty())
311     {
312         return;
313     }
314     unsigned int groupRegisterCount = 0;
315     for (const TVariable *uniform : group)
316     {
317         const TType &type           = uniform->getType();
318         const ImmutableString &name = uniform->name();
319         unsigned int registerCount;
320 
321         // The uniform might be just a regular sampler or one extracted from a struct.
322         unsigned int samplerArrayIndex      = 0u;
323         const ShaderVariable *uniformByName = findUniformByName(name);
324         if (uniformByName)
325         {
326             samplerArrayIndex = assignUniformRegister(type, name, &registerCount);
327         }
328         else
329         {
330             ASSERT(samplerInStructSymbolsToAPINames.find(uniform) !=
331                    samplerInStructSymbolsToAPINames.end());
332             samplerArrayIndex = assignSamplerInStructUniformRegister(
333                 type, samplerInStructSymbolsToAPINames.at(uniform), &registerCount);
334         }
335         groupRegisterCount += registerCount;
336 
337         if (type.isArray())
338         {
339             out << "static const uint " << DecorateVariableIfNeeded(*uniform) << ArrayString(type)
340                 << " = ";
341             OutputUniformIndexArrayInitializer(out, type, samplerArrayIndex);
342             out << ";\n";
343         }
344         else
345         {
346             out << "static const uint " << DecorateVariableIfNeeded(*uniform) << " = "
347                 << samplerArrayIndex << ";\n";
348         }
349     }
350     TString suffix = TextureGroupSuffix(textureGroup);
351     // Since HLSL_TEXTURE_2D is the first group, it has a fixed offset of zero.
352     if (textureGroup != HLSL_TEXTURE_2D)
353     {
354         out << "static const uint textureIndexOffset" << suffix << " = "
355             << (*groupTextureRegisterIndex) << ";\n";
356         out << "static const uint samplerIndexOffset" << suffix << " = "
357             << (*groupTextureRegisterIndex) << ";\n";
358     }
359     out << "uniform " << TextureString(textureGroup) << " textures" << suffix << "["
360         << groupRegisterCount << "]" << " : register(t" << (*groupTextureRegisterIndex) << ");\n";
361     out << "uniform " << SamplerString(textureGroup) << " samplers" << suffix << "["
362         << groupRegisterCount << "]" << " : register(s" << (*groupTextureRegisterIndex) << ");\n";
363     *groupTextureRegisterIndex += groupRegisterCount;
364 }
365 
outputHLSLImageUniformIndices(TInfoSinkBase & out,const TVector<const TVariable * > & group,unsigned int imageArrayIndex,unsigned int * groupRegisterCount)366 void ResourcesHLSL::outputHLSLImageUniformIndices(TInfoSinkBase &out,
367                                                   const TVector<const TVariable *> &group,
368                                                   unsigned int imageArrayIndex,
369                                                   unsigned int *groupRegisterCount)
370 {
371     for (const TVariable *uniform : group)
372     {
373         const TType &type           = uniform->getType();
374         const ImmutableString &name = uniform->name();
375         unsigned int registerCount  = 0;
376 
377         assignUniformRegister(type, name, &registerCount);
378         *groupRegisterCount += registerCount;
379 
380         if (type.isArray())
381         {
382             out << "static const uint " << DecorateVariableIfNeeded(*uniform) << ArrayString(type)
383                 << " = ";
384             OutputUniformIndexArrayInitializer(out, type, imageArrayIndex);
385             out << ";\n";
386         }
387         else
388         {
389             out << "static const uint " << DecorateVariableIfNeeded(*uniform) << " = "
390                 << imageArrayIndex << ";\n";
391         }
392 
393         imageArrayIndex += registerCount;
394     }
395 }
396 
outputHLSLReadonlyImageUniformGroup(TInfoSinkBase & out,const HLSLTextureGroup textureGroup,const TVector<const TVariable * > & group,unsigned int * groupTextureRegisterIndex)397 void ResourcesHLSL::outputHLSLReadonlyImageUniformGroup(TInfoSinkBase &out,
398                                                         const HLSLTextureGroup textureGroup,
399                                                         const TVector<const TVariable *> &group,
400                                                         unsigned int *groupTextureRegisterIndex)
401 {
402     if (group.empty())
403     {
404         return;
405     }
406 
407     unsigned int groupRegisterCount = 0;
408     outputHLSLImageUniformIndices(out, group, *groupTextureRegisterIndex, &groupRegisterCount);
409 
410     TString suffix = TextureGroupSuffix(textureGroup);
411     out << "static const uint readonlyImageIndexOffset" << suffix << " = "
412         << (*groupTextureRegisterIndex) << ";\n";
413     out << "uniform " << TextureString(textureGroup) << " readonlyImages" << suffix << "["
414         << groupRegisterCount << "]" << " : register(t" << (*groupTextureRegisterIndex) << ");\n";
415     *groupTextureRegisterIndex += groupRegisterCount;
416 }
417 
outputHLSLImageUniformGroup(TInfoSinkBase & out,const HLSLRWTextureGroup textureGroup,const TVector<const TVariable * > & group,unsigned int * groupTextureRegisterIndex)418 void ResourcesHLSL::outputHLSLImageUniformGroup(TInfoSinkBase &out,
419                                                 const HLSLRWTextureGroup textureGroup,
420                                                 const TVector<const TVariable *> &group,
421                                                 unsigned int *groupTextureRegisterIndex)
422 {
423     if (group.empty())
424     {
425         return;
426     }
427 
428     // ROVs should all be written out in DynamicImage2DHLSL.cpp.
429     ASSERT(!IsAnyRasterOrdered(group));
430 
431     unsigned int groupRegisterCount = 0;
432     outputHLSLImageUniformIndices(out, group, *groupTextureRegisterIndex, &groupRegisterCount);
433 
434     TString suffix = RWTextureGroupSuffix(textureGroup);
435     out << "static const uint imageIndexOffset" << suffix << " = " << (*groupTextureRegisterIndex)
436         << ";\n";
437     out << "uniform " << RWTextureString(textureGroup) << " images" << suffix << "["
438         << groupRegisterCount << "]" << " : register(u" << (*groupTextureRegisterIndex) << ");\n";
439     *groupTextureRegisterIndex += groupRegisterCount;
440 }
441 
outputUniform(TInfoSinkBase & out,const TType & type,const TVariable & variable,const unsigned int registerIndex)442 void ResourcesHLSL::outputUniform(TInfoSinkBase &out,
443                                   const TType &type,
444                                   const TVariable &variable,
445                                   const unsigned int registerIndex)
446 {
447     const TStructure *structure = type.getStruct();
448     // If this is a nameless struct, we need to use its full definition, rather than its (empty)
449     // name.
450     // TypeString() will invoke defineNameless in this case; qualifier prefixes are unnecessary for
451     // nameless structs in ES, as nameless structs cannot be used anywhere that layout qualifiers
452     // are permitted.
453     const TString &typeName = ((structure && structure->symbolType() != SymbolType::Empty)
454                                    ? QualifiedStructNameString(*structure, false, false, false)
455                                    : TypeString(type));
456 
457     const TString &registerString =
458         TString("register(") + UniformRegisterPrefix(type) + str(registerIndex) + ")";
459 
460     out << "uniform " << typeName << " ";
461 
462     out << DecorateVariableIfNeeded(variable);
463 
464     out << ArrayString(type) << " : " << registerString << ";\n";
465 }
466 
outputAtomicCounterBuffer(TInfoSinkBase & out,const int binding,const unsigned int registerIndex)467 void ResourcesHLSL::outputAtomicCounterBuffer(TInfoSinkBase &out,
468                                               const int binding,
469                                               const unsigned int registerIndex)
470 {
471     // Atomic counter memory access is not incoherent
472     out << "uniform globallycoherent RWByteAddressBuffer "
473         << getAtomicCounterNameForBinding(binding) << " : register(u" << registerIndex << ");\n";
474 }
475 
uniformsHeader(TInfoSinkBase & out,ShShaderOutput outputType,const ReferencedVariables & referencedUniforms,TSymbolTable * symbolTable)476 void ResourcesHLSL::uniformsHeader(TInfoSinkBase &out,
477                                    ShShaderOutput outputType,
478                                    const ReferencedVariables &referencedUniforms,
479                                    TSymbolTable *symbolTable)
480 {
481     if (!referencedUniforms.empty())
482     {
483         out << "// Uniforms\n\n";
484     }
485     // In the case of HLSL 4, sampler uniforms need to be grouped by type before the code is
486     // written. They are grouped based on the combination of the HLSL texture type and
487     // HLSL sampler type, enumerated in HLSLTextureSamplerGroup.
488     TVector<TVector<const TVariable *>> groupedSamplerUniforms(HLSL_TEXTURE_MAX + 1);
489     TMap<const TVariable *, TString> samplerInStructSymbolsToAPINames;
490     TVector<TVector<const TVariable *>> groupedReadonlyImageUniforms(HLSL_TEXTURE_MAX + 1);
491     TVector<TVector<const TVariable *>> groupedImageUniforms(HLSL_RWTEXTURE_MAX + 1);
492 
493     TUnorderedMap<int, unsigned int> assignedAtomicCounterBindings;
494     unsigned int reservedReadonlyImageRegisterCount = 0, reservedImageRegisterCount = 0;
495     for (auto &uniformIt : referencedUniforms)
496     {
497         // Output regular uniforms. Group sampler uniforms by type.
498         const TVariable &variable = *uniformIt.second;
499         const TType &type         = variable.getType();
500 
501         if (outputType == SH_HLSL_4_1_OUTPUT && IsSampler(type.getBasicType()))
502         {
503             HLSLTextureGroup group = TextureGroup(type.getBasicType());
504             groupedSamplerUniforms[group].push_back(&variable);
505         }
506         else if (outputType == SH_HLSL_4_1_OUTPUT && IsImage(type.getBasicType()))
507         {
508             if (IsImage2D(type.getBasicType()))
509             {
510                 const ShaderVariable *uniform = findUniformByName(variable.name());
511                 if (type.getMemoryQualifier().readonly)
512                 {
513                     reservedReadonlyImageRegisterCount +=
514                         HLSLVariableRegisterCount(*uniform, mOutputType);
515                 }
516                 else
517                 {
518                     reservedImageRegisterCount += HLSLVariableRegisterCount(*uniform, mOutputType);
519                 }
520                 continue;
521             }
522             if (type.getMemoryQualifier().readonly)
523             {
524                 HLSLTextureGroup group = TextureGroup(
525                     type.getBasicType(), type.getLayoutQualifier().imageInternalFormat);
526                 groupedReadonlyImageUniforms[group].push_back(&variable);
527             }
528             else
529             {
530                 HLSLRWTextureGroup group = RWTextureGroup(
531                     type.getBasicType(), type.getLayoutQualifier().imageInternalFormat);
532                 groupedImageUniforms[group].push_back(&variable);
533             }
534         }
535         else if (outputType == SH_HLSL_4_1_OUTPUT && IsAtomicCounter(type.getBasicType()))
536         {
537             TLayoutQualifier layout = type.getLayoutQualifier();
538             int binding             = layout.binding;
539             unsigned int registerIndex;
540             if (assignedAtomicCounterBindings.find(binding) == assignedAtomicCounterBindings.end())
541             {
542                 registerIndex                          = mUAVRegister++;
543                 assignedAtomicCounterBindings[binding] = registerIndex;
544                 outputAtomicCounterBuffer(out, binding, registerIndex);
545             }
546             else
547             {
548                 registerIndex = assignedAtomicCounterBindings[binding];
549             }
550             const ShaderVariable *uniform      = findUniformByName(variable.name());
551             mUniformRegisterMap[uniform->name] = registerIndex;
552         }
553         else
554         {
555             if (type.isStructureContainingSamplers())
556             {
557                 TVector<const TVariable *> samplerSymbols;
558                 TMap<const TVariable *, TString> symbolsToAPINames;
559                 ImmutableStringBuilder namePrefix(kAngleDecorString.length() +
560                                                   variable.name().length());
561                 namePrefix << kAngleDecorString;
562                 namePrefix << variable.name();
563                 type.createSamplerSymbols(namePrefix, TString(variable.name().data()),
564                                           &samplerSymbols, &symbolsToAPINames, symbolTable);
565                 for (const TVariable *sampler : samplerSymbols)
566                 {
567                     const TType &samplerType = sampler->getType();
568 
569                     if (outputType == SH_HLSL_4_1_OUTPUT)
570                     {
571                         HLSLTextureGroup group = TextureGroup(samplerType.getBasicType());
572                         groupedSamplerUniforms[group].push_back(sampler);
573                         samplerInStructSymbolsToAPINames[sampler] = symbolsToAPINames[sampler];
574                     }
575                     else
576                     {
577                         ASSERT(outputType == SH_HLSL_3_0_OUTPUT);
578                         unsigned int registerIndex = assignSamplerInStructUniformRegister(
579                             samplerType, symbolsToAPINames[sampler], nullptr);
580                         outputUniform(out, samplerType, *sampler, registerIndex);
581                     }
582                 }
583             }
584             unsigned int registerIndex = assignUniformRegister(type, variable.name(), nullptr);
585             outputUniform(out, type, variable, registerIndex);
586         }
587     }
588 
589     if (outputType == SH_HLSL_4_1_OUTPUT)
590     {
591         unsigned int groupTextureRegisterIndex = 0;
592         // Atomic counters and RW texture share the same resources. Therefore, RW texture need to
593         // start counting after the last atomic counter.
594         unsigned int groupRWTextureRegisterIndex = mUAVRegister;
595         // TEXTURE_2D is special, index offset is assumed to be 0 and omitted in that case.
596         ASSERT(HLSL_TEXTURE_MIN == HLSL_TEXTURE_2D);
597         for (int groupId = HLSL_TEXTURE_MIN; groupId < HLSL_TEXTURE_MAX; ++groupId)
598         {
599             outputHLSLSamplerUniformGroup(
600                 out, HLSLTextureGroup(groupId), groupedSamplerUniforms[groupId],
601                 samplerInStructSymbolsToAPINames, &groupTextureRegisterIndex);
602         }
603         mSamplerCount = groupTextureRegisterIndex;
604 
605         // Reserve t type register for readonly image2D variables.
606         mReadonlyImage2DRegisterIndex = mSRVRegister;
607         groupTextureRegisterIndex += reservedReadonlyImageRegisterCount;
608         mSRVRegister += reservedReadonlyImageRegisterCount;
609 
610         for (int groupId = HLSL_TEXTURE_MIN; groupId < HLSL_TEXTURE_MAX; ++groupId)
611         {
612             outputHLSLReadonlyImageUniformGroup(out, HLSLTextureGroup(groupId),
613                                                 groupedReadonlyImageUniforms[groupId],
614                                                 &groupTextureRegisterIndex);
615         }
616         mReadonlyImageCount = groupTextureRegisterIndex - mReadonlyImage2DRegisterIndex;
617         if (mReadonlyImageCount)
618         {
619             out << "static const uint readonlyImageIndexStart = " << mReadonlyImage2DRegisterIndex
620                 << ";\n";
621         }
622 
623         // Reserve u type register for writable image2D variables.
624         mImage2DRegisterIndex = mUAVRegister;
625         groupRWTextureRegisterIndex += reservedImageRegisterCount;
626         mUAVRegister += reservedImageRegisterCount;
627 
628         for (int groupId = HLSL_RWTEXTURE_MIN; groupId < HLSL_RWTEXTURE_MAX; ++groupId)
629         {
630             outputHLSLImageUniformGroup(out, HLSLRWTextureGroup(groupId),
631                                         groupedImageUniforms[groupId],
632                                         &groupRWTextureRegisterIndex);
633         }
634         mImageCount = groupRWTextureRegisterIndex - mImage2DRegisterIndex;
635         if (mImageCount)
636         {
637             out << "static const uint imageIndexStart = " << mImage2DRegisterIndex << ";\n";
638         }
639     }
640 }
641 
samplerMetadataUniforms(TInfoSinkBase & out,unsigned int regIndex)642 void ResourcesHLSL::samplerMetadataUniforms(TInfoSinkBase &out, unsigned int regIndex)
643 {
644     // If mSamplerCount is 0 the shader doesn't use any textures for samplers.
645     if (mSamplerCount > 0)
646     {
647         out << "    struct SamplerMetadata\n"
648                "    {\n"
649                "        int baseLevel;\n"
650                "        int wrapModes;\n"
651                "        int2 padding;\n"
652                "        int4 intBorderColor;\n"
653                "    };\n"
654                "    SamplerMetadata samplerMetadata["
655             << mSamplerCount << "] : packoffset(c" << regIndex << ");\n";
656     }
657 }
658 
imageMetadataUniforms(TInfoSinkBase & out,unsigned int regIndex)659 void ResourcesHLSL::imageMetadataUniforms(TInfoSinkBase &out, unsigned int regIndex)
660 {
661     if (mReadonlyImageCount > 0 || mImageCount > 0)
662     {
663         out << "    struct ImageMetadata\n"
664                "    {\n"
665                "        int layer;\n"
666                "        uint level;\n"
667                "        int2 padding;\n"
668                "    };\n";
669 
670         if (mReadonlyImageCount > 0)
671         {
672             out << "    ImageMetadata readonlyImageMetadata[" << mReadonlyImageCount
673                 << "] : packoffset(c" << regIndex << ");\n";
674         }
675 
676         if (mImageCount > 0)
677         {
678             out << "    ImageMetadata imageMetadata[" << mImageCount << "] : packoffset(c"
679                 << regIndex + mReadonlyImageCount << ");\n";
680         }
681     }
682 }
683 
uniformBlocksHeader(const ReferencedInterfaceBlocks & referencedInterfaceBlocks,const std::map<int,const TInterfaceBlock * > & uniformBlockOptimizedMap)684 TString ResourcesHLSL::uniformBlocksHeader(
685     const ReferencedInterfaceBlocks &referencedInterfaceBlocks,
686     const std::map<int, const TInterfaceBlock *> &uniformBlockOptimizedMap)
687 {
688     TString interfaceBlocks;
689 
690     for (const auto &blockReference : referencedInterfaceBlocks)
691     {
692         const TInterfaceBlock &interfaceBlock = *blockReference.second->block;
693         const TVariable *instanceVariable     = blockReference.second->instanceVariable;
694         if (instanceVariable != nullptr)
695         {
696             interfaceBlocks += uniformBlockStructString(interfaceBlock);
697         }
698 
699         // In order to avoid compile performance issue, translate uniform block to structured
700         // buffer. anglebug.com/40096608.
701         if (uniformBlockOptimizedMap.count(interfaceBlock.uniqueId().get()) != 0)
702         {
703             unsigned int structuredBufferRegister = mSRVRegister;
704             if (instanceVariable != nullptr && instanceVariable->getType().isArray())
705             {
706                 unsigned int instanceArraySize =
707                     instanceVariable->getType().getOutermostArraySize();
708                 for (unsigned int arrayIndex = 0; arrayIndex < instanceArraySize; arrayIndex++)
709                 {
710                     interfaceBlocks += uniformBlockWithOneLargeArrayMemberString(
711                         interfaceBlock, instanceVariable, structuredBufferRegister + arrayIndex,
712                         arrayIndex);
713                 }
714                 mSRVRegister += instanceArraySize;
715             }
716             else
717             {
718                 interfaceBlocks += uniformBlockWithOneLargeArrayMemberString(
719                     interfaceBlock, instanceVariable, structuredBufferRegister, GL_INVALID_INDEX);
720                 mSRVRegister += 1u;
721             }
722             mUniformBlockRegisterMap[interfaceBlock.name().data()] = structuredBufferRegister;
723             mUniformBlockUseStructuredBufferMap[interfaceBlock.name().data()] = true;
724             continue;
725         }
726 
727         unsigned int activeRegister                            = mUniformBlockRegister;
728         mUniformBlockRegisterMap[interfaceBlock.name().data()] = activeRegister;
729 
730         if (instanceVariable != nullptr && instanceVariable->getType().isArray())
731         {
732             unsigned int instanceArraySize = instanceVariable->getType().getOutermostArraySize();
733             for (unsigned int arrayIndex = 0; arrayIndex < instanceArraySize; arrayIndex++)
734             {
735                 interfaceBlocks += uniformBlockString(interfaceBlock, instanceVariable,
736                                                       activeRegister + arrayIndex, arrayIndex);
737             }
738             mUniformBlockRegister += instanceArraySize;
739         }
740         else
741         {
742             interfaceBlocks += uniformBlockString(interfaceBlock, instanceVariable, activeRegister,
743                                                   GL_INVALID_INDEX);
744             mUniformBlockRegister += 1u;
745         }
746     }
747 
748     return (interfaceBlocks.empty() ? "" : ("// Uniform Blocks\n\n" + interfaceBlocks));
749 }
750 
allocateShaderStorageBlockRegisters(const ReferencedInterfaceBlocks & referencedInterfaceBlocks)751 void ResourcesHLSL::allocateShaderStorageBlockRegisters(
752     const ReferencedInterfaceBlocks &referencedInterfaceBlocks)
753 {
754     for (const auto &interfaceBlockReference : referencedInterfaceBlocks)
755     {
756         const TInterfaceBlock &interfaceBlock = *interfaceBlockReference.second->block;
757         const TVariable *instanceVariable     = interfaceBlockReference.second->instanceVariable;
758 
759         mShaderStorageBlockRegisterMap[interfaceBlock.name().data()] = mUAVRegister;
760 
761         if (instanceVariable != nullptr && instanceVariable->getType().isArray())
762         {
763             mUAVRegister += instanceVariable->getType().getOutermostArraySize();
764         }
765         else
766         {
767             mUAVRegister += 1u;
768         }
769     }
770 }
771 
shaderStorageBlocksHeader(const ReferencedInterfaceBlocks & referencedInterfaceBlocks)772 TString ResourcesHLSL::shaderStorageBlocksHeader(
773     const ReferencedInterfaceBlocks &referencedInterfaceBlocks)
774 {
775     TString interfaceBlocks;
776 
777     for (const auto &interfaceBlockReference : referencedInterfaceBlocks)
778     {
779         const TInterfaceBlock &interfaceBlock = *interfaceBlockReference.second->block;
780         const TVariable *instanceVariable     = interfaceBlockReference.second->instanceVariable;
781 
782         unsigned int activeRegister = mShaderStorageBlockRegisterMap[interfaceBlock.name().data()];
783 
784         if (instanceVariable != nullptr && instanceVariable->getType().isArray())
785         {
786             unsigned int instanceArraySize = instanceVariable->getType().getOutermostArraySize();
787             for (unsigned int arrayIndex = 0; arrayIndex < instanceArraySize; arrayIndex++)
788             {
789                 interfaceBlocks += shaderStorageBlockString(
790                     interfaceBlock, instanceVariable, activeRegister + arrayIndex, arrayIndex);
791             }
792         }
793         else
794         {
795             interfaceBlocks += shaderStorageBlockString(interfaceBlock, instanceVariable,
796                                                         activeRegister, GL_INVALID_INDEX);
797         }
798     }
799 
800     return interfaceBlocks;
801 }
802 
uniformBlockString(const TInterfaceBlock & interfaceBlock,const TVariable * instanceVariable,unsigned int registerIndex,unsigned int arrayIndex)803 TString ResourcesHLSL::uniformBlockString(const TInterfaceBlock &interfaceBlock,
804                                           const TVariable *instanceVariable,
805                                           unsigned int registerIndex,
806                                           unsigned int arrayIndex)
807 {
808     const TString &arrayIndexString = (arrayIndex != GL_INVALID_INDEX ? str(arrayIndex) : "");
809     const TString &blockName        = TString(interfaceBlock.name().data()) + arrayIndexString;
810     TString hlsl;
811 
812     hlsl += "cbuffer " + blockName + " : register(b" + str(registerIndex) +
813             ")\n"
814             "{\n";
815 
816     if (instanceVariable != nullptr)
817     {
818         hlsl += "    " + InterfaceBlockStructName(interfaceBlock) + " " +
819                 InterfaceBlockInstanceString(instanceVariable->name(), arrayIndex) + ";\n";
820     }
821     else
822     {
823         const TLayoutBlockStorage blockStorage = interfaceBlock.blockStorage();
824         hlsl += uniformBlockMembersString(interfaceBlock, blockStorage);
825     }
826 
827     hlsl += "};\n\n";
828 
829     return hlsl;
830 }
831 
uniformBlockWithOneLargeArrayMemberString(const TInterfaceBlock & interfaceBlock,const TVariable * instanceVariable,unsigned int registerIndex,unsigned int arrayIndex)832 TString ResourcesHLSL::uniformBlockWithOneLargeArrayMemberString(
833     const TInterfaceBlock &interfaceBlock,
834     const TVariable *instanceVariable,
835     unsigned int registerIndex,
836     unsigned int arrayIndex)
837 {
838     TString hlsl, typeString;
839 
840     const TField &field                    = *interfaceBlock.fields()[0];
841     const TLayoutBlockStorage blockStorage = interfaceBlock.blockStorage();
842     typeString             = InterfaceBlockFieldTypeString(field, blockStorage, true);
843     const TType &fieldType = *field.type();
844     if (fieldType.isMatrix())
845     {
846         if (arrayIndex == GL_INVALID_INDEX || arrayIndex == 0)
847         {
848             hlsl += "struct pack" + Decorate(interfaceBlock.name()) + " { " + typeString + " " +
849                     Decorate(field.name()) + "; };\n";
850         }
851         typeString = "pack" + Decorate(interfaceBlock.name());
852     }
853     else if (fieldType.isVectorArray() || fieldType.isScalarArray())
854     {
855         // If the member is an array of scalars or vectors, std140 rules require the base array
856         // stride are rounded up to the base alignment of a vec4.
857         if (arrayIndex == GL_INVALID_INDEX || arrayIndex == 0)
858         {
859             hlsl += "struct pack" + Decorate(interfaceBlock.name()) + " { " + typeString + " " +
860                     Decorate(field.name()) + ";\n";
861             hlsl += InterfaceBlockScalarVectorFieldPaddingString(fieldType) + " };\n";
862         }
863         typeString = "pack" + Decorate(interfaceBlock.name());
864     }
865 
866     if (instanceVariable != nullptr)
867     {
868 
869         hlsl += "StructuredBuffer <" + typeString + "> " +
870                 InterfaceBlockInstanceString(instanceVariable->name(), arrayIndex) + "_" +
871                 Decorate(field.name()) + +" : register(t" + str(registerIndex) + ");\n";
872     }
873     else
874     {
875         hlsl += "StructuredBuffer <" + typeString + "> " + Decorate(field.name()) +
876                 " : register(t" + str(registerIndex) + ");\n";
877     }
878 
879     return hlsl;
880 }
881 
shaderStorageBlockString(const TInterfaceBlock & interfaceBlock,const TVariable * instanceVariable,unsigned int registerIndex,unsigned int arrayIndex)882 TString ResourcesHLSL::shaderStorageBlockString(const TInterfaceBlock &interfaceBlock,
883                                                 const TVariable *instanceVariable,
884                                                 unsigned int registerIndex,
885                                                 unsigned int arrayIndex)
886 {
887     TString hlsl;
888     if (instanceVariable != nullptr)
889     {
890         hlsl += "RWByteAddressBuffer " +
891                 InterfaceBlockInstanceString(instanceVariable->name(), arrayIndex) +
892                 ": register(u" + str(registerIndex) + ");\n";
893     }
894     else
895     {
896         hlsl += "RWByteAddressBuffer " + Decorate(interfaceBlock.name()) + ": register(u" +
897                 str(registerIndex) + ");\n";
898     }
899     return hlsl;
900 }
901 
InterfaceBlockInstanceString(const ImmutableString & instanceName,unsigned int arrayIndex)902 TString ResourcesHLSL::InterfaceBlockInstanceString(const ImmutableString &instanceName,
903                                                     unsigned int arrayIndex)
904 {
905     if (arrayIndex != GL_INVALID_INDEX)
906     {
907         return DecoratePrivate(instanceName) + "_" + str(arrayIndex);
908     }
909     else
910     {
911         return Decorate(instanceName);
912     }
913 }
914 
uniformBlockMembersString(const TInterfaceBlock & interfaceBlock,TLayoutBlockStorage blockStorage)915 TString ResourcesHLSL::uniformBlockMembersString(const TInterfaceBlock &interfaceBlock,
916                                                  TLayoutBlockStorage blockStorage)
917 {
918     TString hlsl;
919 
920     Std140PaddingHelper padHelper = mStructureHLSL->getPaddingHelper();
921 
922     const unsigned int fieldCount = static_cast<unsigned int>(interfaceBlock.fields().size());
923     for (unsigned int typeIndex = 0; typeIndex < fieldCount; typeIndex++)
924     {
925         const TField &field    = *interfaceBlock.fields()[typeIndex];
926         const TType &fieldType = *field.type();
927 
928         if (blockStorage == EbsStd140)
929         {
930             // 2 and 3 component vector types in some cases need pre-padding
931             hlsl += padHelper.prePaddingString(fieldType, false);
932         }
933 
934         hlsl += "    " + InterfaceBlockFieldTypeString(field, blockStorage, false) + " " +
935                 Decorate(field.name()) + ArrayString(fieldType).data() + ";\n";
936 
937         // must pad out after matrices and arrays, where HLSL usually allows itself room to pack
938         // stuff
939         if (blockStorage == EbsStd140)
940         {
941             const bool useHLSLRowMajorPacking =
942                 (fieldType.getLayoutQualifier().matrixPacking == EmpColumnMajor);
943             hlsl += padHelper.postPaddingString(fieldType, useHLSLRowMajorPacking,
944                                                 typeIndex == fieldCount - 1, false);
945         }
946     }
947 
948     return hlsl;
949 }
950 
uniformBlockStructString(const TInterfaceBlock & interfaceBlock)951 TString ResourcesHLSL::uniformBlockStructString(const TInterfaceBlock &interfaceBlock)
952 {
953     const TLayoutBlockStorage blockStorage = interfaceBlock.blockStorage();
954 
955     return "struct " + InterfaceBlockStructName(interfaceBlock) +
956            "\n"
957            "{\n" +
958            uniformBlockMembersString(interfaceBlock, blockStorage) + "};\n\n";
959 }
960 }  // namespace sh
961