Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
5564 | serge | 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 |
||
16 | #include |
||
17 | #include |
||
18 | #include |
||
19 | #include |
||
20 | #include |
||
21 | #include |
||
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 | |||
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 | |||
95 | SoftwareRenderer::~SoftwareRenderer() |
||
96 | { |
||
97 | CALLED(); |
||
98 | |||
99 | if (fContextObj) |
||
100 | delete fContextObj; |
||
101 | if (fBitmap) |
||
102 | delete fBitmap; |
||
103 | } |
||
104 | |||
105 | |||
106 | void |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
297 | SoftwareRenderer::EnableDirectMode(bool enabled) |
||
298 | { |
||
299 | fDirectModeEnabled = enabled; |
||
300 | } |
||
301 | |||
302 | |||
303 | void |
||
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 |
||
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 |
||
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 | }>>=>=>>>> |