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