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