blob: 27ab81469be14d6dcbd97a5c9d755517e770493e [file] [log] [blame]
Jamie Madill05a80ce2013-06-20 11:55:49 -04001//
2// Copyright (c) 2013 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
Geoff Lang17732822013-08-29 13:46:49 -04007#include "compiler/translator/ValidateOutputs.h"
8#include "compiler/translator/InfoSink.h"
Jamie Madill6b9cb252013-10-17 10:45:47 -04009#include "compiler/translator/ParseContext.h"
Jamie Madill05a80ce2013-06-20 11:55:49 -040010
Jamie Madill45bcc782016-11-07 13:58:48 -050011namespace sh
12{
13
Kimmo Kinnunenb18609b2015-07-16 14:13:11 +030014namespace
15{
Olli Etuaho77ba4082016-12-16 12:01:18 +000016void error(const TIntermSymbol &symbol, const char *reason, TDiagnostics *diagnostics)
Kimmo Kinnunenb18609b2015-07-16 14:13:11 +030017{
Olli Etuaho77ba4082016-12-16 12:01:18 +000018 diagnostics->error(symbol.getLine(), reason, symbol.getSymbol().c_str());
Kimmo Kinnunenb18609b2015-07-16 14:13:11 +030019}
20
21} // namespace
22
23ValidateOutputs::ValidateOutputs(const TExtensionBehavior &extBehavior, int maxDrawBuffers)
Olli Etuaho3d0d9a42015-06-01 12:16:36 +030024 : TIntermTraverser(true, false, false),
Jamie Madill05a80ce2013-06-20 11:55:49 -040025 mMaxDrawBuffers(maxDrawBuffers),
Kimmo Kinnunenb18609b2015-07-16 14:13:11 +030026 mAllowUnspecifiedOutputLocationResolution(
Andrei Volykhina5527072017-03-22 16:46:30 +030027 IsExtensionEnabled(extBehavior, "GL_EXT_blend_func_extended")),
28 mUsesFragDepth(false)
Jamie Madill05a80ce2013-06-20 11:55:49 -040029{
30}
31
32void ValidateOutputs::visitSymbol(TIntermSymbol *symbol)
33{
Jamie Madilld7b1ab52016-12-12 14:42:19 -050034 TString name = symbol->getSymbol();
Jamie Madill05a80ce2013-06-20 11:55:49 -040035 TQualifier qualifier = symbol->getQualifier();
36
Jamie Madill5ed23982016-04-22 15:08:57 -040037 if (mVisitedSymbols.count(name.c_str()) == 1)
Jamie Madill05a80ce2013-06-20 11:55:49 -040038 return;
39
Jamie Madill5ed23982016-04-22 15:08:57 -040040 mVisitedSymbols.insert(name.c_str());
Jamie Madill05a80ce2013-06-20 11:55:49 -040041
Jamie Madill19571812013-08-12 15:26:34 -070042 if (qualifier == EvqFragmentOut)
Jamie Madill05a80ce2013-06-20 11:55:49 -040043 {
Andrei Volykhina5527072017-03-22 16:46:30 +030044 if (symbol->getType().getLayoutQualifier().location != -1)
Jamie Madill05a80ce2013-06-20 11:55:49 -040045 {
Kimmo Kinnunenb18609b2015-07-16 14:13:11 +030046 mOutputs.push_back(symbol);
Jamie Madill05a80ce2013-06-20 11:55:49 -040047 }
Andrei Volykhina5527072017-03-22 16:46:30 +030048 else if (symbol->getType().getLayoutQualifier().yuv == true)
49 {
50 mYuvOutputs.push_back(symbol);
51 }
52 else
53 {
54 mUnspecifiedLocationOutputs.push_back(symbol);
55 }
56 }
57 else if (qualifier == EvqFragDepth || qualifier == EvqFragDepthEXT)
58 {
59 mUsesFragDepth = true;
Jamie Madill05a80ce2013-06-20 11:55:49 -040060 }
61}
62
Olli Etuaho77ba4082016-12-16 12:01:18 +000063void ValidateOutputs::validate(TDiagnostics *diagnostics) const
Jamie Madill05a80ce2013-06-20 11:55:49 -040064{
Olli Etuaho77ba4082016-12-16 12:01:18 +000065 ASSERT(diagnostics);
Kimmo Kinnunenb18609b2015-07-16 14:13:11 +030066 OutputVector validOutputs(mMaxDrawBuffers);
Kimmo Kinnunenb18609b2015-07-16 14:13:11 +030067
68 for (const auto &symbol : mOutputs)
69 {
70 const TType &type = symbol->getType();
Olli Etuaho856c4972016-08-08 11:38:39 +030071 const size_t elementCount = static_cast<size_t>(type.isArray() ? type.getArraySize() : 1u);
Kimmo Kinnunenb18609b2015-07-16 14:13:11 +030072 const size_t location = static_cast<size_t>(type.getLayoutQualifier().location);
73
74 ASSERT(type.getLayoutQualifier().location != -1);
75
76 if (location + elementCount <= validOutputs.size())
77 {
78 for (size_t elementIndex = 0; elementIndex < elementCount; elementIndex++)
79 {
80 const size_t offsetLocation = location + elementIndex;
81 if (validOutputs[offsetLocation])
82 {
83 std::stringstream strstr;
84 strstr << "conflicting output locations with previously defined output '"
85 << validOutputs[offsetLocation]->getSymbol() << "'";
Olli Etuaho77ba4082016-12-16 12:01:18 +000086 error(*symbol, strstr.str().c_str(), diagnostics);
Kimmo Kinnunenb18609b2015-07-16 14:13:11 +030087 }
88 else
89 {
90 validOutputs[offsetLocation] = symbol;
91 }
92 }
93 }
94 else
95 {
96 if (elementCount > 0)
97 {
Olli Etuaho77ba4082016-12-16 12:01:18 +000098 error(*symbol,
Kimmo Kinnunenb18609b2015-07-16 14:13:11 +030099 elementCount > 1 ? "output array locations would exceed MAX_DRAW_BUFFERS"
Olli Etuaho77ba4082016-12-16 12:01:18 +0000100 : "output location must be < MAX_DRAW_BUFFERS",
101 diagnostics);
Kimmo Kinnunenb18609b2015-07-16 14:13:11 +0300102 }
103 }
104 }
105
106 if (!mAllowUnspecifiedOutputLocationResolution &&
107 ((!mOutputs.empty() && !mUnspecifiedLocationOutputs.empty()) ||
108 mUnspecifiedLocationOutputs.size() > 1))
109 {
110 for (const auto &symbol : mUnspecifiedLocationOutputs)
111 {
Olli Etuaho77ba4082016-12-16 12:01:18 +0000112 error(*symbol,
113 "must explicitly specify all locations when using multiple fragment outputs",
114 diagnostics);
Kimmo Kinnunenb18609b2015-07-16 14:13:11 +0300115 }
116 }
Andrei Volykhina5527072017-03-22 16:46:30 +0300117
118 if (!mYuvOutputs.empty() && (mYuvOutputs.size() > 1 || mUsesFragDepth || !mOutputs.empty() ||
119 !mUnspecifiedLocationOutputs.empty()))
120 {
121 for (const auto &symbol : mYuvOutputs)
122 {
123 error(*symbol,
124 "not allowed to specify yuv qualifier when using depth or multiple color "
125 "fragment outputs",
126 diagnostics);
127 }
128 }
Jamie Madill05a80ce2013-06-20 11:55:49 -0400129}
Jamie Madill45bcc782016-11-07 13:58:48 -0500130
131} // namespace sh