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, ¶meterLength) == 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, ¶meterLength) == 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