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