• 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)40 static TString InterfaceBlockFieldTypeString(const TField &field, TLayoutBlockStorage blockStorage)
41 {
42     const TType &fieldType                   = *field.type();
43     const TLayoutMatrixPacking matrixPacking = fieldType.getLayoutQualifier().matrixPacking;
44     ASSERT(matrixPacking != EmpUnspecified);
45     const TStructure *structure = fieldType.getStruct();
46 
47     if (fieldType.isMatrix())
48     {
49         // Use HLSL row-major packing for GLSL column-major matrices
50         const TString &matrixPackString =
51             (matrixPacking == EmpRowMajor ? "column_major" : "row_major");
52         return matrixPackString + " " + TypeString(fieldType);
53     }
54     else if (structure)
55     {
56         // Use HLSL row-major packing for GLSL column-major matrices
57         return QualifiedStructNameString(*structure, matrixPacking == EmpColumnMajor,
58                                          blockStorage == EbsStd140);
59     }
60     else
61     {
62         return TypeString(fieldType);
63     }
64 }
65 
InterfaceBlockStructName(const TInterfaceBlock & interfaceBlock)66 static TString InterfaceBlockStructName(const TInterfaceBlock &interfaceBlock)
67 {
68     return DecoratePrivate(interfaceBlock.name()) + "_type";
69 }
70 
OutputUniformIndexArrayInitializer(TInfoSinkBase & out,const TType & type,unsigned int startIndex)71 void OutputUniformIndexArrayInitializer(TInfoSinkBase &out,
72                                         const TType &type,
73                                         unsigned int startIndex)
74 {
75     out << "{";
76     TType elementType(type);
77     elementType.toArrayElementType();
78     for (unsigned int i = 0u; i < type.getOutermostArraySize(); ++i)
79     {
80         if (i > 0u)
81         {
82             out << ", ";
83         }
84         if (elementType.isArray())
85         {
86             OutputUniformIndexArrayInitializer(out, elementType,
87                                                startIndex + i * elementType.getArraySizeProduct());
88         }
89         else
90         {
91             out << (startIndex + i);
92         }
93     }
94     out << "}";
95 }
96 
97 }  // anonymous namespace
98 
ResourcesHLSL(StructureHLSL * structureHLSL,ShShaderOutput outputType,const std::vector<Uniform> & uniforms,unsigned int firstUniformRegister)99 ResourcesHLSL::ResourcesHLSL(StructureHLSL *structureHLSL,
100                              ShShaderOutput outputType,
101                              const std::vector<Uniform> &uniforms,
102                              unsigned int firstUniformRegister)
103     : mUniformRegister(firstUniformRegister),
104       mUniformBlockRegister(0),
105       mTextureRegister(0),
106       mUAVRegister(0),
107       mSamplerCount(0),
108       mStructureHLSL(structureHLSL),
109       mOutputType(outputType),
110       mUniforms(uniforms)
111 {}
112 
reserveUniformRegisters(unsigned int registerCount)113 void ResourcesHLSL::reserveUniformRegisters(unsigned int registerCount)
114 {
115     mUniformRegister = registerCount;
116 }
117 
reserveUniformBlockRegisters(unsigned int registerCount)118 void ResourcesHLSL::reserveUniformBlockRegisters(unsigned int registerCount)
119 {
120     mUniformBlockRegister = registerCount;
121 }
122 
findUniformByName(const ImmutableString & name) const123 const Uniform *ResourcesHLSL::findUniformByName(const ImmutableString &name) const
124 {
125     for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); ++uniformIndex)
126     {
127         if (name == mUniforms[uniformIndex].name)
128         {
129             return &mUniforms[uniformIndex];
130         }
131     }
132 
133     return nullptr;
134 }
135 
assignUniformRegister(const TType & type,const ImmutableString & name,unsigned int * outRegisterCount)136 unsigned int ResourcesHLSL::assignUniformRegister(const TType &type,
137                                                   const ImmutableString &name,
138                                                   unsigned int *outRegisterCount)
139 {
140     unsigned int registerIndex;
141     const Uniform *uniform = findUniformByName(name);
142     ASSERT(uniform);
143 
144     if (IsSampler(type.getBasicType()) ||
145         (IsImage(type.getBasicType()) && type.getMemoryQualifier().readonly))
146     {
147         registerIndex = mTextureRegister;
148     }
149     else if (IsImage(type.getBasicType()))
150     {
151         registerIndex = mUAVRegister;
152     }
153     else
154     {
155         registerIndex = mUniformRegister;
156     }
157 
158     if (uniform->name == "angle_DrawID" && uniform->mappedName == "angle_DrawID")
159     {
160         mUniformRegisterMap["gl_DrawID"] = registerIndex;
161     }
162     else
163     {
164         mUniformRegisterMap[uniform->name] = registerIndex;
165     }
166 
167     unsigned int registerCount = HLSLVariableRegisterCount(*uniform, mOutputType);
168 
169     if (IsSampler(type.getBasicType()) ||
170         (IsImage(type.getBasicType()) && type.getMemoryQualifier().readonly))
171     {
172         mTextureRegister += registerCount;
173     }
174     else if (IsImage(type.getBasicType()))
175     {
176         mUAVRegister += registerCount;
177     }
178     else
179     {
180         mUniformRegister += registerCount;
181     }
182     if (outRegisterCount)
183     {
184         *outRegisterCount = registerCount;
185     }
186     return registerIndex;
187 }
188 
assignSamplerInStructUniformRegister(const TType & type,const TString & name,unsigned int * outRegisterCount)189 unsigned int ResourcesHLSL::assignSamplerInStructUniformRegister(const TType &type,
190                                                                  const TString &name,
191                                                                  unsigned int *outRegisterCount)
192 {
193     // Sampler that is a field of a uniform structure.
194     ASSERT(IsSampler(type.getBasicType()));
195     unsigned int registerIndex                     = mTextureRegister;
196     mUniformRegisterMap[std::string(name.c_str())] = registerIndex;
197     unsigned int registerCount = type.isArray() ? type.getArraySizeProduct() : 1u;
198     mTextureRegister += registerCount;
199     if (outRegisterCount)
200     {
201         *outRegisterCount = registerCount;
202     }
203     return registerIndex;
204 }
205 
outputHLSLSamplerUniformGroup(TInfoSinkBase & out,const HLSLTextureGroup textureGroup,const TVector<const TVariable * > & group,const TMap<const TVariable *,TString> & samplerInStructSymbolsToAPINames,unsigned int * groupTextureRegisterIndex)206 void ResourcesHLSL::outputHLSLSamplerUniformGroup(
207     TInfoSinkBase &out,
208     const HLSLTextureGroup textureGroup,
209     const TVector<const TVariable *> &group,
210     const TMap<const TVariable *, TString> &samplerInStructSymbolsToAPINames,
211     unsigned int *groupTextureRegisterIndex)
212 {
213     if (group.empty())
214     {
215         return;
216     }
217     unsigned int groupRegisterCount = 0;
218     for (const TVariable *uniform : group)
219     {
220         const TType &type           = uniform->getType();
221         const ImmutableString &name = uniform->name();
222         unsigned int registerCount;
223 
224         // The uniform might be just a regular sampler or one extracted from a struct.
225         unsigned int samplerArrayIndex = 0u;
226         const Uniform *uniformByName   = findUniformByName(name);
227         if (uniformByName)
228         {
229             samplerArrayIndex = assignUniformRegister(type, name, &registerCount);
230         }
231         else
232         {
233             ASSERT(samplerInStructSymbolsToAPINames.find(uniform) !=
234                    samplerInStructSymbolsToAPINames.end());
235             samplerArrayIndex = assignSamplerInStructUniformRegister(
236                 type, samplerInStructSymbolsToAPINames.at(uniform), &registerCount);
237         }
238         groupRegisterCount += registerCount;
239 
240         if (type.isArray())
241         {
242             out << "static const uint " << DecorateVariableIfNeeded(*uniform) << ArrayString(type)
243                 << " = ";
244             OutputUniformIndexArrayInitializer(out, type, samplerArrayIndex);
245             out << ";\n";
246         }
247         else
248         {
249             out << "static const uint " << DecorateVariableIfNeeded(*uniform) << " = "
250                 << samplerArrayIndex << ";\n";
251         }
252     }
253     TString suffix = TextureGroupSuffix(textureGroup);
254     // Since HLSL_TEXTURE_2D is the first group, it has a fixed offset of zero.
255     if (textureGroup != HLSL_TEXTURE_2D)
256     {
257         out << "static const uint textureIndexOffset" << suffix << " = "
258             << (*groupTextureRegisterIndex) << ";\n";
259         out << "static const uint samplerIndexOffset" << suffix << " = "
260             << (*groupTextureRegisterIndex) << ";\n";
261     }
262     out << "uniform " << TextureString(textureGroup) << " textures" << suffix << "["
263         << groupRegisterCount << "]"
264         << " : register(t" << (*groupTextureRegisterIndex) << ");\n";
265     out << "uniform " << SamplerString(textureGroup) << " samplers" << suffix << "["
266         << groupRegisterCount << "]"
267         << " : register(s" << (*groupTextureRegisterIndex) << ");\n";
268     *groupTextureRegisterIndex += groupRegisterCount;
269 }
270 
outputHLSLImageUniformIndices(TInfoSinkBase & out,const TVector<const TVariable * > & group,unsigned int imageArrayIndex,unsigned int * groupRegisterCount)271 void ResourcesHLSL::outputHLSLImageUniformIndices(TInfoSinkBase &out,
272                                                   const TVector<const TVariable *> &group,
273                                                   unsigned int imageArrayIndex,
274                                                   unsigned int *groupRegisterCount)
275 {
276     for (const TVariable *uniform : group)
277     {
278         const TType &type           = uniform->getType();
279         const ImmutableString &name = uniform->name();
280         unsigned int registerCount  = 0;
281 
282         assignUniformRegister(type, name, &registerCount);
283         *groupRegisterCount += registerCount;
284 
285         if (type.isArray())
286         {
287             out << "static const uint " << DecorateVariableIfNeeded(*uniform) << ArrayString(type)
288                 << " = ";
289             OutputUniformIndexArrayInitializer(out, type, imageArrayIndex);
290             out << ";\n";
291         }
292         else
293         {
294             out << "static const uint " << DecorateVariableIfNeeded(*uniform) << " = "
295                 << imageArrayIndex << ";\n";
296         }
297 
298         imageArrayIndex += registerCount;
299     }
300 }
301 
outputHLSLReadonlyImageUniformGroup(TInfoSinkBase & out,const HLSLTextureGroup textureGroup,const TVector<const TVariable * > & group,unsigned int * groupTextureRegisterIndex)302 void ResourcesHLSL::outputHLSLReadonlyImageUniformGroup(TInfoSinkBase &out,
303                                                         const HLSLTextureGroup textureGroup,
304                                                         const TVector<const TVariable *> &group,
305                                                         unsigned int *groupTextureRegisterIndex)
306 {
307     if (group.empty())
308     {
309         return;
310     }
311 
312     unsigned int groupRegisterCount = 0;
313     outputHLSLImageUniformIndices(out, group, *groupTextureRegisterIndex, &groupRegisterCount);
314 
315     TString suffix = TextureGroupSuffix(textureGroup);
316     out << "static const uint readonlyImageIndexOffset" << suffix << " = "
317         << (*groupTextureRegisterIndex) << ";\n";
318     out << "uniform " << TextureString(textureGroup) << " readonlyImages" << suffix << "["
319         << groupRegisterCount << "]"
320         << " : register(t" << (*groupTextureRegisterIndex) << ");\n";
321     *groupTextureRegisterIndex += groupRegisterCount;
322 }
323 
outputHLSLImageUniformGroup(TInfoSinkBase & out,const HLSLRWTextureGroup textureGroup,const TVector<const TVariable * > & group,unsigned int * groupTextureRegisterIndex)324 void ResourcesHLSL::outputHLSLImageUniformGroup(TInfoSinkBase &out,
325                                                 const HLSLRWTextureGroup textureGroup,
326                                                 const TVector<const TVariable *> &group,
327                                                 unsigned int *groupTextureRegisterIndex)
328 {
329     if (group.empty())
330     {
331         return;
332     }
333 
334     unsigned int groupRegisterCount = 0;
335     outputHLSLImageUniformIndices(out, group, *groupTextureRegisterIndex, &groupRegisterCount);
336 
337     TString suffix = RWTextureGroupSuffix(textureGroup);
338     out << "static const uint imageIndexOffset" << suffix << " = " << (*groupTextureRegisterIndex)
339         << ";\n";
340     out << "uniform " << RWTextureString(textureGroup) << " images" << suffix << "["
341         << groupRegisterCount << "]"
342         << " : register(u" << (*groupTextureRegisterIndex) << ");\n";
343     *groupTextureRegisterIndex += groupRegisterCount;
344 }
345 
outputHLSL4_0_FL9_3Sampler(TInfoSinkBase & out,const TType & type,const TVariable & variable,const unsigned int registerIndex)346 void ResourcesHLSL::outputHLSL4_0_FL9_3Sampler(TInfoSinkBase &out,
347                                                const TType &type,
348                                                const TVariable &variable,
349                                                const unsigned int registerIndex)
350 {
351     out << "uniform " << SamplerString(type.getBasicType()) << " sampler_"
352         << DecorateVariableIfNeeded(variable) << ArrayString(type) << " : register(s"
353         << str(registerIndex) << ");\n";
354     out << "uniform " << TextureString(type.getBasicType()) << " texture_"
355         << DecorateVariableIfNeeded(variable) << ArrayString(type) << " : register(t"
356         << str(registerIndex) << ");\n";
357 }
358 
outputUniform(TInfoSinkBase & out,const TType & type,const TVariable & variable,const unsigned int registerIndex)359 void ResourcesHLSL::outputUniform(TInfoSinkBase &out,
360                                   const TType &type,
361                                   const TVariable &variable,
362                                   const unsigned int registerIndex)
363 {
364     const TStructure *structure = type.getStruct();
365     // If this is a nameless struct, we need to use its full definition, rather than its (empty)
366     // name.
367     // TypeString() will invoke defineNameless in this case; qualifier prefixes are unnecessary for
368     // nameless structs in ES, as nameless structs cannot be used anywhere that layout qualifiers
369     // are permitted.
370     const TString &typeName = ((structure && structure->symbolType() != SymbolType::Empty)
371                                    ? QualifiedStructNameString(*structure, false, false)
372                                    : TypeString(type));
373 
374     const TString &registerString =
375         TString("register(") + UniformRegisterPrefix(type) + str(registerIndex) + ")";
376 
377     out << "uniform " << typeName << " ";
378 
379     out << DecorateVariableIfNeeded(variable);
380 
381     out << ArrayString(type) << " : " << registerString << ";\n";
382 }
383 
outputAtomicCounterBuffer(TInfoSinkBase & out,const int binding,const unsigned int registerIndex)384 void ResourcesHLSL::outputAtomicCounterBuffer(TInfoSinkBase &out,
385                                               const int binding,
386                                               const unsigned int registerIndex)
387 {
388     // Atomic counter memory access is not incoherent
389     out << "uniform globallycoherent RWByteAddressBuffer "
390         << getAtomicCounterNameForBinding(binding) << " : register(u" << registerIndex << ");\n";
391 }
392 
uniformsHeader(TInfoSinkBase & out,ShShaderOutput outputType,const ReferencedVariables & referencedUniforms,TSymbolTable * symbolTable)393 void ResourcesHLSL::uniformsHeader(TInfoSinkBase &out,
394                                    ShShaderOutput outputType,
395                                    const ReferencedVariables &referencedUniforms,
396                                    TSymbolTable *symbolTable)
397 {
398     if (!referencedUniforms.empty())
399     {
400         out << "// Uniforms\n\n";
401     }
402     // In the case of HLSL 4, sampler uniforms need to be grouped by type before the code is
403     // written. They are grouped based on the combination of the HLSL texture type and
404     // HLSL sampler type, enumerated in HLSLTextureSamplerGroup.
405     TVector<TVector<const TVariable *>> groupedSamplerUniforms(HLSL_TEXTURE_MAX + 1);
406     TMap<const TVariable *, TString> samplerInStructSymbolsToAPINames;
407     TVector<TVector<const TVariable *>> groupedReadonlyImageUniforms(HLSL_TEXTURE_MAX + 1);
408     TVector<TVector<const TVariable *>> groupedImageUniforms(HLSL_RWTEXTURE_MAX + 1);
409 
410     TUnorderedMap<int, unsigned int> assignedAtomicCounterBindings;
411     unsigned int reservedReadonlyImageRegisterCount = 0, reservedImageRegisterCount = 0;
412     for (auto &uniformIt : referencedUniforms)
413     {
414         // Output regular uniforms. Group sampler uniforms by type.
415         const TVariable &variable = *uniformIt.second;
416         const TType &type         = variable.getType();
417 
418         if (outputType == SH_HLSL_4_1_OUTPUT && IsSampler(type.getBasicType()))
419         {
420             HLSLTextureGroup group = TextureGroup(type.getBasicType());
421             groupedSamplerUniforms[group].push_back(&variable);
422         }
423         else if (outputType == SH_HLSL_4_0_FL9_3_OUTPUT && IsSampler(type.getBasicType()))
424         {
425             unsigned int registerIndex = assignUniformRegister(type, variable.name(), nullptr);
426             outputHLSL4_0_FL9_3Sampler(out, type, variable, registerIndex);
427         }
428         else if (outputType == SH_HLSL_4_1_OUTPUT && IsImage(type.getBasicType()))
429         {
430             if (IsImage2D(type.getBasicType()))
431             {
432                 const Uniform *uniform = findUniformByName(variable.name());
433                 if (type.getMemoryQualifier().readonly)
434                 {
435                     reservedReadonlyImageRegisterCount +=
436                         HLSLVariableRegisterCount(*uniform, mOutputType);
437                 }
438                 else
439                 {
440                     reservedImageRegisterCount += HLSLVariableRegisterCount(*uniform, mOutputType);
441                 }
442                 continue;
443             }
444             if (type.getMemoryQualifier().readonly)
445             {
446                 HLSLTextureGroup group = TextureGroup(
447                     type.getBasicType(), type.getLayoutQualifier().imageInternalFormat);
448                 groupedReadonlyImageUniforms[group].push_back(&variable);
449             }
450             else
451             {
452                 HLSLRWTextureGroup group = RWTextureGroup(
453                     type.getBasicType(), type.getLayoutQualifier().imageInternalFormat);
454                 groupedImageUniforms[group].push_back(&variable);
455             }
456         }
457         else if (outputType == SH_HLSL_4_1_OUTPUT && IsAtomicCounter(type.getBasicType()))
458         {
459             TLayoutQualifier layout = type.getLayoutQualifier();
460             int binding             = layout.binding;
461             unsigned int registerIndex;
462             if (assignedAtomicCounterBindings.find(binding) == assignedAtomicCounterBindings.end())
463             {
464                 registerIndex                          = mUAVRegister++;
465                 assignedAtomicCounterBindings[binding] = registerIndex;
466                 outputAtomicCounterBuffer(out, binding, registerIndex);
467             }
468             else
469             {
470                 registerIndex = assignedAtomicCounterBindings[binding];
471             }
472             const Uniform *uniform             = findUniformByName(variable.name());
473             mUniformRegisterMap[uniform->name] = registerIndex;
474         }
475         else
476         {
477             if (type.isStructureContainingSamplers())
478             {
479                 TVector<const TVariable *> samplerSymbols;
480                 TMap<const TVariable *, TString> symbolsToAPINames;
481                 ImmutableStringBuilder namePrefix(kAngleDecorString.length() +
482                                                   variable.name().length());
483                 namePrefix << kAngleDecorString;
484                 namePrefix << variable.name();
485                 type.createSamplerSymbols(namePrefix, TString(variable.name().data()),
486                                           &samplerSymbols, &symbolsToAPINames, symbolTable);
487                 for (const TVariable *sampler : samplerSymbols)
488                 {
489                     const TType &samplerType = sampler->getType();
490 
491                     if (outputType == SH_HLSL_4_1_OUTPUT)
492                     {
493                         HLSLTextureGroup group = TextureGroup(samplerType.getBasicType());
494                         groupedSamplerUniforms[group].push_back(sampler);
495                         samplerInStructSymbolsToAPINames[sampler] = symbolsToAPINames[sampler];
496                     }
497                     else if (outputType == SH_HLSL_4_0_FL9_3_OUTPUT)
498                     {
499                         unsigned int registerIndex = assignSamplerInStructUniformRegister(
500                             samplerType, symbolsToAPINames[sampler], nullptr);
501                         outputHLSL4_0_FL9_3Sampler(out, samplerType, *sampler, registerIndex);
502                     }
503                     else
504                     {
505                         ASSERT(outputType == SH_HLSL_3_0_OUTPUT);
506                         unsigned int registerIndex = assignSamplerInStructUniformRegister(
507                             samplerType, symbolsToAPINames[sampler], nullptr);
508                         outputUniform(out, samplerType, *sampler, registerIndex);
509                     }
510                 }
511             }
512             unsigned int registerIndex = assignUniformRegister(type, variable.name(), nullptr);
513             outputUniform(out, type, variable, registerIndex);
514         }
515     }
516 
517     if (outputType == SH_HLSL_4_1_OUTPUT)
518     {
519         unsigned int groupTextureRegisterIndex = 0;
520         // Atomic counters and RW texture share the same resources. Therefore, RW texture need to
521         // start counting after the last atomic counter.
522         unsigned int groupRWTextureRegisterIndex = mUAVRegister;
523         // TEXTURE_2D is special, index offset is assumed to be 0 and omitted in that case.
524         ASSERT(HLSL_TEXTURE_MIN == HLSL_TEXTURE_2D);
525         for (int groupId = HLSL_TEXTURE_MIN; groupId < HLSL_TEXTURE_MAX; ++groupId)
526         {
527             outputHLSLSamplerUniformGroup(
528                 out, HLSLTextureGroup(groupId), groupedSamplerUniforms[groupId],
529                 samplerInStructSymbolsToAPINames, &groupTextureRegisterIndex);
530         }
531         mSamplerCount = groupTextureRegisterIndex;
532 
533         // Reserve t type register for readonly image2D variables.
534         mReadonlyImage2DRegisterIndex = mTextureRegister;
535         groupTextureRegisterIndex += reservedReadonlyImageRegisterCount;
536         mTextureRegister += reservedReadonlyImageRegisterCount;
537 
538         for (int groupId = HLSL_TEXTURE_MIN; groupId < HLSL_TEXTURE_MAX; ++groupId)
539         {
540             outputHLSLReadonlyImageUniformGroup(out, HLSLTextureGroup(groupId),
541                                                 groupedReadonlyImageUniforms[groupId],
542                                                 &groupTextureRegisterIndex);
543         }
544         mReadonlyImageCount = groupTextureRegisterIndex - mReadonlyImage2DRegisterIndex;
545         if (mReadonlyImageCount)
546         {
547             out << "static const uint readonlyImageIndexStart = " << mReadonlyImage2DRegisterIndex
548                 << ";\n";
549         }
550 
551         // Reserve u type register for writable image2D variables.
552         mImage2DRegisterIndex = mUAVRegister;
553         groupRWTextureRegisterIndex += reservedImageRegisterCount;
554         mUAVRegister += reservedImageRegisterCount;
555 
556         for (int groupId = HLSL_RWTEXTURE_MIN; groupId < HLSL_RWTEXTURE_MAX; ++groupId)
557         {
558             outputHLSLImageUniformGroup(out, HLSLRWTextureGroup(groupId),
559                                         groupedImageUniforms[groupId],
560                                         &groupRWTextureRegisterIndex);
561         }
562         mImageCount = groupRWTextureRegisterIndex - mImage2DRegisterIndex;
563         if (mImageCount)
564         {
565             out << "static const uint imageIndexStart = " << mImage2DRegisterIndex << ";\n";
566         }
567     }
568 }
569 
samplerMetadataUniforms(TInfoSinkBase & out,unsigned int regIndex)570 void ResourcesHLSL::samplerMetadataUniforms(TInfoSinkBase &out, unsigned int regIndex)
571 {
572     // If mSamplerCount is 0 the shader doesn't use any textures for samplers.
573     if (mSamplerCount > 0)
574     {
575         out << "    struct SamplerMetadata\n"
576                "    {\n"
577                "        int baseLevel;\n"
578                "        int internalFormatBits;\n"
579                "        int wrapModes;\n"
580                "        int padding;\n"
581                "        int4 intBorderColor;\n"
582                "    };\n"
583                "    SamplerMetadata samplerMetadata["
584             << mSamplerCount << "] : packoffset(c" << regIndex << ");\n";
585     }
586 }
587 
imageMetadataUniforms(TInfoSinkBase & out,unsigned int regIndex)588 void ResourcesHLSL::imageMetadataUniforms(TInfoSinkBase &out, unsigned int regIndex)
589 {
590     if (mReadonlyImageCount > 0 || mImageCount > 0)
591     {
592         out << "    struct ImageMetadata\n"
593                "    {\n"
594                "        int layer;\n"
595                "        uint level;\n"
596                "        int2 padding;\n"
597                "    };\n";
598 
599         if (mReadonlyImageCount > 0)
600         {
601             out << "    ImageMetadata readonlyImageMetadata[" << mReadonlyImageCount
602                 << "] : packoffset(c" << regIndex << ");\n";
603         }
604 
605         if (mImageCount > 0)
606         {
607             out << "    ImageMetadata imageMetadata[" << mImageCount << "] : packoffset(c"
608                 << regIndex + mReadonlyImageCount << ");\n";
609         }
610     }
611 }
612 
uniformBlocksHeader(const ReferencedInterfaceBlocks & referencedInterfaceBlocks)613 TString ResourcesHLSL::uniformBlocksHeader(
614     const ReferencedInterfaceBlocks &referencedInterfaceBlocks)
615 {
616     TString interfaceBlocks;
617 
618     for (const auto &blockReference : referencedInterfaceBlocks)
619     {
620         const TInterfaceBlock &interfaceBlock = *blockReference.second->block;
621         const TVariable *instanceVariable     = blockReference.second->instanceVariable;
622         if (instanceVariable != nullptr)
623         {
624             interfaceBlocks += uniformBlockStructString(interfaceBlock);
625         }
626 
627         unsigned int activeRegister                            = mUniformBlockRegister;
628         mUniformBlockRegisterMap[interfaceBlock.name().data()] = activeRegister;
629 
630         if (instanceVariable != nullptr && instanceVariable->getType().isArray())
631         {
632             unsigned int instanceArraySize = instanceVariable->getType().getOutermostArraySize();
633             for (unsigned int arrayIndex = 0; arrayIndex < instanceArraySize; arrayIndex++)
634             {
635                 interfaceBlocks += uniformBlockString(interfaceBlock, instanceVariable,
636                                                       activeRegister + arrayIndex, arrayIndex);
637             }
638             mUniformBlockRegister += instanceArraySize;
639         }
640         else
641         {
642             interfaceBlocks += uniformBlockString(interfaceBlock, instanceVariable, activeRegister,
643                                                   GL_INVALID_INDEX);
644             mUniformBlockRegister += 1u;
645         }
646     }
647 
648     return (interfaceBlocks.empty() ? "" : ("// Uniform Blocks\n\n" + interfaceBlocks));
649 }
650 
shaderStorageBlocksHeader(const ReferencedInterfaceBlocks & referencedInterfaceBlocks)651 TString ResourcesHLSL::shaderStorageBlocksHeader(
652     const ReferencedInterfaceBlocks &referencedInterfaceBlocks)
653 {
654     TString interfaceBlocks;
655 
656     for (const auto &interfaceBlockReference : referencedInterfaceBlocks)
657     {
658         const TInterfaceBlock &interfaceBlock = *interfaceBlockReference.second->block;
659         const TVariable *instanceVariable     = interfaceBlockReference.second->instanceVariable;
660 
661         unsigned int activeRegister                                  = mUAVRegister;
662         mShaderStorageBlockRegisterMap[interfaceBlock.name().data()] = activeRegister;
663 
664         if (instanceVariable != nullptr && instanceVariable->getType().isArray())
665         {
666             unsigned int instanceArraySize = instanceVariable->getType().getOutermostArraySize();
667             for (unsigned int arrayIndex = 0; arrayIndex < instanceArraySize; arrayIndex++)
668             {
669                 interfaceBlocks += shaderStorageBlockString(
670                     interfaceBlock, instanceVariable, activeRegister + arrayIndex, arrayIndex);
671             }
672             mUAVRegister += instanceArraySize;
673         }
674         else
675         {
676             interfaceBlocks += shaderStorageBlockString(interfaceBlock, instanceVariable,
677                                                         activeRegister, GL_INVALID_INDEX);
678             mUAVRegister += 1u;
679         }
680     }
681 
682     return (interfaceBlocks.empty() ? "" : ("// Shader Storage Blocks\n\n" + interfaceBlocks));
683 }
684 
uniformBlockString(const TInterfaceBlock & interfaceBlock,const TVariable * instanceVariable,unsigned int registerIndex,unsigned int arrayIndex)685 TString ResourcesHLSL::uniformBlockString(const TInterfaceBlock &interfaceBlock,
686                                           const TVariable *instanceVariable,
687                                           unsigned int registerIndex,
688                                           unsigned int arrayIndex)
689 {
690     const TString &arrayIndexString = (arrayIndex != GL_INVALID_INDEX ? str(arrayIndex) : "");
691     const TString &blockName        = TString(interfaceBlock.name().data()) + arrayIndexString;
692     TString hlsl;
693 
694     hlsl += "cbuffer " + blockName + " : register(b" + str(registerIndex) +
695             ")\n"
696             "{\n";
697 
698     if (instanceVariable != nullptr)
699     {
700         hlsl += "    " + InterfaceBlockStructName(interfaceBlock) + " " +
701                 InterfaceBlockInstanceString(instanceVariable->name(), arrayIndex) + ";\n";
702     }
703     else
704     {
705         const TLayoutBlockStorage blockStorage = interfaceBlock.blockStorage();
706         hlsl += uniformBlockMembersString(interfaceBlock, blockStorage);
707     }
708 
709     hlsl += "};\n\n";
710 
711     return hlsl;
712 }
713 
shaderStorageBlockString(const TInterfaceBlock & interfaceBlock,const TVariable * instanceVariable,unsigned int registerIndex,unsigned int arrayIndex)714 TString ResourcesHLSL::shaderStorageBlockString(const TInterfaceBlock &interfaceBlock,
715                                                 const TVariable *instanceVariable,
716                                                 unsigned int registerIndex,
717                                                 unsigned int arrayIndex)
718 {
719     TString hlsl;
720     if (instanceVariable != nullptr)
721     {
722         hlsl += "RWByteAddressBuffer " +
723                 InterfaceBlockInstanceString(instanceVariable->name(), arrayIndex) +
724                 ": register(u" + str(registerIndex) + ");\n";
725     }
726     else
727     {
728         hlsl += "RWByteAddressBuffer " + Decorate(interfaceBlock.name()) + ": register(u" +
729                 str(registerIndex) + ");\n";
730     }
731     return hlsl;
732 }
733 
InterfaceBlockInstanceString(const ImmutableString & instanceName,unsigned int arrayIndex)734 TString ResourcesHLSL::InterfaceBlockInstanceString(const ImmutableString &instanceName,
735                                                     unsigned int arrayIndex)
736 {
737     if (arrayIndex != GL_INVALID_INDEX)
738     {
739         return DecoratePrivate(instanceName) + "_" + str(arrayIndex);
740     }
741     else
742     {
743         return Decorate(instanceName);
744     }
745 }
746 
uniformBlockMembersString(const TInterfaceBlock & interfaceBlock,TLayoutBlockStorage blockStorage)747 TString ResourcesHLSL::uniformBlockMembersString(const TInterfaceBlock &interfaceBlock,
748                                                  TLayoutBlockStorage blockStorage)
749 {
750     TString hlsl;
751 
752     Std140PaddingHelper padHelper = mStructureHLSL->getPaddingHelper();
753 
754     for (unsigned int typeIndex = 0; typeIndex < interfaceBlock.fields().size(); typeIndex++)
755     {
756         const TField &field    = *interfaceBlock.fields()[typeIndex];
757         const TType &fieldType = *field.type();
758 
759         if (blockStorage == EbsStd140)
760         {
761             // 2 and 3 component vector types in some cases need pre-padding
762             hlsl += padHelper.prePaddingString(fieldType);
763         }
764 
765         hlsl += "    " + InterfaceBlockFieldTypeString(field, blockStorage) + " " +
766                 Decorate(field.name()) + ArrayString(fieldType).data() + ";\n";
767 
768         // must pad out after matrices and arrays, where HLSL usually allows itself room to pack
769         // stuff
770         if (blockStorage == EbsStd140)
771         {
772             const bool useHLSLRowMajorPacking =
773                 (fieldType.getLayoutQualifier().matrixPacking == EmpColumnMajor);
774             hlsl += padHelper.postPaddingString(fieldType, useHLSLRowMajorPacking);
775         }
776     }
777 
778     return hlsl;
779 }
780 
uniformBlockStructString(const TInterfaceBlock & interfaceBlock)781 TString ResourcesHLSL::uniformBlockStructString(const TInterfaceBlock &interfaceBlock)
782 {
783     const TLayoutBlockStorage blockStorage = interfaceBlock.blockStorage();
784 
785     return "struct " + InterfaceBlockStructName(interfaceBlock) +
786            "\n"
787            "{\n" +
788            uniformBlockMembersString(interfaceBlock, blockStorage) + "};\n\n";
789 }
790 }  // namespace sh
791