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 28extern "C" status_t _kern_get_safemode_option(const char* parameter, 29 char* buffer, size_t* _bufferSize); 30 31GLRendererRoster *GLRendererRoster::fInstance = NULL; 32 33GLRendererRoster *GLRendererRoster::Roster() 34{ 35 if (fInstance == NULL) { 36 fInstance = new GLRendererRoster(); 37 } 38 return fInstance; 39} 40 41GLRendererRoster::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 86GLRendererRoster::~GLRendererRoster() 87{ 88 89} 90 91 92BGLRenderer* 93GLRendererRoster::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 109void 110GLRendererRoster::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 130status_t 131GLRendererRoster::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 176status_t 177GLRendererRoster::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 197status_t 198GLRendererRoster::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