gallium/target: Haiku 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 #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*
38 instantiate_gl_renderer(BGLView *view, ulong opts, BGLDispatcher *dispatcher)
39 {
40 return new SoftwareRenderer(view, opts, dispatcher);
41 }
42
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 fNewWidth = fWidth;
76 fNewHeight = fHeight;
77
78 _AllocateBitmap();
79
80 // Initialize the first "Haiku Software GL Pipe" context
81 beg = time(NULL);
82 fContextID = fContextObj->CreateContext(fBitmap);
83 end = time(NULL);
84
85 if (fContextID < 0)
86 ERROR("%s: There was an error creating the context!\n", __func__);
87 else {
88 TRACE("%s: Haiku Software GL Pipe context creation time: %f.\n",
89 __func__, difftime(end, beg));
90 }
91
92 if (!fContextObj->GetCurrentContext())
93 LockGL();
94 }
95
96
97 SoftwareRenderer::~SoftwareRenderer()
98 {
99 CALLED();
100
101 if (fContextObj)
102 delete fContextObj;
103 if (fBitmap)
104 delete fBitmap;
105 }
106
107
108 void
109 SoftwareRenderer::LockGL()
110 {
111 // CALLED();
112 BGLRenderer::LockGL();
113
114 color_space cs = BScreen(GLView()->Window()).ColorSpace();
115
116 BAutolock lock(fInfoLocker);
117 if (fDirectModeEnabled && fInfo != NULL) {
118 fNewWidth = fInfo->window_bounds.right - fInfo->window_bounds.left;
119 fNewHeight = fInfo->window_bounds.bottom - fInfo->window_bounds.top;
120 }
121
122 if (fBitmap && cs == fColorSpace && fNewWidth == fWidth
123 && fNewHeight == fHeight) {
124 fContextObj->SetCurrentContext(fBitmap, fContextID);
125 return;
126 }
127
128 fColorSpace = cs;
129 fWidth = fNewWidth;
130 fHeight = fNewHeight;
131
132 _AllocateBitmap();
133 fContextObj->SetCurrentContext(fBitmap, fContextID);
134 }
135
136
137 void
138 SoftwareRenderer::UnlockGL()
139 {
140 // CALLED();
141 if ((fOptions & BGL_DOUBLE) == 0) {
142 SwapBuffers();
143 }
144 fContextObj->SetCurrentContext(NULL, fContextID);
145 BGLRenderer::UnlockGL();
146 }
147
148
149 void
150 SoftwareRenderer::SwapBuffers(bool vsync)
151 {
152 // CALLED();
153 if (!fBitmap)
154 return;
155
156 BScreen screen(GLView()->Window());
157
158 fContextObj->SwapBuffers(fContextID);
159
160 BAutolock lock(fInfoLocker);
161
162 if (!fDirectModeEnabled || fInfo == NULL) {
163 if (GLView()->LockLooperWithTimeout(1000) == B_OK) {
164 GLView()->DrawBitmap(fBitmap, B_ORIGIN);
165 GLView()->UnlockLooper();
166 if (vsync)
167 screen.WaitForRetrace();
168 }
169 return;
170 }
171
172 // check the bitmap size still matches the size
173 if (fInfo->window_bounds.bottom - fInfo->window_bounds.top
174 != fBitmap->Bounds().IntegerHeight()
175 || fInfo->window_bounds.right - fInfo->window_bounds.left
176 != fBitmap->Bounds().IntegerWidth()) {
177 ERROR("%s: Bitmap size doesn't match size!\n", __func__);
178 return;
179 }
180
181 uint32 bytesPerRow = fBitmap->BytesPerRow();
182 uint8 bytesPerPixel = bytesPerRow / fBitmap->Bounds().IntegerWidth();
183
184 for (uint32 i = 0; i < fInfo->clip_list_count; i++) {
185 clipping_rect *clip = &fInfo->clip_list[i];
186 int32 height = clip->bottom - clip->top + 1;
187 int32 bytesWidth
188 = (clip->right - clip->left + 1) * bytesPerPixel;
189 bytesWidth -= bytesPerPixel;
190 uint8 *p = (uint8 *)fInfo->bits + clip->top
191 * fInfo->bytes_per_row + clip->left * bytesPerPixel;
192 uint8 *b = (uint8 *)fBitmap->Bits()
193 + (clip->top - fInfo->window_bounds.top) * bytesPerRow
194 + (clip->left - fInfo->window_bounds.left) * bytesPerPixel;
195
196 for (int y = 0; y < height - 1; y++) {
197 memcpy(p, b, bytesWidth);
198 p += fInfo->bytes_per_row;
199 b += bytesPerRow;
200 }
201 }
202
203 if (vsync)
204 screen.WaitForRetrace();
205 }
206
207
208 void
209 SoftwareRenderer::Draw(BRect updateRect)
210 {
211 // CALLED();
212 if ((!fDirectModeEnabled || fInfo == NULL) && fBitmap)
213 GLView()->DrawBitmap(fBitmap, updateRect, updateRect);
214 }
215
216
217 status_t
218 SoftwareRenderer::CopyPixelsOut(BPoint location, BBitmap *bitmap)
219 {
220 CALLED();
221 color_space scs = fBitmap->ColorSpace();
222 color_space dcs = bitmap->ColorSpace();
223
224 if (scs != dcs && (scs != B_RGBA32 || dcs != B_RGB32)) {
225 ERROR("%s::CopyPixelsOut(): incompatible color space: %s != %s\n",
226 __PRETTY_FUNCTION__, color_space_name(scs), color_space_name(dcs));
227 return B_BAD_TYPE;
228 }
229
230 BRect sr = fBitmap->Bounds();
231 BRect dr = bitmap->Bounds();
232
233 // int32 w1 = sr.IntegerWidth();
234 // int32 h1 = sr.IntegerHeight();
235 // int32 w2 = dr.IntegerWidth();
236 // int32 h2 = dr.IntegerHeight();
237
238 sr = sr & dr.OffsetBySelf(location);
239 dr = sr.OffsetByCopy(-location.x, -location.y);
240
241 uint8 *ps = (uint8 *) fBitmap->Bits();
242 uint8 *pd = (uint8 *) bitmap->Bits();
243 uint32 *s, *d;
244 uint32 y;
245 for (y = (uint32) sr.top; y <= (uint32) sr.bottom; y++) {
246 s = (uint32 *)(ps + y * fBitmap->BytesPerRow());
247 s += (uint32) sr.left;
248
249 d = (uint32 *)(pd + (y + (uint32)(dr.top - sr.top))
250 * bitmap->BytesPerRow());
251 d += (uint32) dr.left;
252 memcpy(d, s, dr.IntegerWidth() * 4);
253 }
254
255 return B_OK;
256 }
257
258
259 status_t
260 SoftwareRenderer::CopyPixelsIn(BBitmap *bitmap, BPoint location)
261 {
262 CALLED();
263
264 color_space sourceCS = bitmap->ColorSpace();
265 color_space destinationCS = fBitmap->ColorSpace();
266
267 if (sourceCS != destinationCS
268 && (sourceCS != B_RGB32 || destinationCS != B_RGBA32)) {
269 ERROR("%s::CopyPixelsIn(): incompatible color space: %s != %s\n",
270 __PRETTY_FUNCTION__, color_space_name(sourceCS),
271 color_space_name(destinationCS));
272 return B_BAD_TYPE;
273 }
274
275 BRect sr = bitmap->Bounds();
276 BRect dr = fBitmap->Bounds();
277
278 sr = sr & dr.OffsetBySelf(location);
279 dr = sr.OffsetByCopy(-location.x, -location.y);
280
281 uint8 *ps = (uint8 *) bitmap->Bits();
282 uint8 *pd = (uint8 *) fBitmap->Bits();
283 uint32 *s, *d;
284 uint32 y;
285
286 for (y = (uint32) sr.top; y <= (uint32) sr.bottom; y++) {
287 s = (uint32 *)(ps + y * bitmap->BytesPerRow());
288 s += (uint32) sr.left;
289
290 d = (uint32 *)(pd + (y + (uint32)(dr.top - sr.top))
291 * fBitmap->BytesPerRow());
292 d += (uint32) dr.left;
293
294 memcpy(d, s, dr.IntegerWidth() * 4);
295 }
296
297 return B_OK;
298 }
299
300
301 void
302 SoftwareRenderer::EnableDirectMode(bool enabled)
303 {
304 fDirectModeEnabled = enabled;
305 }
306
307
308 void
309 SoftwareRenderer::DirectConnected(direct_buffer_info *info)
310 {
311 // CALLED();
312 BAutolock lock(fInfoLocker);
313 if (info) {
314 if (!fInfo) {
315 fInfo = (direct_buffer_info *)calloc(1,
316 DIRECT_BUFFER_INFO_AREA_SIZE);
317 }
318 memcpy(fInfo, info, DIRECT_BUFFER_INFO_AREA_SIZE);
319 } else if (fInfo) {
320 free(fInfo);
321 fInfo = NULL;
322 }
323 }
324
325
326 void
327 SoftwareRenderer::FrameResized(float width, float height)
328 {
329 TRACE("%s: %f x %f\n", __func__, width, height);
330
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 TRACE("%s: New bitmap size: %" B_PRId32 " x %" B_PRId32 "\n", __func__,
359 fBitmap->Bounds().IntegerWidth(), fBitmap->Bounds().IntegerHeight());
360
361 fContextObj->ResizeViewport(fWidth, fHeight);
362
363 #if 0
364 // debug..
365 void *data = fBitmap->Bits();
366 memset(data, 0xcc, fBitmap->BitsLength());
367 #endif
368 }