1 //
2 // Copyright (C) 2002-2005  3Dlabs Inc. Ltd.
3 // All rights reserved.
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions
7 // are met:
8 //
9 //    Redistributions of source code must retain the above copyright
10 //    notice, this list of conditions and the following disclaimer.
11 //
12 //    Redistributions in binary form must reproduce the above
13 //    copyright notice, this list of conditions and the following
14 //    disclaimer in the documentation and/or other materials provided
15 //    with the distribution.
16 //
17 //    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
18 //    contributors may be used to endorse or promote products derived
19 //    from this software without specific prior written permission.
20 //
21 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 // COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31 // ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 // POSSIBILITY OF SUCH DAMAGE.
33 //
34 
35 //
36 // Traverse a tree of constants to create a single folded constant.
37 // It should only be used when the whole tree is known to be constant.
38 //
39 
40 #include "ParseHelper.h"
41 
42 namespace glslang {
43 
44 class TConstTraverser : public TIntermTraverser {
45 public:
TConstTraverser(const TConstUnionArray & cUnion,bool singleConstParam,TOperator constructType,const TType & t)46     TConstTraverser(const TConstUnionArray& cUnion, bool singleConstParam, TOperator constructType, const TType& t)
47       : unionArray(cUnion), type(t),
48         constructorType(constructType), singleConstantParam(singleConstParam), error(false), isMatrix(false),
49         matrixCols(0), matrixRows(0) {  index = 0; tOp = EOpNull; }
50 
51     virtual void visitConstantUnion(TIntermConstantUnion* node);
52     virtual bool visitAggregate(TVisit, TIntermAggregate* node);
53 
54     int index;
55     TConstUnionArray unionArray;
56     TOperator tOp;
57     const TType& type;
58     TOperator constructorType;
59     bool singleConstantParam;
60     bool error;
61     int size; // size of the constructor ( 4 for vec4)
62     bool isMatrix;
63     int matrixCols;
64     int matrixRows;
65 
66 protected:
67     TConstTraverser(TConstTraverser&);
68     TConstTraverser& operator=(TConstTraverser&);
69 };
70 
visitAggregate(TVisit,TIntermAggregate * node)71 bool TConstTraverser::visitAggregate(TVisit /* visit */, TIntermAggregate* node)
72 {
73     if (! node->isConstructor() && node->getOp() != EOpComma) {
74         error = true;
75 
76         return false;
77     }
78 
79     bool flag = node->getSequence().size() == 1 && node->getSequence()[0]->getAsTyped()->getAsConstantUnion();
80     if (flag) {
81         singleConstantParam = true;
82         constructorType = node->getOp();
83         size = node->getType().computeNumComponents();
84 
85         if (node->getType().isMatrix()) {
86             isMatrix = true;
87             matrixCols = node->getType().getMatrixCols();
88             matrixRows = node->getType().getMatrixRows();
89         }
90     }
91 
92     for (TIntermSequence::iterator p = node->getSequence().begin();
93                                    p != node->getSequence().end(); p++) {
94 
95         if (node->getOp() == EOpComma)
96             index = 0;
97 
98         (*p)->traverse(this);
99     }
100     if (flag)
101     {
102         singleConstantParam = false;
103         constructorType = EOpNull;
104         size = 0;
105         isMatrix = false;
106         matrixCols = 0;
107         matrixRows = 0;
108     }
109 
110     return false;
111 }
112 
visitConstantUnion(TIntermConstantUnion * node)113 void TConstTraverser::visitConstantUnion(TIntermConstantUnion* node)
114 {
115     TConstUnionArray leftUnionArray(unionArray);
116     int instanceSize = type.computeNumComponents();
117 
118     if (index >= instanceSize)
119         return;
120 
121     if (! singleConstantParam) {
122         int rightUnionSize = node->getType().computeNumComponents();
123 
124         const TConstUnionArray& rightUnionArray = node->getConstArray();
125         for (int i = 0; i < rightUnionSize; i++) {
126             if (index >= instanceSize)
127                 return;
128             leftUnionArray[index] = rightUnionArray[i];
129 
130             index++;
131         }
132     } else {
133         int endIndex = index + size;
134         const TConstUnionArray& rightUnionArray = node->getConstArray();
135         if (! isMatrix) {
136             int count = 0;
137             int nodeComps = node->getType().computeNumComponents();
138             for (int i = index; i < endIndex; i++) {
139                 if (i >= instanceSize)
140                     return;
141 
142                 leftUnionArray[i] = rightUnionArray[count];
143 
144                 (index)++;
145 
146                 if (nodeComps > 1)
147                     count++;
148             }
149         } else {
150             // constructing a matrix, but from what?
151             if (node->isMatrix()) {
152                 // Matrix from a matrix; this has the outer matrix, node is the argument matrix.
153                 // Traverse the outer, potentially bigger matrix, fill in missing pieces with the
154                 // identity matrix.
155                 for (int c = 0; c < matrixCols; ++c) {
156                     for (int r = 0; r < matrixRows; ++r) {
157                         int targetOffset = index + c * matrixRows + r;
158                         if (r < node->getType().getMatrixRows() && c < node->getType().getMatrixCols()) {
159                             int srcOffset = c * node->getType().getMatrixRows() + r;
160                             leftUnionArray[targetOffset] = rightUnionArray[srcOffset];
161                         } else if (r == c)
162                             leftUnionArray[targetOffset].setDConst(1.0);
163                         else
164                             leftUnionArray[targetOffset].setDConst(0.0);
165                     }
166                 }
167             } else {
168                 // matrix from vector or scalar
169                 int count = 0;
170                 const int startIndex = index;
171                 int nodeComps = node->getType().computeNumComponents();
172                 for (int i = startIndex; i < endIndex; i++) {
173                     if (i >= instanceSize)
174                         return;
175                     if (nodeComps == 1) {
176                         // If there is a single scalar parameter to a matrix
177                         // constructor, it is used to initialize all the
178                         // components on the matrix's diagonal, with the
179                         // remaining components initialized to 0.0.
180                         if (i == startIndex || (i - startIndex) % (matrixRows + 1) == 0 )
181                             leftUnionArray[i] = rightUnionArray[count];
182                         else
183                             leftUnionArray[i].setDConst(0.0);
184                     } else {
185                         // construct the matrix in column-major order, from
186                         // the components provided, in order
187                         leftUnionArray[i] = rightUnionArray[count];
188                     }
189 
190                     index++;
191 
192                     if (nodeComps > 1)
193                         count++;
194                 }
195             }
196         }
197     }
198 }
199 
parseConstTree(TIntermNode * root,TConstUnionArray unionArray,TOperator constructorType,const TType & t,bool singleConstantParam)200 bool TIntermediate::parseConstTree(TIntermNode* root, TConstUnionArray unionArray, TOperator constructorType, const TType& t, bool singleConstantParam)
201 {
202     if (root == 0)
203         return false;
204 
205     TConstTraverser it(unionArray, singleConstantParam, constructorType, t);
206 
207     root->traverse(&it);
208     if (it.error)
209         return true;
210     else
211         return false;
212 }
213 
214 } // end namespace glslang
215