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 } 128