• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
allocateShaderStorageBlockRegisters(const ReferencedInterfaceBlocks & referencedInterfaceBlocks)765 void ResourcesHLSL::allocateShaderStorageBlockRegisters(
766     const ReferencedInterfaceBlocks &referencedInterfaceBlocks)
767 {
768     for (const auto &interfaceBlockReference : referencedInterfaceBlocks)
769     {
770         const TInterfaceBlock &interfaceBlock = *interfaceBlockReference.second->block;
771         const TVariable *instanceVariable     = interfaceBlockReference.second->instanceVariable;
772 
773         mShaderStorageBlockRegisterMap[interfaceBlock.name().data()] = mUAVRegister;
774 
775         if (instanceVariable != nullptr && instanceVariable->getType().isArray())
776         {
777             mUAVRegister += instanceVariable->getType().getOutermostArraySize();
778         }
779         else
780         {
781             mUAVRegister += 1u;
782         }
783     }
784 }
785 
shaderStorageBlocksHeader(const ReferencedInterfaceBlocks & referencedInterfaceBlocks)786 TString ResourcesHLSL::shaderStorageBlocksHeader(
787     const ReferencedInterfaceBlocks &referencedInterfaceBlocks)
788 {
789     TString interfaceBlocks;
790 
791     for (const auto &interfaceBlockReference : referencedInterfaceBlocks)
792     {
793         const TInterfaceBlock &interfaceBlock = *interfaceBlockReference.second->block;
794         const TVariable *instanceVariable     = interfaceBlockReference.second->instanceVariable;
795 
796         unsigned int activeRegister = mShaderStorageBlockRegisterMap[interfaceBlock.name().data()];
797 
798         if (instanceVariable != nullptr && instanceVariable->getType().isArray())
799         {
800             unsigned int instanceArraySize = instanceVariable->getType().getOutermostArraySize();
801             for (unsigned int arrayIndex = 0; arrayIndex < instanceArraySize; arrayIndex++)
802             {
803                 interfaceBlocks += shaderStorageBlockString(
804                     interfaceBlock, instanceVariable, activeRegister + arrayIndex, arrayIndex);
805             }
806         }
807         else
808         {
809             interfaceBlocks += shaderStorageBlockString(interfaceBlock, instanceVariable,
810                                                         activeRegister, GL_INVALID_INDEX);
811         }
812     }
813 
814     return interfaceBlocks;
815 }
816 
uniformBlockString(const TInterfaceBlock & interfaceBlock,const TVariable * instanceVariable,unsigned int registerIndex,unsigned int arrayIndex)817 TString ResourcesHLSL::uniformBlockString(const TInterfaceBlock &interfaceBlock,
818                                           const TVariable *instanceVariable,
819                                           unsigned int registerIndex,
820                                           unsigned int arrayIndex)
821 {
822     const TString &arrayIndexString = (arrayIndex != GL_INVALID_INDEX ? str(arrayIndex) : "");
823     const TString &blockName        = TString(interfaceBlock.name().data()) + arrayIndexString;
824     TString hlsl;
825 
826     hlsl += "cbuffer " + blockName + " : register(b" + str(registerIndex) +
827             ")\n"
828             "{\n";
829 
830     if (instanceVariable != nullptr)
831     {
832         hlsl += "    " + InterfaceBlockStructName(interfaceBlock) + " " +
833                 InterfaceBlockInstanceString(instanceVariable->name(), arrayIndex) + ";\n";
834     }
835     else
836     {
837         const TLayoutBlockStorage blockStorage = interfaceBlock.blockStorage();
838         hlsl += uniformBlockMembersString(interfaceBlock, blockStorage);
839     }
840 
841     hlsl += "};\n\n";
842 
843     return hlsl;
844 }
845 
uniformBlockWithOneLargeArrayMemberString(const TInterfaceBlock & interfaceBlock,const TVariable * instanceVariable,unsigned int registerIndex,unsigned int arrayIndex)846 TString ResourcesHLSL::uniformBlockWithOneLargeArrayMemberString(
847     const TInterfaceBlock &interfaceBlock,
848     const TVariable *instanceVariable,
849     unsigned int registerIndex,
850     unsigned int arrayIndex)
851 {
852     TString hlsl, typeString;
853 
854     const TField &field                    = *interfaceBlock.fields()[0];
855     const TLayoutBlockStorage blockStorage = interfaceBlock.blockStorage();
856     typeString             = InterfaceBlockFieldTypeString(field, blockStorage, true);
857     const TType &fieldType = *field.type();
858     if (fieldType.isMatrix())
859     {
860         if (arrayIndex == GL_INVALID_INDEX || arrayIndex == 0)
861         {
862             hlsl += "struct pack" + Decorate(interfaceBlock.name()) + " { " + typeString + " " +
863                     Decorate(field.name()) + "; };\n";
864         }
865         typeString = "pack" + Decorate(interfaceBlock.name());
866     }
867     else if (fieldType.isVectorArray() || fieldType.isScalarArray())
868     {
869         // If the member is an array of scalars or vectors, std140 rules require the base array
870         // stride are rounded up to the base alignment of a vec4.
871         if (arrayIndex == GL_INVALID_INDEX || arrayIndex == 0)
872         {
873             hlsl += "struct pack" + Decorate(interfaceBlock.name()) + " { " + typeString + " " +
874                     Decorate(field.name()) + ";\n";
875             hlsl += InterfaceBlockScalarVectorFieldPaddingString(fieldType) + " };\n";
876         }
877         typeString = "pack" + Decorate(interfaceBlock.name());
878     }
879 
880     if (instanceVariable != nullptr)
881     {
882 
883         hlsl += "StructuredBuffer <" + typeString + "> " +
884                 InterfaceBlockInstanceString(instanceVariable->name(), arrayIndex) + "_" +
885                 Decorate(field.name()) + +" : register(t" + str(registerIndex) + ");\n";
886     }
887     else
888     {
889         hlsl += "StructuredBuffer <" + typeString + "> " + Decorate(field.name()) +
890                 " : register(t" + str(registerIndex) + ");\n";
891     }
892 
893     return hlsl;
894 }
895 
shaderStorageBlockString(const TInterfaceBlock & interfaceBlock,const TVariable * instanceVariable,unsigned int registerIndex,unsigned int arrayIndex)896 TString ResourcesHLSL::shaderStorageBlockString(const TInterfaceBlock &interfaceBlock,
897                                                 const TVariable *instanceVariable,
898                                                 unsigned int registerIndex,
899                                                 unsigned int arrayIndex)
900 {
901     TString hlsl;
902     if (instanceVariable != nullptr)
903     {
904         hlsl += "RWByteAddressBuffer " +
905                 InterfaceBlockInstanceString(instanceVariable->name(), arrayIndex) +
906                 ": register(u" + str(registerIndex) + ");\n";
907     }
908     else
909     {
910         hlsl += "RWByteAddressBuffer " + Decorate(interfaceBlock.name()) + ": register(u" +
911                 str(registerIndex) + ");\n";
912     }
913     return hlsl;
914 }
915 
InterfaceBlockInstanceString(const ImmutableString & instanceName,unsigned int arrayIndex)916 TString ResourcesHLSL::InterfaceBlockInstanceString(const ImmutableString &instanceName,
917                                                     unsigned int arrayIndex)
918 {
919     if (arrayIndex != GL_INVALID_INDEX)
920     {
921         return DecoratePrivate(instanceName) + "_" + str(arrayIndex);
922     }
923     else
924     {
925         return Decorate(instanceName);
926     }
927 }
928 
uniformBlockMembersString(const TInterfaceBlock & interfaceBlock,TLayoutBlockStorage blockStorage)929 TString ResourcesHLSL::uniformBlockMembersString(const TInterfaceBlock &interfaceBlock,
930                                                  TLayoutBlockStorage blockStorage)
931 {
932     TString hlsl;
933 
934     Std140PaddingHelper padHelper = mStructureHLSL->getPaddingHelper();
935 
936     const unsigned int fieldCount = static_cast<unsigned int>(interfaceBlock.fields().size());
937     for (unsigned int typeIndex = 0; typeIndex < fieldCount; typeIndex++)
938     {
939         const TField &field    = *interfaceBlock.fields()[typeIndex];
940         const TType &fieldType = *field.type();
941 
942         if (blockStorage == EbsStd140)
943         {
944             // 2 and 3 component vector types in some cases need pre-padding
945             hlsl += padHelper.prePaddingString(fieldType, false);
946         }
947 
948         hlsl += "    " + InterfaceBlockFieldTypeString(field, blockStorage, false) + " " +
949                 Decorate(field.name()) + ArrayString(fieldType).data() + ";\n";
950 
951         // must pad out after matrices and arrays, where HLSL usually allows itself room to pack
952         // stuff
953         if (blockStorage == EbsStd140)
954         {
955             const bool useHLSLRowMajorPacking =
956                 (fieldType.getLayoutQualifier().matrixPacking == EmpColumnMajor);
957             hlsl += padHelper.postPaddingString(fieldType, useHLSLRowMajorPacking,
958                                                 typeIndex == fieldCount - 1, false);
959         }
960     }
961 
962     return hlsl;
963 }
964 
uniformBlockStructString(const TInterfaceBlock & interfaceBlock)965 TString ResourcesHLSL::uniformBlockStructString(const TInterfaceBlock &interfaceBlock)
966 {
967     const TLayoutBlockStorage blockStorage = interfaceBlock.blockStorage();
968 
969     return "struct " + InterfaceBlockStructName(interfaceBlock) +
970            "\n"
971            "{\n" +
972            uniformBlockMembersString(interfaceBlock, blockStorage) + "};\n\n";
973 }
974 }  // namespace sh
975