| // | |
| // Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| // | |
| #include "compiler/InfoSink.h" | |
| #include "compiler/ParseHelper.h" | |
| #include "compiler/depgraph/DependencyGraphOutput.h" | |
| #include "compiler/timing/RestrictFragmentShaderTiming.h" | |
| RestrictFragmentShaderTiming::RestrictFragmentShaderTiming(TInfoSinkBase& sink) | |
| : mSink(sink) | |
| , mNumErrors(0) | |
| { | |
| // Sampling ops found only in fragment shaders. | |
| mSamplingOps.insert("texture2D(s21;vf2;f1;"); | |
| mSamplingOps.insert("texture2DProj(s21;vf3;f1;"); | |
| mSamplingOps.insert("texture2DProj(s21;vf4;f1;"); | |
| mSamplingOps.insert("textureCube(sC1;vf3;f1;"); | |
| // Sampling ops found in both vertex and fragment shaders. | |
| mSamplingOps.insert("texture2D(s21;vf2;"); | |
| mSamplingOps.insert("texture2DProj(s21;vf3;"); | |
| mSamplingOps.insert("texture2DProj(s21;vf4;"); | |
| mSamplingOps.insert("textureCube(sC1;vf3;"); | |
| // Sampling ops provided by OES_EGL_image_external. | |
| mSamplingOps.insert("texture2D(1;vf2;"); | |
| mSamplingOps.insert("texture2DProj(1;vf3;"); | |
| mSamplingOps.insert("texture2DProj(1;vf4;"); | |
| // Sampling ops provided by ARB_texture_rectangle. | |
| mSamplingOps.insert("texture2DRect(1;vf2;"); | |
| mSamplingOps.insert("texture2DRectProj(1;vf3;"); | |
| mSamplingOps.insert("texture2DRectProj(1;vf4;"); | |
| } | |
| // FIXME(mvujovic): We do not know if the execution time of built-in operations like sin, pow, etc. | |
| // can vary based on the value of the input arguments. If so, we should restrict those as well. | |
| void RestrictFragmentShaderTiming::enforceRestrictions(const TDependencyGraph& graph) | |
| { | |
| mNumErrors = 0; | |
| // FIXME(mvujovic): The dependency graph does not support user defined function calls right now, | |
| // so we generate errors for them. | |
| validateUserDefinedFunctionCallUsage(graph); | |
| // Starting from each sampler, traverse the dependency graph and generate an error each time we | |
| // hit a node where sampler dependent values are not allowed. | |
| for (TGraphSymbolVector::const_iterator iter = graph.beginSamplerSymbols(); | |
| iter != graph.endSamplerSymbols(); | |
| ++iter) | |
| { | |
| TGraphSymbol* samplerSymbol = *iter; | |
| clearVisited(); | |
| samplerSymbol->traverse(this); | |
| } | |
| } | |
| void RestrictFragmentShaderTiming::validateUserDefinedFunctionCallUsage(const TDependencyGraph& graph) | |
| { | |
| for (TFunctionCallVector::const_iterator iter = graph.beginUserDefinedFunctionCalls(); | |
| iter != graph.endUserDefinedFunctionCalls(); | |
| ++iter) | |
| { | |
| TGraphFunctionCall* functionCall = *iter; | |
| beginError(functionCall->getIntermFunctionCall()); | |
| mSink << "A call to a user defined function is not permitted.\n"; | |
| } | |
| } | |
| void RestrictFragmentShaderTiming::beginError(const TIntermNode* node) | |
| { | |
| ++mNumErrors; | |
| mSink.prefix(EPrefixError); | |
| mSink.location(node->getLine()); | |
| } | |
| bool RestrictFragmentShaderTiming::isSamplingOp(const TIntermAggregate* intermFunctionCall) const | |
| { | |
| return !intermFunctionCall->isUserDefined() && | |
| mSamplingOps.find(intermFunctionCall->getName()) != mSamplingOps.end(); | |
| } | |
| void RestrictFragmentShaderTiming::visitArgument(TGraphArgument* parameter) | |
| { | |
| // Texture cache access time might leak sensitive information. | |
| // Thus, we restrict sampler dependent values from affecting the coordinate or LOD bias of a | |
| // sampling operation. | |
| if (isSamplingOp(parameter->getIntermFunctionCall())) { | |
| switch (parameter->getArgumentNumber()) { | |
| case 1: | |
| // Second argument (coord) | |
| beginError(parameter->getIntermFunctionCall()); | |
| mSink << "An expression dependent on a sampler is not permitted to be the" | |
| << " coordinate argument of a sampling operation.\n"; | |
| break; | |
| case 2: | |
| // Third argument (bias) | |
| beginError(parameter->getIntermFunctionCall()); | |
| mSink << "An expression dependent on a sampler is not permitted to be the" | |
| << " bias argument of a sampling operation.\n"; | |
| break; | |
| default: | |
| // First argument (sampler) | |
| break; | |
| } | |
| } | |
| } | |
| void RestrictFragmentShaderTiming::visitSelection(TGraphSelection* selection) | |
| { | |
| beginError(selection->getIntermSelection()); | |
| mSink << "An expression dependent on a sampler is not permitted in a conditional statement.\n"; | |
| } | |
| void RestrictFragmentShaderTiming::visitLoop(TGraphLoop* loop) | |
| { | |
| beginError(loop->getIntermLoop()); | |
| mSink << "An expression dependent on a sampler is not permitted in a loop condition.\n"; | |
| } | |
| void RestrictFragmentShaderTiming::visitLogicalOp(TGraphLogicalOp* logicalOp) | |
| { | |
| beginError(logicalOp->getIntermLogicalOp()); | |
| mSink << "An expression dependent on a sampler is not permitted on the left hand side of a logical " | |
| << logicalOp->getOpString() | |
| << " operator.\n"; | |
| } |