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