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