/* Copyright (c) 2002, Thomas Kurschel Part of Radeon accelerant Overlay interface */ #include "GlobalData.h" #include "radeon_interface.h" #include "video_overlay.h" #include #include #include #include "overlay_regs.h" #include "generic.h" // we could add support of planar modes and YUV modes // but I neither know how planar modes are defined nor // whether there is any program that makes use of them static uint32 overlay_colorspaces [] = { B_RGB15, B_RGB16, B_RGB32, B_YCbCr422, 0 }; // public function: number of overlay units uint32 OVERLAY_COUNT( const display_mode *dm ) { SHOW_FLOW0( 3, "" ); (void) dm; return 1; } // public function: return list of supported overlay colour spaces // dm - display mode where overlay is to be used const uint32 *OVERLAY_SUPPORTED_SPACES( const display_mode *dm ) { SHOW_FLOW0( 3, "" ); (void) dm; return overlay_colorspaces; } // public function: returns supported features // color_space - overlay's colour space uint32 OVERLAY_SUPPORTED_FEATURES( uint32 color_space ) { SHOW_FLOW0( 3, "" ); (void) color_space; return B_OVERLAY_COLOR_KEY | B_OVERLAY_HORIZONTAL_FILTERING | B_OVERLAY_VERTICAL_FILTERING; } // public function: allocates overlay buffer // cs - overlay's colour space // width, height - width and height of overlay buffer const overlay_buffer *ALLOCATE_OVERLAY_BUFFER( color_space cs, uint16 width, uint16 height ) { virtual_card *vc = ai->vc; shared_info *si = ai->si; radeon_alloc_mem am; overlay_buffer_node *node; overlay_buffer *buffer; status_t result; uint ati_space, test_reg, bpp; SHOW_FLOW0( 3, "" ); switch( cs ) { case B_RGB15: SHOW_FLOW0( 3, "RGB15" ); bpp = 2; ati_space = RADEON_SCALER_SOURCE_15BPP >> 8; test_reg = 0; break; case B_RGB16: SHOW_FLOW0( 3, "RGB16" ); bpp = 2; ati_space = RADEON_SCALER_SOURCE_16BPP >> 8; test_reg = 0; break; case B_RGB32: SHOW_FLOW0( 3, "RGB32" ); bpp = 4; ati_space = RADEON_SCALER_SOURCE_32BPP >> 8; test_reg = 0; break; case B_YCbCr422: SHOW_FLOW0( 3, "YCbCr422" ); bpp = 2; // strange naming convention: VYUY has to be read backward, // i.e. you get (low to high address) YUYV, which is what we want! ati_space = RADEON_SCALER_SOURCE_VYUY422 >> 8; test_reg = 0; break; // YUV12 is planar pixel format consisting of two or three planes // I have no clue whether and how this format is used in BeOS // (don't even know how it is defined officially) /* case B_YUV12: SHOW_FLOW0( 3, "YUV12" ); bpp = 2; uvpp = 1; ati_space = RADEON_SCALER_SOURCE_YUV12 >> 8; testreg = 0; break;*/ default: SHOW_FLOW( 3, "Unsupported format (%x)", (int)cs ); return NULL; } node = malloc( sizeof( overlay_buffer_node )); if( node == NULL ) return NULL; node->ati_space = ati_space; node->test_reg = test_reg; ACQUIRE_BEN( si->engine.lock ); // alloc graphics mem buffer = &node->buffer; buffer->space = cs; buffer->width = width; buffer->height = height; buffer->bytes_per_row = (width * bpp + 0xf) & ~0xf; am.magic = RADEON_PRIVATE_DATA_MAGIC; am.size = buffer->bytes_per_row * height; am.memory_type = mt_local; am.global = false; result = ioctl( ai->fd, RADEON_ALLOC_MEM, &am ); if( result != B_OK ) goto err; node->mem_handle = am.handle; node->mem_offset = am.offset; buffer->buffer = si->local_mem + am.offset; buffer->buffer_dma = (void *) ((unsigned long) si->framebuffer_pci + am.offset); // add to list of overlays node->next = vc->overlay_buffers; node->prev = NULL; if( node->next ) node->next->prev = node; vc->overlay_buffers = node; RELEASE_BEN( si->engine.lock ); SHOW_FLOW( 0, "success: mem_handle=%x, offset=%x, CPU-address=%x, phys-address=%x", node->mem_handle, node->mem_offset, buffer->buffer, buffer->buffer_dma ); return buffer; err: free(node); RELEASE_BEN( si->engine.lock ); return NULL; } // public function: discard overlay buffer status_t RELEASE_OVERLAY_BUFFER( const overlay_buffer *ob ) { virtual_card *vc = ai->vc; shared_info *si = ai->si; overlay_buffer_node *node; radeon_free_mem fm; status_t result; SHOW_FLOW0( 3, "" ); node = (overlay_buffer_node *)((char *)ob - offsetof( overlay_buffer_node, buffer )); if( si->active_overlay.on == node || si->active_overlay.prev_on ) Radeon_HideOverlay( ai ); // free memory fm.magic = RADEON_PRIVATE_DATA_MAGIC; fm.handle = node->mem_handle; fm.memory_type = mt_local; fm.global = false; result = ioctl( ai->fd, RADEON_FREE_MEM, &fm ); if( result != B_OK ) { SHOW_FLOW( 3, "ups - couldn't free memory (handle=%x, status=%s)", node->mem_handle, strerror( result )); } ACQUIRE_BEN( si->engine.lock ); // remove from list if( node->next ) node->next->prev = node->prev; if( node->prev ) node->prev->next = node->next; else vc->overlay_buffers = node->next; RELEASE_BEN( si->engine.lock ); SHOW_FLOW0( 3, "success" ); return B_OK; } // public function: get constraints of overlay unit status_t GET_OVERLAY_CONSTRAINTS( const display_mode *dm, const overlay_buffer *ob, overlay_constraints *oc ) { SHOW_FLOW0( 3, "" ); // probably, this is paranoia as we only get called by app_server // which should know what it's doing if( dm == NULL || ob == NULL || oc == NULL ) return B_BAD_VALUE; // scaler input restrictions // TBD: check all these values; I reckon that // most of them are too restrictive // position oc->view.h_alignment = 0; oc->view.v_alignment = 0; // alignment switch (ob->space) { case B_RGB15: oc->view.width_alignment = 7; break; case B_RGB16: oc->view.width_alignment = 7; break; case B_RGB32: oc->view.width_alignment = 3; break; case B_YCbCr422: oc->view.width_alignment = 7; break; case B_YUV12: oc->view.width_alignment = 7; default: return B_BAD_VALUE; } oc->view.height_alignment = 0; // size oc->view.width.min = 4; // make 4-tap filter happy oc->view.height.min = 4; oc->view.width.max = ob->width; oc->view.height.max = ob->height; // scaler output restrictions oc->window.h_alignment = 0; oc->window.v_alignment = 0; oc->window.width_alignment = 0; oc->window.height_alignment = 0; oc->window.width.min = 2; oc->window.width.max = dm->virtual_width; oc->window.height.min = 2; oc->window.height.max = dm->virtual_height; // TBD: these values need to be checked // (shamelessly copied from Matrix driver) oc->h_scale.min = 1.0f / (1 << 4); oc->h_scale.max = 1 << 12; oc->v_scale.min = 1.0f / (1 << 4); oc->v_scale.max = 1 << 12; SHOW_FLOW0( 3, "success" ); return B_OK; } // public function: allocate overlay unit overlay_token ALLOCATE_OVERLAY( void ) { shared_info *si = ai->si; virtual_card *vc = ai->vc; SHOW_FLOW0( 3, "" ); if( atomic_or( &si->overlay_mgr.inuse, 1 ) != 0 ) { SHOW_FLOW0( 3, "already in use" ); return NULL; } SHOW_FLOW0( 3, "success" ); vc->uses_overlay = true; return (void *)++si->overlay_mgr.token; } // public function: release overlay unit status_t RELEASE_OVERLAY(overlay_token ot) { virtual_card *vc = ai->vc; shared_info *si = ai->si; SHOW_FLOW0( 3, "" ); if( (void *)si->overlay_mgr.token != ot ) return B_BAD_VALUE; if( si->overlay_mgr.inuse == 0 ) return B_ERROR; if( si->active_overlay.on ) Radeon_HideOverlay( ai ); si->overlay_mgr.inuse = 0; vc->uses_overlay = false; SHOW_FLOW0( 3, "released" ); return B_OK; } // public function: show/hide overlay status_t CONFIGURE_OVERLAY( overlay_token ot, const overlay_buffer *ob, const overlay_window *ow, const overlay_view *ov ) { shared_info *si = ai->si; status_t result; SHOW_FLOW0( 4, "" ); if ( (uintptr_t)ot != si->overlay_mgr.token ) return B_BAD_VALUE; if ( !si->overlay_mgr.inuse ) return B_BAD_VALUE; if ( ow == NULL || ov == NULL ) { SHOW_FLOW0( 3, "hide only" ); Radeon_HideOverlay( ai ); return B_OK; } if ( ob == NULL ) return B_ERROR; ACQUIRE_BEN( si->engine.lock ); // store whished values si->pending_overlay.ot = ot; si->pending_overlay.ob = *ob; si->pending_overlay.ow = *ow; si->pending_overlay.ov = *ov; si->pending_overlay.on = (overlay_buffer_node *)((char *)ob - offsetof( overlay_buffer_node, buffer )); result = Radeon_UpdateOverlay( ai ); RELEASE_BEN( si->engine.lock ); return result; }