Line data Source code
1 : //
2 : // Copyright (c) 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 : // UniformHLSL.cpp:
7 : // Methods for GLSL to HLSL translation for uniforms and interface blocks.
8 : //
9 :
10 : #include "compiler/translator/UniformHLSL.h"
11 :
12 : #include "common/utilities.h"
13 : #include "compiler/translator/StructureHLSL.h"
14 : #include "compiler/translator/UtilsHLSL.h"
15 : #include "compiler/translator/blocklayoutHLSL.h"
16 : #include "compiler/translator/util.h"
17 :
18 : namespace sh
19 : {
20 :
21 0 : static const char *UniformRegisterPrefix(const TType &type)
22 : {
23 0 : if (IsSampler(type.getBasicType()))
24 : {
25 0 : return "s";
26 : }
27 : else
28 : {
29 0 : return "c";
30 : }
31 : }
32 :
33 0 : static TString InterfaceBlockFieldTypeString(const TField &field, TLayoutBlockStorage blockStorage)
34 : {
35 0 : const TType &fieldType = *field.type();
36 0 : const TLayoutMatrixPacking matrixPacking = fieldType.getLayoutQualifier().matrixPacking;
37 0 : ASSERT(matrixPacking != EmpUnspecified);
38 0 : TStructure *structure = fieldType.getStruct();
39 :
40 0 : if (fieldType.isMatrix())
41 : {
42 : // Use HLSL row-major packing for GLSL column-major matrices
43 0 : const TString &matrixPackString = (matrixPacking == EmpRowMajor ? "column_major" : "row_major");
44 0 : return matrixPackString + " " + TypeString(fieldType);
45 : }
46 0 : else if (structure)
47 : {
48 : // Use HLSL row-major packing for GLSL column-major matrices
49 : return QualifiedStructNameString(*structure, matrixPacking == EmpColumnMajor,
50 0 : blockStorage == EbsStd140);
51 : }
52 : else
53 : {
54 0 : return TypeString(fieldType);
55 : }
56 : }
57 :
58 0 : static TString InterfaceBlockStructName(const TInterfaceBlock &interfaceBlock)
59 : {
60 0 : return DecoratePrivate(interfaceBlock.name()) + "_type";
61 : }
62 :
63 0 : UniformHLSL::UniformHLSL(StructureHLSL *structureHLSL, ShShaderOutput outputType, const std::vector<Uniform> &uniforms)
64 : : mUniformRegister(0),
65 : mInterfaceBlockRegister(0),
66 : mSamplerRegister(0),
67 : mStructureHLSL(structureHLSL),
68 : mOutputType(outputType),
69 0 : mUniforms(uniforms)
70 0 : {}
71 :
72 0 : void UniformHLSL::reserveUniformRegisters(unsigned int registerCount)
73 : {
74 0 : mUniformRegister = registerCount;
75 0 : }
76 :
77 0 : void UniformHLSL::reserveInterfaceBlockRegisters(unsigned int registerCount)
78 : {
79 0 : mInterfaceBlockRegister = registerCount;
80 0 : }
81 :
82 0 : const Uniform *UniformHLSL::findUniformByName(const TString &name) const
83 : {
84 0 : for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); ++uniformIndex)
85 : {
86 0 : if (mUniforms[uniformIndex].name == name.c_str())
87 : {
88 0 : return &mUniforms[uniformIndex];
89 : }
90 : }
91 :
92 0 : return nullptr;
93 : }
94 :
95 0 : unsigned int UniformHLSL::assignUniformRegister(const TType &type,
96 : const TString &name,
97 : unsigned int *outRegisterCount)
98 : {
99 0 : unsigned int registerIndex = (IsSampler(type.getBasicType()) ? mSamplerRegister : mUniformRegister);
100 :
101 0 : const Uniform *uniform = findUniformByName(name);
102 0 : ASSERT(uniform);
103 :
104 0 : mUniformRegisterMap[uniform->name] = registerIndex;
105 :
106 0 : unsigned int registerCount = HLSLVariableRegisterCount(*uniform, mOutputType);
107 :
108 0 : if (gl::IsSamplerType(uniform->type))
109 : {
110 0 : mSamplerRegister += registerCount;
111 : }
112 : else
113 : {
114 0 : mUniformRegister += registerCount;
115 : }
116 0 : if (outRegisterCount)
117 : {
118 0 : *outRegisterCount = registerCount;
119 : }
120 0 : return registerIndex;
121 : }
122 :
123 0 : unsigned int UniformHLSL::assignSamplerInStructUniformRegister(const TType &type,
124 : const TString &name,
125 : unsigned int *outRegisterCount)
126 : {
127 : // Sampler that is a field of a uniform structure.
128 0 : ASSERT(IsSampler(type.getBasicType()));
129 0 : unsigned int registerIndex = mSamplerRegister;
130 0 : mUniformRegisterMap[std::string(name.c_str())] = registerIndex;
131 0 : unsigned int registerCount = type.isArray() ? type.getArraySize() : 1u;
132 0 : mSamplerRegister += registerCount;
133 0 : if (outRegisterCount)
134 : {
135 0 : *outRegisterCount = registerCount;
136 : }
137 0 : return registerIndex;
138 : }
139 :
140 0 : void UniformHLSL::outputHLSLSamplerUniformGroup(
141 : TInfoSinkBase &out,
142 : const HLSLTextureSamplerGroup textureGroup,
143 : const TVector<const TIntermSymbol *> &group,
144 : const TMap<const TIntermSymbol *, TString> &samplerInStructSymbolsToAPINames,
145 : unsigned int *groupTextureRegisterIndex)
146 : {
147 0 : if (group.empty())
148 : {
149 0 : return;
150 : }
151 0 : unsigned int groupRegisterCount = 0;
152 0 : for (const TIntermSymbol *uniform : group)
153 : {
154 0 : const TType &type = uniform->getType();
155 0 : const TString &name = uniform->getSymbol();
156 : unsigned int registerCount;
157 :
158 : // The uniform might be just a regular sampler or one extracted from a struct.
159 0 : unsigned int samplerArrayIndex = 0u;
160 0 : const Uniform *uniformByName = findUniformByName(name);
161 0 : if (uniformByName)
162 : {
163 0 : samplerArrayIndex = assignUniformRegister(type, name, ®isterCount);
164 : }
165 : else
166 : {
167 0 : ASSERT(samplerInStructSymbolsToAPINames.find(uniform) !=
168 0 : samplerInStructSymbolsToAPINames.end());
169 0 : samplerArrayIndex = assignSamplerInStructUniformRegister(
170 0 : type, samplerInStructSymbolsToAPINames.at(uniform), ®isterCount);
171 : }
172 0 : groupRegisterCount += registerCount;
173 :
174 0 : if (type.isArray())
175 : {
176 0 : out << "static const uint " << DecorateIfNeeded(uniform->getName()) << ArrayString(type)
177 0 : << " = {";
178 0 : for (unsigned int i = 0u; i < type.getArraySize(); ++i)
179 : {
180 0 : if (i > 0u)
181 0 : out << ", ";
182 0 : out << (samplerArrayIndex + i);
183 : }
184 0 : out << "};\n";
185 : }
186 : else
187 : {
188 0 : out << "static const uint " << DecorateIfNeeded(uniform->getName()) << " = "
189 0 : << samplerArrayIndex << ";\n";
190 : }
191 : }
192 0 : TString suffix = TextureGroupSuffix(textureGroup);
193 : // Since HLSL_TEXTURE_2D is the first group, it has a fixed offset of zero.
194 0 : if (textureGroup != HLSL_TEXTURE_2D)
195 : {
196 0 : out << "static const uint textureIndexOffset" << suffix << " = "
197 0 : << (*groupTextureRegisterIndex) << ";\n";
198 0 : out << "static const uint samplerIndexOffset" << suffix << " = "
199 0 : << (*groupTextureRegisterIndex) << ";\n";
200 : }
201 0 : out << "uniform " << TextureString(textureGroup) << " textures" << suffix << "["
202 0 : << groupRegisterCount << "]"
203 0 : << " : register(t" << (*groupTextureRegisterIndex) << ");\n";
204 0 : out << "uniform " << SamplerString(textureGroup) << " samplers" << suffix << "["
205 0 : << groupRegisterCount << "]"
206 0 : << " : register(s" << (*groupTextureRegisterIndex) << ");\n";
207 0 : *groupTextureRegisterIndex += groupRegisterCount;
208 : }
209 :
210 0 : void UniformHLSL::outputHLSL4_0_FL9_3Sampler(TInfoSinkBase &out,
211 : const TType &type,
212 : const TName &name,
213 : const unsigned int registerIndex)
214 : {
215 0 : out << "uniform " << SamplerString(type.getBasicType()) << " sampler_"
216 0 : << DecorateUniform(name, type) << ArrayString(type) << " : register(s" << str(registerIndex)
217 0 : << ");\n";
218 0 : out << "uniform " << TextureString(type.getBasicType()) << " texture_"
219 0 : << DecorateUniform(name, type) << ArrayString(type) << " : register(t" << str(registerIndex)
220 0 : << ");\n";
221 0 : }
222 :
223 0 : void UniformHLSL::outputUniform(TInfoSinkBase &out,
224 : const TType &type,
225 : const TName &name,
226 : const unsigned int registerIndex)
227 : {
228 0 : const TStructure *structure = type.getStruct();
229 : // If this is a nameless struct, we need to use its full definition, rather than its (empty)
230 : // name.
231 : // TypeString() will invoke defineNameless in this case; qualifier prefixes are unnecessary for
232 : // nameless structs in ES, as nameless structs cannot be used anywhere that layout qualifiers
233 : // are permitted.
234 0 : const TString &typeName = ((structure && !structure->name().empty())
235 0 : ? QualifiedStructNameString(*structure, false, false)
236 0 : : TypeString(type));
237 :
238 : const TString ®isterString =
239 0 : TString("register(") + UniformRegisterPrefix(type) + str(registerIndex) + ")";
240 :
241 0 : out << "uniform " << typeName << " ";
242 :
243 0 : out << DecorateUniform(name, type);
244 :
245 0 : out << ArrayString(type) << " : " << registerString << ";\n";
246 0 : }
247 :
248 0 : void UniformHLSL::uniformsHeader(TInfoSinkBase &out,
249 : ShShaderOutput outputType,
250 : const ReferencedSymbols &referencedUniforms)
251 : {
252 0 : if (!referencedUniforms.empty())
253 : {
254 0 : out << "// Uniforms\n\n";
255 : }
256 : // In the case of HLSL 4, sampler uniforms need to be grouped by type before the code is
257 : // written. They are grouped based on the combination of the HLSL texture type and
258 : // HLSL sampler type, enumerated in HLSLTextureSamplerGroup.
259 0 : TVector<TVector<const TIntermSymbol *>> groupedSamplerUniforms(HLSL_TEXTURE_MAX + 1);
260 0 : TMap<const TIntermSymbol *, TString> samplerInStructSymbolsToAPINames;
261 0 : for (auto &uniformIt : referencedUniforms)
262 : {
263 : // Output regular uniforms. Group sampler uniforms by type.
264 0 : const TIntermSymbol &uniform = *uniformIt.second;
265 0 : const TType &type = uniform.getType();
266 0 : const TName &name = uniform.getName();
267 :
268 0 : if (outputType == SH_HLSL_4_1_OUTPUT && IsSampler(type.getBasicType()))
269 : {
270 0 : HLSLTextureSamplerGroup group = TextureGroup(type.getBasicType());
271 0 : groupedSamplerUniforms[group].push_back(&uniform);
272 : }
273 0 : else if (outputType == SH_HLSL_4_0_FL9_3_OUTPUT && IsSampler(type.getBasicType()))
274 : {
275 0 : unsigned int registerIndex = assignUniformRegister(type, name.getString(), nullptr);
276 0 : outputHLSL4_0_FL9_3Sampler(out, type, name, registerIndex);
277 : }
278 : else
279 : {
280 0 : if (type.isStructureContainingSamplers())
281 : {
282 0 : TVector<TIntermSymbol *> samplerSymbols;
283 0 : TMap<TIntermSymbol *, TString> symbolsToAPINames;
284 0 : unsigned int arrayOfStructsSize = type.isArray() ? type.getArraySize() : 0u;
285 0 : type.createSamplerSymbols("angle_" + name.getString(), name.getString(),
286 0 : arrayOfStructsSize, &samplerSymbols, &symbolsToAPINames);
287 0 : for (TIntermSymbol *sampler : samplerSymbols)
288 : {
289 0 : const TType &samplerType = sampler->getType();
290 :
291 : // Will use angle_ prefix instead of regular prefix.
292 0 : sampler->setInternal(true);
293 0 : const TName &samplerName = sampler->getName();
294 :
295 0 : if (outputType == SH_HLSL_4_1_OUTPUT)
296 : {
297 0 : HLSLTextureSamplerGroup group = TextureGroup(samplerType.getBasicType());
298 0 : groupedSamplerUniforms[group].push_back(sampler);
299 0 : samplerInStructSymbolsToAPINames[sampler] = symbolsToAPINames[sampler];
300 : }
301 0 : else if (outputType == SH_HLSL_4_0_FL9_3_OUTPUT)
302 : {
303 : unsigned int registerIndex = assignSamplerInStructUniformRegister(
304 0 : samplerType, symbolsToAPINames[sampler], nullptr);
305 0 : outputHLSL4_0_FL9_3Sampler(out, samplerType, samplerName, registerIndex);
306 : }
307 : else
308 : {
309 0 : ASSERT(outputType == SH_HLSL_3_0_OUTPUT);
310 : unsigned int registerIndex = assignSamplerInStructUniformRegister(
311 0 : samplerType, symbolsToAPINames[sampler], nullptr);
312 0 : outputUniform(out, samplerType, samplerName, registerIndex);
313 : }
314 : }
315 : }
316 0 : unsigned int registerIndex = assignUniformRegister(type, name.getString(), nullptr);
317 0 : outputUniform(out, type, name, registerIndex);
318 : }
319 : }
320 :
321 0 : if (outputType == SH_HLSL_4_1_OUTPUT)
322 : {
323 0 : unsigned int groupTextureRegisterIndex = 0;
324 : // TEXTURE_2D is special, index offset is assumed to be 0 and omitted in that case.
325 : ASSERT(HLSL_TEXTURE_MIN == HLSL_TEXTURE_2D);
326 0 : for (int groupId = HLSL_TEXTURE_MIN; groupId < HLSL_TEXTURE_MAX; ++groupId)
327 : {
328 0 : outputHLSLSamplerUniformGroup(
329 0 : out, HLSLTextureSamplerGroup(groupId), groupedSamplerUniforms[groupId],
330 0 : samplerInStructSymbolsToAPINames, &groupTextureRegisterIndex);
331 : }
332 : }
333 0 : }
334 :
335 0 : void UniformHLSL::samplerMetadataUniforms(TInfoSinkBase &out, const char *reg)
336 : {
337 : // If mSamplerRegister is 0 the shader doesn't use any textures.
338 0 : if (mSamplerRegister > 0)
339 : {
340 : out << " struct SamplerMetadata\n"
341 : " {\n"
342 : " int baseLevel;\n"
343 : " int internalFormatBits;\n"
344 : " int wrapModes;\n"
345 : " int padding;\n"
346 : " };\n"
347 0 : " SamplerMetadata samplerMetadata["
348 0 : << mSamplerRegister << "] : packoffset(" << reg << ");\n";
349 : }
350 0 : }
351 :
352 0 : TString UniformHLSL::interfaceBlocksHeader(const ReferencedSymbols &referencedInterfaceBlocks)
353 : {
354 0 : TString interfaceBlocks;
355 :
356 0 : for (ReferencedSymbols::const_iterator interfaceBlockIt = referencedInterfaceBlocks.begin();
357 0 : interfaceBlockIt != referencedInterfaceBlocks.end(); interfaceBlockIt++)
358 : {
359 0 : const TType &nodeType = interfaceBlockIt->second->getType();
360 0 : const TInterfaceBlock &interfaceBlock = *nodeType.getInterfaceBlock();
361 :
362 0 : unsigned int arraySize = static_cast<unsigned int>(interfaceBlock.arraySize());
363 0 : unsigned int activeRegister = mInterfaceBlockRegister;
364 :
365 0 : mInterfaceBlockRegisterMap[interfaceBlock.name().c_str()] = activeRegister;
366 0 : mInterfaceBlockRegister += std::max(1u, arraySize);
367 :
368 : // FIXME: interface block field names
369 :
370 0 : if (interfaceBlock.hasInstanceName())
371 : {
372 0 : interfaceBlocks += interfaceBlockStructString(interfaceBlock);
373 : }
374 :
375 0 : if (arraySize > 0)
376 : {
377 0 : for (unsigned int arrayIndex = 0; arrayIndex < arraySize; arrayIndex++)
378 : {
379 0 : interfaceBlocks += interfaceBlockString(interfaceBlock, activeRegister + arrayIndex, arrayIndex);
380 : }
381 : }
382 : else
383 : {
384 0 : interfaceBlocks += interfaceBlockString(interfaceBlock, activeRegister, GL_INVALID_INDEX);
385 : }
386 : }
387 :
388 0 : return (interfaceBlocks.empty() ? "" : ("// Interface Blocks\n\n" + interfaceBlocks));
389 : }
390 :
391 0 : TString UniformHLSL::interfaceBlockString(const TInterfaceBlock &interfaceBlock, unsigned int registerIndex, unsigned int arrayIndex)
392 : {
393 0 : const TString &arrayIndexString = (arrayIndex != GL_INVALID_INDEX ? Decorate(str(arrayIndex)) : "");
394 0 : const TString &blockName = interfaceBlock.name() + arrayIndexString;
395 0 : TString hlsl;
396 :
397 0 : hlsl += "cbuffer " + blockName + " : register(b" + str(registerIndex) + ")\n"
398 0 : "{\n";
399 :
400 0 : if (interfaceBlock.hasInstanceName())
401 : {
402 0 : hlsl += " " + InterfaceBlockStructName(interfaceBlock) + " " +
403 0 : interfaceBlockInstanceString(interfaceBlock, arrayIndex) + ";\n";
404 : }
405 : else
406 : {
407 0 : const TLayoutBlockStorage blockStorage = interfaceBlock.blockStorage();
408 0 : hlsl += interfaceBlockMembersString(interfaceBlock, blockStorage);
409 : }
410 :
411 0 : hlsl += "};\n\n";
412 :
413 0 : return hlsl;
414 : }
415 :
416 0 : TString UniformHLSL::interfaceBlockInstanceString(const TInterfaceBlock& interfaceBlock, unsigned int arrayIndex)
417 : {
418 0 : if (!interfaceBlock.hasInstanceName())
419 : {
420 0 : return "";
421 : }
422 0 : else if (interfaceBlock.isArray())
423 : {
424 0 : return DecoratePrivate(interfaceBlock.instanceName()) + "_" + str(arrayIndex);
425 : }
426 : else
427 : {
428 0 : return Decorate(interfaceBlock.instanceName());
429 : }
430 : }
431 :
432 0 : TString UniformHLSL::interfaceBlockMembersString(const TInterfaceBlock &interfaceBlock, TLayoutBlockStorage blockStorage)
433 : {
434 0 : TString hlsl;
435 :
436 0 : Std140PaddingHelper padHelper = mStructureHLSL->getPaddingHelper();
437 :
438 0 : for (unsigned int typeIndex = 0; typeIndex < interfaceBlock.fields().size(); typeIndex++)
439 : {
440 0 : const TField &field = *interfaceBlock.fields()[typeIndex];
441 0 : const TType &fieldType = *field.type();
442 :
443 0 : if (blockStorage == EbsStd140)
444 : {
445 : // 2 and 3 component vector types in some cases need pre-padding
446 0 : hlsl += padHelper.prePaddingString(fieldType);
447 : }
448 :
449 0 : hlsl += " " + InterfaceBlockFieldTypeString(field, blockStorage) +
450 0 : " " + Decorate(field.name()) + ArrayString(fieldType) + ";\n";
451 :
452 : // must pad out after matrices and arrays, where HLSL usually allows itself room to pack stuff
453 0 : if (blockStorage == EbsStd140)
454 : {
455 0 : const bool useHLSLRowMajorPacking = (fieldType.getLayoutQualifier().matrixPacking == EmpColumnMajor);
456 0 : hlsl += padHelper.postPaddingString(fieldType, useHLSLRowMajorPacking);
457 : }
458 : }
459 :
460 0 : return hlsl;
461 : }
462 :
463 0 : TString UniformHLSL::interfaceBlockStructString(const TInterfaceBlock &interfaceBlock)
464 : {
465 0 : const TLayoutBlockStorage blockStorage = interfaceBlock.blockStorage();
466 :
467 0 : return "struct " + InterfaceBlockStructName(interfaceBlock) + "\n"
468 0 : "{\n" +
469 0 : interfaceBlockMembersString(interfaceBlock, blockStorage) +
470 0 : "};\n\n";
471 : }
472 :
473 : }
|