blob: a3fef345b8ccf2be51f6bb9c5d580c98fb27d5e3 [file] [log] [blame]
/*
* Copyright (C) 2011 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 "gles/share_group.h"
#include "gles/macros.h"
using android::base::AutoLock;
namespace {
ObjectGlobalName GenerateGlobalName(GlesContext* c, ObjectType type) {
ObjectGlobalName name = 0;
switch (type) {
case BUFFER:
PASS_THROUGH(c, GenBuffers, 1, &name);
break;
case TEXTURE:
PASS_THROUGH(c, GenTextures, 1, &name);
break;
case RENDERBUFFER:
PASS_THROUGH(c, GenRenderbuffers, 1, &name);
break;
case FRAMEBUFFER:
PASS_THROUGH(c, GenFramebuffers, 1, &name);
break;
default:
name = 0;
break;
}
#ifdef ENABLE_API_LOGGING
ALOGI("Generated name %d of type %d", name, type);
#endif
return name;
}
void DeleteGlobalName(GlesContext* c, ObjectType type, ObjectGlobalName name) {
if (name == 0) {
return;
}
switch (type) {
case BUFFER:
PASS_THROUGH(c, DeleteBuffers, 1, &name);
break;
case TEXTURE:
PASS_THROUGH(c, DeleteTextures, 1, &name);
break;
case RENDERBUFFER:
PASS_THROUGH(c, DeleteRenderbuffers, 1, &name);
break;
case FRAMEBUFFER:
PASS_THROUGH(c, DeleteFramebuffers, 1, &name);
break;
default:
// Do nothing.
break;
}
}
} // namespace
// This class manages the association between "local" names (ie. names for
// objects used by client code) and "global" names (ie. names for objects
// managed by the underlying context.)
class NamespaceImpl {
public:
explicit NamespaceImpl(ObjectType type);
~NamespaceImpl();
// Generates a unique local name that is currently not in use.
ObjectLocalName GenLocalName();
// Returns the global name associated with the specified local name, or 0 if
// the name is unknown.
ObjectGlobalName GetGlobalName(ObjectLocalName local_name);
// Associates the specified local name with the global name.
void SetGlobalName(ObjectLocalName local_name, ObjectGlobalName global_name);
// Removes the name from the namespace as well as deleting the global name
// from the underlying context.
void DeleteName(GlesContext* c, ObjectLocalName local_name);
// Deletes all names from the namespace.
void DeleteAllNames(GlesContext* c);
typedef std::map<ObjectLocalName, ObjectGlobalName> NameMap;
const ObjectType type_;
ObjectLocalName next_name_;
NameMap names_;
};
NamespaceImpl::NamespaceImpl(ObjectType type)
: type_(type),
next_name_(0) {
}
NamespaceImpl::~NamespaceImpl() {
LOG_ALWAYS_FATAL_IF(names_.size() > 0, "DeleteAllNames before destroying.");
}
ObjectLocalName NamespaceImpl::GenLocalName() {
ObjectLocalName local_name = 0;
do {
local_name = ++next_name_;
} while (local_name == 0 || names_.find(local_name) != names_.end());
return local_name;
}
ObjectGlobalName NamespaceImpl::GetGlobalName(ObjectLocalName local_name) {
NameMap::iterator it = names_.find(local_name);
return it != names_.end() ? it->second : 0;
}
void NamespaceImpl::SetGlobalName(ObjectLocalName local_name,
ObjectGlobalName global_name) {
names_[local_name] = global_name;
}
void NamespaceImpl::DeleteName(GlesContext* c, ObjectLocalName local_name) {
NameMap::iterator it = names_.find(local_name);
if (it != names_.end()) {
DeleteGlobalName(c, type_, it->second);
names_.erase(it);
}
}
void NamespaceImpl::DeleteAllNames(GlesContext* c) {
for (NameMap::iterator it = names_.begin(); it != names_.end(); ++it) {
DeleteGlobalName(c, type_, it->second);
}
names_.clear();
}
ShareGroup::ShareGroup(GlesContext* context)
: context_(context) {
for (int i = 0; i < NUM_OBJECT_TYPES; ++i) {
namespace_[i] = new NamespaceImpl((ObjectType)i);
}
}
ShareGroup::~ShareGroup() {
AutoLock mutex(lock_);
objects_.clear();
for (int i = 0; i < NUM_OBJECT_TYPES; ++i) {
namespace_[i]->DeleteAllNames(context_);
delete namespace_[i];
}
}
void ShareGroup::GenNames(ObjectType type, int n, ObjectLocalName* names) {
AutoLock mutex(lock_);
NamespaceImpl* ns = GetNamespace(type);
for (int i = 0; i < n; ++i) {
names[i] = ns->GenLocalName();
// TODO(crbug.com/441939): Generate all global names in a batch.
const ObjectGlobalName global_name = GenerateGlobalName(context_, type);
ns->SetGlobalName(names[i], global_name);
}
}
ObjectGlobalName ShareGroup::GetGlobalName(ObjectType type,
ObjectLocalName local_name) {
AutoLock mutex(lock_);
return GetNamespace(type)->GetGlobalName(local_name);
}
void ShareGroup::SetGlobalName(ObjectType type,
ObjectLocalName local_name,
ObjectGlobalName global_name) {
AutoLock mutex(lock_);
GetNamespace(type)->SetGlobalName(local_name, global_name);
}
ObjectDataPtr ShareGroup::GetObject(ObjectType type, ObjectLocalName name,
bool create_if_needed) {
if (name == 0) {
return ObjectDataPtr();
}
AutoLock mutex(lock_);
const ObjectID id = GetObjectID(type, name);
ObjectDataMap::iterator iter = objects_.find(id);
if (iter != objects_.end()) {
return iter->second;
}
if (!create_if_needed) {
return ObjectDataPtr();
}
// We do not have an object with this name. In this case, we are dealing
// with client-managed object names. We will generate a new global name and
// associate it with the client-managed local name. Note that some objects
// (e.g. programs and shaders) manage their own global names, and so will
// not be allocated here.
if (type != FRAGMENT_SHADER && type != VERTEX_SHADER && type != PROGRAM) {
NamespaceImpl* ns = GetNamespace(type);
ObjectGlobalName global_name = ns->GetGlobalName(name);
if (global_name == 0) {
global_name = GenerateGlobalName(context_, type);
ns->SetGlobalName(name, global_name);
}
}
// Create the object data for the newly generated name.
ObjectDataPtr obj;
switch (type) {
case BUFFER:
obj = ObjectDataPtr(new BufferData(name));
break;
case TEXTURE:
obj = ObjectDataPtr(new TextureData(name));
break;
case RENDERBUFFER:
obj = ObjectDataPtr(new RenderbufferData(name));
break;
case FRAMEBUFFER:
obj = ObjectDataPtr(new FramebufferData(name));
break;
case VERTEX_SHADER:
obj = ObjectDataPtr(new ShaderData(type, name));
break;
case FRAGMENT_SHADER:
obj = ObjectDataPtr(new ShaderData(type, name));
break;
case PROGRAM:
obj = ObjectDataPtr(new ProgramData(name));
break;
default:
LOG_ALWAYS_FATAL("Unsupported object type %d", type);
break;
}
objects_.insert(std::make_pair(id, obj));
return obj;
}
void ShareGroup::DeleteObjects(ObjectType type, int n,
const ObjectLocalName* names) {
AutoLock mutex(lock_);
NamespaceImpl* ns = GetNamespace(type);
for (int i = 0; i < n; ++i) {
if (names[i] != 0) {
// TODO(crbug.com/441939): Delete the underlying global names in a batch.
ns->DeleteName(context_, names[i]);
objects_.erase(GetObjectID(type, names[i]));
}
}
}
NamespaceImpl* ShareGroup::GetNamespace(ObjectType type) {
return namespace_[ValidateType(type)];
}
ShareGroup::ObjectID ShareGroup::GetObjectID(ObjectType type,
ObjectLocalName name) const {
return ObjectID(ValidateType(type), name);
}
ObjectType ShareGroup::ValidateType(ObjectType type) const {
LOG_ALWAYS_FATAL_IF(type < 0 || type >= NUM_OBJECT_TYPES);
// To simplify lookup, both vertex shader and fragment shaders are given the
// common SHADER type.
if (type == FRAGMENT_SHADER || type == VERTEX_SHADER) {
return SHADER;
} else {
return type;
}
}