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