/*************************************************************************** * Copyright (c) 2003-2006, Broadcom Corporation * All Rights Reserved * Confidential Property of Broadcom Corporation * * THIS SOFTWARE MAY ONLY BE USED SUBJECT TO AN EXECUTED SOFTWARE LICENSE * AGREEMENT BETWEEN THE USER AND BROADCOM. YOU HAVE NO RIGHT TO USE OR * EXPLOIT THIS MATERIAL EXCEPT SUBJECT TO THE TERMS OF SUCH AN AGREEMENT. * * $brcm_Workfile: $ * $brcm_Revision: $ * $brcm_Date: $ * * Module Description: * * Revision History: * * $brcm_Log: $ * ***************************************************************************/ #include "bsettop_graphics.h" #include "bsettop_display.h" #include "bsettop_display_priv.h" #include "bstd.h" #include "bos.h" #include "cache_util.h" #include "gist.h" #ifdef CONFIG_GFX_ARGB32 #include "bgrc.h" #endif BDBG_MODULE(bsettop_graphics); typedef enum bgraphics_state_t { eGS_UNINITIALIZED, eGS_OPENED }bgraphics_state_t; struct bgraphics { bgraphics_state_t state; bdisplay_t display; BFMT_VideoFmt eSurfaceFmt; BFMT_VideoFmt eOSDFmt; #ifdef CONFIG_GFX_ARGB32 BGRC_Handle grc; /* grc handle */ int32_t coeffs_ycbcr[20]; /* coefficient table from RGB to YCbCr */ int32_t coeffs_rgb[20]; BKNI_EventHandle event; /* event for waiting GRC is complete */ b_mutex_t mutex; #endif }; static struct bgraphics s_graphics = { eGS_UNINITIALIZED, NULL, BFMT_VideoFmt_eNTSC, BFMT_VideoFmt_eNTSC }; #ifdef CONFIG_GFX_ARGB32 typedef struct bsurface_create_settings { uint32_t width; uint32_t height; BPXL_Format pxl_format; } bsurface_create_settings; static BERR_Code bgraphics_p_surface_create(bgraphics_t graphics, const bsurface_create_settings *psettings, bsettop_surf_t *surface); static void bgraphics_p_surface_destroy(bgraphics_t graphics, bsettop_surf_t surface); static BERR_Code bgraphics_p_flip_osd(bgraphics_t graphics, bgraphics_id id, bool overlay); static BERR_Code bgraphics_p_set_event(BGRC_Handle hGrc, void *pData); static void b_graphics_calculate_coeffs_table(bool src_rgb, bool dest_rgb, int32_t *pcoeffs); #endif static bgraphics_settings s_settings = {bgraphics_pixel_format_a8_r8_g8_b8}; /** Summary: Release graphics surface resources. **/ static BERR_Code bgraphics_surface_destroy(bgraphics_t graphics) { BERR_Code rc; bdisplay_t display; BDBG_ASSERT(graphics); BDBG_ASSERT(graphics->display); display = graphics->display; #if HAS_HDMI if (display->disp[eBDISPLAY_HDMI].hGfxSource) { rc = BVDC_Source_Destroy(display->disp[eBDISPLAY_HDMI].hGfxSource); if (rc != BERR_SUCCESS) { BDBG_ERR(("BVDC_Source_Destroy failed %d\n", rc)); } display->disp[eBDISPLAY_HDMI].hGfxSource = NULL; } #endif if (display->disp[eBDISPLAY_COMPOSITE].hGfxSource) { rc = BVDC_Source_Destroy(display->disp[eBDISPLAY_COMPOSITE].hGfxSource); if (rc != BERR_SUCCESS) { BDBG_ERR(("BVDC_Source_Destroy failed %d\n", rc)); } display->disp[eBDISPLAY_COMPOSITE].hGfxSource = NULL; } #ifdef CONFIG_GFX_ARGB32 bgraphics_p_surface_destroy(graphics, display->offscreen); bgraphics_p_surface_destroy(graphics, display->osd); bgraphics_p_surface_destroy(graphics, display->overlay); #else for (display->surface_idx = eBSURFACE_0; display->surface_idx < eBSURFACE_MAX; display->surface_idx++) { if (display->osd[display->surface_idx].hSurface) { rc = BSUR_Surface_Destroy(display->osd[display->surface_idx].hSurface); if (rc != BERR_SUCCESS) { BDBG_ERR(("BSUR_Surface_Destroy failed %d\n", rc)); } display->osd[display->surface_idx].hSurface = NULL; } if (display->osd[display->surface_idx].hPalette) { rc = BSUR_Palette_Destroy(display->osd[display->surface_idx].hPalette); if (rc != BERR_SUCCESS) { BDBG_ERR(("BSUR_Surface_Create failed %d\n", rc)); } display->osd[display->surface_idx].hPalette = NULL; } } #endif rc = BVDC_ApplyChanges(display->hVdc); if (rc != BERR_SUCCESS) { BDBG_ERR(("BVDC_ApplyChanges failed %d\n", rc)); } return BERR_SUCCESS; } /** Summary: Allocate and reserve resources. Expects allocated graphics structure. **/ static BERR_Code bgraphics_surface_create(bgraphics_t graphics) { BERR_Code rc; bdisplay_t display; BFMT_VideoInfo formatInfo; BFMT_VideoInfo osdFormatInfo; BAVC_Gfx_Picture gfxPicture; #ifdef CONFIG_GFX_ARGB32 bsurface_create_settings settings; #endif BDBG_ASSERT(graphics); BDBG_ASSERT(graphics->display); display = graphics->display; rc = BFMT_GetVideoFormatInfo(graphics->eSurfaceFmt,&formatInfo); if (rc != BERR_SUCCESS) { BDBG_ERR(("BFMT_GetVideoFormatInfo failed %d\n", rc)); goto error; } rc = BFMT_GetVideoFormatInfo(graphics->eOSDFmt,&osdFormatInfo); if (rc != BERR_SUCCESS) { BDBG_ERR(("BFMT_GetVideoFormatInfo failed %d\n", rc)); goto error; } #ifdef CONFIG_GFX_ARGB32 settings.width = osdFormatInfo.ulDigitalWidth; settings.height = osdFormatInfo.ulDigitalHeight; settings.pxl_format = BPXL_eA8_R8_G8_B8; /* create offscreen RGB888 surface */ bgraphics_p_surface_create(graphics, &settings, &display->offscreen); /* create overlay RGB888 surface */ bgraphics_p_surface_create(graphics, &settings, &display->overlay); /* create frame buffer for both GFD0/GFD1 */ bgraphics_p_surface_create(graphics, &settings, &display->osd); #else /* Create surfaces so graphics sources can set the sureface */ for (display->surface_idx = eBSURFACE_0; display->surface_idx < eBSURFACE_MAX; display->surface_idx++) { rc = BSUR_Palette_Create(GetHEAP(),BPXL_NUM_PALETTE_ENTRIES(display->pxl_format), NULL,BPXL_eA8_Y8_Cb8_Cr8, BSUR_CONSTRAINT_ADDRESS_PIXEL_ALIGNED, &display->osd[display->surface_idx].hPalette); if (rc != BERR_SUCCESS) { BDBG_ERR(("BSUR_Palette_Create failed %d\n", rc)); goto error; } rc = BSUR_Palette_GetAddress(display->osd[display->surface_idx].hPalette, (void**)&(display->osd[display->surface_idx].p_palette)); if (rc != BERR_SUCCESS) { BDBG_ERR(("BSUR_Palette_GetAddress failed %d\n", rc)); goto error; } rc = BSUR_Surface_Create(GetHEAP(),osdFormatInfo.ulDigitalWidth,osdFormatInfo.ulDigitalHeight, 0,NULL,display->pxl_format, display->osd[display->surface_idx].hPalette, BSUR_CONSTRAINT_ADDRESS_PIXEL_ALIGNED,NULL,&(display->osd[display->surface_idx].hSurface)); if (rc != BERR_SUCCESS) { BDBG_ERR(("BSUR_Surface_Create failed %d\n", rc)); goto error; } rc = BSUR_Surface_GetAddress(display->osd[display->surface_idx].hSurface, (void**)&(display->osd[display->surface_idx].p_pixels), &(display->osd[display->surface_idx].pitch)); if (rc != BERR_SUCCESS) { BDBG_ERR(("BSUR_Surface_GetAddress failed %d\n", rc)); goto error; } } display->surface_idx = eBSURFACE_0; #endif #if HAS_HDMI rc = BVDC_Source_Create(display->hVdc,&(display->disp[eBDISPLAY_HDMI].hGfxSource),BAVC_SourceId_eGfx0 + eBDISPLAY_HDMI,NULL); if (rc != BERR_SUCCESS) { BDBG_ERR(("BFMT_GetVideoFormatInfo failed %d\n", rc)); goto error; } BVDC_Source_DisableColorKey(display->disp[eBDISPLAY_HDMI].hGfxSource); BVDC_Source_SetHorizontalScaleCoeffs(display->disp[eBDISPLAY_HDMI].hGfxSource,BVDC_FilterCoeffs_eAnisotropic); #ifdef CONFIG_GFX_ARGB32 gfxPicture.hSurface = display->osd->hSurface; #else gfxPicture.hSurface = display->osd[display->surface_idx]->hSurface; #endif /* same for R surface */ gfxPicture.hRSurface = NULL; gfxPicture.hAlphaSurface = NULL; gfxPicture.hAlphaRSurface = NULL; gfxPicture.ucW0Alpha = 0; gfxPicture.ucW1Alpha = 0; gfxPicture.eInOrientation = BFMT_Orientation_e2D; rc = BVDC_Source_SetSurface( display->disp[eBDISPLAY_HDMI].hGfxSource, &gfxPicture ); if (rc != BERR_SUCCESS) { BDBG_ERR(("BVDC_Source_SetSurface failed %d\n", rc)); goto error; } rc = BVDC_ApplyChanges(display->hVdc); if (rc != BERR_SUCCESS) { BDBG_ERR(("BVDC_ApplyChanges failed %d\n", rc)); } #endif #ifndef CONFIG_NO_SD_OUTPUT rc = BVDC_Source_Create(display->hVdc,&(display->disp[eBDISPLAY_COMPOSITE].hGfxSource),BAVC_SourceId_eGfx0 + eBDISPLAY_COMPOSITE,NULL); if (rc != BERR_SUCCESS) { BDBG_ERR(("BFMT_GetVideoFormatInfo failed %d\n", rc)); goto error; } BVDC_Source_DisableColorKey(display->disp[eBDISPLAY_COMPOSITE].hGfxSource); BVDC_Source_SetHorizontalScaleCoeffs(display->disp[eBDISPLAY_COMPOSITE].hGfxSource,BVDC_FilterCoeffs_eAnisotropic); #ifdef CONFIG_GFX_ARGB32 gfxPicture.hSurface = display->osd->hSurface; #else gfxPicture.hSurface = display->osd[display->surface_idx]->hSurface; #endif /* same for R surface */ gfxPicture.hRSurface = NULL; gfxPicture.hAlphaSurface = NULL; gfxPicture.hAlphaRSurface = NULL; gfxPicture.ucW0Alpha = 0; gfxPicture.ucW1Alpha = 0; gfxPicture.eInOrientation = BFMT_Orientation_e2D; rc = BVDC_Source_SetSurface( display->disp[eBDISPLAY_COMPOSITE].hGfxSource, &gfxPicture ); if (rc != BERR_SUCCESS) { BDBG_ERR(("BVDC_Source_SetSurface failed %d\n", rc)); goto error; } rc = BVDC_ApplyChanges(display->hVdc); if (rc != BERR_SUCCESS) { BDBG_ERR(("BVDC_ApplyChanges failed %d\n", rc)); } #endif display->surface_idx = eBSURFACE_1; return BERR_SUCCESS; error: bgraphics_surface_destroy(graphics); return rc; } /** Summary: Open and enable a graphics engine. Description: Each display can have only one graphics engine. A graphics engine can only go to one display. Graphics can also appear on a second display when it is driven by a cloned window (see bdecode_window_close), however those graphics are identical to the other display. When the display format for the linked display changes, the graphics engine will be automatically disabled. See bdisplay_set for details. bgraphics_t bgraphics_open( bobject_t id, bdisplay_t display display on which the graphics are displayed ); **/ bgraphics_t bgraphics_open( bobject_t id, bdisplay_t display) { if (s_graphics.state > eGS_UNINITIALIZED) return (bgraphics_t)0; s_graphics.display = display; if (s_settings.format == bgraphics_pixel_format_palette4) display->pxl_format = BPXL_eP4; else if (s_settings.format == bgraphics_pixel_format_palette8) display->pxl_format = BPXL_eP8; else if (s_settings.format == bgraphics_pixel_format_r5_g6_b5) display->pxl_format = BPXL_eR5_G6_B5; #ifdef CONFIG_GFX_ARGB32 if (BGRC_Open(&s_graphics.grc, GetCHP(), GetREG(), GetHEAP(), GetINT(), NULL) != BERR_SUCCESS) { BDBG_WRN(("BGRC_Open failed")); return (bgraphics_t)0; } if (BGRC_Source_ToggleFilter(s_graphics.grc, false, false) != BERR_SUCCESS) { BDBG_WRN(("BGRC_Source_ToggleFilter failed")); } if (BGRC_Source_ToggleColorKey(s_graphics.grc, false) != BERR_SUCCESS) { BDBG_WRN(("BGRC_Source_ToggleColorKey failed")); } if (BGRC_Output_SetColorKeySelection(s_graphics.grc, BGRC_Output_ColorKeySelection_eTakeBlend, BGRC_Output_ColorKeySelection_eTakeSource, BGRC_Output_ColorKeySelection_eTakeDestination, BGRC_Output_ColorKeySelection_eTakeDestination) != BERR_SUCCESS) { BDBG_WRN(("BGRC_Output_SetColorKeySelection failed")); } /* calculate coefficient table for offscreen->SD frame buffer */ b_graphics_calculate_coeffs_table(true, false, s_graphics.coeffs_ycbcr); b_graphics_calculate_coeffs_table(false, true, s_graphics.coeffs_rgb); BKNI_CreateEvent(&s_graphics.event); bos_create_mutex(&s_graphics.mutex); #endif b_lock_vdc(); if (bgraphics_surface_create(&s_graphics) != BERR_SUCCESS) { goto error; } #if HAS_HDMI if (bdisplay_graphics_window_open(display,eBDISPLAY_HDMI) != BERR_SUCCESS) { bgraphics_surface_destroy(&s_graphics); goto error; } #endif #ifndef CONFIG_NO_SD_OUTPUT if (bdisplay_graphics_window_open(display,eBDISPLAY_COMPOSITE) != BERR_SUCCESS) { #if HAS_HDMI bdisplay_graphics_window_close(display,eBDISPLAY_HDMI); #endif bgraphics_surface_destroy(&s_graphics); goto error; } #endif s_graphics.state = eGS_OPENED; b_unlock_vdc(); return (bgraphics_t)&s_graphics; error: b_unlock_vdc(); return (bgraphics_t)0; } /* Summary: Close a graphics engine. Description: You should close all surfaces before closing a graphics engine. Also, you must close graphics before closing the display to which it is linked. Generally, close things in the opposite order in which you brought them up. void bgraphics_close( bgraphics_t graphics handle returned by bgraphics_open ); */ void bgraphics_close( bgraphics_t graphics ) { if (graphics->state == eGS_OPENED) { b_lock_vdc(); bgraphics_surface_destroy(graphics); #if HAS_HDMI bdisplay_graphics_window_close(graphics->display,eBDISPLAY_HDMI); #endif bdisplay_graphics_window_close(graphics->display,eBDISPLAY_COMPOSITE); #ifdef CONFIG_GFX_ARGB32 BGRC_Close(graphics->grc); BKNI_DestroyEvent(graphics->event); bos_delete_mutex(&graphics->mutex); #endif graphics->state = eGS_UNINITIALIZED; b_unlock_vdc(); } } /* Summary: Get the graphics framebuffer parameters bresult bgraphics_get_framebuffer( bgraphics_t graphics, handle returned by bgraphics_open void **buffer, [out] address of framebuffer memory unsinged int **palette, [out] address of palette int *width, [out] width of the OSD surface int *height, [out] height of the OSD surface int *pitch [out] pitch of the OSD surface ); */ bresult bgraphics_get_framebuffer( bgraphics_t graphics, void **buffer, unsigned int **palette, int *width, int *height, int *pitch) { BFMT_VideoInfo osdFormatInfo; bdisplay_t display; BERR_Code rc; BDBG_ASSERT(graphics); BDBG_ASSERT(graphics->display); display = graphics->display; rc = BFMT_GetVideoFormatInfo(graphics->eOSDFmt,&osdFormatInfo); if (rc != BERR_SUCCESS) { BDBG_ERR(("BFMT_GetVideoFormatInfo failed %d\n", rc)); return rc; } #ifdef CONFIG_GFX_ARGB32 /* return offscreen frame buffer */ *buffer = display->offscreen->p_pixels; *palette = (unsigned int *)display->offscreen->p_palette; *pitch = display->offscreen->pitch; *width = display->offscreen->width; *height = display->offscreen->height; #else *buffer = display->osd[display->surface_idx]->p_pixels; *palette = (unsigned int*)display->osd[display->surface_idx]->p_palette; *width = osdFormatInfo.ulDigitalWidth; *height = osdFormatInfo.ulDigitalHeight; *pitch = display->osd[display->surface_idx]->pitch; #endif return b_ok; } #ifdef CONFIG_GFX_ARGB32 bresult bgraphics_get_osd_params(bgraphics_t graphics, bsettop_surf_t *p_osd_surf, void **osd_buffer, bsettop_surf_t *p_overlay_surf, void **overlay_mem) { bdisplay_t display; BDBG_ASSERT(graphics); BDBG_ASSERT(graphics->display); display = graphics->display; if (p_osd_surf && osd_buffer) { *p_osd_surf = display->offscreen; *osd_buffer = display->offscreen->p_pixels; } if (overlay_mem && p_overlay_surf) { *overlay_mem = display->overlay->p_pixels; *p_overlay_surf = display->overlay; } return b_ok; } #endif /** Summary: Wait for vsync. id : bgraphics_id to be updated **/ bresult bgraphics_osd_flush(bgraphics_t graphics, bgraphics_id id, bool overlay) { BERR_Code rc; bdisplay_t display; #ifndef CONFIG_GFX_ARGB32 BAVC_Gfx_Picture gfxPicture; #endif BDBG_ASSERT(graphics); BDBG_ASSERT(graphics->display); display = graphics->display; #ifdef CONFIG_GFX_ARGB32 rc = bgraphics_p_flip_osd(graphics, id, overlay); #else b_lock_vdc(); gfxPicture.hSurface = display->osd[display->surface_idx].hSurface; /* same for R surface */ gfxPicture.hRSurface = NULL; gfxPicture.hAlphaSurface = NULL; gfxPicture.hAlphaRSurface = NULL; gfxPicture.ucW0Alpha = 0; gfxPicture.ucW1Alpha = 0; gfxPicture.eInOrientation = BFMT_Orientation_e2D; #if HAS_HDMI rc = BVDC_Source_SetSurface( display->disp[eBDISPLAY_HDMI].hGfxSource, &gfxPicture ); if (rc != BERR_SUCCESS) { BDBG_ERR(("BVDC_Source_SetSurface failed %d\n", rc)); b_unlock_vdc(); return rc; } #endif #ifndef CONFIG_NO_SD_OUTPUT gfxPicture.hSurface = display->osd[display->surface_idx].hSurface; /* same for R surface */ gfxPicture.hRSurface = NULL; gfxPicture.hAlphaSurface = NULL; gfxPicture.hAlphaRSurface = NULL; gfxPicture.ucW0Alpha = 0; gfxPicture.ucW1Alpha = 0; gfxPicture.eInOrientation = BFMT_Orientation_e2D; rc = BVDC_Source_SetSurface( display->disp[eBDISPLAY_COMPOSITE].hGfxSource, &gfxPicture ); if (rc != BERR_SUCCESS) { BDBG_ERR(("BVDC_Source_SetSurface failed %d\n", rc)); b_unlock_vdc(); return rc; } #endif rc = BVDC_ApplyChanges(display->hVdc); if (rc != BERR_SUCCESS) { BDBG_ERR(("BVDC_ApplyChanges failed %d\n", rc)); } display->surface_idx++; if (display->surface_idx >= eBSURFACE_MAX) { display->surface_idx = eBSURFACE_0; } rc = b_ok; b_unlock_vdc(); #endif return rc; } /** Summary: Block until vsync. bresult bgraphics_sync( bgraphics_t g handle returned by bgraphics_open ); **/ bresult bgraphics_sync( bgraphics_t g, bool overlay) { return bgraphics_osd_flush(g, eGRAPHICS_BOTH, overlay); } /** * Summary: * update HD frame buffer only * id: graphics_id to be updated */ bresult bgraphics_sync_partial(bgraphics_t g, bgraphics_id id, bool overlay) { if (!(id&eGRAPHICS_BOTH)) id = eGRAPHICS_BOTH; return bgraphics_osd_flush(g, id, overlay); } /* Summary: Reload the graphics palette bresult bgraphics_load_palette( bgraphics_t g handle returned by bgraphics_open ); */ bresult bgraphics_load_palette( bgraphics_t graphics ) { #ifndef CONFIG_GFX_ARGB32 bsettop_surf_idx_t osd_surface_idx; bdisplay_t display; BDBG_ASSERT(graphics); BDBG_ASSERT(graphics->display); display = graphics->display; for (osd_surface_idx=0; osd_surface_idxsurface_idx) { BKNI_Memcpy(display->osd[osd_surface_idx].p_palette, display->osd[display->surface_idx].p_palette, BPXL_NUM_PALETTE_ENTRIES(display->pxl_format)* sizeof(unsigned int)); } } return bgraphics_osd_flush(graphics, eGRAPHICS_BOTH, false); #endif return b_ok; } /** Summary: Set graphics settings. **/ bresult bgraphics_set( const bgraphics_settings *settings ) { if ((settings->format != bgraphics_pixel_format_palette4) && (settings->format != bgraphics_pixel_format_palette8) && (settings->format != bgraphics_pixel_format_r5_g6_b5)) { return berr_invalid_parameter; } s_settings.format = settings->format; return b_ok; } /** Summary: Get current graphics settings. **/ void bgraphics_get( bgraphics_settings *settings /* [out] */ ) { *settings = s_settings; return; } #ifdef CONFIG_GFX_ARGB32 static BERR_Code bgraphics_p_set_event(BGRC_Handle hGrc, void *pData) { BKNI_SetEvent((BKNI_EventHandle)pData); return 0; } /* * Description: * RGB to YCbCr color matrix table. * * Y = R * 0.257 + G * 0.504 + B * 0.098 + A * 0 + 16 * Cb = R * -0.148 + G * -0.291 + B * 0.439 + A * 0 + 128 * Cr = R * 0.439 + G * -0.368 + B * -0.071 + A * 0 + 128 * A = R * 0 + G * 0 + B * 0 + A * 1 + 0 */ static const float s_Matrix_RGBtoYCbCr[25] = { 0.257, 0.504, 0.098, 0, 16, -0.148, -0.291, 0.439, 0, 128, 0.439, -0.368, -0.071, 0, 128, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1 }; /*************************************************************************** * Description: * YCbCr to RGB color matrix table. *****************************************************************************/ /* R = Y * 1.164 + Cb * 0 + Cr * 1.596 + A * 0 - 223 */ /* G = Y * 1.164 + Cb * -0.391 + Cr * -0.813 + A * 0 + 136 */ /* B = Y * 1.164 + Cb * 2.018 + Cr * 0 + A * 0 - 277 */ /* A = Y * 0 + Cb * 0 + Cr * 0 + A * 1 - 0 */ static const float s_Matrix_YCbCrtoRGB[25] = { 1.164, 0, 1.596, 0, -223, 1.164, -0.391, -0.813, 0, 136, 1.164, 2.018, 0, 0, -277, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1 }; static void bgraphics_cacheflush(bsettop_surf_t surf); /* Description: * Coefficient table for RGB (offscreen) to YCbCr(GFD1 for composite) */ static void b_graphics_calculate_coeffs_table(bool src_rgb, bool dest_rgb, int32_t *pcoeffs) { float a[25], b[25]; int i,j,k; BKNI_Memset(a, 0, sizeof(a)); BKNI_Memset(b, 0, sizeof(b)); for (i=0; i<=24; i+=6) a[i] = 1.0; if (src_rgb) { for (i=0; i<=4; i++) for (j=0; j<=4; j++) for (k=0; k<=4; k++) b[i*5+j] += a[i*5+k]*s_Matrix_RGBtoYCbCr[k*5+j]; for (i=0; i<=24; i++) a[i] = b[i]; BKNI_Memset(b, 0, sizeof(b)); } if (dest_rgb) { for (i=0; i<=4; i++) for (j=0; j<=4; j++) for (k=0; k<=4; k++) b[i * 5 + j] += s_Matrix_YCbCrtoRGB[i * 5 + k] * a[k * 5 + j]; for (i=0; i<=24; i++) a[i] = b[i]; } for (i=0; i<=19; i++) pcoeffs[i] = (int32_t)(a[i]*(1<<10)); return; } /* * Description * Blit source surface + destination to output surface */ bresult bsurface_blit_surface(bsettop_surf_t src_surf, bsettop_rect *src_r, bsettop_surf_t dst_surf, bsettop_rect *dst_r, bsettop_surf_t out_surf, bsettop_rect *out_r) { BGRC_Handle grc; BERR_Code rc; bgraphics_t graphics = &s_graphics; int32_t *coeffs = NULL; BDBG_ASSERT(graphics->grc); grc = s_graphics.grc; if (bos_acquire_mutex(&s_graphics.mutex, 500) != b_ok) { BDBG_WRN(("fail to get graphics mutex")); return BERR_SUCCESS; } /* clear the GRC state */ BGRC_ResetState(grc); /* set source surface and rectangle */ rc = BGRC_Source_SetSurface(grc, src_surf->hSurface); if (rc != BERR_SUCCESS) { BDBG_ERR(("BGRC_Source_SetSurface failed: %d", rc)); goto blit_err; } rc = BGRC_Source_SetRectangle(grc, src_r->x, src_r->y, src_r->width, src_r->height); if (rc != BERR_SUCCESS) { BDBG_ERR(("BGRC_Source_SetRectangle failed: %d", rc)); goto blit_err; } /* set scale coefficients */ if ((src_r->width != out_r->width) || (src_r->height != out_r->height)) { rc = BGRC_Source_ToggleFilter(grc, true, true); if (rc != BERR_SUCCESS) { BDBG_ERR(("BGRC_Source_ToggleFilter failed: %d")); goto blit_err; } rc = BGRC_Source_SetFilterCoeffs(grc, BGRC_FilterCoeffs_eAnisotropic, BGRC_FilterCoeffs_eAnisotropic); if (rc != BERR_SUCCESS) { BDBG_ERR(("BGRC_Source_SetFilterCoeffs failed: %d", rc)); goto blit_err; } } else { /* no scaling */ rc = BGRC_Source_ToggleFilter(grc, false, false); if (rc != BERR_SUCCESS) { BDBG_ERR(("BGRC_Source_ToggleFilter failed: %d", rc)); goto blit_err; } } /* disable color keying */ rc = BGRC_Source_ToggleColorKey(grc, false); if (rc != BERR_SUCCESS) { BDBG_ERR(("BGRC_Source_ToggleColorKey failed: %d", rc)); goto blit_err; } if (src_surf->pixel_format != out_surf->pixel_format) { /* color space conversion required */ rc = BGRC_Source_ToggleColorMatrix(grc, true); if (rc != BERR_SUCCESS) { BDBG_ERR(("BGRC_Source_ToggleColorMatrix failed: %d", rc)); goto blit_err; } if (src_surf->pixel_format == BPXL_eA8_R8_G8_B8) { if (out_surf->pixel_format == BPXL_eA8_Y8_Cb8_Cr8) { coeffs = graphics->coeffs_ycbcr; } } else if (src_surf->pixel_format == BPXL_eA8_Y8_Cb8_Cr8) { if (out_surf->pixel_format == BPXL_eA8_R8_G8_B8) { coeffs = graphics->coeffs_rgb; } } if (coeffs == NULL) { BDBG_WRN(("Unsupported CSC : %d -> %d", src_surf->pixel_format, out_surf->pixel_format)); /* disable CSC */ BGRC_Source_ToggleColorMatrix(grc, false); } else { rc = BGRC_Source_SetColorMatrix5x4(grc, coeffs, 10); if (rc != BERR_SUCCESS) { BDBG_ERR(("BGRC_Source_SetColorMatrix5x4 failed: %d", rc)); goto blit_err; } } } else { rc = BGRC_Source_ToggleColorMatrix(grc, false); if (rc != BERR_SUCCESS) { BDBG_ERR(("BGRC_Source_ToggleColorMatrx failed:%d", rc)); } } /* set destination surface if exist */ if (dst_surf) { rc = BGRC_Destination_SetSurface(grc, dst_surf->hSurface); if (rc != BERR_SUCCESS) { BDBG_ERR(("BGRC_Destination_SetSurface failed: %d",rc)); goto blit_err; } rc = BGRC_Destination_SetRectangle(grc, dst_r->x, dst_r->y, dst_r->width, dst_r->height); if (rc != BERR_SUCCESS) { BDBG_ERR(("BGRC_Destination_SetRectangle failed: %d", rc)); goto blit_err; } } /* set output surface and rectangle */ rc = BGRC_Output_SetSurface(grc, out_surf->hSurface); if (rc != BERR_SUCCESS) { BDBG_ERR(("BGRC_Output_SetSurface failed: %d", rc)); goto blit_err; } rc = BGRC_Output_SetRectangle(grc, out_r->x, out_r->y, out_r->width, out_r->height); if (rc != BERR_SUCCESS) { BDBG_ERR(("BGRC_Output_SetRectangle faield: %d", rc)); goto blit_err; } /* setup blend setting */ if (dst_surf) { rc = BGRC_Output_SetColorKeySelection(grc, BGRC_Output_ColorKeySelection_eTakeBlend, /* default is eTakeSource */ BGRC_Output_ColorKeySelection_eTakeSource, BGRC_Output_ColorKeySelection_eTakeDestination, BGRC_Output_ColorKeySelection_eTakeDestination); if (rc != BERR_SUCCESS) { BDBG_ERR(("BGRC_Output_SetColorKeySelection failed: %d", rc)); goto blit_err; } rc = BGRC_Blend_SetColorBlend(grc, BGRC_Blend_Source_eSourceColor,BGRC_Blend_Source_eSourceAlpha, false, BGRC_Blend_Source_eDestinationColor,BGRC_Blend_Source_eInverseSourceAlpha, false, BGRC_Blend_Source_eZero); if (rc != BERR_SUCCESS) { BDBG_ERR(("BGRC_Blend_SetColorBlend failed: %d", rc)); goto blit_err; } rc = BGRC_Blend_SetAlphaBlend(grc, BGRC_Blend_Source_eSourceAlpha,BGRC_Blend_Source_eOne, false, BGRC_Blend_Source_eDestinationAlpha, BGRC_Blend_Source_eInverseSourceAlpha, false, BGRC_Blend_Source_eZero); if (rc != BERR_SUCCESS) { BDBG_ERR(("BGRC_Blend_SetAlphaBlend failed: %d", rc)); goto blit_err; } } else { rc = BGRC_Blend_SetAlphaBlend(grc, BGRC_Blend_Source_eSourceAlpha,BGRC_Blend_Source_eOne, false, BGRC_Blend_Source_eZero, BGRC_Blend_Source_eZero, false, BGRC_Blend_Source_eZero); } bgraphics_cacheflush(src_surf); if (dst_surf != out_surf) { bgraphics_cacheflush(out_surf); } if (dst_surf) { bgraphics_cacheflush(dst_surf); } rc = BGRC_IssueState(grc, bgraphics_p_set_event, graphics->event); if (rc != BERR_SUCCESS) { BDBG_ERR(("BGRC_IssueState failed: %d", rc)); goto blit_err; } bos_release_mutex(&s_graphics.mutex); rc = BKNI_WaitForEvent(graphics->event, 500000); if (rc == BERR_TIMEOUT) rc = berr_timeout; else if (rc != BERR_SUCCESS) BDBG_ERR(("BKNI_WaitForEvent failed %d (%d)", rc, __LINE__)); return rc; blit_err: bos_release_mutex(&s_graphics.mutex); return (rc == BERR_SUCCESS) ? b_ok : berr_invalid_parameter; } /* Description: * Blit offscreen to OSD frame buffer */ static BERR_Code bgraphics_p_flip_osd(bgraphics_t graphics, bgraphics_id id, bool overlay) { BERR_Code rc; bsettop_surf_t out_surf,dst_surf,src_surf; bsettop_rect out_r,dst_r,src_r; BDBG_ASSERT(graphics); rc = BERR_UNKNOWN; BKNI_Memset(&src_r, 0, sizeof(src_r)); BKNI_Memset(&dst_r, 0, sizeof(dst_r)); BKNI_Memset(&out_r, 0, sizeof(out_r)); out_surf = graphics->display->osd; out_r.width = out_surf->width; out_r.height = out_surf->height; if (!overlay) { src_surf = graphics->display->offscreen; dst_surf = NULL; /* blit offscreen into framebuffer */ src_r.width = src_surf->width; src_r.height = src_surf->height; rc = bsurface_blit_surface(src_surf,&src_r, dst_surf,&dst_r, out_surf, &out_r ); } else { /* alpha blending : overlay+offscreen -> HD frame buffer */ src_surf = graphics->display->overlay; dst_surf = graphics->display->offscreen; src_r.width = src_surf->width; src_r.height = src_surf->height; dst_r.width = dst_surf->width; dst_r.height = dst_surf->height; rc = bsurface_blit_surface(src_surf,&src_r, dst_surf,&dst_r, out_surf, &out_r ); } return rc; } /* Description: * Fill surface */ bresult bsurface_fill(bsettop_surf_t surface, bsettop_rect *rect, bgraphics_pixel pixel) { BGRC_Handle grc; BERR_Code rc; unsigned int aycbcr_pixel; grc = s_graphics.grc; BDBG_ASSERT(grc); BDBG_ASSERT(surface); if (!rect->width || !rect->height) return b_ok; if (bos_acquire_mutex(&s_graphics.mutex, 500) != b_ok) { BDBG_WRN(("fail to get graphics mutex")); return b_ok; } BGRC_ResetState(grc); rc = BGRC_Destination_SetSurface(grc, NULL); if (rc != BERR_SUCCESS) { BDBG_ERR(("BGRC_Destination_SetSurface failed: %d", rc)); goto fill_err; } switch (surface->pixel_format) { case bgraphics_pixel_format_palette2: pixel = (pixel & 0x3) << 6; break; case bgraphics_pixel_format_palette4: pixel = (pixel & 0xF) << 4; break; case bgraphics_pixel_format_a8_palette8: pixel = ((pixel&0xFF00)<<16) | (pixel&0xFF); break; case bgraphics_pixel_format_a8: pixel = (pixel & 0xFF)<<24; break; case bgraphics_pixel_format_y08_cb8_y18_cr8: BPXL_ConvertPixel_RGBtoYCbCr(BPXL_eA8_Y8_Cb8_Cr8, BPXL_eA8_R8_G8_B8, pixel, &aycbcr_pixel); pixel = aycbcr_pixel; break; default: break; } /* turn off features possibly turned on by copy */ rc = BGRC_Source_ToggleColorKey(grc, false); if (rc != BERR_SUCCESS) { BDBG_ERR(("BGRC_Source_ToggleColorKey failed: %d", rc)); goto fill_err; } rc = BGRC_Source_ToggleFilter(grc, false, false); if (rc != BERR_SUCCESS) { BDBG_ERR(("BGRC_Source_ToggleFilter failed: %d", rc)); goto fill_err; } rc = BGRC_Source_ToggleColorMatrix(grc, false); if (rc != BERR_SUCCESS) { BDBG_ERR(("BGRC_Source_ToggleColorMatrix failed: %d", rc)); goto fill_err; } /* set the output */ rc = BGRC_Output_SetSurface(grc, surface->hSurface); if (rc != BERR_SUCCESS) { BDBG_ERR(("BGRC_Output_SetSurface failed: %d", rc)); goto fill_err; } if ((rect->x + rect->width) > surface->width) rect->width = surface->width-rect->x; if ((rect->y + rect->height) > surface->height) rect->height = surface->height-rect->y; rc = BGRC_Output_SetRectangle(grc, rect->x, rect->y, rect->width, rect->height); if (rc != BERR_SUCCESS) { BDBG_ERR(("BGRC_Output_SetRectangle failed: %d (%d %d %d %d)", rc, rect->x, rect->y, rect->width, rect->height)); goto fill_err; } rc = BGRC_Source_SetSurface(grc, NULL); if (rc != BERR_SUCCESS) { BDBG_ERR(("BGRC_Source_SetSurface failed: %d", rc)); goto fill_err; } rc = BGRC_Source_SetColor(grc, pixel); if (rc != BERR_SUCCESS) { BDBG_ERR(("BGRC_Source_SetColor failed: %d", rc)); goto fill_err; } #if 0 rc = BGRC_Output_SetColorKeySelection(grc, BGRC_Output_ColorKeySelection_eTakeSource, BGRC_Output_ColorKeySelection_eTakeSource, BGRC_Output_ColorKeySelection_eTakeDestination, BGRC_Output_ColorKeySelection_eTakeDestination); if (rc != BERR_SUCCESS) { BDBG_ERR(("BGRC_Output_SetColorKeySelection failed: %d", rc)); return rc; } #endif bgraphics_cacheflush(surface); rc = BGRC_IssueState(grc, bgraphics_p_set_event, s_graphics.event); bos_release_mutex(&s_graphics.mutex); if (rc == BERR_TIMEOUT) { rc = berr_timeout; } else if (rc != BERR_SUCCESS) BDBG_ERR(("BKNI_WaitForEvent failed %d (%d)", rc, __LINE__)); BKNI_WaitForEvent(s_graphics.event, 500000); return rc; fill_err: bos_release_mutex(&s_graphics.mutex); return (rc == BERR_SUCCESS) ? b_ok : berr_invalid_parameter; } /* Description: * destroy surface */ static void bgraphics_p_surface_destroy(bgraphics_t graphics, bsettop_surf_t surface) { BERR_Code rc; if (surface->hSurface) { rc = BSUR_Surface_Destroy(surface->hSurface); if (rc != BERR_SUCCESS) { BDBG_ERR(("BSUR_Surface_Destroy failed %d", rc)); } } surface->hSurface = NULL; if (surface->hPalette) { rc = BSUR_Palette_Destroy(surface->hPalette); if (rc != BERR_SUCCESS) { BDBG_ERR(("BSUR_Palette_Destroy failed %d", rc)); } surface->hPalette = NULL; } BKNI_Free(surface); } /* Description: * create surface */ static BERR_Code bgraphics_p_surface_create(bgraphics_t graphics, const bsurface_create_settings *psettings, bsettop_surf_t *surface) { BERR_Code rc; bdisplay_t display; void *uncached; BDBG_ASSERT(graphics); BDBG_ASSERT(graphics->display); display = graphics->display; *surface = BKNI_Malloc(sizeof(struct bsettop_surf)); if (*surface == NULL) { BDBG_ERR(("bgraphics_p_surface_create failed allocating surface structure")); goto error; } /* TODO: check pxl_format or palette_format */ if (BPXL_IS_PALETTE_FORMAT(psettings->pxl_format)) { rc = BSUR_Palette_Create(GetHEAP(), BPXL_NUM_PALETTE_ENTRIES(psettings->pxl_format), NULL, psettings->pxl_format, BSUR_CONSTRAINT_ADDRESS_PIXEL_ALIGNED, &(*surface)->hPalette); if (rc != BERR_SUCCESS) { BDBG_ERR(("BSUR_Palette_Create failed %d", rc)); goto error; } rc = BSUR_Palette_GetAddress((*surface)->hPalette, (void **)&uncached); if (rc != BERR_SUCCESS) { BDBG_ERR(("BSUR_Palette_GetAddress failed %d", rc)); goto error; } rc = BMEM_Heap_ConvertAddressToCached(GetHEAP(), uncached, (void **)&((*surface)->p_palette)); if (rc != BERR_SUCCESS) { BDBG_ERR(("BMEM_Heap_ConvertAddressToCached failed %d", rc)); goto error; } } else { (*surface)->hPalette = NULL; } rc = BSUR_Surface_Create(GetHEAP(), psettings->width, psettings->height, 0, NULL, psettings->pxl_format, (*surface)->hPalette, BSUR_CONSTRAINT_ADDRESS_PIXEL_ALIGNED, NULL, &(*surface)->hSurface); if (rc != BERR_SUCCESS) { BDBG_ERR(("BSUR_Surface_Create failed %d", rc)); goto error; } (*surface)->pixel_format = psettings->pxl_format; (*surface)->width = psettings->width; (*surface)->height = psettings->height; rc = BSUR_Surface_GetAddress((*surface)->hSurface, (void **)&uncached, &(*surface)->pitch); if (rc != BERR_SUCCESS) { BDBG_ERR(("BSUR_Surface_GetAddress failed %d", rc)); goto error; } rc = BMEM_Heap_ConvertAddressToCached(GetHEAP(), uncached, (void **)&((*surface)->p_pixels)); if (rc != BERR_SUCCESS) { BDBG_ERR(("BMEM_Heap_ConvertAddressToCached failed %d", rc)); goto error; } /* clear the buffer */ BKNI_Memset((*surface)->p_pixels, 0, (*surface)->pitch * psettings->height); error: return rc; } /* * Description: * create BSUR_Surface. RGB888 or YCbCr888 only */ bresult bsurface_create_surface(uint32_t width, uint32_t height, bgraphics_pixel_format format, uint8_t **mem, uint32_t *pitch, bsettop_surf_t *p_settop_surf) { bsurface_create_settings settings; BERR_Code rc = BERR_SUCCESS; BDBG_ASSERT(p_settop_surf); switch (format) { case bgraphics_pixel_format_a8_r8_g8_b8: settings.pxl_format = BPXL_eA8_R8_G8_B8; break; case bgraphics_pixel_format_y08_cb8_y18_cr8: settings.pxl_format = BPXL_eA8_Y8_Cb8_Cr8; break; default: BDBG_WRN(("unsupported..")); settings.pxl_format = BPXL_eA8_R8_G8_B8; break; } settings.width = width; settings.height = height; rc = bgraphics_p_surface_create(&s_graphics, &settings, p_settop_surf); if (rc == BERR_SUCCESS) { *mem = (*p_settop_surf)->p_pixels; *pitch = (*p_settop_surf)->pitch; BDBG_MSG(("%s: (%dx%d) 0x%x", __FUNCTION__, width, height, (*p_settop_surf)->p_pixels)); } return (rc == BERR_SUCCESS) ? b_ok : berr_invalid_parameter; } /* * Description: * destroy BSUR_Surface. */ void bsurface_destroy_surface(bsettop_surf_t surf) { BDBG_MSG(("%s: 0x%x", surf->p_pixels)); bgraphics_p_surface_destroy(&s_graphics, surf); } /* * Description: * flush cache before HW uses cached address. * Heap's callback function is flush_dcache */ static void bgraphics_cacheflush(bsettop_surf_t surf) { BMEM_Heap_FlushCache(GetHEAP(), surf->p_pixels, surf->pitch*surf->height); } #endif