1 /*---------------------------------------------------------------------------*
2 
3   Copyright (C) Nintendo.  All rights reserved.
4 
5   These coded instructions, statements, and computer programs contain
6   proprietary information of Nintendo of America Inc. and/or Nintendo
7   Company Ltd., and are protected by Federal copyright law.  They may
8   not be disclosed to third parties or copied or duplicated in any form,
9   in whole or in part, without the prior written consent of Nintendo.
10 
11  *---------------------------------------------------------------------------*/
12 ////===========================================================================
13 ///  DEMODRC.c
14 ///
15 ///     This is DRC system code for the DEMO library.
16 ///
17 ////===========================================================================
18 
19 #include <cafe/demo.h>
20 #include <cafe/gx2.h>
21 #include <cafe/procui.h>
22 #include <cafe/camera/camera.h>
23 
24 // A bit like asserts, but even for NDEBUG=TRUE:
25 #define DEMOCheck(x,y) if (!(x)) { OSReport("%s\n", y); while(1) OSSleepSeconds(1); }
26 
27 #define _DEMO_NUM_DRC 2
28 
29 GX2ColorBuffer   DEMODRCColorBuffer;
30 GX2DepthBuffer   DEMODRCDepthBuffer;
31 void            *DEMODRCScanBufferPtr;
32 
33 // DEMO Gfx Context State
34 GX2ContextState *DEMODRCContextState;
35 
36 static BOOL gDemoDRCRunningFlag = FALSE;
37 static BOOL gDemoDRCOutputEnabled = FALSE;
38 
39 extern BOOL gDemoGfxInForeground;
40 
41 // State set at init time that needs to be used to reacquire foreground.
42 static GX2DRCMode       gDemoDRCRenderMode;
43 static GX2SurfaceFormat gDemoDRCScanOutCBFormat;
44 static u32 gDemoDRCScanSize;
45 
46 // Other preserved items
47 static u32 gDemoDRCRenderWidth;
48 static u32 gDemoDRCRenderHeight;
49 
50 // Instance
51 static DEMODRCInstance* gDemoDRCCurInstance = NULL;
52 
DEMODRCCallbackAcquiredForeground(void * unused)53 static u32 DEMODRCCallbackAcquiredForeground(void* unused)
54 {
55     DEMODRCAcquiredForeground();
56 
57     // No issues
58     return 0;
59 }
60 
DEMODRCCallbackReleaseForeground(void * unused)61 static u32 DEMODRCCallbackReleaseForeground(void* unused)
62 {
63     DEMODRCReleaseForeground();
64 
65     // No issues
66     return 0;
67 }
68 
DEMODRCInit(int argc,char * argv[])69 DEMODRCInstance* DEMODRCInit(int argc, char *argv[])
70 {
71     void *ptr;
72 
73     u32 scanSize;
74     GX2Boolean scaleNeeded;
75 
76     u32 i;
77     char *p;
78     u32 renderWidth =  854;
79     u32 renderHeight = 480;
80     // Default to SRGB for gamma
81     GX2SurfaceFormat renderCBFormat  = GX2_SURFACE_FORMAT_TCS_R8_G8_B8_A8_SRGB;
82     GX2SurfaceFormat scanOutCBFormat = GX2_SURFACE_FORMAT_TCS_R8_G8_B8_A8_SRGB;
83     GX2SurfaceFormat renderDBFormat  = GX2_SURFACE_FORMAT_TCD_R32_FLOAT;
84     GX2AAMode renderAAMode = GX2_AA_MODE_1X;
85     GX2DRCMode renderMode = GX2_DRC_SINGLE;
86 
87 #define SKIP_NON_DIGIT(c) ((c)!=0&&((c)<'0'||(c)>'9'))
88 
89     // Analyze arguments
90     // Note that all arguments might be in a single string!
91     for (i = 0; i < argc; ++i)
92     {
93         p = strstr(argv[i], "DEMO_DRC_WIDTH");
94         if (p != 0){
95             renderWidth = (u32)atoi(p+14+SKIP_NON_DIGIT(p[14]));
96         }
97         p = strstr(argv[i], "DEMO_DRC_HEIGHT");
98         if (p != 0){
99             renderHeight = (u32)atoi(p+15+SKIP_NON_DIGIT(p[15]));
100         }
101         p = strstr(argv[i], "DEMO_DRC_CB_FORMAT");
102         if (p != 0){
103             p = p+18+SKIP_NON_DIGIT(p[18]);
104             if(strncmp(p, "10_10_10_2", 10) == 0){
105                 renderCBFormat = GX2_SURFACE_FORMAT_TCS_R10_G10_B10_A2_UNORM;
106             } else if(strncmp(p, "2_10_10_10", 10) == 0){
107                 renderCBFormat = GX2_SURFACE_FORMAT_TCS_A2_B10_G10_R10_UNORM;
108             } else if(strncmp(p, "8_8_8_8_SRGB", 12) == 0){
109                 renderCBFormat = GX2_SURFACE_FORMAT_TCS_R8_G8_B8_A8_SRGB;
110             } else if(strncmp(p, "8_8_8_8", 7) == 0){
111                 renderCBFormat = GX2_SURFACE_FORMAT_TCS_R8_G8_B8_A8_UNORM;
112             } else if(strncmp(p, "16_16_16_16F", 12) == 0){
113                 renderCBFormat = GX2_SURFACE_FORMAT_TC_R16_G16_B16_A16_FLOAT;
114             } else if(strncmp(p, "32_32_32_32F", 12) == 0){
115                 renderCBFormat = GX2_SURFACE_FORMAT_TC_R32_G32_B32_A32_FLOAT;
116             } else {
117                 DEMOPrintf("Unrecognized CB format: %s\n",p);
118             }
119         }
120         p = strstr(argv[i], "DEMO_DRC_SCAN_FORMAT");
121         if (p != 0){
122             p = p+20+SKIP_NON_DIGIT(p[20]);
123             if(strncmp(p, "10_10_10_2", 10) == 0){
124                 scanOutCBFormat = GX2_SURFACE_FORMAT_TCS_R10_G10_B10_A2_UNORM;
125             }else if(strncmp(p, "2_10_10_10", 10) == 0){
126                 scanOutCBFormat = GX2_SURFACE_FORMAT_TCS_A2_B10_G10_R10_UNORM;
127             }else if(strncmp(p, "8_8_8_8_SRGB", 12) == 0){
128                 scanOutCBFormat = GX2_SURFACE_FORMAT_TCS_R8_G8_B8_A8_SRGB;
129             }else if(strncmp(p, "8_8_8_8", 7) == 0){
130                 scanOutCBFormat = GX2_SURFACE_FORMAT_TCS_R8_G8_B8_A8_UNORM;
131             } else {
132                 DEMOPrintf("Unrecognized SCAN format: %s\n",p);
133             }
134         }
135         p = strstr(argv[i], "DEMO_DRC_DB_FORMAT");
136         if (p != 0){
137             p = p+18+SKIP_NON_DIGIT(p[18]);
138             if(strncmp(p, "16", 2) == 0){
139                 renderDBFormat = GX2_SURFACE_FORMAT_TCD_R16_UNORM;
140             }else if(strncmp(p, "8_24F", 5) == 0){
141                 renderDBFormat = GX2_SURFACE_FORMAT_D_D24_S8_FLOAT;
142             }else if(strncmp(p, "8_24", 4) == 0){
143                 renderDBFormat = GX2_SURFACE_FORMAT_D_D24_S8_UNORM;
144             }else if(strncmp(p, "X24_8_32F", 9) == 0){
145                 renderDBFormat = GX2_SURFACE_FORMAT_D_D32_FLOAT_S8_UINT_X24;
146             }else if(strncmp(p, "32F", 3) == 0){
147                 renderDBFormat = GX2_SURFACE_FORMAT_TCD_R32_FLOAT;
148             } else  {
149                 DEMOPrintf("Unrecognized DB format: %s\n",p);
150             }
151         }
152         p = strstr(argv[i], "DEMO_DRC_AA_MODE");
153         if (p != 0){
154             renderAAMode = (GX2AAMode)atoi(p+16+SKIP_NON_DIGIT(p[16]));
155             GX2_CHECK_ENUM_RANGE(renderAAMode, GX2_AA_MODE)
156         }
157         p = strstr(argv[i], "DEMO_DRC_MODE");
158         if (p != 0){
159             renderMode = (GX2DRCMode)atoi(p+13);
160             GX2_CHECK_ENUM_RANGE(renderMode, GX2_DRC)
161         }
162     }
163 
164     char *aaStr[4]={ "1X", "2X", "4X", "8X" };
165     char *modeStr[4]={ "none", "Single", "Double", "Single 30Hz"};
166 
167     DEMOPrintf("DEMO: Rendering DRC:%dx%d CB:%s DB:%s ScanCB:%s AA:%s Mode:%s\n",
168                renderWidth, renderHeight,
169                &DEMOGfxGetSurfaceFormatName(renderCBFormat)[19],
170                &DEMOGfxGetSurfaceFormatName(renderDBFormat)[19],
171                &DEMOGfxGetSurfaceFormatName(scanOutCBFormat)[19],
172                aaStr[renderAAMode], modeStr[renderMode]);
173 
174     // Setup Scan Buffers
175     GX2CalcDRCSize(renderMode, scanOutCBFormat,
176                   GX2_BUFFERING_DOUBLE, &scanSize, &scaleNeeded);
177 
178     // For Cafe, should put scan buffers in the foreground bucket
179     DEMODRCScanBufferPtr = DEMOGfxAllocBucket(scanSize, GX2_SCAN_BUFFER_ALIGNMENT);
180     DEMOCheck(DEMODRCScanBufferPtr!=NULL, "DRC Scan buffer alloc failed");
181     GX2Invalidate(GX2_INVALIDATE_CPU, DEMODRCScanBufferPtr, scanSize);
182 
183     GX2SetDRCBuffer(DEMODRCScanBufferPtr, scanSize, renderMode,
184                    scanOutCBFormat, GX2_BUFFERING_DOUBLE);
185 
186     // Setup render buffer
187     GX2InitColorBuffer(&DEMODRCColorBuffer,
188                        renderWidth, renderHeight,
189                        renderCBFormat,
190                        renderAAMode);
191 
192     ptr = DEMOGfxAllocMEM1(DEMODRCColorBuffer.surface.imageSize,
193                            DEMODRCColorBuffer.surface.alignment);
194     DEMOCheck(ptr!=NULL, "DRC Color buffer alloc failed");
195     GX2Invalidate(GX2_INVALIDATE_CPU, ptr, DEMODRCColorBuffer.surface.imageSize);
196 
197     GX2InitColorBufferPtr(&DEMODRCColorBuffer, ptr);
198 
199     // Setup aux buffer
200     if (DEMODRCColorBuffer.surface.aa != GX2_AA_MODE_1X) {
201         u32 size, align;
202         GX2CalcColorBufferAuxInfo(&DEMODRCColorBuffer, &size, &align);
203         ptr = DEMOGfxAllocMEM1(size, align);
204         DEMOCheck(ptr!=NULL, "DRC Color aux buffer alloc failed");
205         GX2InitColorBufferAuxPtr(&DEMODRCColorBuffer, ptr);
206         GX2Invalidate(GX2_INVALIDATE_CPU, ptr, size);
207         // Aux buffer must be cleared manually to this value once:
208         GX2UTSetupColorAuxBuffer(&DEMODRCColorBuffer);
209     }
210 
211     // Setup Depth Buffer
212     GX2InitDepthBuffer(&DEMODRCDepthBuffer,
213                        renderWidth, renderHeight,
214                        renderDBFormat,
215                        renderAAMode);
216     ptr = DEMOGfxAllocMEM1(DEMODRCDepthBuffer.surface.imageSize,
217                            DEMODRCDepthBuffer.surface.alignment);
218     DEMOCheck(ptr!=NULL, "DRC Depth buffer alloc failed");
219     GX2Invalidate(GX2_INVALIDATE_CPU, ptr, DEMODRCDepthBuffer.surface.imageSize);
220     GX2InitDepthBufferPtr(&DEMODRCDepthBuffer, ptr);
221 
222     // Setup Hi-Z buffer
223     if (1) { // Allow testing with & without Hi-Z
224         u32 size, align;
225         GX2CalcDepthBufferHiZInfo(&DEMODRCDepthBuffer, &size, &align);
226         ptr = DEMOGfxAllocMEM1(size, align);
227         DEMOCheck(ptr!=NULL, "DRC Depth Hi-Z buffer alloc failed");
228         GX2Invalidate(GX2_INVALIDATE_CPU, ptr, size);
229         GX2InitDepthBufferHiZPtr(&DEMODRCDepthBuffer, ptr);
230     }
231 
232     // Register a callback upon foreground acquire and release
233     ProcUIRegisterCallback(PROCUI_MESSAGE_ACQUIRE, DEMODRCCallbackAcquiredForeground, NULL, 200);
234     ProcUIRegisterCallback(PROCUI_MESSAGE_RELEASE, DEMODRCCallbackReleaseForeground, NULL, 200);
235 
236     // Save state for DEMODRCAcquireForeground
237     gDemoDRCRenderMode = renderMode;
238     gDemoDRCScanOutCBFormat = scanOutCBFormat;
239     gDemoDRCScanSize = scanSize;
240 
241     // Save state for instancing
242     gDemoDRCRenderWidth = renderWidth;
243     gDemoDRCRenderHeight = renderHeight;
244 
245     // Create a new instance (including the context state)
246     gDemoDRCCurInstance = NULL;
247     DEMODRCAddInstance();
248 
249     // Indicate that graphics has been started
250     gDemoDRCRunningFlag = TRUE;
251 
252     return gDemoDRCCurInstance;
253 }
254 
DEMODRCShutdown()255 void DEMODRCShutdown()
256 {
257     // Delete the instances
258     DEMODRCDeleteInstance(gDemoDRCCurInstance);
259 
260     gDemoDRCOutputEnabled = FALSE;
261 
262     // Disable video outputs if this process is in the foreground.
263     if (gDemoGfxInForeground && OS_SHUTDOWN_RESTART != OSGetShutdownReason())
264     {
265         GX2SetDRCEnable(GX2_FALSE);
266     }
267 
268     // Free allocated buffers
269     DEMOGfxFreeBucket(DEMODRCScanBufferPtr);
270     if (DEMODRCDepthBuffer.hiZPtr) {
271         DEMOGfxFreeMEM1(DEMODRCDepthBuffer.hiZPtr);
272         DEMODRCDepthBuffer.hiZPtr = NULL;
273     }
274     DEMOGfxFreeMEM1(DEMODRCDepthBuffer.surface.imagePtr);
275     if (DEMODRCColorBuffer.auxPtr) {
276         DEMOGfxFreeMEM1(DEMODRCColorBuffer.auxPtr);
277         DEMODRCColorBuffer.auxPtr = NULL;
278     }
279     DEMOGfxFreeMEM1(DEMODRCColorBuffer.surface.imagePtr);
280 
281     gDemoDRCRunningFlag = FALSE;
282 }
283 
DEMODRCReleaseForeground()284 void DEMODRCReleaseForeground()
285 {
286     if (DEMODRCDepthBuffer.hiZPtr) {
287         DEMOGfxFreeMEM1(DEMODRCDepthBuffer.hiZPtr);
288         DEMODRCDepthBuffer.hiZPtr = NULL;
289     }
290     DEMOGfxFreeMEM1(DEMODRCDepthBuffer.surface.imagePtr);
291     if (DEMODRCColorBuffer.auxPtr) {
292         DEMOGfxFreeMEM1(DEMODRCColorBuffer.auxPtr);
293         DEMODRCColorBuffer.auxPtr = NULL;
294     }
295     DEMOGfxFreeMEM1(DEMODRCColorBuffer.surface.imagePtr);
296 
297     DEMOGfxFreeBucket(DEMODRCScanBufferPtr);
298 
299     gDemoDRCOutputEnabled = FALSE;
300 }
301 
DEMODRCAcquiredForeground()302 void DEMODRCAcquiredForeground()
303 {
304     void * ptr;
305 
306     // For Cafe, should put scan buffers in the foreground bucket
307     DEMODRCScanBufferPtr = DEMOGfxAllocBucket(gDemoDRCScanSize, GX2_SCAN_BUFFER_ALIGNMENT);
308     GX2Invalidate(GX2_INVALIDATE_CPU, DEMODRCScanBufferPtr, gDemoDRCScanSize);
309 
310     GX2SetDRCBuffer(DEMODRCScanBufferPtr, gDemoDRCScanSize, gDemoDRCRenderMode,
311                     gDemoDRCScanOutCBFormat, GX2_BUFFERING_DOUBLE);
312 
313     // Re-allocate color buffer
314     ptr = DEMOGfxAllocMEM1(DEMODRCColorBuffer.surface.imageSize,
315                            DEMODRCColorBuffer.surface.alignment);
316     GX2Invalidate(GX2_INVALIDATE_CPU, ptr, DEMODRCColorBuffer.surface.imageSize);
317 
318     GX2InitColorBufferPtr(&DEMODRCColorBuffer, ptr);
319 
320     // Setup aux buffer
321     if (DEMODRCColorBuffer.surface.aa != GX2_AA_MODE_1X) {
322         u32 size, align;
323         GX2CalcColorBufferAuxInfo(&DEMODRCColorBuffer, &size, &align);
324         ptr = DEMOGfxAllocMEM1(size, align);
325         GX2InitColorBufferAuxPtr(&DEMODRCColorBuffer, ptr);
326         GX2Invalidate(GX2_INVALIDATE_CPU, ptr, size);
327         // Aux buffer must be cleared manually to this value once:
328         GX2UTSetupColorAuxBuffer(&DEMODRCColorBuffer);
329     }
330 
331     // Re-allocate depth buffer
332     ptr = DEMOGfxAllocMEM1(DEMODRCDepthBuffer.surface.imageSize,
333                            DEMODRCDepthBuffer.surface.alignment);
334     GX2Invalidate(GX2_INVALIDATE_CPU, ptr, DEMODRCDepthBuffer.surface.imageSize);
335     GX2InitDepthBufferPtr(&DEMODRCDepthBuffer, ptr);
336 
337     // Setup Hi-Z buffer
338     if (1) { // Allow testing with & without Hi-Z
339         u32 size, align;
340         GX2CalcDepthBufferHiZInfo(&DEMODRCDepthBuffer, &size, &align);
341         ptr = DEMOGfxAllocMEM1(size, align);
342         GX2Invalidate(GX2_INVALIDATE_CPU, ptr, size);
343         GX2InitDepthBufferHiZPtr(&DEMODRCDepthBuffer, ptr);
344     }
345 
346     GX2SetContextState(DEMODRCContextState);
347 
348     // Force the next call to DEMODRCDoneRender to enable DRC output.
349     gDemoDRCOutputEnabled = FALSE;
350 }
351 
DEMODRCIsRunning()352 BOOL DEMODRCIsRunning()
353 {
354     return gDemoDRCRunningFlag;
355 }
356 
DEMODRCGetStatus()357 GX2DRCMode DEMODRCGetStatus()
358 {
359     return GX2GetSystemDRCMode();
360 }
361 
DEMODRCSetContextState(void)362 void DEMODRCSetContextState(void)
363 {
364     GX2SetContextState(DEMODRCContextState);
365 }
366 
DEMODRCBeforeRender(void)367 void DEMODRCBeforeRender(void)
368 {
369     // Set DRC Context
370     GX2SetContextState(DEMODRCContextState);
371 }
372 
DEMODRCDoneRender(void)373 void DEMODRCDoneRender(void)
374 {
375     // Copy Color Buffer to DRC SCAN Buffer
376     GX2CopyColorBufferToScanBuffer(&DEMODRCColorBuffer, GX2_SCAN_TARGET_DRC_FIRST);
377 
378     // Restore Demo context state after copy
379     DEMOGfxSetContextState();
380 
381     // Enable video output after first frame rendered
382     if (gDemoDRCOutputEnabled == FALSE) {
383         GX2SetDRCEnable(GX2_TRUE);
384         gDemoDRCOutputEnabled = TRUE;
385     }
386 }
387 
388 
DEMODRCAddInstance(void)389 DEMODRCInstance* DEMODRCAddInstance(void)
390 {
391     // Setup Context State buffer
392     DEMODRCContextState = DEMOGfxAllocMEM2(sizeof(GX2ContextState), GX2_CONTEXT_STATE_ALIGNMENT);
393     DEMOCheck(DEMODRCContextState != NULL, "DRC Context state buffer alloc failed");
394     // GX2SetupContextState will invalidate CPU cache for us
395     GX2SetupContextState(DEMODRCContextState);
396 
397     // Setup render/depth buffers to be used now
398     GX2SetColorBuffer(&DEMODRCColorBuffer, GX2_RENDER_TARGET_0);
399     GX2SetDepthBuffer(&DEMODRCDepthBuffer);
400 
401     // Misc graphics setup
402     GX2SetViewport(0, 0, (f32)gDemoDRCRenderWidth, (f32)gDemoDRCRenderHeight, 0.0f, 1.0f);
403     GX2SetScissor(0, 0, gDemoDRCRenderWidth, gDemoDRCRenderHeight);
404     GX2SetDRCScale(gDemoDRCRenderWidth, gDemoDRCRenderHeight);
405 
406     /////////////////////////////////////////////////////////////////////////////
407     // Create the new instance
408     gDemoDRCCurInstance = DEMOAlloc(sizeof(DEMODRCInstance));
409     gDemoDRCCurInstance->contextState = DEMODRCContextState;
410 
411     return gDemoDRCCurInstance;
412 }
413 
DEMODRCDeleteInstance(DEMODRCInstance * instance)414 void DEMODRCDeleteInstance(DEMODRCInstance *instance)
415 {
416     DEMOGfxFreeMEM2(instance->contextState);
417     DEMOFree(instance);
418 
419     // Edge case:  delete current
420     if (gDemoDRCCurInstance == instance) {
421         gDemoDRCCurInstance = NULL;
422         DEMODRCContextState = NULL;
423     }
424 }
425 
426 
DEMODRCSetInstance(DEMODRCInstance * instance)427 void DEMODRCSetInstance(DEMODRCInstance *instance)
428 {
429     gDemoDRCCurInstance = instance;
430 
431     DEMODRCContextState = instance->contextState;
432     GX2SetContextState(DEMODRCContextState);
433 }
434 
DEMODRCGetInstance(void)435 DEMODRCInstance* DEMODRCGetInstance(void)
436 {
437     return gDemoDRCCurInstance;
438 }
439