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) 39{ 40 return new SoftwareRenderer(view, opts); 41} 42 43struct RasBuf32 44{ 45 int32 width, height, stride; 46 int32 orgX, orgY; 47 int32 *colors; 48 49 RasBuf32(int32 width, int32 height, int32 stride, int32 orgX, int32 orgY, int32 *colors): 50 width(width), height(height), stride(stride), orgX(orgX), orgY(orgY), colors(colors) 51 {} 52 53 RasBuf32(BBitmap *bmp) 54 { 55 width = bmp->Bounds().IntegerWidth() + 1; 56 height = bmp->Bounds().IntegerHeight() + 1; 57 stride = bmp->BytesPerRow()/4; 58 orgX = 0; 59 orgY = 0; 60 colors = (int32*)bmp->Bits(); 61 } 62 63 RasBuf32(direct_buffer_info *info) 64 { 65 width = 0x7fffffff; 66 height = 0x7fffffff; 67 stride = info->bytes_per_row/4; 68 orgX = 0; 69 orgY = 0; 70 colors = (int32*)info->bits; 71 } 72 73 void ClipSize(int32 x, int32 y, int32 w, int32 h) 74 { 75 if (x < 0) {w += x; x = 0;} 76 if (y < 0) {h += y; y = 0;} 77 if (x + w > width) {w = width - x;} 78 if (y + h > height) {h = height - y;} 79 if ((w > 0) && (h > 0)) { 80 colors += y*stride + x; 81 width = w; 82 height = h; 83 } else { 84 width = 0; height = 0; colors = NULL; 85 } 86 if (x + orgX > 0) {orgX += x;} else {orgX = 0;} 87 if (y + orgY > 0) {orgY += y;} else {orgY = 0;} 88 } 89 90 void ClipRect(int32 l, int32 t, int32 r, int32 b) 91 { 92 ClipSize(l, t, r - l, b - t); 93 } 94 95 void Shift(int32 dx, int32 dy) 96 { 97 orgX += dx; 98 orgY += dy; 99 } 100 101 void Clear(int32 color) 102 { 103 RasBuf32 dst = *this; 104 dst.stride -= dst.width; 105 for (; dst.height > 0; dst.height--) { 106 for (int32 i = dst.width; i > 0; i--) 107 *dst.colors++ = color; 108 dst.colors += dst.stride; 109 } 110 } 111 112 void Blit(RasBuf32 src) 113 { 114 RasBuf32 dst = *this; 115 int32 x, y; 116 x = src.orgX - orgX; 117 y = src.orgY - orgY; 118 dst.ClipSize(x, y, src.width, src.height); 119 src.ClipSize(-x, -y, width, height); 120 for (; dst.height > 0; dst.height--) { 121 memcpy(dst.colors, src.colors, 4*dst.width); 122 dst.colors += dst.stride; 123 src.colors += src.stride; 124 } 125 } 126}; 127 128SoftwareRenderer::SoftwareRenderer(BGLView *view, ulong options) 129 : 130 BGLRenderer(view, options), 131 fDirectModeEnabled(false), 132 fInfo(NULL), 133 fInfoLocker("info locker"), 134 fOptions(options), 135 fColorSpace(B_NO_COLOR_SPACE) 136{ 137 CALLED(); 138 139 // Initialize the "Haiku Software GL Pipe" 140 time_t beg; 141 time_t end; 142 beg = time(NULL); 143 fContextObj = new GalliumContext(options); 144 end = time(NULL); 145 TRACE("Haiku Software GL Pipe initialization time: %f.\n", 146 difftime(end, beg)); 147 148 BRect b = view->Bounds(); 149 fColorSpace = BScreen(view->Window()).ColorSpace(); 150 TRACE("%s: Colorspace:\t%s\n", __func__, color_space_name(fColorSpace)); 151 152 fWidth = (GLint)b.IntegerWidth(); 153 fHeight = (GLint)b.IntegerHeight(); 154 155 // Initialize the first "Haiku Software GL Pipe" context 156 beg = time(NULL); 157 fContextID = fContextObj->CreateContext(this); 158 end = time(NULL); 159 160 if (fContextID < 0) 161 ERROR("%s: There was an error creating the context!\n", __func__); 162 else { 163 TRACE("%s: Haiku Software GL Pipe context creation time: %f.\n", 164 __func__, difftime(end, beg)); 165 } 166 167 if (!fContextObj->GetCurrentContext()) 168 LockGL(); 169} 170 171 172SoftwareRenderer::~SoftwareRenderer() 173{ 174 CALLED(); 175 176 if (fContextObj) 177 delete fContextObj; 178} 179 180 181void 182SoftwareRenderer::LockGL() 183{ 184// CALLED(); 185 BGLRenderer::LockGL(); 186 187 color_space cs = BScreen(GLView()->Window()).ColorSpace(); 188 189 { 190 BAutolock lock(fInfoLocker); 191 if (fDirectModeEnabled && fInfo != NULL) { 192 fWidth = fInfo->window_bounds.right - fInfo->window_bounds.left; 193 fHeight = fInfo->window_bounds.bottom - fInfo->window_bounds.top; 194 } 195 196 fContextObj->Validate(fWidth, fHeight); 197 fColorSpace = cs; 198 } 199 200 // do not hold fInfoLocker here to avoid deadlock 201 fContextObj->SetCurrentContext(true, fContextID); 202} 203 204 205void 206SoftwareRenderer::UnlockGL() 207{ 208// CALLED(); 209 if ((fOptions & BGL_DOUBLE) == 0) { 210 SwapBuffers(); 211 } 212 fContextObj->SetCurrentContext(false, fContextID); 213 BGLRenderer::UnlockGL(); 214} 215 216 217void 218SoftwareRenderer::Display(BBitmap *bitmap, BRect *updateRect) 219{ 220// CALLED(); 221 222 if (!fDirectModeEnabled) { 223 // TODO: avoid timeout 224 if (GLView()->LockLooperWithTimeout(1000) == B_OK) { 225 GLView()->DrawBitmap(bitmap, B_ORIGIN); 226 GLView()->UnlockLooper(); 227 } 228 } else { 229 BAutolock lock(fInfoLocker); 230 if (fInfo != NULL) { 231 RasBuf32 srcBuf(bitmap); 232 RasBuf32 dstBuf(fInfo); 233 for (uint32 i = 0; i < fInfo->clip_list_count; i++) { 234 clipping_rect *clip = &fInfo->clip_list[i]; 235 RasBuf32 dstClip = dstBuf; 236 dstClip.ClipRect(clip->left, clip->top, clip->right + 1, clip->bottom + 1); 237 dstClip.Shift(-fInfo->window_bounds.left, -fInfo->window_bounds.top); 238 dstClip.Blit(srcBuf); 239 } 240 } 241 } 242} 243 244 245void 246SoftwareRenderer::SwapBuffers(bool vsync) 247{ 248 BScreen screen(GLView()->Window()); 249 fContextObj->SwapBuffers(fContextID); 250 fContextObj->Validate(fWidth, fHeight); 251 if (vsync) 252 screen.WaitForRetrace(); 253} 254 255void 256SoftwareRenderer::Draw(BRect updateRect) 257{ 258// CALLED(); 259 fContextObj->Draw(fContextID, updateRect); 260} 261 262 263status_t 264SoftwareRenderer::CopyPixelsOut(BPoint location, BBitmap *bitmap) 265{ 266 CALLED(); 267 268 // TODO: implement 269 return B_ERROR; 270} 271 272 273status_t 274SoftwareRenderer::CopyPixelsIn(BBitmap *bitmap, BPoint location) 275{ 276 CALLED(); 277 278 // TODO: implement 279 return B_ERROR; 280} 281 282 283void 284SoftwareRenderer::EnableDirectMode(bool enabled) 285{ 286 fDirectModeEnabled = enabled; 287} 288 289 290void 291SoftwareRenderer::DirectConnected(direct_buffer_info *info) 292{ 293// CALLED(); 294 BAutolock lock(fInfoLocker); 295 if (info) { 296 if (!fInfo) { 297 fInfo = (direct_buffer_info *)calloc(1, 298 DIRECT_BUFFER_INFO_AREA_SIZE); 299 } 300 memcpy(fInfo, info, DIRECT_BUFFER_INFO_AREA_SIZE); 301 } else if (fInfo) { 302 free(fInfo); 303 fInfo = NULL; 304 } 305} 306 307 308void 309SoftwareRenderer::FrameResized(float width, float height) 310{ 311 TRACE("%s: %f x %f\n", __func__, width, height); 312 313 BAutolock lock(fInfoLocker); 314 fWidth = (GLuint)width; 315 fHeight = (GLuint)height; 316} 317