Files
mesa/src/hgl/GLRendererRoster.cpp
T
Alexander von Gluck IV 61ef697afc haiku libGL: Move from gallium target to src/hgl
* The Haiku renderers need to link to libGL to function properly
  in all usage contexts. As mesa drivers build before gallium
  targets, we couldn't properly link the mesa swrast driver to
  the gallium libGL target for Haiku.
* This is likely better as it mimics how glx is laid out ensuring
  the Haiku libGL is better understood.
* All renderers properly link in libGL now.

Acked-by: Brian Paul <brianp@vmware.com>
2014-01-06 15:50:21 -06:00

225 lines
4.9 KiB
C++

/*
* 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 <String.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, &parameterLength) == 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, &parameterLength) == 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);
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);
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;
}