| /* |
| * 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 <GLcommon/ShareGroup.h> |
| #include <GLcommon/ObjectNameSpace.h> |
| #include <GLcommon/GLEScontext.h> |
| |
| #include "aemu/base/synchronization/Lock.h" |
| #include "aemu/base/containers/Lookup.h" |
| #include "GLcommon/FramebufferData.h" |
| |
| #include "host-common/logging.h" |
| |
| #include <array> |
| #include <utility> |
| |
| static constexpr int toIndex(NamedObjectType type) { |
| return static_cast<int>(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<NamedObjectType>(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); |
| } |
| } |