• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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