166ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.com//
266ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.com// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
366ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.com// Use of this source code is governed by a BSD-style license that can be
466ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.com// found in the LICENSE file.
566ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.com//
666ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.com
717732823f9c21bdba9cc51ffaceb545ce3857a8cGeoff Lang#include "compiler/translator/InfoSink.h"
86b9cb25980022d0c792d858bc6f6500c00a6c29dJamie Madill#include "compiler/translator/ParseContext.h"
917732823f9c21bdba9cc51ffaceb545ce3857a8cGeoff Lang#include "compiler/translator/depgraph/DependencyGraphOutput.h"
1017732823f9c21bdba9cc51ffaceb545ce3857a8cGeoff Lang#include "compiler/translator/timing/RestrictFragmentShaderTiming.h"
1166ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.com
128b8f02dcd343c52f90f4e5d1937d3cc496812405maxvujovic@gmail.comRestrictFragmentShaderTiming::RestrictFragmentShaderTiming(TInfoSinkBase& sink)
138b8f02dcd343c52f90f4e5d1937d3cc496812405maxvujovic@gmail.com    : mSink(sink)
148b8f02dcd343c52f90f4e5d1937d3cc496812405maxvujovic@gmail.com    , mNumErrors(0)
158b8f02dcd343c52f90f4e5d1937d3cc496812405maxvujovic@gmail.com{
168b8f02dcd343c52f90f4e5d1937d3cc496812405maxvujovic@gmail.com    // Sampling ops found only in fragment shaders.
178b8f02dcd343c52f90f4e5d1937d3cc496812405maxvujovic@gmail.com    mSamplingOps.insert("texture2D(s21;vf2;f1;");
188b8f02dcd343c52f90f4e5d1937d3cc496812405maxvujovic@gmail.com    mSamplingOps.insert("texture2DProj(s21;vf3;f1;");
198b8f02dcd343c52f90f4e5d1937d3cc496812405maxvujovic@gmail.com    mSamplingOps.insert("texture2DProj(s21;vf4;f1;");
208b8f02dcd343c52f90f4e5d1937d3cc496812405maxvujovic@gmail.com    mSamplingOps.insert("textureCube(sC1;vf3;f1;");
218b8f02dcd343c52f90f4e5d1937d3cc496812405maxvujovic@gmail.com    // Sampling ops found in both vertex and fragment shaders.
228b8f02dcd343c52f90f4e5d1937d3cc496812405maxvujovic@gmail.com    mSamplingOps.insert("texture2D(s21;vf2;");
238b8f02dcd343c52f90f4e5d1937d3cc496812405maxvujovic@gmail.com    mSamplingOps.insert("texture2DProj(s21;vf3;");
248b8f02dcd343c52f90f4e5d1937d3cc496812405maxvujovic@gmail.com    mSamplingOps.insert("texture2DProj(s21;vf4;");
258b8f02dcd343c52f90f4e5d1937d3cc496812405maxvujovic@gmail.com    mSamplingOps.insert("textureCube(sC1;vf3;");
268b8f02dcd343c52f90f4e5d1937d3cc496812405maxvujovic@gmail.com    // Sampling ops provided by OES_EGL_image_external.
278b8f02dcd343c52f90f4e5d1937d3cc496812405maxvujovic@gmail.com    mSamplingOps.insert("texture2D(1;vf2;");
288b8f02dcd343c52f90f4e5d1937d3cc496812405maxvujovic@gmail.com    mSamplingOps.insert("texture2DProj(1;vf3;");
298b8f02dcd343c52f90f4e5d1937d3cc496812405maxvujovic@gmail.com    mSamplingOps.insert("texture2DProj(1;vf4;");
308b8f02dcd343c52f90f4e5d1937d3cc496812405maxvujovic@gmail.com    // Sampling ops provided by ARB_texture_rectangle.
318b8f02dcd343c52f90f4e5d1937d3cc496812405maxvujovic@gmail.com    mSamplingOps.insert("texture2DRect(1;vf2;");
328b8f02dcd343c52f90f4e5d1937d3cc496812405maxvujovic@gmail.com    mSamplingOps.insert("texture2DRectProj(1;vf3;");
338b8f02dcd343c52f90f4e5d1937d3cc496812405maxvujovic@gmail.com    mSamplingOps.insert("texture2DRectProj(1;vf4;");
34464850868307005a1287d79f7a640f05372358bbNicolas Capens    // Sampling ops provided by EXT_shader_texture_lod.
35464850868307005a1287d79f7a640f05372358bbNicolas Capens    mSamplingOps.insert("texture2DLodEXT(1;vf2;f1;");
36464850868307005a1287d79f7a640f05372358bbNicolas Capens    mSamplingOps.insert("texture2DProjLodEXT(1;vf3;f1;");
37464850868307005a1287d79f7a640f05372358bbNicolas Capens    mSamplingOps.insert("texture2DProjLodEXT(1;vf4;f1;");
38464850868307005a1287d79f7a640f05372358bbNicolas Capens    mSamplingOps.insert("textureCubeLodEXT(1;vf4;f1;");
39464850868307005a1287d79f7a640f05372358bbNicolas Capens    mSamplingOps.insert("texture2DGradEXT(1;vf2;vf2;vf2;");
40464850868307005a1287d79f7a640f05372358bbNicolas Capens    mSamplingOps.insert("texture2DProjGradEXT(1;vf3;vf2;vf2;");
41464850868307005a1287d79f7a640f05372358bbNicolas Capens    mSamplingOps.insert("texture2DProjGradEXT(1;vf4;vf2;vf2;");
42464850868307005a1287d79f7a640f05372358bbNicolas Capens    mSamplingOps.insert("textureCubeGradEXT(1;vf3;vf3;vf3;");
438b8f02dcd343c52f90f4e5d1937d3cc496812405maxvujovic@gmail.com}
448b8f02dcd343c52f90f4e5d1937d3cc496812405maxvujovic@gmail.com
4566ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.com// FIXME(mvujovic): We do not know if the execution time of built-in operations like sin, pow, etc.
4666ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.com// can vary based on the value of the input arguments. If so, we should restrict those as well.
4766ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.comvoid RestrictFragmentShaderTiming::enforceRestrictions(const TDependencyGraph& graph)
4866ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.com{
4966ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.com    mNumErrors = 0;
5066ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.com
5166ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.com    // FIXME(mvujovic): The dependency graph does not support user defined function calls right now,
5266ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.com    // so we generate errors for them.
5366ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.com    validateUserDefinedFunctionCallUsage(graph);
5466ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.com
5577222c9715408518c21a7f359b8f0f9af8c4bfddmaxvujovic@gmail.com    // Starting from each sampler, traverse the dependency graph and generate an error each time we
5677222c9715408518c21a7f359b8f0f9af8c4bfddmaxvujovic@gmail.com    // hit a node where sampler dependent values are not allowed.
5777222c9715408518c21a7f359b8f0f9af8c4bfddmaxvujovic@gmail.com    for (TGraphSymbolVector::const_iterator iter = graph.beginSamplerSymbols();
5877222c9715408518c21a7f359b8f0f9af8c4bfddmaxvujovic@gmail.com         iter != graph.endSamplerSymbols();
5977222c9715408518c21a7f359b8f0f9af8c4bfddmaxvujovic@gmail.com         ++iter)
6077222c9715408518c21a7f359b8f0f9af8c4bfddmaxvujovic@gmail.com    {
6177222c9715408518c21a7f359b8f0f9af8c4bfddmaxvujovic@gmail.com        TGraphSymbol* samplerSymbol = *iter;
6277222c9715408518c21a7f359b8f0f9af8c4bfddmaxvujovic@gmail.com        clearVisited();
6377222c9715408518c21a7f359b8f0f9af8c4bfddmaxvujovic@gmail.com        samplerSymbol->traverse(this);
6477222c9715408518c21a7f359b8f0f9af8c4bfddmaxvujovic@gmail.com    }
6566ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.com}
6666ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.com
6766ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.comvoid RestrictFragmentShaderTiming::validateUserDefinedFunctionCallUsage(const TDependencyGraph& graph)
6866ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.com{
6966ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.com    for (TFunctionCallVector::const_iterator iter = graph.beginUserDefinedFunctionCalls();
7066ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.com         iter != graph.endUserDefinedFunctionCalls();
7166ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.com         ++iter)
7266ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.com    {
7366ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.com        TGraphFunctionCall* functionCall = *iter;
7466ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.com        beginError(functionCall->getIntermFunctionCall());
7566ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.com        mSink << "A call to a user defined function is not permitted.\n";
7666ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.com    }
7766ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.com}
7866ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.com
7966ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.comvoid RestrictFragmentShaderTiming::beginError(const TIntermNode* node)
8066ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.com{
8166ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.com    ++mNumErrors;
8266ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.com    mSink.prefix(EPrefixError);
8366ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.com    mSink.location(node->getLine());
8466ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.com}
8566ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.com
868b8f02dcd343c52f90f4e5d1937d3cc496812405maxvujovic@gmail.combool RestrictFragmentShaderTiming::isSamplingOp(const TIntermAggregate* intermFunctionCall) const
8766ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.com{
888b8f02dcd343c52f90f4e5d1937d3cc496812405maxvujovic@gmail.com    return !intermFunctionCall->isUserDefined() &&
898b8f02dcd343c52f90f4e5d1937d3cc496812405maxvujovic@gmail.com           mSamplingOps.find(intermFunctionCall->getName()) != mSamplingOps.end();
908b8f02dcd343c52f90f4e5d1937d3cc496812405maxvujovic@gmail.com}
9166ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.com
928b8f02dcd343c52f90f4e5d1937d3cc496812405maxvujovic@gmail.comvoid RestrictFragmentShaderTiming::visitArgument(TGraphArgument* parameter)
938b8f02dcd343c52f90f4e5d1937d3cc496812405maxvujovic@gmail.com{
948b8f02dcd343c52f90f4e5d1937d3cc496812405maxvujovic@gmail.com    // Texture cache access time might leak sensitive information.
958b8f02dcd343c52f90f4e5d1937d3cc496812405maxvujovic@gmail.com    // Thus, we restrict sampler dependent values from affecting the coordinate or LOD bias of a
968b8f02dcd343c52f90f4e5d1937d3cc496812405maxvujovic@gmail.com    // sampling operation.
978b8f02dcd343c52f90f4e5d1937d3cc496812405maxvujovic@gmail.com    if (isSamplingOp(parameter->getIntermFunctionCall())) {
988b8f02dcd343c52f90f4e5d1937d3cc496812405maxvujovic@gmail.com        switch (parameter->getArgumentNumber()) {
998b8f02dcd343c52f90f4e5d1937d3cc496812405maxvujovic@gmail.com            case 1:
1008b8f02dcd343c52f90f4e5d1937d3cc496812405maxvujovic@gmail.com                // Second argument (coord)
1018b8f02dcd343c52f90f4e5d1937d3cc496812405maxvujovic@gmail.com                beginError(parameter->getIntermFunctionCall());
1028b8f02dcd343c52f90f4e5d1937d3cc496812405maxvujovic@gmail.com                mSink << "An expression dependent on a sampler is not permitted to be the"
1038b8f02dcd343c52f90f4e5d1937d3cc496812405maxvujovic@gmail.com                      << " coordinate argument of a sampling operation.\n";
1048b8f02dcd343c52f90f4e5d1937d3cc496812405maxvujovic@gmail.com                break;
1058b8f02dcd343c52f90f4e5d1937d3cc496812405maxvujovic@gmail.com            case 2:
1068b8f02dcd343c52f90f4e5d1937d3cc496812405maxvujovic@gmail.com                // Third argument (bias)
1078b8f02dcd343c52f90f4e5d1937d3cc496812405maxvujovic@gmail.com                beginError(parameter->getIntermFunctionCall());
1088b8f02dcd343c52f90f4e5d1937d3cc496812405maxvujovic@gmail.com                mSink << "An expression dependent on a sampler is not permitted to be the"
1098b8f02dcd343c52f90f4e5d1937d3cc496812405maxvujovic@gmail.com                      << " bias argument of a sampling operation.\n";
1108b8f02dcd343c52f90f4e5d1937d3cc496812405maxvujovic@gmail.com                break;
1118b8f02dcd343c52f90f4e5d1937d3cc496812405maxvujovic@gmail.com            default:
1128b8f02dcd343c52f90f4e5d1937d3cc496812405maxvujovic@gmail.com                // First argument (sampler)
1138b8f02dcd343c52f90f4e5d1937d3cc496812405maxvujovic@gmail.com                break;
1148b8f02dcd343c52f90f4e5d1937d3cc496812405maxvujovic@gmail.com        }
1158b8f02dcd343c52f90f4e5d1937d3cc496812405maxvujovic@gmail.com    }
11666ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.com}
11766ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.com
11866ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.comvoid RestrictFragmentShaderTiming::visitSelection(TGraphSelection* selection)
11966ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.com{
12066ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.com    beginError(selection->getIntermSelection());
12177222c9715408518c21a7f359b8f0f9af8c4bfddmaxvujovic@gmail.com    mSink << "An expression dependent on a sampler is not permitted in a conditional statement.\n";
12266ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.com}
12366ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.com
12466ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.comvoid RestrictFragmentShaderTiming::visitLoop(TGraphLoop* loop)
12566ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.com{
12666ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.com    beginError(loop->getIntermLoop());
12777222c9715408518c21a7f359b8f0f9af8c4bfddmaxvujovic@gmail.com    mSink << "An expression dependent on a sampler is not permitted in a loop condition.\n";
12866ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.com}
12966ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.com
13066ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.comvoid RestrictFragmentShaderTiming::visitLogicalOp(TGraphLogicalOp* logicalOp)
13166ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.com{
13266ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.com    beginError(logicalOp->getIntermLogicalOp());
13377222c9715408518c21a7f359b8f0f9af8c4bfddmaxvujovic@gmail.com    mSink << "An expression dependent on a sampler is not permitted on the left hand side of a logical "
13477222c9715408518c21a7f359b8f0f9af8c4bfddmaxvujovic@gmail.com          << logicalOp->getOpString()
13566ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.com          << " operator.\n";
13666ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.com}
137