Hash :
46485086
Author :
Date :
2014-04-15T13:12:50
Implement EXT_shader_texture_lod BUG=angle:551 Change-Id: I81d7574a15861f1b24ddf6147cf71adbf20e10f3 Reviewed-on: https://chromium-review.googlesource.com/194960 Tested-by: Nicolas Capens <nicolascapens@chromium.org> Reviewed-by: Shannon Woods <shannonwoods@chromium.org>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
//
// 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/translator/InfoSink.h"
#include "compiler/translator/ParseContext.h"
#include "compiler/translator/depgraph/DependencyGraphOutput.h"
#include "compiler/translator/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;");
// Sampling ops provided by EXT_shader_texture_lod.
mSamplingOps.insert("texture2DLodEXT(1;vf2;f1;");
mSamplingOps.insert("texture2DProjLodEXT(1;vf3;f1;");
mSamplingOps.insert("texture2DProjLodEXT(1;vf4;f1;");
mSamplingOps.insert("textureCubeLodEXT(1;vf4;f1;");
mSamplingOps.insert("texture2DGradEXT(1;vf2;vf2;vf2;");
mSamplingOps.insert("texture2DProjGradEXT(1;vf3;vf2;vf2;");
mSamplingOps.insert("texture2DProjGradEXT(1;vf4;vf2;vf2;");
mSamplingOps.insert("textureCubeGradEXT(1;vf3;vf3;vf3;");
}
// 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";
}