• 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/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 << "]"
361         << " : register(t" << (*groupTextureRegisterIndex) << ");\n";
362     out << "uniform " << SamplerString(textureGroup) << " samplers" << suffix << "["
363         << groupRegisterCount << "]"
364         << " : register(s" << (*groupTextureRegisterIndex) << ");\n";
365     *groupTextureRegisterIndex += groupRegisterCount;
366 }
367 
outputHLSLImageUniformIndices(TInfoSinkBase & out,const TVector<const TVariable * > & group,unsigned int imageArrayIndex,unsigned int * groupRegisterCount)368 void ResourcesHLSL::outputHLSLImageUniformIndices(TInfoSinkBase &out,
369                                                   const TVector<const TVariable *> &group,
370                                                   unsigned int imageArrayIndex,
371                                                   unsigned int *groupRegisterCount)
372 {
373     for (const TVariable *uniform : group)
374     {
375         const TType &type           = uniform->getType();
376         const ImmutableString &name = uniform->name();
377         unsigned int registerCount  = 0;
378 
379         assignUniformRegister(type, name, &registerCount);
380         *groupRegisterCount += registerCount;
381 
382         if (type.isArray())
383         {
384             out << "static const uint " << DecorateVariableIfNeeded(*uniform) << ArrayString(type)
385                 << " = ";
386             OutputUniformIndexArrayInitializer(out, type, imageArrayIndex);
387             out << ";\n";
388         }
389         else
390         {
391             out << "static const uint " << DecorateVariableIfNeeded(*uniform) << " = "
392                 << imageArrayIndex << ";\n";
393         }
394 
395         imageArrayIndex += registerCount;
396     }
397 }
398 
outputHLSLReadonlyImageUniformGroup(TInfoSinkBase & out,const HLSLTextureGroup textureGroup,const TVector<const TVariable * > & group,unsigned int * groupTextureRegisterIndex)399 void ResourcesHLSL::outputHLSLReadonlyImageUniformGroup(TInfoSinkBase &out,
400                                                         const HLSLTextureGroup textureGroup,
401                                                         const TVector<const TVariable *> &group,
402                                                         unsigned int *groupTextureRegisterIndex)
403 {
404     if (group.empty())
405     {
406         return;
407     }
408 
409     unsigned int groupRegisterCount = 0;
410     outputHLSLImageUniformIndices(out, group, *groupTextureRegisterIndex, &groupRegisterCount);
411 
412     TString suffix = TextureGroupSuffix(textureGroup);
413     out << "static const uint readonlyImageIndexOffset" << suffix << " = "
414         << (*groupTextureRegisterIndex) << ";\n";
415     out << "uniform " << TextureString(textureGroup) << " readonlyImages" << suffix << "["
416         << groupRegisterCount << "]"
417         << " : register(t" << (*groupTextureRegisterIndex) << ");\n";
418     *groupTextureRegisterIndex += groupRegisterCount;
419 }
420 
outputHLSLImageUniformGroup(TInfoSinkBase & out,const HLSLRWTextureGroup textureGroup,const TVector<const TVariable * > & group,unsigned int * groupTextureRegisterIndex)421 void ResourcesHLSL::outputHLSLImageUniformGroup(TInfoSinkBase &out,
422                                                 const HLSLRWTextureGroup textureGroup,
423                                                 const TVector<const TVariable *> &group,
424                                                 unsigned int *groupTextureRegisterIndex)
425 {
426     if (group.empty())
427     {
428         return;
429     }
430 
431     // ROVs should all be written out in DynamicImage2DHLSL.cpp.
432     ASSERT(!IsAnyRasterOrdered(group));
433 
434     unsigned int groupRegisterCount = 0;
435     outputHLSLImageUniformIndices(out, group, *groupTextureRegisterIndex, &groupRegisterCount);
436 
437     TString suffix = RWTextureGroupSuffix(textureGroup);
438     out << "static const uint imageIndexOffset" << suffix << " = " << (*groupTextureRegisterIndex)
439         << ";\n";
440     out << "uniform " << RWTextureString(textureGroup) << " images" << suffix << "["
441         << groupRegisterCount << "]"
442         << " : register(u" << (*groupTextureRegisterIndex) << ");\n";
443     *groupTextureRegisterIndex += groupRegisterCount;
444 }
445 
outputHLSL4_0_FL9_3Sampler(TInfoSinkBase & out,const TType & type,const TVariable & variable,const unsigned int registerIndex)446 void ResourcesHLSL::outputHLSL4_0_FL9_3Sampler(TInfoSinkBase &out,
447                                                const TType &type,
448                                                const TVariable &variable,
449                                                const unsigned int registerIndex)
450 {
451     out << "uniform " << SamplerString(type.getBasicType()) << " sampler_"
452         << DecorateVariableIfNeeded(variable) << ArrayString(type) << " : register(s"
453         << str(registerIndex) << ");\n";
454     out << "uniform " << TextureString(type.getBasicType()) << " texture_"
455         << DecorateVariableIfNeeded(variable) << ArrayString(type) << " : register(t"
456         << str(registerIndex) << ");\n";
457 }
458 
outputUniform(TInfoSinkBase & out,const TType & type,const TVariable & variable,const unsigned int registerIndex)459 void ResourcesHLSL::outputUniform(TInfoSinkBase &out,
460                                   const TType &type,
461                                   const TVariable &variable,
462                                   const unsigned int registerIndex)
463 {
464     const TStructure *structure = type.getStruct();
465     // If this is a nameless struct, we need to use its full definition, rather than its (empty)
466     // name.
467     // TypeString() will invoke defineNameless in this case; qualifier prefixes are unnecessary for
468     // nameless structs in ES, as nameless structs cannot be used anywhere that layout qualifiers
469     // are permitted.
470     const TString &typeName = ((structure && structure->symbolType() != SymbolType::Empty)
471                                    ? QualifiedStructNameString(*structure, false, false, false)
472                                    : TypeString(type));
473 
474     const TString &registerString =
475         TString("register(") + UniformRegisterPrefix(type) + str(registerIndex) + ")";
476 
477     out << "uniform " << typeName << " ";
478 
479     out << DecorateVariableIfNeeded(variable);
480 
481     out << ArrayString(type) << " : " << registerString << ";\n";
482 }
483 
outputAtomicCounterBuffer(TInfoSinkBase & out,const int binding,const unsigned int registerIndex)484 void ResourcesHLSL::outputAtomicCounterBuffer(TInfoSinkBase &out,
485                                               const int binding,
486                                               const unsigned int registerIndex)
487 {
488     // Atomic counter memory access is not incoherent
489     out << "uniform globallycoherent RWByteAddressBuffer "
490         << getAtomicCounterNameForBinding(binding) << " : register(u" << registerIndex << ");\n";
491 }
492 
uniformsHeader(TInfoSinkBase & out,ShShaderOutput outputType,const ReferencedVariables & referencedUniforms,TSymbolTable * symbolTable)493 void ResourcesHLSL::uniformsHeader(TInfoSinkBase &out,
494                                    ShShaderOutput outputType,
495                                    const ReferencedVariables &referencedUniforms,
496                                    TSymbolTable *symbolTable)
497 {
498     if (!referencedUniforms.empty())
499     {
500         out << "// Uniforms\n\n";
501     }
502     // In the case of HLSL 4, sampler uniforms need to be grouped by type before the code is
503     // written. They are grouped based on the combination of the HLSL texture type and
504     // HLSL sampler type, enumerated in HLSLTextureSamplerGroup.
505     TVector<TVector<const TVariable *>> groupedSamplerUniforms(HLSL_TEXTURE_MAX + 1);
506     TMap<const TVariable *, TString> samplerInStructSymbolsToAPINames;
507     TVector<TVector<const TVariable *>> groupedReadonlyImageUniforms(HLSL_TEXTURE_MAX + 1);
508     TVector<TVector<const TVariable *>> groupedImageUniforms(HLSL_RWTEXTURE_MAX + 1);
509 
510     TUnorderedMap<int, unsigned int> assignedAtomicCounterBindings;
511     unsigned int reservedReadonlyImageRegisterCount = 0, reservedImageRegisterCount = 0;
512     for (auto &uniformIt : referencedUniforms)
513     {
514         // Output regular uniforms. Group sampler uniforms by type.
515         const TVariable &variable = *uniformIt.second;
516         const TType &type         = variable.getType();
517 
518         if (outputType == SH_HLSL_4_1_OUTPUT && IsSampler(type.getBasicType()))
519         {
520             HLSLTextureGroup group = TextureGroup(type.getBasicType());
521             groupedSamplerUniforms[group].push_back(&variable);
522         }
523         else if (outputType == SH_HLSL_4_0_FL9_3_OUTPUT && IsSampler(type.getBasicType()))
524         {
525             unsigned int registerIndex = assignUniformRegister(type, variable.name(), nullptr);
526             outputHLSL4_0_FL9_3Sampler(out, type, variable, registerIndex);
527         }
528         else if (outputType == SH_HLSL_4_1_OUTPUT && IsImage(type.getBasicType()))
529         {
530             if (IsImage2D(type.getBasicType()))
531             {
532                 const ShaderVariable *uniform = findUniformByName(variable.name());
533                 if (type.getMemoryQualifier().readonly)
534                 {
535                     reservedReadonlyImageRegisterCount +=
536                         HLSLVariableRegisterCount(*uniform, mOutputType);
537                 }
538                 else
539                 {
540                     reservedImageRegisterCount += HLSLVariableRegisterCount(*uniform, mOutputType);
541                 }
542                 continue;
543             }
544             if (type.getMemoryQualifier().readonly)
545             {
546                 HLSLTextureGroup group = TextureGroup(
547                     type.getBasicType(), type.getLayoutQualifier().imageInternalFormat);
548                 groupedReadonlyImageUniforms[group].push_back(&variable);
549             }
550             else
551             {
552                 HLSLRWTextureGroup group = RWTextureGroup(
553                     type.getBasicType(), type.getLayoutQualifier().imageInternalFormat);
554                 groupedImageUniforms[group].push_back(&variable);
555             }
556         }
557         else if (outputType == SH_HLSL_4_1_OUTPUT && IsAtomicCounter(type.getBasicType()))
558         {
559             TLayoutQualifier layout = type.getLayoutQualifier();
560             int binding             = layout.binding;
561             unsigned int registerIndex;
562             if (assignedAtomicCounterBindings.find(binding) == assignedAtomicCounterBindings.end())
563             {
564                 registerIndex                          = mUAVRegister++;
565                 assignedAtomicCounterBindings[binding] = registerIndex;
566                 outputAtomicCounterBuffer(out, binding, registerIndex);
567             }
568             else
569             {
570                 registerIndex = assignedAtomicCounterBindings[binding];
571             }
572             const ShaderVariable *uniform      = findUniformByName(variable.name());
573             mUniformRegisterMap[uniform->name] = registerIndex;
574         }
575         else
576         {
577             if (type.isStructureContainingSamplers())
578             {
579                 TVector<const TVariable *> samplerSymbols;
580                 TMap<const TVariable *, TString> symbolsToAPINames;
581                 ImmutableStringBuilder namePrefix(kAngleDecorString.length() +
582                                                   variable.name().length());
583                 namePrefix << kAngleDecorString;
584                 namePrefix << variable.name();
585                 type.createSamplerSymbols(namePrefix, TString(variable.name().data()),
586                                           &samplerSymbols, &symbolsToAPINames, symbolTable);
587                 for (const TVariable *sampler : samplerSymbols)
588                 {
589                     const TType &samplerType = sampler->getType();
590 
591                     if (outputType == SH_HLSL_4_1_OUTPUT)
592                     {
593                         HLSLTextureGroup group = TextureGroup(samplerType.getBasicType());
594                         groupedSamplerUniforms[group].push_back(sampler);
595                         samplerInStructSymbolsToAPINames[sampler] = symbolsToAPINames[sampler];
596                     }
597                     else if (outputType == SH_HLSL_4_0_FL9_3_OUTPUT)
598                     {
599                         unsigned int registerIndex = assignSamplerInStructUniformRegister(
600                             samplerType, symbolsToAPINames[sampler], nullptr);
601                         outputHLSL4_0_FL9_3Sampler(out, samplerType, *sampler, registerIndex);
602                     }
603                     else
604                     {
605                         ASSERT(outputType == SH_HLSL_3_0_OUTPUT);
606                         unsigned int registerIndex = assignSamplerInStructUniformRegister(
607                             samplerType, symbolsToAPINames[sampler], nullptr);
608                         outputUniform(out, samplerType, *sampler, registerIndex);
609                     }
610                 }
611             }
612             unsigned int registerIndex = assignUniformRegister(type, variable.name(), nullptr);
613             outputUniform(out, type, variable, registerIndex);
614         }
615     }
616 
617     if (outputType == SH_HLSL_4_1_OUTPUT)
618     {
619         unsigned int groupTextureRegisterIndex = 0;
620         // Atomic counters and RW texture share the same resources. Therefore, RW texture need to
621         // start counting after the last atomic counter.
622         unsigned int groupRWTextureRegisterIndex = mUAVRegister;
623         // TEXTURE_2D is special, index offset is assumed to be 0 and omitted in that case.
624         ASSERT(HLSL_TEXTURE_MIN == HLSL_TEXTURE_2D);
625         for (int groupId = HLSL_TEXTURE_MIN; groupId < HLSL_TEXTURE_MAX; ++groupId)
626         {
627             outputHLSLSamplerUniformGroup(
628                 out, HLSLTextureGroup(groupId), groupedSamplerUniforms[groupId],
629                 samplerInStructSymbolsToAPINames, &groupTextureRegisterIndex);
630         }
631         mSamplerCount = groupTextureRegisterIndex;
632 
633         // Reserve t type register for readonly image2D variables.
634         mReadonlyImage2DRegisterIndex = mSRVRegister;
635         groupTextureRegisterIndex += reservedReadonlyImageRegisterCount;
636         mSRVRegister += reservedReadonlyImageRegisterCount;
637 
638         for (int groupId = HLSL_TEXTURE_MIN; groupId < HLSL_TEXTURE_MAX; ++groupId)
639         {
640             outputHLSLReadonlyImageUniformGroup(out, HLSLTextureGroup(groupId),
641                                                 groupedReadonlyImageUniforms[groupId],
642                                                 &groupTextureRegisterIndex);
643         }
644         mReadonlyImageCount = groupTextureRegisterIndex - mReadonlyImage2DRegisterIndex;
645         if (mReadonlyImageCount)
646         {
647             out << "static const uint readonlyImageIndexStart = " << mReadonlyImage2DRegisterIndex
648                 << ";\n";
649         }
650 
651         // Reserve u type register for writable image2D variables.
652         mImage2DRegisterIndex = mUAVRegister;
653         groupRWTextureRegisterIndex += reservedImageRegisterCount;
654         mUAVRegister += reservedImageRegisterCount;
655 
656         for (int groupId = HLSL_RWTEXTURE_MIN; groupId < HLSL_RWTEXTURE_MAX; ++groupId)
657         {
658             outputHLSLImageUniformGroup(out, HLSLRWTextureGroup(groupId),
659                                         groupedImageUniforms[groupId],
660                                         &groupRWTextureRegisterIndex);
661         }
662         mImageCount = groupRWTextureRegisterIndex - mImage2DRegisterIndex;
663         if (mImageCount)
664         {
665             out << "static const uint imageIndexStart = " << mImage2DRegisterIndex << ";\n";
666         }
667     }
668 }
669 
samplerMetadataUniforms(TInfoSinkBase & out,unsigned int regIndex)670 void ResourcesHLSL::samplerMetadataUniforms(TInfoSinkBase &out, unsigned int regIndex)
671 {
672     // If mSamplerCount is 0 the shader doesn't use any textures for samplers.
673     if (mSamplerCount > 0)
674     {
675         out << "    struct SamplerMetadata\n"
676                "    {\n"
677                "        int baseLevel;\n"
678                "        int wrapModes;\n"
679                "        int2 padding;\n"
680                "        int4 intBorderColor;\n"
681                "    };\n"
682                "    SamplerMetadata samplerMetadata["
683             << mSamplerCount << "] : packoffset(c" << regIndex << ");\n";
684     }
685 }
686 
imageMetadataUniforms(TInfoSinkBase & out,unsigned int regIndex)687 void ResourcesHLSL::imageMetadataUniforms(TInfoSinkBase &out, unsigned int regIndex)
688 {
689     if (mReadonlyImageCount > 0 || mImageCount > 0)
690     {
691         out << "    struct ImageMetadata\n"
692                "    {\n"
693                "        int layer;\n"
694                "        uint level;\n"
695                "        int2 padding;\n"
696                "    };\n";
697 
698         if (mReadonlyImageCount > 0)
699         {
700             out << "    ImageMetadata readonlyImageMetadata[" << mReadonlyImageCount
701                 << "] : packoffset(c" << regIndex << ");\n";
702         }
703 
704         if (mImageCount > 0)
705         {
706             out << "    ImageMetadata imageMetadata[" << mImageCount << "] : packoffset(c"
707                 << regIndex + mReadonlyImageCount << ");\n";
708         }
709     }
710 }
711 
uniformBlocksHeader(const ReferencedInterfaceBlocks & referencedInterfaceBlocks,const std::map<int,const TInterfaceBlock * > & uniformBlockOptimizedMap)712 TString ResourcesHLSL::uniformBlocksHeader(
713     const ReferencedInterfaceBlocks &referencedInterfaceBlocks,
714     const std::map<int, const TInterfaceBlock *> &uniformBlockOptimizedMap)
715 {
716     TString interfaceBlocks;
717 
718     for (const auto &blockReference : referencedInterfaceBlocks)
719     {
720         const TInterfaceBlock &interfaceBlock = *blockReference.second->block;
721         const TVariable *instanceVariable     = blockReference.second->instanceVariable;
722         if (instanceVariable != nullptr)
723         {
724             interfaceBlocks += uniformBlockStructString(interfaceBlock);
725         }
726 
727         // In order to avoid compile performance issue, translate uniform block to structured
728         // buffer. anglebug.com/3682.
729         if (uniformBlockOptimizedMap.count(interfaceBlock.uniqueId().get()) != 0)
730         {
731             unsigned int structuredBufferRegister = mSRVRegister;
732             if (instanceVariable != nullptr && instanceVariable->getType().isArray())
733             {
734                 unsigned int instanceArraySize =
735                     instanceVariable->getType().getOutermostArraySize();
736                 for (unsigned int arrayIndex = 0; arrayIndex < instanceArraySize; arrayIndex++)
737                 {
738                     interfaceBlocks += uniformBlockWithOneLargeArrayMemberString(
739                         interfaceBlock, instanceVariable, structuredBufferRegister + arrayIndex,
740                         arrayIndex);
741                 }
742                 mSRVRegister += instanceArraySize;
743             }
744             else
745             {
746                 interfaceBlocks += uniformBlockWithOneLargeArrayMemberString(
747                     interfaceBlock, instanceVariable, structuredBufferRegister, GL_INVALID_INDEX);
748                 mSRVRegister += 1u;
749             }
750             mUniformBlockRegisterMap[interfaceBlock.name().data()] = structuredBufferRegister;
751             mUniformBlockUseStructuredBufferMap[interfaceBlock.name().data()] = true;
752             continue;
753         }
754 
755         unsigned int activeRegister                            = mUniformBlockRegister;
756         mUniformBlockRegisterMap[interfaceBlock.name().data()] = activeRegister;
757 
758         if (instanceVariable != nullptr && instanceVariable->getType().isArray())
759         {
760             unsigned int instanceArraySize = instanceVariable->getType().getOutermostArraySize();
761             for (unsigned int arrayIndex = 0; arrayIndex < instanceArraySize; arrayIndex++)
762             {
763                 interfaceBlocks += uniformBlockString(interfaceBlock, instanceVariable,
764                                                       activeRegister + arrayIndex, arrayIndex);
765             }
766             mUniformBlockRegister += instanceArraySize;
767         }
768         else
769         {
770             interfaceBlocks += uniformBlockString(interfaceBlock, instanceVariable, activeRegister,
771                                                   GL_INVALID_INDEX);
772             mUniformBlockRegister += 1u;
773         }
774     }
775 
776     return (interfaceBlocks.empty() ? "" : ("// Uniform Blocks\n\n" + interfaceBlocks));
777 }
778 
allocateShaderStorageBlockRegisters(const ReferencedInterfaceBlocks & referencedInterfaceBlocks)779 void ResourcesHLSL::allocateShaderStorageBlockRegisters(
780     const ReferencedInterfaceBlocks &referencedInterfaceBlocks)
781 {
782     for (const auto &interfaceBlockReference : referencedInterfaceBlocks)
783     {
784         const TInterfaceBlock &interfaceBlock = *interfaceBlockReference.second->block;
785         const TVariable *instanceVariable     = interfaceBlockReference.second->instanceVariable;
786 
787         mShaderStorageBlockRegisterMap[interfaceBlock.name().data()] = mUAVRegister;
788 
789         if (instanceVariable != nullptr && instanceVariable->getType().isArray())
790         {
791             mUAVRegister += instanceVariable->getType().getOutermostArraySize();
792         }
793         else
794         {
795             mUAVRegister += 1u;
796         }
797     }
798 }
799 
shaderStorageBlocksHeader(const ReferencedInterfaceBlocks & referencedInterfaceBlocks)800 TString ResourcesHLSL::shaderStorageBlocksHeader(
801     const ReferencedInterfaceBlocks &referencedInterfaceBlocks)
802 {
803     TString interfaceBlocks;
804 
805     for (const auto &interfaceBlockReference : referencedInterfaceBlocks)
806     {
807         const TInterfaceBlock &interfaceBlock = *interfaceBlockReference.second->block;
808         const TVariable *instanceVariable     = interfaceBlockReference.second->instanceVariable;
809 
810         unsigned int activeRegister = mShaderStorageBlockRegisterMap[interfaceBlock.name().data()];
811 
812         if (instanceVariable != nullptr && instanceVariable->getType().isArray())
813         {
814             unsigned int instanceArraySize = instanceVariable->getType().getOutermostArraySize();
815             for (unsigned int arrayIndex = 0; arrayIndex < instanceArraySize; arrayIndex++)
816             {
817                 interfaceBlocks += shaderStorageBlockString(
818                     interfaceBlock, instanceVariable, activeRegister + arrayIndex, arrayIndex);
819             }
820         }
821         else
822         {
823             interfaceBlocks += shaderStorageBlockString(interfaceBlock, instanceVariable,
824                                                         activeRegister, GL_INVALID_INDEX);
825         }
826     }
827 
828     return interfaceBlocks;
829 }
830 
uniformBlockString(const TInterfaceBlock & interfaceBlock,const TVariable * instanceVariable,unsigned int registerIndex,unsigned int arrayIndex)831 TString ResourcesHLSL::uniformBlockString(const TInterfaceBlock &interfaceBlock,
832                                           const TVariable *instanceVariable,
833                                           unsigned int registerIndex,
834                                           unsigned int arrayIndex)
835 {
836     const TString &arrayIndexString = (arrayIndex != GL_INVALID_INDEX ? str(arrayIndex) : "");
837     const TString &blockName        = TString(interfaceBlock.name().data()) + arrayIndexString;
838     TString hlsl;
839 
840     hlsl += "cbuffer " + blockName + " : register(b" + str(registerIndex) +
841             ")\n"
842             "{\n";
843 
844     if (instanceVariable != nullptr)
845     {
846         hlsl += "    " + InterfaceBlockStructName(interfaceBlock) + " " +
847                 InterfaceBlockInstanceString(instanceVariable->name(), arrayIndex) + ";\n";
848     }
849     else
850     {
851         const TLayoutBlockStorage blockStorage = interfaceBlock.blockStorage();
852         hlsl += uniformBlockMembersString(interfaceBlock, blockStorage);
853     }
854 
855     hlsl += "};\n\n";
856 
857     return hlsl;
858 }
859 
uniformBlockWithOneLargeArrayMemberString(const TInterfaceBlock & interfaceBlock,const TVariable * instanceVariable,unsigned int registerIndex,unsigned int arrayIndex)860 TString ResourcesHLSL::uniformBlockWithOneLargeArrayMemberString(
861     const TInterfaceBlock &interfaceBlock,
862     const TVariable *instanceVariable,
863     unsigned int registerIndex,
864     unsigned int arrayIndex)
865 {
866     TString hlsl, typeString;
867 
868     const TField &field                    = *interfaceBlock.fields()[0];
869     const TLayoutBlockStorage blockStorage = interfaceBlock.blockStorage();
870     typeString             = InterfaceBlockFieldTypeString(field, blockStorage, true);
871     const TType &fieldType = *field.type();
872     if (fieldType.isMatrix())
873     {
874         if (arrayIndex == GL_INVALID_INDEX || arrayIndex == 0)
875         {
876             hlsl += "struct pack" + Decorate(interfaceBlock.name()) + " { " + typeString + " " +
877                     Decorate(field.name()) + "; };\n";
878         }
879         typeString = "pack" + Decorate(interfaceBlock.name());
880     }
881     else if (fieldType.isVectorArray() || fieldType.isScalarArray())
882     {
883         // If the member is an array of scalars or vectors, std140 rules require the base array
884         // stride are rounded up to the base alignment of a vec4.
885         if (arrayIndex == GL_INVALID_INDEX || arrayIndex == 0)
886         {
887             hlsl += "struct pack" + Decorate(interfaceBlock.name()) + " { " + typeString + " " +
888                     Decorate(field.name()) + ";\n";
889             hlsl += InterfaceBlockScalarVectorFieldPaddingString(fieldType) + " };\n";
890         }
891         typeString = "pack" + Decorate(interfaceBlock.name());
892     }
893 
894     if (instanceVariable != nullptr)
895     {
896 
897         hlsl += "StructuredBuffer <" + typeString + "> " +
898                 InterfaceBlockInstanceString(instanceVariable->name(), arrayIndex) + "_" +
899                 Decorate(field.name()) + +" : register(t" + str(registerIndex) + ");\n";
900     }
901     else
902     {
903         hlsl += "StructuredBuffer <" + typeString + "> " + Decorate(field.name()) +
904                 " : register(t" + str(registerIndex) + ");\n";
905     }
906 
907     return hlsl;
908 }
909 
shaderStorageBlockString(const TInterfaceBlock & interfaceBlock,const TVariable * instanceVariable,unsigned int registerIndex,unsigned int arrayIndex)910 TString ResourcesHLSL::shaderStorageBlockString(const TInterfaceBlock &interfaceBlock,
911                                                 const TVariable *instanceVariable,
912                                                 unsigned int registerIndex,
913                                                 unsigned int arrayIndex)
914 {
915     TString hlsl;
916     if (instanceVariable != nullptr)
917     {
918         hlsl += "RWByteAddressBuffer " +
919                 InterfaceBlockInstanceString(instanceVariable->name(), arrayIndex) +
920                 ": register(u" + str(registerIndex) + ");\n";
921     }
922     else
923     {
924         hlsl += "RWByteAddressBuffer " + Decorate(interfaceBlock.name()) + ": register(u" +
925                 str(registerIndex) + ");\n";
926     }
927     return hlsl;
928 }
929 
InterfaceBlockInstanceString(const ImmutableString & instanceName,unsigned int arrayIndex)930 TString ResourcesHLSL::InterfaceBlockInstanceString(const ImmutableString &instanceName,
931                                                     unsigned int arrayIndex)
932 {
933     if (arrayIndex != GL_INVALID_INDEX)
934     {
935         return DecoratePrivate(instanceName) + "_" + str(arrayIndex);
936     }
937     else
938     {
939         return Decorate(instanceName);
940     }
941 }
942 
uniformBlockMembersString(const TInterfaceBlock & interfaceBlock,TLayoutBlockStorage blockStorage)943 TString ResourcesHLSL::uniformBlockMembersString(const TInterfaceBlock &interfaceBlock,
944                                                  TLayoutBlockStorage blockStorage)
945 {
946     TString hlsl;
947 
948     Std140PaddingHelper padHelper = mStructureHLSL->getPaddingHelper();
949 
950     const unsigned int fieldCount = static_cast<unsigned int>(interfaceBlock.fields().size());
951     for (unsigned int typeIndex = 0; typeIndex < fieldCount; typeIndex++)
952     {
953         const TField &field    = *interfaceBlock.fields()[typeIndex];
954         const TType &fieldType = *field.type();
955 
956         if (blockStorage == EbsStd140)
957         {
958             // 2 and 3 component vector types in some cases need pre-padding
959             hlsl += padHelper.prePaddingString(fieldType, false);
960         }
961 
962         hlsl += "    " + InterfaceBlockFieldTypeString(field, blockStorage, false) + " " +
963                 Decorate(field.name()) + ArrayString(fieldType).data() + ";\n";
964 
965         // must pad out after matrices and arrays, where HLSL usually allows itself room to pack
966         // stuff
967         if (blockStorage == EbsStd140)
968         {
969             const bool useHLSLRowMajorPacking =
970                 (fieldType.getLayoutQualifier().matrixPacking == EmpColumnMajor);
971             hlsl += padHelper.postPaddingString(fieldType, useHLSLRowMajorPacking,
972                                                 typeIndex == fieldCount - 1, false);
973         }
974     }
975 
976     return hlsl;
977 }
978 
uniformBlockStructString(const TInterfaceBlock & interfaceBlock)979 TString ResourcesHLSL::uniformBlockStructString(const TInterfaceBlock &interfaceBlock)
980 {
981     const TLayoutBlockStorage blockStorage = interfaceBlock.blockStorage();
982 
983     return "struct " + InterfaceBlockStructName(interfaceBlock) +
984            "\n"
985            "{\n" +
986            uniformBlockMembersString(interfaceBlock, blockStorage) + "};\n\n";
987 }
988 }  // namespace sh
989