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, ®isterCount);
327 }
328 else
329 {
330 ASSERT(samplerInStructSymbolsToAPINames.find(uniform) !=
331 samplerInStructSymbolsToAPINames.end());
332 samplerArrayIndex = assignSamplerInStructUniformRegister(
333 type, samplerInStructSymbolsToAPINames.at(uniform), ®isterCount);
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, ®isterCount);
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 ®isterString =
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