xref: /third_party/mesa3d/src/hgl/GLView.cpp (revision bf215546)
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
28struct 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
38BGLView::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
55BGLView::~BGLView()
56{
57	delete fClipInfo;
58	if (fRenderer)
59		fRenderer->Release();
60}
61
62
63void
64BGLView::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
74void
75BGLView::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
94void
95BGLView::SwapBuffers()
96{
97	SwapBuffers(false);
98}
99
100
101void
102BGLView::SwapBuffers(bool vSync)
103{
104	if (fRenderer) {
105		_LockDraw();
106		fRenderer->SwapBuffers(vSync);
107		_UnlockDraw();
108	}
109}
110
111
112BView*
113BGLView::EmbeddedView()
114{
115	return NULL;
116}
117
118
119void*
120BGLView::GetGLProcAddress(const char* procName)
121{
122	return (void*)_glapi_get_proc_address(procName);
123}
124
125
126status_t
127BGLView::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
139status_t
140BGLView::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 */
157void
158BGLView::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
167void
168BGLView::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
181void
182BGLView::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
227void
228BGLView::AllAttached()
229{
230	BView::AllAttached();
231}
232
233
234void
235BGLView::DetachedFromWindow()
236{
237	BView::DetachedFromWindow();
238}
239
240
241void
242BGLView::AllDetached()
243{
244	BView::AllDetached();
245}
246
247
248void
249BGLView::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
265status_t
266BGLView::Perform(perform_code d, void* arg)
267{
268	return BView::Perform(d, arg);
269}
270
271
272status_t
273BGLView::Archive(BMessage* data, bool deep) const
274{
275	return BView::Archive(data, deep);
276}
277
278
279void
280BGLView::MessageReceived(BMessage* msg)
281{
282	BView::MessageReceived(msg);
283}
284
285
286void
287BGLView::SetResizingMode(uint32 mode)
288{
289	BView::SetResizingMode(mode);
290}
291
292
293void
294BGLView::GetPreferredSize(float* _width, float* _height)
295{
296	if (_width)
297		*_width = 0;
298	if (_height)
299		*_height = 0;
300}
301
302
303void
304BGLView::Show()
305{
306	BView::Show();
307}
308
309
310void
311BGLView::Hide()
312{
313	BView::Hide();
314}
315
316
317BHandler*
318BGLView::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
325status_t
326BGLView::GetSupportedSuites(BMessage* data)
327{
328	return BView::GetSupportedSuites(data);
329}
330
331
332void
333BGLView::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
367void
368BGLView::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
383void
384BGLView::_LockDraw()
385{
386	if (!fClipInfo || !fClipInfo->enable_direct_mode)
387		return;
388
389	fDrawLock.Lock();
390}
391
392
393void
394BGLView::_UnlockDraw()
395{
396	if (!fClipInfo || !fClipInfo->enable_direct_mode)
397		return;
398
399	fDrawLock.Unlock();
400}
401
402
403void
404BGLView::_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
442void BGLView::_ReservedGLView1() {}
443void BGLView::_ReservedGLView2() {}
444void BGLView::_ReservedGLView3() {}
445void BGLView::_ReservedGLView4() {}
446void BGLView::_ReservedGLView5() {}
447void BGLView::_ReservedGLView6() {}
448void BGLView::_ReservedGLView7() {}
449void 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.
457BGLView::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
478BGLScreen::BGLScreen(char* name, ulong screenMode, ulong options,
479		status_t* error, bool debug)
480	:
481	BWindowScreen(name, screenMode, error, debug)
482{
483}
484
485
486BGLScreen::~BGLScreen()
487{
488}
489
490
491void
492BGLScreen::LockGL()
493{
494}
495
496
497void
498BGLScreen::UnlockGL()
499{
500}
501
502
503void
504BGLScreen::SwapBuffers()
505{
506}
507
508
509void
510BGLScreen::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
521void
522BGLScreen::ScreenConnected(bool enabled)
523{
524}
525
526
527void
528BGLScreen::FrameResized(float width, float height)
529{
530	return BWindowScreen::FrameResized(width, height);
531}
532
533
534status_t
535BGLScreen::Perform(perform_code d, void* arg)
536{
537	return BWindowScreen::Perform(d, arg);
538}
539
540
541status_t
542BGLScreen::Archive(BMessage* data, bool deep) const
543{
544	return BWindowScreen::Archive(data, deep);
545}
546
547
548void
549BGLScreen::MessageReceived(BMessage* msg)
550{
551	BWindowScreen::MessageReceived(msg);
552}
553
554
555void
556BGLScreen::Show()
557{
558	BWindowScreen::Show();
559}
560
561
562void
563BGLScreen::Hide()
564{
565	BWindowScreen::Hide();
566}
567
568
569BHandler*
570BGLScreen::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
578status_t
579BGLScreen::GetSupportedSuites(BMessage* data)
580{
581	return BWindowScreen::GetSupportedSuites(data);
582}
583
584
585//---- virtual reserved methods ----------
586
587void BGLScreen::_ReservedGLScreen1() {}
588void BGLScreen::_ReservedGLScreen2() {}
589void BGLScreen::_ReservedGLScreen3() {}
590void BGLScreen::_ReservedGLScreen4() {}
591void BGLScreen::_ReservedGLScreen5() {}
592void BGLScreen::_ReservedGLScreen6() {}
593void BGLScreen::_ReservedGLScreen7() {}
594void BGLScreen::_ReservedGLScreen8() {}
595#endif
596
597
598const 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
622glview_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
631glview_direct_info::~glview_direct_info()
632{
633	free(direct_info);
634}
635
636