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