1/*
2	Copyright (c) 2002, Thomas Kurschel
3
4
5	Part of Radeon accelerant
6
7	Overlay interface
8*/
9
10#include "GlobalData.h"
11#include "radeon_interface.h"
12#include "video_overlay.h"
13#include <stdlib.h>
14#include <sys/ioctl.h>
15#include <string.h>
16#include "overlay_regs.h"
17#include "generic.h"
18
19// we could add support of planar modes and YUV modes
20// but I neither know how planar modes are defined nor
21// whether there is any program that makes use of them
22static uint32 overlay_colorspaces [] =
23{
24	B_RGB15, B_RGB16, B_RGB32, B_YCbCr422, 0
25};
26
27
28// public function: number of overlay units
29uint32 OVERLAY_COUNT( const display_mode *dm )
30{
31	SHOW_FLOW0( 3, "" );
32
33	(void) dm;
34
35	return 1;
36}
37
38
39// public function: return list of supported overlay colour spaces
40//	dm - display mode where overlay is to be used
41const uint32 *OVERLAY_SUPPORTED_SPACES( const display_mode *dm )
42{
43	SHOW_FLOW0( 3, "" );
44
45	(void) dm;
46
47	return overlay_colorspaces;
48}
49
50
51// public function: returns supported features
52//	color_space - overlay's colour space
53uint32 OVERLAY_SUPPORTED_FEATURES( uint32 color_space )
54{
55	SHOW_FLOW0( 3, "" );
56
57	(void) color_space;
58
59	return
60		B_OVERLAY_COLOR_KEY |
61		B_OVERLAY_HORIZONTAL_FILTERING |
62		B_OVERLAY_VERTICAL_FILTERING;
63}
64
65
66// public function: allocates overlay buffer
67//	cs - overlay's colour space
68//	width, height - width and height of overlay buffer
69const overlay_buffer *ALLOCATE_OVERLAY_BUFFER( color_space cs, uint16 width, uint16 height )
70{
71	virtual_card *vc = ai->vc;
72	shared_info *si = ai->si;
73	radeon_alloc_mem am;
74	overlay_buffer_node *node;
75	overlay_buffer *buffer;
76	status_t result;
77	uint ati_space, test_reg, bpp;
78
79	SHOW_FLOW0( 3, "" );
80
81	switch( cs ) {
82	case B_RGB15:
83		SHOW_FLOW0( 3, "RGB15" );
84		bpp = 2;
85		ati_space = RADEON_SCALER_SOURCE_15BPP >> 8;
86		test_reg = 0;
87		break;
88	case B_RGB16:
89		SHOW_FLOW0( 3, "RGB16" );
90		bpp = 2;
91		ati_space = RADEON_SCALER_SOURCE_16BPP >> 8;
92		test_reg = 0;
93		break;
94	case B_RGB32:
95		SHOW_FLOW0( 3, "RGB32" );
96		bpp = 4;
97		ati_space = RADEON_SCALER_SOURCE_32BPP >> 8;
98		test_reg = 0;
99		break;
100	case B_YCbCr422:
101		SHOW_FLOW0( 3, "YCbCr422" );
102		bpp = 2;
103		// strange naming convention: VYUY has to be read backward,
104		// i.e. you get (low to high address) YUYV, which is what we want!
105		ati_space = RADEON_SCALER_SOURCE_VYUY422 >> 8;
106		test_reg = 0;
107		break;
108	// YUV12 is planar pixel format consisting of two or three planes
109	// I have no clue whether and how this format is used in BeOS
110	// (don't even know how it is defined officially)
111/*	case B_YUV12:
112		SHOW_FLOW0( 3, "YUV12" );
113		bpp = 2;
114		uvpp = 1;
115		ati_space = RADEON_SCALER_SOURCE_YUV12 >> 8;
116		testreg = 0;
117		break;*/
118	default:
119		SHOW_FLOW( 3, "Unsupported format (%x)", (int)cs );
120		return NULL;
121	}
122
123	node = malloc( sizeof( overlay_buffer_node ));
124	if( node == NULL )
125		return NULL;
126
127	node->ati_space = ati_space;
128	node->test_reg = test_reg;
129
130	ACQUIRE_BEN( si->engine.lock );
131
132	// alloc graphics mem
133	buffer = &node->buffer;
134
135	buffer->space = cs;
136	buffer->width = width;
137	buffer->height = height;
138	buffer->bytes_per_row = (width * bpp + 0xf) & ~0xf;
139
140	am.magic = RADEON_PRIVATE_DATA_MAGIC;
141	am.size = buffer->bytes_per_row * height;
142	am.memory_type = mt_local;
143	am.global = false;
144
145	result = ioctl( ai->fd, RADEON_ALLOC_MEM, &am );
146	if( result != B_OK )
147		goto err;
148
149	node->mem_handle = am.handle;
150	node->mem_offset = am.offset;
151	buffer->buffer = si->local_mem + am.offset;
152	buffer->buffer_dma = (void *) ((unsigned long) si->framebuffer_pci + am.offset);
153
154	// add to list of overlays
155	node->next = vc->overlay_buffers;
156	node->prev = NULL;
157	if( node->next )
158		node->next->prev = node;
159
160	vc->overlay_buffers = node;
161
162	RELEASE_BEN( si->engine.lock );
163
164	SHOW_FLOW( 0, "success: mem_handle=%x, offset=%x, CPU-address=%x, phys-address=%x",
165		node->mem_handle, node->mem_offset, buffer->buffer, buffer->buffer_dma );
166
167	return buffer;
168
169err:
170	free(node);
171	RELEASE_BEN( si->engine.lock );
172	return NULL;
173}
174
175
176// public function: discard overlay buffer
177status_t RELEASE_OVERLAY_BUFFER( const overlay_buffer *ob )
178{
179	virtual_card *vc = ai->vc;
180	shared_info *si = ai->si;
181	overlay_buffer_node *node;
182	radeon_free_mem fm;
183	status_t result;
184
185	SHOW_FLOW0( 3, "" );
186
187	node = (overlay_buffer_node *)((char *)ob - offsetof( overlay_buffer_node, buffer ));
188
189	if( si->active_overlay.on == node || si->active_overlay.prev_on )
190		Radeon_HideOverlay( ai );
191
192	// free memory
193	fm.magic = RADEON_PRIVATE_DATA_MAGIC;
194	fm.handle = node->mem_handle;
195	fm.memory_type = mt_local;
196	fm.global = false;
197
198	result = ioctl( ai->fd, RADEON_FREE_MEM, &fm );
199	if( result != B_OK ) {
200		SHOW_FLOW( 3, "ups - couldn't free memory (handle=%x, status=%s)",
201			node->mem_handle, strerror( result ));
202	}
203
204	ACQUIRE_BEN( si->engine.lock );
205
206	// remove from list
207	if( node->next )
208		node->next->prev = node->prev;
209
210	if( node->prev )
211		node->prev->next = node->next;
212	else
213		vc->overlay_buffers = node->next;
214
215	RELEASE_BEN( si->engine.lock );
216
217	SHOW_FLOW0( 3, "success" );
218
219	return B_OK;
220}
221
222
223// public function: get constraints of overlay unit
224status_t GET_OVERLAY_CONSTRAINTS( const display_mode *dm, const overlay_buffer *ob,
225	overlay_constraints *oc )
226{
227	SHOW_FLOW0( 3, "" );
228
229	// probably, this is paranoia as we only get called by app_server
230	// which should know what it's doing
231	if( dm == NULL || ob == NULL || oc == NULL )
232		return B_BAD_VALUE;
233
234	// scaler input restrictions
235	// TBD: check all these values; I reckon that
236	//      most of them are too restrictive
237
238	// position
239	oc->view.h_alignment = 0;
240	oc->view.v_alignment = 0;
241
242	// alignment
243	switch (ob->space) {
244		case B_RGB15:
245			oc->view.width_alignment = 7;
246			break;
247		case B_RGB16:
248			oc->view.width_alignment = 7;
249			break;
250		case B_RGB32:
251			oc->view.width_alignment = 3;
252			break;
253		case B_YCbCr422:
254			oc->view.width_alignment = 7;
255			break;
256		case B_YUV12:
257			oc->view.width_alignment = 7;
258		default:
259			return B_BAD_VALUE;
260	}
261	oc->view.height_alignment = 0;
262
263	// size
264	oc->view.width.min = 4;		// make 4-tap filter happy
265	oc->view.height.min = 4;
266	oc->view.width.max = ob->width;
267	oc->view.height.max = ob->height;
268
269	// scaler output restrictions
270	oc->window.h_alignment = 0;
271	oc->window.v_alignment = 0;
272	oc->window.width_alignment = 0;
273	oc->window.height_alignment = 0;
274	oc->window.width.min = 2;
275	oc->window.width.max = dm->virtual_width;
276	oc->window.height.min = 2;
277	oc->window.height.max = dm->virtual_height;
278
279	// TBD: these values need to be checked
280	//      (shamelessly copied from Matrix driver)
281	oc->h_scale.min = 1.0f / (1 << 4);
282	oc->h_scale.max = 1 << 12;
283	oc->v_scale.min = 1.0f / (1 << 4);
284	oc->v_scale.max = 1 << 12;
285
286	SHOW_FLOW0( 3, "success" );
287
288	return B_OK;
289}
290
291
292// public function: allocate overlay unit
293overlay_token ALLOCATE_OVERLAY( void )
294{
295	shared_info *si = ai->si;
296	virtual_card *vc = ai->vc;
297
298	SHOW_FLOW0( 3, "" );
299
300	if( atomic_or( &si->overlay_mgr.inuse, 1 ) != 0 ) {
301		SHOW_FLOW0( 3, "already in use" );
302		return NULL;
303	}
304
305	SHOW_FLOW0( 3, "success" );
306
307	vc->uses_overlay = true;
308
309	return (void *)++si->overlay_mgr.token;
310}
311
312
313// public function: release overlay unit
314status_t RELEASE_OVERLAY(overlay_token ot)
315{
316	virtual_card *vc = ai->vc;
317	shared_info *si = ai->si;
318
319	SHOW_FLOW0( 3, "" );
320
321	if( (void *)si->overlay_mgr.token != ot )
322		return B_BAD_VALUE;
323
324	if( si->overlay_mgr.inuse == 0 )
325		return B_ERROR;
326
327	if( si->active_overlay.on )
328		Radeon_HideOverlay( ai );
329
330	si->overlay_mgr.inuse = 0;
331	vc->uses_overlay = false;
332
333	SHOW_FLOW0( 3, "released" );
334
335	return B_OK;
336}
337
338
339// public function: show/hide overlay
340status_t CONFIGURE_OVERLAY( overlay_token ot, const overlay_buffer *ob,
341	const overlay_window *ow, const overlay_view *ov )
342{
343	shared_info *si = ai->si;
344	status_t result;
345
346	SHOW_FLOW0( 4, "" );
347
348	if ( (uintptr_t)ot != si->overlay_mgr.token )
349		return B_BAD_VALUE;
350
351	if ( !si->overlay_mgr.inuse )
352		return B_BAD_VALUE;
353
354	if ( ow == NULL || ov == NULL ) {
355		SHOW_FLOW0( 3, "hide only" );
356		Radeon_HideOverlay( ai );
357		return B_OK;
358	}
359
360	if ( ob == NULL )
361		return B_ERROR;
362
363	ACQUIRE_BEN( si->engine.lock );
364
365	// store whished values
366	si->pending_overlay.ot = ot;
367	si->pending_overlay.ob = *ob;
368	si->pending_overlay.ow = *ow;
369	si->pending_overlay.ov = *ov;
370
371	si->pending_overlay.on = (overlay_buffer_node *)((char *)ob - offsetof( overlay_buffer_node, buffer ));
372
373	result = Radeon_UpdateOverlay( ai );
374
375	RELEASE_BEN( si->engine.lock );
376
377	return result;
378}
379