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