/*---------------------------------------------------------------------------* Project: TwlSDK - dsp File: dsp_graphics.c Copyright 2008-2009 Nintendo. All rights reserved. These coded instructions, statements, and computer programs contain proprietary information of Nintendo of America Inc. and/or Nintendo Company Ltd., and are protected by Federal copyright law. They may not be disclosed to third parties or copied or duplicated in any form, in whole or in part, without the prior written consent of Nintendo. $Date:: 2009-06-04#$ $Rev: 10698 $ $Author: okubata_ryoma $ *---------------------------------------------------------------------------*/ #include #include #include #include "dsp_process.h" extern const u8 DSPiFirmware_graphics[]; /*---------------------------------------------------------------------------*/ /* Variables */ static DSPPipe binOut[1]; static BOOL DSPiGraphicsAvailable = FALSE; static DSPProcessContext DSPiProcessGraphics[1]; static u16 replyReg; /* Determine whether limitation conditions have been met (FALSE if so) */ static BOOL CheckLimitation(f32 rx, f32 ry, DSPGraphicsScalingMode mode, u16 src_width); /*---------------------------------------------------------------------------*/ /* Functions */ /*---------------------------------------------------------------------------* Name: CheckLimitation Description: Determines if limitation conditions set by the DSP_Scaling* functions' specifications have been met. Arguments: mode: Scaling mode rx, ry: Horizontal and vertical scaling factors src_width: Width of the input image Returns: FALSE if limitation conditions have been met *---------------------------------------------------------------------------*/ static BOOL CheckLimitation(f32 rx, f32 ry, DSPGraphicsScalingMode mode, u16 src_width) { // When the processed data size is at least as large as the original data size if (rx * ry >= 1.0f) { switch(mode) { case DSP_GRAPHICS_SCALING_MODE_N_NEIGHBOR: case DSP_GRAPHICS_SCALING_MODE_BILINEAR: if (DSP_CALC_SCALING_SIZE(src_width, rx) * ry >= 8192) { return FALSE; } break; case DSP_GRAPHICS_SCALING_MODE_BICUBIC: if (DSP_CALC_SCALING_SIZE(src_width, rx) * ry >= 4096) { return FALSE; } break; } } else // When the processed data size is less than the original data size { switch(mode) { case DSP_GRAPHICS_SCALING_MODE_N_NEIGHBOR: case DSP_GRAPHICS_SCALING_MODE_BILINEAR: if (src_width >= 8192) { return FALSE; } break; case DSP_GRAPHICS_SCALING_MODE_BICUBIC: if (src_width >= 4096) { return FALSE; } break; } } return TRUE; } /*---------------------------------------------------------------------------* Name: DSPi_OpenStaticComponentGraphicsCore Description: Opens the memory file(s) for the graphics component. It is no longer necessary to prepare a file system in advance, but because it is linked as static memory, the program size increases. Arguments: file: FSFile structure that opens the memory file Returns: None. *---------------------------------------------------------------------------*/ void DSPi_OpenStaticComponentGraphicsCore(FSFile *file) { extern const u8 DSPiFirmware_graphics[]; (void)DSPi_CreateMemoryFile(file, DSPiFirmware_graphics); } /*---------------------------------------------------------------------------* Name: DSPi_GraphicsEvents(void *userdata) Description: Event handler of the DSP graphics component. Arguments: None. Returns: None. *---------------------------------------------------------------------------*/ static void DSPi_GraphicsEvents(void *userdata) { (void)userdata; // When running asynchronous processing, check for the presence of completion notices if ( isAsync ) { replyReg = DSP_RecvData(DSP_GRAPHICS_REP_REGISTER); if (replyReg == DSP_STATE_SUCCESS) { isBusy = FALSE; isAsync = FALSE; if ( callBackFunc != NULL) { callBackFunc(); } } else if (replyReg == DSP_STATE_FAIL) { OS_Warning("a process on DSP is failed.\n"); isBusy = FALSE; isAsync = FALSE; } else { OS_Warning("unknown error occured.\n"); isBusy = FALSE; isAsync = FALSE; } } else // Synchronous version { // replyReg = DSP_RecvData(DSP_GRAPHICS_REP_REGISTER); // isBusy = FALSE; } } /*---------------------------------------------------------------------------* Name: DSP_LoadGraphicsCore Description: Loads graphics component to DSP. Arguments: file: Graphics component file slotB: WRAM-B allowed for use for code memory slotC: WRAM-C allowed for use for data memory Returns: TRUE if the graphics component is correctly loaded to DSP. *---------------------------------------------------------------------------*/ BOOL DSPi_LoadGraphicsCore(FSFile *file, int slotB, int slotC) { if (!DSPiGraphicsAvailable) { isBusy = FALSE; isAsync = FALSE; DSP_InitProcessContext(DSPiProcessGraphics, "graphics"); // (If there is specification to a linker script file on the DSP side, this explicit setting is unnecessary) DSPiProcessGraphics->flags |= DSP_PROCESS_FLAG_USING_OS; DSP_SetProcessHook(DSPiProcessGraphics, DSP_HOOK_REPLY_(DSP_GRAPHICS_REP_REGISTER), DSPi_GraphicsEvents, NULL); if (DSP_ExecuteProcess(DSPiProcessGraphics, file, slotB, slotC)) { DSPiGraphicsAvailable = TRUE; } (void)DSP_LoadPipe(binOut, DSP_PIPE_BINARY, DSP_PIPE_OUTPUT); } return DSPiGraphicsAvailable; } /*---------------------------------------------------------------------------* Name: DSP_UnloadGraphicsCore Description: Ends the DSP graphics component. Arguments: None. Returns: None. *---------------------------------------------------------------------------*/ void DSPi_UnloadGraphicsCore(void) { if(DSPiGraphicsAvailable) { DSP_QuitProcess(DSPiProcessGraphics); DSPiGraphicsAvailable = FALSE; } } /*---------------------------------------------------------------------------* Name: DSPi_YuvToRgbConvertCore Description: Converts YUV to RGB. Arguments: src: Address of (source) data to process dest: Address for storing data (destination) after processing size: Size of src data callback: Pointer for callback function run after conversion ends async: TRUE when running asynchronously Returns: TRUE if successful. *---------------------------------------------------------------------------*/ BOOL DSPi_ConvertYuvToRgbCore(const void* src, void* dst, u32 size, DSP_GraphicsCallback callback, BOOL async) { DSPYuv2RgbParam yr_param; u32 offset = 0; u16 command; // Check one more time whether DSP is busy if (isBusy) { OS_TPrintf("dsp is busy.\n"); return FALSE; } isBusy = TRUE; // Register the callback function callBackFunc = callback; isAsync = async; if (async) { DSP_SetProcessHook(DSPiProcessGraphics, DSP_HOOK_REPLY_(DSP_GRAPHICS_REP_REGISTER), DSPi_GraphicsEvents, NULL); } else { DSP_SetProcessHook(DSPiProcessGraphics, DSP_HOOK_REPLY_(DSP_GRAPHICS_REP_REGISTER), NULL, NULL); } // Notify the DSP of the content of processes to start command = DSP_G_FUNCID_YUV2RGB; DSP_SendData(DSP_GRAPHICS_COM_REGISTER, command); // Send parameters to DSP yr_param.size = size; yr_param.src = (u32)((u32)src + offset); yr_param.dst = (u32)((u32)dst + offset); DSP_WritePipe(binOut, &yr_param, sizeof(DSPYuv2RgbParam)); if (async) { return TRUE; } else { // Wait for a reply from the DSP while (!DSP_RecvDataIsReady(DSP_GRAPHICS_REP_REGISTER)) { OS_Sleep(1); } replyReg = DSP_RecvData(DSP_GRAPHICS_REP_REGISTER); isBusy = FALSE; if ( replyReg == DSP_STATE_SUCCESS) { return TRUE; } else { return FALSE; } } return FALSE; } /*---------------------------------------------------------------------------* Name: DSPi_ScalingCore Description: Scales the image data. Returns: TRUE if successful. *---------------------------------------------------------------------------*/ BOOL DSPi_ScalingCore(const void* src, void* dst, u16 img_width, u16 img_height, f32 rx, f32 ry, DSPGraphicsScalingMode mode, u16 x, u16 y, u16 width, u16 height, DSP_GraphicsCallback callback, BOOL async) { DSPScalingParam sc_param; u16 command; // Check limitation conditions SDK_ASSERTMSG(CheckLimitation(rx, ry, mode, width), "DSP_Scaling: arguments exceed the limit."); // Check one more time whether DSP is busy if (isBusy) { OS_TPrintf("dsp is busy.\n"); return FALSE; } isBusy = TRUE; // Register the callback function callBackFunc = callback; isAsync = async; if (async) { DSP_SetProcessHook(DSPiProcessGraphics, DSP_HOOK_REPLY_(DSP_GRAPHICS_REP_REGISTER), DSPi_GraphicsEvents, NULL); } else { DSP_SetProcessHook(DSPiProcessGraphics, DSP_HOOK_REPLY_(DSP_GRAPHICS_REP_REGISTER), NULL, NULL); } // Notify the DSP of the content of processes to start command = DSP_G_FUNCID_SCALING; DSP_SendData(DSP_GRAPHICS_COM_REGISTER, command); // Transfer parameters to DSP sc_param.src = (u32)src; sc_param.dst = (u32)dst; sc_param.mode = mode; sc_param.img_width = img_width; sc_param.img_height = img_height; sc_param.rate_w = (u16)(rx * 1000); sc_param.rate_h = (u16)(ry * 1000); sc_param.block_x = x; sc_param.block_y = y; sc_param.width = width; sc_param.height = height; DSP_WritePipe(binOut, &sc_param, sizeof(DSPScalingParam)); // Branch if processing asynchronously if(isAsync) { return TRUE; } else { // Wait for a reply from the DSP while (!DSP_RecvDataIsReady(DSP_GRAPHICS_REP_REGISTER)) { OS_Sleep(1); } replyReg = DSP_RecvData(DSP_GRAPHICS_REP_REGISTER); isBusy = FALSE; if ( replyReg == DSP_STATE_SUCCESS ) { return TRUE; } else { return FALSE; } } return FALSE; } BOOL DSPi_ScalingFxCore(const void* src, void* dst, u16 img_width, u16 img_height, fx32 rx, fx32 ry, DSPGraphicsScalingMode mode, u16 x, u16 y, u16 width, u16 height, DSP_GraphicsCallback callback, BOOL async) { DSPScalingParam sc_param; u16 command; // Check limitation conditions SDK_ASSERTMSG(CheckLimitation(FX_FX32_TO_F32(rx), FX_FX32_TO_F32(ry), mode, width), "DSP_Scaling: arguments exceed the limit."); // Check one more time whether DSP is busy if (isBusy) { OS_TPrintf("dsp is busy.\n"); return FALSE; } isBusy = TRUE; // Register the callback function callBackFunc = callback; isAsync = async; if (async) { DSP_SetProcessHook(DSPiProcessGraphics, DSP_HOOK_REPLY_(DSP_GRAPHICS_REP_REGISTER), DSPi_GraphicsEvents, NULL); } else { DSP_SetProcessHook(DSPiProcessGraphics, DSP_HOOK_REPLY_(DSP_GRAPHICS_REP_REGISTER), NULL, NULL); } // Notify the DSP of the content of processes to start command = DSP_G_FUNCID_SCALING; DSP_SendData(DSP_GRAPHICS_COM_REGISTER, command); // Transfer parameters to DSP sc_param.src = (u32)src; sc_param.dst = (u32)dst; sc_param.mode = mode; sc_param.img_width = img_width; sc_param.img_height = img_height; sc_param.rate_w = (u16)(rx / 4096.0f * 1000); sc_param.rate_h = (u16)(ry / 4096.0f * 1000); sc_param.block_x = x; sc_param.block_y = y; sc_param.width = width; sc_param.height = height; DSP_WritePipe(binOut, &sc_param, sizeof(DSPScalingParam)); // Branch if processing asynchronously if(isAsync) { return TRUE; } else { // Wait for a reply from the DSP while (!DSP_RecvDataIsReady(DSP_GRAPHICS_REP_REGISTER)) { OS_Sleep(1); } replyReg = DSP_RecvData(DSP_GRAPHICS_REP_REGISTER); isBusy = FALSE; if ( replyReg == DSP_STATE_SUCCESS ) { return TRUE; } else { return FALSE; } } return FALSE; }