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 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 // 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. 47 void 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 67 void 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 79 void RestrictFragmentShaderTiming::beginError(const TIntermNode* node) 80 { 81 ++mNumErrors; 82 mSink.prefix(EPrefixError); 83 mSink.location(node->getLine()); 84 } 85 86 bool RestrictFragmentShaderTiming::isSamplingOp(const TIntermAggregate* intermFunctionCall) const 87 { 88 return !intermFunctionCall->isUserDefined() && 89 mSamplingOps.find(intermFunctionCall->getName()) != mSamplingOps.end(); 90 } 91 92 void 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 118 void 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 124 void 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 130 void 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