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