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