/* * Copyright (C) 2016 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. */ #include #include #include #include "aemu/base/synchronization/Lock.h" #include "aemu/base/containers/Lookup.h" #include "GLcommon/FramebufferData.h" #include "host-common/logging.h" #include #include static constexpr int toIndex(NamedObjectType type) { return static_cast(type); } struct ShareGroup::ObjectDataAutoLock { ObjectDataAutoLock(ShareGroup* self) : self(self) { self->lockObjectData(); } ~ObjectDataAutoLock() { self->unlockObjectData(); } ShareGroup* self; }; ShareGroup::ShareGroup(GlobalNameSpace *globalNameSpace, uint64_t sharedGroupID, android::base::Stream* stream, const ObjectData::loadObject_t& loadObject) : m_sharedGroupID(sharedGroupID) { ObjectDataAutoLock lock(this); for (int i = 0; i < toIndex(NamedObjectType::NUM_OBJECT_TYPES); i++) { m_nameSpace[i] = new NameSpace(static_cast(i), globalNameSpace, stream, loadObject); } if (stream) { m_needLoadRestore = true; int i = 0; for (auto ns : m_nameSpace) { GL_LOG("ShareGroup::%s: %p: start restore namespace for type %d\n", __func__, this, i); ns->postLoad( [this](NamedObjectType p_type, ObjectLocalName p_localName) { return this->getObjectDataPtrNoLock(p_type, p_localName); }); GL_LOG("ShareGroup::%s: %p: finish restore namespace for type %d\n", __func__, this, i); ++i; } } } void ShareGroup::preSave(GlobalNameSpace *globalNameSpace) { ObjectDataAutoLock lock(this); if (m_saveStage == PreSaved) return; assert(m_saveStage == Empty); m_saveStage = PreSaved; m_nameSpace[(int)NamedObjectType::TEXTURE]->preSave(globalNameSpace); } void ShareGroup::onSave(android::base::Stream* stream) { // we do not save m_nameSpace ObjectDataAutoLock lock(this); if (m_saveStage == Saved) return; assert(m_saveStage == PreSaved); m_saveStage = Saved; int i = 0; for (auto ns : m_nameSpace) { GL_LOG("ShareGroup::%s: %p: start saving type %d\n", __func__, this, i); ns->onSave(stream); GL_LOG("ShareGroup::%s: %p: finish saving type %d\n", __func__, this, i); ++i; } } void ShareGroup::postSave(android::base::Stream* stream) { (void)stream; m_saveStage = Empty; // We need to mark the textures dirty, for those that has been bound to // a potential render target. NameSpace* renderbufferNs = m_nameSpace[(int)NamedObjectType::RENDERBUFFER]; for (ObjectDataMap::const_iterator it = renderbufferNs->objDataMapBegin(); it != renderbufferNs->objDataMapEnd(); it ++) { RenderbufferData* rbData = (RenderbufferData*)it->second.get(); rbData->makeTextureDirty(); } } void ShareGroup::postLoadRestore() { android::base::AutoLock lock(m_restoreLock); if (m_needLoadRestore) { int i = 0; for (auto ns : m_nameSpace) { GL_LOG("ShareGroup::%s: %p: start post load restore namespace for type %d\n", __func__, this, i); ns->postLoadRestore([this](NamedObjectType p_type, ObjectLocalName p_localName) { return getGlobalName(p_type, p_localName); }); GL_LOG("ShareGroup::%s: %p: end post load restore namespace for type %d\n", __func__, this, i); ++i; } m_needLoadRestore = false; } } bool ShareGroup::needRestore() { return m_needLoadRestore; } void ShareGroup::lockObjectData() { while (m_objectsDataLock.test_and_set(std::memory_order_acquire)) { ; } } void ShareGroup::unlockObjectData() { m_objectsDataLock.clear(std::memory_order_release); } ShareGroup::~ShareGroup() { { android::base::AutoLock lock(m_namespaceLock); ObjectDataAutoLock objDataLock(this); for (auto n : m_nameSpace) { delete n; } } } ObjectLocalName ShareGroup::genName(GenNameInfo genNameInfo, ObjectLocalName p_localName, bool genLocal) { assert(genNameInfo.m_type != NamedObjectType::FRAMEBUFFER); if (toIndex(genNameInfo.m_type) >= toIndex(NamedObjectType::NUM_OBJECT_TYPES)) { return 0; } android::base::AutoLock lock(m_namespaceLock); ObjectLocalName localName = m_nameSpace[toIndex(genNameInfo.m_type)]->genName( genNameInfo, p_localName, genLocal); return localName; } ObjectLocalName ShareGroup::genName(NamedObjectType namedObjectType, ObjectLocalName p_localName, bool genLocal) { return genName(GenNameInfo(namedObjectType), p_localName, genLocal); } ObjectLocalName ShareGroup::genName(ShaderProgramType shaderProgramType, ObjectLocalName p_localName, bool genLocal, GLuint existingGlobal) { return genName(GenNameInfo(shaderProgramType, existingGlobal), p_localName, genLocal); } unsigned int ShareGroup::getGlobalName(NamedObjectType p_type, ObjectLocalName p_localName) { assert(p_type != NamedObjectType::FRAMEBUFFER); if (toIndex(p_type) >= toIndex(NamedObjectType::NUM_OBJECT_TYPES)) { return 0; } android::base::AutoLock lock(m_namespaceLock); return m_nameSpace[toIndex(p_type)]->getGlobalName(p_localName); } ObjectLocalName ShareGroup::getLocalName(NamedObjectType p_type, unsigned int p_globalName) { assert(p_type != NamedObjectType::FRAMEBUFFER); if (toIndex(p_type) >= toIndex(NamedObjectType::NUM_OBJECT_TYPES)) { return 0; } android::base::AutoLock lock(m_namespaceLock); return m_nameSpace[toIndex(p_type)]->getLocalName(p_globalName); } NamedObjectPtr ShareGroup::getNamedObject(NamedObjectType p_type, ObjectLocalName p_localName) { assert(p_type != NamedObjectType::FRAMEBUFFER); if (toIndex(p_type) >= toIndex(NamedObjectType::NUM_OBJECT_TYPES)) { return 0; } android::base::AutoLock lock(m_namespaceLock); return m_nameSpace[toIndex(p_type)]->getNamedObject(p_localName); } void ShareGroup::deleteName(NamedObjectType p_type, ObjectLocalName p_localName) { assert(p_type != NamedObjectType::FRAMEBUFFER); if (toIndex(p_type) >= toIndex(NamedObjectType::NUM_OBJECT_TYPES)) { return; } android::base::AutoLock lock(m_namespaceLock); ObjectDataAutoLock objDataLock(this); m_nameSpace[toIndex(p_type)]->deleteName(p_localName); } bool ShareGroup::isObject(NamedObjectType p_type, ObjectLocalName p_localName) { assert(p_type != NamedObjectType::FRAMEBUFFER); if (toIndex(p_type) >= toIndex(NamedObjectType::NUM_OBJECT_TYPES)) { return 0; } android::base::AutoLock lock(m_namespaceLock); return m_nameSpace[toIndex(p_type)]->isObject(p_localName); } void ShareGroup::replaceGlobalObject(NamedObjectType p_type, ObjectLocalName p_localName, NamedObjectPtr p_globalObject) { assert(p_type != NamedObjectType::FRAMEBUFFER); if (toIndex(p_type) >= toIndex(NamedObjectType::NUM_OBJECT_TYPES)) { return; } android::base::AutoLock lock(m_namespaceLock); m_nameSpace[toIndex(p_type)]->replaceGlobalObject(p_localName, p_globalObject); } void ShareGroup::setGlobalObject(NamedObjectType p_type, ObjectLocalName p_localName, NamedObjectPtr p_globalObject) { assert(p_type != NamedObjectType::FRAMEBUFFER); if (toIndex(p_type) >= toIndex(NamedObjectType::NUM_OBJECT_TYPES)) { return; } android::base::AutoLock lock(m_namespaceLock); m_nameSpace[toIndex(p_type)]->setGlobalObject(p_localName, p_globalObject); } void ShareGroup::setObjectData(NamedObjectType p_type, ObjectLocalName p_localName, ObjectDataPtr data) { ObjectDataAutoLock lock(this); setObjectDataLocked(p_type, p_localName, std::move(data)); } void ShareGroup::setObjectDataLocked(NamedObjectType p_type, ObjectLocalName p_localName, ObjectDataPtr&& data) { assert(p_type != NamedObjectType::FRAMEBUFFER); if (toIndex(p_type) >= toIndex(NamedObjectType::NUM_OBJECT_TYPES)) { return; } m_nameSpace[toIndex(p_type)]->setObjectData(p_localName, data); } const ObjectDataPtr& ShareGroup::getObjectDataPtrNoLock( NamedObjectType p_type, ObjectLocalName p_localName) { assert(p_type != NamedObjectType::FRAMEBUFFER); return m_nameSpace[toIndex(p_type)]->getObjectDataPtr(p_localName); } ObjectData* ShareGroup::getObjectData(NamedObjectType p_type, ObjectLocalName p_localName) { if (toIndex(p_type) >= toIndex(NamedObjectType::NUM_OBJECT_TYPES)) return nullptr; ObjectDataAutoLock lock(this); return getObjectDataPtrNoLock(p_type, p_localName).get(); } ObjectDataPtr ShareGroup::getObjectDataPtr(NamedObjectType p_type, ObjectLocalName p_localName) { if (toIndex(p_type) >= toIndex(NamedObjectType::NUM_OBJECT_TYPES)) return {}; ObjectDataAutoLock lock(this); return getObjectDataPtrNoLock(p_type, p_localName); } #define CC_LIKELY( exp ) (__builtin_expect( !!(exp), true )) #define CC_UNLIKELY( exp ) (__builtin_expect( !!(exp), false )) unsigned int ShareGroup::ensureObjectOnBind(NamedObjectType p_type, ObjectLocalName p_localName) { android::base::AutoLock lock(m_namespaceLock); ObjectDataAutoLock objDataLock(this); auto ns = m_nameSpace[toIndex(p_type)]; bool isObj; unsigned int globalName = ns->getGlobalName(p_localName, &isObj); if (CC_LIKELY(isObj)) { bool everBound = ns->everBound(p_localName); if (CC_LIKELY(everBound)) return globalName; auto ptr = ns->getObjectDataPtr(p_localName); if (ptr) { switch (p_type) { case NamedObjectType::VERTEXBUFFER: { auto vbo = ((GLESbuffer*)(ptr.get())); vbo->setBinded(); break; } // TODO: Add other object types here default: fprintf(stderr, "%s: Warning: Unhandled object type 0x%x\n", __func__, (uint32_t)p_type); break; } } ns->setBoundAtLeastOnce(p_localName); return globalName; } // No such object, generate one and bind it bool genLocal = false; auto gi = GenNameInfo(p_type); ns->genName( gi, p_localName, genLocal); switch (p_type) { case NamedObjectType::VERTEXBUFFER: { auto vbo = new GLESbuffer; vbo->setBinded(); ns->setObjectData(p_localName, ObjectDataPtr(vbo)); break; } // TODO: Add other object types here default: fprintf(stderr, "%s: Warning: Unhandled object type 0x%x\n", __func__, (uint32_t)p_type); break; } ns->setBoundAtLeastOnce(p_localName); return (uint32_t)(ns->getGlobalName(p_localName)); } ObjectNameManager::ObjectNameManager(GlobalNameSpace *globalNameSpace) : m_globalNameSpace(globalNameSpace) {} ShareGroupPtr ObjectNameManager::createShareGroup(void *p_groupName, uint64_t sharedGroupID, android::base::Stream* stream, const ObjectData::loadObject_t& loadObject) { android::base::AutoLock lock(m_lock); ShareGroupPtr& shareGroupReturn = m_groups[p_groupName]; if (!shareGroupReturn) { if (!sharedGroupID) { while (m_nextSharedGroupID == 0 || android::base::contains(m_usedSharedGroupIDs, m_nextSharedGroupID)) { m_nextSharedGroupID ++; } sharedGroupID = m_nextSharedGroupID; m_usedSharedGroupIDs.insert(sharedGroupID); ++m_nextSharedGroupID; } else { assert(!m_usedSharedGroupIDs.count(sharedGroupID)); m_usedSharedGroupIDs.insert(sharedGroupID); } shareGroupReturn.reset(new ShareGroup(m_globalNameSpace, sharedGroupID, stream, loadObject)); } else { assert(sharedGroupID == 0 || sharedGroupID == shareGroupReturn->getId()); } return shareGroupReturn; } ShareGroupPtr ObjectNameManager::getShareGroup(void *p_groupName) { android::base::AutoLock lock(m_lock); ShareGroupPtr shareGroupReturn; ShareGroupsMap::iterator s( m_groups.find(p_groupName) ); if (s != m_groups.end()) { shareGroupReturn = (*s).second; } return shareGroupReturn; } ShareGroupPtr ObjectNameManager::attachShareGroup(void *p_groupName, void *p_existingGroupName) { android::base::AutoLock lock(m_lock); ShareGroupsMap::iterator s( m_groups.find(p_existingGroupName) ); if (s == m_groups.end()) { // ShareGroup is not found !!! return ShareGroupPtr(); } ShareGroupPtr shareGroupReturn((*s).second); if (m_groups.find(p_groupName) == m_groups.end()) { m_groups.emplace(p_groupName, shareGroupReturn); m_usedSharedGroupIDs.insert(shareGroupReturn->getId()); } return shareGroupReturn; } ShareGroupPtr ObjectNameManager::attachOrCreateShareGroup(void *p_groupName, uint64_t p_existingGroupID, android::base::Stream* stream, const ObjectData::loadObject_t& loadObject) { assert(m_groups.find(p_groupName) == m_groups.end()); ShareGroupsMap::iterator ite = p_existingGroupID ? m_groups.begin() : m_groups.end(); while (ite != m_groups.end() && ite->second->getId() != p_existingGroupID) { ++ite; } if (ite == m_groups.end()) { return createShareGroup(p_groupName, p_existingGroupID, stream, loadObject); } else { return attachShareGroup(p_groupName, ite->first); } } void ObjectNameManager::deleteShareGroup(void *p_groupName) { android::base::AutoLock lock(m_lock); auto sharedGroup = m_groups.find(p_groupName); if (sharedGroup == m_groups.end()) return; m_usedSharedGroupIDs.erase(sharedGroup->second->getId()); m_groups.erase(sharedGroup); } void *ObjectNameManager::getGlobalContext() { android::base::AutoLock lock(m_lock); return m_groups.empty() ? nullptr : m_groups.begin()->first; } void ObjectNameManager::preSave() { for (auto& shareGroup : m_groups) { shareGroup.second->preSave(m_globalNameSpace); } }