1 //
2 // Copyright 2014 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // ResourcesHLSL.cpp:
7 // Methods for GLSL to HLSL translation for uniforms and interface blocks.
8 //
9
10 #include "compiler/translator/ResourcesHLSL.h"
11
12 #include "common/utilities.h"
13 #include "compiler/translator/AtomicCounterFunctionHLSL.h"
14 #include "compiler/translator/ImmutableStringBuilder.h"
15 #include "compiler/translator/StructureHLSL.h"
16 #include "compiler/translator/UtilsHLSL.h"
17 #include "compiler/translator/blocklayoutHLSL.h"
18 #include "compiler/translator/util.h"
19
20 namespace sh
21 {
22
23 namespace
24 {
25
26 constexpr const ImmutableString kAngleDecorString("angle_");
27
UniformRegisterPrefix(const TType & type)28 static const char *UniformRegisterPrefix(const TType &type)
29 {
30 if (IsSampler(type.getBasicType()))
31 {
32 return "s";
33 }
34 else
35 {
36 return "c";
37 }
38 }
39
InterfaceBlockFieldTypeString(const TField & field,TLayoutBlockStorage blockStorage,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
164 } // anonymous namespace
165
ResourcesHLSL(StructureHLSL * structureHLSL,ShShaderOutput outputType,const std::vector<ShaderVariable> & uniforms,unsigned int firstUniformRegister)166 ResourcesHLSL::ResourcesHLSL(StructureHLSL *structureHLSL,
167 ShShaderOutput outputType,
168 const std::vector<ShaderVariable> &uniforms,
169 unsigned int firstUniformRegister)
170 : mUniformRegister(firstUniformRegister),
171 mUniformBlockRegister(0),
172 mSRVRegister(0),
173 mUAVRegister(0),
174 mSamplerCount(0),
175 mStructureHLSL(structureHLSL),
176 mOutputType(outputType),
177 mUniforms(uniforms)
178 {}
179
reserveUniformRegisters(unsigned int registerCount)180 void ResourcesHLSL::reserveUniformRegisters(unsigned int registerCount)
181 {
182 mUniformRegister = registerCount;
183 }
184
reserveUniformBlockRegisters(unsigned int registerCount)185 void ResourcesHLSL::reserveUniformBlockRegisters(unsigned int registerCount)
186 {
187 mUniformBlockRegister = registerCount;
188 }
189
findUniformByName(const ImmutableString & name) const190 const ShaderVariable *ResourcesHLSL::findUniformByName(const ImmutableString &name) const
191 {
192 for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); ++uniformIndex)
193 {
194 if (name == mUniforms[uniformIndex].name)
195 {
196 return &mUniforms[uniformIndex];
197 }
198 }
199
200 return nullptr;
201 }
202
assignUniformRegister(const TType & type,const ImmutableString & name,unsigned int * outRegisterCount)203 unsigned int ResourcesHLSL::assignUniformRegister(const TType &type,
204 const ImmutableString &name,
205 unsigned int *outRegisterCount)
206 {
207 unsigned int registerIndex;
208 const ShaderVariable *uniform = findUniformByName(name);
209 ASSERT(uniform);
210
211 if (IsSampler(type.getBasicType()) ||
212 (IsImage(type.getBasicType()) && type.getMemoryQualifier().readonly))
213 {
214 registerIndex = mSRVRegister;
215 }
216 else if (IsImage(type.getBasicType()))
217 {
218 registerIndex = mUAVRegister;
219 }
220 else
221 {
222 registerIndex = mUniformRegister;
223 }
224
225 if (uniform->name == "angle_DrawID" && uniform->mappedName == "angle_DrawID")
226 {
227 mUniformRegisterMap["gl_DrawID"] = registerIndex;
228 }
229 else
230 {
231 mUniformRegisterMap[uniform->name] = registerIndex;
232 }
233
234 if (uniform->name == "angle_BaseVertex" && uniform->mappedName == "angle_BaseVertex")
235 {
236 mUniformRegisterMap["gl_BaseVertex"] = registerIndex;
237 }
238 else
239 {
240 mUniformRegisterMap[uniform->name] = registerIndex;
241 }
242
243 if (uniform->name == "angle_BaseInstance" && uniform->mappedName == "angle_BaseInstance")
244 {
245 mUniformRegisterMap["gl_BaseInstance"] = registerIndex;
246 }
247 else
248 {
249 mUniformRegisterMap[uniform->name] = registerIndex;
250 }
251
252 unsigned int registerCount = HLSLVariableRegisterCount(*uniform, mOutputType);
253
254 if (IsSampler(type.getBasicType()) ||
255 (IsImage(type.getBasicType()) && type.getMemoryQualifier().readonly))
256 {
257 mSRVRegister += registerCount;
258 }
259 else if (IsImage(type.getBasicType()))
260 {
261 mUAVRegister += registerCount;
262 }
263 else
264 {
265 mUniformRegister += registerCount;
266 }
267 if (outRegisterCount)
268 {
269 *outRegisterCount = registerCount;
270 }
271 return registerIndex;
272 }
273
assignSamplerInStructUniformRegister(const TType & type,const TString & name,unsigned int * outRegisterCount)274 unsigned int ResourcesHLSL::assignSamplerInStructUniformRegister(const TType &type,
275 const TString &name,
276 unsigned int *outRegisterCount)
277 {
278 // Sampler that is a field of a uniform structure.
279 ASSERT(IsSampler(type.getBasicType()));
280 unsigned int registerIndex = mSRVRegister;
281 mUniformRegisterMap[std::string(name.c_str())] = registerIndex;
282 unsigned int registerCount = type.isArray() ? type.getArraySizeProduct() : 1u;
283 mSRVRegister += registerCount;
284 if (outRegisterCount)
285 {
286 *outRegisterCount = registerCount;
287 }
288 return registerIndex;
289 }
290
outputHLSLSamplerUniformGroup(TInfoSinkBase & out,const HLSLTextureGroup textureGroup,const TVector<const TVariable * > & group,const TMap<const TVariable *,TString> & samplerInStructSymbolsToAPINames,unsigned int * groupTextureRegisterIndex)291 void ResourcesHLSL::outputHLSLSamplerUniformGroup(
292 TInfoSinkBase &out,
293 const HLSLTextureGroup textureGroup,
294 const TVector<const TVariable *> &group,
295 const TMap<const TVariable *, TString> &samplerInStructSymbolsToAPINames,
296 unsigned int *groupTextureRegisterIndex)
297 {
298 if (group.empty())
299 {
300 return;
301 }
302 unsigned int groupRegisterCount = 0;
303 for (const TVariable *uniform : group)
304 {
305 const TType &type = uniform->getType();
306 const ImmutableString &name = uniform->name();
307 unsigned int registerCount;
308
309 // The uniform might be just a regular sampler or one extracted from a struct.
310 unsigned int samplerArrayIndex = 0u;
311 const ShaderVariable *uniformByName = findUniformByName(name);
312 if (uniformByName)
313 {
314 samplerArrayIndex = assignUniformRegister(type, name, ®isterCount);
315 }
316 else
317 {
318 ASSERT(samplerInStructSymbolsToAPINames.find(uniform) !=
319 samplerInStructSymbolsToAPINames.end());
320 samplerArrayIndex = assignSamplerInStructUniformRegister(
321 type, samplerInStructSymbolsToAPINames.at(uniform), ®isterCount);
322 }
323 groupRegisterCount += registerCount;
324
325 if (type.isArray())
326 {
327 out << "static const uint " << DecorateVariableIfNeeded(*uniform) << ArrayString(type)
328 << " = ";
329 OutputUniformIndexArrayInitializer(out, type, samplerArrayIndex);
330 out << ";\n";
331 }
332 else
333 {
334 out << "static const uint " << DecorateVariableIfNeeded(*uniform) << " = "
335 << samplerArrayIndex << ";\n";
336 }
337 }
338 TString suffix = TextureGroupSuffix(textureGroup);
339 // Since HLSL_TEXTURE_2D is the first group, it has a fixed offset of zero.
340 if (textureGroup != HLSL_TEXTURE_2D)
341 {
342 out << "static const uint textureIndexOffset" << suffix << " = "
343 << (*groupTextureRegisterIndex) << ";\n";
344 out << "static const uint samplerIndexOffset" << suffix << " = "
345 << (*groupTextureRegisterIndex) << ";\n";
346 }
347 out << "uniform " << TextureString(textureGroup) << " textures" << suffix << "["
348 << groupRegisterCount << "]"
349 << " : register(t" << (*groupTextureRegisterIndex) << ");\n";
350 out << "uniform " << SamplerString(textureGroup) << " samplers" << suffix << "["
351 << groupRegisterCount << "]"
352 << " : register(s" << (*groupTextureRegisterIndex) << ");\n";
353 *groupTextureRegisterIndex += groupRegisterCount;
354 }
355
outputHLSLImageUniformIndices(TInfoSinkBase & out,const TVector<const TVariable * > & group,unsigned int imageArrayIndex,unsigned int * groupRegisterCount)356 void ResourcesHLSL::outputHLSLImageUniformIndices(TInfoSinkBase &out,
357 const TVector<const TVariable *> &group,
358 unsigned int imageArrayIndex,
359 unsigned int *groupRegisterCount)
360 {
361 for (const TVariable *uniform : group)
362 {
363 const TType &type = uniform->getType();
364 const ImmutableString &name = uniform->name();
365 unsigned int registerCount = 0;
366
367 assignUniformRegister(type, name, ®isterCount);
368 *groupRegisterCount += registerCount;
369
370 if (type.isArray())
371 {
372 out << "static const uint " << DecorateVariableIfNeeded(*uniform) << ArrayString(type)
373 << " = ";
374 OutputUniformIndexArrayInitializer(out, type, imageArrayIndex);
375 out << ";\n";
376 }
377 else
378 {
379 out << "static const uint " << DecorateVariableIfNeeded(*uniform) << " = "
380 << imageArrayIndex << ";\n";
381 }
382
383 imageArrayIndex += registerCount;
384 }
385 }
386
outputHLSLReadonlyImageUniformGroup(TInfoSinkBase & out,const HLSLTextureGroup textureGroup,const TVector<const TVariable * > & group,unsigned int * groupTextureRegisterIndex)387 void ResourcesHLSL::outputHLSLReadonlyImageUniformGroup(TInfoSinkBase &out,
388 const HLSLTextureGroup textureGroup,
389 const TVector<const TVariable *> &group,
390 unsigned int *groupTextureRegisterIndex)
391 {
392 if (group.empty())
393 {
394 return;
395 }
396
397 unsigned int groupRegisterCount = 0;
398 outputHLSLImageUniformIndices(out, group, *groupTextureRegisterIndex, &groupRegisterCount);
399
400 TString suffix = TextureGroupSuffix(textureGroup);
401 out << "static const uint readonlyImageIndexOffset" << suffix << " = "
402 << (*groupTextureRegisterIndex) << ";\n";
403 out << "uniform " << TextureString(textureGroup) << " readonlyImages" << suffix << "["
404 << groupRegisterCount << "]"
405 << " : register(t" << (*groupTextureRegisterIndex) << ");\n";
406 *groupTextureRegisterIndex += groupRegisterCount;
407 }
408
outputHLSLImageUniformGroup(TInfoSinkBase & out,const HLSLRWTextureGroup textureGroup,const TVector<const TVariable * > & group,unsigned int * groupTextureRegisterIndex)409 void ResourcesHLSL::outputHLSLImageUniformGroup(TInfoSinkBase &out,
410 const HLSLRWTextureGroup textureGroup,
411 const TVector<const TVariable *> &group,
412 unsigned int *groupTextureRegisterIndex)
413 {
414 if (group.empty())
415 {
416 return;
417 }
418
419 unsigned int groupRegisterCount = 0;
420 outputHLSLImageUniformIndices(out, group, *groupTextureRegisterIndex, &groupRegisterCount);
421
422 TString suffix = RWTextureGroupSuffix(textureGroup);
423 out << "static const uint imageIndexOffset" << suffix << " = " << (*groupTextureRegisterIndex)
424 << ";\n";
425 out << "uniform " << RWTextureString(textureGroup) << " images" << suffix << "["
426 << groupRegisterCount << "]"
427 << " : register(u" << (*groupTextureRegisterIndex) << ");\n";
428 *groupTextureRegisterIndex += groupRegisterCount;
429 }
430
outputHLSL4_0_FL9_3Sampler(TInfoSinkBase & out,const TType & type,const TVariable & variable,const unsigned int registerIndex)431 void ResourcesHLSL::outputHLSL4_0_FL9_3Sampler(TInfoSinkBase &out,
432 const TType &type,
433 const TVariable &variable,
434 const unsigned int registerIndex)
435 {
436 out << "uniform " << SamplerString(type.getBasicType()) << " sampler_"
437 << DecorateVariableIfNeeded(variable) << ArrayString(type) << " : register(s"
438 << str(registerIndex) << ");\n";
439 out << "uniform " << TextureString(type.getBasicType()) << " texture_"
440 << DecorateVariableIfNeeded(variable) << ArrayString(type) << " : register(t"
441 << str(registerIndex) << ");\n";
442 }
443
outputUniform(TInfoSinkBase & out,const TType & type,const TVariable & variable,const unsigned int registerIndex)444 void ResourcesHLSL::outputUniform(TInfoSinkBase &out,
445 const TType &type,
446 const TVariable &variable,
447 const unsigned int registerIndex)
448 {
449 const TStructure *structure = type.getStruct();
450 // If this is a nameless struct, we need to use its full definition, rather than its (empty)
451 // name.
452 // TypeString() will invoke defineNameless in this case; qualifier prefixes are unnecessary for
453 // nameless structs in ES, as nameless structs cannot be used anywhere that layout qualifiers
454 // are permitted.
455 const TString &typeName = ((structure && structure->symbolType() != SymbolType::Empty)
456 ? QualifiedStructNameString(*structure, false, false, false)
457 : TypeString(type));
458
459 const TString ®isterString =
460 TString("register(") + UniformRegisterPrefix(type) + str(registerIndex) + ")";
461
462 out << "uniform " << typeName << " ";
463
464 out << DecorateVariableIfNeeded(variable);
465
466 out << ArrayString(type) << " : " << registerString << ";\n";
467 }
468
outputAtomicCounterBuffer(TInfoSinkBase & out,const int binding,const unsigned int registerIndex)469 void ResourcesHLSL::outputAtomicCounterBuffer(TInfoSinkBase &out,
470 const int binding,
471 const unsigned int registerIndex)
472 {
473 // Atomic counter memory access is not incoherent
474 out << "uniform globallycoherent RWByteAddressBuffer "
475 << getAtomicCounterNameForBinding(binding) << " : register(u" << registerIndex << ");\n";
476 }
477
uniformsHeader(TInfoSinkBase & out,ShShaderOutput outputType,const ReferencedVariables & referencedUniforms,TSymbolTable * symbolTable)478 void ResourcesHLSL::uniformsHeader(TInfoSinkBase &out,
479 ShShaderOutput outputType,
480 const ReferencedVariables &referencedUniforms,
481 TSymbolTable *symbolTable)
482 {
483 if (!referencedUniforms.empty())
484 {
485 out << "// Uniforms\n\n";
486 }
487 // In the case of HLSL 4, sampler uniforms need to be grouped by type before the code is
488 // written. They are grouped based on the combination of the HLSL texture type and
489 // HLSL sampler type, enumerated in HLSLTextureSamplerGroup.
490 TVector<TVector<const TVariable *>> groupedSamplerUniforms(HLSL_TEXTURE_MAX + 1);
491 TMap<const TVariable *, TString> samplerInStructSymbolsToAPINames;
492 TVector<TVector<const TVariable *>> groupedReadonlyImageUniforms(HLSL_TEXTURE_MAX + 1);
493 TVector<TVector<const TVariable *>> groupedImageUniforms(HLSL_RWTEXTURE_MAX + 1);
494
495 TUnorderedMap<int, unsigned int> assignedAtomicCounterBindings;
496 unsigned int reservedReadonlyImageRegisterCount = 0, reservedImageRegisterCount = 0;
497 for (auto &uniformIt : referencedUniforms)
498 {
499 // Output regular uniforms. Group sampler uniforms by type.
500 const TVariable &variable = *uniformIt.second;
501 const TType &type = variable.getType();
502
503 if (outputType == SH_HLSL_4_1_OUTPUT && IsSampler(type.getBasicType()))
504 {
505 HLSLTextureGroup group = TextureGroup(type.getBasicType());
506 groupedSamplerUniforms[group].push_back(&variable);
507 }
508 else if (outputType == SH_HLSL_4_0_FL9_3_OUTPUT && IsSampler(type.getBasicType()))
509 {
510 unsigned int registerIndex = assignUniformRegister(type, variable.name(), nullptr);
511 outputHLSL4_0_FL9_3Sampler(out, type, variable, registerIndex);
512 }
513 else if (outputType == SH_HLSL_4_1_OUTPUT && IsImage(type.getBasicType()))
514 {
515 if (IsImage2D(type.getBasicType()))
516 {
517 const ShaderVariable *uniform = findUniformByName(variable.name());
518 if (type.getMemoryQualifier().readonly)
519 {
520 reservedReadonlyImageRegisterCount +=
521 HLSLVariableRegisterCount(*uniform, mOutputType);
522 }
523 else
524 {
525 reservedImageRegisterCount += HLSLVariableRegisterCount(*uniform, mOutputType);
526 }
527 continue;
528 }
529 if (type.getMemoryQualifier().readonly)
530 {
531 HLSLTextureGroup group = TextureGroup(
532 type.getBasicType(), type.getLayoutQualifier().imageInternalFormat);
533 groupedReadonlyImageUniforms[group].push_back(&variable);
534 }
535 else
536 {
537 HLSLRWTextureGroup group = RWTextureGroup(
538 type.getBasicType(), type.getLayoutQualifier().imageInternalFormat);
539 groupedImageUniforms[group].push_back(&variable);
540 }
541 }
542 else if (outputType == SH_HLSL_4_1_OUTPUT && IsAtomicCounter(type.getBasicType()))
543 {
544 TLayoutQualifier layout = type.getLayoutQualifier();
545 int binding = layout.binding;
546 unsigned int registerIndex;
547 if (assignedAtomicCounterBindings.find(binding) == assignedAtomicCounterBindings.end())
548 {
549 registerIndex = mUAVRegister++;
550 assignedAtomicCounterBindings[binding] = registerIndex;
551 outputAtomicCounterBuffer(out, binding, registerIndex);
552 }
553 else
554 {
555 registerIndex = assignedAtomicCounterBindings[binding];
556 }
557 const ShaderVariable *uniform = findUniformByName(variable.name());
558 mUniformRegisterMap[uniform->name] = registerIndex;
559 }
560 else
561 {
562 if (type.isStructureContainingSamplers())
563 {
564 TVector<const TVariable *> samplerSymbols;
565 TMap<const TVariable *, TString> symbolsToAPINames;
566 ImmutableStringBuilder namePrefix(kAngleDecorString.length() +
567 variable.name().length());
568 namePrefix << kAngleDecorString;
569 namePrefix << variable.name();
570 type.createSamplerSymbols(namePrefix, TString(variable.name().data()),
571 &samplerSymbols, &symbolsToAPINames, symbolTable);
572 for (const TVariable *sampler : samplerSymbols)
573 {
574 const TType &samplerType = sampler->getType();
575
576 if (outputType == SH_HLSL_4_1_OUTPUT)
577 {
578 HLSLTextureGroup group = TextureGroup(samplerType.getBasicType());
579 groupedSamplerUniforms[group].push_back(sampler);
580 samplerInStructSymbolsToAPINames[sampler] = symbolsToAPINames[sampler];
581 }
582 else if (outputType == SH_HLSL_4_0_FL9_3_OUTPUT)
583 {
584 unsigned int registerIndex = assignSamplerInStructUniformRegister(
585 samplerType, symbolsToAPINames[sampler], nullptr);
586 outputHLSL4_0_FL9_3Sampler(out, samplerType, *sampler, registerIndex);
587 }
588 else
589 {
590 ASSERT(outputType == SH_HLSL_3_0_OUTPUT);
591 unsigned int registerIndex = assignSamplerInStructUniformRegister(
592 samplerType, symbolsToAPINames[sampler], nullptr);
593 outputUniform(out, samplerType, *sampler, registerIndex);
594 }
595 }
596 }
597 unsigned int registerIndex = assignUniformRegister(type, variable.name(), nullptr);
598 outputUniform(out, type, variable, registerIndex);
599 }
600 }
601
602 if (outputType == SH_HLSL_4_1_OUTPUT)
603 {
604 unsigned int groupTextureRegisterIndex = 0;
605 // Atomic counters and RW texture share the same resources. Therefore, RW texture need to
606 // start counting after the last atomic counter.
607 unsigned int groupRWTextureRegisterIndex = mUAVRegister;
608 // TEXTURE_2D is special, index offset is assumed to be 0 and omitted in that case.
609 ASSERT(HLSL_TEXTURE_MIN == HLSL_TEXTURE_2D);
610 for (int groupId = HLSL_TEXTURE_MIN; groupId < HLSL_TEXTURE_MAX; ++groupId)
611 {
612 outputHLSLSamplerUniformGroup(
613 out, HLSLTextureGroup(groupId), groupedSamplerUniforms[groupId],
614 samplerInStructSymbolsToAPINames, &groupTextureRegisterIndex);
615 }
616 mSamplerCount = groupTextureRegisterIndex;
617
618 // Reserve t type register for readonly image2D variables.
619 mReadonlyImage2DRegisterIndex = mSRVRegister;
620 groupTextureRegisterIndex += reservedReadonlyImageRegisterCount;
621 mSRVRegister += reservedReadonlyImageRegisterCount;
622
623 for (int groupId = HLSL_TEXTURE_MIN; groupId < HLSL_TEXTURE_MAX; ++groupId)
624 {
625 outputHLSLReadonlyImageUniformGroup(out, HLSLTextureGroup(groupId),
626 groupedReadonlyImageUniforms[groupId],
627 &groupTextureRegisterIndex);
628 }
629 mReadonlyImageCount = groupTextureRegisterIndex - mReadonlyImage2DRegisterIndex;
630 if (mReadonlyImageCount)
631 {
632 out << "static const uint readonlyImageIndexStart = " << mReadonlyImage2DRegisterIndex
633 << ";\n";
634 }
635
636 // Reserve u type register for writable image2D variables.
637 mImage2DRegisterIndex = mUAVRegister;
638 groupRWTextureRegisterIndex += reservedImageRegisterCount;
639 mUAVRegister += reservedImageRegisterCount;
640
641 for (int groupId = HLSL_RWTEXTURE_MIN; groupId < HLSL_RWTEXTURE_MAX; ++groupId)
642 {
643 outputHLSLImageUniformGroup(out, HLSLRWTextureGroup(groupId),
644 groupedImageUniforms[groupId],
645 &groupRWTextureRegisterIndex);
646 }
647 mImageCount = groupRWTextureRegisterIndex - mImage2DRegisterIndex;
648 if (mImageCount)
649 {
650 out << "static const uint imageIndexStart = " << mImage2DRegisterIndex << ";\n";
651 }
652 }
653 }
654
samplerMetadataUniforms(TInfoSinkBase & out,unsigned int regIndex)655 void ResourcesHLSL::samplerMetadataUniforms(TInfoSinkBase &out, unsigned int regIndex)
656 {
657 // If mSamplerCount is 0 the shader doesn't use any textures for samplers.
658 if (mSamplerCount > 0)
659 {
660 out << " struct SamplerMetadata\n"
661 " {\n"
662 " int baseLevel;\n"
663 " int internalFormatBits;\n"
664 " int wrapModes;\n"
665 " int padding;\n"
666 " int4 intBorderColor;\n"
667 " };\n"
668 " SamplerMetadata samplerMetadata["
669 << mSamplerCount << "] : packoffset(c" << regIndex << ");\n";
670 }
671 }
672
imageMetadataUniforms(TInfoSinkBase & out,unsigned int regIndex)673 void ResourcesHLSL::imageMetadataUniforms(TInfoSinkBase &out, unsigned int regIndex)
674 {
675 if (mReadonlyImageCount > 0 || mImageCount > 0)
676 {
677 out << " struct ImageMetadata\n"
678 " {\n"
679 " int layer;\n"
680 " uint level;\n"
681 " int2 padding;\n"
682 " };\n";
683
684 if (mReadonlyImageCount > 0)
685 {
686 out << " ImageMetadata readonlyImageMetadata[" << mReadonlyImageCount
687 << "] : packoffset(c" << regIndex << ");\n";
688 }
689
690 if (mImageCount > 0)
691 {
692 out << " ImageMetadata imageMetadata[" << mImageCount << "] : packoffset(c"
693 << regIndex + mReadonlyImageCount << ");\n";
694 }
695 }
696 }
697
uniformBlocksHeader(const ReferencedInterfaceBlocks & referencedInterfaceBlocks,const std::map<int,const TInterfaceBlock * > & uniformBlockOptimizedMap)698 TString ResourcesHLSL::uniformBlocksHeader(
699 const ReferencedInterfaceBlocks &referencedInterfaceBlocks,
700 const std::map<int, const TInterfaceBlock *> &uniformBlockOptimizedMap)
701 {
702 TString interfaceBlocks;
703
704 for (const auto &blockReference : referencedInterfaceBlocks)
705 {
706 const TInterfaceBlock &interfaceBlock = *blockReference.second->block;
707 const TVariable *instanceVariable = blockReference.second->instanceVariable;
708 if (instanceVariable != nullptr)
709 {
710 interfaceBlocks += uniformBlockStructString(interfaceBlock);
711 }
712
713 // In order to avoid compile performance issue, translate uniform block to structured
714 // buffer. anglebug.com/3682.
715 if (uniformBlockOptimizedMap.count(interfaceBlock.uniqueId().get()) != 0)
716 {
717 unsigned int structuredBufferRegister = mSRVRegister;
718 if (instanceVariable != nullptr && instanceVariable->getType().isArray())
719 {
720 unsigned int instanceArraySize =
721 instanceVariable->getType().getOutermostArraySize();
722 for (unsigned int arrayIndex = 0; arrayIndex < instanceArraySize; arrayIndex++)
723 {
724 interfaceBlocks += uniformBlockWithOneLargeArrayMemberString(
725 interfaceBlock, instanceVariable, structuredBufferRegister + arrayIndex,
726 arrayIndex);
727 }
728 mSRVRegister += instanceArraySize;
729 }
730 else
731 {
732 interfaceBlocks += uniformBlockWithOneLargeArrayMemberString(
733 interfaceBlock, instanceVariable, structuredBufferRegister, GL_INVALID_INDEX);
734 mSRVRegister += 1u;
735 }
736 mUniformBlockRegisterMap[interfaceBlock.name().data()] = structuredBufferRegister;
737 mUniformBlockUseStructuredBufferMap[interfaceBlock.name().data()] = true;
738 continue;
739 }
740
741 unsigned int activeRegister = mUniformBlockRegister;
742 mUniformBlockRegisterMap[interfaceBlock.name().data()] = activeRegister;
743
744 if (instanceVariable != nullptr && instanceVariable->getType().isArray())
745 {
746 unsigned int instanceArraySize = instanceVariable->getType().getOutermostArraySize();
747 for (unsigned int arrayIndex = 0; arrayIndex < instanceArraySize; arrayIndex++)
748 {
749 interfaceBlocks += uniformBlockString(interfaceBlock, instanceVariable,
750 activeRegister + arrayIndex, arrayIndex);
751 }
752 mUniformBlockRegister += instanceArraySize;
753 }
754 else
755 {
756 interfaceBlocks += uniformBlockString(interfaceBlock, instanceVariable, activeRegister,
757 GL_INVALID_INDEX);
758 mUniformBlockRegister += 1u;
759 }
760 }
761
762 return (interfaceBlocks.empty() ? "" : ("// Uniform Blocks\n\n" + interfaceBlocks));
763 }
764
shaderStorageBlocksHeader(const ReferencedInterfaceBlocks & referencedInterfaceBlocks)765 TString ResourcesHLSL::shaderStorageBlocksHeader(
766 const ReferencedInterfaceBlocks &referencedInterfaceBlocks)
767 {
768 TString interfaceBlocks;
769
770 for (const auto &interfaceBlockReference : referencedInterfaceBlocks)
771 {
772 const TInterfaceBlock &interfaceBlock = *interfaceBlockReference.second->block;
773 const TVariable *instanceVariable = interfaceBlockReference.second->instanceVariable;
774
775 unsigned int activeRegister = mUAVRegister;
776 mShaderStorageBlockRegisterMap[interfaceBlock.name().data()] = activeRegister;
777
778 if (instanceVariable != nullptr && instanceVariable->getType().isArray())
779 {
780 unsigned int instanceArraySize = instanceVariable->getType().getOutermostArraySize();
781 for (unsigned int arrayIndex = 0; arrayIndex < instanceArraySize; arrayIndex++)
782 {
783 interfaceBlocks += shaderStorageBlockString(
784 interfaceBlock, instanceVariable, activeRegister + arrayIndex, arrayIndex);
785 }
786 mUAVRegister += instanceArraySize;
787 }
788 else
789 {
790 interfaceBlocks += shaderStorageBlockString(interfaceBlock, instanceVariable,
791 activeRegister, GL_INVALID_INDEX);
792 mUAVRegister += 1u;
793 }
794 }
795
796 return (interfaceBlocks.empty() ? "" : ("// Shader Storage Blocks\n\n" + interfaceBlocks));
797 }
798
uniformBlockString(const TInterfaceBlock & interfaceBlock,const TVariable * instanceVariable,unsigned int registerIndex,unsigned int arrayIndex)799 TString ResourcesHLSL::uniformBlockString(const TInterfaceBlock &interfaceBlock,
800 const TVariable *instanceVariable,
801 unsigned int registerIndex,
802 unsigned int arrayIndex)
803 {
804 const TString &arrayIndexString = (arrayIndex != GL_INVALID_INDEX ? str(arrayIndex) : "");
805 const TString &blockName = TString(interfaceBlock.name().data()) + arrayIndexString;
806 TString hlsl;
807
808 hlsl += "cbuffer " + blockName + " : register(b" + str(registerIndex) +
809 ")\n"
810 "{\n";
811
812 if (instanceVariable != nullptr)
813 {
814 hlsl += " " + InterfaceBlockStructName(interfaceBlock) + " " +
815 InterfaceBlockInstanceString(instanceVariable->name(), arrayIndex) + ";\n";
816 }
817 else
818 {
819 const TLayoutBlockStorage blockStorage = interfaceBlock.blockStorage();
820 hlsl += uniformBlockMembersString(interfaceBlock, blockStorage);
821 }
822
823 hlsl += "};\n\n";
824
825 return hlsl;
826 }
827
uniformBlockWithOneLargeArrayMemberString(const TInterfaceBlock & interfaceBlock,const TVariable * instanceVariable,unsigned int registerIndex,unsigned int arrayIndex)828 TString ResourcesHLSL::uniformBlockWithOneLargeArrayMemberString(
829 const TInterfaceBlock &interfaceBlock,
830 const TVariable *instanceVariable,
831 unsigned int registerIndex,
832 unsigned int arrayIndex)
833 {
834 TString hlsl, typeString;
835
836 const TField &field = *interfaceBlock.fields()[0];
837 const TLayoutBlockStorage blockStorage = interfaceBlock.blockStorage();
838 typeString = InterfaceBlockFieldTypeString(field, blockStorage, true);
839 const TType &fieldType = *field.type();
840 if (fieldType.isMatrix())
841 {
842 if (arrayIndex == GL_INVALID_INDEX || arrayIndex == 0)
843 {
844 hlsl += "struct pack" + Decorate(interfaceBlock.name()) + " { " + typeString + " " +
845 Decorate(field.name()) + "; };\n";
846 }
847 typeString = "pack" + Decorate(interfaceBlock.name());
848 }
849 else if (fieldType.isVectorArray() || fieldType.isScalarArray())
850 {
851 // If the member is an array of scalars or vectors, std140 rules require the base array
852 // stride are rounded up to the base alignment of a vec4.
853 if (arrayIndex == GL_INVALID_INDEX || arrayIndex == 0)
854 {
855 hlsl += "struct pack" + Decorate(interfaceBlock.name()) + " { " + typeString + " " +
856 Decorate(field.name()) + ";\n";
857 hlsl += InterfaceBlockScalarVectorFieldPaddingString(fieldType) + " };\n";
858 }
859 typeString = "pack" + Decorate(interfaceBlock.name());
860 }
861
862 if (instanceVariable != nullptr)
863 {
864
865 hlsl += "StructuredBuffer <" + typeString + "> " +
866 InterfaceBlockInstanceString(instanceVariable->name(), arrayIndex) + "_" +
867 Decorate(field.name()) + +" : register(t" + str(registerIndex) + ");\n";
868 }
869 else
870 {
871 hlsl += "StructuredBuffer <" + typeString + "> " + Decorate(field.name()) +
872 " : register(t" + str(registerIndex) + ");\n";
873 }
874
875 return hlsl;
876 }
877
shaderStorageBlockString(const TInterfaceBlock & interfaceBlock,const TVariable * instanceVariable,unsigned int registerIndex,unsigned int arrayIndex)878 TString ResourcesHLSL::shaderStorageBlockString(const TInterfaceBlock &interfaceBlock,
879 const TVariable *instanceVariable,
880 unsigned int registerIndex,
881 unsigned int arrayIndex)
882 {
883 TString hlsl;
884 if (instanceVariable != nullptr)
885 {
886 hlsl += "RWByteAddressBuffer " +
887 InterfaceBlockInstanceString(instanceVariable->name(), arrayIndex) +
888 ": register(u" + str(registerIndex) + ");\n";
889 }
890 else
891 {
892 hlsl += "RWByteAddressBuffer " + Decorate(interfaceBlock.name()) + ": register(u" +
893 str(registerIndex) + ");\n";
894 }
895 return hlsl;
896 }
897
InterfaceBlockInstanceString(const ImmutableString & instanceName,unsigned int arrayIndex)898 TString ResourcesHLSL::InterfaceBlockInstanceString(const ImmutableString &instanceName,
899 unsigned int arrayIndex)
900 {
901 if (arrayIndex != GL_INVALID_INDEX)
902 {
903 return DecoratePrivate(instanceName) + "_" + str(arrayIndex);
904 }
905 else
906 {
907 return Decorate(instanceName);
908 }
909 }
910
uniformBlockMembersString(const TInterfaceBlock & interfaceBlock,TLayoutBlockStorage blockStorage)911 TString ResourcesHLSL::uniformBlockMembersString(const TInterfaceBlock &interfaceBlock,
912 TLayoutBlockStorage blockStorage)
913 {
914 TString hlsl;
915
916 Std140PaddingHelper padHelper = mStructureHLSL->getPaddingHelper();
917
918 const unsigned int fieldCount = static_cast<unsigned int>(interfaceBlock.fields().size());
919 for (unsigned int typeIndex = 0; typeIndex < fieldCount; typeIndex++)
920 {
921 const TField &field = *interfaceBlock.fields()[typeIndex];
922 const TType &fieldType = *field.type();
923
924 if (blockStorage == EbsStd140)
925 {
926 // 2 and 3 component vector types in some cases need pre-padding
927 hlsl += padHelper.prePaddingString(fieldType, false);
928 }
929
930 hlsl += " " + InterfaceBlockFieldTypeString(field, blockStorage, false) + " " +
931 Decorate(field.name()) + ArrayString(fieldType).data() + ";\n";
932
933 // must pad out after matrices and arrays, where HLSL usually allows itself room to pack
934 // stuff
935 if (blockStorage == EbsStd140)
936 {
937 const bool useHLSLRowMajorPacking =
938 (fieldType.getLayoutQualifier().matrixPacking == EmpColumnMajor);
939 hlsl += padHelper.postPaddingString(fieldType, useHLSLRowMajorPacking,
940 typeIndex == fieldCount - 1, false);
941 }
942 }
943
944 return hlsl;
945 }
946
uniformBlockStructString(const TInterfaceBlock & interfaceBlock)947 TString ResourcesHLSL::uniformBlockStructString(const TInterfaceBlock &interfaceBlock)
948 {
949 const TLayoutBlockStorage blockStorage = interfaceBlock.blockStorage();
950
951 return "struct " + InterfaceBlockStructName(interfaceBlock) +
952 "\n"
953 "{\n" +
954 uniformBlockMembersString(interfaceBlock, blockStorage) + "};\n\n";
955 }
956 } // namespace sh
957