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