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