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
34 extern const char* color_space_name(color_space space);
35
36
37 extern "C" _EXPORT BGLRenderer*
instantiate_gl_renderer(BGLView * view,ulong opts,BGLDispatcher * dispatcher)38 instantiate_gl_renderer(BGLView *view, ulong opts, BGLDispatcher *dispatcher)
39 {
40 return new SoftwareRenderer(view, opts, dispatcher);
41 }
42
SoftwareRenderer(BGLView * view,ulong options,BGLDispatcher * dispatcher)43 SoftwareRenderer::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
~SoftwareRenderer()95 SoftwareRenderer::~SoftwareRenderer()
96 {
97 CALLED();
98
99 if (fContextObj)
100 delete fContextObj;
101 if (fBitmap)
102 delete fBitmap;
103 }
104
105
106 void
LockGL()107 SoftwareRenderer::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
132 void
UnlockGL()133 SoftwareRenderer::UnlockGL()
134 {
135 // CALLED();
136 if ((fOptions & BGL_DOUBLE) == 0) {
137 SwapBuffers();
138 }
139 fContextObj->SetCurrentContext(NULL, fContextID);
140 BGLRenderer::UnlockGL();
141 }
142
143
144 void
SwapBuffers(bool vsync)145 SoftwareRenderer::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
203 void
Draw(BRect updateRect)204 SoftwareRenderer::Draw(BRect updateRect)
205 {
206 // CALLED();
207 if ((!fDirectModeEnabled || fInfo == NULL) && fBitmap)
208 GLView()->DrawBitmap(fBitmap, updateRect, updateRect);
209 }
210
211
212 status_t
CopyPixelsOut(BPoint location,BBitmap * bitmap)213 SoftwareRenderer::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
254 status_t
CopyPixelsIn(BBitmap * bitmap,BPoint location)255 SoftwareRenderer::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
296 void
EnableDirectMode(bool enabled)297 SoftwareRenderer::EnableDirectMode(bool enabled)
298 {
299 fDirectModeEnabled = enabled;
300 }
301
302
303 void
DirectConnected(direct_buffer_info * info)304 SoftwareRenderer::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
321 void
FrameResized(float width,float height)322 SoftwareRenderer::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
332 void
_AllocateBitmap()333 SoftwareRenderer::_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