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