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