1//
2// Copyright (c) 2012 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
7#include "compiler/translator/InfoSink.h"
8#include "compiler/translator/ParseContext.h"
9#include "compiler/translator/depgraph/DependencyGraphOutput.h"
10#include "compiler/translator/timing/RestrictFragmentShaderTiming.h"
11
12RestrictFragmentShaderTiming::RestrictFragmentShaderTiming(TInfoSinkBase& sink)
13    : mSink(sink)
14    , mNumErrors(0)
15{
16    // Sampling ops found only in fragment shaders.
17    mSamplingOps.insert("texture2D(s21;vf2;f1;");
18    mSamplingOps.insert("texture2DProj(s21;vf3;f1;");
19    mSamplingOps.insert("texture2DProj(s21;vf4;f1;");
20    mSamplingOps.insert("textureCube(sC1;vf3;f1;");
21    // Sampling ops found in both vertex and fragment shaders.
22    mSamplingOps.insert("texture2D(s21;vf2;");
23    mSamplingOps.insert("texture2DProj(s21;vf3;");
24    mSamplingOps.insert("texture2DProj(s21;vf4;");
25    mSamplingOps.insert("textureCube(sC1;vf3;");
26    // Sampling ops provided by OES_EGL_image_external.
27    mSamplingOps.insert("texture2D(1;vf2;");
28    mSamplingOps.insert("texture2DProj(1;vf3;");
29    mSamplingOps.insert("texture2DProj(1;vf4;");
30    // Sampling ops provided by ARB_texture_rectangle.
31    mSamplingOps.insert("texture2DRect(1;vf2;");
32    mSamplingOps.insert("texture2DRectProj(1;vf3;");
33    mSamplingOps.insert("texture2DRectProj(1;vf4;");
34    // Sampling ops provided by EXT_shader_texture_lod.
35    mSamplingOps.insert("texture2DLodEXT(1;vf2;f1;");
36    mSamplingOps.insert("texture2DProjLodEXT(1;vf3;f1;");
37    mSamplingOps.insert("texture2DProjLodEXT(1;vf4;f1;");
38    mSamplingOps.insert("textureCubeLodEXT(1;vf4;f1;");
39    mSamplingOps.insert("texture2DGradEXT(1;vf2;vf2;vf2;");
40    mSamplingOps.insert("texture2DProjGradEXT(1;vf3;vf2;vf2;");
41    mSamplingOps.insert("texture2DProjGradEXT(1;vf4;vf2;vf2;");
42    mSamplingOps.insert("textureCubeGradEXT(1;vf3;vf3;vf3;");
43}
44
45// FIXME(mvujovic): We do not know if the execution time of built-in operations like sin, pow, etc.
46// can vary based on the value of the input arguments. If so, we should restrict those as well.
47void RestrictFragmentShaderTiming::enforceRestrictions(const TDependencyGraph& graph)
48{
49    mNumErrors = 0;
50
51    // FIXME(mvujovic): The dependency graph does not support user defined function calls right now,
52    // so we generate errors for them.
53    validateUserDefinedFunctionCallUsage(graph);
54
55    // Starting from each sampler, traverse the dependency graph and generate an error each time we
56    // hit a node where sampler dependent values are not allowed.
57    for (TGraphSymbolVector::const_iterator iter = graph.beginSamplerSymbols();
58         iter != graph.endSamplerSymbols();
59         ++iter)
60    {
61        TGraphSymbol* samplerSymbol = *iter;
62        clearVisited();
63        samplerSymbol->traverse(this);
64    }
65}
66
67void RestrictFragmentShaderTiming::validateUserDefinedFunctionCallUsage(const TDependencyGraph& graph)
68{
69    for (TFunctionCallVector::const_iterator iter = graph.beginUserDefinedFunctionCalls();
70         iter != graph.endUserDefinedFunctionCalls();
71         ++iter)
72    {
73        TGraphFunctionCall* functionCall = *iter;
74        beginError(functionCall->getIntermFunctionCall());
75        mSink << "A call to a user defined function is not permitted.\n";
76    }
77}
78
79void RestrictFragmentShaderTiming::beginError(const TIntermNode* node)
80{
81    ++mNumErrors;
82    mSink.prefix(EPrefixError);
83    mSink.location(node->getLine());
84}
85
86bool RestrictFragmentShaderTiming::isSamplingOp(const TIntermAggregate* intermFunctionCall) const
87{
88    return !intermFunctionCall->isUserDefined() &&
89           mSamplingOps.find(intermFunctionCall->getName()) != mSamplingOps.end();
90}
91
92void RestrictFragmentShaderTiming::visitArgument(TGraphArgument* parameter)
93{
94    // Texture cache access time might leak sensitive information.
95    // Thus, we restrict sampler dependent values from affecting the coordinate or LOD bias of a
96    // sampling operation.
97    if (isSamplingOp(parameter->getIntermFunctionCall())) {
98        switch (parameter->getArgumentNumber()) {
99            case 1:
100                // Second argument (coord)
101                beginError(parameter->getIntermFunctionCall());
102                mSink << "An expression dependent on a sampler is not permitted to be the"
103                      << " coordinate argument of a sampling operation.\n";
104                break;
105            case 2:
106                // Third argument (bias)
107                beginError(parameter->getIntermFunctionCall());
108                mSink << "An expression dependent on a sampler is not permitted to be the"
109                      << " bias argument of a sampling operation.\n";
110                break;
111            default:
112                // First argument (sampler)
113                break;
114        }
115    }
116}
117
118void RestrictFragmentShaderTiming::visitSelection(TGraphSelection* selection)
119{
120    beginError(selection->getIntermSelection());
121    mSink << "An expression dependent on a sampler is not permitted in a conditional statement.\n";
122}
123
124void RestrictFragmentShaderTiming::visitLoop(TGraphLoop* loop)
125{
126    beginError(loop->getIntermLoop());
127    mSink << "An expression dependent on a sampler is not permitted in a loop condition.\n";
128}
129
130void RestrictFragmentShaderTiming::visitLogicalOp(TGraphLogicalOp* logicalOp)
131{
132    beginError(logicalOp->getIntermLogicalOp());
133    mSink << "An expression dependent on a sampler is not permitted on the left hand side of a logical "
134          << logicalOp->getOpString()
135          << " operator.\n";
136}
137