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
766ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.com#include "compiler/InfoSink.h"
866ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.com#include "compiler/ParseHelper.h"
966ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.com#include "compiler/depgraph/DependencyGraphOutput.h"
1066ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.com#include "compiler/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;");
348b8f02dcd343c52f90f4e5d1937d3cc496812405maxvujovic@gmail.com}
358b8f02dcd343c52f90f4e5d1937d3cc496812405maxvujovic@gmail.com
3666ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.com// FIXME(mvujovic): We do not know if the execution time of built-in operations like sin, pow, etc.
3766ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.com// can vary based on the value of the input arguments. If so, we should restrict those as well.
3866ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.comvoid RestrictFragmentShaderTiming::enforceRestrictions(const TDependencyGraph& graph)
3966ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.com{
4066ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.com    mNumErrors = 0;
4166ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.com
4266ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.com    // FIXME(mvujovic): The dependency graph does not support user defined function calls right now,
4366ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.com    // so we generate errors for them.
4466ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.com    validateUserDefinedFunctionCallUsage(graph);
4566ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.com
4677222c9715408518c21a7f359b8f0f9af8c4bfddmaxvujovic@gmail.com    // Starting from each sampler, traverse the dependency graph and generate an error each time we
4777222c9715408518c21a7f359b8f0f9af8c4bfddmaxvujovic@gmail.com    // hit a node where sampler dependent values are not allowed.
4877222c9715408518c21a7f359b8f0f9af8c4bfddmaxvujovic@gmail.com    for (TGraphSymbolVector::const_iterator iter = graph.beginSamplerSymbols();
4977222c9715408518c21a7f359b8f0f9af8c4bfddmaxvujovic@gmail.com         iter != graph.endSamplerSymbols();
5077222c9715408518c21a7f359b8f0f9af8c4bfddmaxvujovic@gmail.com         ++iter)
5177222c9715408518c21a7f359b8f0f9af8c4bfddmaxvujovic@gmail.com    {
5277222c9715408518c21a7f359b8f0f9af8c4bfddmaxvujovic@gmail.com        TGraphSymbol* samplerSymbol = *iter;
5377222c9715408518c21a7f359b8f0f9af8c4bfddmaxvujovic@gmail.com        clearVisited();
5477222c9715408518c21a7f359b8f0f9af8c4bfddmaxvujovic@gmail.com        samplerSymbol->traverse(this);
5577222c9715408518c21a7f359b8f0f9af8c4bfddmaxvujovic@gmail.com    }
5666ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.com}
5766ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.com
5866ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.comvoid RestrictFragmentShaderTiming::validateUserDefinedFunctionCallUsage(const TDependencyGraph& graph)
5966ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.com{
6066ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.com    for (TFunctionCallVector::const_iterator iter = graph.beginUserDefinedFunctionCalls();
6166ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.com         iter != graph.endUserDefinedFunctionCalls();
6266ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.com         ++iter)
6366ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.com    {
6466ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.com        TGraphFunctionCall* functionCall = *iter;
6566ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.com        beginError(functionCall->getIntermFunctionCall());
6666ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.com        mSink << "A call to a user defined function is not permitted.\n";
6766ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.com    }
6866ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.com}
6966ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.com
7066ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.comvoid RestrictFragmentShaderTiming::beginError(const TIntermNode* node)
7166ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.com{
7266ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.com    ++mNumErrors;
7366ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.com    mSink.prefix(EPrefixError);
7466ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.com    mSink.location(node->getLine());
7566ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.com}
7666ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.com
778b8f02dcd343c52f90f4e5d1937d3cc496812405maxvujovic@gmail.combool RestrictFragmentShaderTiming::isSamplingOp(const TIntermAggregate* intermFunctionCall) const
7866ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.com{
798b8f02dcd343c52f90f4e5d1937d3cc496812405maxvujovic@gmail.com    return !intermFunctionCall->isUserDefined() &&
808b8f02dcd343c52f90f4e5d1937d3cc496812405maxvujovic@gmail.com           mSamplingOps.find(intermFunctionCall->getName()) != mSamplingOps.end();
818b8f02dcd343c52f90f4e5d1937d3cc496812405maxvujovic@gmail.com}
8266ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.com
838b8f02dcd343c52f90f4e5d1937d3cc496812405maxvujovic@gmail.comvoid RestrictFragmentShaderTiming::visitArgument(TGraphArgument* parameter)
848b8f02dcd343c52f90f4e5d1937d3cc496812405maxvujovic@gmail.com{
858b8f02dcd343c52f90f4e5d1937d3cc496812405maxvujovic@gmail.com    // Texture cache access time might leak sensitive information.
868b8f02dcd343c52f90f4e5d1937d3cc496812405maxvujovic@gmail.com    // Thus, we restrict sampler dependent values from affecting the coordinate or LOD bias of a
878b8f02dcd343c52f90f4e5d1937d3cc496812405maxvujovic@gmail.com    // sampling operation.
888b8f02dcd343c52f90f4e5d1937d3cc496812405maxvujovic@gmail.com    if (isSamplingOp(parameter->getIntermFunctionCall())) {
898b8f02dcd343c52f90f4e5d1937d3cc496812405maxvujovic@gmail.com        switch (parameter->getArgumentNumber()) {
908b8f02dcd343c52f90f4e5d1937d3cc496812405maxvujovic@gmail.com            case 1:
918b8f02dcd343c52f90f4e5d1937d3cc496812405maxvujovic@gmail.com                // Second argument (coord)
928b8f02dcd343c52f90f4e5d1937d3cc496812405maxvujovic@gmail.com                beginError(parameter->getIntermFunctionCall());
938b8f02dcd343c52f90f4e5d1937d3cc496812405maxvujovic@gmail.com                mSink << "An expression dependent on a sampler is not permitted to be the"
948b8f02dcd343c52f90f4e5d1937d3cc496812405maxvujovic@gmail.com                      << " coordinate argument of a sampling operation.\n";
958b8f02dcd343c52f90f4e5d1937d3cc496812405maxvujovic@gmail.com                break;
968b8f02dcd343c52f90f4e5d1937d3cc496812405maxvujovic@gmail.com            case 2:
978b8f02dcd343c52f90f4e5d1937d3cc496812405maxvujovic@gmail.com                // Third argument (bias)
988b8f02dcd343c52f90f4e5d1937d3cc496812405maxvujovic@gmail.com                beginError(parameter->getIntermFunctionCall());
998b8f02dcd343c52f90f4e5d1937d3cc496812405maxvujovic@gmail.com                mSink << "An expression dependent on a sampler is not permitted to be the"
1008b8f02dcd343c52f90f4e5d1937d3cc496812405maxvujovic@gmail.com                      << " bias argument of a sampling operation.\n";
1018b8f02dcd343c52f90f4e5d1937d3cc496812405maxvujovic@gmail.com                break;
1028b8f02dcd343c52f90f4e5d1937d3cc496812405maxvujovic@gmail.com            default:
1038b8f02dcd343c52f90f4e5d1937d3cc496812405maxvujovic@gmail.com                // First argument (sampler)
1048b8f02dcd343c52f90f4e5d1937d3cc496812405maxvujovic@gmail.com                break;
1058b8f02dcd343c52f90f4e5d1937d3cc496812405maxvujovic@gmail.com        }
1068b8f02dcd343c52f90f4e5d1937d3cc496812405maxvujovic@gmail.com    }
10766ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.com}
10866ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.com
10966ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.comvoid RestrictFragmentShaderTiming::visitSelection(TGraphSelection* selection)
11066ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.com{
11166ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.com    beginError(selection->getIntermSelection());
11277222c9715408518c21a7f359b8f0f9af8c4bfddmaxvujovic@gmail.com    mSink << "An expression dependent on a sampler is not permitted in a conditional statement.\n";
11366ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.com}
11466ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.com
11566ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.comvoid RestrictFragmentShaderTiming::visitLoop(TGraphLoop* loop)
11666ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.com{
11766ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.com    beginError(loop->getIntermLoop());
11877222c9715408518c21a7f359b8f0f9af8c4bfddmaxvujovic@gmail.com    mSink << "An expression dependent on a sampler is not permitted in a loop condition.\n";
11966ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.com}
12066ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.com
12166ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.comvoid RestrictFragmentShaderTiming::visitLogicalOp(TGraphLogicalOp* logicalOp)
12266ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.com{
12366ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.com    beginError(logicalOp->getIntermLogicalOp());
12477222c9715408518c21a7f359b8f0f9af8c4bfddmaxvujovic@gmail.com    mSink << "An expression dependent on a sampler is not permitted on the left hand side of a logical "
12577222c9715408518c21a7f359b8f0f9af8c4bfddmaxvujovic@gmail.com          << logicalOp->getOpString()
12666ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.com          << " operator.\n";
12766ebd0143ea40a9beb83eab5d86e24f52825b3famaxvujovic@gmail.com}
128