|
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/ParseHelper.h" |
|
9 #include "compiler/depgraph/DependencyGraphOutput.h" |
|
10 #include "compiler/timing/RestrictFragmentShaderTiming.h" |
|
11 |
|
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. |
|
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 |
|
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 |
|
70 void RestrictFragmentShaderTiming::beginError(const TIntermNode* node) |
|
71 { |
|
72 ++mNumErrors; |
|
73 mSink.prefix(EPrefixError); |
|
74 mSink.location(node->getLine()); |
|
75 } |
|
76 |
|
77 bool RestrictFragmentShaderTiming::isSamplingOp(const TIntermAggregate* intermFunctionCall) const |
|
78 { |
|
79 return !intermFunctionCall->isUserDefined() && |
|
80 mSamplingOps.find(intermFunctionCall->getName()) != mSamplingOps.end(); |
|
81 } |
|
82 |
|
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 |
|
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 |
|
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 |
|
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 } |