| /* |
| * 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; |
| } |