/*------------------------------------------------------------------------- * drawElements Quality Program Random Shader Generator * ---------------------------------------------------- * * Copyright 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * *//*! * \file * \brief Variable manager. *//*--------------------------------------------------------------------*/ #include "rsgVariableManager.hpp" #include <algorithm> #include <map> #include <set> using std::vector; using std::set; using std::map; namespace rsg { class SubValueRangeIterator { public: SubValueRangeIterator (const ConstValueRangeAccess& valueRange); ~SubValueRangeIterator (void) {} bool hasItem (void) const; ConstValueRangeAccess getItem (void) const; void next (void); private: vector<ConstValueRangeAccess> m_stack; }; SubValueRangeIterator::SubValueRangeIterator (const ConstValueRangeAccess& valueRange) { m_stack.push_back(valueRange); } inline bool SubValueRangeIterator::hasItem (void) const { return !m_stack.empty(); } inline ConstValueRangeAccess SubValueRangeIterator::getItem (void) const { return m_stack[m_stack.size()-1]; } void SubValueRangeIterator::next (void) { ConstValueRangeAccess curItem = getItem(); m_stack.pop_back(); // Remove current switch (curItem.getType().getBaseType()) { case VariableType::TYPE_ARRAY: { int numElements = curItem.getType().getNumElements(); for (int ndx = 0; ndx < numElements; ndx++) m_stack.push_back(curItem.member(ndx)); break; } case VariableType::TYPE_STRUCT: { int numMembers = (int)curItem.getType().getMembers().size(); for (int ndx = 0; ndx < numMembers; ndx++) m_stack.push_back(curItem.member(ndx)); break; } default: break; // \todo [2011-02-03 pyry] Swizzle control? } } ValueEntry::ValueEntry (const Variable* variable) : m_variable (variable) , m_valueRange (variable->getType()) { } VariableScope::VariableScope (void) { } VariableScope::~VariableScope (void) { for (vector<Variable*>::iterator i = m_declaredVariables.begin(); i != m_declaredVariables.end(); i++) delete *i; for (vector<Variable*>::iterator i = m_liveVariables.begin(); i != m_liveVariables.end(); i++) delete *i; } Variable* VariableScope::allocate (const VariableType& type, Variable::Storage storage, const char* name) { Variable* variable = new Variable(type, storage, name); try { m_liveVariables.push_back(variable); return variable; } catch (const std::exception&) { delete variable; throw; } } void VariableScope::declare (Variable* variable) { m_declaredVariables.push_back(variable); removeLive(variable); } void VariableScope::removeLive (const Variable* variable) { vector<Variable*>::iterator pos = std::find(m_liveVariables.begin(), m_liveVariables.end(), variable); DE_ASSERT(pos != m_liveVariables.end()); // \todo [pyry] Not so efficient m_liveVariables.erase(pos); } ValueScope::ValueScope (void) { } ValueScope::~ValueScope (void) { clear(); } void ValueScope::clear (void) { for (vector<ValueEntry*>::iterator i = m_entries.begin(); i != m_entries.end(); i++) delete *i; m_entries.clear(); } ValueEntry* ValueScope::allocate (const Variable* variable) { ValueEntry* entry = new ValueEntry(variable); try { m_entries.push_back(entry); return entry; } catch (const std::exception&) { delete entry; throw; } } class CompareEntryVariable { public: CompareEntryVariable (const Variable* variable) : m_variable(variable) { } bool operator== (const ValueEntry* entry) const { return entry->getVariable() == m_variable; } private: const Variable* m_variable; }; bool operator== (const ValueEntry* entry, const CompareEntryVariable& cmp) { return cmp == entry; } ValueEntry* ValueScope::findEntry (const Variable* variable) const { vector<ValueEntry*>::const_iterator pos = std::find(m_entries.begin(), m_entries.end(), CompareEntryVariable(variable)); return pos != m_entries.end() ? *pos : DE_NULL; } void ValueScope::setValue (const Variable* variable, ConstValueRangeAccess value) { ValueEntry* entry = findEntry(variable); DE_ASSERT(entry); ValueRangeAccess dst = entry->getValueRange(); dst.getMin() = value.getMin().value(); dst.getMax() = value.getMax().value(); } void ValueScope::removeValue (const Variable* variable) { vector<ValueEntry*>::iterator pos = std::find(m_entries.begin(), m_entries.end(), CompareEntryVariable(variable)); if (pos != m_entries.end()) { ValueEntry* entry = *pos; m_entries.erase(pos); delete entry; } } VariableManager::VariableManager (NameAllocator& nameAllocator) : m_numAllocatedScalars (0) , m_numAllocatedShaderInScalars (0) , m_numAllocatedShaderInVariables (0) , m_numAllocatedUniformScalars (0) , m_nameAllocator (nameAllocator) { } VariableManager::~VariableManager (void) { } Variable* VariableManager::allocate (const VariableType& type) { return allocate(type, Variable::STORAGE_LOCAL, m_nameAllocator.allocate().c_str()); } Variable* VariableManager::allocate (const VariableType& type, Variable::Storage storage, const char* name) { VariableScope& varScope = getCurVariableScope(); ValueScope& valueScope = getCurValueScope(); int numScalars = type.getScalarSize(); // Allocate in current scope Variable* variable = varScope.allocate(type, Variable::STORAGE_LOCAL, name); // Allocate value entry ValueEntry* valueEntry = valueScope.allocate(variable); // Add to cache m_entryCache.push_back(valueEntry); m_numAllocatedScalars += numScalars; // Set actual storage - affects uniform/shader in allocations. setStorage(variable, storage); return variable; } void VariableManager::setStorage (Variable* variable, Variable::Storage storage) { int numScalars = variable->getType().getScalarSize(); // Decrement old. if (variable->getStorage() == Variable::STORAGE_SHADER_IN) { m_numAllocatedShaderInScalars -= numScalars; m_numAllocatedShaderInVariables -= 1; } else if (variable->getStorage() == Variable::STORAGE_UNIFORM) m_numAllocatedUniformScalars -= numScalars; // Add new. if (storage == Variable::STORAGE_SHADER_IN) { m_numAllocatedShaderInScalars += numScalars; m_numAllocatedShaderInVariables += 1; } else if (storage == Variable::STORAGE_UNIFORM) m_numAllocatedUniformScalars += numScalars; variable->setStorage(storage); } bool VariableManager::canDeclareInCurrentScope (const Variable* variable) const { const vector<Variable*>& curLiveVars = getCurVariableScope().getLiveVariables(); return std::find(curLiveVars.begin(), curLiveVars.end(), variable) != curLiveVars.end(); } const vector<Variable*>& VariableManager::getLiveVariables (void) const { return getCurVariableScope().getLiveVariables(); } void VariableManager::declareVariable (Variable* variable) { // Remove from cache if exists in there. std::vector<const ValueEntry*>::iterator pos = std::find(m_entryCache.begin(), m_entryCache.end(), CompareEntryVariable(variable)); if (pos != m_entryCache.end()) m_entryCache.erase(pos); DE_ASSERT(std::find(m_entryCache.begin(), m_entryCache.end(), CompareEntryVariable(variable)) == m_entryCache.end()); // Remove from scope stack. for (vector<ValueScope*>::const_iterator stackIter = m_valueScopeStack.begin(); stackIter != m_valueScopeStack.end(); stackIter++) { ValueScope* scope = *stackIter; scope->removeValue(variable); } // Declare in current scope. getCurVariableScope().declare(variable); } const ValueEntry* VariableManager::getValue (const Variable* variable) const { vector<const ValueEntry*>::const_iterator pos = std::find(m_entryCache.begin(), m_entryCache.end(), CompareEntryVariable(variable)); return pos != m_entryCache.end() ? *pos : DE_NULL; } void VariableManager::removeValueFromCurrentScope (const Variable* variable) { // Remove from cache std::vector<const ValueEntry*>::iterator pos = std::find(m_entryCache.begin(), m_entryCache.end(), CompareEntryVariable(variable)); DE_ASSERT(pos != m_entryCache.end()); m_entryCache.erase(pos); // Remove from current scope \note May not exist in there. getCurValueScope().removeValue(variable); } const ValueEntry* VariableManager::getParentValue (const Variable* variable) const { if (m_valueScopeStack.size() < 2) return DE_NULL; // Only single value scope for (vector<ValueScope*>::const_reverse_iterator i = m_valueScopeStack.rbegin()+1; i != m_valueScopeStack.rend(); i++) { const ValueScope* scope = *i; ValueEntry* entry = scope->findEntry(variable); if (entry) return entry; } return DE_NULL; // Not found in stack } void VariableManager::setValue (const Variable* variable, ConstValueRangeAccess value) { ValueScope& curScope = getCurValueScope(); if (!curScope.findEntry(variable)) { // New value, allocate and update cache. ValueEntry* newEntry = curScope.allocate(variable); std::vector<const ValueEntry*>::iterator cachePos = std::find(m_entryCache.begin(), m_entryCache.end(), CompareEntryVariable(variable)); if (cachePos != m_entryCache.end()) *cachePos = newEntry; else m_entryCache.push_back(newEntry); } curScope.setValue(variable, value); } void VariableManager::reserve (ReservedScalars& store, int numScalars) { DE_ASSERT(store.numScalars == 0); store.numScalars = numScalars; m_numAllocatedScalars += numScalars; } void VariableManager::release (ReservedScalars& store) { m_numAllocatedScalars -= store.numScalars; store.numScalars = 0; } void VariableManager::pushVariableScope (VariableScope& scope) { // Expects emtpy scope DE_ASSERT(scope.getDeclaredVariables().size() == 0); DE_ASSERT(scope.getLiveVariables().size() == 0); m_variableScopeStack.push_back(&scope); } void VariableManager::popVariableScope (void) { VariableScope& curScope = getCurVariableScope(); // Migrate live variables to parent scope. // Variables allocated in child scopes can be declared in any parent scope but not the other way around. if (m_variableScopeStack.size() > 1) { VariableScope& parentScope = *m_variableScopeStack[m_variableScopeStack.size()-2]; vector<Variable*>& curLiveVars = curScope.getLiveVariables(); vector<Variable*>& parenLiveVars = parentScope.getLiveVariables(); while (!curLiveVars.empty()) { Variable* liveVar = curLiveVars.back(); parenLiveVars.push_back(liveVar); curLiveVars.pop_back(); } } // All variables should be either migrated to parent or declared (in case of root scope). DE_ASSERT(curScope.getLiveVariables().size() == 0); m_variableScopeStack.pop_back(); } void VariableManager::pushValueScope (ValueScope& scope) { // Value scope should be empty DE_ASSERT(scope.getValues().size() == 0); m_valueScopeStack.push_back(&scope); } void VariableManager::popValueScope (void) { ValueScope& oldScope = getCurValueScope(); // Pop scope and clear cache. m_valueScopeStack.pop_back(); m_entryCache.clear(); // Re-build entry cache. if (!m_valueScopeStack.empty()) { ValueScope& newTopScope = getCurValueScope(); // Speed up computing intersections. map<const Variable*, const ValueEntry*> oldValues; const vector<ValueEntry*>& oldEntries = oldScope.getValues(); for (vector<ValueEntry*>::const_iterator valueIter = oldEntries.begin(); valueIter != oldEntries.end(); valueIter++) oldValues[(*valueIter)->getVariable()] = *valueIter; set<const Variable*> addedVars; // Re-build based on current stack. for (vector<ValueScope*>::reverse_iterator scopeIter = m_valueScopeStack.rbegin(); scopeIter != m_valueScopeStack.rend(); scopeIter++) { const ValueScope* scope = *scopeIter; const vector<ValueEntry*>& valueEntries = scope->getValues(); for (vector<ValueEntry*>::const_iterator valueIter = valueEntries.begin(); valueIter != valueEntries.end(); valueIter++) { const ValueEntry* entry = *valueIter; const Variable* var = entry->getVariable(); if (addedVars.find(var) != addedVars.end()) continue; // Already in cache, set deeper in scope stack. DE_ASSERT(std::find(m_entryCache.begin(), m_entryCache.end(), CompareEntryVariable(var)) == m_entryCache.end()); if (oldValues.find(var) != oldValues.end()) { const ValueEntry* oldEntry = oldValues[var]; // Build new intersected value and store into current scope. ValueRange intersectedValue(var->getType()); DE_ASSERT(oldEntry->getValueRange().intersects(entry->getValueRange())); // Must intersect ValueRange::computeIntersection(intersectedValue, entry->getValueRange(), oldEntry->getValueRange()); if (!newTopScope.findEntry(var)) newTopScope.allocate(var); newTopScope.setValue(var, intersectedValue.asAccess()); // Add entry from top scope to cache. m_entryCache.push_back(newTopScope.findEntry(var)); } else m_entryCache.push_back(entry); // Just add to cache. addedVars.insert(var); // Record as cached variable. } } // Copy entries from popped scope that don't yet exist in the stack. for (vector<ValueEntry*>::const_iterator valueIter = oldEntries.begin(); valueIter != oldEntries.end(); valueIter++) { const ValueEntry* oldEntry = *valueIter; const Variable* var = oldEntry->getVariable(); if (addedVars.find(var) == addedVars.end()) setValue(var, oldEntry->getValueRange()); } } } } // rsg