/*
* Copyright 2006-2012 Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Philippe Houdoin <philippe.houdoin@free.fr>
* Alexander von Gluck IV <kallisti5@unixzen.com>
*/
#include <driver_settings.h>
#include <image.h>
#include <kernel/image.h>
#include <system/safemode_defs.h>
#include <Directory.h>
#include <FindDirectory.h>
#include <Path.h>
#include <strings.h>
#include "GLDispatcher.h"
#include "GLRendererRoster.h"
#include <new>
#include <string.h>
extern "C" status_t _kern_get_safemode_option(const char* parameter,
char* buffer, size_t* _bufferSize);
GLRendererRoster::GLRendererRoster(BGLView* view, ulong options)
:
fNextID(0),
fView(view),
fOptions(options),
fSafeMode(false),
fABISubDirectory(NULL)
{
char parameter[32];
size_t parameterLength = sizeof(parameter);
if (_kern_get_safemode_option(B_SAFEMODE_SAFE_MODE,
parameter, ¶meterLength) == B_OK) {
if (!strcasecmp(parameter, "enabled") || !strcasecmp(parameter, "on")
|| !strcasecmp(parameter, "true") || !strcasecmp(parameter, "yes")
|| !strcasecmp(parameter, "enable") || !strcmp(parameter, "1"))
fSafeMode = true;
}
if (_kern_get_safemode_option(B_SAFEMODE_DISABLE_USER_ADD_ONS,
parameter, ¶meterLength) == B_OK) {
if (!strcasecmp(parameter, "enabled") || !strcasecmp(parameter, "on")
|| !strcasecmp(parameter, "true") || !strcasecmp(parameter, "yes")
|| !strcasecmp(parameter, "enable") || !strcmp(parameter, "1"))
fSafeMode = true;
}
// We might run in compatibility mode on a system with a different ABI. The
// renderers matching our ABI can usually be found in respective
// subdirectories of the opengl add-ons directories.
system_info info;
if (get_system_info(&info) == B_OK
&& (info.abi & B_HAIKU_ABI_MAJOR)
!= (B_HAIKU_ABI & B_HAIKU_ABI_MAJOR)) {
switch (B_HAIKU_ABI & B_HAIKU_ABI_MAJOR) {
case B_HAIKU_ABI_GCC_2:
fABISubDirectory = "gcc2";
break;
case B_HAIKU_ABI_GCC_4:
fABISubDirectory = "gcc4";
break;
}
}
AddDefaultPaths();
}
GLRendererRoster::~GLRendererRoster()
{
}
BGLRenderer*
GLRendererRoster::GetRenderer(int32 id)
{
RendererMap::const_iterator iterator = fRenderers.find(id);
if (iterator == fRenderers.end())
return NULL;
struct renderer_item item = iterator->second;
return item.renderer;
}
void
GLRendererRoster::AddDefaultPaths()
{
// add user directories first, so that they can override system renderers
const directory_which paths[] = {
B_USER_NONPACKAGED_ADDONS_DIRECTORY,
B_USER_ADDONS_DIRECTORY,
B_SYSTEM_ADDONS_DIRECTORY,
};
for (uint32 i = fSafeMode ? 4 : 0;
i < sizeof(paths) / sizeof(paths[0]); i++) {
BPath path;
status_t status = find_directory(paths[i], &path, true);
if (status == B_OK && path.Append("opengl") == B_OK)
AddPath(path.Path());
}
}
status_t
GLRendererRoster::AddPath(const char* path)
{
BDirectory directory(path);
status_t status = directory.InitCheck();
if (status < B_OK)
return status;
// if a subdirectory for our ABI exists, use that instead
if (fABISubDirectory != NULL) {
BEntry entry(&directory, fABISubDirectory);
if (entry.IsDirectory()) {
status = directory.SetTo(&entry);
if (status != B_OK)
return status;
}
}
node_ref nodeRef;
status = directory.GetNodeRef(&nodeRef);
if (status < B_OK)
return status;
int32 count = 0;
int32 files = 0;
entry_ref ref;
BEntry entry;
while (directory.GetNextRef(&ref) == B_OK) {
entry.SetTo(&ref, true);
if (entry.InitCheck() == B_OK && !entry.IsFile())
continue;
if (CreateRenderer(ref) == B_OK)
count++;
files++;
}
if (files != 0 && count == 0)
return B_BAD_VALUE;
return B_OK;
}
status_t
GLRendererRoster::AddRenderer(BGLRenderer* renderer,
image_id image, const entry_ref* ref, ino_t node)
{
renderer_item item;
item.renderer = renderer;
item.image = image;
item.node = node;
if (ref != NULL)
item.ref = *ref;
try {
fRenderers[fNextID] = item;
} catch (...) {
return B_NO_MEMORY;
}
renderer->fOwningRoster = this;
renderer->fID = fNextID++;
return B_OK;
}
status_t
GLRendererRoster::CreateRenderer(const entry_ref& ref)
{
BEntry entry(&ref, true);
node_ref nodeRef;
status_t status = entry.GetNodeRef(&nodeRef);
if (status < B_OK)
return status;
BPath path(&ref);
image_id image = load_add_on(path.Path());
if (image < B_OK)
return image;
BGLRenderer* (*instantiate_renderer)
(BGLView* view, ulong options, BGLDispatcher* dispatcher);
status = get_image_symbol(image, "instantiate_gl_renderer",
B_SYMBOL_TYPE_TEXT, (void**)&instantiate_renderer);
if (status == B_OK) {
BGLRenderer* renderer
= instantiate_renderer(fView, fOptions, new BGLDispatcher());
if (!renderer) {
unload_add_on(image);
return B_UNSUPPORTED;
}
if (AddRenderer(renderer, image, &ref, nodeRef.node) != B_OK) {
renderer->Release();
// this will delete the renderer
unload_add_on(image);
}
return B_OK;
}
unload_add_on(image);
return status;
}