xref: /haiku/src/add-ons/accelerants/radeon/overlay_management.c (revision 71452e98334eaac603bf542d159e24788a46bebb)
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
22 static uint32 overlay_colorspaces [] =
23 {
24 	B_RGB15, B_RGB16, B_RGB32, B_YCbCr422, 0
25 };
26 
27 
28 // public function: number of overlay units
29 uint32 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
41 const 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
53 uint32 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
69 const 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 
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_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 || si->active_overlay.prev_on )
189 		Radeon_HideOverlay( ai );
190 
191 	// free memory
192 	fm.magic = RADEON_PRIVATE_DATA_MAGIC;
193 	fm.handle = node->mem_handle;
194 	fm.memory_type = mt_local;
195 	fm.global = false;
196 
197 	result = ioctl( ai->fd, RADEON_FREE_MEM, &fm );
198 	if( result != B_OK ) {
199 		SHOW_FLOW( 3, "ups - couldn't free memory (handle=%x, status=%s)",
200 			node->mem_handle, strerror( result ));
201 	}
202 
203 	ACQUIRE_BEN( si->engine.lock );
204 
205 	// remove from list
206 	if( node->next )
207 		node->next->prev = node->prev;
208 
209 	if( node->prev )
210 		node->prev->next = node->next;
211 	else
212 		vc->overlay_buffers = node->next;
213 
214 	RELEASE_BEN( si->engine.lock );
215 
216 	SHOW_FLOW0( 3, "success" );
217 
218 	return B_OK;
219 }
220 
221 
222 // public function: get constraints of overlay unit
223 status_t GET_OVERLAY_CONSTRAINTS( const display_mode *dm, const overlay_buffer *ob,
224 	overlay_constraints *oc )
225 {
226 	SHOW_FLOW0( 3, "" );
227 
228 	// probably, this is paranoia as we only get called by app_server
229 	// which should know what it's doing
230 	if( dm == NULL || ob == NULL || oc == NULL )
231 		return B_BAD_VALUE;
232 
233 	// scaler input restrictions
234 	// TBD: check all these values; I reckon that
235 	//      most of them are too restrictive
236 
237 	// position
238 	oc->view.h_alignment = 0;
239 	oc->view.v_alignment = 0;
240 
241 	// alignment
242 	switch (ob->space) {
243 		case B_RGB15:
244 			oc->view.width_alignment = 7;
245 			break;
246 		case B_RGB16:
247 			oc->view.width_alignment = 7;
248 			break;
249 		case B_RGB32:
250 			oc->view.width_alignment = 3;
251 			break;
252 		case B_YCbCr422:
253 			oc->view.width_alignment = 7;
254 			break;
255 		case B_YUV12:
256 			oc->view.width_alignment = 7;
257 		default:
258 			return B_BAD_VALUE;
259 	}
260 	oc->view.height_alignment = 0;
261 
262 	// size
263 	oc->view.width.min = 4;		// make 4-tap filter happy
264 	oc->view.height.min = 4;
265 	oc->view.width.max = ob->width;
266 	oc->view.height.max = ob->height;
267 
268 	// scaler output restrictions
269 	oc->window.h_alignment = 0;
270 	oc->window.v_alignment = 0;
271 	oc->window.width_alignment = 0;
272 	oc->window.height_alignment = 0;
273 	oc->window.width.min = 2;
274 	oc->window.width.max = dm->virtual_width;
275 	oc->window.height.min = 2;
276 	oc->window.height.max = dm->virtual_height;
277 
278 	// TBD: these values need to be checked
279 	//      (shamelessly copied from Matrix driver)
280 	oc->h_scale.min = 1.0f / (1 << 4);
281 	oc->h_scale.max = 1 << 12;
282 	oc->v_scale.min = 1.0f / (1 << 4);
283 	oc->v_scale.max = 1 << 12;
284 
285 	SHOW_FLOW0( 3, "success" );
286 
287 	return B_OK;
288 }
289 
290 
291 // public function: allocate overlay unit
292 overlay_token ALLOCATE_OVERLAY( void )
293 {
294 	shared_info *si = ai->si;
295 	virtual_card *vc = ai->vc;
296 
297 	SHOW_FLOW0( 3, "" );
298 
299 	if( atomic_or( &si->overlay_mgr.inuse, 1 ) != 0 ) {
300 		SHOW_FLOW0( 3, "already in use" );
301 		return NULL;
302 	}
303 
304 	SHOW_FLOW0( 3, "success" );
305 
306 	vc->uses_overlay = true;
307 
308 	return (void *)++si->overlay_mgr.token;
309 }
310 
311 
312 // public function: release overlay unit
313 status_t RELEASE_OVERLAY(overlay_token ot)
314 {
315 	virtual_card *vc = ai->vc;
316 	shared_info *si = ai->si;
317 
318 	SHOW_FLOW0( 3, "" );
319 
320 	if( (void *)si->overlay_mgr.token != ot )
321 		return B_BAD_VALUE;
322 
323 	if( si->overlay_mgr.inuse == 0 )
324 		return B_ERROR;
325 
326 	if( si->active_overlay.on )
327 		Radeon_HideOverlay( ai );
328 
329 	si->overlay_mgr.inuse = 0;
330 	vc->uses_overlay = false;
331 
332 	SHOW_FLOW0( 3, "released" );
333 
334 	return B_OK;
335 }
336 
337 
338 // public function: show/hide overlay
339 status_t CONFIGURE_OVERLAY( overlay_token ot, const overlay_buffer *ob,
340 	const overlay_window *ow, const overlay_view *ov )
341 {
342 	shared_info *si = ai->si;
343 	status_t result;
344 
345 	SHOW_FLOW0( 4, "" );
346 
347 	if ( (uintptr_t)ot != si->overlay_mgr.token )
348 		return B_BAD_VALUE;
349 
350 	if ( !si->overlay_mgr.inuse )
351 		return B_BAD_VALUE;
352 
353 	if ( ow == NULL || ov == NULL ) {
354 		SHOW_FLOW0( 3, "hide only" );
355 		Radeon_HideOverlay( ai );
356 		return B_OK;
357 	}
358 
359 	if ( ob == NULL )
360 		return B_ERROR;
361 
362 	ACQUIRE_BEN( si->engine.lock );
363 
364 	// store whished values
365 	si->pending_overlay.ot = ot;
366 	si->pending_overlay.ob = *ob;
367 	si->pending_overlay.ow = *ow;
368 	si->pending_overlay.ov = *ov;
369 
370 	si->pending_overlay.on = (overlay_buffer_node *)((char *)ob - offsetof( overlay_buffer_node, buffer ));
371 
372 	result = Radeon_UpdateOverlay( ai );
373 
374 	RELEASE_BEN( si->engine.lock );
375 
376 	return result;
377 }
378