1848b8605Smrg/* 2848b8605Smrg * Copyright 2006-2012, Haiku, Inc. All rights reserved. 3848b8605Smrg * Distributed under the terms of the MIT License. 4848b8605Smrg * 5848b8605Smrg * Authors: 6848b8605Smrg * Jérôme Duval, korli@users.berlios.de 7848b8605Smrg * Philippe Houdoin, philippe.houdoin@free.fr 8848b8605Smrg * Artur Wyszynski, harakash@gmail.com 9848b8605Smrg * Alexander von Gluck IV, kallisti5@unixzen.com 10848b8605Smrg */ 11848b8605Smrg 12848b8605Smrg 13848b8605Smrg#include "SoftwareRenderer.h" 14848b8605Smrg 15848b8605Smrg#include <Autolock.h> 16848b8605Smrg#include <interface/DirectWindowPrivate.h> 17848b8605Smrg#include <GraphicsDefs.h> 18848b8605Smrg#include <Screen.h> 19848b8605Smrg#include <stdio.h> 20848b8605Smrg#include <sys/time.h> 21848b8605Smrg#include <new> 22848b8605Smrg 23848b8605Smrg 24848b8605Smrg#ifdef DEBUG 25848b8605Smrg# define TRACE(x...) printf("SoftwareRenderer: " x) 26848b8605Smrg# define CALLED() TRACE("CALLED: %s\n", __PRETTY_FUNCTION__) 27848b8605Smrg#else 28848b8605Smrg# define TRACE(x...) 29848b8605Smrg# define CALLED() 30848b8605Smrg#endif 31848b8605Smrg#define ERROR(x...) printf("SoftwareRenderer: " x) 32848b8605Smrg 33848b8605Smrg 34848b8605Smrgextern const char* color_space_name(color_space space); 35848b8605Smrg 36848b8605Smrg 37848b8605Smrgextern "C" _EXPORT BGLRenderer* 38848b8605Smrginstantiate_gl_renderer(BGLView *view, ulong opts, BGLDispatcher *dispatcher) 39848b8605Smrg{ 40848b8605Smrg return new SoftwareRenderer(view, opts, dispatcher); 41848b8605Smrg} 42848b8605Smrg 43848b8605SmrgSoftwareRenderer::SoftwareRenderer(BGLView *view, ulong options, 44848b8605Smrg BGLDispatcher* dispatcher) 45848b8605Smrg : 46848b8605Smrg BGLRenderer(view, options, dispatcher), 47848b8605Smrg fBitmap(NULL), 48848b8605Smrg fDirectModeEnabled(false), 49848b8605Smrg fInfo(NULL), 50848b8605Smrg fInfoLocker("info locker"), 51848b8605Smrg fOptions(options), 52848b8605Smrg fColorSpace(B_NO_COLOR_SPACE) 53848b8605Smrg{ 54848b8605Smrg CALLED(); 55848b8605Smrg 56848b8605Smrg // Disable double buffer for the moment. 57b8e80941Smrg //options &= ~BGL_DOUBLE; 58848b8605Smrg 59848b8605Smrg // Initialize the "Haiku Software GL Pipe" 60848b8605Smrg time_t beg; 61848b8605Smrg time_t end; 62848b8605Smrg beg = time(NULL); 63848b8605Smrg fContextObj = new GalliumContext(options); 64848b8605Smrg end = time(NULL); 65848b8605Smrg TRACE("Haiku Software GL Pipe initialization time: %f.\n", 66848b8605Smrg difftime(end, beg)); 67848b8605Smrg 68848b8605Smrg // Allocate a bitmap 69848b8605Smrg BRect b = view->Bounds(); 70848b8605Smrg fColorSpace = BScreen(view->Window()).ColorSpace(); 71848b8605Smrg TRACE("%s: Colorspace:\t%s\n", __func__, color_space_name(fColorSpace)); 72848b8605Smrg 73848b8605Smrg fWidth = (GLint)b.IntegerWidth(); 74848b8605Smrg fHeight = (GLint)b.IntegerHeight(); 75848b8605Smrg 76848b8605Smrg _AllocateBitmap(); 77848b8605Smrg 78848b8605Smrg // Initialize the first "Haiku Software GL Pipe" context 79848b8605Smrg beg = time(NULL); 80848b8605Smrg fContextID = fContextObj->CreateContext(fBitmap); 81848b8605Smrg end = time(NULL); 82848b8605Smrg 83848b8605Smrg if (fContextID < 0) 84848b8605Smrg ERROR("%s: There was an error creating the context!\n", __func__); 85848b8605Smrg else { 86848b8605Smrg TRACE("%s: Haiku Software GL Pipe context creation time: %f.\n", 87848b8605Smrg __func__, difftime(end, beg)); 88848b8605Smrg } 89848b8605Smrg 90848b8605Smrg if (!fContextObj->GetCurrentContext()) 91848b8605Smrg LockGL(); 92848b8605Smrg} 93848b8605Smrg 94848b8605Smrg 95848b8605SmrgSoftwareRenderer::~SoftwareRenderer() 96848b8605Smrg{ 97848b8605Smrg CALLED(); 98848b8605Smrg 99848b8605Smrg if (fContextObj) 100848b8605Smrg delete fContextObj; 101848b8605Smrg if (fBitmap) 102848b8605Smrg delete fBitmap; 103848b8605Smrg} 104848b8605Smrg 105848b8605Smrg 106848b8605Smrgvoid 107848b8605SmrgSoftwareRenderer::LockGL() 108848b8605Smrg{ 109848b8605Smrg// CALLED(); 110848b8605Smrg BGLRenderer::LockGL(); 111848b8605Smrg 112848b8605Smrg color_space cs = BScreen(GLView()->Window()).ColorSpace(); 113848b8605Smrg 114848b8605Smrg BAutolock lock(fInfoLocker); 115848b8605Smrg if (fDirectModeEnabled && fInfo != NULL) { 116b8e80941Smrg fWidth = fInfo->window_bounds.right - fInfo->window_bounds.left; 117b8e80941Smrg fHeight = fInfo->window_bounds.bottom - fInfo->window_bounds.top; 118848b8605Smrg } 119848b8605Smrg 120b8e80941Smrg if (fBitmap && cs == fColorSpace && fContextObj->Validate(fWidth, fHeight)) { 121848b8605Smrg fContextObj->SetCurrentContext(fBitmap, fContextID); 122848b8605Smrg return; 123848b8605Smrg } 124848b8605Smrg 125848b8605Smrg fColorSpace = cs; 126848b8605Smrg 127848b8605Smrg _AllocateBitmap(); 128848b8605Smrg fContextObj->SetCurrentContext(fBitmap, fContextID); 129848b8605Smrg} 130848b8605Smrg 131848b8605Smrg 132848b8605Smrgvoid 133848b8605SmrgSoftwareRenderer::UnlockGL() 134848b8605Smrg{ 135848b8605Smrg// CALLED(); 136848b8605Smrg if ((fOptions & BGL_DOUBLE) == 0) { 137848b8605Smrg SwapBuffers(); 138848b8605Smrg } 139848b8605Smrg fContextObj->SetCurrentContext(NULL, fContextID); 140848b8605Smrg BGLRenderer::UnlockGL(); 141848b8605Smrg} 142848b8605Smrg 143848b8605Smrg 144848b8605Smrgvoid 145848b8605SmrgSoftwareRenderer::SwapBuffers(bool vsync) 146848b8605Smrg{ 147848b8605Smrg// CALLED(); 148848b8605Smrg if (!fBitmap) 149848b8605Smrg return; 150848b8605Smrg 151848b8605Smrg BScreen screen(GLView()->Window()); 152848b8605Smrg 153848b8605Smrg fContextObj->SwapBuffers(fContextID); 154848b8605Smrg 155848b8605Smrg BAutolock lock(fInfoLocker); 156848b8605Smrg 157848b8605Smrg if (!fDirectModeEnabled || fInfo == NULL) { 158848b8605Smrg if (GLView()->LockLooperWithTimeout(1000) == B_OK) { 159848b8605Smrg GLView()->DrawBitmap(fBitmap, B_ORIGIN); 160848b8605Smrg GLView()->UnlockLooper(); 161848b8605Smrg if (vsync) 162848b8605Smrg screen.WaitForRetrace(); 163848b8605Smrg } 164848b8605Smrg return; 165848b8605Smrg } 166848b8605Smrg 167848b8605Smrg // check the bitmap size still matches the size 168848b8605Smrg if (fInfo->window_bounds.bottom - fInfo->window_bounds.top 169848b8605Smrg != fBitmap->Bounds().IntegerHeight() 170848b8605Smrg || fInfo->window_bounds.right - fInfo->window_bounds.left 171848b8605Smrg != fBitmap->Bounds().IntegerWidth()) { 172848b8605Smrg ERROR("%s: Bitmap size doesn't match size!\n", __func__); 173848b8605Smrg return; 174848b8605Smrg } 175848b8605Smrg 176848b8605Smrg uint32 bytesPerRow = fBitmap->BytesPerRow(); 177848b8605Smrg uint8 bytesPerPixel = bytesPerRow / fBitmap->Bounds().IntegerWidth(); 178848b8605Smrg 179848b8605Smrg for (uint32 i = 0; i < fInfo->clip_list_count; i++) { 180848b8605Smrg clipping_rect *clip = &fInfo->clip_list[i]; 181848b8605Smrg int32 height = clip->bottom - clip->top + 1; 182848b8605Smrg int32 bytesWidth 183848b8605Smrg = (clip->right - clip->left + 1) * bytesPerPixel; 184848b8605Smrg bytesWidth -= bytesPerPixel; 185848b8605Smrg uint8 *p = (uint8 *)fInfo->bits + clip->top 186848b8605Smrg * fInfo->bytes_per_row + clip->left * bytesPerPixel; 187848b8605Smrg uint8 *b = (uint8 *)fBitmap->Bits() 188848b8605Smrg + (clip->top - fInfo->window_bounds.top) * bytesPerRow 189848b8605Smrg + (clip->left - fInfo->window_bounds.left) * bytesPerPixel; 190848b8605Smrg 191848b8605Smrg for (int y = 0; y < height - 1; y++) { 192848b8605Smrg memcpy(p, b, bytesWidth); 193848b8605Smrg p += fInfo->bytes_per_row; 194848b8605Smrg b += bytesPerRow; 195848b8605Smrg } 196848b8605Smrg } 197848b8605Smrg 198848b8605Smrg if (vsync) 199848b8605Smrg screen.WaitForRetrace(); 200848b8605Smrg} 201848b8605Smrg 202848b8605Smrg 203848b8605Smrgvoid 204848b8605SmrgSoftwareRenderer::Draw(BRect updateRect) 205848b8605Smrg{ 206848b8605Smrg// CALLED(); 207848b8605Smrg if ((!fDirectModeEnabled || fInfo == NULL) && fBitmap) 208848b8605Smrg GLView()->DrawBitmap(fBitmap, updateRect, updateRect); 209848b8605Smrg} 210848b8605Smrg 211848b8605Smrg 212848b8605Smrgstatus_t 213848b8605SmrgSoftwareRenderer::CopyPixelsOut(BPoint location, BBitmap *bitmap) 214848b8605Smrg{ 215848b8605Smrg CALLED(); 216848b8605Smrg color_space scs = fBitmap->ColorSpace(); 217848b8605Smrg color_space dcs = bitmap->ColorSpace(); 218848b8605Smrg 219848b8605Smrg if (scs != dcs && (scs != B_RGBA32 || dcs != B_RGB32)) { 220848b8605Smrg ERROR("%s::CopyPixelsOut(): incompatible color space: %s != %s\n", 221848b8605Smrg __PRETTY_FUNCTION__, color_space_name(scs), color_space_name(dcs)); 222848b8605Smrg return B_BAD_TYPE; 223848b8605Smrg } 224848b8605Smrg 225848b8605Smrg BRect sr = fBitmap->Bounds(); 226848b8605Smrg BRect dr = bitmap->Bounds(); 227848b8605Smrg 228848b8605Smrg// int32 w1 = sr.IntegerWidth(); 229848b8605Smrg// int32 h1 = sr.IntegerHeight(); 230848b8605Smrg// int32 w2 = dr.IntegerWidth(); 231848b8605Smrg// int32 h2 = dr.IntegerHeight(); 232848b8605Smrg 233848b8605Smrg sr = sr & dr.OffsetBySelf(location); 234848b8605Smrg dr = sr.OffsetByCopy(-location.x, -location.y); 235848b8605Smrg 236848b8605Smrg uint8 *ps = (uint8 *) fBitmap->Bits(); 237848b8605Smrg uint8 *pd = (uint8 *) bitmap->Bits(); 238848b8605Smrg uint32 *s, *d; 239848b8605Smrg uint32 y; 240848b8605Smrg for (y = (uint32) sr.top; y <= (uint32) sr.bottom; y++) { 241848b8605Smrg s = (uint32 *)(ps + y * fBitmap->BytesPerRow()); 242848b8605Smrg s += (uint32) sr.left; 243848b8605Smrg 244848b8605Smrg d = (uint32 *)(pd + (y + (uint32)(dr.top - sr.top)) 245848b8605Smrg * bitmap->BytesPerRow()); 246848b8605Smrg d += (uint32) dr.left; 247848b8605Smrg memcpy(d, s, dr.IntegerWidth() * 4); 248848b8605Smrg } 249848b8605Smrg 250848b8605Smrg return B_OK; 251848b8605Smrg} 252848b8605Smrg 253848b8605Smrg 254848b8605Smrgstatus_t 255848b8605SmrgSoftwareRenderer::CopyPixelsIn(BBitmap *bitmap, BPoint location) 256848b8605Smrg{ 257848b8605Smrg CALLED(); 258848b8605Smrg 259848b8605Smrg color_space sourceCS = bitmap->ColorSpace(); 260848b8605Smrg color_space destinationCS = fBitmap->ColorSpace(); 261848b8605Smrg 262848b8605Smrg if (sourceCS != destinationCS 263848b8605Smrg && (sourceCS != B_RGB32 || destinationCS != B_RGBA32)) { 264848b8605Smrg ERROR("%s::CopyPixelsIn(): incompatible color space: %s != %s\n", 265848b8605Smrg __PRETTY_FUNCTION__, color_space_name(sourceCS), 266848b8605Smrg color_space_name(destinationCS)); 267848b8605Smrg return B_BAD_TYPE; 268848b8605Smrg } 269848b8605Smrg 270848b8605Smrg BRect sr = bitmap->Bounds(); 271848b8605Smrg BRect dr = fBitmap->Bounds(); 272848b8605Smrg 273848b8605Smrg sr = sr & dr.OffsetBySelf(location); 274848b8605Smrg dr = sr.OffsetByCopy(-location.x, -location.y); 275848b8605Smrg 276848b8605Smrg uint8 *ps = (uint8 *) bitmap->Bits(); 277848b8605Smrg uint8 *pd = (uint8 *) fBitmap->Bits(); 278848b8605Smrg uint32 *s, *d; 279848b8605Smrg uint32 y; 280848b8605Smrg 281848b8605Smrg for (y = (uint32) sr.top; y <= (uint32) sr.bottom; y++) { 282848b8605Smrg s = (uint32 *)(ps + y * bitmap->BytesPerRow()); 283848b8605Smrg s += (uint32) sr.left; 284848b8605Smrg 285848b8605Smrg d = (uint32 *)(pd + (y + (uint32)(dr.top - sr.top)) 286848b8605Smrg * fBitmap->BytesPerRow()); 287848b8605Smrg d += (uint32) dr.left; 288848b8605Smrg 289848b8605Smrg memcpy(d, s, dr.IntegerWidth() * 4); 290848b8605Smrg } 291848b8605Smrg 292848b8605Smrg return B_OK; 293848b8605Smrg} 294848b8605Smrg 295848b8605Smrg 296848b8605Smrgvoid 297848b8605SmrgSoftwareRenderer::EnableDirectMode(bool enabled) 298848b8605Smrg{ 299848b8605Smrg fDirectModeEnabled = enabled; 300848b8605Smrg} 301848b8605Smrg 302848b8605Smrg 303848b8605Smrgvoid 304848b8605SmrgSoftwareRenderer::DirectConnected(direct_buffer_info *info) 305848b8605Smrg{ 306848b8605Smrg// CALLED(); 307848b8605Smrg BAutolock lock(fInfoLocker); 308848b8605Smrg if (info) { 309848b8605Smrg if (!fInfo) { 310848b8605Smrg fInfo = (direct_buffer_info *)calloc(1, 311848b8605Smrg DIRECT_BUFFER_INFO_AREA_SIZE); 312848b8605Smrg } 313848b8605Smrg memcpy(fInfo, info, DIRECT_BUFFER_INFO_AREA_SIZE); 314848b8605Smrg } else if (fInfo) { 315848b8605Smrg free(fInfo); 316848b8605Smrg fInfo = NULL; 317848b8605Smrg } 318848b8605Smrg} 319848b8605Smrg 320848b8605Smrg 321848b8605Smrgvoid 322848b8605SmrgSoftwareRenderer::FrameResized(float width, float height) 323848b8605Smrg{ 324848b8605Smrg TRACE("%s: %f x %f\n", __func__, width, height); 325848b8605Smrg 326848b8605Smrg BAutolock lock(fInfoLocker); 327b8e80941Smrg fWidth = (GLuint)width; 328b8e80941Smrg fHeight = (GLuint)height; 329848b8605Smrg} 330848b8605Smrg 331848b8605Smrg 332848b8605Smrgvoid 333848b8605SmrgSoftwareRenderer::_AllocateBitmap() 334848b8605Smrg{ 335848b8605Smrg// CALLED(); 336848b8605Smrg 337848b8605Smrg // allocate new size of back buffer bitmap 338848b8605Smrg BAutolock lock(fInfoLocker); 339b8e80941Smrg if (fBitmap) 340b8e80941Smrg delete fBitmap; 341b8e80941Smrg 342848b8605Smrg if (fWidth < 1 || fHeight < 1) { 343848b8605Smrg TRACE("%s: Can't allocate bitmap of %dx%d\n", __func__, 344848b8605Smrg fWidth, fHeight); 345848b8605Smrg return; 346848b8605Smrg } 347848b8605Smrg BRect rect(0.0, 0.0, fWidth, fHeight); 348848b8605Smrg fBitmap = new (std::nothrow) BBitmap(rect, fColorSpace); 349848b8605Smrg if (fBitmap == NULL) { 350848b8605Smrg TRACE("%s: Can't create bitmap!\n", __func__); 351848b8605Smrg return; 352848b8605Smrg } 353848b8605Smrg 354b8e80941Smrg TRACE("%s: New bitmap size: %" B_PRId32 " x %" B_PRId32 "\n", __func__, 355848b8605Smrg fBitmap->Bounds().IntegerWidth(), fBitmap->Bounds().IntegerHeight()); 356848b8605Smrg 357848b8605Smrg#if 0 358848b8605Smrg // debug.. 359848b8605Smrg void *data = fBitmap->Bits(); 360848b8605Smrg memset(data, 0xcc, fBitmap->BitsLength()); 361848b8605Smrg#endif 362848b8605Smrg} 363