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 /// DEMOGfx.c
14 ///
15 /// This is graphics system code for the DEMO library.
16 ///
17 ////===========================================================================
18
19 #include <stdio.h>
20 #include <cafe/demo.h>
21 #include <cafe/gx2.h>
22 #include <cafe/procui.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 GX2ColorBuffer DEMOColorBuffer;
28 GX2DepthBuffer DEMODepthBuffer;
29 void *DEMOScanBufferPtr;
30
31 // DEMO Gfx Context State
32 GX2ContextState *DEMOContextState;
33
34 u32 *DEMOCommandBufferBasePtr;
35 #define DEMO_GFX_COMMAND_BUFFER_POOL_SIZE 1024*1024*sizeof(u32)
36
37 static BOOL gDemoGfxRunningFlag=FALSE;
38 static BOOL gDemoGfxTVEnabled=FALSE;
39 static BOOL gDemoGfxForceMEM2=FALSE;
40
41 BOOL gDemoGfxInForeground=TRUE;
42
43 static MEMHeapHandle gDEMOMem1Heap = MEM_HEAP_INVALID_HANDLE;
44 static MEMHeapHandle gDEMOBucketHeap = MEM_HEAP_INVALID_HANDLE;
45
46 static char gDemoAssetsDir[MAX_ASSET_DIR_LEN] = "assets/";
47
48 // State from init that needs to be preserved when reacquiring foreground.
49 static GX2TVRenderMode gDemoGfxRenderMode;
50 static GX2SurfaceFormat gDemoGfxScanOutCBFormat;
51 static u32 gDemoGfxScanSize;
52
53 // Other preserved items
54 static u32 gDemoGfxRenderWidth;
55 static u32 gDemoGfxRenderHeight;
56 static u32 gDemoGfxSwapInterval;
57
58 // Instance
59 static DEMOGfxInstance* gDemoGfxCurInstance = NULL;
60
61 //GPU Job Control
62 DEMOGfxGPUTask *pgDemoGfxGPUTaskList = NULL;
63 u32 gDemoGfxGPUFence = 1; // Start with fence unlocked
64 u64 *gpDemoGfxGPUTs = NULL;
65 u64 gDemoGfxTimeVal = 0;
66
67
DEMOGX2RAlloc(GX2RResourceFlags resourceFlags,u32 byteCount,u32 alignment)68 static void* DEMOGX2RAlloc(GX2RResourceFlags resourceFlags, u32 byteCount, u32 alignment)
69 {
70 if (GX2TestBitFlagsAny(resourceFlags, GX2R_BIND_COLOR_BUFFER | GX2R_BIND_DEPTH_BUFFER | GX2R_BIND_SCAN_BUFFER | GX2R_BIND_GS_RING | GX2R_USAGE_FORCE_MEM1) &&
71 !GX2TestBitFlagsAny(resourceFlags, GX2R_USAGE_FORCE_MEM2))
72 {
73 return DEMOGfxAllocMEM1(byteCount, alignment);
74 }
75 else
76 {
77 return DEMOGfxAllocMEM2(byteCount, alignment);
78 }
79 }
80
81
DEMOGX2RFree(GX2RResourceFlags resourceFlags,void * pMem)82 static void DEMOGX2RFree(GX2RResourceFlags resourceFlags, void* pMem)
83 {
84 if (GX2TestBitFlagsAny(resourceFlags, GX2R_BIND_COLOR_BUFFER | GX2R_BIND_DEPTH_BUFFER | GX2R_BIND_SCAN_BUFFER | GX2R_BIND_GS_RING | GX2R_USAGE_FORCE_MEM1) &&
85 !GX2TestBitFlagsAny(resourceFlags, GX2R_USAGE_FORCE_MEM2))
86 {
87 DEMOGfxFreeMEM1(pMem);
88 }
89 else
90 {
91 DEMOGfxFreeMEM2(pMem);
92 }
93 }
94
95
96
DEMOGfxAllocMEM1(u32 size,u32 align)97 void *DEMOGfxAllocMEM1(u32 size, u32 align)
98 {
99 void *ptr;
100
101 if (align < 4)
102 {
103 align = 4;
104 }
105
106 // DEMOGfxMem1HeapInit() must be called first to init the heap.
107 DEMOAssert(gDEMOMem1Heap != MEM_HEAP_INVALID_HANDLE);
108
109 // Use the expanded heap for demos.
110 ptr = MEMAllocFromExpHeapEx(gDEMOMem1Heap, size, align);
111 GX2NotifyMemAlloc(ptr, size, align);
112
113 DEMOAssert(ptr&&"Failed MEM1 alloc");
114
115 return ptr;
116 }
117
DEMOGfxFreeMEM1(void * ptr)118 void DEMOGfxFreeMEM1(void * ptr)
119 {
120 if (gDemoGfxInForeground) MEMFreeToExpHeap(gDEMOMem1Heap, ptr);
121 GX2NotifyMemFree(ptr);
122 }
123
DEMOGfxAllocBucket(u32 size,u32 align)124 void *DEMOGfxAllocBucket(u32 size, u32 align)
125 {
126 DEMOAssert(gDEMOBucketHeap != MEM_HEAP_INVALID_HANDLE);
127
128 void * ptr = MEMAllocFromExpHeapEx(gDEMOBucketHeap, size, align);
129 GX2NotifyMemAlloc(ptr, size, align);
130
131 DEMOAssert(ptr);
132
133 return ptr;
134 }
135
DEMOGfxFreeBucket(void * ptr)136 void DEMOGfxFreeBucket(void * ptr)
137 {
138 if (gDemoGfxInForeground) MEMFreeToExpHeap(gDEMOBucketHeap, ptr);
139 GX2NotifyMemFree(ptr);
140 }
141
DEMOGfxAllocMEM2(u32 size,u32 align)142 void *DEMOGfxAllocMEM2(u32 size, u32 align)
143 {
144 void *ptr;
145
146 if (align < 4)
147 {
148 align = 4;
149 }
150 // FINAL MEMORY MANAGEMENT MODEL
151 ptr = DEMOAllocEx(size, align);
152 GX2NotifyMemAlloc(ptr, size, align);
153
154 DEMOAssert(ptr&&"Failed MEM2 alloc");
155
156 return ptr;
157 }
158
159
DEMOGfxFreeMEM2(void * ptr)160 void DEMOGfxFreeMEM2(void * ptr)
161 {
162 // FINAL MEMORY MANAGEMENT MODEL
163 DEMOFree(ptr);
164 GX2NotifyMemFree(ptr);
165 }
166
DEMOGfxCallbackAcquiredForeground(void * unused)167 static u32 DEMOGfxCallbackAcquiredForeground(void* unused)
168 {
169 DEMOGfxAcquiredForeground();
170
171 // No issues
172 return 0;
173 }
174
DEMOGfxCallbackReleaseForeground(void * unused)175 static u32 DEMOGfxCallbackReleaseForeground(void* unused)
176 {
177 DEMOGfxReleaseForeground();
178
179 // No issues
180 return 0;
181 }
182
DEMOGfxInit(int argc,char * argv[])183 DEMOGfxInstance* DEMOGfxInit(int argc, char *argv[])
184 {
185 void *ptr;
186
187 u32 scanSize;
188 GX2Boolean scaleNeeded;
189
190 u32 i;
191 char *p;
192 u32 renderWidth = 1280;
193 u32 renderHeight = 720;
194 // Default to SRGB for gamma
195 GX2SurfaceFormat renderCBFormat = GX2_SURFACE_FORMAT_TCS_R8_G8_B8_A8_SRGB;
196 GX2SurfaceFormat scanOutCBFormat = GX2_SURFACE_FORMAT_TCS_R8_G8_B8_A8_SRGB;
197 GX2SurfaceFormat renderDBFormat = GX2_SURFACE_FORMAT_TCD_R32_FLOAT;
198 GX2AAMode renderAAMode = GX2_AA_MODE_1X;
199 GX2Boolean renderHiZ = GX2_TRUE;
200
201 static const u32 tvRenderModeTable[] = {
202 640, 480, GX2_TV_RENDER_480_NARROW, // 4:3 ratio (640x480)
203 854, 480, GX2_TV_RENDER_480_WIDE, // 16:9 ratio (854x480)
204 1280, 720, GX2_TV_RENDER_720, // 16:9 for all the rest...
205 1920, 1080, GX2_TV_RENDER_1080,
206 };
207 #define RM_TABLE_SZ 4
208
209 GX2TVRenderMode renderMode;
210
211 // Init flags
212 gDemoGfxRunningFlag=FALSE;
213 gDemoGfxTVEnabled=FALSE;
214 gDemoGfxForceMEM2=FALSE;
215
216 // Asset Directory
217 strcpy(gDemoAssetsDir, "assets/");
218
219 // Alloc Gfx command buffer pool
220 DEMOCommandBufferBasePtr = (u32 *) DEMOAllocEx(
221 DEMO_GFX_COMMAND_BUFFER_POOL_SIZE,
222 GX2_DEFAULT_BUFFER_ALIGNMENT);
223 DEMOCheck(DEMOCommandBufferBasePtr, "Failed to allocate command buffer pool");
224
225 // Passing user allocated cb buffer and command-line arguments to gx2Init
226 u32 gx2InitAttribs[] =
227 {
228 GX2_INIT_ATTRIB_CB_BASE, (u32)DEMOCommandBufferBasePtr, // cb buffer
229 GX2_INIT_ATTRIB_CB_SIZE, (u32)DEMO_GFX_COMMAND_BUFFER_POOL_SIZE, // cb size
230 GX2_INIT_ATTRIB_ARGC, (u32)argc, // number of args
231 GX2_INIT_ATTRIB_ARGV, (u32)argv, // command-line args
232 GX2_INIT_ATTRIB_NULL // terminates the list
233 };
234
235 // Initialize GX2 library
236 GX2Init(gx2InitAttribs);
237
238 s32 gx2DebugMode=-1;
239 s32 gx2rDebugOptions=-1;
240 u32 swapInterval = 1;
241
242 #define SKIP_NON_DIGIT(c) ((c)!=0&&((c)<'0'||(c)>'9'))
243
244 // Analyze arguments
245 // Note that all arguments might be in a single string!
246 for (i = 0; i < argc; ++i)
247 {
248 p = strstr(argv[i], "DEMO_WIDTH");
249 if (p != 0){
250 renderWidth = (u32)atoi(p+10+SKIP_NON_DIGIT(p[10]));
251 }
252 p = strstr(argv[i], "DEMO_HEIGHT");
253 if (p != 0){
254 renderHeight = (u32)atoi(p+11+SKIP_NON_DIGIT(p[11]));
255 }
256 p = strstr(argv[i], "DEMO_CB_FORMAT");
257 if (p != 0){
258 p = p+14+SKIP_NON_DIGIT(p[14]);
259 if(strncmp(p, "10_10_10_2", 10) == 0){
260 renderCBFormat = GX2_SURFACE_FORMAT_TCS_R10_G10_B10_A2_UNORM;
261 } else if(strncmp(p, "2_10_10_10", 10) == 0){
262 renderCBFormat = GX2_SURFACE_FORMAT_TCS_A2_B10_G10_R10_UNORM;
263 } else if(strncmp(p, "8_8_8_8_SRGB", 12) == 0){
264 renderCBFormat = GX2_SURFACE_FORMAT_TCS_R8_G8_B8_A8_SRGB;
265 } else if(strncmp(p, "8_8_8_8", 7) == 0){
266 renderCBFormat = GX2_SURFACE_FORMAT_TCS_R8_G8_B8_A8_UNORM;
267 } else if(strncmp(p, "16_16_16_16F", 12) == 0){
268 renderCBFormat = GX2_SURFACE_FORMAT_TC_R16_G16_B16_A16_FLOAT;
269 } else if(strncmp(p, "32_32_32_32F", 12) == 0){
270 renderCBFormat = GX2_SURFACE_FORMAT_TC_R32_G32_B32_A32_FLOAT;
271 } else if(strncmp(p, "16", 2) == 0){
272 renderCBFormat = GX2_SURFACE_FORMAT_TCD_R16_UNORM;
273 } else if(strncmp(p, "32F", 3) == 0){
274 renderCBFormat = GX2_SURFACE_FORMAT_TCD_R32_FLOAT;
275 } else {
276 DEMOPrintf("Unrecognized CB format: %s\n",p);
277 }
278 }
279 p = strstr(argv[i], "DEMO_SCAN_FORMAT");
280 if (p != 0){
281 p = p+16+SKIP_NON_DIGIT(p[16]);
282 if(strncmp(p, "10_10_10_2", 10) == 0){
283 scanOutCBFormat = GX2_SURFACE_FORMAT_TCS_R10_G10_B10_A2_UNORM;
284 }else if(strncmp(p, "2_10_10_10", 10) == 0){
285 scanOutCBFormat = GX2_SURFACE_FORMAT_TCS_A2_B10_G10_R10_UNORM;
286 }else if(strncmp(p, "8_8_8_8_SRGB", 12) == 0){
287 scanOutCBFormat = GX2_SURFACE_FORMAT_TCS_R8_G8_B8_A8_SRGB;
288 }else if(strncmp(p, "8_8_8_8", 7) == 0){
289 scanOutCBFormat = GX2_SURFACE_FORMAT_TCS_R8_G8_B8_A8_UNORM;
290 } else {
291 DEMOPrintf("Unrecognized SCAN format: %s\n",p);
292 }
293 }
294 p = strstr(argv[i], "DEMO_DB_FORMAT");
295 if (p != 0){
296 p = p+14+SKIP_NON_DIGIT(p[14]);
297 if(strncmp(p, "16", 2) == 0){
298 renderDBFormat = GX2_SURFACE_FORMAT_TCD_R16_UNORM;
299 }else if(strncmp(p, "8_24F", 5) == 0){
300 renderDBFormat = GX2_SURFACE_FORMAT_D_D24_S8_FLOAT;
301 }else if(strncmp(p, "8_24", 4) == 0){
302 renderDBFormat = GX2_SURFACE_FORMAT_D_D24_S8_UNORM;
303 }else if(strncmp(p, "X24_8_32F", 9) == 0){
304 renderDBFormat = GX2_SURFACE_FORMAT_D_D32_FLOAT_S8_UINT_X24;
305 }else if(strncmp(p, "32F", 3) == 0){
306 renderDBFormat = GX2_SURFACE_FORMAT_TCD_R32_FLOAT;
307 } else {
308 DEMOPrintf("Unrecognized DB format: %s\n",p);
309 }
310 }
311 p = strstr(argv[i], "DEMO_AA_MODE");
312 if (p != 0){
313 renderAAMode = (GX2AAMode)atoi(p+12+SKIP_NON_DIGIT(p[12]));
314 GX2_CHECK_ENUM_RANGE(renderAAMode, GX2_AA_MODE)
315 }
316 p = strstr(argv[i], "DEMO_FONT_DISABLE");
317 if (p != 0){
318 DEMOFontDrawEnable(FALSE);
319 DEMOPrintf("DEMO: DISABLE_FONT\n");
320 }
321 p = strstr(argv[i], "DEMO_HIZ_DISABLE");
322 if (p != 0){
323 DEMOPrintf("DEMO: DISABLE_HIZ\n");
324 renderHiZ = GX2_FALSE;
325 }
326
327 p = strstr(argv[i], "DEMO_GX2_DEBUG_MODE");
328 if (p != 0)
329 {
330 sscanf(p+strlen("DEMO_GX2_DEBUG_MODE="), "%i", &gx2DebugMode); // allows hex notation
331 }
332
333 p = strstr(argv[i], "DEMO_GX2R_DEBUG_OPTIONS");
334 if (p != 0)
335 {
336 sscanf(p+strlen("DEMO_GX2R_DEBUG_OPTIONS="), "%i", &gx2rDebugOptions); // allows hex notation
337 }
338
339 p = strstr(argv[i], "DEMO_SWAP_INTERVAL");
340 if (p != 0)
341 {
342 u32 offset=strlen("DEMO_SWAP_INTERVAL");
343 swapInterval = atoi(p+offset+SKIP_NON_DIGIT(p[offset]));
344 OSReport("DEMO: swap interval=%d\n", swapInterval);
345 }
346
347 p = strstr(argv[i], "DEMO_FORCE_MEM2");
348 if (p != 0){
349 gDemoGfxForceMEM2 = TRUE;
350 DEMOPrintf("DEMO: FORCE_MEM2\n");
351 DEMOPrintf("DEMO: Performance will be signifcantly worse!\n");
352 }
353
354 // Modify the assets directory if DEMO_ASSETS_DIR is passed in
355 p = strstr(argv[i], "DEMO_ASSETS_DIR=");
356 if (p != 0){
357 char tempBuffer[MAX_ASSET_DIR_LEN];
358 tempBuffer[MAX_ASSET_DIR_LEN - 2] = 0;
359
360 strncpy(tempBuffer, p+strlen("DEMO_ASSETS_DIR="), MAX_ASSET_DIR_LEN - 2);
361 // replace EOL or ',' with terminating 0
362 char* p2 = tempBuffer;
363 for( ; *p2 != '\n' && *p2 != '\r' && *p2 != ',' && *p2 != 0; p2++ ) {}
364 *p2 = 0;
365
366 // Make sure the asset directory ends with a forward slash
367 if (*(p2 - 1) != '/')
368 {
369 *p2 = '/';
370 *(p2 + 1) = 0;
371 }
372
373 strcpy(gDemoAssetsDir, tempBuffer);
374 }
375 }
376
377 //Use a different MEM1 allocator for DEMO lib.
378 DEMOGfxMem1HeapInit();
379 DEMOGfxBucketHeapInit();
380
381 if (gx2DebugMode!=-1)
382 {
383 DEMOPrintf("DEMO: GX2 debug mode=%#04x\n", gx2DebugMode);
384 GX2SetDebugMode((GX2DebugMode)gx2DebugMode);
385 }
386
387 #ifdef _DEBUG
388 // If no GX2R debug options specified, default some of them in debug builds
389 if (gx2rDebugOptions==-1)
390 {
391 gx2rDebugOptions = GX2R_DEBUG_GUARD_BANDS_ENABLED | GX2R_DEBUG_LEAK_CHECK | GX2R_DEBUG_CHECK_GPU_CONTENTION;
392 }
393 #endif
394
395 if (gx2rDebugOptions!=-1)
396 {
397 DEMOPrintf("DEMO: GX2R debug options=%#04x\n", gx2rDebugOptions);
398 GX2RSetDebugOptions((GX2RDebugOptions)gx2rDebugOptions);
399 }
400
401 // Hook in the demo allocators for GX2R
402 GX2RSetAllocator(DEMOGX2RAlloc, DEMOGX2RFree);
403
404 char *aaStr[4]={ "1X", "2X", "4X", "8X" };
405
406 DEMOPrintf("DEMO: Rendering TV:%dx%d CB:%s DB:%s ScanCB:%s AA:%s\n",
407 renderWidth, renderHeight,
408 &DEMOGfxGetSurfaceFormatName(renderCBFormat)[19],
409 &DEMOGfxGetSurfaceFormatName(renderDBFormat)[19],
410 &DEMOGfxGetSurfaceFormatName(scanOutCBFormat)[19],
411 aaStr[renderAAMode]);
412
413 // Choose an appropriate TV render mode based on desired dimensions
414 for (i = 0; i < RM_TABLE_SZ; i++) {
415 if (((tvRenderModeTable[i*3] >= renderWidth) &&
416 (tvRenderModeTable[i*3+1] >= renderHeight)) || i==(RM_TABLE_SZ-1)) {
417 renderMode = (GX2TVRenderMode) tvRenderModeTable[i*3+2];
418 break;
419 }
420 }
421
422 // Setup Scan Buffers; this must be done before setting up TV render targets!
423 GX2CalcTVSize(renderMode, scanOutCBFormat,
424 GX2_BUFFERING_DOUBLE, &scanSize, &scaleNeeded);
425
426 // For Cafe, should put scan buffers in the foreground bucket
427 DEMOScanBufferPtr = DEMOGfxAllocBucket(scanSize, GX2_SCAN_BUFFER_ALIGNMENT);
428 DEMOCheck(DEMOScanBufferPtr!=NULL, "Scan buffer alloc failed");
429 GX2Invalidate(GX2_INVALIDATE_CPU, DEMOScanBufferPtr, scanSize);
430
431 GX2SetTVBuffer(DEMOScanBufferPtr, scanSize, renderMode,
432 scanOutCBFormat, GX2_BUFFERING_DOUBLE);
433
434 // First, we do all the memory allocations to see what fits into MEM1.
435
436 // Setup render buffer; designate it as "final" TV render target.
437 GX2InitColorBufferFTV(&DEMOColorBuffer,
438 renderWidth, renderHeight,
439 renderCBFormat,
440 renderAAMode);
441
442 // AA mode may have changed due to display-related issues.
443 // Please refer to the GX2 display documentation.
444 renderAAMode = DEMOColorBuffer.surface.aa;
445
446 ptr = DEMOGfxAllocMEM1(DEMOColorBuffer.surface.imageSize,
447 DEMOColorBuffer.surface.alignment);
448 DEMOCheck(ptr!=NULL, "Color buffer alloc failed");
449 GX2Invalidate(GX2_INVALIDATE_CPU, ptr, DEMOColorBuffer.surface.imageSize);
450
451 GX2InitColorBufferPtr(&DEMOColorBuffer, ptr);
452
453 // Setup aux buffer
454 if (DEMOColorBuffer.surface.aa != GX2_AA_MODE_1X) {
455 u32 size, align;
456 GX2CalcColorBufferAuxInfo(&DEMOColorBuffer, &size, &align);
457 ptr = DEMOGfxAllocMEM1(size, align);
458 DEMOCheck(ptr!=NULL, "Color aux buffer alloc failed");
459 GX2InitColorBufferAuxPtr(&DEMOColorBuffer, ptr);
460 GX2Invalidate(GX2_INVALIDATE_CPU, ptr, size);
461 // Aux buffer must be cleared manually to this value once:
462 GX2UTSetupColorAuxBuffer(&DEMOColorBuffer);
463 }
464
465 // Setup Depth Buffer
466 GX2InitDepthBuffer(&DEMODepthBuffer,
467 renderWidth, renderHeight,
468 renderDBFormat,
469 renderAAMode);
470 ptr = DEMOGfxAllocMEM1(DEMODepthBuffer.surface.imageSize,
471 DEMODepthBuffer.surface.alignment);
472 DEMOCheck(ptr!=NULL, "Depth buffer alloc failed");
473 GX2Invalidate(GX2_INVALIDATE_CPU, ptr, DEMODepthBuffer.surface.imageSize);
474 GX2InitDepthBufferPtr(&DEMODepthBuffer, ptr);
475
476 // Setup Hi-Z buffer
477 if (renderHiZ) {
478 u32 size, align;
479 GX2CalcDepthBufferHiZInfo(&DEMODepthBuffer, &size, &align);
480 ptr = DEMOGfxAllocMEM1(size, align);
481 DEMOCheck(ptr!=NULL, "Depth Hi-Z buffer alloc failed");
482 GX2Invalidate(GX2_INVALIDATE_CPU, ptr, size);
483 GX2InitDepthBufferHiZPtr(&DEMODepthBuffer, ptr);
484 }
485
486 // Register a callback upon foreground acquire and release
487 ProcUIRegisterCallback(PROCUI_MESSAGE_ACQUIRE, DEMOGfxCallbackAcquiredForeground, NULL, 100);
488 ProcUIRegisterCallback(PROCUI_MESSAGE_RELEASE, DEMOGfxCallbackReleaseForeground, NULL, 100);
489
490 // Save state for DEMOGfxAcquiredForeground
491 gDemoGfxRenderMode = renderMode;
492 gDemoGfxScanOutCBFormat = scanOutCBFormat;
493 gDemoGfxScanSize = scanSize;
494
495 // Save state for instancing
496 gDemoGfxRenderWidth = renderWidth;
497 gDemoGfxRenderHeight = renderHeight;
498 gDemoGfxSwapInterval = swapInterval;
499
500 // Create a new instance (including the context state)
501 gDemoGfxCurInstance = NULL;
502 DEMOGfxAddInstance();
503
504 // The main core is the one with GFX
505 DEMOSetMainCore(OSGetCoreId());
506
507 // Indicate that graphics has been started
508 gDemoGfxRunningFlag = TRUE;
509
510 // Align on a cache-line boundary
511 gpDemoGfxGPUTs = (u64*)DEMOGfxAllocMEM2(sizeof(u64), 32);
512 *gpDemoGfxGPUTs = GX2_INVALID_COUNTER_VALUE_U64;
513 GX2Invalidate(GX2_INVALIDATE_CPU, gpDemoGfxGPUTs, 32);
514
515 return gDemoGfxCurInstance;
516 }
517
DEMOGfxShutdown()518 void DEMOGfxShutdown()
519 {
520 // Delete the instances
521 DEMOGfxDeleteInstance(gDemoGfxCurInstance);
522
523 // It is possible to exit from the background, but some API calls
524 // can only happen from the foreground. Check a flag to see if this
525 // processes is exiting from the foreground before calling APIs
526 // that deal with foreground-only resources.
527
528 // Disable video outputs
529 if (gDemoGfxInForeground && OS_SHUTDOWN_RESTART != OSGetShutdownReason())
530 {
531 GX2SetTVEnable(GX2_FALSE);
532 }
533 gDemoGfxTVEnabled = FALSE;
534
535 // Free allocated buffers
536 DEMOGfxFreeBucket(DEMOScanBufferPtr);
537 if (DEMODepthBuffer.hiZPtr) {
538 DEMOGfxFreeMEM1(DEMODepthBuffer.hiZPtr);
539 DEMODepthBuffer.hiZPtr = NULL;
540 }
541 DEMOGfxFreeMEM1(DEMODepthBuffer.surface.imagePtr);
542 if (DEMOColorBuffer.auxPtr) {
543 DEMOGfxFreeMEM1(DEMOColorBuffer.auxPtr);
544 DEMOColorBuffer.auxPtr = NULL;
545 }
546 DEMOGfxFreeMEM1(DEMOColorBuffer.surface.imagePtr);
547 if (gDemoGfxInForeground) DEMOFree(DEMOCommandBufferBasePtr);
548
549 // Free GPU Task Control System
550 DEMOGfxFreeMEM2(gpDemoGfxGPUTs);
551 if (pgDemoGfxGPUTaskList)
552 {
553 DEMOGfxFreeGPUTasks();
554 }
555
556 // Shutdown GX2 (which is safe to call from the background);
557 GX2Shutdown();
558
559 // Dump any leaked resources if enabled
560 if (GX2RGetDebugOptions() & GX2R_DEBUG_LEAK_CHECK)
561 {
562 if (GX2TempGetResourceCount()>0)
563 {
564 OSReport("***DEMO: resources were not destroyed on shutdown\n");
565 GX2TempDumpResources();
566 ASSERT(FALSE && "Resources were not destroyed on shutdown");
567 }
568 }
569 // Unhook the GX2R allocator functions.
570 GX2RSetAllocator(NULL, NULL);
571
572 // Only destroy these heaps if this process is in the foreground.
573 if (gDemoGfxInForeground)
574 {
575 DEMOGfxMem1HeapDestroy();
576 DEMOGfxBucketHeapDestroy();
577 }
578
579 gDemoGfxRunningFlag = FALSE;
580 }
581
DEMOGfxReleaseForeground()582 void DEMOGfxReleaseForeground()
583 {
584 // First wait for all pending draws to complete.
585 GX2DrawDone();
586
587 // Release resources in MEM1
588 if (DEMODepthBuffer.hiZPtr) {
589 DEMOGfxFreeMEM1(DEMODepthBuffer.hiZPtr);
590 DEMODepthBuffer.hiZPtr = NULL;
591 }
592 DEMOGfxFreeMEM1(DEMODepthBuffer.surface.imagePtr);
593 if (DEMOColorBuffer.auxPtr) {
594 DEMOGfxFreeMEM1(DEMOColorBuffer.auxPtr);
595 DEMOColorBuffer.auxPtr = NULL;
596 }
597 DEMOGfxFreeMEM1(DEMOColorBuffer.surface.imagePtr);
598
599 // Free resources from the foreground bucket
600 DEMOGfxFreeBucket(DEMOScanBufferPtr);
601
602 // Destroy heaps that will not be available.
603 DEMOGfxMem1HeapDestroy();
604 DEMOGfxBucketHeapDestroy();
605
606 // Mark the TV as disabled.
607 gDemoGfxTVEnabled=FALSE;
608
609 // Set a flag to indicate that this process is in the background.
610 gDemoGfxInForeground=FALSE;
611 OSMemoryBarrier();
612 }
613
DEMOGfxAcquiredForeground()614 void DEMOGfxAcquiredForeground()
615 {
616 void *ptr;
617
618 // Set a flag to indicate that this process is in the foreground.
619 gDemoGfxInForeground=TRUE;
620 OSMemoryBarrier();
621
622 // Recreate heaps that were lost.
623 DEMOGfxMem1HeapInit();
624 DEMOGfxBucketHeapInit();
625
626 // For Cafe, should put scan buffers in the foreground bucket
627 DEMOScanBufferPtr = DEMOGfxAllocBucket(gDemoGfxScanSize, GX2_SCAN_BUFFER_ALIGNMENT);
628 GX2Invalidate(GX2_INVALIDATE_CPU, DEMOScanBufferPtr, gDemoGfxScanSize);
629
630 GX2SetTVBuffer(DEMOScanBufferPtr, gDemoGfxScanSize, gDemoGfxRenderMode,
631 gDemoGfxScanOutCBFormat, GX2_BUFFERING_DOUBLE);
632
633 // Re-allocate color buffer
634 ptr = DEMOGfxAllocMEM1(DEMOColorBuffer.surface.imageSize,
635 DEMOColorBuffer.surface.alignment);
636 GX2Invalidate(GX2_INVALIDATE_CPU, ptr, DEMOColorBuffer.surface.imageSize);
637
638 GX2InitColorBufferPtr(&DEMOColorBuffer, ptr);
639
640 // Setup aux buffer
641 if (DEMOColorBuffer.surface.aa != GX2_AA_MODE_1X) {
642 u32 size, align;
643 GX2CalcColorBufferAuxInfo(&DEMOColorBuffer, &size, &align);
644 ptr = DEMOGfxAllocMEM1(size, align);
645 GX2InitColorBufferAuxPtr(&DEMOColorBuffer, ptr);
646 GX2Invalidate(GX2_INVALIDATE_CPU, ptr, size);
647 // Aux buffer must be cleared manually to this value once:
648 GX2UTSetupColorAuxBuffer(&DEMOColorBuffer);
649 }
650
651 // Re-allocate depth buffer
652 ptr = DEMOGfxAllocMEM1(DEMODepthBuffer.surface.imageSize,
653 DEMODepthBuffer.surface.alignment);
654 GX2Invalidate(GX2_INVALIDATE_CPU, ptr, DEMODepthBuffer.surface.imageSize);
655 GX2InitDepthBufferPtr(&DEMODepthBuffer, ptr);
656
657 // Setup Hi-Z buffer
658 if (1) { // Allow testing with & without Hi-Z
659 u32 size, align;
660 GX2CalcDepthBufferHiZInfo(&DEMODepthBuffer, &size, &align);
661 ptr = DEMOGfxAllocMEM1(size, align);
662 GX2Invalidate(GX2_INVALIDATE_CPU, ptr, size);
663 GX2InitDepthBufferHiZPtr(&DEMODepthBuffer, ptr);
664 }
665
666 GX2SetContextState(DEMOContextState);
667
668 // Indicate that graphics has been started
669 gDemoGfxRunningFlag = TRUE;
670 }
671
DEMOGfxIsRunning()672 BOOL DEMOGfxIsRunning()
673 {
674 return gDemoGfxRunningFlag;
675 }
676
DEMOGfxSetContextState(void)677 void DEMOGfxSetContextState(void)
678 {
679 GX2UTDebugTagIndent("DEMOGfxSetContextState()");
680 GX2SetContextState(DEMOContextState);
681 GX2UTDebugTagUndent();
682 }
683
DEMOGfxBeforeRender(void)684 void DEMOGfxBeforeRender(void)
685 {
686 GX2UTDebugTagIndent("DEMOGfxBeforeRender()");
687 // Allow CPU to run 1 frame ahead of GPU and display
688 //DEMOGfxWaitForSwap(1, 0);
689 //TEMP TODO: most of the demos rely on the CPU not being ahead of the GPU, until that's (maybe) going to get fixed
690 // we need to leave the swap queue depth at 0.
691 DEMOGfxWaitForSwap(0, 0);
692
693 // Enabled when Demo Perf condition is met
694 DEMOTestCheckPerfBegin();
695 GX2UTDebugTagUndent();
696 }
697
DEMOGfxDoneRender(void)698 void DEMOGfxDoneRender(void)
699 {
700 GX2UTDebugTagIndent("DEMOGfxDoneRender()");
701 // Enabled when Demo Perf condition is met
702 DEMOTestCheckPerfEnd();
703
704 // This extra flush avoids a potential race condition that can occur with
705 // the GX2R Resource Tracker: the swap buffer command might finish before
706 // the time stamp of its CB is updated. The race condition would make the
707 // resource appear still in use at the start of the next frame. This extra
708 // flush makes sure that no GX2R resources share the same time stamp as
709 // the swap buffer CB, thus avoiding the problem.
710 GX2Flush();
711
712 GX2SwapBuffers(&DEMOColorBuffer);
713
714 // Restore the context state after copy
715 GX2SetContextState(DEMOContextState);
716
717 // Do this before the flush so it's in the same CB as everything else
718 GX2UTDebugTagUndent();
719
720 // Flush after swap, since swap goes into the FIFO
721 GX2Flush();
722
723 // Enable video output after first frame rendered
724 if (gDemoGfxTVEnabled == FALSE) {
725 GX2SetTVEnable(GX2_TRUE);
726 gDemoGfxTVEnabled = TRUE;
727 }
728 }
729
DEMOGfxDrawDone(void)730 void DEMOGfxDrawDone(void)
731 {
732 // Only if running and in the foreground
733 if (APP_IN_FOREGROUND && DEMOGfxIsRunning())
734 GX2DrawDone();
735 }
736
DEMOGfxWaitForSwap(u32 depth,u32 percent)737 void DEMOGfxWaitForSwap(u32 depth, u32 percent)
738 {
739 GX2UTDebugTagIndent("DEMOGfxWaitForSwap()");
740 u32 swapCount, flipCount, waitCount=0;
741 OSTime tLastFlip, tLastVsync;
742 OSTime tNow;
743 const OSTime t60 = (OSTime)OSSecondsToTicks(1.0f/59.94f);
744 OSTime period;
745 u32 swapInt = GX2GetSwapInterval();
746
747 if (swapInt != 0)
748 {
749 // Note: must be careful about unsigned wrap-around!
750
751 // Wait for "depth" frames ago to post
752 while (1)
753 {
754 GX2GetSwapStatus(&swapCount, &flipCount, &tLastFlip, &tLastVsync);
755 if (flipCount+depth >= swapCount) break;
756
757 // If we've waited over 10 seconds for a flip, consider the GPU hung
758 // and stop running.
759 if (waitCount++ > 60*GX2GetGPUTimeout()/1000) {
760 OSReport("DEMOGfxWaitForSwap timed out. Potential GPU hang detected?\n");
761 GX2SetMiscParam(GX2_MISC_HANG_STATE, GX2_HANG_STATE_ETC);
762 if (GX2GetMiscParam(GX2_MISC_HANG_RESPONSE) == GX2_HANG_RESPONSE_DEBUG) {
763 GX2PrintGPUStatus();
764 OSDebugStrIfConnected(0);
765 DEMOStopRunning();
766 }
767 break;
768 }
769
770 // Call WaitForVsync instead of WaitForFlip due to possible
771 // race condition of flip happening right after above test.
772 // (There will always be more vsyncs, but not always more flips.)
773 GX2WaitForVsync();
774 }
775
776 // Wait for (percent * Swap Period) milliseconds since last flip
777 period = (percent * swapInt * t60 / 100);
778 tNow = OSGetSystemTime();
779 if (period > (tNow - tLastFlip))
780 {
781 OSSleepTicks(period - (tNow - tLastFlip));
782 }
783 }
784
785 GX2UTDebugTagUndent();
786 }
787
DEMOGfxMem1HeapInit(void)788 void DEMOGfxMem1HeapInit(void)
789 {
790 //A real game should use the frame heap directly to save memory,
791 //but using an expanded heap makes the demos simpler.
792
793 //For more information on MEM1 usage, go to
794 // Operating System->Cafe Core OS (COS) Overview->Basic Memory Allocation->MEM1
795 //in the MAN pages.
796 MEMHeapHandle hMEM1 = MEMGetBaseHeapHandle(MEM_ARENA_1);
797 u32 uMEM1Size = MEMGetAllocatableSizeForFrmHeapEx(hMEM1,4);
798 if (!gDemoGfxForceMEM2)
799 {
800 void* pStartOfMem1 = MEMAllocFromFrmHeapEx(hMEM1, uMEM1Size, 4);
801 gDEMOMem1Heap = MEMCreateExpHeap(pStartOfMem1, uMEM1Size);
802 }
803 else
804 {
805 void* pStartOfMem1 = MEMAllocFromDefaultHeapEx(uMEM1Size, 4);
806 gDEMOMem1Heap = MEMCreateExpHeap(pStartOfMem1, uMEM1Size);
807 }
808 DEMOAssert(gDEMOMem1Heap != MEM_HEAP_INVALID_HANDLE);
809 }
810
DEMOGfxMem1HeapDestroy(void)811 void DEMOGfxMem1HeapDestroy(void)
812 {
813 DEMOAssert(gDEMOMem1Heap != MEM_HEAP_INVALID_HANDLE);
814
815 //Destroy the expanded heap and reset the frame heap to restore the allocation.
816 MEMDestroyExpHeap(gDEMOMem1Heap);
817 if (!gDemoGfxForceMEM2)
818 {
819 MEMHeapHandle hMEM1 = MEMGetBaseHeapHandle(MEM_ARENA_1);
820 MEMFreeToFrmHeap(hMEM1, MEM_FRMHEAP_FREE_ALL);
821 }
822 else
823 {
824 MEMFreeToDefaultHeap(gDEMOMem1Heap);
825 }
826 gDEMOMem1Heap = MEM_HEAP_INVALID_HANDLE;
827 }
828
DEMOGfxBucketHeapInit(void)829 void DEMOGfxBucketHeapInit(void)
830 {
831 //A real game should use the frame heap directly to save memory,
832 //but using an expanded heap makes the demos simpler.
833
834 //For more information on Foreground Bucket usage, go to
835 // Operating System->Cafe Core OS (COS) Overview->Basic Memory Allocation->Foreground Bucket
836 //in the MAN pages.
837 MEMHeapHandle hMEMFg = MEMGetBaseHeapHandle(MEM_ARENA_FG);
838 u32 uMEMFgSize = MEMGetAllocatableSizeForFrmHeapEx(hMEMFg,4);
839 void* pStartOfMemFg = MEMAllocFromFrmHeapEx(hMEMFg, uMEMFgSize, 4);
840 gDEMOBucketHeap = MEMCreateExpHeap(pStartOfMemFg, uMEMFgSize);
841 DEMOAssert(gDEMOBucketHeap != MEM_HEAP_INVALID_HANDLE);
842 }
843
DEMOGfxBucketHeapDestroy(void)844 void DEMOGfxBucketHeapDestroy(void)
845 {
846 DEMOAssert(gDEMOBucketHeap != MEM_HEAP_INVALID_HANDLE);
847
848 //Destroy the expanded heap and reset the frame heap to restore the allocation.
849 MEMDestroyExpHeap(gDEMOBucketHeap);
850 gDEMOBucketHeap = MEM_HEAP_INVALID_HANDLE;
851 MEMHeapHandle hMEMFg = MEMGetBaseHeapHandle(MEM_ARENA_FG);
852 MEMFreeToFrmHeap(hMEMFg, MEM_FRMHEAP_FREE_ALL);
853 }
854
855
DEMOGfxAddInstance(void)856 DEMOGfxInstance* DEMOGfxAddInstance(void)
857 {
858 // Setup Context State buffer
859 DEMOContextState = (GX2ContextState *)DEMOGfxAllocMEM2(sizeof(GX2ContextState), GX2_CONTEXT_STATE_ALIGNMENT);
860 DEMOCheck(DEMOContextState != NULL, "Context state buffer alloc failed");
861 // GX2SetupContextState will invalidate CPU cache for us
862 GX2SetupContextState(DEMOContextState);
863
864 // Setup render/depth buffers to be used now
865 GX2SetColorBuffer(&DEMOColorBuffer, GX2_RENDER_TARGET_0);
866 GX2SetDepthBuffer(&DEMODepthBuffer);
867
868 // Misc graphics setup
869 GX2SetViewport(0, 0, (f32)gDemoGfxRenderWidth, (f32)gDemoGfxRenderHeight, 0.0f, 1.0f);
870 GX2SetScissor(0, 0, gDemoGfxRenderWidth, gDemoGfxRenderHeight);
871
872 // Indicate that swaps can happen as fast as every vertical interval (1/60 sec)
873 GX2SetSwapInterval(gDemoGfxSwapInterval);
874
875 /////////////////////////////////////////////////////////////////////////////
876 // Create the new instance
877 gDemoGfxCurInstance = (DEMOGfxInstance *)DEMOAlloc(sizeof(DEMOGfxInstance));
878 gDemoGfxCurInstance->contextState = DEMOContextState;
879
880 return gDemoGfxCurInstance;
881 }
882
DEMOGfxDeleteInstance(DEMOGfxInstance * instance)883 void DEMOGfxDeleteInstance(DEMOGfxInstance *instance)
884 {
885 DEMOGfxFreeMEM2(instance->contextState);
886 DEMOFree(instance);
887
888 // Edge case: delete current
889 if (gDemoGfxCurInstance == instance) {
890 gDemoGfxCurInstance = NULL;
891 DEMOContextState = NULL;
892 }
893 }
894
895
DEMOGfxSetInstance(DEMOGfxInstance * instance)896 void DEMOGfxSetInstance(DEMOGfxInstance *instance)
897 {
898 gDemoGfxCurInstance = instance;
899
900 DEMOContextState = instance->contextState;
901 GX2SetContextState(DEMOContextState);
902 }
903
DEMOGfxGetInstance(void)904 DEMOGfxInstance* DEMOGfxGetInstance(void)
905 {
906 return gDemoGfxCurInstance;
907 }
908
DEMOGfxOpenAssetFile(const char * path,DEMOFSFileInfo * info)909 s32 DEMOGfxOpenAssetFile(const char* path, DEMOFSFileInfo* info)
910 {
911 char filename[MAX_ASSET_DIR_FULL_LEN];
912
913 strcpy(filename, gDemoAssetsDir);
914 strncat(filename, path, MAX_ASSET_DIR_FULL_LEN - MAX_ASSET_DIR_LEN);
915
916 return DEMOFSOpenFile(filename, info);
917 }
918
DEMOGfxGetAssetFileLength(const DEMOFSFileInfo * fileInfo,u32 * length)919 s32 DEMOGfxGetAssetFileLength(const DEMOFSFileInfo* fileInfo, u32* length)
920 {
921 return DEMOFSGetLength(fileInfo, length);
922 }
923
DEMOGfxReadAssetFile(DEMOFSFileInfo * fileInfo,void * addr,s32 length,s32 offset)924 s32 DEMOGfxReadAssetFile(DEMOFSFileInfo* fileInfo, void* addr, s32 length, s32 offset)
925 {
926 return DEMOFSRead(fileInfo, addr, length, offset);
927 }
928
DEMOGfxCloseAssetFile(DEMOFSFileInfo * fileInfo)929 s32 DEMOGfxCloseAssetFile(DEMOFSFileInfo* fileInfo)
930 {
931 return DEMOFSCloseFile(fileInfo);
932 }
933
DEMOGfxLoadAssetFile(const char * path,u32 * len)934 void* DEMOGfxLoadAssetFile(const char* path, u32* len)
935 {
936 char filename[MAX_ASSET_DIR_FULL_LEN];
937
938 strcpy(filename, gDemoAssetsDir);
939 strncat(filename, path, MAX_ASSET_DIR_FULL_LEN - MAX_ASSET_DIR_LEN);
940
941 return DEMOFSSimpleRead(filename, len);
942 }
943
DEMOGfxLoadAssetFileAlign(const char * path,u32 * len,u32 alignSize)944 void* DEMOGfxLoadAssetFileAlign(const char* path, u32* len, u32 alignSize)
945 {
946 char filename[MAX_ASSET_DIR_FULL_LEN];
947
948 strcpy(filename, gDemoAssetsDir);
949 strncat(filename, path, MAX_ASSET_DIR_FULL_LEN - MAX_ASSET_DIR_LEN);
950
951 return DEMOFSSimpleReadAlign(filename, len, alignSize);
952 }
953
DEMOGfxScanAssetDir(const char * path,u32 * pFileCount,u32 maxFiles,char ** ppFileNames)954 s32 DEMOGfxScanAssetDir(const char *path, u32 *pFileCount, u32 maxFiles, char** ppFileNames)
955 {
956 char filename[MAX_ASSET_DIR_FULL_LEN];
957
958 strcpy(filename, gDemoAssetsDir);
959 strncat(filename, path, MAX_ASSET_DIR_FULL_LEN - MAX_ASSET_DIR_LEN);
960
961 return DEMOFSScanDir(filename, path, pFileCount, maxFiles, ppFileNames);
962 }
963
DEMOGfxFileExists(const char * path)964 BOOL DEMOGfxFileExists(const char* path)
965 {
966 char filename[MAX_ASSET_DIR_FULL_LEN];
967
968 strcpy(filename, gDemoAssetsDir);
969 strncat(filename, path, MAX_ASSET_DIR_FULL_LEN - MAX_ASSET_DIR_LEN);
970
971 return DEMOFSFileExists(path);
972 }
973
DEMOGfxGetAttribFormatName(GX2AttribFormat format)974 const char *DEMOGfxGetAttribFormatName(GX2AttribFormat format)
975 {
976 switch(format) {
977 case GX2_ATTRIB_FORMAT_8_UNORM: return "GX2_ATTRIB_FORMAT_8_UNORM"; // 0x0000
978 case GX2_ATTRIB_FORMAT_8_UINT: return "GX2_ATTRIB_FORMAT_8_UINT"; // 0x0100
979 case GX2_ATTRIB_FORMAT_8_SNORM: return "GX2_ATTRIB_FORMAT_8_SNORM"; // 0x0200
980 case GX2_ATTRIB_FORMAT_8_SINT: return "GX2_ATTRIB_FORMAT_8_SINT"; // 0x0300
981 case GX2_ATTRIB_FORMAT_8_UINT_TO_FLOAT: return "GX2_ATTRIB_FORMAT_8_UINT_TO_FLOAT"; // 0x0800
982 case GX2_ATTRIB_FORMAT_8_SINT_TO_FLOAT: return "GX2_ATTRIB_FORMAT_8_SINT_TO_FLOAT"; // 0x0a00
983 case GX2_ATTRIB_FORMAT_4_4_UNORM: return "GX2_ATTRIB_FORMAT_4_4_UNORM"; // 0x0001
984 case GX2_ATTRIB_FORMAT_16_UNORM: return "GX2_ATTRIB_FORMAT_16_UNORM"; // 0x0002
985 case GX2_ATTRIB_FORMAT_16_UINT: return "GX2_ATTRIB_FORMAT_16_UINT"; // 0x0102
986 case GX2_ATTRIB_FORMAT_16_SNORM: return "GX2_ATTRIB_FORMAT_16_SNORM"; // 0x0202
987 case GX2_ATTRIB_FORMAT_16_SINT: return "GX2_ATTRIB_FORMAT_16_SINT"; // 0x0302
988 case GX2_ATTRIB_FORMAT_16_FLOAT: return "GX2_ATTRIB_FORMAT_16_FLOAT"; // 0x0803
989 case GX2_ATTRIB_FORMAT_16_UINT_TO_FLOAT: return "GX2_ATTRIB_FORMAT_16_UINT_TO_FLOAT"; // 0x0802
990 case GX2_ATTRIB_FORMAT_16_SINT_TO_FLOAT: return "GX2_ATTRIB_FORMAT_16_SINT_TO_FLOAT"; // 0x0a02
991 case GX2_ATTRIB_FORMAT_8_8_UNORM: return "GX2_ATTRIB_FORMAT_8_8_UNORM"; // 0x0004
992 case GX2_ATTRIB_FORMAT_8_8_UINT: return "GX2_ATTRIB_FORMAT_8_8_UINT"; // 0x0104
993 case GX2_ATTRIB_FORMAT_8_8_SNORM: return "GX2_ATTRIB_FORMAT_8_8_SNORM"; // 0x0204
994 case GX2_ATTRIB_FORMAT_8_8_SINT: return "GX2_ATTRIB_FORMAT_8_8_SINT"; // 0x0304
995 case GX2_ATTRIB_FORMAT_8_8_UINT_TO_FLOAT: return "GX2_ATTRIB_FORMAT_8_8_UINT_TO_FLOAT"; // 0x0804
996 case GX2_ATTRIB_FORMAT_8_8_SINT_TO_FLOAT: return "GX2_ATTRIB_FORMAT_8_8_SINT_TO_FLOAT"; // 0x0a04
997 case GX2_ATTRIB_FORMAT_32_UINT: return "GX2_ATTRIB_FORMAT_32_UINT"; // 0x0105
998 case GX2_ATTRIB_FORMAT_32_SINT: return "GX2_ATTRIB_FORMAT_32_SINT"; // 0x0305
999 case GX2_ATTRIB_FORMAT_32_FLOAT: return "GX2_ATTRIB_FORMAT_32_FLOAT"; // 0x0806
1000 case GX2_ATTRIB_FORMAT_16_16_UNORM: return "GX2_ATTRIB_FORMAT_16_16_UNORM"; // 0x0007
1001 case GX2_ATTRIB_FORMAT_16_16_UINT: return "GX2_ATTRIB_FORMAT_16_16_UINT"; // 0x0107
1002 case GX2_ATTRIB_FORMAT_16_16_SNORM: return "GX2_ATTRIB_FORMAT_16_16_SNORM"; // 0x0207
1003 case GX2_ATTRIB_FORMAT_16_16_SINT: return "GX2_ATTRIB_FORMAT_16_16_SINT"; // 0x0307
1004 case GX2_ATTRIB_FORMAT_16_16_FLOAT: return "GX2_ATTRIB_FORMAT_16_16_FLOAT"; // 0x0808
1005 case GX2_ATTRIB_FORMAT_16_16_UINT_TO_FLOAT: return "GX2_ATTRIB_FORMAT_16_16_UINT_TO_FLOAT"; // 0x0807
1006 case GX2_ATTRIB_FORMAT_16_16_SINT_TO_FLOAT: return "GX2_ATTRIB_FORMAT_16_16_SINT_TO_FLOAT"; // 0x0a07
1007 case GX2_ATTRIB_FORMAT_10_11_11_FLOAT: return "GX2_ATTRIB_FORMAT_10_11_11_FLOAT"; // 0x0809
1008 case GX2_ATTRIB_FORMAT_8_8_8_8_UNORM: return "GX2_ATTRIB_FORMAT_8_8_8_8_UNORM"; // 0x000a
1009 case GX2_ATTRIB_FORMAT_8_8_8_8_UINT: return "GX2_ATTRIB_FORMAT_8_8_8_8_UINT"; // 0x010a
1010 case GX2_ATTRIB_FORMAT_8_8_8_8_SNORM: return "GX2_ATTRIB_FORMAT_8_8_8_8_SNORM"; // 0x020a
1011 case GX2_ATTRIB_FORMAT_8_8_8_8_SINT: return "GX2_ATTRIB_FORMAT_8_8_8_8_SINT"; // 0x030a
1012 case GX2_ATTRIB_FORMAT_8_8_8_8_UINT_TO_FLOAT: return "GX2_ATTRIB_FORMAT_8_8_8_8_UINT_TO_FLOAT"; // 0x080a
1013 case GX2_ATTRIB_FORMAT_8_8_8_8_SINT_TO_FLOAT: return "GX2_ATTRIB_FORMAT_8_8_8_8_SINT_TO_FLOAT"; // 0x0a0a
1014 case GX2_ATTRIB_FORMAT_10_10_10_2_UNORM: return "GX2_ATTRIB_FORMAT_10_10_10_2_UNORM"; // 0x000b
1015 case GX2_ATTRIB_FORMAT_10_10_10_2_UINT: return "GX2_ATTRIB_FORMAT_10_10_10_2_UINT"; // 0x010b
1016 case GX2_ATTRIB_FORMAT_10_10_10_2_SNORM: return "GX2_ATTRIB_FORMAT_10_10_10_2_SNORM"; // 0x020b
1017 case GX2_ATTRIB_FORMAT_10_10_10_2_SINT: return "GX2_ATTRIB_FORMAT_10_10_10_2_SINT"; // 0x030b
1018 case GX2_ATTRIB_FORMAT_32_32_UINT: return "GX2_ATTRIB_FORMAT_32_32_UINT"; // 0x010c
1019 case GX2_ATTRIB_FORMAT_32_32_SINT: return "GX2_ATTRIB_FORMAT_32_32_SINT"; // 0x030c
1020 case GX2_ATTRIB_FORMAT_32_32_FLOAT: return "GX2_ATTRIB_FORMAT_32_32_FLOAT"; // 0x080d
1021 case GX2_ATTRIB_FORMAT_16_16_16_16_UNORM: return "GX2_ATTRIB_FORMAT_16_16_16_16_UNORM"; // 0x000e
1022 case GX2_ATTRIB_FORMAT_16_16_16_16_UINT: return "GX2_ATTRIB_FORMAT_16_16_16_16_UINT"; // 0x010e
1023 case GX2_ATTRIB_FORMAT_16_16_16_16_SNORM: return "GX2_ATTRIB_FORMAT_16_16_16_16_SNORM"; // 0x020e
1024 case GX2_ATTRIB_FORMAT_16_16_16_16_SINT: return "GX2_ATTRIB_FORMAT_16_16_16_16_SINT"; // 0x030e
1025 case GX2_ATTRIB_FORMAT_16_16_16_16_FLOAT: return "GX2_ATTRIB_FORMAT_16_16_16_16_FLOAT"; // 0x080f
1026 case GX2_ATTRIB_FORMAT_16_16_16_16_UINT_TO_FLOAT: return "GX2_ATTRIB_FORMAT_16_16_16_16_UINT_TO_FLOAT"; // 0x080e
1027 case GX2_ATTRIB_FORMAT_16_16_16_16_SINT_TO_FLOAT: return "GX2_ATTRIB_FORMAT_16_16_16_16_SINT_TO_FLOAT"; // 0x0a0e
1028 case GX2_ATTRIB_FORMAT_32_32_32_UINT: return "GX2_ATTRIB_FORMAT_32_32_32_UINT"; // 0x0110
1029 case GX2_ATTRIB_FORMAT_32_32_32_SINT: return "GX2_ATTRIB_FORMAT_32_32_32_SINT"; // 0x0310
1030 case GX2_ATTRIB_FORMAT_32_32_32_FLOAT: return "GX2_ATTRIB_FORMAT_32_32_32_FLOAT"; // 0x0811
1031 case GX2_ATTRIB_FORMAT_32_32_32_32_UINT: return "GX2_ATTRIB_FORMAT_32_32_32_32_UINT"; // 0x0112
1032 case GX2_ATTRIB_FORMAT_32_32_32_32_SINT: return "GX2_ATTRIB_FORMAT_32_32_32_32_SINT"; // 0x0312
1033 case GX2_ATTRIB_FORMAT_32_32_32_32_FLOAT: return "GX2_ATTRIB_FORMAT_32_32_32_32_FLOAT"; // 0x0813
1034 default: return "invalid format";
1035 }
1036 }
1037
DEMOGfxGetSurfaceFormatName(GX2SurfaceFormat format)1038 const char *DEMOGfxGetSurfaceFormatName(GX2SurfaceFormat format)
1039 {
1040 switch(format) {
1041 case GX2_SURFACE_FORMAT_INVALID: return "GX2_SURFACE_FORMAT_INVALID"; // 0x0000
1042 case GX2_SURFACE_FORMAT_TC_R8_UNORM: return "GX2_SURFACE_FORMAT_TC_R8_UNORM"; // 0x0001
1043 case GX2_SURFACE_FORMAT_TC_R8_UINT: return "GX2_SURFACE_FORMAT_TC_R8_UINT"; // 0x0101
1044 case GX2_SURFACE_FORMAT_TC_R8_SNORM: return "GX2_SURFACE_FORMAT_TC_R8_SNORM"; // 0x0201
1045 case GX2_SURFACE_FORMAT_TC_R8_SINT: return "GX2_SURFACE_FORMAT_TC_R8_SINT"; // 0x0301
1046 case GX2_SURFACE_FORMAT_T_R4_G4_UNORM: return "GX2_SURFACE_FORMAT_T_R4_G4_UNORM"; // 0x0002
1047 case GX2_SURFACE_FORMAT_TCD_R16_UNORM: return "GX2_SURFACE_FORMAT_TCD_R16_UNORM"; // 0x0005
1048 case GX2_SURFACE_FORMAT_TC_R16_UINT: return "GX2_SURFACE_FORMAT_TC_R16_UINT"; // 0x0105
1049 case GX2_SURFACE_FORMAT_TC_R16_SNORM: return "GX2_SURFACE_FORMAT_TC_R16_SNORM"; // 0x0205
1050 case GX2_SURFACE_FORMAT_TC_R16_SINT: return "GX2_SURFACE_FORMAT_TC_R16_SINT"; // 0x0305
1051 case GX2_SURFACE_FORMAT_TC_R16_FLOAT: return "GX2_SURFACE_FORMAT_TC_R16_FLOAT"; // 0x0806
1052 case GX2_SURFACE_FORMAT_TC_R8_G8_UNORM: return "GX2_SURFACE_FORMAT_TC_R8_G8_UNORM"; // 0x0007
1053 case GX2_SURFACE_FORMAT_TC_R8_G8_UINT: return "GX2_SURFACE_FORMAT_TC_R8_G8_UINT"; // 0x0107
1054 case GX2_SURFACE_FORMAT_TC_R8_G8_SNORM: return "GX2_SURFACE_FORMAT_TC_R8_G8_SNORM"; // 0x0207
1055 case GX2_SURFACE_FORMAT_TC_R8_G8_SINT: return "GX2_SURFACE_FORMAT_TC_R8_G8_SINT"; // 0x0307
1056 case GX2_SURFACE_FORMAT_TCS_R5_G6_B5_UNORM: return "GX2_SURFACE_FORMAT_TCS_R5_G6_B5_UNORM"; // 0x0008
1057 case GX2_SURFACE_FORMAT_TC_R5_G5_B5_A1_UNORM: return "GX2_SURFACE_FORMAT_TC_R5_G5_B5_A1_UNORM"; // 0x000a
1058 case GX2_SURFACE_FORMAT_TC_R4_G4_B4_A4_UNORM: return "GX2_SURFACE_FORMAT_TC_R4_G4_B4_A4_UNORM"; // 0x000b
1059 case GX2_SURFACE_FORMAT_TC_A1_B5_G5_R5_UNORM: return "GX2_SURFACE_FORMAT_TC_A1_B5_G5_R5_UNORM"; // 0x000c
1060 case GX2_SURFACE_FORMAT_TC_R32_UINT: return "GX2_SURFACE_FORMAT_TC_R32_UINT"; // 0x010d
1061 case GX2_SURFACE_FORMAT_TC_R32_SINT: return "GX2_SURFACE_FORMAT_TC_R32_SINT"; // 0x030d
1062 case GX2_SURFACE_FORMAT_TCD_R32_FLOAT: return "GX2_SURFACE_FORMAT_TCD_R32_FLOAT"; // 0x080e
1063 case GX2_SURFACE_FORMAT_TC_R16_G16_UNORM: return "GX2_SURFACE_FORMAT_TC_R16_G16_UNORM"; // 0x000f
1064 case GX2_SURFACE_FORMAT_TC_R16_G16_UINT: return "GX2_SURFACE_FORMAT_TC_R16_G16_UINT"; // 0x010f
1065 case GX2_SURFACE_FORMAT_TC_R16_G16_SNORM: return "GX2_SURFACE_FORMAT_TC_R16_G16_SNORM"; // 0x020f
1066 case GX2_SURFACE_FORMAT_TC_R16_G16_SINT: return "GX2_SURFACE_FORMAT_TC_R16_G16_SINT"; // 0x030f
1067 case GX2_SURFACE_FORMAT_TC_R16_G16_FLOAT: return "GX2_SURFACE_FORMAT_TC_R16_G16_FLOAT"; // 0x0810
1068 case GX2_SURFACE_FORMAT_D_D24_S8_UNORM: return "GX2_SURFACE_FORMAT_D_D24_S8_UNORM"; // 0x0011
1069 // case GX2_SURFACE_FORMAT_T_R24_UNORM_X8: return "GX2_SURFACE_FORMAT_T_R24_UNORM_X8"; // 0x0011
1070 case GX2_SURFACE_FORMAT_T_X24_G8_UINT: return "GX2_SURFACE_FORMAT_T_X24_G8_UINT"; // 0x0111
1071 case GX2_SURFACE_FORMAT_D_D24_S8_FLOAT: return "GX2_SURFACE_FORMAT_D_D24_S8_FLOAT"; // 0x0811
1072 case GX2_SURFACE_FORMAT_TC_R11_G11_B10_FLOAT: return "GX2_SURFACE_FORMAT_TC_R11_G11_B10_FLOAT"; // 0x0816
1073 case GX2_SURFACE_FORMAT_TCS_R10_G10_B10_A2_UNORM: return "GX2_SURFACE_FORMAT_TCS_R10_G10_B10_A2_UNORM"; // 0x0019
1074 case GX2_SURFACE_FORMAT_TC_R10_G10_B10_A2_UINT: return "GX2_SURFACE_FORMAT_TC_R10_G10_B10_A2_UINT"; // 0x0119
1075 case GX2_SURFACE_FORMAT_TC_R10_G10_B10_A2_SNORM: return "GX2_SURFACE_FORMAT_TC_R10_G10_B10_A2_SNORM"; // 0x0219
1076 case GX2_SURFACE_FORMAT_TC_R10_G10_B10_A2_SINT: return "GX2_SURFACE_FORMAT_TC_R10_G10_B10_A2_SINT"; // 0x0319
1077 case GX2_SURFACE_FORMAT_TCS_R8_G8_B8_A8_UNORM: return "GX2_SURFACE_FORMAT_TCS_R8_G8_B8_A8_UNORM"; // 0x001a
1078 case GX2_SURFACE_FORMAT_TC_R8_G8_B8_A8_UINT: return "GX2_SURFACE_FORMAT_TC_R8_G8_B8_A8_UINT"; // 0x011a
1079 case GX2_SURFACE_FORMAT_TC_R8_G8_B8_A8_SNORM: return "GX2_SURFACE_FORMAT_TC_R8_G8_B8_A8_SNORM"; // 0x021a
1080 case GX2_SURFACE_FORMAT_TC_R8_G8_B8_A8_SINT: return "GX2_SURFACE_FORMAT_TC_R8_G8_B8_A8_SINT"; // 0x031a
1081 case GX2_SURFACE_FORMAT_TCS_R8_G8_B8_A8_SRGB: return "GX2_SURFACE_FORMAT_TCS_R8_G8_B8_A8_SRGB"; // 0x041a
1082 case GX2_SURFACE_FORMAT_TCS_A2_B10_G10_R10_UNORM: return "GX2_SURFACE_FORMAT_TCS_A2_B10_G10_R10_UNORM"; // 0x001b
1083 case GX2_SURFACE_FORMAT_TC_A2_B10_G10_R10_UINT: return "GX2_SURFACE_FORMAT_TC_A2_B10_G10_R10_UINT"; // 0x011b
1084 case GX2_SURFACE_FORMAT_D_D32_FLOAT_S8_UINT_X24: return "GX2_SURFACE_FORMAT_D_D32_FLOAT_S8_UINT_X24"; // 0x081c
1085 // case GX2_SURFACE_FORMAT_T_R32_FLOAT_X8_X24: return "GX2_SURFACE_FORMAT_T_R32_FLOAT_X8_X24"; // 0x081c
1086 case GX2_SURFACE_FORMAT_T_X32_G8_UINT_X24: return "GX2_SURFACE_FORMAT_T_X32_G8_UINT_X24"; // 0x011c
1087 case GX2_SURFACE_FORMAT_TC_R32_G32_UINT: return "GX2_SURFACE_FORMAT_TC_R32_G32_UINT"; // 0x011d
1088 case GX2_SURFACE_FORMAT_TC_R32_G32_SINT: return "GX2_SURFACE_FORMAT_TC_R32_G32_SINT"; // 0x031d
1089 case GX2_SURFACE_FORMAT_TC_R32_G32_FLOAT: return "GX2_SURFACE_FORMAT_TC_R32_G32_FLOAT"; // 0x081e
1090 case GX2_SURFACE_FORMAT_TC_R16_G16_B16_A16_UNORM: return "GX2_SURFACE_FORMAT_TC_R16_G16_B16_A16_UNORM"; // 0x001f
1091 case GX2_SURFACE_FORMAT_TC_R16_G16_B16_A16_UINT: return "GX2_SURFACE_FORMAT_TC_R16_G16_B16_A16_UINT"; // 0x011f
1092 case GX2_SURFACE_FORMAT_TC_R16_G16_B16_A16_SNORM: return "GX2_SURFACE_FORMAT_TC_R16_G16_B16_A16_SNORM"; // 0x021f
1093 case GX2_SURFACE_FORMAT_TC_R16_G16_B16_A16_SINT: return "GX2_SURFACE_FORMAT_TC_R16_G16_B16_A16_SINT"; // 0x031f
1094 case GX2_SURFACE_FORMAT_TC_R16_G16_B16_A16_FLOAT: return "GX2_SURFACE_FORMAT_TC_R16_G16_B16_A16_FLOAT"; // 0x0820
1095 case GX2_SURFACE_FORMAT_TC_R32_G32_B32_A32_UINT: return "GX2_SURFACE_FORMAT_TC_R32_G32_B32_A32_UINT"; // 0x0122
1096 case GX2_SURFACE_FORMAT_TC_R32_G32_B32_A32_SINT: return "GX2_SURFACE_FORMAT_TC_R32_G32_B32_A32_SINT"; // 0x0322
1097 case GX2_SURFACE_FORMAT_TC_R32_G32_B32_A32_FLOAT: return "GX2_SURFACE_FORMAT_TC_R32_G32_B32_A32_FLOAT"; // 0x0823
1098 case GX2_SURFACE_FORMAT_T_BC1_UNORM: return "GX2_SURFACE_FORMAT_T_BC1_UNORM"; // 0x0031
1099 case GX2_SURFACE_FORMAT_T_BC1_SRGB: return "GX2_SURFACE_FORMAT_T_BC1_SRGB"; // 0x0431
1100 case GX2_SURFACE_FORMAT_T_BC2_UNORM: return "GX2_SURFACE_FORMAT_T_BC2_UNORM"; // 0x0032
1101 case GX2_SURFACE_FORMAT_T_BC2_SRGB: return "GX2_SURFACE_FORMAT_T_BC2_SRGB"; // 0x0432
1102 case GX2_SURFACE_FORMAT_T_BC3_UNORM: return "GX2_SURFACE_FORMAT_T_BC3_UNORM"; // 0x0033
1103 case GX2_SURFACE_FORMAT_T_BC3_SRGB: return "GX2_SURFACE_FORMAT_T_BC3_SRGB"; // 0x0433
1104 case GX2_SURFACE_FORMAT_T_BC4_UNORM: return "GX2_SURFACE_FORMAT_T_BC4_UNORM"; // 0x0034
1105 case GX2_SURFACE_FORMAT_T_BC4_SNORM: return "GX2_SURFACE_FORMAT_T_BC4_SNORM"; // 0x0234
1106 case GX2_SURFACE_FORMAT_T_BC5_UNORM: return "GX2_SURFACE_FORMAT_T_BC5_UNORM"; // 0x0035
1107 case GX2_SURFACE_FORMAT_T_BC5_SNORM: return "GX2_SURFACE_FORMAT_T_BC5_SNORM"; // 0x0235
1108 case GX2_SURFACE_FORMAT_T_NV12_UNORM: return "GX2_SURFACE_FORMAT_T_NV12_UNORM"; // 0x0081
1109 default: return "invalid format";
1110 }
1111 }
1112
DEMOGfxBeginGPUTask()1113 DEMOGfxGPUTask* DEMOGfxBeginGPUTask()
1114 {
1115 // Create a new time value, meaning a new key in the list
1116 u64 timeVal = gDemoGfxTimeVal;
1117
1118 DEMOGfxGPUTask *pTask = (DEMOGfxGPUTask *)DEMOAlloc(sizeof(DEMOGfxGPUTask));
1119 ASSERT(pTask && "Failed to allocate pTask!");
1120
1121 pTask->pDLPatchLoc = GX2BeginGPUTask();
1122 pTask->timeVal = timeVal;
1123 pTask->next = pgDemoGfxGPUTaskList;
1124 pgDemoGfxGPUTaskList = pTask;
1125
1126 GX2SubmitUserTimeStamp(gpDemoGfxGPUTs, timeVal, GX2_PIPE_EVENT_TOP, GX2_FALSE);
1127
1128 return pTask;
1129 }
1130
DEMOGfxEndGPUTask()1131 void DEMOGfxEndGPUTask()
1132 {
1133 u64 timeVal = gDemoGfxTimeVal | DEMO_GPU_TASK_END_TS;
1134 GX2SubmitUserTimeStamp(gpDemoGfxGPUTs, timeVal, GX2_PIPE_EVENT_TOP, GX2_FALSE);
1135 GX2EndGPUTask(&gDemoGfxGPUFence);
1136
1137 // Move to next timeval
1138 gDemoGfxTimeVal++;
1139 }
1140
DEMOGfxInsertGPUTask(void * pDisplayList,u32 byteSize)1141 void DEMOGfxInsertGPUTask(void *pDisplayList, u32 byteSize)
1142 {
1143 DEMOGfxGPUTask *pTask;
1144 u64 timeVal;
1145
1146 // Set the fence
1147 gDemoGfxGPUFence = 0;
1148 GX2Invalidate(GX2_INVALIDATE_CPU, &gDemoGfxGPUFence, sizeof(u32));
1149
1150 timeVal = GX2ReadUserTimeStamp(gpDemoGfxGPUTs);
1151
1152 // If it is a begin Ts
1153 if ((timeVal & DEMO_GPU_TASK_END_TS) == 0)
1154 {
1155 // Look for the patch entry for the next job
1156 timeVal++;
1157 }
1158 else
1159 {
1160 // Try looking up the patch entry after the next one
1161 timeVal = (timeVal & (~DEMO_GPU_TASK_END_TS)) + 2ull;
1162 }
1163
1164 for (pTask = pgDemoGfxGPUTaskList; pTask != NULL; pTask = pTask->next)
1165 {
1166 if (pTask->timeVal == timeVal)
1167 break;
1168 }
1169 if (pTask)
1170 {
1171 // Read pTask->pDLPatchLoc, pass it to GX2SubmitUserGpuTask
1172 GX2InsertGPUTask((u32*)pTask->pDLPatchLoc, (u32*)pDisplayList, byteSize);
1173 }
1174 else
1175 {
1176 // the gpu is already idle, just call the new task directly
1177 GX2DirectCallDisplayList(pDisplayList, byteSize);
1178 }
1179
1180 // Release the fence
1181 gDemoGfxGPUFence = 1;
1182 GX2Invalidate(GX2_INVALIDATE_CPU, &gDemoGfxGPUFence, sizeof(u32));
1183 }
1184
DEMOGfxFreeGPUTask(DEMOGfxGPUTask * pTask)1185 void DEMOGfxFreeGPUTask(DEMOGfxGPUTask *pTask)
1186 {
1187 DEMOGfxGPUTask *pList;
1188
1189 ASSERT(pgDemoGfxGPUTaskList && "Can't free a GPU Task from an empty list!");
1190 for (pList = pgDemoGfxGPUTaskList; pList != NULL; pList = pList->next)
1191 {
1192 if (pList == pTask)
1193 {
1194 pList = pTask->next;
1195 break;
1196 }
1197 }
1198 DEMOFree(pTask);
1199 }
1200
DEMOGfxFreeGPUTasks(void)1201 void DEMOGfxFreeGPUTasks(void)
1202 {
1203 DEMOGfxGPUTask *pList, *pNext;
1204
1205 ASSERT(pgDemoGfxGPUTaskList && "Can't free GPU Tasks from an empty list!");
1206 for (pList = pgDemoGfxGPUTaskList; pList != NULL; pList = pNext)
1207 {
1208 pNext = pList->next;
1209 DEMOFree(pList);
1210 }
1211 }
1212