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