1/* Written by Rudolf Cornelissen 05/2002-4/2006 */
2
3/* Note on 'missing features' in BeOS 5.0.3 and DANO:
4 * BeOS needs to define more colorspaces! It would be nice if BeOS would support the FourCC 'definitions'
5 * of colorspaces. These colorspaces are 32bit words, so it could be simply done (or is it already so?)
6 */
7
8#define MODULE_BIT 0x00000400
9
10#include "acc_std.h"
11
12/* define the supported overlay input colorspaces */
13/* It would be nice to have the YUV4:2:0 2-plane mode implemented also later on, but the Be colorspace
14 * definitions (in GraphicsDefs.h, R5.0.3 and DANO5.1d0) do not include this one... */
15static uint32 overlay_colorspaces [] = { (uint32)B_YCbCr422, (uint32)B_NO_COLOR_SPACE };
16
17uint32 OVERLAY_COUNT(const display_mode *dm)
18// This method is never used AFAIK though it *is* exported on R5.0.3 and DANO.
19// Does someone know howto invoke it?
20{
21	LOG(4,("Overlay: count called\n"));
22
23	/* check for NULL pointer */
24	if (dm == NULL)
25	{
26		LOG(4,("Overlay: No display mode specified!\n"));
27	}
28	/* apparantly overlay count should report the number of 'overlay units' on the card */
29	return 1;
30}
31
32const uint32 *OVERLAY_SUPPORTED_SPACES(const display_mode *dm)
33// This method is never used AFAIK though it *is* exported on R5.0.3 and DANO.
34// Does someone know howto invoke it?
35{
36	LOG(4,("Overlay: supported_spaces called.\n"));
37
38	/* check for NULL pointer */
39	if (dm == NULL)
40	{
41		LOG(4,("Overlay: No display mode specified!\n"));
42		return NULL;
43	}
44
45	/* assuming interlaced VGA is not supported */
46	if (dm->timing.flags & B_TIMING_INTERLACED)
47	{
48		return NULL;
49	}
50	/* return a B_NO_COLOR_SPACE terminated list */
51	return &overlay_colorspaces[0];
52}
53
54uint32 OVERLAY_SUPPORTED_FEATURES(uint32 a_color_space)
55// This method is never used AFAIK. On R5.0.3 and DANO it is not even exported!
56{
57	LOG(4,("Overlay: supported_features: color_space $%08x\n",a_color_space));
58
59	/* check what features are supported for the current overlaybitmap colorspace */
60	switch (a_color_space)
61	{
62	default:
63			return
64				( B_OVERLAY_KEYING_USES_ALPHA 	 |
65				  B_OVERLAY_COLOR_KEY 			 |
66				  B_OVERLAY_HORIZONTAL_FILTERING |
67				  B_OVERLAY_VERTICAL_FILTERING );
68	}
69}
70
71const overlay_buffer *ALLOCATE_OVERLAY_BUFFER(color_space cs, uint16 width, uint16 height)
72{
73	int offset = 0;					/* used to determine next buffer to create */
74	uint32 adress, adress2, temp32;	/* used to calculate buffer adresses */
75	uint32 oldsize = 0;				/* used to 'squeeze' new buffers between already existing ones */
76	int cnt;						/* loopcounter */
77
78	/* acquire the shared benaphore */
79	AQUIRE_BEN(si->overlay.lock)
80
81	LOG(4,("Overlay: cardRAM_start = $%08x\n",(uint32)((uint8*)si->framebuffer)));
82	LOG(4,("Overlay: cardRAM_start_DMA = $%08x\n",(uint32)((uint8*)si->framebuffer_pci)));
83	LOG(4,("Overlay: cardRAM_size = %3.3fMb\n",(si->ps.memory_size / (1024.0 * 1024.0))));
84
85	/* find first empty slot (room for another buffer?) */
86	for (offset = 0; offset < MAXBUFFERS; offset++)
87	{
88		if (si->overlay.myBuffer[offset].buffer == NULL) break;
89	}
90
91	LOG(4,("Overlay: Allocate_buffer offset = %d\n",offset));
92
93	if (offset < MAXBUFFERS)
94	/* setup new scaler input buffer */
95	{
96		switch (cs)
97		{
98			case B_YCbCr422:
99					if (si->ps.card_arch < NV10A)
100					{
101						/* check if slopspace is needed: RIVA128 and TNT need ~0x000f. */
102						si->overlay.myBuffer[offset].width = ((width + 0x000f) & ~0x000f);
103					}
104					else
105					{
106						/* check if slopspace is needed: GeForce need ~0x001f. */
107						/* fixme:
108						 * update needed for GF DVDmax support to adhere to CRTC2 constraints?? */
109						si->overlay.myBuffer[offset].width = ((width + 0x001f) & ~0x001f);
110					}
111					si->overlay.myBuffer[offset].bytes_per_row = 2 * si->overlay.myBuffer[offset].width;
112
113					/* check if the requested horizontal pitch is supported: */
114					//fixme: tune for GF and TNT...
115					if (si->overlay.myBuffer[offset].width > 4088)
116					{
117						LOG(4,("Overlay: Sorry, requested buffer pitch not supported, aborted\n"));
118
119						/* release the shared benaphore */
120						RELEASE_BEN(si->overlay.lock)
121
122						return NULL;
123					}
124					break;
125			default:
126					/* unsupported colorspace! */
127					LOG(4,("Overlay: Sorry, colorspace $%08x not supported, aborted\n",cs));
128
129					/* release the shared benaphore */
130					RELEASE_BEN(si->overlay.lock)
131
132					return NULL;
133					break;
134		}
135
136		/* check if the requested buffer width is supported */
137		if (si->overlay.myBuffer[offset].width > 1024)
138		{
139			LOG(4,("Overlay: Sorry, requested buffer width not supported, aborted\n"));
140
141			/* release the shared benaphore */
142			RELEASE_BEN(si->overlay.lock)
143
144			return NULL;
145		}
146		/* check if the requested buffer height is supported */
147		if (height > 1024)
148		{
149			LOG(4,("Overlay: Sorry, requested buffer height not supported, aborted\n"));
150
151			/* release the shared benaphore */
152			RELEASE_BEN(si->overlay.lock)
153
154			return NULL;
155		}
156
157		/* store slopspace (in pixels) for each bitmap for use by 'overlay unit' (BES) */
158		si->overlay.myBufInfo[offset].slopspace = si->overlay.myBuffer[offset].width - width;
159
160		si->overlay.myBuffer[offset].space = cs;
161		si->overlay.myBuffer[offset].height = height;
162
163		/* we define the overlay buffers to reside 'in the back' of the cards RAM */
164		/* NOTE to app programmers:
165		 * Beware that an app using overlay needs to track workspace switches and screenprefs
166		 * changes. If such an action is detected, the app needs to reset it's pointers to the
167		 * newly created overlay bitmaps, which will be assigned by BeOS automatically after such
168		 * an event. (Also the app needs to respect the new overlay_constraints that will be applicable!)
169		 *
170		 * It is entirely possible that new bitmaps may *not* be re-setup at all, or less of them
171		 * than previously setup by the app might be re-setup. This is due to cardRAM restraints then.
172		 * This means that the app should also check for NULL pointers returned by the bitmaps,
173		 * and if this happens, it needs to fallback to single buffered overlay or even fallback to
174		 * bitmap output for the new situation. */
175
176		/* Another NOTE for app programmers:
177		 * A *positive* side-effect of assigning the first overlay buffer exactly at the end of the
178		 * cardRAM is that apps that try to write beyond the buffer's space get a segfault immediately.
179		 * This *greatly* simplifies tracking such errors!
180		 * Of course such errors may lead to strange effects in the app or driver behaviour if they are
181		 * not hunted down and removed.. */
182
183		/* calculate first free RAM adress in card:
184		 * Driver setup is as follows:
185		 * card base: 		- hardware cursor bitmap (if used),
186		 * directly above	- screen memory for both heads */
187		adress2 = (((uint32)((uint8*)si->fbc.frame_buffer)) +	/* cursor already included here */
188			(si->fbc.bytes_per_row * si->dm.virtual_height));	/* size in bytes of screen(s) */
189		LOG(4,("Overlay: first free cardRAM virtual adress $%08x\n", adress2));
190
191		/* calculate 'preliminary' buffer size including slopspace */
192		oldsize = si->overlay.myBufInfo[offset].size;
193		si->overlay.myBufInfo[offset].size =
194			si->overlay.myBuffer[offset].bytes_per_row * si->overlay.myBuffer[offset].height;
195
196		/* calculate virtual memory adress that would be needed for a new bitmap */
197		/* NOTE to app programmers:
198		 * For testing app behaviour regarding workspace switches or screen prefs changes to settings
199		 * that do not have enough cardRAM left for allocation of overlay bitmaps, you need a card with
200		 * a low amount of RAM. Or you can set in the file skel.settings for example:
201		 * memory 8 #8Mb RAM on card
202		 * and reboot (this simulates 8Mb RAM on the card).
203		 *
204		 * If you switch now to settings: 1600x1200x32bit (single head) the app needs to fallback to
205		 * bitmap output or maybe single buffered overlay output if small bitmaps are used. */
206
207		adress = (((uint32)((uint8*)si->framebuffer)) + si->ps.memory_size);
208		for (cnt = 0; cnt <= offset; cnt++)
209		{
210			adress -= si->overlay.myBufInfo[cnt].size;
211		}
212
213		/* the > G200 scalers require buffers to be aligned to 16 byte pages cardRAM offset, G200 can do with
214		 * 8 byte pages cardRAM offset. Compatible settings used, has no real downside consequences here */
215
216		/* Check if we need to modify the buffers starting adress and thus the size */
217		/* calculate 'would be' cardRAM offset */
218		temp32 = (adress - ((uint32)((vuint32 *)si->framebuffer)));
219		/* check if it is aligned */
220		if (temp32 != (temp32 & 0xfffffff0))
221		{
222			/* update the (already calculated) buffersize to get it aligned */
223			si->overlay.myBufInfo[offset].size += (temp32 - (temp32 & 0xfffffff0));
224			/* update the (already calculated) adress to get it aligned */
225			adress -= (temp32 - (temp32 & 0xfffffff0));
226		}
227		LOG(4,("Overlay: new buffer needs virtual adress $%08x\n", adress));
228
229		/* First check now if buffer to be defined is 'last one' in memory (speaking backwards):
230		 * this is done to prevent a large buffer getting created in the space a small buffer
231		 * occupied earlier, if not all buffers created were deleted.
232		 * Note also that the app can delete the buffers in any order desired. */
233
234		/* NOTE to app programmers:
235		 * If you are going to delete a overlay buffer you created, you should delete them *all* and
236		 * then re-create only the new ones needed. This way you are sure not to get unused memory-
237		 * space in between your overlay buffers for instance, so cardRAM is used 'to the max'.
238		 * If you don't, you might not get a buffer at all if you are trying to set up a larger one
239		 * than before.
240		 * (Indeed: not all buffers *have* to be of the same type and size...) */
241
242		for (cnt = offset; cnt < MAXBUFFERS; cnt++)
243		{
244			if (si->overlay.myBuffer[cnt].buffer != NULL)
245			{
246				/* Check if the new buffer would fit into the space the single old one used here */
247				if (si->overlay.myBufInfo[offset].size <= oldsize)
248				{
249					/* It does, so we reset to the old size and adresses to prevent the space from shrinking
250					 * if we get here again... */
251					adress -= (oldsize - si->overlay.myBufInfo[offset].size);
252					si->overlay.myBufInfo[offset].size = oldsize;
253					LOG(4,("Overlay: 'squeezing' in buffer:\n"
254						   "Overlay: resetting it to virtual adress $%08x and size $%08x\n", adress,oldsize));
255					/* force exiting the FOR loop */
256					cnt = MAXBUFFERS;
257				}
258				else
259				{
260					/* nogo, sorry */
261					LOG(4,("Overlay: Other buffer(s) exist after this one:\n"
262						   "Overlay: not enough space to 'squeeze' this one in, aborted\n"));
263
264					/* Reset to the old size to prevent the space from 'growing' if we get here again... */
265					si->overlay.myBufInfo[offset].size = oldsize;
266
267					/* release the shared benaphore */
268					RELEASE_BEN(si->overlay.lock)
269
270					return NULL;
271				}
272			}
273		}
274
275		/* check if we have enough space to setup this new bitmap
276		 * (preventing overlap of desktop RAMspace & overlay bitmap RAMspace here) */
277		if (adress < adress2)
278		/* nope, sorry */
279		{
280			LOG(4,("Overlay: Sorry, no more space for buffers: aborted\n"));
281
282			/* release the shared benaphore */
283			RELEASE_BEN(si->overlay.lock)
284
285			return NULL;
286		}
287		/* continue buffer setup */
288		si->overlay.myBuffer[offset].buffer = (void *) adress;
289
290		/* calculate physical memory adress (for dma use) */
291		adress = (((uint32)((uint8*)si->framebuffer_pci)) + si->ps.memory_size);
292		for (cnt = 0; cnt <= offset; cnt++)
293		{
294			adress -= si->overlay.myBufInfo[cnt].size;
295		}
296		/* this adress is already aligned to the scaler's requirements (via the already modified sizes) */
297		si->overlay.myBuffer[offset].buffer_dma = (void *) adress;
298
299		LOG(4,("Overlay: New buffer: addr $%08x, dma_addr $%08x, color space $%08x\n",
300			(uint32)((uint8*)si->overlay.myBuffer[offset].buffer),
301			(uint32)((uint8*)si->overlay.myBuffer[offset].buffer_dma), cs));
302		LOG(4,("Overlay: New buffer's size is $%08x\n", si->overlay.myBufInfo[offset].size));
303
304		/* release the shared benaphore */
305		RELEASE_BEN(si->overlay.lock)
306
307		return &si->overlay.myBuffer[offset];
308	}
309	else
310	/* sorry, no more room for buffers */
311	{
312		LOG(4,("Overlay: Sorry, no more space for buffers: aborted\n"));
313
314		/* release the shared benaphore */
315		RELEASE_BEN(si->overlay.lock)
316
317		return NULL;
318	}
319}
320
321status_t RELEASE_OVERLAY_BUFFER(const overlay_buffer *ob)
322/* Note that the user can delete the buffers in any order desired! */
323{
324	int offset = 0;
325
326	if (ob != NULL)
327	{
328		/* find the buffer */
329		for (offset = 0; offset < MAXBUFFERS; offset++)
330		{
331			if (si->overlay.myBuffer[offset].buffer == ob->buffer) break;
332		}
333
334		if (offset < MAXBUFFERS)
335		/* delete current buffer */
336		{
337			si->overlay.myBuffer[offset].buffer = NULL;
338			si->overlay.myBuffer[offset].buffer_dma = NULL;
339
340			LOG(4,("Overlay: Release_buffer offset = %d, buffer released\n",offset));
341
342			return B_OK;
343		}
344		else
345		{
346			/* this is no buffer of ours! */
347			LOG(4,("Overlay: Release_overlay_buffer: not ours, aborted!\n"));
348
349			return B_ERROR;
350		}
351	}
352	else
353	/* no buffer specified! */
354	{
355		LOG(4,("Overlay: Release_overlay_buffer: no buffer specified, aborted!\n"));
356
357		return B_ERROR;
358	}
359}
360
361status_t GET_OVERLAY_CONSTRAINTS
362	(const display_mode *dm, const overlay_buffer *ob, overlay_constraints *oc)
363{
364	int offset = 0;
365
366	LOG(4,("Overlay: Get_overlay_constraints called\n"));
367
368	/* check for NULL pointers */
369	if ((dm == NULL) || (ob == NULL) || (oc == NULL))
370	{
371		LOG(4,("Overlay: Get_overlay_constraints: Null pointer(s) detected!\n"));
372		return B_ERROR;
373	}
374
375	/* find the buffer */
376	for (offset = 0; offset < MAXBUFFERS; offset++)
377	{
378		if (si->overlay.myBuffer[offset].buffer == ob->buffer) break;
379	}
380
381	if (offset < MAXBUFFERS)
382	{
383		/* scaler input (values are in pixels) */
384		oc->view.h_alignment = 0;
385		oc->view.v_alignment = 0;
386
387		switch (ob->space)
388		{
389			case B_YCbCr422:
390					if (si->ps.card_arch < NV10A)
391					{
392						/* RIVA128 and TNT need 15.
393						 * Note: this has to be in sync with the slopspace setup during buffer allocation.. */
394						oc->view.width_alignment = 15;
395					}
396					else
397					{
398						/* GeForce need 31.
399						 * Note: this has to be in sync with the slopspace setup during buffer allocation.. */
400						oc->view.width_alignment = 31;
401					}
402					break;
403			default:
404					/* we should not be here, but set the worst-case value just to be safe anyway */
405					oc->view.width_alignment = 31;
406					break;
407		}
408
409		oc->view.height_alignment = 0;
410		oc->view.width.min = 1;
411		oc->view.height.min = 2; /* two fields */
412		oc->view.width.max = ob->width;
413		oc->view.height.max = ob->height;
414
415		/* scaler output restrictions */
416		oc->window.h_alignment = 0;
417		oc->window.v_alignment = 0;
418		oc->window.width_alignment = 0;
419		oc->window.height_alignment = 0;
420		oc->window.width.min = 2;
421		/* GeForce cards can output upto and including 2046 pixels in width */
422		//fixme: how about TNT?
423		if (dm->virtual_width > 2046)
424		{
425			oc->window.width.max = 2046;
426		}
427		else
428		{
429			oc->window.width.max = dm->virtual_width;
430		}
431		oc->window.height.min = 2;
432		/* GeForce cards can output upto and including 2046 pixels in height */
433		//fixme: how about TNT?
434		if (dm->virtual_height > 2046)
435		{
436			oc->window.height.max = 2046;
437		}
438		else
439		{
440			oc->window.height.max = dm->virtual_height;
441		}
442
443		/* GeForce scaling restrictions */
444		switch (si->ps.card_arch)
445		{
446		case NV04A:
447			/* Riva128-TNT2 series have an old BES engine... */
448			oc->h_scale.min = 1.0;
449			oc->v_scale.min = 1.0;
450			break;
451		case NV30A:
452		case NV40A:
453			/* GeForceFX series and up have a new BES engine... */
454			oc->h_scale.min = 0.5;
455			oc->v_scale.min = 0.5;
456			/* NV31 (confirmed GeForceFX 5600) has NV20A scaling limits!
457			 * So let it fall through... */
458			if (si->ps.card_type != NV31) break;
459		default:
460			/* the rest in between... */
461			oc->h_scale.min = 0.125;
462			oc->v_scale.min = 0.125;
463			break;
464		}
465		/* all cards have a upscaling limit of 8.0 (see official nVidia specsheets) */
466		oc->h_scale.max = 8.0;
467		oc->v_scale.max = 8.0;
468
469		return B_OK;
470	}
471	else
472	{
473		/* this is no buffer of ours! */
474		LOG(4,("Overlay: Get_overlay_constraints: buffer is not ours, aborted!\n"));
475
476		return B_ERROR;
477	}
478}
479
480overlay_token ALLOCATE_OVERLAY(void)
481{
482	uint32 tmpToken;
483	LOG(4,("Overlay: Allocate_overlay called: "));
484
485	/* come up with a token */
486	tmpToken = 0x12345678;
487
488	/* acquire the shared benaphore */
489	AQUIRE_BEN(si->overlay.lock)
490
491	/* overlay unit already in use? */
492	if (si->overlay.myToken == NULL)
493	/* overlay unit is available */
494	{
495		LOG(4,("succesfull\n"));
496
497		si->overlay.myToken = &tmpToken;
498
499		/* release the shared benaphore */
500		RELEASE_BEN(si->overlay.lock)
501
502		return si->overlay.myToken;
503	}
504	else
505	/* sorry, overlay unit is occupied */
506	{
507		LOG(4,("failed: already in use!\n"));
508
509		/* release the shared benaphore */
510		RELEASE_BEN(si->overlay.lock)
511
512		return NULL;
513	}
514}
515
516status_t RELEASE_OVERLAY(overlay_token ot)
517{
518	LOG(4,("Overlay: Release_overlay called: "));
519
520	/* is this call for real? */
521	if ((ot == NULL) || (si->overlay.myToken == NULL) || (ot != si->overlay.myToken))
522	/* nope, abort */
523	{
524		LOG(4,("failed, not in use!\n"));
525
526		return B_ERROR;
527	}
528	else
529	/* call is for real */
530	{
531
532		eng_release_bes();
533
534		LOG(4,("succesfull\n"));
535
536		si->overlay.myToken = NULL;
537		return B_OK;
538	}
539}
540
541status_t CONFIGURE_OVERLAY
542	(overlay_token ot, const overlay_buffer *ob, const overlay_window *ow, const overlay_view *ov)
543{
544	int offset = 0; /* used for buffer index */
545
546	LOG(4,("Overlay: Configure_overlay called: "));
547
548	/* Note:
549	 * When a Workspace switch, screen prefs change, or overlay app shutdown occurs, BeOS will
550	 * release all overlay buffers. The buffer currently displayed at that moment, may need some
551	 * 'hardware releasing' in the CONFIGURE_OVERLAY routine. This is why CONFIGURE_OVERLAY gets
552	 * called one more time then, with a null pointer for overlay_window and overlay_view, while
553	 * the currently displayed overlay_buffer is given.
554	 * The G200-G550 do not need to do anything on such an occasion, so we simply return if we
555	 * get called then. */
556	if ((ow == NULL) || (ov == NULL))
557	{
558		LOG(4,("output properties changed\n"));
559
560		return B_OK;
561	}
562
563	/* Note:
564	 * If during overlay use the screen prefs are changed, or the workspace has changed, it
565	 * may be that we were not able to re-allocate the requested overlay buffers (or only partly)
566	 * due to lack of cardRAM. If the app does not respond properly to this, we might end up
567	 * with a NULL pointer instead of a overlay_buffer to work with here.
568	 * Of course, we need to abort then to prevent the system from 'going down'.
569	 * The app will probably crash because it will want to write into this non-existant buffer
570	 * at some point. */
571	if (ob == NULL)
572	{
573		LOG(4,("no overlay buffer specified\n"));
574
575		return B_ERROR;
576	}
577
578	/* is this call done by the app that owns us? */
579	if ((ot == NULL) || (si->overlay.myToken == NULL) || (ot != si->overlay.myToken))
580	/* nope, abort */
581	{
582		LOG(4,("failed\n"));
583
584		return B_ERROR;
585	}
586	else
587	/* call is for real */
588	{
589		/* find the buffer's offset */
590		for (offset = 0; offset < MAXBUFFERS; offset++)
591		{
592			if (si->overlay.myBuffer[offset].buffer == ob->buffer) break;
593		}
594
595		if (offset < MAXBUFFERS)
596		{
597			LOG(4,("succesfull, switching to buffer %d\n", offset));
598
599			/* program overlay hardware */
600			eng_configure_bes(ob, ow, ov, offset);
601
602			return B_OK;
603		}
604		else
605		{
606			/* this is no buffer of ours! */
607			LOG(4,("buffer is not ours, aborted!\n"));
608
609			return B_ERROR;
610		}
611	}
612}
613