1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/angle/src/compiler/timing/RestrictFragmentShaderTiming.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,127 @@ 1.4 +// 1.5 +// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. 1.6 +// Use of this source code is governed by a BSD-style license that can be 1.7 +// found in the LICENSE file. 1.8 +// 1.9 + 1.10 +#include "compiler/InfoSink.h" 1.11 +#include "compiler/ParseHelper.h" 1.12 +#include "compiler/depgraph/DependencyGraphOutput.h" 1.13 +#include "compiler/timing/RestrictFragmentShaderTiming.h" 1.14 + 1.15 +RestrictFragmentShaderTiming::RestrictFragmentShaderTiming(TInfoSinkBase& sink) 1.16 + : mSink(sink) 1.17 + , mNumErrors(0) 1.18 +{ 1.19 + // Sampling ops found only in fragment shaders. 1.20 + mSamplingOps.insert("texture2D(s21;vf2;f1;"); 1.21 + mSamplingOps.insert("texture2DProj(s21;vf3;f1;"); 1.22 + mSamplingOps.insert("texture2DProj(s21;vf4;f1;"); 1.23 + mSamplingOps.insert("textureCube(sC1;vf3;f1;"); 1.24 + // Sampling ops found in both vertex and fragment shaders. 1.25 + mSamplingOps.insert("texture2D(s21;vf2;"); 1.26 + mSamplingOps.insert("texture2DProj(s21;vf3;"); 1.27 + mSamplingOps.insert("texture2DProj(s21;vf4;"); 1.28 + mSamplingOps.insert("textureCube(sC1;vf3;"); 1.29 + // Sampling ops provided by OES_EGL_image_external. 1.30 + mSamplingOps.insert("texture2D(1;vf2;"); 1.31 + mSamplingOps.insert("texture2DProj(1;vf3;"); 1.32 + mSamplingOps.insert("texture2DProj(1;vf4;"); 1.33 + // Sampling ops provided by ARB_texture_rectangle. 1.34 + mSamplingOps.insert("texture2DRect(1;vf2;"); 1.35 + mSamplingOps.insert("texture2DRectProj(1;vf3;"); 1.36 + mSamplingOps.insert("texture2DRectProj(1;vf4;"); 1.37 +} 1.38 + 1.39 +// FIXME(mvujovic): We do not know if the execution time of built-in operations like sin, pow, etc. 1.40 +// can vary based on the value of the input arguments. If so, we should restrict those as well. 1.41 +void RestrictFragmentShaderTiming::enforceRestrictions(const TDependencyGraph& graph) 1.42 +{ 1.43 + mNumErrors = 0; 1.44 + 1.45 + // FIXME(mvujovic): The dependency graph does not support user defined function calls right now, 1.46 + // so we generate errors for them. 1.47 + validateUserDefinedFunctionCallUsage(graph); 1.48 + 1.49 + // Starting from each sampler, traverse the dependency graph and generate an error each time we 1.50 + // hit a node where sampler dependent values are not allowed. 1.51 + for (TGraphSymbolVector::const_iterator iter = graph.beginSamplerSymbols(); 1.52 + iter != graph.endSamplerSymbols(); 1.53 + ++iter) 1.54 + { 1.55 + TGraphSymbol* samplerSymbol = *iter; 1.56 + clearVisited(); 1.57 + samplerSymbol->traverse(this); 1.58 + } 1.59 +} 1.60 + 1.61 +void RestrictFragmentShaderTiming::validateUserDefinedFunctionCallUsage(const TDependencyGraph& graph) 1.62 +{ 1.63 + for (TFunctionCallVector::const_iterator iter = graph.beginUserDefinedFunctionCalls(); 1.64 + iter != graph.endUserDefinedFunctionCalls(); 1.65 + ++iter) 1.66 + { 1.67 + TGraphFunctionCall* functionCall = *iter; 1.68 + beginError(functionCall->getIntermFunctionCall()); 1.69 + mSink << "A call to a user defined function is not permitted.\n"; 1.70 + } 1.71 +} 1.72 + 1.73 +void RestrictFragmentShaderTiming::beginError(const TIntermNode* node) 1.74 +{ 1.75 + ++mNumErrors; 1.76 + mSink.prefix(EPrefixError); 1.77 + mSink.location(node->getLine()); 1.78 +} 1.79 + 1.80 +bool RestrictFragmentShaderTiming::isSamplingOp(const TIntermAggregate* intermFunctionCall) const 1.81 +{ 1.82 + return !intermFunctionCall->isUserDefined() && 1.83 + mSamplingOps.find(intermFunctionCall->getName()) != mSamplingOps.end(); 1.84 +} 1.85 + 1.86 +void RestrictFragmentShaderTiming::visitArgument(TGraphArgument* parameter) 1.87 +{ 1.88 + // Texture cache access time might leak sensitive information. 1.89 + // Thus, we restrict sampler dependent values from affecting the coordinate or LOD bias of a 1.90 + // sampling operation. 1.91 + if (isSamplingOp(parameter->getIntermFunctionCall())) { 1.92 + switch (parameter->getArgumentNumber()) { 1.93 + case 1: 1.94 + // Second argument (coord) 1.95 + beginError(parameter->getIntermFunctionCall()); 1.96 + mSink << "An expression dependent on a sampler is not permitted to be the" 1.97 + << " coordinate argument of a sampling operation.\n"; 1.98 + break; 1.99 + case 2: 1.100 + // Third argument (bias) 1.101 + beginError(parameter->getIntermFunctionCall()); 1.102 + mSink << "An expression dependent on a sampler is not permitted to be the" 1.103 + << " bias argument of a sampling operation.\n"; 1.104 + break; 1.105 + default: 1.106 + // First argument (sampler) 1.107 + break; 1.108 + } 1.109 + } 1.110 +} 1.111 + 1.112 +void RestrictFragmentShaderTiming::visitSelection(TGraphSelection* selection) 1.113 +{ 1.114 + beginError(selection->getIntermSelection()); 1.115 + mSink << "An expression dependent on a sampler is not permitted in a conditional statement.\n"; 1.116 +} 1.117 + 1.118 +void RestrictFragmentShaderTiming::visitLoop(TGraphLoop* loop) 1.119 +{ 1.120 + beginError(loop->getIntermLoop()); 1.121 + mSink << "An expression dependent on a sampler is not permitted in a loop condition.\n"; 1.122 +} 1.123 + 1.124 +void RestrictFragmentShaderTiming::visitLogicalOp(TGraphLogicalOp* logicalOp) 1.125 +{ 1.126 + beginError(logicalOp->getIntermLogicalOp()); 1.127 + mSink << "An expression dependent on a sampler is not permitted on the left hand side of a logical " 1.128 + << logicalOp->getOpString() 1.129 + << " operator.\n"; 1.130 +}