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