1af69d88dSmrg/* 2af69d88dSmrg * Copyright 2006-2012, Haiku, Inc. All rights reserved. 3af69d88dSmrg * Distributed under the terms of the MIT License. 4af69d88dSmrg * 5af69d88dSmrg * Authors: 6af69d88dSmrg * Jérôme Duval, korli@users.berlios.de 7af69d88dSmrg * Philippe Houdoin, philippe.houdoin@free.fr 8af69d88dSmrg * Artur Wyszynski, harakash@gmail.com 9af69d88dSmrg * Alexander von Gluck IV, kallisti5@unixzen.com 10af69d88dSmrg */ 11af69d88dSmrg 12af69d88dSmrg 13af69d88dSmrg#include "SoftwareRenderer.h" 14af69d88dSmrg 15af69d88dSmrg#include <Autolock.h> 16af69d88dSmrg#include <interface/DirectWindowPrivate.h> 17af69d88dSmrg#include <GraphicsDefs.h> 18af69d88dSmrg#include <Screen.h> 19af69d88dSmrg#include <stdio.h> 20af69d88dSmrg#include <sys/time.h> 21af69d88dSmrg#include <new> 22af69d88dSmrg 23af69d88dSmrg 24af69d88dSmrg#ifdef DEBUG 25af69d88dSmrg# define TRACE(x...) printf("SoftwareRenderer: " x) 26af69d88dSmrg# define CALLED() TRACE("CALLED: %s\n", __PRETTY_FUNCTION__) 27af69d88dSmrg#else 28af69d88dSmrg# define TRACE(x...) 29af69d88dSmrg# define CALLED() 30af69d88dSmrg#endif 31af69d88dSmrg#define ERROR(x...) printf("SoftwareRenderer: " x) 32af69d88dSmrg 33af69d88dSmrg 34af69d88dSmrgextern const char* color_space_name(color_space space); 35af69d88dSmrg 36af69d88dSmrg 37af69d88dSmrgextern "C" _EXPORT BGLRenderer* 387ec681f3Smrginstantiate_gl_renderer(BGLView *view, ulong opts) 39af69d88dSmrg{ 407ec681f3Smrg return new SoftwareRenderer(view, opts); 41af69d88dSmrg} 42af69d88dSmrg 437ec681f3Smrgstruct RasBuf32 447ec681f3Smrg{ 457ec681f3Smrg int32 width, height, stride; 467ec681f3Smrg int32 orgX, orgY; 477ec681f3Smrg int32 *colors; 487ec681f3Smrg 497ec681f3Smrg RasBuf32(int32 width, int32 height, int32 stride, int32 orgX, int32 orgY, int32 *colors): 507ec681f3Smrg width(width), height(height), stride(stride), orgX(orgX), orgY(orgY), colors(colors) 517ec681f3Smrg {} 527ec681f3Smrg 537ec681f3Smrg RasBuf32(BBitmap *bmp) 547ec681f3Smrg { 557ec681f3Smrg width = bmp->Bounds().IntegerWidth() + 1; 567ec681f3Smrg height = bmp->Bounds().IntegerHeight() + 1; 577ec681f3Smrg stride = bmp->BytesPerRow()/4; 587ec681f3Smrg orgX = 0; 597ec681f3Smrg orgY = 0; 607ec681f3Smrg colors = (int32*)bmp->Bits(); 617ec681f3Smrg } 627ec681f3Smrg 637ec681f3Smrg RasBuf32(direct_buffer_info *info) 647ec681f3Smrg { 657ec681f3Smrg width = 0x7fffffff; 667ec681f3Smrg height = 0x7fffffff; 677ec681f3Smrg stride = info->bytes_per_row/4; 687ec681f3Smrg orgX = 0; 697ec681f3Smrg orgY = 0; 707ec681f3Smrg colors = (int32*)info->bits; 717ec681f3Smrg } 727ec681f3Smrg 737ec681f3Smrg void ClipSize(int32 x, int32 y, int32 w, int32 h) 747ec681f3Smrg { 757ec681f3Smrg if (x < 0) {w += x; x = 0;} 767ec681f3Smrg if (y < 0) {h += y; y = 0;} 777ec681f3Smrg if (x + w > width) {w = width - x;} 787ec681f3Smrg if (y + h > height) {h = height - y;} 797ec681f3Smrg if ((w > 0) && (h > 0)) { 807ec681f3Smrg colors += y*stride + x; 817ec681f3Smrg width = w; 827ec681f3Smrg height = h; 837ec681f3Smrg } else { 847ec681f3Smrg width = 0; height = 0; colors = NULL; 857ec681f3Smrg } 867ec681f3Smrg if (x + orgX > 0) {orgX += x;} else {orgX = 0;} 877ec681f3Smrg if (y + orgY > 0) {orgY += y;} else {orgY = 0;} 887ec681f3Smrg } 897ec681f3Smrg 907ec681f3Smrg void ClipRect(int32 l, int32 t, int32 r, int32 b) 917ec681f3Smrg { 927ec681f3Smrg ClipSize(l, t, r - l, b - t); 937ec681f3Smrg } 947ec681f3Smrg 957ec681f3Smrg void Shift(int32 dx, int32 dy) 967ec681f3Smrg { 977ec681f3Smrg orgX += dx; 987ec681f3Smrg orgY += dy; 997ec681f3Smrg } 1007ec681f3Smrg 1017ec681f3Smrg void Clear(int32 color) 1027ec681f3Smrg { 1037ec681f3Smrg RasBuf32 dst = *this; 1047ec681f3Smrg dst.stride -= dst.width; 1057ec681f3Smrg for (; dst.height > 0; dst.height--) { 1067ec681f3Smrg for (int32 i = dst.width; i > 0; i--) 1077ec681f3Smrg *dst.colors++ = color; 1087ec681f3Smrg dst.colors += dst.stride; 1097ec681f3Smrg } 1107ec681f3Smrg } 1117ec681f3Smrg 1127ec681f3Smrg void Blit(RasBuf32 src) 1137ec681f3Smrg { 1147ec681f3Smrg RasBuf32 dst = *this; 1157ec681f3Smrg int32 x, y; 1167ec681f3Smrg x = src.orgX - orgX; 1177ec681f3Smrg y = src.orgY - orgY; 1187ec681f3Smrg dst.ClipSize(x, y, src.width, src.height); 1197ec681f3Smrg src.ClipSize(-x, -y, width, height); 1207ec681f3Smrg for (; dst.height > 0; dst.height--) { 1217ec681f3Smrg memcpy(dst.colors, src.colors, 4*dst.width); 1227ec681f3Smrg dst.colors += dst.stride; 1237ec681f3Smrg src.colors += src.stride; 1247ec681f3Smrg } 1257ec681f3Smrg } 1267ec681f3Smrg}; 1277ec681f3Smrg 1287ec681f3SmrgSoftwareRenderer::SoftwareRenderer(BGLView *view, ulong options) 129af69d88dSmrg : 1307ec681f3Smrg BGLRenderer(view, options), 131af69d88dSmrg fDirectModeEnabled(false), 132af69d88dSmrg fInfo(NULL), 133af69d88dSmrg fInfoLocker("info locker"), 134af69d88dSmrg fOptions(options), 135af69d88dSmrg fColorSpace(B_NO_COLOR_SPACE) 136af69d88dSmrg{ 137af69d88dSmrg CALLED(); 138af69d88dSmrg 139af69d88dSmrg // Initialize the "Haiku Software GL Pipe" 140af69d88dSmrg time_t beg; 141af69d88dSmrg time_t end; 142af69d88dSmrg beg = time(NULL); 143af69d88dSmrg fContextObj = new GalliumContext(options); 144af69d88dSmrg end = time(NULL); 145af69d88dSmrg TRACE("Haiku Software GL Pipe initialization time: %f.\n", 146af69d88dSmrg difftime(end, beg)); 147af69d88dSmrg 148af69d88dSmrg BRect b = view->Bounds(); 149af69d88dSmrg fColorSpace = BScreen(view->Window()).ColorSpace(); 150af69d88dSmrg TRACE("%s: Colorspace:\t%s\n", __func__, color_space_name(fColorSpace)); 151af69d88dSmrg 152af69d88dSmrg fWidth = (GLint)b.IntegerWidth(); 153af69d88dSmrg fHeight = (GLint)b.IntegerHeight(); 154af69d88dSmrg 155af69d88dSmrg // Initialize the first "Haiku Software GL Pipe" context 156af69d88dSmrg beg = time(NULL); 1577ec681f3Smrg fContextID = fContextObj->CreateContext(this); 158af69d88dSmrg end = time(NULL); 159af69d88dSmrg 160af69d88dSmrg if (fContextID < 0) 161af69d88dSmrg ERROR("%s: There was an error creating the context!\n", __func__); 162af69d88dSmrg else { 163af69d88dSmrg TRACE("%s: Haiku Software GL Pipe context creation time: %f.\n", 164af69d88dSmrg __func__, difftime(end, beg)); 165af69d88dSmrg } 166af69d88dSmrg 167af69d88dSmrg if (!fContextObj->GetCurrentContext()) 168af69d88dSmrg LockGL(); 169af69d88dSmrg} 170af69d88dSmrg 171af69d88dSmrg 172af69d88dSmrgSoftwareRenderer::~SoftwareRenderer() 173af69d88dSmrg{ 174af69d88dSmrg CALLED(); 175af69d88dSmrg 176af69d88dSmrg if (fContextObj) 177af69d88dSmrg delete fContextObj; 178af69d88dSmrg} 179af69d88dSmrg 180af69d88dSmrg 181af69d88dSmrgvoid 182af69d88dSmrgSoftwareRenderer::LockGL() 183af69d88dSmrg{ 184af69d88dSmrg// CALLED(); 185af69d88dSmrg BGLRenderer::LockGL(); 186af69d88dSmrg 187af69d88dSmrg color_space cs = BScreen(GLView()->Window()).ColorSpace(); 188af69d88dSmrg 1897ec681f3Smrg { 1907ec681f3Smrg BAutolock lock(fInfoLocker); 1917ec681f3Smrg if (fDirectModeEnabled && fInfo != NULL) { 1927ec681f3Smrg fWidth = fInfo->window_bounds.right - fInfo->window_bounds.left; 1937ec681f3Smrg fHeight = fInfo->window_bounds.bottom - fInfo->window_bounds.top; 1947ec681f3Smrg } 195af69d88dSmrg 1967ec681f3Smrg fContextObj->Validate(fWidth, fHeight); 1977ec681f3Smrg fColorSpace = cs; 198af69d88dSmrg } 199af69d88dSmrg 2007ec681f3Smrg // do not hold fInfoLocker here to avoid deadlock 2017ec681f3Smrg fContextObj->SetCurrentContext(true, fContextID); 202af69d88dSmrg} 203af69d88dSmrg 204af69d88dSmrg 205af69d88dSmrgvoid 206af69d88dSmrgSoftwareRenderer::UnlockGL() 207af69d88dSmrg{ 208af69d88dSmrg// CALLED(); 209af69d88dSmrg if ((fOptions & BGL_DOUBLE) == 0) { 210af69d88dSmrg SwapBuffers(); 211af69d88dSmrg } 2127ec681f3Smrg fContextObj->SetCurrentContext(false, fContextID); 213af69d88dSmrg BGLRenderer::UnlockGL(); 214af69d88dSmrg} 215af69d88dSmrg 216af69d88dSmrg 217af69d88dSmrgvoid 2187ec681f3SmrgSoftwareRenderer::Display(BBitmap *bitmap, BRect *updateRect) 219af69d88dSmrg{ 220af69d88dSmrg// CALLED(); 221af69d88dSmrg 2227ec681f3Smrg if (!fDirectModeEnabled) { 2237ec681f3Smrg // TODO: avoid timeout 224af69d88dSmrg if (GLView()->LockLooperWithTimeout(1000) == B_OK) { 2257ec681f3Smrg GLView()->DrawBitmap(bitmap, B_ORIGIN); 226af69d88dSmrg GLView()->UnlockLooper(); 227af69d88dSmrg } 2287ec681f3Smrg } else { 2297ec681f3Smrg BAutolock lock(fInfoLocker); 2307ec681f3Smrg if (fInfo != NULL) { 2317ec681f3Smrg RasBuf32 srcBuf(bitmap); 2327ec681f3Smrg RasBuf32 dstBuf(fInfo); 2337ec681f3Smrg for (uint32 i = 0; i < fInfo->clip_list_count; i++) { 2347ec681f3Smrg clipping_rect *clip = &fInfo->clip_list[i]; 2357ec681f3Smrg RasBuf32 dstClip = dstBuf; 2367ec681f3Smrg dstClip.ClipRect(clip->left, clip->top, clip->right + 1, clip->bottom + 1); 2377ec681f3Smrg dstClip.Shift(-fInfo->window_bounds.left, -fInfo->window_bounds.top); 2387ec681f3Smrg dstClip.Blit(srcBuf); 2397ec681f3Smrg } 240af69d88dSmrg } 241af69d88dSmrg } 2427ec681f3Smrg} 243af69d88dSmrg 2447ec681f3Smrg 2457ec681f3Smrgvoid 2467ec681f3SmrgSoftwareRenderer::SwapBuffers(bool vsync) 2477ec681f3Smrg{ 2487ec681f3Smrg BScreen screen(GLView()->Window()); 2497ec681f3Smrg fContextObj->SwapBuffers(fContextID); 2507ec681f3Smrg fContextObj->Validate(fWidth, fHeight); 251af69d88dSmrg if (vsync) 252af69d88dSmrg screen.WaitForRetrace(); 253af69d88dSmrg} 254af69d88dSmrg 255af69d88dSmrgvoid 256af69d88dSmrgSoftwareRenderer::Draw(BRect updateRect) 257af69d88dSmrg{ 258af69d88dSmrg// CALLED(); 2597ec681f3Smrg fContextObj->Draw(fContextID, updateRect); 260af69d88dSmrg} 261af69d88dSmrg 262af69d88dSmrg 263af69d88dSmrgstatus_t 264af69d88dSmrgSoftwareRenderer::CopyPixelsOut(BPoint location, BBitmap *bitmap) 265af69d88dSmrg{ 266af69d88dSmrg CALLED(); 267af69d88dSmrg 2687ec681f3Smrg // TODO: implement 2697ec681f3Smrg return B_ERROR; 270af69d88dSmrg} 271af69d88dSmrg 272af69d88dSmrg 273af69d88dSmrgstatus_t 274af69d88dSmrgSoftwareRenderer::CopyPixelsIn(BBitmap *bitmap, BPoint location) 275af69d88dSmrg{ 276af69d88dSmrg CALLED(); 277af69d88dSmrg 2787ec681f3Smrg // TODO: implement 2797ec681f3Smrg return B_ERROR; 280af69d88dSmrg} 281af69d88dSmrg 282af69d88dSmrg 283af69d88dSmrgvoid 284af69d88dSmrgSoftwareRenderer::EnableDirectMode(bool enabled) 285af69d88dSmrg{ 286af69d88dSmrg fDirectModeEnabled = enabled; 287af69d88dSmrg} 288af69d88dSmrg 289af69d88dSmrg 290af69d88dSmrgvoid 291af69d88dSmrgSoftwareRenderer::DirectConnected(direct_buffer_info *info) 292af69d88dSmrg{ 293af69d88dSmrg// CALLED(); 294af69d88dSmrg BAutolock lock(fInfoLocker); 295af69d88dSmrg if (info) { 296af69d88dSmrg if (!fInfo) { 297af69d88dSmrg fInfo = (direct_buffer_info *)calloc(1, 298af69d88dSmrg DIRECT_BUFFER_INFO_AREA_SIZE); 299af69d88dSmrg } 300af69d88dSmrg memcpy(fInfo, info, DIRECT_BUFFER_INFO_AREA_SIZE); 301af69d88dSmrg } else if (fInfo) { 302af69d88dSmrg free(fInfo); 303af69d88dSmrg fInfo = NULL; 304af69d88dSmrg } 305af69d88dSmrg} 306af69d88dSmrg 307af69d88dSmrg 308af69d88dSmrgvoid 309af69d88dSmrgSoftwareRenderer::FrameResized(float width, float height) 310af69d88dSmrg{ 311af69d88dSmrg TRACE("%s: %f x %f\n", __func__, width, height); 312af69d88dSmrg 313af69d88dSmrg BAutolock lock(fInfoLocker); 31401e04c3fSmrg fWidth = (GLuint)width; 31501e04c3fSmrg fHeight = (GLuint)height; 316af69d88dSmrg} 317