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/InfoSink.h"
      8 #include "compiler/ParseContext.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