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 */ 8 9 10#include <driver_settings.h> 11#include <image.h> 12#include <safemode_defs.h> 13 14#include <Directory.h> 15#include <FindDirectory.h> 16#include <Path.h> 17#include <String.h> 18#include "GLDispatcher.h" 19#include "GLRendererRoster.h" 20 21#include <new> 22#include <string.h> 23 24 25extern "C" status_t _kern_get_safemode_option(const char* parameter, 26 char* buffer, size_t* _bufferSize); 27 28 29GLRendererRoster::GLRendererRoster(BGLView* view, ulong options) 30 : 31 fNextID(0), 32 fView(view), 33 fOptions(options), 34 fSafeMode(false), 35 fABISubDirectory(NULL) 36{ 37 char parameter[32]; 38 size_t parameterLength = sizeof(parameter); 39 40 if (_kern_get_safemode_option(B_SAFEMODE_SAFE_MODE, 41 parameter, ¶meterLength) == B_OK) { 42 if (!strcasecmp(parameter, "enabled") || !strcasecmp(parameter, "on") 43 || !strcasecmp(parameter, "true") || !strcasecmp(parameter, "yes") 44 || !strcasecmp(parameter, "enable") || !strcmp(parameter, "1")) 45 fSafeMode = true; 46 } 47 48 if (_kern_get_safemode_option(B_SAFEMODE_DISABLE_USER_ADD_ONS, 49 parameter, ¶meterLength) == B_OK) { 50 if (!strcasecmp(parameter, "enabled") || !strcasecmp(parameter, "on") 51 || !strcasecmp(parameter, "true") || !strcasecmp(parameter, "yes") 52 || !strcasecmp(parameter, "enable") || !strcmp(parameter, "1")) 53 fSafeMode = true; 54 } 55 56 // We might run in compatibility mode on a system with a different ABI. The 57 // renderers matching our ABI can usually be found in respective 58 // subdirectories of the opengl add-ons directories. 59 system_info info; 60 if (get_system_info(&info) == B_OK 61 && (info.abi & B_HAIKU_ABI_MAJOR) 62 != (B_HAIKU_ABI & B_HAIKU_ABI_MAJOR)) { 63 switch (B_HAIKU_ABI & B_HAIKU_ABI_MAJOR) { 64 case B_HAIKU_ABI_GCC_2: 65 fABISubDirectory = "gcc2"; 66 break; 67 case B_HAIKU_ABI_GCC_4: 68 fABISubDirectory = "gcc4"; 69 break; 70 } 71 } 72 73 AddDefaultPaths(); 74} 75 76 77GLRendererRoster::~GLRendererRoster() 78{ 79 80} 81 82 83BGLRenderer* 84GLRendererRoster::GetRenderer(int32 id) 85{ 86 RendererMap::const_iterator iterator = fRenderers.find(id); 87 if (iterator == fRenderers.end()) 88 return NULL; 89 90 struct renderer_item item = iterator->second; 91 return item.renderer; 92} 93 94 95void 96GLRendererRoster::AddDefaultPaths() 97{ 98 // add user directories first, so that they can override system renderers 99 const directory_which paths[] = { 100 B_USER_ADDONS_DIRECTORY, 101 B_COMMON_ADDONS_DIRECTORY, 102 B_SYSTEM_ADDONS_DIRECTORY, 103 }; 104 105 for (uint32 i = fSafeMode ? 4 : 0; 106 i < sizeof(paths) / sizeof(paths[0]); i++) { 107 BPath path; 108 status_t status = find_directory(paths[i], &path, true); 109 if (status == B_OK && path.Append("opengl") == B_OK) 110 AddPath(path.Path()); 111 } 112} 113 114 115status_t 116GLRendererRoster::AddPath(const char* path) 117{ 118 BDirectory directory(path); 119 status_t status = directory.InitCheck(); 120 if (status < B_OK) 121 return status; 122 123 // if a subdirectory for our ABI exists, use that instead 124 if (fABISubDirectory != NULL) { 125 BEntry entry(&directory, fABISubDirectory); 126 if (entry.IsDirectory()) { 127 status = directory.SetTo(&entry); 128 if (status != B_OK) 129 return status; 130 } 131 } 132 133 node_ref nodeRef; 134 status = directory.GetNodeRef(&nodeRef); 135 if (status < B_OK) 136 return status; 137 138 int32 count = 0; 139 int32 files = 0; 140 141 entry_ref ref; 142 BEntry entry; 143 while (directory.GetNextRef(&ref) == B_OK) { 144 entry.SetTo(&ref); 145 if (entry.InitCheck() == B_OK && !entry.IsFile()) 146 continue; 147 148 if (CreateRenderer(ref) == B_OK) 149 count++; 150 151 files++; 152 } 153 154 if (files != 0 && count == 0) 155 return B_BAD_VALUE; 156 157 return B_OK; 158} 159 160 161status_t 162GLRendererRoster::AddRenderer(BGLRenderer* renderer, 163 image_id image, const entry_ref* ref, ino_t node) 164{ 165 renderer_item item; 166 item.renderer = renderer; 167 item.image = image; 168 item.node = node; 169 if (ref != NULL) 170 item.ref = *ref; 171 172 try { 173 fRenderers[fNextID] = item; 174 } catch (...) { 175 return B_NO_MEMORY; 176 } 177 178 renderer->fOwningRoster = this; 179 renderer->fID = fNextID++; 180 return B_OK; 181} 182 183 184status_t 185GLRendererRoster::CreateRenderer(const entry_ref& ref) 186{ 187 BEntry entry(&ref); 188 node_ref nodeRef; 189 status_t status = entry.GetNodeRef(&nodeRef); 190 if (status < B_OK) 191 return status; 192 193 BPath path(&ref); 194 image_id image = load_add_on(path.Path()); 195 if (image < B_OK) 196 return image; 197 198 BGLRenderer* (*instantiate_renderer) 199 (BGLView* view, ulong options, BGLDispatcher* dispatcher); 200 201 status = get_image_symbol(image, "instantiate_gl_renderer", 202 B_SYMBOL_TYPE_TEXT, (void**)&instantiate_renderer); 203 if (status == B_OK) { 204 BGLRenderer* renderer 205 = instantiate_renderer(fView, fOptions, new BGLDispatcher()); 206 if (!renderer) { 207 unload_add_on(image); 208 return B_UNSUPPORTED; 209 } 210 211 if (AddRenderer(renderer, image, &ref, nodeRef.node) != B_OK) { 212 renderer->Release(); 213 // this will delete the renderer 214 unload_add_on(image); 215 } 216 return B_OK; 217 } 218 unload_add_on(image); 219 220 return status; 221} 222