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
OVERLAY_COUNT(const display_mode * dm)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
OVERLAY_SUPPORTED_SPACES(const display_mode * dm)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
OVERLAY_SUPPORTED_FEATURES(uint32 color_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
ALLOCATE_OVERLAY_BUFFER(color_space cs,uint16 width,uint16 height)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
RELEASE_OVERLAY_BUFFER(const overlay_buffer * ob)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
GET_OVERLAY_CONSTRAINTS(const display_mode * dm,const overlay_buffer * ob,overlay_constraints * oc)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
ALLOCATE_OVERLAY(void)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
RELEASE_OVERLAY(overlay_token ot)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
CONFIGURE_OVERLAY(overlay_token ot,const overlay_buffer * ob,const overlay_window * ow,const overlay_view * ov)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