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 28extern "C" status_t _kern_get_safemode_option(const char* parameter, 29 char* buffer, size_t* _bufferSize); 30 31 32GLRendererRoster::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, ¶meterLength) == 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, ¶meterLength) == 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 80GLRendererRoster::~GLRendererRoster() 81{ 82 83} 84 85 86BGLRenderer* 87GLRendererRoster::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 98void 99GLRendererRoster::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 118status_t 119GLRendererRoster::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 164status_t 165GLRendererRoster::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 187status_t 188GLRendererRoster::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