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:: 2009-09-24#$
14   $Rev: 11063 $
15   $Author: okubata_ryoma $
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 
140     FS_Init(DMA_NO_FOR_FS);
141 
142     (void)OS_EnableInterrupts();
143 
144     IsDspProcessing = FALSE;
145 
146     // Clear the screen buffer
147     MI_CpuClear8(ScrBuf, sizeof(ScrBuf));
148 
149     // Load graphics component
150     DSP_OpenStaticComponentGraphics(&file);
151     if(!DSP_LoadGraphics(&file, 0xFF, 0xFF))
152     {
153         OS_TPanic("failed to load graphics DSP-component! (lack of WRAM-B/C)");
154     }
155 
156     // Initial execution
157     ExecScaling();
158 
159     while (1)
160     {
161         DEMOReadKey();
162 
163         if (DEMO_IS_TRIG( PAD_BUTTON_START ))
164         {
165             break;    // Quit
166         }
167 
168         // Move area targeted for processing
169         if (DEMO_IS_PRESS( PAD_KEY_RIGHT ))
170         {
171             AreaX += 5;
172 
173             if (AreaX >= DATA_WIDTH - AREA_WIDTH - 1)
174             {
175                 AreaX = DATA_WIDTH - AREA_WIDTH - 1;
176             }
177             ExecScaling();
178         }
179         else if (DEMO_IS_PRESS( PAD_KEY_LEFT ))
180         {
181             if (AreaX != 0)
182             {
183                 if (AreaX <= 5)
184                 {
185                     AreaX = 0;
186                 }
187                 else
188                 {
189                     AreaX -= 5;
190                 }
191 
192                 ExecScaling();
193             }
194         }
195 
196         if (DEMO_IS_PRESS( PAD_KEY_UP ))
197         {
198             if (AreaY != 0)
199             {
200                 if (AreaY <= 5)
201                 {
202                     AreaY = 0;
203                 }
204                 else
205                 {
206                     AreaY -= 5;
207                 }
208 
209                 ExecScaling();
210             }
211         }
212         else if (DEMO_IS_PRESS( PAD_KEY_DOWN ))
213         {
214             AreaY += 5;
215             if (AreaY >= DATA_HEIGHT - AREA_HEIGHT - 1)
216             {
217                 AreaY = DATA_HEIGHT - AREA_HEIGHT - 1;
218             }
219             ExecScaling();
220         }
221 
222         // Change the interpolation mode
223         if (DEMO_IS_TRIG( PAD_BUTTON_A ))
224         {
225             DspMode++;
226             if (DspMode >= 3)
227             {
228                 DspMode = 0;
229             }
230 
231             ExecScaling();
232         }
233 
234         OS_WaitVBlankIntr();           // Waiting for the end of the V-Blank interrupt
235     }
236 
237     OS_TPrintf("demo end.\n");
238 
239     // Unload graphics component
240     DSP_UnloadGraphics();
241     OS_Terminate();
242 }
243 
244 //--------------------------------------------------------------------------------
245 //    V-Blank interrupt process
246 //
VBlankIntr(void)247 void VBlankIntr(void)
248 {
249     OS_SetIrqCheckFlag(OS_IE_V_BLANK); // Checking V-Blank interrupt
250 }
251 
252 /*--------------------------------------------------------------------------------
253     Scale the image data using the DSP and the configured options
254  ---------------------------------------------------------------------------------*/
ExecScaling()255 static void ExecScaling()
256 {
257     // Get the scale ratio for input to the DSP_Scaling function from the desired output size
258 #if USE_FX32
259     fx32 factx, facty;
260     factx = DSP_CalcScalingFactorFx32(AREA_WIDTH, OUTPUT_WIDTH);
261     facty = DSP_CalcScalingFactorFx32(AREA_HEIGHT, OUTPUT_HEIGHT);
262 #else
263     f32  factx, facty;
264     factx = DSP_CalcScalingFactorF32(AREA_WIDTH, OUTPUT_WIDTH);
265     facty = DSP_CalcScalingFactorF32(AREA_HEIGHT, OUTPUT_HEIGHT);
266 #endif
267 
268     // Execute
269 #if RUN_ASYNC
270 
271     if ( !IsDspProcessing )
272     {
273         StartTick = OS_GetTick();
274 #if USE_FX32
275         (void)DSP_ScalingFxAsyncEx(_binary_output_dat, TmpBuf, DATA_WIDTH, DATA_HEIGHT,
276                            factx, facty, ModeNames[DspMode], AreaX, AreaY, AREA_WIDTH, AREA_HEIGHT, ScalingCallbackFunc);
277 #else
278         (void)DSP_ScalingAsyncEx(_binary_output_dat, TmpBuf, DATA_WIDTH, DATA_HEIGHT,
279                            factx, facty, ModeNames[DspMode], AreaX, AreaY, AREA_WIDTH, AREA_HEIGHT, ScalingCallbackFunc);
280 #endif	// USE_FX32
281 
282         IsDspProcessing = TRUE;
283     }
284 
285 #else   // RUN_ASYNC == 0
286     StartTick = OS_GetTick();
287 
288 #if USE_FX32
289     DSP_ScalingFxEx(_binary_output_dat, TmpBuf, DATA_WIDTH, DATA_HEIGHT,
290                   factx, facty, ModeNames[DspMode], AreaX, AreaY, AREA_WIDTH, AREA_HEIGHT);
291 #else
292     (void)DSP_ScalingEx(_binary_output_dat, TmpBuf, DATA_WIDTH, DATA_HEIGHT,
293                   factx, facty, ModeNames[DspMode], AreaX, AreaY, AREA_WIDTH, AREA_HEIGHT);
294 #endif  // USE_FX32
295 
296     OS_TPrintf("mode: %s, time: %d microsec.\n", ModeNameStrings[DspMode], OS_TicksToMicroSeconds(OS_GetTick() - StartTick));
297 
298     // Adjust data for display on screen
299     WriteScreenBuffer(TmpBuf, OUTPUT_WIDTH, OUTPUT_HEIGHT, ScrBuf);
300     // Destroy the screen buffer cache
301     DC_FlushAll();
302     // Load processing results to VRAM
303     GX_LoadBG3Bmp(ScrBuf, 0, HW_LCD_WIDTH * HW_LCD_HEIGHT * sizeof(u16));
304 #endif      // RUN_ASYNC
305 
306 }
307 
InitializeGraphics()308 static void InitializeGraphics()
309 {
310     // VRAM allocation
311     GX_SetBankForBG(GX_VRAM_BG_128_A);
312     GX_SetBankForSubBG(GX_VRAM_SUB_BG_128_C);
313 
314     GX_SetGraphicsMode(GX_DISPMODE_GRAPHICS, GX_BGMODE_5, GX_BG0_AS_2D);
315     GX_SetVisiblePlane( GX_PLANEMASK_BG3 );
316     GXS_SetGraphicsMode( GX_BGMODE_4 );
317     GXS_SetVisiblePlane( GX_PLANEMASK_BG3 );
318 
319     GX_SetBGScrOffset(GX_BGSCROFFSET_0x00000);  // Set screen offset value
320     GX_SetBGCharOffset(GX_BGCHAROFFSET_0x20000);  // Configure character base offset value
321 
322     G2_BlendNone();
323     G2S_BlendNone();
324     GX_Power2DSub(TRUE);    // Turn the sub 2D graphic engine off
325 
326     // Main-BG
327     // BG3: scr 96KB
328     {
329         G2_SetBG3ControlDCBmp(GX_BG_SCRSIZE_DCBMP_256x256, GX_BG_AREAOVER_XLU, GX_BG_BMPSCRBASE_0x00000);
330         G2_SetBG3Priority(2);
331         G2_BG3Mosaic(FALSE);
332     }
333 
334     // Sub-BG
335     // BG3: scr 96KB
336     {
337         G2S_SetBG3ControlDCBmp(GX_BG_SCRSIZE_DCBMP_256x256, GX_BG_AREAOVER_XLU, GX_BG_BMPSCRBASE_0x00000);
338         G2S_SetBG3Priority(2);
339         G2S_BG3Mosaic(FALSE);
340     }
341 }
342 
343 /* Write the contents of 'data' to a 256x192 screen buffer */
WriteScreenBuffer(u16 * data,u32 width,u32 height,u16 * scr)344 static void WriteScreenBuffer(u16 *data, u32 width, u32 height, u16 *scr)
345 {
346     int i;
347     u32 lp_count;
348     u32 tmp_linesize;
349 
350     // Create scrbuf
351     if( height > HW_LCD_HEIGHT )
352     {
353         lp_count = HW_LCD_HEIGHT;
354     }
355     else
356     {
357         lp_count = height;
358     }
359 
360     // Because it is displayed on the lower screen as a 256x256 BMP, you need to take size into account.
361     // Copy line by line
362     if( width > HW_LCD_WIDTH)
363     {
364         tmp_linesize = HW_LCD_WIDTH * sizeof(u16);
365     }
366     else
367     {
368         tmp_linesize = width * sizeof(u16);
369     }
370 
371     for ( i=0; i < lp_count; i++ )
372     {
373         MI_CpuCopy( data + width * i, scr + HW_LCD_WIDTH * i, tmp_linesize );
374     }
375 }
376 
377 /* Callback function called when scaling is done */
ScalingCallbackFunc(void)378 static void ScalingCallbackFunc(void)
379 {
380     OS_TPrintf("[Async]mode: %s, time: %d microsec.\n", ModeNameStrings[DspMode], OS_TicksToMicroSeconds(OS_GetTick() - StartTick));
381 
382         // Adjust data for display on screen
383     WriteScreenBuffer(TmpBuf, OUTPUT_WIDTH, OUTPUT_HEIGHT, ScrBuf);
384     // Destroy the screen buffer cache
385     DC_FlushAll();
386     // Load processing results to VRAM
387     GX_LoadBG3Bmp(ScrBuf, 0, HW_LCD_WIDTH * HW_LCD_HEIGHT * sizeof(u16));
388 
389     IsDspProcessing = FALSE;
390 }
391 
392