Jarkko Poyry | 3c82736 | 2014-09-02 11:48:52 +0300 | [diff] [blame] | 1 | /*------------------------------------------------------------------------- |
| 2 | * drawElements Quality Program Random Shader Generator |
| 3 | * ---------------------------------------------------- |
| 4 | * |
| 5 | * Copyright 2014 The Android Open Source Project |
| 6 | * |
| 7 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 8 | * you may not use this file except in compliance with the License. |
| 9 | * You may obtain a copy of the License at |
| 10 | * |
| 11 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 12 | * |
| 13 | * Unless required by applicable law or agreed to in writing, software |
| 14 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 16 | * See the License for the specific language governing permissions and |
| 17 | * limitations under the License. |
| 18 | * |
| 19 | *//*! |
| 20 | * \file |
| 21 | * \brief Shader generator. |
| 22 | *//*--------------------------------------------------------------------*/ |
| 23 | |
| 24 | #include "rsgShaderGenerator.hpp" |
| 25 | #include "rsgFunctionGenerator.hpp" |
| 26 | #include "rsgToken.hpp" |
| 27 | #include "rsgPrettyPrinter.hpp" |
| 28 | #include "rsgUtils.hpp" |
| 29 | #include "deString.h" |
| 30 | |
| 31 | #include <iterator> |
| 32 | |
| 33 | using std::string; |
| 34 | using std::vector; |
| 35 | |
| 36 | namespace rsg |
| 37 | { |
| 38 | |
| 39 | ShaderGenerator::ShaderGenerator (GeneratorState& state) |
| 40 | : m_state (state) |
| 41 | , m_varManager (state.getNameAllocator()) |
| 42 | { |
| 43 | state.setVariableManager(m_varManager); |
| 44 | } |
| 45 | |
| 46 | ShaderGenerator::~ShaderGenerator (void) |
| 47 | { |
| 48 | } |
| 49 | |
| 50 | namespace |
| 51 | { |
| 52 | |
| 53 | const char* getFragColorName (const GeneratorState& state) |
| 54 | { |
| 55 | switch (state.getProgramParameters().version) |
| 56 | { |
| 57 | case VERSION_100: return "gl_FragColor"; |
| 58 | case VERSION_300: return "dEQP_FragColor"; |
| 59 | default: |
| 60 | DE_ASSERT(DE_FALSE); |
| 61 | return DE_NULL; |
| 62 | } |
| 63 | } |
| 64 | |
| 65 | void createAssignment (BlockStatement& block, const Variable* dstVar, const Variable* srcVar) |
| 66 | { |
| 67 | VariableRead* varRead = new VariableRead(srcVar); |
| 68 | try |
| 69 | { |
| 70 | block.addChild(new AssignStatement( dstVar, varRead)); |
| 71 | } |
| 72 | catch (const std::exception&) |
| 73 | { |
| 74 | delete varRead; |
| 75 | throw; |
| 76 | } |
| 77 | } |
| 78 | |
| 79 | const ValueEntry* findByName (VariableManager& varManager, const char* name) |
| 80 | { |
| 81 | AnyEntry::Iterator iter = varManager.getBegin<AnyEntry>(); |
| 82 | AnyEntry::Iterator end = varManager.getEnd<AnyEntry>(); |
| 83 | for (; iter != end; iter++) |
| 84 | { |
| 85 | const ValueEntry* entry = *iter; |
| 86 | if (deStringEqual(entry->getVariable()->getName(), name)) |
| 87 | return entry; |
| 88 | } |
| 89 | return DE_NULL; |
| 90 | } |
| 91 | |
| 92 | void genVertexPassthrough (GeneratorState& state, Shader& shader) |
| 93 | { |
| 94 | // Create copies from shader inputs to outputs |
| 95 | vector<const ValueEntry*> entries; |
| 96 | std::copy(state.getVariableManager().getBegin<AnyEntry>(), state.getVariableManager().getEnd<AnyEntry>(), std::inserter(entries, entries.begin())); |
| 97 | |
| 98 | for (vector<const ValueEntry*>::const_iterator i = entries.begin(); i != entries.end(); i++) |
| 99 | { |
| 100 | const ValueEntry* entry = *i; |
| 101 | const Variable* outVar = entry->getVariable(); |
| 102 | std::string inVarName; |
| 103 | |
| 104 | if (outVar->getStorage() != Variable::STORAGE_SHADER_OUT) |
| 105 | continue; |
| 106 | |
| 107 | // Name: a_[name], remove v_ -prefix if such exists |
| 108 | inVarName = "a_"; |
| 109 | if (deStringBeginsWith(outVar->getName(), "v_")) |
| 110 | inVarName += (outVar->getName()+2); |
| 111 | else |
| 112 | inVarName += outVar->getName(); |
| 113 | |
| 114 | Variable* inVar = state.getVariableManager().allocate(outVar->getType(), Variable::STORAGE_SHADER_IN, inVarName.c_str()); |
| 115 | |
| 116 | // Update value range. This will be stored into shader input info. |
| 117 | state.getVariableManager().setValue(inVar, entry->getValueRange()); |
| 118 | |
| 119 | // Add assignment from input to output into main() body |
| 120 | createAssignment(shader.getMain().getBody(), entry->getVariable(), inVar); |
| 121 | } |
| 122 | } |
| 123 | |
| 124 | void genFragmentPassthrough (GeneratorState& state, Shader& shader) |
| 125 | { |
| 126 | // Add simple gl_FragColor = v_color; assignment |
| 127 | const ValueEntry* fragColorEntry = findByName(state.getVariableManager(), getFragColorName(state)); |
| 128 | TCU_CHECK(fragColorEntry); |
| 129 | |
| 130 | Variable* inColorVariable = state.getVariableManager().allocate(fragColorEntry->getVariable()->getType(), Variable::STORAGE_SHADER_IN, "v_color"); |
| 131 | |
| 132 | state.getVariableManager().setValue(inColorVariable, fragColorEntry->getValueRange()); |
| 133 | createAssignment(shader.getMain().getBody(), fragColorEntry->getVariable(), inColorVariable); |
| 134 | } |
| 135 | |
| 136 | // Sets undefined (-inf..inf) components to some meaningful values. Used for sanitizing final shader input value ranges. |
| 137 | void fillUndefinedComponents (ValueRangeAccess valueRange) |
| 138 | { |
| 139 | VariableType::Type baseType = valueRange.getType().getBaseType(); |
| 140 | TCU_CHECK(baseType == VariableType::TYPE_FLOAT || |
| 141 | baseType == VariableType::TYPE_INT || |
| 142 | baseType == VariableType::TYPE_BOOL); |
| 143 | |
| 144 | for (int elemNdx = 0; elemNdx < valueRange.getType().getNumElements(); elemNdx++) |
| 145 | { |
| 146 | if (isUndefinedValueRange(valueRange.component(elemNdx))) |
| 147 | { |
| 148 | ValueAccess min = valueRange.component(elemNdx).getMin(); |
| 149 | ValueAccess max = valueRange.component(elemNdx).getMax(); |
| 150 | |
| 151 | switch (baseType) |
| 152 | { |
| 153 | case VariableType::TYPE_FLOAT: min = 0.0f; max = 1.0f; break; |
| 154 | case VariableType::TYPE_INT: min = 0; max = 1; break; |
| 155 | case VariableType::TYPE_BOOL: min = false; max = true; break; |
| 156 | default: DE_ASSERT(DE_FALSE); |
| 157 | } |
| 158 | } |
| 159 | } |
| 160 | } |
| 161 | |
| 162 | void fillUndefinedShaderInputs (vector<ShaderInput*>& inputs) |
| 163 | { |
| 164 | for (vector<ShaderInput*>::iterator i = inputs.begin(); i != inputs.end(); i++) |
| 165 | { |
| 166 | if (!(*i)->getVariable()->getType().isSampler()) // Samplers are assigned at program-level. |
| 167 | fillUndefinedComponents((*i)->getValueRange()); |
| 168 | } |
| 169 | } |
| 170 | |
| 171 | } // anonymous |
| 172 | |
| 173 | void ShaderGenerator::generate (const ShaderParameters& shaderParams, Shader& shader, const vector<ShaderInput*>& outputs) |
| 174 | { |
| 175 | // Global scopes |
| 176 | VariableScope& globalVariableScope = shader.getGlobalScope(); |
| 177 | ValueScope globalValueScope; |
| 178 | |
| 179 | // Init state |
| 180 | m_state.setShader(shaderParams, shader); |
| 181 | DE_ASSERT(m_state.getExpressionFlags() == 0); |
| 182 | |
| 183 | // Reserve some scalars for gl_Position & dEQP_Position |
| 184 | ReservedScalars reservedScalars; |
| 185 | if (shader.getType() == Shader::TYPE_VERTEX) |
| 186 | m_state.getVariableManager().reserve(reservedScalars, 4*2); |
| 187 | |
| 188 | // Push global scopes |
| 189 | m_varManager.pushVariableScope(globalVariableScope); |
| 190 | m_varManager.pushValueScope(globalValueScope); |
| 191 | |
| 192 | // Init shader outputs. |
| 193 | { |
| 194 | for (vector<ShaderInput*>::const_iterator i = outputs.begin(); i != outputs.end(); i++) |
| 195 | { |
| 196 | const ShaderInput* input = *i; |
| 197 | Variable* variable = m_state.getVariableManager().allocate(input->getVariable()->getType(), Variable::STORAGE_SHADER_OUT, input->getVariable()->getName()); |
| 198 | |
| 199 | m_state.getVariableManager().setValue(variable, input->getValueRange()); |
| 200 | } |
| 201 | |
| 202 | if (shader.getType() == Shader::TYPE_FRAGMENT) |
| 203 | { |
| 204 | // gl_FragColor |
| 205 | // \todo [2011-11-22 pyry] Multiple outputs from fragment shader! |
| 206 | Variable* fragColorVar = m_state.getVariableManager().allocate(VariableType(VariableType::TYPE_FLOAT, 4), Variable::STORAGE_SHADER_OUT, getFragColorName(m_state)); |
| 207 | ValueRange valueRange(fragColorVar->getType()); |
| 208 | |
| 209 | valueRange.getMin() = tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f); |
| 210 | valueRange.getMax() = tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f); |
| 211 | |
| 212 | fragColorVar->setLayoutLocation(0); // Bind color output to location 0 (applies to GLSL ES 3.0 onwards). |
| 213 | |
Jarkko Pöyry | ba84b6d | 2015-05-19 17:44:29 -0700 | [diff] [blame] | 214 | m_state.getVariableManager().setValue(fragColorVar, valueRange.asAccess()); |
Jarkko Poyry | 3c82736 | 2014-09-02 11:48:52 +0300 | [diff] [blame] | 215 | } |
| 216 | } |
| 217 | |
| 218 | // Construct shader code. |
| 219 | { |
| 220 | Function& main = shader.getMain(); |
| 221 | main.setReturnType(VariableType(VariableType::TYPE_VOID)); |
| 222 | |
| 223 | if (shaderParams.randomize) |
| 224 | { |
| 225 | FunctionGenerator funcGen(m_state, main); |
| 226 | |
| 227 | // Mandate assignment into to all shader outputs in main() |
| 228 | const vector<Variable*>& liveVars = globalVariableScope.getLiveVariables(); |
| 229 | for (vector<Variable*>::const_iterator i = liveVars.begin(); i != liveVars.end(); i++) |
| 230 | { |
| 231 | Variable* variable = *i; |
| 232 | if (variable->getStorage() == Variable::STORAGE_SHADER_OUT) |
| 233 | funcGen.requireAssignment(variable); |
| 234 | } |
| 235 | |
| 236 | funcGen.generate(); |
| 237 | } |
| 238 | else |
| 239 | { |
| 240 | if (shader.getType() == Shader::TYPE_VERTEX) |
| 241 | genVertexPassthrough(m_state, shader); |
| 242 | else |
| 243 | { |
| 244 | DE_ASSERT(shader.getType() == Shader::TYPE_FRAGMENT); |
| 245 | genFragmentPassthrough(m_state, shader); |
| 246 | } |
| 247 | } |
| 248 | |
| 249 | if (shader.getType() == Shader::TYPE_VERTEX) |
| 250 | { |
| 251 | // Add gl_Position = dEQP_Position; |
| 252 | m_state.getVariableManager().release(reservedScalars); |
| 253 | |
| 254 | Variable* glPosVariable = m_state.getVariableManager().allocate(VariableType(VariableType::TYPE_FLOAT, 4), Variable::STORAGE_SHADER_OUT, "gl_Position"); |
| 255 | Variable* qpPosVariable = m_state.getVariableManager().allocate(VariableType(VariableType::TYPE_FLOAT, 4), Variable::STORAGE_SHADER_IN, "dEQP_Position"); |
| 256 | |
| 257 | ValueRange valueRange(glPosVariable->getType()); |
| 258 | |
| 259 | valueRange.getMin() = tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f); |
| 260 | valueRange.getMax() = tcu::Vec4( 1.0f, 1.0f, 0.0f, 1.0f); |
| 261 | |
Jarkko Pöyry | ba84b6d | 2015-05-19 17:44:29 -0700 | [diff] [blame] | 262 | m_state.getVariableManager().setValue(qpPosVariable, valueRange.asAccess()); // \todo [2011-05-24 pyry] No expression should be able to use gl_Position or dEQP_Position.. |
Jarkko Poyry | 3c82736 | 2014-09-02 11:48:52 +0300 | [diff] [blame] | 263 | |
| 264 | createAssignment(main.getBody(), glPosVariable, qpPosVariable); |
| 265 | } |
| 266 | } |
| 267 | |
| 268 | // Declare live global variables. |
| 269 | { |
| 270 | vector<Variable*> liveVariables; |
| 271 | std::copy(globalVariableScope.getLiveVariables().begin(), globalVariableScope.getLiveVariables().end(), std::inserter(liveVariables, liveVariables.begin())); |
| 272 | |
| 273 | vector<Variable*> createDeclarationStatementVars; |
| 274 | |
| 275 | for (vector<Variable*>::iterator i = liveVariables.begin(); i != liveVariables.end(); i++) |
| 276 | { |
| 277 | Variable* variable = *i; |
| 278 | const char* name = variable->getName(); |
| 279 | bool declare = !deStringBeginsWith(name, "gl_"); // Do not declare built-in types. |
| 280 | |
| 281 | // Create input entries (store value range) if necessary |
| 282 | vector<ShaderInput*>& inputs = shader.getInputs(); |
| 283 | vector<ShaderInput*>& uniforms = shader.getUniforms(); |
| 284 | |
| 285 | switch (variable->getStorage()) |
| 286 | { |
| 287 | case Variable::STORAGE_SHADER_IN: |
| 288 | { |
| 289 | const ValueEntry* value = m_state.getVariableManager().getValue(variable); |
| 290 | |
| 291 | inputs.reserve(inputs.size()+1); |
| 292 | inputs.push_back(new ShaderInput(variable, value->getValueRange())); |
| 293 | break; |
| 294 | } |
| 295 | |
| 296 | case Variable::STORAGE_UNIFORM: |
| 297 | { |
| 298 | const ValueEntry* value = m_state.getVariableManager().getValue(variable); |
| 299 | |
| 300 | uniforms.reserve(uniforms.size()+1); |
| 301 | uniforms.push_back(new ShaderInput(variable, value->getValueRange())); |
| 302 | break; |
| 303 | } |
| 304 | |
| 305 | default: |
| 306 | break; |
| 307 | } |
| 308 | |
| 309 | if (declare) |
| 310 | createDeclarationStatementVars.push_back(variable); |
| 311 | else |
| 312 | { |
| 313 | // Just move to global scope without declaration statement. |
| 314 | m_state.getVariableManager().declareVariable(variable); |
| 315 | } |
| 316 | } |
| 317 | |
| 318 | // All global initializers must be constant expressions, no variable allocation is allowed |
| 319 | DE_ASSERT(m_state.getExpressionFlags() == 0); |
| 320 | m_state.pushExpressionFlags(CONST_EXPR|NO_VAR_ALLOCATION); |
| 321 | |
| 322 | // Create declaration statements |
| 323 | for (vector<Variable*>::iterator i = createDeclarationStatementVars.begin(); i != createDeclarationStatementVars.end(); i++) |
| 324 | { |
| 325 | shader.getGlobalStatements().reserve(shader.getGlobalStatements().size()); |
| 326 | shader.getGlobalStatements().push_back(new DeclarationStatement(m_state, *i)); |
| 327 | } |
| 328 | |
| 329 | m_state.popExpressionFlags(); |
| 330 | } |
| 331 | |
| 332 | // Pop global scopes |
| 333 | m_varManager.popVariableScope(); |
| 334 | m_varManager.popValueScope(); |
| 335 | |
| 336 | // Fill undefined (unused) components in inputs with dummy values |
| 337 | fillUndefinedShaderInputs(shader.getInputs()); |
| 338 | fillUndefinedShaderInputs(shader.getUniforms()); |
| 339 | |
| 340 | // Tokenize shader and write source |
| 341 | { |
| 342 | TokenStream tokenStr; |
| 343 | shader.tokenize(m_state, tokenStr); |
| 344 | |
| 345 | std::ostringstream str; |
| 346 | PrettyPrinter printer(str); |
| 347 | |
| 348 | // Append #version if necessary. |
| 349 | if (m_state.getProgramParameters().version == VERSION_300) |
| 350 | str << "#version 300 es\n"; |
| 351 | |
| 352 | printer.append(tokenStr); |
| 353 | shader.setSource(str.str().c_str()); |
| 354 | } |
| 355 | } |
| 356 | |
| 357 | } // rsg |