• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/InfoSink.h"
8 #include "compiler/ParseContext.h"
9 #include "compiler/depgraph/DependencyGraphOutput.h"
10 #include "compiler/timing/RestrictFragmentShaderTiming.h"
11 
RestrictFragmentShaderTiming(TInfoSinkBase & sink)12 RestrictFragmentShaderTiming::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 }
35 
36 // FIXME(mvujovic): We do not know if the execution time of built-in operations like sin, pow, etc.
37 // can vary based on the value of the input arguments. If so, we should restrict those as well.
enforceRestrictions(const TDependencyGraph & graph)38 void RestrictFragmentShaderTiming::enforceRestrictions(const TDependencyGraph& graph)
39 {
40     mNumErrors = 0;
41 
42     // FIXME(mvujovic): The dependency graph does not support user defined function calls right now,
43     // so we generate errors for them.
44     validateUserDefinedFunctionCallUsage(graph);
45 
46     // Starting from each sampler, traverse the dependency graph and generate an error each time we
47     // hit a node where sampler dependent values are not allowed.
48     for (TGraphSymbolVector::const_iterator iter = graph.beginSamplerSymbols();
49          iter != graph.endSamplerSymbols();
50          ++iter)
51     {
52         TGraphSymbol* samplerSymbol = *iter;
53         clearVisited();
54         samplerSymbol->traverse(this);
55     }
56 }
57 
validateUserDefinedFunctionCallUsage(const TDependencyGraph & graph)58 void RestrictFragmentShaderTiming::validateUserDefinedFunctionCallUsage(const TDependencyGraph& graph)
59 {
60     for (TFunctionCallVector::const_iterator iter = graph.beginUserDefinedFunctionCalls();
61          iter != graph.endUserDefinedFunctionCalls();
62          ++iter)
63     {
64         TGraphFunctionCall* functionCall = *iter;
65         beginError(functionCall->getIntermFunctionCall());
66         mSink << "A call to a user defined function is not permitted.\n";
67     }
68 }
69 
beginError(const TIntermNode * node)70 void RestrictFragmentShaderTiming::beginError(const TIntermNode* node)
71 {
72     ++mNumErrors;
73     mSink.prefix(EPrefixError);
74     mSink.location(node->getLine());
75 }
76 
isSamplingOp(const TIntermAggregate * intermFunctionCall) const77 bool RestrictFragmentShaderTiming::isSamplingOp(const TIntermAggregate* intermFunctionCall) const
78 {
79     return !intermFunctionCall->isUserDefined() &&
80            mSamplingOps.find(intermFunctionCall->getName()) != mSamplingOps.end();
81 }
82 
visitArgument(TGraphArgument * parameter)83 void RestrictFragmentShaderTiming::visitArgument(TGraphArgument* parameter)
84 {
85     // Texture cache access time might leak sensitive information.
86     // Thus, we restrict sampler dependent values from affecting the coordinate or LOD bias of a
87     // sampling operation.
88     if (isSamplingOp(parameter->getIntermFunctionCall())) {
89         switch (parameter->getArgumentNumber()) {
90             case 1:
91                 // Second argument (coord)
92                 beginError(parameter->getIntermFunctionCall());
93                 mSink << "An expression dependent on a sampler is not permitted to be the"
94                       << " coordinate argument of a sampling operation.\n";
95                 break;
96             case 2:
97                 // Third argument (bias)
98                 beginError(parameter->getIntermFunctionCall());
99                 mSink << "An expression dependent on a sampler is not permitted to be the"
100                       << " bias argument of a sampling operation.\n";
101                 break;
102             default:
103                 // First argument (sampler)
104                 break;
105         }
106     }
107 }
108 
visitSelection(TGraphSelection * selection)109 void RestrictFragmentShaderTiming::visitSelection(TGraphSelection* selection)
110 {
111     beginError(selection->getIntermSelection());
112     mSink << "An expression dependent on a sampler is not permitted in a conditional statement.\n";
113 }
114 
visitLoop(TGraphLoop * loop)115 void RestrictFragmentShaderTiming::visitLoop(TGraphLoop* loop)
116 {
117     beginError(loop->getIntermLoop());
118     mSink << "An expression dependent on a sampler is not permitted in a loop condition.\n";
119 }
120 
visitLogicalOp(TGraphLogicalOp * logicalOp)121 void RestrictFragmentShaderTiming::visitLogicalOp(TGraphLogicalOp* logicalOp)
122 {
123     beginError(logicalOp->getIntermLogicalOp());
124     mSink << "An expression dependent on a sampler is not permitted on the left hand side of a logical "
125           << logicalOp->getOpString()
126           << " operator.\n";
127 }
128