blob: dcb572b88b89f80efbe1c52f9dce602216d3dc3b [file] [log] [blame]
/*
* 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 "base/Lock.h"
#include "base/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);
}
}