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