1 /*
2 * Copyright 2006-2012, Haiku. 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 * Stefano Ceccherini, burton666@libero.it
9 */
10
11 #include <kernel/image.h>
12
13 #include <GLView.h>
14
15 #include <assert.h>
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19
20 #include <DirectWindow.h>
21 #include "GLRenderer.h"
22
23 #include <private/interface/DirectWindowPrivate.h>
24 #include "GLRendererRoster.h"
25
26 #include "glapi/glapi.h"
27
28 struct glview_direct_info {
29 direct_buffer_info* direct_info;
30 bool direct_connected;
31 bool enable_direct_mode;
32
33 glview_direct_info();
34 ~glview_direct_info();
35 };
36
37
BGLView(BRect rect,const char * name,ulong resizingMode,ulong mode,ulong options)38 BGLView::BGLView(BRect rect, const char* name, ulong resizingMode, ulong mode,
39 ulong options)
40 :
41 BView(rect, name, B_FOLLOW_ALL_SIDES, mode | B_WILL_DRAW | B_FRAME_EVENTS),
42 fGc(NULL),
43 fOptions(options),
44 fDitherCount(0),
45 fDrawLock("BGLView draw lock"),
46 fDisplayLock("BGLView display lock"),
47 fClipInfo(NULL),
48 fRenderer(NULL),
49 fDitherMap(NULL)
50 {
51 fRenderer = GLRendererRoster::Roster()->GetRenderer(this, options);
52 }
53
54
~BGLView()55 BGLView::~BGLView()
56 {
57 delete fClipInfo;
58 if (fRenderer)
59 fRenderer->Release();
60 }
61
62
63 void
LockGL()64 BGLView::LockGL()
65 {
66 // TODO: acquire the OpenGL API lock it on this glview
67
68 fDisplayLock.Lock();
69 if (fRenderer != NULL && fDisplayLock.CountLocks() == 1)
70 fRenderer->LockGL();
71 }
72
73
74 void
UnlockGL()75 BGLView::UnlockGL()
76 {
77 thread_id lockerThread = fDisplayLock.LockingThread();
78 thread_id callerThread = find_thread(NULL);
79
80 if (lockerThread != B_ERROR && lockerThread != callerThread) {
81 printf("UnlockGL is called from wrong thread, lockerThread: %d, callerThread: %d\n",
82 (int)lockerThread, (int)callerThread);
83 debugger("[!]");
84 }
85
86 if (fRenderer != NULL && fDisplayLock.CountLocks() == 1)
87 fRenderer->UnlockGL();
88 fDisplayLock.Unlock();
89
90 // TODO: release the GL API lock to others glviews
91 }
92
93
94 void
SwapBuffers()95 BGLView::SwapBuffers()
96 {
97 SwapBuffers(false);
98 }
99
100
101 void
SwapBuffers(bool vSync)102 BGLView::SwapBuffers(bool vSync)
103 {
104 if (fRenderer) {
105 _LockDraw();
106 fRenderer->SwapBuffers(vSync);
107 _UnlockDraw();
108 }
109 }
110
111
112 BView*
EmbeddedView()113 BGLView::EmbeddedView()
114 {
115 return NULL;
116 }
117
118
119 void*
GetGLProcAddress(const char * procName)120 BGLView::GetGLProcAddress(const char* procName)
121 {
122 return (void*)_glapi_get_proc_address(procName);
123 }
124
125
126 status_t
CopyPixelsOut(BPoint source,BBitmap * dest)127 BGLView::CopyPixelsOut(BPoint source, BBitmap* dest)
128 {
129 if (!fRenderer)
130 return B_ERROR;
131
132 if (!dest || !dest->Bounds().IsValid())
133 return B_BAD_VALUE;
134
135 return fRenderer->CopyPixelsOut(source, dest);
136 }
137
138
139 status_t
CopyPixelsIn(BBitmap * source,BPoint dest)140 BGLView::CopyPixelsIn(BBitmap* source, BPoint dest)
141 {
142 if (!fRenderer)
143 return B_ERROR;
144
145 if (!source || !source->Bounds().IsValid())
146 return B_BAD_VALUE;
147
148 return fRenderer->CopyPixelsIn(source, dest);
149 }
150
151
152 /*! Mesa's GLenum is not ulong but uint, so we can't use GLenum
153 without breaking this method signature.
154 Instead, we have to use the effective BeOS's SGI OpenGL GLenum type:
155 unsigned long.
156 */
157 void
ErrorCallback(unsigned long errorCode)158 BGLView::ErrorCallback(unsigned long errorCode)
159 {
160 char msg[32];
161 sprintf(msg, "GL: Error code $%04lx.", errorCode);
162 // TODO: under BeOS R5, it call debugger(msg);
163 fprintf(stderr, "%s\n", msg);
164 }
165
166
167 void
Draw(BRect updateRect)168 BGLView::Draw(BRect updateRect)
169 {
170 if (fRenderer) {
171 if (!fClipInfo || !fClipInfo->enable_direct_mode)
172 fRenderer->Draw(updateRect);
173 return;
174 }
175 // TODO: auto-size and center the string
176 MovePenTo(8, 32);
177 DrawString("No OpenGL renderer available!");
178 }
179
180
181 void
AttachedToWindow()182 BGLView::AttachedToWindow()
183 {
184 BView::AttachedToWindow();
185
186 fBounds = Bounds();
187 for (BView* view = this; view != NULL; view = view->Parent())
188 view->ConvertToParent(&fBounds);
189
190 if (fRenderer != NULL) {
191 // Jackburton: The following code was commented because it doesn't look
192 // good in "direct" mode:
193 // when the window is moved, the app_server doesn't paint the view's
194 // background, and the stuff behind the window itself shows up.
195 // Setting the view color to black, instead, looks a bit more elegant.
196 #if 0
197 // Don't paint white window background when resized
198 SetViewColor(B_TRANSPARENT_32_BIT);
199 #else
200 SetViewColor(0, 0, 0);
201 #endif
202
203 // Set default OpenGL viewport:
204 LockGL();
205 glViewport(0, 0, Bounds().IntegerWidth(), Bounds().IntegerHeight());
206 UnlockGL();
207 fRenderer->FrameResized(Bounds().IntegerWidth(),
208 Bounds().IntegerHeight());
209
210 if (fClipInfo) {
211 fRenderer->DirectConnected(fClipInfo->direct_info);
212 fRenderer->EnableDirectMode(fClipInfo->enable_direct_mode);
213 }
214
215 return;
216 }
217
218 fprintf(stderr, "no renderer found! \n");
219
220 // No Renderer, no rendering. Setup a minimal "No Renderer" string drawing
221 // context
222 SetFont(be_bold_font);
223 // SetFontSize(16);
224 }
225
226
227 void
AllAttached()228 BGLView::AllAttached()
229 {
230 BView::AllAttached();
231 }
232
233
234 void
DetachedFromWindow()235 BGLView::DetachedFromWindow()
236 {
237 BView::DetachedFromWindow();
238 }
239
240
241 void
AllDetached()242 BGLView::AllDetached()
243 {
244 BView::AllDetached();
245 }
246
247
248 void
FrameResized(float width,float height)249 BGLView::FrameResized(float width, float height)
250 {
251 fBounds = Bounds();
252 for (BView* v = this; v; v = v->Parent())
253 v->ConvertToParent(&fBounds);
254
255 if (fRenderer) {
256 //_LockDraw();
257 fRenderer->FrameResized(width, height);
258 //_UnlockDraw();
259 }
260
261 BView::FrameResized(width, height);
262 }
263
264
265 status_t
Perform(perform_code d,void * arg)266 BGLView::Perform(perform_code d, void* arg)
267 {
268 return BView::Perform(d, arg);
269 }
270
271
272 status_t
Archive(BMessage * data,bool deep) const273 BGLView::Archive(BMessage* data, bool deep) const
274 {
275 return BView::Archive(data, deep);
276 }
277
278
279 void
MessageReceived(BMessage * msg)280 BGLView::MessageReceived(BMessage* msg)
281 {
282 BView::MessageReceived(msg);
283 }
284
285
286 void
SetResizingMode(uint32 mode)287 BGLView::SetResizingMode(uint32 mode)
288 {
289 BView::SetResizingMode(mode);
290 }
291
292
293 void
GetPreferredSize(float * _width,float * _height)294 BGLView::GetPreferredSize(float* _width, float* _height)
295 {
296 if (_width)
297 *_width = 0;
298 if (_height)
299 *_height = 0;
300 }
301
302
303 void
Show()304 BGLView::Show()
305 {
306 BView::Show();
307 }
308
309
310 void
Hide()311 BGLView::Hide()
312 {
313 BView::Hide();
314 }
315
316
317 BHandler*
ResolveSpecifier(BMessage * msg,int32 index,BMessage * specifier,int32 form,const char * property)318 BGLView::ResolveSpecifier(BMessage* msg, int32 index, BMessage* specifier,
319 int32 form, const char* property)
320 {
321 return BView::ResolveSpecifier(msg, index, specifier, form, property);
322 }
323
324
325 status_t
GetSupportedSuites(BMessage * data)326 BGLView::GetSupportedSuites(BMessage* data)
327 {
328 return BView::GetSupportedSuites(data);
329 }
330
331
332 void
DirectConnected(direct_buffer_info * info)333 BGLView::DirectConnected(direct_buffer_info* info)
334 {
335 printf("BGLView::DirectConnected\n");
336 if (fClipInfo == NULL) {
337 fClipInfo = new (std::nothrow) glview_direct_info();
338 if (fClipInfo == NULL)
339 return;
340 }
341
342 direct_buffer_info* localInfo = fClipInfo->direct_info;
343
344 _LockDraw();
345 switch (info->buffer_state & B_DIRECT_MODE_MASK) {
346 case B_DIRECT_START:
347 fClipInfo->direct_connected = true;
348 memcpy(localInfo, info, DIRECT_BUFFER_INFO_AREA_SIZE);
349 break;
350
351 case B_DIRECT_MODIFY:
352 memcpy(localInfo, info, DIRECT_BUFFER_INFO_AREA_SIZE);
353 break;
354
355 case B_DIRECT_STOP:
356 fClipInfo->direct_connected = false;
357 break;
358 }
359
360 if (fRenderer)
361 _CallDirectConnected();
362
363 _UnlockDraw();
364 }
365
366
367 void
EnableDirectMode(bool enabled)368 BGLView::EnableDirectMode(bool enabled)
369 {
370 printf("BGLView::EnableDirectMode: %d\n", (int)enabled);
371 if (fRenderer)
372 fRenderer->EnableDirectMode(enabled);
373 if (fClipInfo == NULL) {
374 fClipInfo = new (std::nothrow) glview_direct_info();
375 if (fClipInfo == NULL)
376 return;
377 }
378
379 fClipInfo->enable_direct_mode = enabled;
380 }
381
382
383 void
_LockDraw()384 BGLView::_LockDraw()
385 {
386 if (!fClipInfo || !fClipInfo->enable_direct_mode)
387 return;
388
389 fDrawLock.Lock();
390 }
391
392
393 void
_UnlockDraw()394 BGLView::_UnlockDraw()
395 {
396 if (!fClipInfo || !fClipInfo->enable_direct_mode)
397 return;
398
399 fDrawLock.Unlock();
400 }
401
402
403 void
_CallDirectConnected()404 BGLView::_CallDirectConnected()
405 {
406 if (!fClipInfo || !fClipInfo->direct_connected) {
407 fRenderer->DirectConnected(NULL);
408 return;
409 }
410
411 direct_buffer_info* localInfo = fClipInfo->direct_info;
412 direct_buffer_info* info = (direct_buffer_info*)malloc(
413 DIRECT_BUFFER_INFO_AREA_SIZE);
414 if (info == NULL)
415 return;
416
417 memcpy(info, localInfo, DIRECT_BUFFER_INFO_AREA_SIZE);
418
419 // Collect the rects into a BRegion, then clip to the view's bounds
420 BRegion region;
421 for (uint32 c = 0; c < localInfo->clip_list_count; c++)
422 region.Include(localInfo->clip_list[c]);
423 BRegion boundsRegion = fBounds.OffsetByCopy(localInfo->window_bounds.left,
424 localInfo->window_bounds.top);
425 info->window_bounds = boundsRegion.RectAtInt(0);
426 // window_bounds are now view bounds
427 region.IntersectWith(&boundsRegion);
428
429 info->clip_list_count = region.CountRects();
430 info->clip_bounds = region.FrameInt();
431
432 for (uint32 c = 0; c < info->clip_list_count; c++)
433 info->clip_list[c] = region.RectAtInt(c);
434 fRenderer->DirectConnected(info);
435 free(info);
436 }
437
438
439 //---- virtual reserved methods ----------
440
441
_ReservedGLView1()442 void BGLView::_ReservedGLView1() {}
_ReservedGLView2()443 void BGLView::_ReservedGLView2() {}
_ReservedGLView3()444 void BGLView::_ReservedGLView3() {}
_ReservedGLView4()445 void BGLView::_ReservedGLView4() {}
_ReservedGLView5()446 void BGLView::_ReservedGLView5() {}
_ReservedGLView6()447 void BGLView::_ReservedGLView6() {}
_ReservedGLView7()448 void BGLView::_ReservedGLView7() {}
_ReservedGLView8()449 void BGLView::_ReservedGLView8() {}
450
451
452 // #pragma mark -
453
454
455 // BeOS compatibility: contrary to others BView's contructors,
456 // BGLView one wants a non-const name argument.
BGLView(BRect rect,char * name,ulong resizingMode,ulong mode,ulong options)457 BGLView::BGLView(BRect rect, char* name, ulong resizingMode, ulong mode,
458 ulong options)
459 :
460 BView(rect, name, B_FOLLOW_ALL_SIDES, mode | B_WILL_DRAW | B_FRAME_EVENTS),
461 fGc(NULL),
462 fOptions(options),
463 fDitherCount(0),
464 fDrawLock("BGLView draw lock"),
465 fDisplayLock("BGLView display lock"),
466 fClipInfo(NULL),
467 fRenderer(NULL),
468 fDitherMap(NULL)
469 {
470 fRenderer = GLRendererRoster::Roster()->GetRenderer(this, options);
471 }
472
473
474 #if 0
475 // TODO: implement BGLScreen class...
476
477
478 BGLScreen::BGLScreen(char* name, ulong screenMode, ulong options,
479 status_t* error, bool debug)
480 :
481 BWindowScreen(name, screenMode, error, debug)
482 {
483 }
484
485
486 BGLScreen::~BGLScreen()
487 {
488 }
489
490
491 void
492 BGLScreen::LockGL()
493 {
494 }
495
496
497 void
498 BGLScreen::UnlockGL()
499 {
500 }
501
502
503 void
504 BGLScreen::SwapBuffers()
505 {
506 }
507
508
509 void
510 BGLScreen::ErrorCallback(unsigned long errorCode)
511 {
512 // Mesa's GLenum is not ulong but uint!
513 char msg[32];
514 sprintf(msg, "GL: Error code $%04lx.", errorCode);
515 // debugger(msg);
516 fprintf(stderr, "%s\n", msg);
517 return;
518 }
519
520
521 void
522 BGLScreen::ScreenConnected(bool enabled)
523 {
524 }
525
526
527 void
528 BGLScreen::FrameResized(float width, float height)
529 {
530 return BWindowScreen::FrameResized(width, height);
531 }
532
533
534 status_t
535 BGLScreen::Perform(perform_code d, void* arg)
536 {
537 return BWindowScreen::Perform(d, arg);
538 }
539
540
541 status_t
542 BGLScreen::Archive(BMessage* data, bool deep) const
543 {
544 return BWindowScreen::Archive(data, deep);
545 }
546
547
548 void
549 BGLScreen::MessageReceived(BMessage* msg)
550 {
551 BWindowScreen::MessageReceived(msg);
552 }
553
554
555 void
556 BGLScreen::Show()
557 {
558 BWindowScreen::Show();
559 }
560
561
562 void
563 BGLScreen::Hide()
564 {
565 BWindowScreen::Hide();
566 }
567
568
569 BHandler*
570 BGLScreen::ResolveSpecifier(BMessage* msg, int32 index, BMessage* specifier,
571 int32 form, const char* property)
572 {
573 return BWindowScreen::ResolveSpecifier(msg, index, specifier,
574 form, property);
575 }
576
577
578 status_t
579 BGLScreen::GetSupportedSuites(BMessage* data)
580 {
581 return BWindowScreen::GetSupportedSuites(data);
582 }
583
584
585 //---- virtual reserved methods ----------
586
587 void BGLScreen::_ReservedGLScreen1() {}
588 void BGLScreen::_ReservedGLScreen2() {}
589 void BGLScreen::_ReservedGLScreen3() {}
590 void BGLScreen::_ReservedGLScreen4() {}
591 void BGLScreen::_ReservedGLScreen5() {}
592 void BGLScreen::_ReservedGLScreen6() {}
593 void BGLScreen::_ReservedGLScreen7() {}
594 void BGLScreen::_ReservedGLScreen8() {}
595 #endif
596
597
color_space_name(color_space space)598 const char* color_space_name(color_space space)
599 {
600 #define C2N(a) case a: return #a
601
602 switch (space) {
603 C2N(B_RGB24);
604 C2N(B_RGB32);
605 C2N(B_RGBA32);
606 C2N(B_RGB32_BIG);
607 C2N(B_RGBA32_BIG);
608 C2N(B_GRAY8);
609 C2N(B_GRAY1);
610 C2N(B_RGB16);
611 C2N(B_RGB15);
612 C2N(B_RGBA15);
613 C2N(B_CMAP8);
614 default:
615 return "Unknown!";
616 };
617
618 #undef C2N
619 };
620
621
glview_direct_info()622 glview_direct_info::glview_direct_info()
623 {
624 // TODO: See direct_window_data() in app_server's ServerWindow.cpp
625 direct_info = (direct_buffer_info*)calloc(1, DIRECT_BUFFER_INFO_AREA_SIZE);
626 direct_connected = false;
627 enable_direct_mode = false;
628 }
629
630
~glview_direct_info()631 glview_direct_info::~glview_direct_info()
632 {
633 free(direct_info);
634 }
635
636