haiku: Build Haiku's libGL from within Mesa
[mesa.git] / src / gallium / targets / libgl-haiku / GLRendererRoster.cpp
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 <system/safemode_defs.h>
16
17 #include <Directory.h>
18 #include <FindDirectory.h>
19 #include <Path.h>
20 #include <String.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_COMMON_NONPACKAGED_ADDONS_DIRECTORY,
106 B_COMMON_ADDONS_DIRECTORY,
107 B_SYSTEM_ADDONS_DIRECTORY,
108 };
109
110 for (uint32 i = fSafeMode ? 4 : 0;
111 i < sizeof(paths) / sizeof(paths[0]); i++) {
112 BPath path;
113 status_t status = find_directory(paths[i], &path, true);
114 if (status == B_OK && path.Append("opengl") == B_OK)
115 AddPath(path.Path());
116 }
117 }
118
119
120 status_t
121 GLRendererRoster::AddPath(const char* path)
122 {
123 BDirectory directory(path);
124 status_t status = directory.InitCheck();
125 if (status < B_OK)
126 return status;
127
128 // if a subdirectory for our ABI exists, use that instead
129 if (fABISubDirectory != NULL) {
130 BEntry entry(&directory, fABISubDirectory);
131 if (entry.IsDirectory()) {
132 status = directory.SetTo(&entry);
133 if (status != B_OK)
134 return status;
135 }
136 }
137
138 node_ref nodeRef;
139 status = directory.GetNodeRef(&nodeRef);
140 if (status < B_OK)
141 return status;
142
143 int32 count = 0;
144 int32 files = 0;
145
146 entry_ref ref;
147 BEntry entry;
148 while (directory.GetNextRef(&ref) == B_OK) {
149 entry.SetTo(&ref);
150 if (entry.InitCheck() == B_OK && !entry.IsFile())
151 continue;
152
153 if (CreateRenderer(ref) == B_OK)
154 count++;
155
156 files++;
157 }
158
159 if (files != 0 && count == 0)
160 return B_BAD_VALUE;
161
162 return B_OK;
163 }
164
165
166 status_t
167 GLRendererRoster::AddRenderer(BGLRenderer* renderer,
168 image_id image, const entry_ref* ref, ino_t node)
169 {
170 renderer_item item;
171 item.renderer = renderer;
172 item.image = image;
173 item.node = node;
174 if (ref != NULL)
175 item.ref = *ref;
176
177 try {
178 fRenderers[fNextID] = item;
179 } catch (...) {
180 return B_NO_MEMORY;
181 }
182
183 renderer->fOwningRoster = this;
184 renderer->fID = fNextID++;
185 return B_OK;
186 }
187
188
189 status_t
190 GLRendererRoster::CreateRenderer(const entry_ref& ref)
191 {
192 BEntry entry(&ref);
193 node_ref nodeRef;
194 status_t status = entry.GetNodeRef(&nodeRef);
195 if (status < B_OK)
196 return status;
197
198 BPath path(&ref);
199 image_id image = load_add_on(path.Path());
200 if (image < B_OK)
201 return image;
202
203 BGLRenderer* (*instantiate_renderer)
204 (BGLView* view, ulong options, BGLDispatcher* dispatcher);
205
206 status = get_image_symbol(image, "instantiate_gl_renderer",
207 B_SYMBOL_TYPE_TEXT, (void**)&instantiate_renderer);
208 if (status == B_OK) {
209 BGLRenderer* renderer
210 = instantiate_renderer(fView, fOptions, new BGLDispatcher());
211 if (!renderer) {
212 unload_add_on(image);
213 return B_UNSUPPORTED;
214 }
215
216 if (AddRenderer(renderer, image, &ref, nodeRef.node) != B_OK) {
217 renderer->Release();
218 // this will delete the renderer
219 unload_add_on(image);
220 }
221 return B_OK;
222 }
223 unload_add_on(image);
224
225 return status;
226 }