~gabriel1984sibiu/minitube/qt5.6

« back to all changes in this revision

Viewing changes to src/3rdparty/angle/src/libANGLE/renderer/d3d/DynamicHLSL.cpp

  • Committer: Grevutiu Gabriel
  • Date: 2017-06-13 08:43:17 UTC
  • Revision ID: gabriel1984sibiu@gmail.com-20170613084317-ek0zqe0u9g3ocvi8
OriginalĀ upstreamĀ code

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
// DynamicHLSL.cpp: Implementation for link and run-time HLSL generation
 
7
//
 
8
 
 
9
#include "libANGLE/renderer/d3d/DynamicHLSL.h"
 
10
 
 
11
#include "common/utilities.h"
 
12
#include "compiler/translator/blocklayoutHLSL.h"
 
13
#include "libANGLE/Program.h"
 
14
#include "libANGLE/Shader.h"
 
15
#include "libANGLE/formatutils.h"
 
16
#include "libANGLE/renderer/d3d/ProgramD3D.h"
 
17
#include "libANGLE/renderer/d3d/RendererD3D.h"
 
18
#include "libANGLE/renderer/d3d/ShaderD3D.h"
 
19
#include "libANGLE/renderer/d3d/VaryingPacking.h"
 
20
 
 
21
using namespace gl;
 
22
 
 
23
namespace rx
 
24
{
 
25
 
 
26
namespace
 
27
{
 
28
 
 
29
std::string HLSLComponentTypeString(GLenum componentType)
 
30
{
 
31
    switch (componentType)
 
32
    {
 
33
        case GL_UNSIGNED_INT:
 
34
            return "uint";
 
35
        case GL_INT:
 
36
            return "int";
 
37
        case GL_UNSIGNED_NORMALIZED:
 
38
        case GL_SIGNED_NORMALIZED:
 
39
        case GL_FLOAT:
 
40
            return "float";
 
41
        default:
 
42
            UNREACHABLE();
 
43
            return "not-component-type";
 
44
    }
 
45
}
 
46
 
 
47
std::string HLSLComponentTypeString(GLenum componentType, int componentCount)
 
48
{
 
49
    return HLSLComponentTypeString(componentType) + (componentCount > 1 ? Str(componentCount) : "");
 
50
}
 
51
 
 
52
std::string HLSLMatrixTypeString(GLenum type)
 
53
{
 
54
    switch (type)
 
55
    {
 
56
        case GL_FLOAT_MAT2:
 
57
            return "float2x2";
 
58
        case GL_FLOAT_MAT3:
 
59
            return "float3x3";
 
60
        case GL_FLOAT_MAT4:
 
61
            return "float4x4";
 
62
        case GL_FLOAT_MAT2x3:
 
63
            return "float2x3";
 
64
        case GL_FLOAT_MAT3x2:
 
65
            return "float3x2";
 
66
        case GL_FLOAT_MAT2x4:
 
67
            return "float2x4";
 
68
        case GL_FLOAT_MAT4x2:
 
69
            return "float4x2";
 
70
        case GL_FLOAT_MAT3x4:
 
71
            return "float3x4";
 
72
        case GL_FLOAT_MAT4x3:
 
73
            return "float4x3";
 
74
        default:
 
75
            UNREACHABLE();
 
76
            return "not-matrix-type";
 
77
    }
 
78
}
 
79
 
 
80
std::string HLSLTypeString(GLenum type)
 
81
{
 
82
    if (gl::IsMatrixType(type))
 
83
    {
 
84
        return HLSLMatrixTypeString(type);
 
85
    }
 
86
 
 
87
    return HLSLComponentTypeString(gl::VariableComponentType(type),
 
88
                                   gl::VariableComponentCount(type));
 
89
}
 
90
 
 
91
const PixelShaderOutputVariable *FindOutputAtLocation(
 
92
    const std::vector<PixelShaderOutputVariable> &outputVariables,
 
93
    unsigned int location)
 
94
{
 
95
    for (size_t variableIndex = 0; variableIndex < outputVariables.size(); ++variableIndex)
 
96
    {
 
97
        if (outputVariables[variableIndex].outputIndex == location)
 
98
        {
 
99
            return &outputVariables[variableIndex];
 
100
        }
 
101
    }
 
102
 
 
103
    return nullptr;
 
104
}
 
105
 
 
106
void WriteArrayString(std::stringstream &strstr, unsigned int i)
 
107
{
 
108
    static_assert(GL_INVALID_INDEX == UINT_MAX,
 
109
                  "GL_INVALID_INDEX must be equal to the max unsigned int.");
 
110
    if (i == UINT_MAX)
 
111
    {
 
112
        return;
 
113
    }
 
114
 
 
115
    strstr << "[";
 
116
    strstr << i;
 
117
    strstr << "]";
 
118
}
 
119
 
 
120
const std::string VERTEX_ATTRIBUTE_STUB_STRING = "@@ VERTEX ATTRIBUTES @@";
 
121
const std::string PIXEL_OUTPUT_STUB_STRING     = "@@ PIXEL OUTPUT @@";
 
122
}  // anonymous namespace
 
123
 
 
124
std::string GetVaryingSemantic(int majorShaderModel, bool programUsesPointSize)
 
125
{
 
126
    // SM3 reserves the TEXCOORD semantic for point sprite texcoords (gl_PointCoord)
 
127
    // In D3D11 we manually compute gl_PointCoord in the GS.
 
128
    return ((programUsesPointSize && majorShaderModel < 4) ? "COLOR" : "TEXCOORD");
 
129
}
 
130
 
 
131
// DynamicHLSL implementation
 
132
 
 
133
DynamicHLSL::DynamicHLSL(RendererD3D *const renderer) : mRenderer(renderer)
 
134
{
 
135
}
 
136
 
 
137
void DynamicHLSL::generateVaryingHLSL(const VaryingPacking &varyingPacking,
 
138
                                      std::stringstream &hlslStream) const
 
139
{
 
140
    std::string varyingSemantic =
 
141
        GetVaryingSemantic(mRenderer->getMajorShaderModel(), varyingPacking.usesPointSize());
 
142
 
 
143
    for (const PackedVaryingRegister &registerInfo : varyingPacking.getRegisterList())
 
144
    {
 
145
        const auto &varying = *registerInfo.packedVarying->varying;
 
146
        ASSERT(!varying.isStruct());
 
147
 
 
148
        // TODO: Add checks to ensure D3D interpolation modifiers don't result in too many
 
149
        // registers being used.
 
150
        // For example, if there are N registers, and we have N vec3 varyings and 1 float
 
151
        // varying, then D3D will pack them into N registers.
 
152
        // If the float varying has the 'nointerpolation' modifier on it then we would need
 
153
        // N + 1 registers, and D3D compilation will fail.
 
154
 
 
155
        switch (registerInfo.packedVarying->interpolation)
 
156
        {
 
157
            case sh::INTERPOLATION_SMOOTH:
 
158
                hlslStream << "    ";
 
159
                break;
 
160
            case sh::INTERPOLATION_FLAT:
 
161
                hlslStream << "    nointerpolation ";
 
162
                break;
 
163
            case sh::INTERPOLATION_CENTROID:
 
164
                hlslStream << "    centroid ";
 
165
                break;
 
166
            default:
 
167
                UNREACHABLE();
 
168
        }
 
169
 
 
170
        GLenum transposedType = gl::TransposeMatrixType(varying.type);
 
171
        GLenum componentType  = gl::VariableComponentType(transposedType);
 
172
        int columnCount = gl::VariableColumnCount(transposedType);
 
173
        hlslStream << HLSLComponentTypeString(componentType, columnCount);
 
174
        unsigned int semanticIndex = registerInfo.semanticIndex;
 
175
        hlslStream << " v" << semanticIndex << " : " << varyingSemantic << semanticIndex << ";\n";
 
176
    }
 
177
}
 
178
 
 
179
std::string DynamicHLSL::generateVertexShaderForInputLayout(
 
180
    const std::string &sourceShader,
 
181
    const InputLayout &inputLayout,
 
182
    const std::vector<sh::Attribute> &shaderAttributes) const
 
183
{
 
184
    std::stringstream structStream;
 
185
    std::stringstream initStream;
 
186
 
 
187
    structStream << "struct VS_INPUT\n"
 
188
                 << "{\n";
 
189
 
 
190
    int semanticIndex       = 0;
 
191
    unsigned int inputIndex = 0;
 
192
 
 
193
    // If gl_PointSize is used in the shader then pointsprites rendering is expected.
 
194
    // If the renderer does not support Geometry shaders then Instanced PointSprite emulation
 
195
    // must be used.
 
196
    bool usesPointSize = sourceShader.find("GL_USES_POINT_SIZE") != std::string::npos;
 
197
    bool useInstancedPointSpriteEmulation =
 
198
        usesPointSize && mRenderer->getWorkarounds().useInstancedPointSpriteEmulation;
 
199
 
 
200
    // Instanced PointSprite emulation requires additional entries in the
 
201
    // VS_INPUT structure to support the vertices that make up the quad vertices.
 
202
    // These values must be in sync with the cooresponding values added during inputlayout creation
 
203
    // in InputLayoutCache::applyVertexBuffers().
 
204
    //
 
205
    // The additional entries must appear first in the VS_INPUT layout because
 
206
    // Windows Phone 8 era devices require per vertex data to physically come
 
207
    // before per instance data in the shader.
 
208
    if (useInstancedPointSpriteEmulation)
 
209
    {
 
210
        structStream << "    float3 spriteVertexPos : SPRITEPOSITION0;\n"
 
211
                     << "    float2 spriteTexCoord : SPRITETEXCOORD0;\n";
 
212
    }
 
213
 
 
214
    for (size_t attributeIndex = 0; attributeIndex < shaderAttributes.size(); ++attributeIndex)
 
215
    {
 
216
        const sh::Attribute &shaderAttribute = shaderAttributes[attributeIndex];
 
217
        if (!shaderAttribute.name.empty())
 
218
        {
 
219
            ASSERT(inputIndex < MAX_VERTEX_ATTRIBS);
 
220
            VertexFormatType vertexFormatType =
 
221
                inputIndex < inputLayout.size() ? inputLayout[inputIndex] : VERTEX_FORMAT_INVALID;
 
222
 
 
223
            // HLSL code for input structure
 
224
            if (IsMatrixType(shaderAttribute.type))
 
225
            {
 
226
                // Matrix types are always transposed
 
227
                structStream << "    "
 
228
                             << HLSLMatrixTypeString(TransposeMatrixType(shaderAttribute.type));
 
229
            }
 
230
            else
 
231
            {
 
232
                GLenum componentType = mRenderer->getVertexComponentType(vertexFormatType);
 
233
 
 
234
                if (shaderAttribute.name == "gl_InstanceID")
 
235
                {
 
236
                    // The input type of the instance ID in HLSL (uint) differs from the one in ESSL
 
237
                    // (int).
 
238
                    structStream << " uint";
 
239
                }
 
240
                else
 
241
                {
 
242
                    structStream << "    " << HLSLComponentTypeString(
 
243
                                                  componentType,
 
244
                                                  VariableComponentCount(shaderAttribute.type));
 
245
                }
 
246
            }
 
247
 
 
248
            structStream << " " << decorateVariable(shaderAttribute.name) << " : ";
 
249
 
 
250
            if (shaderAttribute.name == "gl_InstanceID")
 
251
            {
 
252
                structStream << "SV_InstanceID";
 
253
            }
 
254
            else
 
255
            {
 
256
                structStream << "TEXCOORD" << semanticIndex;
 
257
                semanticIndex += VariableRegisterCount(shaderAttribute.type);
 
258
            }
 
259
 
 
260
            structStream << ";\n";
 
261
 
 
262
            // HLSL code for initialization
 
263
            initStream << "    " << decorateVariable(shaderAttribute.name) << " = ";
 
264
 
 
265
            // Mismatched vertex attribute to vertex input may result in an undefined
 
266
            // data reinterpretation (eg for pure integer->float, float->pure integer)
 
267
            // TODO: issue warning with gl debug info extension, when supported
 
268
            if (IsMatrixType(shaderAttribute.type) ||
 
269
                (mRenderer->getVertexConversionType(vertexFormatType) & VERTEX_CONVERT_GPU) != 0)
 
270
            {
 
271
                initStream << generateAttributeConversionHLSL(vertexFormatType, shaderAttribute);
 
272
            }
 
273
            else
 
274
            {
 
275
                initStream << "input." << decorateVariable(shaderAttribute.name);
 
276
            }
 
277
 
 
278
            initStream << ";\n";
 
279
 
 
280
            inputIndex += VariableRowCount(TransposeMatrixType(shaderAttribute.type));
 
281
        }
 
282
    }
 
283
 
 
284
    structStream << "};\n"
 
285
                    "\n"
 
286
                    "void initAttributes(VS_INPUT input)\n"
 
287
                    "{\n"
 
288
                 << initStream.str() << "}\n";
 
289
 
 
290
    std::string vertexHLSL(sourceShader);
 
291
 
 
292
    size_t copyInsertionPos = vertexHLSL.find(VERTEX_ATTRIBUTE_STUB_STRING);
 
293
    vertexHLSL.replace(copyInsertionPos, VERTEX_ATTRIBUTE_STUB_STRING.length(), structStream.str());
 
294
 
 
295
    return vertexHLSL;
 
296
}
 
297
 
 
298
std::string DynamicHLSL::generatePixelShaderForOutputSignature(
 
299
    const std::string &sourceShader,
 
300
    const std::vector<PixelShaderOutputVariable> &outputVariables,
 
301
    bool usesFragDepth,
 
302
    const std::vector<GLenum> &outputLayout) const
 
303
{
 
304
    const int shaderModel      = mRenderer->getMajorShaderModel();
 
305
    std::string targetSemantic = (shaderModel >= 4) ? "SV_TARGET" : "COLOR";
 
306
    std::string depthSemantic  = (shaderModel >= 4) ? "SV_Depth" : "DEPTH";
 
307
 
 
308
    std::stringstream declarationStream;
 
309
    std::stringstream copyStream;
 
310
 
 
311
    declarationStream << "struct PS_OUTPUT\n"
 
312
                         "{\n";
 
313
 
 
314
    for (size_t layoutIndex = 0; layoutIndex < outputLayout.size(); ++layoutIndex)
 
315
    {
 
316
        GLenum binding = outputLayout[layoutIndex];
 
317
 
 
318
        if (binding != GL_NONE)
 
319
        {
 
320
            unsigned int location = (binding - GL_COLOR_ATTACHMENT0);
 
321
 
 
322
            const PixelShaderOutputVariable *outputVariable =
 
323
                FindOutputAtLocation(outputVariables, location);
 
324
 
 
325
            // OpenGL ES 3.0 spec $4.2.1
 
326
            // If [...] not all user-defined output variables are written, the values of fragment
 
327
            // colors
 
328
            // corresponding to unwritten variables are similarly undefined.
 
329
            if (outputVariable)
 
330
            {
 
331
                declarationStream << "    " + HLSLTypeString(outputVariable->type) << " "
 
332
                                  << outputVariable->name << " : " << targetSemantic
 
333
                                  << static_cast<int>(layoutIndex) << ";\n";
 
334
 
 
335
                copyStream << "    output." << outputVariable->name << " = "
 
336
                           << outputVariable->source << ";\n";
 
337
            }
 
338
        }
 
339
    }
 
340
 
 
341
    if (usesFragDepth)
 
342
    {
 
343
        declarationStream << "    float gl_Depth : " << depthSemantic << ";\n";
 
344
        copyStream << "    output.gl_Depth = gl_Depth; \n";
 
345
    }
 
346
 
 
347
    declarationStream << "};\n"
 
348
                         "\n"
 
349
                         "PS_OUTPUT generateOutput()\n"
 
350
                         "{\n"
 
351
                         "    PS_OUTPUT output;\n"
 
352
                      << copyStream.str() << "    return output;\n"
 
353
                                             "}\n";
 
354
 
 
355
    std::string pixelHLSL(sourceShader);
 
356
 
 
357
    size_t outputInsertionPos = pixelHLSL.find(PIXEL_OUTPUT_STUB_STRING);
 
358
    pixelHLSL.replace(outputInsertionPos, PIXEL_OUTPUT_STUB_STRING.length(),
 
359
                      declarationStream.str());
 
360
 
 
361
    return pixelHLSL;
 
362
}
 
363
 
 
364
void DynamicHLSL::generateVaryingLinkHLSL(ShaderType shaderType,
 
365
                                          const VaryingPacking &varyingPacking,
 
366
                                          std::stringstream &linkStream) const
 
367
{
 
368
    const auto &builtins = varyingPacking.builtins(shaderType);
 
369
    ASSERT(builtins.dxPosition.enabled);
 
370
    linkStream << "{\n"
 
371
               << "    float4 dx_Position : " << builtins.dxPosition.str() << ";\n";
 
372
 
 
373
    if (builtins.glPosition.enabled)
 
374
    {
 
375
        linkStream << "    float4 gl_Position : " << builtins.glPosition.str() << ";\n";
 
376
    }
 
377
 
 
378
    if (builtins.glFragCoord.enabled)
 
379
    {
 
380
        linkStream << "    float4 gl_FragCoord : " << builtins.glFragCoord.str() << ";\n";
 
381
    }
 
382
 
 
383
    if (builtins.glPointCoord.enabled)
 
384
    {
 
385
        linkStream << "    float2 gl_PointCoord : " << builtins.glPointCoord.str() << ";\n";
 
386
    }
 
387
 
 
388
    if (builtins.glPointSize.enabled)
 
389
    {
 
390
        linkStream << "    float gl_PointSize : " << builtins.glPointSize.str() << ";\n";
 
391
    }
 
392
 
 
393
    // Do this after glPointSize, to potentially combine gl_PointCoord and gl_PointSize into the
 
394
    // same register.
 
395
    generateVaryingHLSL(varyingPacking, linkStream);
 
396
 
 
397
    linkStream << "};\n";
 
398
}
 
399
 
 
400
bool DynamicHLSL::generateShaderLinkHLSL(const gl::Data &data,
 
401
                                         const gl::Program::Data &programData,
 
402
                                         const ProgramD3DMetadata &programMetadata,
 
403
                                         const VaryingPacking &varyingPacking,
 
404
                                         std::string *pixelHLSL,
 
405
                                         std::string *vertexHLSL) const
 
406
{
 
407
    ASSERT(pixelHLSL->empty() && vertexHLSL->empty());
 
408
 
 
409
    const gl::Shader *vertexShaderGL   = programData.getAttachedVertexShader();
 
410
    const ShaderD3D *vertexShader      = GetImplAs<ShaderD3D>(vertexShaderGL);
 
411
    const gl::Shader *fragmentShaderGL = programData.getAttachedFragmentShader();
 
412
    const ShaderD3D *fragmentShader    = GetImplAs<ShaderD3D>(fragmentShaderGL);
 
413
    const int shaderModel              = mRenderer->getMajorShaderModel();
 
414
 
 
415
    // usesViewScale() isn't supported in the D3D9 renderer
 
416
    ASSERT(shaderModel >= 4 || !programMetadata.usesViewScale());
 
417
 
 
418
    bool useInstancedPointSpriteEmulation =
 
419
        programMetadata.usesPointSize() &&
 
420
        mRenderer->getWorkarounds().useInstancedPointSpriteEmulation;
 
421
 
 
422
    // Validation done in the compiler
 
423
    ASSERT(!fragmentShader->usesFragColor() || !fragmentShader->usesFragData());
 
424
 
 
425
    std::stringstream vertexStream;
 
426
    vertexStream << vertexShaderGL->getTranslatedSource();
 
427
 
 
428
    // Instanced PointSprite emulation requires additional entries originally generated in the
 
429
    // GeometryShader HLSL. These include pointsize clamp values.
 
430
    if (useInstancedPointSpriteEmulation)
 
431
    {
 
432
        vertexStream << "static float minPointSize = "
 
433
                     << static_cast<int>(data.caps->minAliasedPointSize) << ".0f;\n"
 
434
                     << "static float maxPointSize = "
 
435
                     << static_cast<int>(data.caps->maxAliasedPointSize) << ".0f;\n";
 
436
    }
 
437
 
 
438
    // Add stub string to be replaced when shader is dynamically defined by its layout
 
439
    vertexStream << "\n" << VERTEX_ATTRIBUTE_STUB_STRING + "\n";
 
440
 
 
441
    // Write the HLSL input/output declarations
 
442
    vertexStream << "struct VS_OUTPUT\n";
 
443
    generateVaryingLinkHLSL(SHADER_VERTEX, varyingPacking, vertexStream);
 
444
    vertexStream << "\n"
 
445
                 << "VS_OUTPUT main(VS_INPUT input)\n"
 
446
                 << "{\n"
 
447
                 << "    initAttributes(input);\n";
 
448
 
 
449
    if (vertexShader->usesDeferredInit())
 
450
    {
 
451
        vertexStream << "\n"
 
452
                     << "    initializeDeferredGlobals();\n";
 
453
    }
 
454
 
 
455
    vertexStream << "\n"
 
456
                 << "    gl_main();\n"
 
457
                 << "\n"
 
458
                 << "    VS_OUTPUT output;\n";
 
459
 
 
460
    const auto &vertexBuiltins = varyingPacking.builtins(SHADER_VERTEX);
 
461
 
 
462
    if (vertexBuiltins.glPosition.enabled)
 
463
    {
 
464
        vertexStream << "    output.gl_Position = gl_Position;\n";
 
465
    }
 
466
 
 
467
    // On D3D9 or D3D11 Feature Level 9, we need to emulate large viewports using dx_ViewAdjust.
 
468
    if (shaderModel >= 4 && mRenderer->getShaderModelSuffix() == "")
 
469
    {
 
470
        vertexStream << "    output.dx_Position.x = gl_Position.x;\n";
 
471
 
 
472
        if (programMetadata.usesViewScale())
 
473
        {
 
474
            // This code assumes that dx_ViewScale.y = -1.0f when rendering to texture, and +1.0f
 
475
            // when rendering to the default framebuffer. No other values are valid.
 
476
            vertexStream << "    output.dx_Position.y = dx_ViewScale.y * gl_Position.y;\n";
 
477
        }
 
478
        else
 
479
        {
 
480
            vertexStream << "    output.dx_Position.y = - gl_Position.y;\n";
 
481
        }
 
482
 
 
483
        vertexStream << "    output.dx_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
 
484
                     << "    output.dx_Position.w = gl_Position.w;\n";
 
485
    }
 
486
    else
 
487
    {
 
488
        vertexStream << "    output.dx_Position.x = gl_Position.x * dx_ViewAdjust.z + "
 
489
                        "dx_ViewAdjust.x * gl_Position.w;\n";
 
490
 
 
491
        // If usesViewScale() is true and we're using the D3D11 renderer via Feature Level 9_*,
 
492
        // then we need to multiply the gl_Position.y by the viewScale.
 
493
        // usesViewScale() isn't supported when using the D3D9 renderer.
 
494
        if (programMetadata.usesViewScale() &&
 
495
            (shaderModel >= 4 && mRenderer->getShaderModelSuffix() != ""))
 
496
        {
 
497
            vertexStream << "    output.dx_Position.y = dx_ViewScale.y * (gl_Position.y * "
 
498
                            "dx_ViewAdjust.w + dx_ViewAdjust.y * gl_Position.w);\n";
 
499
        }
 
500
        else
 
501
        {
 
502
            vertexStream << "    output.dx_Position.y = -(gl_Position.y * dx_ViewAdjust.w + "
 
503
                            "dx_ViewAdjust.y * gl_Position.w);\n";
 
504
        }
 
505
 
 
506
        vertexStream << "    output.dx_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
 
507
                     << "    output.dx_Position.w = gl_Position.w;\n";
 
508
    }
 
509
 
 
510
    // We don't need to output gl_PointSize if we use are emulating point sprites via instancing.
 
511
    if (vertexBuiltins.glPointSize.enabled)
 
512
    {
 
513
        vertexStream << "    output.gl_PointSize = gl_PointSize;\n";
 
514
    }
 
515
 
 
516
    if (vertexBuiltins.glFragCoord.enabled)
 
517
    {
 
518
        vertexStream << "    output.gl_FragCoord = gl_Position;\n";
 
519
    }
 
520
 
 
521
    for (const PackedVaryingRegister &registerInfo : varyingPacking.getRegisterList())
 
522
    {
 
523
        const auto &packedVarying = *registerInfo.packedVarying;
 
524
        const auto &varying = *packedVarying.varying;
 
525
        ASSERT(!varying.isStruct());
 
526
 
 
527
        vertexStream << "    output.v" << registerInfo.semanticIndex << " = ";
 
528
 
 
529
        if (packedVarying.isStructField())
 
530
        {
 
531
            vertexStream << decorateVariable(packedVarying.parentStructName) << ".";
 
532
        }
 
533
 
 
534
        vertexStream << decorateVariable(varying.name);
 
535
 
 
536
        if (varying.isArray())
 
537
        {
 
538
            WriteArrayString(vertexStream, registerInfo.varyingArrayIndex);
 
539
        }
 
540
 
 
541
        if (VariableRowCount(varying.type) > 1)
 
542
        {
 
543
            WriteArrayString(vertexStream, registerInfo.varyingRowIndex);
 
544
        }
 
545
 
 
546
        vertexStream << ";\n";
 
547
    }
 
548
 
 
549
    // Instanced PointSprite emulation requires additional entries to calculate
 
550
    // the final output vertex positions of the quad that represents each sprite.
 
551
    if (useInstancedPointSpriteEmulation)
 
552
    {
 
553
        vertexStream << "\n"
 
554
                     << "    gl_PointSize = clamp(gl_PointSize, minPointSize, maxPointSize);\n";
 
555
 
 
556
        vertexStream << "    output.dx_Position.x += (input.spriteVertexPos.x * gl_PointSize / "
 
557
                        "(dx_ViewCoords.x*2)) * output.dx_Position.w;";
 
558
 
 
559
        if (programMetadata.usesViewScale())
 
560
        {
 
561
            // Multiply by ViewScale to invert the rendering when appropriate
 
562
            vertexStream << "    output.dx_Position.y += (-dx_ViewScale.y * "
 
563
                            "input.spriteVertexPos.y * gl_PointSize / (dx_ViewCoords.y*2)) * "
 
564
                            "output.dx_Position.w;";
 
565
        }
 
566
        else
 
567
        {
 
568
            vertexStream << "    output.dx_Position.y += (input.spriteVertexPos.y * gl_PointSize / "
 
569
                            "(dx_ViewCoords.y*2)) * output.dx_Position.w;";
 
570
        }
 
571
 
 
572
        vertexStream
 
573
            << "    output.dx_Position.z += input.spriteVertexPos.z * output.dx_Position.w;\n";
 
574
 
 
575
        if (programMetadata.usesPointCoord())
 
576
        {
 
577
            vertexStream << "\n"
 
578
                         << "    output.gl_PointCoord = input.spriteTexCoord;\n";
 
579
        }
 
580
    }
 
581
 
 
582
    // Renderers that enable instanced pointsprite emulation require the vertex shader output member
 
583
    // gl_PointCoord to be set to a default value if used without gl_PointSize. 0.5,0.5 is the same
 
584
    // default value used in the generated pixel shader.
 
585
    if (programMetadata.usesInsertedPointCoordValue())
 
586
    {
 
587
        ASSERT(!useInstancedPointSpriteEmulation);
 
588
        vertexStream << "\n"
 
589
                     << "    output.gl_PointCoord = float2(0.5, 0.5);\n";
 
590
    }
 
591
 
 
592
    vertexStream << "\n"
 
593
                 << "    return output;\n"
 
594
                 << "}\n";
 
595
 
 
596
    std::stringstream pixelStream;
 
597
    pixelStream << fragmentShaderGL->getTranslatedSource();
 
598
    pixelStream << "struct PS_INPUT\n";
 
599
    generateVaryingLinkHLSL(SHADER_PIXEL, varyingPacking, pixelStream);
 
600
    pixelStream << "\n";
 
601
 
 
602
    pixelStream << PIXEL_OUTPUT_STUB_STRING + "\n";
 
603
 
 
604
    if (fragmentShader->usesFrontFacing())
 
605
    {
 
606
        if (shaderModel >= 4)
 
607
        {
 
608
            pixelStream << "PS_OUTPUT main(PS_INPUT input, bool isFrontFace : SV_IsFrontFace)\n"
 
609
                        << "{\n";
 
610
        }
 
611
        else
 
612
        {
 
613
            pixelStream << "PS_OUTPUT main(PS_INPUT input, float vFace : VFACE)\n"
 
614
                        << "{\n";
 
615
        }
 
616
    }
 
617
    else
 
618
    {
 
619
        pixelStream << "PS_OUTPUT main(PS_INPUT input)\n"
 
620
                    << "{\n";
 
621
    }
 
622
 
 
623
    const auto &pixelBuiltins = varyingPacking.builtins(SHADER_PIXEL);
 
624
 
 
625
    if (pixelBuiltins.glFragCoord.enabled)
 
626
    {
 
627
        pixelStream << "    float rhw = 1.0 / input.gl_FragCoord.w;\n";
 
628
 
 
629
        // Certain Shader Models (4_0+ and 3_0) allow reading from dx_Position in the pixel shader.
 
630
        // Other Shader Models (4_0_level_9_3 and 2_x) don't support this, so we emulate it using
 
631
        // dx_ViewCoords.
 
632
        if (shaderModel >= 4 && mRenderer->getShaderModelSuffix() == "")
 
633
        {
 
634
            pixelStream << "    gl_FragCoord.x = input.dx_Position.x;\n"
 
635
                        << "    gl_FragCoord.y = input.dx_Position.y;\n";
 
636
        }
 
637
        else if (shaderModel == 3)
 
638
        {
 
639
            pixelStream << "    gl_FragCoord.x = input.dx_Position.x + 0.5;\n"
 
640
                        << "    gl_FragCoord.y = input.dx_Position.y + 0.5;\n";
 
641
        }
 
642
        else
 
643
        {
 
644
            // dx_ViewCoords contains the viewport width/2, height/2, center.x and center.y. See
 
645
            // Renderer::setViewport()
 
646
            pixelStream << "    gl_FragCoord.x = (input.gl_FragCoord.x * rhw) * dx_ViewCoords.x + "
 
647
                           "dx_ViewCoords.z;\n"
 
648
                        << "    gl_FragCoord.y = (input.gl_FragCoord.y * rhw) * dx_ViewCoords.y + "
 
649
                           "dx_ViewCoords.w;\n";
 
650
        }
 
651
 
 
652
        if (programMetadata.usesViewScale())
 
653
        {
 
654
            // For Feature Level 9_3 and below, we need to correct gl_FragCoord.y to account
 
655
            // for dx_ViewScale. On Feature Level 10_0+, gl_FragCoord.y is calculated above using
 
656
            // dx_ViewCoords and is always correct irrespective of dx_ViewScale's value.
 
657
            // NOTE: usesViewScale() can only be true on D3D11 (i.e. Shader Model 4.0+).
 
658
            if (shaderModel >= 4 && mRenderer->getShaderModelSuffix() == "")
 
659
            {
 
660
                // Some assumptions:
 
661
                //  - dx_ViewScale.y = -1.0f when rendering to texture
 
662
                //  - dx_ViewScale.y = +1.0f when rendering to the default framebuffer
 
663
                //  - gl_FragCoord.y has been set correctly above.
 
664
                //
 
665
                // When rendering to the backbuffer, the code inverts gl_FragCoord's y coordinate.
 
666
                // This involves subtracting the y coordinate from the height of the area being
 
667
                // rendered to.
 
668
                //
 
669
                // First we calculate the height of the area being rendered to:
 
670
                //    render_area_height = (2.0f / (1.0f - input.gl_FragCoord.y * rhw)) *
 
671
                //    gl_FragCoord.y
 
672
                //
 
673
                // Note that when we're rendering to default FB, we want our output to be
 
674
                // equivalent to:
 
675
                //    "gl_FragCoord.y = render_area_height - gl_FragCoord.y"
 
676
                //
 
677
                // When we're rendering to a texture, we want our output to be equivalent to:
 
678
                //    "gl_FragCoord.y = gl_FragCoord.y;"
 
679
                //
 
680
                // If we set scale_factor = ((1.0f + dx_ViewScale.y) / 2.0f), then notice that
 
681
                //  - When rendering to default FB: scale_factor = 1.0f
 
682
                //  - When rendering to texture:    scale_factor = 0.0f
 
683
                //
 
684
                // Therefore, we can get our desired output by setting:
 
685
                //    "gl_FragCoord.y = scale_factor * render_area_height - dx_ViewScale.y *
 
686
                //    gl_FragCoord.y"
 
687
                //
 
688
                // Simplifying, this becomes:
 
689
                pixelStream
 
690
                    << "    gl_FragCoord.y = (1.0f + dx_ViewScale.y) * gl_FragCoord.y /"
 
691
                       "(1.0f - input.gl_FragCoord.y * rhw)  - dx_ViewScale.y * gl_FragCoord.y;\n";
 
692
            }
 
693
        }
 
694
 
 
695
        pixelStream << "    gl_FragCoord.z = (input.gl_FragCoord.z * rhw) * dx_DepthFront.x + "
 
696
                       "dx_DepthFront.y;\n"
 
697
                    << "    gl_FragCoord.w = rhw;\n";
 
698
    }
 
699
 
 
700
    if (pixelBuiltins.glPointCoord.enabled && shaderModel >= 3)
 
701
    {
 
702
        pixelStream << "    gl_PointCoord.x = input.gl_PointCoord.x;\n"
 
703
                    << "    gl_PointCoord.y = 1.0 - input.gl_PointCoord.y;\n";
 
704
    }
 
705
 
 
706
    if (fragmentShader->usesFrontFacing())
 
707
    {
 
708
        if (shaderModel <= 3)
 
709
        {
 
710
            pixelStream << "    gl_FrontFacing = (vFace * dx_DepthFront.z >= 0.0);\n";
 
711
        }
 
712
        else
 
713
        {
 
714
            pixelStream << "    gl_FrontFacing = isFrontFace;\n";
 
715
        }
 
716
    }
 
717
 
 
718
    for (const PackedVaryingRegister &registerInfo : varyingPacking.getRegisterList())
 
719
    {
 
720
        const auto &packedVarying = *registerInfo.packedVarying;
 
721
        const auto &varying = *packedVarying.varying;
 
722
        ASSERT(!varying.isBuiltIn() && !varying.isStruct());
 
723
 
 
724
        // Don't reference VS-only transform feedback varyings in the PS.
 
725
        if (registerInfo.packedVarying->vertexOnly)
 
726
            continue;
 
727
 
 
728
        pixelStream << "    ";
 
729
 
 
730
        if (packedVarying.isStructField())
 
731
        {
 
732
            pixelStream << decorateVariable(packedVarying.parentStructName) << ".";
 
733
        }
 
734
 
 
735
        pixelStream << decorateVariable(varying.name);
 
736
 
 
737
        if (varying.isArray())
 
738
        {
 
739
            WriteArrayString(pixelStream, registerInfo.varyingArrayIndex);
 
740
        }
 
741
 
 
742
        GLenum transposedType = TransposeMatrixType(varying.type);
 
743
        if (VariableRowCount(transposedType) > 1)
 
744
        {
 
745
            WriteArrayString(pixelStream, registerInfo.varyingRowIndex);
 
746
        }
 
747
 
 
748
        pixelStream << " = input.v" << registerInfo.semanticIndex;
 
749
 
 
750
        switch (VariableColumnCount(transposedType))
 
751
        {
 
752
            case 1:
 
753
                pixelStream << ".x";
 
754
                break;
 
755
            case 2:
 
756
                pixelStream << ".xy";
 
757
                break;
 
758
            case 3:
 
759
                pixelStream << ".xyz";
 
760
                break;
 
761
            case 4:
 
762
                break;
 
763
            default:
 
764
                UNREACHABLE();
 
765
        }
 
766
        pixelStream << ";\n";
 
767
    }
 
768
 
 
769
    if (fragmentShader->usesDeferredInit())
 
770
    {
 
771
        pixelStream << "\n"
 
772
                    << "    initializeDeferredGlobals();\n";
 
773
    }
 
774
 
 
775
    pixelStream << "\n"
 
776
                << "    gl_main();\n"
 
777
                << "\n"
 
778
                << "    return generateOutput();\n"
 
779
                << "}\n";
 
780
 
 
781
    *vertexHLSL = vertexStream.str();
 
782
    *pixelHLSL  = pixelStream.str();
 
783
 
 
784
    return true;
 
785
}
 
786
 
 
787
std::string DynamicHLSL::generateGeometryShaderPreamble(const VaryingPacking &varyingPacking) const
 
788
{
 
789
    ASSERT(mRenderer->getMajorShaderModel() >= 4);
 
790
 
 
791
    std::stringstream preambleStream;
 
792
 
 
793
    const auto &builtins = varyingPacking.builtins(SHADER_VERTEX);
 
794
 
 
795
    preambleStream << "struct GS_INPUT\n";
 
796
    generateVaryingLinkHLSL(SHADER_VERTEX, varyingPacking, preambleStream);
 
797
    preambleStream << "\n"
 
798
                   << "struct GS_OUTPUT\n";
 
799
    generateVaryingLinkHLSL(SHADER_GEOMETRY, varyingPacking, preambleStream);
 
800
    preambleStream
 
801
        << "\n"
 
802
        << "void copyVertex(inout GS_OUTPUT output, GS_INPUT input, GS_INPUT flatinput)\n"
 
803
        << "{\n"
 
804
        << "    output.gl_Position = input.gl_Position;\n";
 
805
 
 
806
    if (builtins.glPointSize.enabled)
 
807
    {
 
808
        preambleStream << "    output.gl_PointSize = input.gl_PointSize;\n";
 
809
    }
 
810
 
 
811
    for (const PackedVaryingRegister &varyingRegister : varyingPacking.getRegisterList())
 
812
    {
 
813
        preambleStream << "    output.v" << varyingRegister.semanticIndex << " = ";
 
814
        if (varyingRegister.packedVarying->interpolation == sh::INTERPOLATION_FLAT)
 
815
        {
 
816
            preambleStream << "flat";
 
817
        }
 
818
        preambleStream << "input.v" << varyingRegister.semanticIndex << "; \n";
 
819
    }
 
820
 
 
821
    if (builtins.glFragCoord.enabled)
 
822
    {
 
823
        preambleStream << "    output.gl_FragCoord = input.gl_FragCoord;\n";
 
824
    }
 
825
 
 
826
    // Only write the dx_Position if we aren't using point sprites
 
827
    preambleStream << "#ifndef ANGLE_POINT_SPRITE_SHADER\n"
 
828
                   << "    output.dx_Position = input.dx_Position;\n"
 
829
                   << "#endif  // ANGLE_POINT_SPRITE_SHADER\n"
 
830
                   << "}\n";
 
831
 
 
832
    return preambleStream.str();
 
833
}
 
834
 
 
835
std::string DynamicHLSL::generateGeometryShaderHLSL(gl::PrimitiveType primitiveType,
 
836
                                                    const gl::Data &data,
 
837
                                                    const gl::Program::Data &programData,
 
838
                                                    const bool useViewScale,
 
839
                                                    const std::string &preambleString) const
 
840
{
 
841
    ASSERT(mRenderer->getMajorShaderModel() >= 4);
 
842
 
 
843
    std::stringstream shaderStream;
 
844
 
 
845
    const bool pointSprites   = (primitiveType == PRIMITIVE_POINTS);
 
846
    const bool usesPointCoord = preambleString.find("gl_PointCoord") != std::string::npos;
 
847
 
 
848
    const char *inputPT  = nullptr;
 
849
    const char *outputPT = nullptr;
 
850
    int inputSize        = 0;
 
851
    int maxVertexOutput  = 0;
 
852
 
 
853
    switch (primitiveType)
 
854
    {
 
855
        case PRIMITIVE_POINTS:
 
856
            inputPT         = "point";
 
857
            outputPT        = "Triangle";
 
858
            inputSize       = 1;
 
859
            maxVertexOutput = 4;
 
860
            break;
 
861
 
 
862
        case PRIMITIVE_LINES:
 
863
        case PRIMITIVE_LINE_STRIP:
 
864
        case PRIMITIVE_LINE_LOOP:
 
865
            inputPT         = "line";
 
866
            outputPT        = "Line";
 
867
            inputSize       = 2;
 
868
            maxVertexOutput = 2;
 
869
            break;
 
870
 
 
871
        case PRIMITIVE_TRIANGLES:
 
872
        case PRIMITIVE_TRIANGLE_STRIP:
 
873
        case PRIMITIVE_TRIANGLE_FAN:
 
874
            inputPT         = "triangle";
 
875
            outputPT        = "Triangle";
 
876
            inputSize       = 3;
 
877
            maxVertexOutput = 3;
 
878
            break;
 
879
 
 
880
        default:
 
881
            UNREACHABLE();
 
882
            break;
 
883
    }
 
884
 
 
885
    if (pointSprites)
 
886
    {
 
887
        shaderStream << "#define ANGLE_POINT_SPRITE_SHADER\n"
 
888
                        "\n"
 
889
                        "uniform float4 dx_ViewCoords : register(c1);\n";
 
890
 
 
891
        if (useViewScale)
 
892
        {
 
893
            shaderStream << "uniform float2 dx_ViewScale : register(c3);\n";
 
894
        }
 
895
 
 
896
        shaderStream << "\n"
 
897
                        "static float2 pointSpriteCorners[] = \n"
 
898
                        "{\n"
 
899
                        "    float2( 0.5f, -0.5f),\n"
 
900
                        "    float2( 0.5f,  0.5f),\n"
 
901
                        "    float2(-0.5f, -0.5f),\n"
 
902
                        "    float2(-0.5f,  0.5f)\n"
 
903
                        "};\n"
 
904
                        "\n"
 
905
                        "static float2 pointSpriteTexcoords[] = \n"
 
906
                        "{\n"
 
907
                        "    float2(1.0f, 1.0f),\n"
 
908
                        "    float2(1.0f, 0.0f),\n"
 
909
                        "    float2(0.0f, 1.0f),\n"
 
910
                        "    float2(0.0f, 0.0f)\n"
 
911
                        "};\n"
 
912
                        "\n"
 
913
                        "static float minPointSize = "
 
914
                     << static_cast<int>(data.caps->minAliasedPointSize)
 
915
                     << ".0f;\n"
 
916
                        "static float maxPointSize = "
 
917
                     << static_cast<int>(data.caps->maxAliasedPointSize) << ".0f;\n"
 
918
                     << "\n";
 
919
    }
 
920
 
 
921
    shaderStream << preambleString << "\n"
 
922
                 << "[maxvertexcount(" << maxVertexOutput << ")]\n"
 
923
                 << "void main(" << inputPT << " GS_INPUT input[" << inputSize << "], ";
 
924
 
 
925
    if (primitiveType == PRIMITIVE_TRIANGLE_STRIP)
 
926
    {
 
927
        shaderStream << "uint primitiveID : SV_PrimitiveID, ";
 
928
    }
 
929
 
 
930
    shaderStream << " inout " << outputPT << "Stream<GS_OUTPUT> outStream)\n"
 
931
                 << "{\n"
 
932
                 << "    GS_OUTPUT output = (GS_OUTPUT)0;\n";
 
933
 
 
934
    if (primitiveType == PRIMITIVE_TRIANGLE_STRIP)
 
935
    {
 
936
        shaderStream << "    uint lastVertexIndex = (primitiveID % 2 == 0 ? 2 : 1);\n";
 
937
    }
 
938
    else
 
939
    {
 
940
        shaderStream << "    uint lastVertexIndex = " << (inputSize - 1) << ";\n";
 
941
    }
 
942
 
 
943
    for (int vertexIndex = 0; vertexIndex < inputSize; ++vertexIndex)
 
944
    {
 
945
        shaderStream << "    copyVertex(output, input[" << vertexIndex
 
946
                     << "], input[lastVertexIndex]);\n";
 
947
 
 
948
        if (!pointSprites)
 
949
        {
 
950
            ASSERT(inputSize == maxVertexOutput);
 
951
            shaderStream << "    outStream.Append(output);\n";
 
952
        }
 
953
    }
 
954
 
 
955
    if (pointSprites)
 
956
    {
 
957
        shaderStream << "\n"
 
958
                        "    float4 dx_Position = input[0].dx_Position;\n"
 
959
                        "    float gl_PointSize = clamp(input[0].gl_PointSize, minPointSize, "
 
960
                        "maxPointSize);\n"
 
961
                        "    float2 viewportScale = float2(1.0f / dx_ViewCoords.x, 1.0f / "
 
962
                        "dx_ViewCoords.y) * dx_Position.w;\n";
 
963
 
 
964
        for (int corner = 0; corner < 4; corner++)
 
965
        {
 
966
            if (useViewScale)
 
967
            {
 
968
                shaderStream << "    \n"
 
969
                                "    output.dx_Position = dx_Position + float4(1.0f, "
 
970
                                "-dx_ViewScale.y, 1.0f, 1.0f)"
 
971
                                "        * float4(pointSpriteCorners["
 
972
                             << corner << "] * viewportScale * gl_PointSize, 0.0f, 0.0f);\n";
 
973
            }
 
974
            else
 
975
            {
 
976
                shaderStream << "\n"
 
977
                                "    output.dx_Position = dx_Position + float4(pointSpriteCorners["
 
978
                             << corner << "] * viewportScale * gl_PointSize, 0.0f, 0.0f);\n";
 
979
            }
 
980
 
 
981
            if (usesPointCoord)
 
982
            {
 
983
                shaderStream << "    output.gl_PointCoord = pointSpriteTexcoords[" << corner
 
984
                             << "];\n";
 
985
            }
 
986
 
 
987
            shaderStream << "    outStream.Append(output);\n";
 
988
        }
 
989
    }
 
990
 
 
991
    shaderStream << "    \n"
 
992
                    "    outStream.RestartStrip();\n"
 
993
                    "}\n";
 
994
 
 
995
    return shaderStream.str();
 
996
}
 
997
 
 
998
// This method needs to match OutputHLSL::decorate
 
999
std::string DynamicHLSL::decorateVariable(const std::string &name)
 
1000
{
 
1001
    if (name.compare(0, 3, "gl_") != 0)
 
1002
    {
 
1003
        return "_" + name;
 
1004
    }
 
1005
 
 
1006
    return name;
 
1007
}
 
1008
 
 
1009
std::string DynamicHLSL::generateAttributeConversionHLSL(
 
1010
    gl::VertexFormatType vertexFormatType,
 
1011
    const sh::ShaderVariable &shaderAttrib) const
 
1012
{
 
1013
    const gl::VertexFormat &vertexFormat = gl::GetVertexFormatFromType(vertexFormatType);
 
1014
    std::string attribString             = "input." + decorateVariable(shaderAttrib.name);
 
1015
 
 
1016
    // Matrix
 
1017
    if (IsMatrixType(shaderAttrib.type))
 
1018
    {
 
1019
        return "transpose(" + attribString + ")";
 
1020
    }
 
1021
 
 
1022
    GLenum shaderComponentType = VariableComponentType(shaderAttrib.type);
 
1023
    int shaderComponentCount   = VariableComponentCount(shaderAttrib.type);
 
1024
 
 
1025
    // Perform integer to float conversion (if necessary)
 
1026
    bool requiresTypeConversion =
 
1027
        (shaderComponentType == GL_FLOAT && vertexFormat.type != GL_FLOAT);
 
1028
 
 
1029
    if (requiresTypeConversion)
 
1030
    {
 
1031
        // TODO: normalization for 32-bit integer formats
 
1032
        ASSERT(!vertexFormat.normalized && !vertexFormat.pureInteger);
 
1033
        return "float" + Str(shaderComponentCount) + "(" + attribString + ")";
 
1034
    }
 
1035
 
 
1036
    // No conversion necessary
 
1037
    return attribString;
 
1038
}
 
1039
 
 
1040
void DynamicHLSL::getPixelShaderOutputKey(const gl::Data &data,
 
1041
                                          const gl::Program::Data &programData,
 
1042
                                          const ProgramD3DMetadata &metadata,
 
1043
                                          std::vector<PixelShaderOutputVariable> *outPixelShaderKey)
 
1044
{
 
1045
    // Two cases when writing to gl_FragColor and using ESSL 1.0:
 
1046
    // - with a 3.0 context, the output color is copied to channel 0
 
1047
    // - with a 2.0 context, the output color is broadcast to all channels
 
1048
    bool broadcast = metadata.usesBroadcast(data);
 
1049
    const unsigned int numRenderTargets =
 
1050
        (broadcast || metadata.usesMultipleFragmentOuts() ? data.caps->maxDrawBuffers : 1);
 
1051
 
 
1052
    if (metadata.getMajorShaderVersion() < 300)
 
1053
    {
 
1054
        for (unsigned int renderTargetIndex = 0; renderTargetIndex < numRenderTargets;
 
1055
             renderTargetIndex++)
 
1056
        {
 
1057
            PixelShaderOutputVariable outputKeyVariable;
 
1058
            outputKeyVariable.type = GL_FLOAT_VEC4;
 
1059
            outputKeyVariable.name = "gl_Color" + Str(renderTargetIndex);
 
1060
            outputKeyVariable.source =
 
1061
                broadcast ? "gl_Color[0]" : "gl_Color[" + Str(renderTargetIndex) + "]";
 
1062
            outputKeyVariable.outputIndex = renderTargetIndex;
 
1063
 
 
1064
            outPixelShaderKey->push_back(outputKeyVariable);
 
1065
        }
 
1066
    }
 
1067
    else
 
1068
    {
 
1069
        const auto &shaderOutputVars =
 
1070
            metadata.getFragmentShader()->getData().getActiveOutputVariables();
 
1071
 
 
1072
        for (auto outputPair : programData.getOutputVariables())
 
1073
        {
 
1074
            const VariableLocation &outputLocation   = outputPair.second;
 
1075
            const sh::ShaderVariable &outputVariable = shaderOutputVars[outputLocation.index];
 
1076
            const std::string &variableName = "out_" + outputLocation.name;
 
1077
            const std::string &elementString =
 
1078
                (outputLocation.element == GL_INVALID_INDEX ? "" : Str(outputLocation.element));
 
1079
 
 
1080
            ASSERT(outputVariable.staticUse);
 
1081
 
 
1082
            PixelShaderOutputVariable outputKeyVariable;
 
1083
            outputKeyVariable.type        = outputVariable.type;
 
1084
            outputKeyVariable.name        = variableName + elementString;
 
1085
            outputKeyVariable.source      = variableName + ArrayString(outputLocation.element);
 
1086
            outputKeyVariable.outputIndex = outputPair.first;
 
1087
 
 
1088
            outPixelShaderKey->push_back(outputKeyVariable);
 
1089
        }
 
1090
    }
 
1091
}
 
1092
 
 
1093
}  // namespace rx