Home | History | Annotate | Download | only in timing
      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