Home | History | Annotate | Download | only in hgl
      1 /*
      2  * Copyright 2006-2012 Haiku, Inc. All Rights Reserved.
      3  * Distributed under the terms of the MIT License.
      4  *
      5  * Authors:
      6  *		Philippe Houdoin <philippe.houdoin (at) free.fr>
      7  *		Alexander von Gluck IV <kallisti5 (at) unixzen.com>
      8  */
      9 
     10 
     11 #include <driver_settings.h>
     12 #include <image.h>
     13 
     14 #include <kernel/image.h>
     15 #include <system/safemode_defs.h>
     16 
     17 #include <Directory.h>
     18 #include <FindDirectory.h>
     19 #include <Path.h>
     20 #include <strings.h>
     21 #include "GLDispatcher.h"
     22 #include "GLRendererRoster.h"
     23 
     24 #include <new>
     25 #include <string.h>
     26 
     27 
     28 extern "C" status_t _kern_get_safemode_option(const char* parameter,
     29 	char* buffer, size_t* _bufferSize);
     30 
     31 
     32 GLRendererRoster::GLRendererRoster(BGLView* view, ulong options)
     33 	:
     34 	fNextID(0),
     35 	fView(view),
     36 	fOptions(options),
     37 	fSafeMode(false),
     38 	fABISubDirectory(NULL)
     39 {
     40 	char parameter[32];
     41 	size_t parameterLength = sizeof(parameter);
     42 
     43 	if (_kern_get_safemode_option(B_SAFEMODE_SAFE_MODE,
     44 		parameter, &parameterLength) == B_OK) {
     45 		if (!strcasecmp(parameter, "enabled") || !strcasecmp(parameter, "on")
     46 			|| !strcasecmp(parameter, "true") || !strcasecmp(parameter, "yes")
     47 			|| !strcasecmp(parameter, "enable") || !strcmp(parameter, "1"))
     48 			fSafeMode = true;
     49 	}
     50 
     51 	if (_kern_get_safemode_option(B_SAFEMODE_DISABLE_USER_ADD_ONS,
     52 		parameter, &parameterLength) == B_OK) {
     53 		if (!strcasecmp(parameter, "enabled") || !strcasecmp(parameter, "on")
     54 			|| !strcasecmp(parameter, "true") || !strcasecmp(parameter, "yes")
     55 			|| !strcasecmp(parameter, "enable") || !strcmp(parameter, "1"))
     56 			fSafeMode = true;
     57 	}
     58 
     59 	// We might run in compatibility mode on a system with a different ABI. The
     60 	// renderers matching our ABI can usually be found in respective
     61 	// subdirectories of the opengl add-ons directories.
     62 	system_info info;
     63 	if (get_system_info(&info) == B_OK
     64 		&& (info.abi & B_HAIKU_ABI_MAJOR)
     65 			!= (B_HAIKU_ABI & B_HAIKU_ABI_MAJOR)) {
     66 			switch (B_HAIKU_ABI & B_HAIKU_ABI_MAJOR) {
     67 				case B_HAIKU_ABI_GCC_2:
     68 					fABISubDirectory = "gcc2";
     69 					break;
     70 				case B_HAIKU_ABI_GCC_4:
     71 					fABISubDirectory = "gcc4";
     72 					break;
     73 			}
     74 	}
     75 
     76 	AddDefaultPaths();
     77 }
     78 
     79 
     80 GLRendererRoster::~GLRendererRoster()
     81 {
     82 
     83 }
     84 
     85 
     86 BGLRenderer*
     87 GLRendererRoster::GetRenderer(int32 id)
     88 {
     89 	RendererMap::const_iterator iterator = fRenderers.find(id);
     90 	if (iterator == fRenderers.end())
     91 		return NULL;
     92 
     93 	struct renderer_item item = iterator->second;
     94 	return item.renderer;
     95 }
     96 
     97 
     98 void
     99 GLRendererRoster::AddDefaultPaths()
    100 {
    101 	// add user directories first, so that they can override system renderers
    102 	const directory_which paths[] = {
    103 		B_USER_NONPACKAGED_ADDONS_DIRECTORY,
    104 		B_USER_ADDONS_DIRECTORY,
    105 		B_SYSTEM_ADDONS_DIRECTORY,
    106 	};
    107 
    108 	for (uint32 i = fSafeMode ? 4 : 0;
    109 		i < sizeof(paths) / sizeof(paths[0]); i++) {
    110 		BPath path;
    111 		status_t status = find_directory(paths[i], &path, true);
    112 		if (status == B_OK && path.Append("opengl") == B_OK)
    113 			AddPath(path.Path());
    114 	}
    115 }
    116 
    117 
    118 status_t
    119 GLRendererRoster::AddPath(const char* path)
    120 {
    121 	BDirectory directory(path);
    122 	status_t status = directory.InitCheck();
    123 	if (status < B_OK)
    124 		return status;
    125 
    126 	// if a subdirectory for our ABI exists, use that instead
    127 	if (fABISubDirectory != NULL) {
    128 		BEntry entry(&directory, fABISubDirectory);
    129 		if (entry.IsDirectory()) {
    130 			status = directory.SetTo(&entry);
    131 			if (status != B_OK)
    132 				return status;
    133 		}
    134 	}
    135 
    136 	node_ref nodeRef;
    137 	status = directory.GetNodeRef(&nodeRef);
    138 	if (status < B_OK)
    139 		return status;
    140 
    141 	int32 count = 0;
    142 	int32 files = 0;
    143 
    144 	entry_ref ref;
    145 	BEntry entry;
    146 	while (directory.GetNextRef(&ref) == B_OK) {
    147 		entry.SetTo(&ref, true);
    148 		if (entry.InitCheck() == B_OK && !entry.IsFile())
    149 			continue;
    150 
    151 		if (CreateRenderer(ref) == B_OK)
    152 			count++;
    153 
    154 		files++;
    155 	}
    156 
    157 	if (files != 0 && count == 0)
    158 		return B_BAD_VALUE;
    159 
    160 	return B_OK;
    161 }
    162 
    163 
    164 status_t
    165 GLRendererRoster::AddRenderer(BGLRenderer* renderer,
    166 	image_id image, const entry_ref* ref, ino_t node)
    167 {
    168 	renderer_item item;
    169 	item.renderer = renderer;
    170 	item.image = image;
    171 	item.node = node;
    172 	if (ref != NULL)
    173 		item.ref = *ref;
    174 
    175 	try {
    176 		fRenderers[fNextID] = item;
    177 	} catch (...) {
    178 		return B_NO_MEMORY;
    179 	}
    180 
    181 	renderer->fOwningRoster = this;
    182 	renderer->fID = fNextID++;
    183 	return B_OK;
    184 }
    185 
    186 
    187 status_t
    188 GLRendererRoster::CreateRenderer(const entry_ref& ref)
    189 {
    190 	BEntry entry(&ref, true);
    191 	node_ref nodeRef;
    192 	status_t status = entry.GetNodeRef(&nodeRef);
    193 	if (status < B_OK)
    194 		return status;
    195 
    196 	BPath path(&ref);
    197 	image_id image = load_add_on(path.Path());
    198 	if (image < B_OK)
    199 		return image;
    200 
    201 	BGLRenderer* (*instantiate_renderer)
    202 		(BGLView* view, ulong options, BGLDispatcher* dispatcher);
    203 
    204 	status = get_image_symbol(image, "instantiate_gl_renderer",
    205 		B_SYMBOL_TYPE_TEXT, (void**)&instantiate_renderer);
    206 	if (status == B_OK) {
    207 		BGLRenderer* renderer
    208 			= instantiate_renderer(fView, fOptions, new BGLDispatcher());
    209 		if (!renderer) {
    210 			unload_add_on(image);
    211 			return B_UNSUPPORTED;
    212 		}
    213 
    214 		if (AddRenderer(renderer, image, &ref, nodeRef.node) != B_OK) {
    215 			renderer->Release();
    216 			// this will delete the renderer
    217 			unload_add_on(image);
    218 		}
    219 		return B_OK;
    220 	}
    221 	unload_add_on(image);
    222 
    223 	return status;
    224 }
    225