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 RELEASE_BEN( si->engine.lock ); 171 return NULL; 172 } 173 174 175 // public function: discard overlay buffer 176 status_t RELEASE_OVERLAY_BUFFER( const overlay_buffer *ob ) 177 { 178 virtual_card *vc = ai->vc; 179 shared_info *si = ai->si; 180 overlay_buffer_node *node; 181 radeon_free_mem fm; 182 status_t result; 183 184 SHOW_FLOW0( 3, "" ); 185 186 node = (overlay_buffer_node *)((char *)ob - offsetof( overlay_buffer_node, buffer )); 187 188 if( si->active_overlay.on == node || si->active_overlay.prev_on ) 189 Radeon_HideOverlay( ai ); 190 191 // free memory 192 fm.magic = RADEON_PRIVATE_DATA_MAGIC; 193 fm.handle = node->mem_handle; 194 fm.memory_type = mt_local; 195 fm.global = false; 196 197 result = ioctl( ai->fd, RADEON_FREE_MEM, &fm ); 198 if( result != B_OK ) { 199 SHOW_FLOW( 3, "ups - couldn't free memory (handle=%x, status=%s)", 200 node->mem_handle, strerror( result )); 201 } 202 203 ACQUIRE_BEN( si->engine.lock ); 204 205 // remove from list 206 if( node->next ) 207 node->next->prev = node->prev; 208 209 if( node->prev ) 210 node->prev->next = node->next; 211 else 212 vc->overlay_buffers = node->next; 213 214 RELEASE_BEN( si->engine.lock ); 215 216 SHOW_FLOW0( 3, "success" ); 217 218 return B_OK; 219 } 220 221 222 // public function: get constraints of overlay unit 223 status_t GET_OVERLAY_CONSTRAINTS( const display_mode *dm, const overlay_buffer *ob, 224 overlay_constraints *oc ) 225 { 226 SHOW_FLOW0( 3, "" ); 227 228 // probably, this is paranoia as we only get called by app_server 229 // which should know what it's doing 230 if( dm == NULL || ob == NULL || oc == NULL ) 231 return B_BAD_VALUE; 232 233 // scaler input restrictions 234 // TBD: check all these values; I reckon that 235 // most of them are too restrictive 236 237 // position 238 oc->view.h_alignment = 0; 239 oc->view.v_alignment = 0; 240 241 // alignment 242 switch (ob->space) { 243 case B_RGB15: 244 oc->view.width_alignment = 7; 245 break; 246 case B_RGB16: 247 oc->view.width_alignment = 7; 248 break; 249 case B_RGB32: 250 oc->view.width_alignment = 3; 251 break; 252 case B_YCbCr422: 253 oc->view.width_alignment = 7; 254 break; 255 case B_YUV12: 256 oc->view.width_alignment = 7; 257 default: 258 return B_BAD_VALUE; 259 } 260 oc->view.height_alignment = 0; 261 262 // size 263 oc->view.width.min = 4; // make 4-tap filter happy 264 oc->view.height.min = 4; 265 oc->view.width.max = ob->width; 266 oc->view.height.max = ob->height; 267 268 // scaler output restrictions 269 oc->window.h_alignment = 0; 270 oc->window.v_alignment = 0; 271 oc->window.width_alignment = 0; 272 oc->window.height_alignment = 0; 273 oc->window.width.min = 2; 274 oc->window.width.max = dm->virtual_width; 275 oc->window.height.min = 2; 276 oc->window.height.max = dm->virtual_height; 277 278 // TBD: these values need to be checked 279 // (shamelessly copied from Matrix driver) 280 oc->h_scale.min = 1.0f / (1 << 4); 281 oc->h_scale.max = 1 << 12; 282 oc->v_scale.min = 1.0f / (1 << 4); 283 oc->v_scale.max = 1 << 12; 284 285 SHOW_FLOW0( 3, "success" ); 286 287 return B_OK; 288 } 289 290 291 // public function: allocate overlay unit 292 overlay_token ALLOCATE_OVERLAY( void ) 293 { 294 shared_info *si = ai->si; 295 virtual_card *vc = ai->vc; 296 297 SHOW_FLOW0( 3, "" ); 298 299 if( atomic_or( &si->overlay_mgr.inuse, 1 ) != 0 ) { 300 SHOW_FLOW0( 3, "already in use" ); 301 return NULL; 302 } 303 304 SHOW_FLOW0( 3, "success" ); 305 306 vc->uses_overlay = true; 307 308 return (void *)++si->overlay_mgr.token; 309 } 310 311 312 // public function: release overlay unit 313 status_t RELEASE_OVERLAY(overlay_token ot) 314 { 315 virtual_card *vc = ai->vc; 316 shared_info *si = ai->si; 317 318 SHOW_FLOW0( 3, "" ); 319 320 if( (void *)si->overlay_mgr.token != ot ) 321 return B_BAD_VALUE; 322 323 if( si->overlay_mgr.inuse == 0 ) 324 return B_ERROR; 325 326 if( si->active_overlay.on ) 327 Radeon_HideOverlay( ai ); 328 329 si->overlay_mgr.inuse = 0; 330 vc->uses_overlay = false; 331 332 SHOW_FLOW0( 3, "released" ); 333 334 return B_OK; 335 } 336 337 338 // public function: show/hide overlay 339 status_t CONFIGURE_OVERLAY( overlay_token ot, const overlay_buffer *ob, 340 const overlay_window *ow, const overlay_view *ov ) 341 { 342 shared_info *si = ai->si; 343 status_t result; 344 345 SHOW_FLOW0( 4, "" ); 346 347 if ( (uintptr_t)ot != si->overlay_mgr.token ) 348 return B_BAD_VALUE; 349 350 if ( !si->overlay_mgr.inuse ) 351 return B_BAD_VALUE; 352 353 if ( ow == NULL || ov == NULL ) { 354 SHOW_FLOW0( 3, "hide only" ); 355 Radeon_HideOverlay( ai ); 356 return B_OK; 357 } 358 359 if ( ob == NULL ) 360 return B_ERROR; 361 362 ACQUIRE_BEN( si->engine.lock ); 363 364 // store whished values 365 si->pending_overlay.ot = ot; 366 si->pending_overlay.ob = *ob; 367 si->pending_overlay.ow = *ow; 368 si->pending_overlay.ov = *ov; 369 370 si->pending_overlay.on = (overlay_buffer_node *)((char *)ob - offsetof( overlay_buffer_node, buffer )); 371 372 result = Radeon_UpdateOverlay( ai ); 373 374 RELEASE_BEN( si->engine.lock ); 375 376 return result; 377 } 378