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 (at) free.fr> 7 * Alexander von Gluck IV <kallisti5 (at) 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 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, ¶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 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_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 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 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 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