1/* 2 * Copyright 2006-2012, Haiku, Inc. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Jérôme Duval, korli@users.berlios.de 7 * Philippe Houdoin, philippe.houdoin@free.fr 8 * Artur Wyszynski, harakash@gmail.com 9 * Alexander von Gluck IV, kallisti5@unixzen.com 10 */ 11 12 13#include "SoftwareRenderer.h" 14 15#include <Autolock.h> 16#include <interface/DirectWindowPrivate.h> 17#include <GraphicsDefs.h> 18#include <Screen.h> 19#include <stdio.h> 20#include <sys/time.h> 21#include <new> 22 23 24#ifdef DEBUG 25# define TRACE(x...) printf("SoftwareRenderer: " x) 26# define CALLED() TRACE("CALLED: %s\n", __PRETTY_FUNCTION__) 27#else 28# define TRACE(x...) 29# define CALLED() 30#endif 31#define ERROR(x...) printf("SoftwareRenderer: " x) 32 33 34extern const char* color_space_name(color_space space); 35 36 37extern "C" _EXPORT BGLRenderer* 38instantiate_gl_renderer(BGLView *view, ulong opts, BGLDispatcher *dispatcher) 39{ 40 return new SoftwareRenderer(view, opts, dispatcher); 41} 42 43SoftwareRenderer::SoftwareRenderer(BGLView *view, ulong options, 44 BGLDispatcher* dispatcher) 45 : 46 BGLRenderer(view, options, dispatcher), 47 fBitmap(NULL), 48 fDirectModeEnabled(false), 49 fInfo(NULL), 50 fInfoLocker("info locker"), 51 fOptions(options), 52 fColorSpace(B_NO_COLOR_SPACE) 53{ 54 CALLED(); 55 56 // Disable double buffer for the moment. 57 //options &= ~BGL_DOUBLE; 58 59 // Initialize the "Haiku Software GL Pipe" 60 time_t beg; 61 time_t end; 62 beg = time(NULL); 63 fContextObj = new GalliumContext(options); 64 end = time(NULL); 65 TRACE("Haiku Software GL Pipe initialization time: %f.\n", 66 difftime(end, beg)); 67 68 // Allocate a bitmap 69 BRect b = view->Bounds(); 70 fColorSpace = BScreen(view->Window()).ColorSpace(); 71 TRACE("%s: Colorspace:\t%s\n", __func__, color_space_name(fColorSpace)); 72 73 fWidth = (GLint)b.IntegerWidth(); 74 fHeight = (GLint)b.IntegerHeight(); 75 76 _AllocateBitmap(); 77 78 // Initialize the first "Haiku Software GL Pipe" context 79 beg = time(NULL); 80 fContextID = fContextObj->CreateContext(fBitmap); 81 end = time(NULL); 82 83 if (fContextID < 0) 84 ERROR("%s: There was an error creating the context!\n", __func__); 85 else { 86 TRACE("%s: Haiku Software GL Pipe context creation time: %f.\n", 87 __func__, difftime(end, beg)); 88 } 89 90 if (!fContextObj->GetCurrentContext()) 91 LockGL(); 92} 93 94 95SoftwareRenderer::~SoftwareRenderer() 96{ 97 CALLED(); 98 99 if (fContextObj) 100 delete fContextObj; 101 if (fBitmap) 102 delete fBitmap; 103} 104 105 106void 107SoftwareRenderer::LockGL() 108{ 109// CALLED(); 110 BGLRenderer::LockGL(); 111 112 color_space cs = BScreen(GLView()->Window()).ColorSpace(); 113 114 BAutolock lock(fInfoLocker); 115 if (fDirectModeEnabled && fInfo != NULL) { 116 fWidth = fInfo->window_bounds.right - fInfo->window_bounds.left; 117 fHeight = fInfo->window_bounds.bottom - fInfo->window_bounds.top; 118 } 119 120 if (fBitmap && cs == fColorSpace && fContextObj->Validate(fWidth, fHeight)) { 121 fContextObj->SetCurrentContext(fBitmap, fContextID); 122 return; 123 } 124 125 fColorSpace = cs; 126 127 _AllocateBitmap(); 128 fContextObj->SetCurrentContext(fBitmap, fContextID); 129} 130 131 132void 133SoftwareRenderer::UnlockGL() 134{ 135// CALLED(); 136 if ((fOptions & BGL_DOUBLE) == 0) { 137 SwapBuffers(); 138 } 139 fContextObj->SetCurrentContext(NULL, fContextID); 140 BGLRenderer::UnlockGL(); 141} 142 143 144void 145SoftwareRenderer::SwapBuffers(bool vsync) 146{ 147// CALLED(); 148 if (!fBitmap) 149 return; 150 151 BScreen screen(GLView()->Window()); 152 153 fContextObj->SwapBuffers(fContextID); 154 155 BAutolock lock(fInfoLocker); 156 157 if (!fDirectModeEnabled || fInfo == NULL) { 158 if (GLView()->LockLooperWithTimeout(1000) == B_OK) { 159 GLView()->DrawBitmap(fBitmap, B_ORIGIN); 160 GLView()->UnlockLooper(); 161 if (vsync) 162 screen.WaitForRetrace(); 163 } 164 return; 165 } 166 167 // check the bitmap size still matches the size 168 if (fInfo->window_bounds.bottom - fInfo->window_bounds.top 169 != fBitmap->Bounds().IntegerHeight() 170 || fInfo->window_bounds.right - fInfo->window_bounds.left 171 != fBitmap->Bounds().IntegerWidth()) { 172 ERROR("%s: Bitmap size doesn't match size!\n", __func__); 173 return; 174 } 175 176 uint32 bytesPerRow = fBitmap->BytesPerRow(); 177 uint8 bytesPerPixel = bytesPerRow / fBitmap->Bounds().IntegerWidth(); 178 179 for (uint32 i = 0; i < fInfo->clip_list_count; i++) { 180 clipping_rect *clip = &fInfo->clip_list[i]; 181 int32 height = clip->bottom - clip->top + 1; 182 int32 bytesWidth 183 = (clip->right - clip->left + 1) * bytesPerPixel; 184 bytesWidth -= bytesPerPixel; 185 uint8 *p = (uint8 *)fInfo->bits + clip->top 186 * fInfo->bytes_per_row + clip->left * bytesPerPixel; 187 uint8 *b = (uint8 *)fBitmap->Bits() 188 + (clip->top - fInfo->window_bounds.top) * bytesPerRow 189 + (clip->left - fInfo->window_bounds.left) * bytesPerPixel; 190 191 for (int y = 0; y < height - 1; y++) { 192 memcpy(p, b, bytesWidth); 193 p += fInfo->bytes_per_row; 194 b += bytesPerRow; 195 } 196 } 197 198 if (vsync) 199 screen.WaitForRetrace(); 200} 201 202 203void 204SoftwareRenderer::Draw(BRect updateRect) 205{ 206// CALLED(); 207 if ((!fDirectModeEnabled || fInfo == NULL) && fBitmap) 208 GLView()->DrawBitmap(fBitmap, updateRect, updateRect); 209} 210 211 212status_t 213SoftwareRenderer::CopyPixelsOut(BPoint location, BBitmap *bitmap) 214{ 215 CALLED(); 216 color_space scs = fBitmap->ColorSpace(); 217 color_space dcs = bitmap->ColorSpace(); 218 219 if (scs != dcs && (scs != B_RGBA32 || dcs != B_RGB32)) { 220 ERROR("%s::CopyPixelsOut(): incompatible color space: %s != %s\n", 221 __PRETTY_FUNCTION__, color_space_name(scs), color_space_name(dcs)); 222 return B_BAD_TYPE; 223 } 224 225 BRect sr = fBitmap->Bounds(); 226 BRect dr = bitmap->Bounds(); 227 228// int32 w1 = sr.IntegerWidth(); 229// int32 h1 = sr.IntegerHeight(); 230// int32 w2 = dr.IntegerWidth(); 231// int32 h2 = dr.IntegerHeight(); 232 233 sr = sr & dr.OffsetBySelf(location); 234 dr = sr.OffsetByCopy(-location.x, -location.y); 235 236 uint8 *ps = (uint8 *) fBitmap->Bits(); 237 uint8 *pd = (uint8 *) bitmap->Bits(); 238 uint32 *s, *d; 239 uint32 y; 240 for (y = (uint32) sr.top; y <= (uint32) sr.bottom; y++) { 241 s = (uint32 *)(ps + y * fBitmap->BytesPerRow()); 242 s += (uint32) sr.left; 243 244 d = (uint32 *)(pd + (y + (uint32)(dr.top - sr.top)) 245 * bitmap->BytesPerRow()); 246 d += (uint32) dr.left; 247 memcpy(d, s, dr.IntegerWidth() * 4); 248 } 249 250 return B_OK; 251} 252 253 254status_t 255SoftwareRenderer::CopyPixelsIn(BBitmap *bitmap, BPoint location) 256{ 257 CALLED(); 258 259 color_space sourceCS = bitmap->ColorSpace(); 260 color_space destinationCS = fBitmap->ColorSpace(); 261 262 if (sourceCS != destinationCS 263 && (sourceCS != B_RGB32 || destinationCS != B_RGBA32)) { 264 ERROR("%s::CopyPixelsIn(): incompatible color space: %s != %s\n", 265 __PRETTY_FUNCTION__, color_space_name(sourceCS), 266 color_space_name(destinationCS)); 267 return B_BAD_TYPE; 268 } 269 270 BRect sr = bitmap->Bounds(); 271 BRect dr = fBitmap->Bounds(); 272 273 sr = sr & dr.OffsetBySelf(location); 274 dr = sr.OffsetByCopy(-location.x, -location.y); 275 276 uint8 *ps = (uint8 *) bitmap->Bits(); 277 uint8 *pd = (uint8 *) fBitmap->Bits(); 278 uint32 *s, *d; 279 uint32 y; 280 281 for (y = (uint32) sr.top; y <= (uint32) sr.bottom; y++) { 282 s = (uint32 *)(ps + y * bitmap->BytesPerRow()); 283 s += (uint32) sr.left; 284 285 d = (uint32 *)(pd + (y + (uint32)(dr.top - sr.top)) 286 * fBitmap->BytesPerRow()); 287 d += (uint32) dr.left; 288 289 memcpy(d, s, dr.IntegerWidth() * 4); 290 } 291 292 return B_OK; 293} 294 295 296void 297SoftwareRenderer::EnableDirectMode(bool enabled) 298{ 299 fDirectModeEnabled = enabled; 300} 301 302 303void 304SoftwareRenderer::DirectConnected(direct_buffer_info *info) 305{ 306// CALLED(); 307 BAutolock lock(fInfoLocker); 308 if (info) { 309 if (!fInfo) { 310 fInfo = (direct_buffer_info *)calloc(1, 311 DIRECT_BUFFER_INFO_AREA_SIZE); 312 } 313 memcpy(fInfo, info, DIRECT_BUFFER_INFO_AREA_SIZE); 314 } else if (fInfo) { 315 free(fInfo); 316 fInfo = NULL; 317 } 318} 319 320 321void 322SoftwareRenderer::FrameResized(float width, float height) 323{ 324 TRACE("%s: %f x %f\n", __func__, width, height); 325 326 BAutolock lock(fInfoLocker); 327 fWidth = (GLuint)width; 328 fHeight = (GLuint)height; 329} 330 331 332void 333SoftwareRenderer::_AllocateBitmap() 334{ 335// CALLED(); 336 337 // allocate new size of back buffer bitmap 338 BAutolock lock(fInfoLocker); 339 if (fBitmap) 340 delete fBitmap; 341 342 if (fWidth < 1 || fHeight < 1) { 343 TRACE("%s: Can't allocate bitmap of %dx%d\n", __func__, 344 fWidth, fHeight); 345 return; 346 } 347 BRect rect(0.0, 0.0, fWidth, fHeight); 348 fBitmap = new (std::nothrow) BBitmap(rect, fColorSpace); 349 if (fBitmap == NULL) { 350 TRACE("%s: Can't create bitmap!\n", __func__); 351 return; 352 } 353 354 TRACE("%s: New bitmap size: %" B_PRId32 " x %" B_PRId32 "\n", __func__, 355 fBitmap->Bounds().IntegerWidth(), fBitmap->Bounds().IntegerHeight()); 356 357#if 0 358 // debug.. 359 void *data = fBitmap->Bits(); 360 memset(data, 0xcc, fBitmap->BitsLength()); 361#endif 362} 363