1 /*---------------------------------------------------------------------------*
2   Project:  TwlSDK - DSP - demos - scaling-2
3   File:     main.c
4 
5   Copyright 2008-2009 Nintendo. All rights reserved.
6 
7   These coded instructions, statements, and computer programs contain
8   proprietary information of Nintendo of America Inc. and/or Nintendo
9   Company Ltd., and are protected by Federal copyright law. They may
10   not be disclosed to third parties or copied or duplicated in any form,
11   in whole or in part, without the prior written consent of Nintendo.
12 
13   $Date:: 2010-05-17#$
14   $Rev: 11335 $
15   $Author: kitase_hirotake $
16 *---------------------------------------------------------------------------*/
17 
18 /*---------------------------------------------------------------------------
19  This demo enlarges (or shrinks) 640x480 image data to fit a specified size area.
20 
21  Three interpolation methods are available to choose from when scaling.
22 
23  - How to Use
24      -- A : Change the interpolation mode
25            Cycles in order through Nearest Neighbor, Bilinear, Bicubic, Nearest Neighbor, ....
26 
27      -- UP, DOWN, RIGHT, LEFT : Moves the area.
28            Moves the area where the scaling will be performed.
29            Movement cannot exceed the boundaries of the 640x480 image.
30 
31      -- START : Ends the demo.
32 
33  - Other Notes
34      -- To change the post-scaling size, modify OUTPUT_WIDTH and OUTPUT_HEIGHT and rebuild the demo.
35 
36 
37      -- To change the DSP processing area size, change AREA_WIDTH and AREA_HEIGHT and rebuild the demo.
38 
39 
40  ----------------------------------------------------------------------------*/
41 
42 #include <twl.h>
43 #include <twl/dsp.h>
44 
45 #include <DEMO.h>
46 #include <twl/dsp/common/graphics.h>
47 
48 /* Settings */
49 #define RUN_ASYNC     1            // Whether to scale asynchronously
50 #define USE_FX32      1            // This is 1 when using the fx32 version of DSP_Scaling
51 
52 #define DMA_NO_FOR_FS 1            // For FS_Init
53 
54 #define AREA_WIDTH   185            // Width of the area to scale
55 #define AREA_HEIGHT  140            // Height of the area to scale
56 
57 #define OUTPUT_WIDTH  HW_LCD_WIDTH  // Resolution after processing
58 #define OUTPUT_HEIGHT HW_LCD_HEIGHT
59 
60 /*---------------------------------------------------------------------------*
61  Image data (640x480)
62  *---------------------------------------------------------------------------*/
63 extern const u8 _binary_output_dat[];
64 extern const u8 _binary_output_dat_end[];
65 
66 #define DATA_WIDTH    640
67 #define DATA_HEIGHT   480
68 
69 /*---------------------------------------------------------------------------*
70  Prototype Declarations
71 *---------------------------------------------------------------------------*/
72 void VBlankIntr(void);
73 
74 static void ExecScaling(void);
75 static void InitializeGraphics(void);
76 static void WriteScreenBuffer(u16 *data, u32 width, u32 height, u16 *scr);
77 static void ScalingCallbackFunc(void);
78 
79 /*---------------------------------------------------------------------------*
80  Internal Variable Definitions
81 *---------------------------------------------------------------------------*/
82 // Screen buffers for main and sub-screens
83 static u16 ScrBuf[HW_LCD_WIDTH * HW_LCD_HEIGHT] ATTRIBUTE_ALIGN(32);
84 // Buffer storing results after transformation by the DSP
85 static u16 TmpBuf[OUTPUT_WIDTH * OUTPUT_HEIGHT] ATTRIBUTE_ALIGN(32);
86 
87 static OSTick StartTick;       // Variable for measuring DSP processing time
88 static BOOL IsDspProcessing;   // Whether DSP is currently processing something (used when running this as an asynchronous process)
89 
90 static u16 AreaX = 0;          // Upper-left x-coordinate of area to scale
91 static u16 AreaY = 0;          // Upper-left y-coordinate of area to scale
92 
93 // Interpolation mode
94 static u16 ModeNames[3] = {
95     DSP_GRAPHICS_SCALING_MODE_N_NEIGHBOR,
96     DSP_GRAPHICS_SCALING_MODE_BILINEAR,
97     DSP_GRAPHICS_SCALING_MODE_BICUBIC
98     };
99 
100 static u8 ModeNameStrings[3][24] = {
101         "Nearest Neighbor",
102         "Bilinear",
103         "Bicubic"
104         };
105 
106 static u32 DspMode = 0;
107 
108 /*---------------------------------------------------------------------------*
109  Name:         TwlMain
110 
111  Description:  Initialization and main loop.
112 
113  Arguments:    None.
114 
115  Returns:      None.
116 *---------------------------------------------------------------------------*/
TwlMain(void)117 void TwlMain(void)
118 {
119     FSFile file;
120 
121     DEMOInitCommon();
122     OS_InitThread();
123     OS_InitTick();
124     OS_InitAlarm();             // This is required when using synchronous versions of DSP_Scaling* functions (because the OS_Sleep function is used internally)
125 
126     // When in NITRO mode, stopped by Panic
127     DEMOCheckRunOnTWL();
128 
129     DEMOInitVRAM();
130     InitializeGraphics();
131 
132     DEMOStartDisplay();
133 
134     // Because at first there is a possibility that WRAM might have been allocated to something as per the ROM header, clear it
135     (void)MI_FreeWram_B( MI_WRAM_ARM9 );
136     (void)MI_CancelWram_B( MI_WRAM_ARM9 );
137     (void)MI_FreeWram_C( MI_WRAM_ARM9 );
138     (void)MI_CancelWram_C( MI_WRAM_ARM9 );
139     (void)MI_FreeWram_B( MI_WRAM_ARM7 );
140     (void)MI_CancelWram_B( MI_WRAM_ARM7 );
141     (void)MI_FreeWram_C( MI_WRAM_ARM7 );
142     (void)MI_CancelWram_C( MI_WRAM_ARM7 );
143 
144     FS_Init(DMA_NO_FOR_FS);
145 
146     (void)OS_EnableInterrupts();
147 
148     IsDspProcessing = FALSE;
149 
150     // Clear the screen buffer
151     MI_CpuClear8(ScrBuf, sizeof(ScrBuf));
152 
153     // Load graphics component
154     DSP_OpenStaticComponentGraphics(&file);
155     if(!DSP_LoadGraphics(&file, 0xFF, 0xFF))
156     {
157         OS_TPanic("failed to load graphics DSP-component! (lack of WRAM-B/C)");
158     }
159 
160     // Initial execution
161     ExecScaling();
162 
163     while (1)
164     {
165         DEMOReadKey();
166 
167         if (DEMO_IS_TRIG( PAD_BUTTON_START ))
168         {
169             break;    // Quit
170         }
171 
172         // Move area targeted for processing
173         if (DEMO_IS_PRESS( PAD_KEY_RIGHT ))
174         {
175             AreaX += 5;
176 
177             if (AreaX >= DATA_WIDTH - AREA_WIDTH - 1)
178             {
179                 AreaX = DATA_WIDTH - AREA_WIDTH - 1;
180             }
181             ExecScaling();
182         }
183         else if (DEMO_IS_PRESS( PAD_KEY_LEFT ))
184         {
185             if (AreaX != 0)
186             {
187                 if (AreaX <= 5)
188                 {
189                     AreaX = 0;
190                 }
191                 else
192                 {
193                     AreaX -= 5;
194                 }
195 
196                 ExecScaling();
197             }
198         }
199 
200         if (DEMO_IS_PRESS( PAD_KEY_UP ))
201         {
202             if (AreaY != 0)
203             {
204                 if (AreaY <= 5)
205                 {
206                     AreaY = 0;
207                 }
208                 else
209                 {
210                     AreaY -= 5;
211                 }
212 
213                 ExecScaling();
214             }
215         }
216         else if (DEMO_IS_PRESS( PAD_KEY_DOWN ))
217         {
218             AreaY += 5;
219             if (AreaY >= DATA_HEIGHT - AREA_HEIGHT - 1)
220             {
221                 AreaY = DATA_HEIGHT - AREA_HEIGHT - 1;
222             }
223             ExecScaling();
224         }
225 
226         // Change the interpolation mode
227         if (DEMO_IS_TRIG( PAD_BUTTON_A ))
228         {
229             DspMode++;
230             if (DspMode >= 3)
231             {
232                 DspMode = 0;
233             }
234 
235             ExecScaling();
236         }
237 
238         OS_WaitVBlankIntr();           // Waiting for the end of the V-Blank interrupt
239     }
240 
241     OS_TPrintf("demo end.\n");
242 
243     // Unload graphics component
244     DSP_UnloadGraphics();
245     OS_Terminate();
246 }
247 
248 //--------------------------------------------------------------------------------
249 //    V-Blank interrupt process
250 //
VBlankIntr(void)251 void VBlankIntr(void)
252 {
253     OS_SetIrqCheckFlag(OS_IE_V_BLANK); // Checking V-Blank interrupt
254 }
255 
256 /*--------------------------------------------------------------------------------
257     Scale the image data using the DSP and the configured options
258  ---------------------------------------------------------------------------------*/
ExecScaling()259 static void ExecScaling()
260 {
261     // Get the scale ratio for input to the DSP_Scaling function from the desired output size
262 #if USE_FX32
263     fx32 factx, facty;
264     factx = DSP_CalcScalingFactorFx32(AREA_WIDTH, OUTPUT_WIDTH);
265     facty = DSP_CalcScalingFactorFx32(AREA_HEIGHT, OUTPUT_HEIGHT);
266 #else
267     f32  factx, facty;
268     factx = DSP_CalcScalingFactorF32(AREA_WIDTH, OUTPUT_WIDTH);
269     facty = DSP_CalcScalingFactorF32(AREA_HEIGHT, OUTPUT_HEIGHT);
270 #endif
271 
272     // Execute
273 #if RUN_ASYNC
274 
275     if ( !IsDspProcessing )
276     {
277         StartTick = OS_GetTick();
278 #if USE_FX32
279         (void)DSP_ScalingFxAsyncEx(_binary_output_dat, TmpBuf, DATA_WIDTH, DATA_HEIGHT,
280                            factx, facty, ModeNames[DspMode], AreaX, AreaY, AREA_WIDTH, AREA_HEIGHT, ScalingCallbackFunc);
281 #else
282         (void)DSP_ScalingAsyncEx(_binary_output_dat, TmpBuf, DATA_WIDTH, DATA_HEIGHT,
283                            factx, facty, ModeNames[DspMode], AreaX, AreaY, AREA_WIDTH, AREA_HEIGHT, ScalingCallbackFunc);
284 #endif	// USE_FX32
285 
286         IsDspProcessing = TRUE;
287     }
288 
289 #else   // RUN_ASYNC == 0
290     StartTick = OS_GetTick();
291 
292 #if USE_FX32
293     DSP_ScalingFxEx(_binary_output_dat, TmpBuf, DATA_WIDTH, DATA_HEIGHT,
294                   factx, facty, ModeNames[DspMode], AreaX, AreaY, AREA_WIDTH, AREA_HEIGHT);
295 #else
296     (void)DSP_ScalingEx(_binary_output_dat, TmpBuf, DATA_WIDTH, DATA_HEIGHT,
297                   factx, facty, ModeNames[DspMode], AreaX, AreaY, AREA_WIDTH, AREA_HEIGHT);
298 #endif  // USE_FX32
299 
300     OS_TPrintf("mode: %s, time: %d microsec.\n", ModeNameStrings[DspMode], OS_TicksToMicroSeconds(OS_GetTick() - StartTick));
301 
302     // Adjust data for display on screen
303     WriteScreenBuffer(TmpBuf, OUTPUT_WIDTH, OUTPUT_HEIGHT, ScrBuf);
304     // Destroy the screen buffer cache
305     DC_FlushAll();
306     // Load processing results to VRAM
307     GX_LoadBG3Bmp(ScrBuf, 0, HW_LCD_WIDTH * HW_LCD_HEIGHT * sizeof(u16));
308 #endif      // RUN_ASYNC
309 
310 }
311 
InitializeGraphics()312 static void InitializeGraphics()
313 {
314     // VRAM allocation
315     GX_SetBankForBG(GX_VRAM_BG_128_A);
316     GX_SetBankForSubBG(GX_VRAM_SUB_BG_128_C);
317 
318     GX_SetGraphicsMode(GX_DISPMODE_GRAPHICS, GX_BGMODE_5, GX_BG0_AS_2D);
319     GX_SetVisiblePlane( GX_PLANEMASK_BG3 );
320     GXS_SetGraphicsMode( GX_BGMODE_4 );
321     GXS_SetVisiblePlane( GX_PLANEMASK_BG3 );
322 
323     GX_SetBGScrOffset(GX_BGSCROFFSET_0x00000);  // Set screen offset value
324     GX_SetBGCharOffset(GX_BGCHAROFFSET_0x20000);  // Configure character base offset value
325 
326     G2_BlendNone();
327     G2S_BlendNone();
328     GX_Power2DSub(TRUE);    // Turn the sub 2D graphic engine off
329 
330     // Main-BG
331     // BG3: scr 96KB
332     {
333         G2_SetBG3ControlDCBmp(GX_BG_SCRSIZE_DCBMP_256x256, GX_BG_AREAOVER_XLU, GX_BG_BMPSCRBASE_0x00000);
334         G2_SetBG3Priority(2);
335         G2_BG3Mosaic(FALSE);
336     }
337 
338     // Sub-BG
339     // BG3: scr 96KB
340     {
341         G2S_SetBG3ControlDCBmp(GX_BG_SCRSIZE_DCBMP_256x256, GX_BG_AREAOVER_XLU, GX_BG_BMPSCRBASE_0x00000);
342         G2S_SetBG3Priority(2);
343         G2S_BG3Mosaic(FALSE);
344     }
345 }
346 
347 /* Write the contents of 'data' to a 256x192 screen buffer */
WriteScreenBuffer(u16 * data,u32 width,u32 height,u16 * scr)348 static void WriteScreenBuffer(u16 *data, u32 width, u32 height, u16 *scr)
349 {
350     int i;
351     u32 lp_count;
352     u32 tmp_linesize;
353 
354     // Create scrbuf
355     if( height > HW_LCD_HEIGHT )
356     {
357         lp_count = HW_LCD_HEIGHT;
358     }
359     else
360     {
361         lp_count = height;
362     }
363 
364     // Because it is displayed on the lower screen as a 256x256 BMP, you need to take size into account.
365     // Copy line by line
366     if( width > HW_LCD_WIDTH)
367     {
368         tmp_linesize = HW_LCD_WIDTH * sizeof(u16);
369     }
370     else
371     {
372         tmp_linesize = width * sizeof(u16);
373     }
374 
375     for ( i=0; i < lp_count; i++ )
376     {
377         MI_CpuCopy( data + width * i, scr + HW_LCD_WIDTH * i, tmp_linesize );
378     }
379 }
380 
381 /* Callback function called when scaling is done */
ScalingCallbackFunc(void)382 static void ScalingCallbackFunc(void)
383 {
384     OS_TPrintf("[Async]mode: %s, time: %d microsec.\n", ModeNameStrings[DspMode], OS_TicksToMicroSeconds(OS_GetTick() - StartTick));
385 
386         // Adjust data for display on screen
387     WriteScreenBuffer(TmpBuf, OUTPUT_WIDTH, OUTPUT_HEIGHT, ScrBuf);
388     // Destroy the screen buffer cache
389     DC_FlushAll();
390     // Load processing results to VRAM
391     GX_LoadBG3Bmp(ScrBuf, 0, HW_LCD_WIDTH * HW_LCD_HEIGHT * sizeof(u16));
392 
393     IsDspProcessing = FALSE;
394 }
395 
396