xref: /haiku/src/add-ons/accelerants/radeon/overlay_management.c (revision 1deede7388b04dbeec5af85cae7164735ea9e70d)
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 	free(node);
171 	RELEASE_BEN( si->engine.lock );
172 	return NULL;
173 }
174 
175 
176 // public function: discard overlay buffer
177 status_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
224 status_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
293 overlay_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
314 status_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
340 status_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