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 // gfdInterface.c
14 // ----------------------------------------------------------------
15 
16 #include <string.h>
17 #include <stdlib.h>
18 #include <types.h>
19 #include <cafe/os.h>
20 #include <cafe/gx2.h>
21 #include <cafe/gfd.h>
22 
23 #ifdef __cplusplus
24 extern "C"
25 {
26 #endif // __cplusplus
27 
28 #define GFDPRINT(...)
29 //#define GFDPRINT(...)             OSReport(__VA_ARGS__)
30 
31 #define _GFD_SWAP_BYTES(x) ( (((x) >> 24) & 0xff) | (((x) >> 8) & 0xff00) | (((x) << 8) & 0xff0000) | (((x) << 24) & 0xff000000) )
32 
33 // ----------------------
34 //
35 // Proto Types
36 //
37 // ----------------------
38 BOOL _GFDGetHeaderVersions(u32 *pVerMajor, u32 *pVerMinor, u32 *pVerGPU, const void *pData);
39 BOOL _GFDCheckHeaderVersions(const void *pData);
40 BOOL _GFDCheckBlockHeaderMagicVersions(const GFDBlockHeader *pBlockHeader);
41 u32  _GFDGetBlockCount(GFDBlockType blockType, const void *pData);
42 u32  _GFDGetBlockDataSize(GFDBlockType blockType, u32 index, const void *pData);
43 BOOL _GFDRelocateBlock(u32 nBytesBlock, char *pData);
44 BOOL _GFDRelocateBlockEx(GFDBlockRelocationHeader *pTrailer, u32 fromOffset, u32 toOffset, char *pData);
45 
46 // ----------------------
47 //
48 // Public Functions
49 //
50 // ----------------------
51 
52 //
53 // For shader file (gsh)
54 //
55 
GFDGetVertexShaderCount(const void * pData)56 u32 GFDGetVertexShaderCount(const void *pData)
57 {
58     return _GFDGetBlockCount(GFD_BLOCK_TYPE_GX2_VSH_HEADER, pData);
59 }
60 
GFDGetPixelShaderCount(const void * pData)61 u32 GFDGetPixelShaderCount(const void *pData)
62 {
63     return _GFDGetBlockCount(GFD_BLOCK_TYPE_GX2_PSH_HEADER, pData);
64 }
65 
GFDGetGeometryShaderCount(const void * pData)66 u32 GFDGetGeometryShaderCount(const void *pData)
67 {
68     return _GFDGetBlockCount(GFD_BLOCK_TYPE_GX2_GSH_HEADER, pData);
69 }
70 
GFDGetComputeShaderCount(const void * pData)71 u32 GFDGetComputeShaderCount(const void *pData)
72 {
73     return _GFDGetBlockCount(GFD_BLOCK_TYPE_GX2_CSH_HEADER, pData);
74 }
75 
GFDGetVertexShaderHeaderSize(u32 index,const void * pData)76 u32 GFDGetVertexShaderHeaderSize(u32 index, const void *pData)
77 {
78     return _GFDGetBlockDataSize(GFD_BLOCK_TYPE_GX2_VSH_HEADER, index, pData);
79 }
80 
GFDGetPixelShaderHeaderSize(u32 index,const void * pData)81 u32 GFDGetPixelShaderHeaderSize(u32 index, const void *pData)
82 {
83     return _GFDGetBlockDataSize(GFD_BLOCK_TYPE_GX2_PSH_HEADER, index, pData);
84 }
85 
GFDGetGeometryShaderHeaderSize(u32 index,const void * pData)86 u32 GFDGetGeometryShaderHeaderSize(u32 index, const void *pData)
87 {
88     return _GFDGetBlockDataSize(GFD_BLOCK_TYPE_GX2_GSH_HEADER, index, pData);
89 }
90 
GFDGetComputeShaderHeaderSize(u32 index,const void * pData)91 u32 GFDGetComputeShaderHeaderSize(u32 index, const void *pData)
92 {
93     return _GFDGetBlockDataSize(GFD_BLOCK_TYPE_GX2_CSH_HEADER, index, pData);
94 }
95 
GFDGetVertexShaderProgramSize(u32 index,const void * pData)96 u32 GFDGetVertexShaderProgramSize(u32 index, const void *pData)
97 {
98     return _GFDGetBlockDataSize(GFD_BLOCK_TYPE_GX2_VSH_PROGRAM, index, pData);
99 }
100 
GFDGetPixelShaderProgramSize(u32 index,const void * pData)101 u32 GFDGetPixelShaderProgramSize(u32 index, const void *pData)
102 {
103     return _GFDGetBlockDataSize(GFD_BLOCK_TYPE_GX2_PSH_PROGRAM, index, pData);
104 }
105 
GFDGetGeometryShaderProgramSize(u32 index,const void * pData)106 u32 GFDGetGeometryShaderProgramSize(u32 index, const void *pData)
107 {
108     return _GFDGetBlockDataSize(GFD_BLOCK_TYPE_GX2_GSH_PROGRAM, index, pData);
109 }
110 
GFDGetGeometryShaderCopyProgramSize(u32 index,const void * pData)111 u32 GFDGetGeometryShaderCopyProgramSize(u32 index, const void *pData)
112 {
113     return _GFDGetBlockDataSize(GFD_BLOCK_TYPE_GX2_GSH_COPY_PROGRAM, index, pData);
114 }
115 
GFDGetComputeShaderProgramSize(u32 index,const void * pData)116 u32 GFDGetComputeShaderProgramSize(u32 index, const void *pData)
117 {
118     return _GFDGetBlockDataSize(GFD_BLOCK_TYPE_GX2_CSH_PROGRAM, index, pData);
119 }
120 
GFDGetVertexShader(GX2VertexShader * pHeader,void * pProgram,u32 index,const void * pData)121 BOOL GFDGetVertexShader(GX2VertexShader *pHeader, void *pProgram, u32 index, const void *pData)
122 {
123     BOOL ret;
124     char *pDataStruct;
125     GFDBlockHeader *pBlockHeader;
126     u32 nHeaders  = 0;
127     u32 nPrograms = 0;
128 
129     if(pHeader == NULL || pProgram == NULL || pData == NULL)
130         return FALSE;
131 
132     if(!_GFDCheckHeaderVersions(pData))
133         return FALSE;
134 
135     if( 0 != (((u32) pProgram) & (GX2_SHADER_ALIGNMENT-1)))
136     {
137         OSReport("Warning: Shader program buffer not aligned correctly. It needs %d byte align buffer.\n", GX2_SHADER_ALIGNMENT);
138         return FALSE;
139     }
140 
141     pDataStruct = (char*)pData + ((GFDHeader*)pData)->size; // jump over the header
142     pBlockHeader = (GFDBlockHeader *)pDataStruct;
143 
144     while((ret = _GFDCheckBlockHeaderMagicVersions(pBlockHeader)))
145     {
146         pBlockHeader = (GFDBlockHeader *)pDataStruct;
147         pDataStruct += pBlockHeader->size;
148 
149         switch(pBlockHeader->type)
150         {
151         case GFD_BLOCK_TYPE_GX2_VSH_HEADER:
152             if(index == nHeaders)
153             {
154                 memcpy(pHeader, (void *)pDataStruct, pBlockHeader->dataSize);
155 
156                 if (!_GFDRelocateBlock(pBlockHeader->dataSize,(char *)pHeader))
157                 {
158                     ASSERT(!"Internal offset/pointers corrupted.");
159                     return FALSE;
160                 }
161                 GFDPRINT("GFD:VSH_HEADER: %x -> %x size: %d\n", pDataStruct, pHeader, pBlockHeader->dataSize);
162             }
163             nHeaders++;
164             break;
165         case GFD_BLOCK_TYPE_GX2_VSH_PROGRAM:
166             if(index == nPrograms)
167             {
168                 // Set shader program
169                 pHeader->shaderPtr = pProgram;
170                 memcpy(pHeader->shaderPtr, (char *)pDataStruct, pBlockHeader->dataSize);
171                 // This is done one layer up (in demoGfd)
172                 // GX2Invalidate(GX2_INVALIDATE_CPU_SHADER, pDataStruct, pBlockHeader->dataSize);
173                 GFDPRINT("GFD:VSH_PROGRAM: %x -> %x size: %d\n", pDataStruct, pHeader->shaderPtr, pBlockHeader->dataSize);
174             }
175             nPrograms++;
176             break;
177         default:
178             break;
179         }
180         pDataStruct += pBlockHeader->dataSize;
181 
182         // Terminate once the full structure has been found
183         if ( nHeaders > index && nPrograms > index )
184             break;
185 
186         if(GFD_BLOCK_TYPE_END == pBlockHeader->type)
187             // terminate read, we have an end block
188             break;
189     }
190 
191     return (ret && nHeaders >= index && nPrograms >= index);
192 }
193 
GFDGetPixelShader(GX2PixelShader * pHeader,void * pProgram,u32 index,const void * pData)194 BOOL GFDGetPixelShader(GX2PixelShader *pHeader, void *pProgram, u32 index, const void *pData)
195 {
196     BOOL ret;
197     char *pDataStruct;
198     GFDBlockHeader *pBlockHeader;
199     u32 nHeaders  = 0;
200     u32 nPrograms = 0;
201 
202     if(pHeader == NULL || pProgram == NULL || pData == NULL)
203         return FALSE;
204 
205     if(!_GFDCheckHeaderVersions(pData))
206         return FALSE;
207 
208     if( 0 != (((u32) pProgram) & (GX2_SHADER_ALIGNMENT-1)))
209     {
210         OSReport("Warning: Shader program buffer not aligned correctly. It needs %d byte align buffer.\n", GX2_SHADER_ALIGNMENT);
211         return FALSE;
212     }
213 
214     pDataStruct = (char*) pData + ((GFDHeader*)pData)->size; // jump over the header
215     pBlockHeader = (GFDBlockHeader *)pDataStruct;
216 
217     while((ret = _GFDCheckBlockHeaderMagicVersions(pBlockHeader)))
218     {
219         pBlockHeader = (GFDBlockHeader *)pDataStruct;
220         pDataStruct += pBlockHeader->size;
221 
222         switch(pBlockHeader->type)
223         {
224         case GFD_BLOCK_TYPE_GX2_PSH_HEADER:
225             if(index == nHeaders)
226             {
227                 memcpy(pHeader, (void *)pDataStruct, pBlockHeader->dataSize);
228 
229                 if (!_GFDRelocateBlock(pBlockHeader->dataSize,(char *)pHeader))
230                 {
231                     ASSERT(!"Internal offset/pointers corrupted.");
232                     return FALSE;
233                 }
234                 GFDPRINT("GFD:PSH_HEADER: %x -> %x size: %d\n", pDataStruct, pHeader->shaderPtr, pBlockHeader->dataSize);
235             }
236             nHeaders++;
237             break;
238         case GFD_BLOCK_TYPE_GX2_PSH_PROGRAM:
239             if(index == nPrograms)
240             {
241                 // Set shader program
242                 pHeader->shaderPtr = pProgram;
243                 memcpy(pHeader->shaderPtr, (char *)pDataStruct, pBlockHeader->dataSize);
244                 // This is done one layer up (in demoGfd)
245                 // GX2Invalidate(GX2_INVALIDATE_CPU_SHADER, pDataStruct, pBlockHeader->dataSize);
246                 GFDPRINT("GFD:PSH_PROGRAM: %x -> %x size: %d\n", pDataStruct, pHeader->shaderPtr, pBlockHeader->dataSize);
247             }
248             nPrograms++;
249             break;
250         default:
251             break;
252         }
253         pDataStruct += pBlockHeader->dataSize;
254 
255         // Terminate once the full structure has been found
256         if ( nHeaders > index && nPrograms > index )
257             break;
258 
259         if(GFD_BLOCK_TYPE_END == pBlockHeader->type)
260             // terminate read, we have an end block
261             break;
262     }
263 
264     return (ret && nHeaders >= index && nPrograms >= index);
265 }
266 
GFDGetGeometryShader(GX2GeometryShader * pHeader,void * pProgram,void * pCopyProgram,u32 index,const void * pData)267 BOOL GFDGetGeometryShader(GX2GeometryShader *pHeader, void *pProgram, void *pCopyProgram, u32 index, const void *pData)
268 {
269     BOOL ret;
270     char *pDataStruct;
271     GFDBlockHeader *pBlockHeader;
272     u32 nHeaders  = 0;
273     u32 nPrograms = 0;
274     u32 nCopyPrograms = 0;
275 
276     if(pHeader == NULL || pProgram == NULL || pData == NULL)
277         return FALSE;
278 
279     if(!_GFDCheckHeaderVersions(pData))
280         return FALSE;
281 
282     if( 0 != (((u32) pProgram) & (GX2_SHADER_ALIGNMENT-1)))
283     {
284         OSReport("Warning: Shader program buffer not aligned correctly. It needs %d byte align buffer.\n", GX2_SHADER_ALIGNMENT);
285         return FALSE;
286     }
287 
288     pDataStruct = (char*) pData + ((GFDHeader*)pData)->size; // jump over the header
289     pBlockHeader = (GFDBlockHeader *)pDataStruct;
290 
291     while((ret = _GFDCheckBlockHeaderMagicVersions(pBlockHeader)))
292     {
293         pBlockHeader = (GFDBlockHeader *)pDataStruct;
294         pDataStruct += pBlockHeader->size;
295 
296         switch(pBlockHeader->type)
297         {
298         case GFD_BLOCK_TYPE_GX2_GSH_HEADER:
299             if(index == nHeaders)
300             {
301                 memcpy(pHeader, (void *)pDataStruct, pBlockHeader->dataSize);
302 
303                 if (!_GFDRelocateBlock(pBlockHeader->dataSize,(char *)pHeader))
304                 {
305                     ASSERT(!"Internal offset/pointers corrupted.");
306                     return FALSE;
307                 }
308                 GFDPRINT("GFD:GSH_HEADER: %x -> %x size: %d\n", pDataStruct, pHeader->shaderPtr, pBlockHeader->dataSize);
309             }
310             nHeaders++;
311             break;
312         case GFD_BLOCK_TYPE_GX2_GSH_COPY_PROGRAM:
313             if(index == nCopyPrograms)
314             {
315                 // Set copy shader program
316                 pHeader->copyShaderPtr = pCopyProgram;
317                 memcpy(pHeader->copyShaderPtr, (char *)pDataStruct, pBlockHeader->dataSize);
318                 // This is done one layer up (in demoGfd)
319                 // GX2Invalidate(GX2_INVALIDATE_CPU_SHADER, pDataStruct, pBlockHeader->dataSize);
320                 GFDPRINT("GFD:GSH_COPY_PROGRAM: %x -> %x size: %d\n", pDataStruct, pHeader->copyShaderPtr, pBlockHeader->dataSize);
321             }
322             nCopyPrograms++;
323             break;
324 
325         case GFD_BLOCK_TYPE_GX2_GSH_PROGRAM:
326             if(index == nPrograms)
327             {
328                 // Set shader program
329                 pHeader->shaderPtr = pProgram;
330                 memcpy(pHeader->shaderPtr, (char *)pDataStruct, pBlockHeader->dataSize);
331                 // This is done one layer up (in demoGfd)
332                 // GX2Invalidate(GX2_INVALIDATE_CPU_SHADER, pDataStruct, pBlockHeader->dataSize);
333                 GFDPRINT("GFD:GSH_PROGRAM: %x -> %x size: %d\n", pDataStruct, pHeader->shaderPtr, pBlockHeader->dataSize);
334             }
335             nPrograms++;
336             break;
337         default:
338             break;
339         }
340         pDataStruct += pBlockHeader->dataSize;
341 
342         // Terminate once the full structure has been found
343         if ( nHeaders > index && nPrograms > index  && nCopyPrograms > index)
344             break;
345 
346         if(GFD_BLOCK_TYPE_END == pBlockHeader->type)
347             // terminate read, we have an end block
348             break;
349     }
350 
351     return (ret && nHeaders >= index && nCopyPrograms >= index && nPrograms >= index);
352 }
353 
GFDGetComputeShader(GX2ComputeShader * pHeader,void * pProgram,u32 index,const void * pData)354 BOOL GFDGetComputeShader(GX2ComputeShader *pHeader, void *pProgram, u32 index, const void *pData)
355 {
356     BOOL ret;
357     char *pDataStruct;
358     GFDBlockHeader *pBlockHeader;
359     u32 nHeaders  = 0;
360     u32 nPrograms = 0;
361 
362     if(pHeader == NULL || pProgram == NULL || pData == NULL)
363         return FALSE;
364 
365     if(!_GFDCheckHeaderVersions(pData))
366         return FALSE;
367 
368     if( 0 != (((u32) pProgram) & (GX2_SHADER_ALIGNMENT-1)))
369     {
370         OSReport("Warning: Shader program buffer not aligned correctly. It needs %d byte align buffer.\n", GX2_SHADER_ALIGNMENT);
371         return FALSE;
372     }
373 
374     pDataStruct = (char*)pData + ((GFDHeader*)pData)->size; // jump over the header
375     pBlockHeader = (GFDBlockHeader *)pDataStruct;
376 
377     while((ret = _GFDCheckBlockHeaderMagicVersions(pBlockHeader)))
378     {
379         pBlockHeader = (GFDBlockHeader *)pDataStruct;
380         pDataStruct += pBlockHeader->size;
381 
382         switch(pBlockHeader->type)
383         {
384         case GFD_BLOCK_TYPE_GX2_CSH_HEADER:
385             if(index == nHeaders)
386             {
387                 memcpy(pHeader, (void *)pDataStruct, pBlockHeader->dataSize);
388 
389                 if (!_GFDRelocateBlock(pBlockHeader->dataSize,(char *)pHeader))
390                 {
391                     ASSERT(!"Internal offset/pointers corrupted.");
392                     return FALSE;
393                 }
394                 GFDPRINT("GFD:CSH_HEADER: %x -> %x size: %d\n", pDataStruct, pHeader, pBlockHeader->dataSize);
395             }
396             nHeaders++;
397             break;
398         case GFD_BLOCK_TYPE_GX2_CSH_PROGRAM:
399             if(index == nPrograms)
400             {
401                 // Set shader program
402                 pHeader->shaderPtr = pProgram;
403                 memcpy(pHeader->shaderPtr, (char *)pDataStruct, pBlockHeader->dataSize);
404                 // This is done one layer up (in demoGfd)
405                 // GX2Invalidate(GX2_INVALIDATE_CPU_SHADER, pDataStruct, pBlockHeader->dataSize);
406                 GFDPRINT("GFD:CSH_PROGRAM: %x -> %x size: %d\n", pDataStruct, pHeader->shaderPtr, pBlockHeader->dataSize);
407             }
408             nPrograms++;
409             break;
410         default:
411             break;
412         }
413         pDataStruct += pBlockHeader->dataSize;
414 
415         // Terminate once the full structure has been found
416         if ( nHeaders > index && nPrograms > index )
417             break;
418 
419         if(GFD_BLOCK_TYPE_END == pBlockHeader->type)
420             // terminate read, we have an end block
421             break;
422     }
423 
424     return (ret && nHeaders >= index && nPrograms >= index);
425 }
426 
427 
GFDGetVertexShaderPointer(u32 index,const void * pData)428 GX2VertexShader *GFDGetVertexShaderPointer(u32 index, const void *pData)
429 {
430     GX2VertexShader *pHeader = NULL;
431 
432     char *pDataStruct;
433     GFDBlockHeader *pBlockHeader;
434     u32 nHeaders  = 0;
435     u32 nPrograms = 0;
436 
437     if(!_GFDCheckHeaderVersions(pData))
438         return NULL;
439 
440     pDataStruct = (char*)pData + ((GFDHeader*)pData)->size; // jump over the header
441     pBlockHeader = (GFDBlockHeader *)pDataStruct;
442 
443     while(_GFDCheckBlockHeaderMagicVersions(pBlockHeader))
444     {
445         pBlockHeader = (GFDBlockHeader *)pDataStruct;
446         pDataStruct += pBlockHeader->size;
447 
448         switch(pBlockHeader->type)
449         {
450         case GFD_BLOCK_TYPE_GX2_VSH_HEADER:
451             if(index == nHeaders)
452             {
453                 pHeader = (GX2VertexShader *)pDataStruct;
454                 if (!_GFDRelocateBlock(pBlockHeader->dataSize,(char *)pHeader))
455                 {
456                     ASSERT(!"Internal offset/pointers corrupted.");
457                     return NULL;
458                 }
459                 GFDPRINT("GFD:VSH_HEADER: %x -> %x size: %d\n", pDataStruct, pHeader, pBlockHeader->dataSize);
460             }
461             nHeaders++;
462             break;
463         case GFD_BLOCK_TYPE_GX2_VSH_PROGRAM:
464             if(index == nPrograms)
465             {
466                 if( 0 != (((u32) pDataStruct) & (GX2_SHADER_ALIGNMENT-1)))
467                 {
468                     OSReport("Warning: Shader program buffer not aligned correctly. It needs %d byte align buffer.\n", GX2_SHADER_ALIGNMENT);
469                     return NULL;
470                 }
471                 if(pHeader == NULL)
472                     return NULL;
473                 // Set shader program
474                 pHeader->shaderPtr = (char *)pDataStruct;
475                 GFDPRINT("GFD:VSH_PROGRAM: %x -> %x size: %d\n", pDataStruct, pHeader->shaderPtr, pBlockHeader->dataSize);
476             }
477             nPrograms++;
478             break;
479         default:
480             break;
481         }
482         pDataStruct += pBlockHeader->dataSize;
483 
484         // Terminate once the full structure has been found
485         if ( nHeaders > index && nPrograms > index )
486             break;
487 
488         if(GFD_BLOCK_TYPE_END == pBlockHeader->type)
489             // terminate read, we have an end block
490             break;
491     }
492 
493     // Failed to find the shader program data
494     if(pHeader && !pHeader->shaderPtr)
495         return NULL;
496 
497     return pHeader;
498 }
499 
GFDGetPixelShaderPointer(u32 index,const void * pData)500 GX2PixelShader *GFDGetPixelShaderPointer(u32 index, const void *pData)
501 {
502     GX2PixelShader *pHeader = NULL;
503 
504     char *pDataStruct;
505     GFDBlockHeader *pBlockHeader;
506     u32 nHeaders  = 0;
507     u32 nPrograms = 0;
508 
509     if(!_GFDCheckHeaderVersions(pData))
510         return NULL;
511 
512     pDataStruct = (char*)pData + ((GFDHeader*)pData)->size; // jump over the header
513     pBlockHeader = (GFDBlockHeader *)pDataStruct;
514 
515     while(_GFDCheckBlockHeaderMagicVersions(pBlockHeader))
516     {
517         pBlockHeader = (GFDBlockHeader *)pDataStruct;
518         pDataStruct += pBlockHeader->size;
519 
520         switch(pBlockHeader->type)
521         {
522         case GFD_BLOCK_TYPE_GX2_PSH_HEADER:
523             if(index == nHeaders)
524             {
525                 pHeader = (GX2PixelShader *)pDataStruct;
526                 if (!_GFDRelocateBlock(pBlockHeader->dataSize,(char *)pHeader))
527                 {
528                     ASSERT(!"Internal offset/pointers corrupted.");
529                     return NULL;
530                 }
531                 GFDPRINT("GFD:PSH_HEADER: %x -> %x size: %d\n", pDataStruct, pHeader, pBlockHeader->dataSize);
532             }
533             nHeaders++;
534             break;
535         case GFD_BLOCK_TYPE_GX2_PSH_PROGRAM:
536             if(index == nPrograms)
537             {
538                 if( 0 != (((u32) pDataStruct) & (GX2_SHADER_ALIGNMENT-1)))
539                 {
540                     OSReport("Warning: Shader program buffer not aligned correctly. It needs %d byte align buffer.\n", GX2_SHADER_ALIGNMENT);
541                     return NULL;
542                 }
543                 if(pHeader == NULL)
544                     return NULL;
545                 // Set shader program
546                 pHeader->shaderPtr = (char *)pDataStruct;
547                 GFDPRINT("GFD:PSH_PROGRAM: %x -> %x size: %d\n", pDataStruct, pHeader->shaderPtr, pBlockHeader->dataSize);
548             }
549             nPrograms++;
550             break;
551         default:
552             break;
553         }
554         pDataStruct += pBlockHeader->dataSize;
555 
556         // Terminate once the full structure has been found
557         if ( nHeaders > index && nPrograms > index )
558             break;
559 
560         if(GFD_BLOCK_TYPE_END == pBlockHeader->type)
561             // terminate read, we have an end block
562             break;
563     }
564 
565     // Failed to find the shader program data
566     if(pHeader && !pHeader->shaderPtr)
567         return NULL;
568 
569     return pHeader;
570 }
571 
GFDGetGeometryShaderPointer(u32 index,const void * pData)572 GX2GeometryShader *GFDGetGeometryShaderPointer(u32 index, const void *pData)
573 {
574     GX2GeometryShader *pHeader = NULL;
575 
576     char *pDataStruct;
577     GFDBlockHeader *pBlockHeader;
578     u32 nHeaders  = 0;
579     u32 nPrograms = 0;
580     u32 nCopyPrograms = 0;
581 
582     if(!_GFDCheckHeaderVersions(pData))
583         return NULL;
584 
585     pDataStruct = (char*) pData + ((GFDHeader*)pData)->size; // jump over the header
586     pBlockHeader = (GFDBlockHeader *)pDataStruct;
587 
588     while(_GFDCheckBlockHeaderMagicVersions(pBlockHeader))
589     {
590         pBlockHeader = (GFDBlockHeader *)pDataStruct;
591         pDataStruct += pBlockHeader->size;
592 
593         switch(pBlockHeader->type)
594         {
595         case GFD_BLOCK_TYPE_GX2_GSH_HEADER:
596             if(index == nHeaders)
597             {
598                 pHeader = (GX2GeometryShader *)pDataStruct;
599 
600                 if (!_GFDRelocateBlock(pBlockHeader->dataSize,(char *)pHeader))
601                 {
602                     ASSERT(!"Internal offset/pointers corrupted.");
603                     return NULL;
604                 }
605                 GFDPRINT("GFD:GSH_HEADER: %x -> %x size: %d\n", pDataStruct, pHeader->shaderPtr, pBlockHeader->dataSize);
606             }
607             nHeaders++;
608             break;
609         case GFD_BLOCK_TYPE_GX2_GSH_COPY_PROGRAM:
610             if(index == nCopyPrograms)
611             {
612                 if( 0 != (((u32) pDataStruct) & (GX2_SHADER_ALIGNMENT-1)))
613                 {
614                     OSReport("Warning: Copy shader program buffer not aligned correctly. It needs %d byte align buffer.\n", GX2_SHADER_ALIGNMENT);
615                     return NULL;
616                 }
617                 if(pHeader == NULL)
618                     return NULL;
619 
620                 // Set copy shader program
621                 pHeader->copyShaderPtr = (char *)pDataStruct;
622                 GFDPRINT("GFD:GSH_COPY_PROGRAM: %x -> %x size: %d\n", pDataStruct, pHeader->copyShaderPtr, pBlockHeader->dataSize);
623             }
624             nCopyPrograms++;
625             break;
626 
627         case GFD_BLOCK_TYPE_GX2_GSH_PROGRAM:
628             if(index == nPrograms)
629             {
630                 if( 0 != (((u32) pDataStruct) & (GX2_SHADER_ALIGNMENT-1)))
631                 {
632                     OSReport("Warning: Shader program buffer not aligned correctly. It needs %d byte align buffer.\n", GX2_SHADER_ALIGNMENT);
633                     return NULL;
634                 }
635                 if(pHeader == NULL)
636                     return NULL;
637 
638                 // Set shader program
639                 pHeader->shaderPtr = (char *)pDataStruct;
640                 GFDPRINT("GFD:GSH_PROGRAM: %x -> %x size: %d\n", pDataStruct, pHeader->shaderPtr, pBlockHeader->dataSize);
641             }
642             nPrograms++;
643             break;
644         default:
645             break;
646         }
647         pDataStruct += pBlockHeader->dataSize;
648 
649         // Terminate once the full structure has been found
650         if (nHeaders > index && nPrograms > index && nCopyPrograms > index)
651             break;
652 
653         if(GFD_BLOCK_TYPE_END == pBlockHeader->type)
654             // terminate read, we have an end block
655             break;
656     }
657 
658     // Failed to find the shader program data
659     if(pHeader && (!pHeader->shaderPtr || !pHeader->copyShaderPtr))
660         return NULL;
661 
662     return pHeader;
663 }
664 
GFDGetComputeShaderPointer(u32 index,const void * pData)665 GX2ComputeShader *GFDGetComputeShaderPointer(u32 index, const void *pData)
666 {
667     GX2ComputeShader *pHeader = NULL;
668 
669     char *pDataStruct;
670     GFDBlockHeader *pBlockHeader;
671     u32 nHeaders  = 0;
672     u32 nPrograms = 0;
673 
674     if(!_GFDCheckHeaderVersions(pData))
675         return NULL;
676 
677     pDataStruct = (char*)pData + ((GFDHeader*)pData)->size; // jump over the header
678     pBlockHeader = (GFDBlockHeader *)pDataStruct;
679 
680     while(_GFDCheckBlockHeaderMagicVersions(pBlockHeader))
681     {
682         pBlockHeader = (GFDBlockHeader *)pDataStruct;
683         pDataStruct += pBlockHeader->size;
684 
685         switch(pBlockHeader->type)
686         {
687         case GFD_BLOCK_TYPE_GX2_CSH_HEADER:
688             if(index == nHeaders)
689             {
690                 pHeader = (GX2ComputeShader *)pDataStruct;
691                 if (!_GFDRelocateBlock(pBlockHeader->dataSize,(char *)pHeader))
692                 {
693                     ASSERT(!"Internal offset/pointers corrupted.");
694                     return NULL;
695                 }
696                 GFDPRINT("GFD:CSH_HEADER: %x -> %x size: %d\n", pDataStruct, pHeader, pBlockHeader->dataSize);
697             }
698             nHeaders++;
699             break;
700         case GFD_BLOCK_TYPE_GX2_CSH_PROGRAM:
701             if(index == nPrograms)
702             {
703                 if( 0 != (((u32) pDataStruct) & (GX2_SHADER_ALIGNMENT-1)))
704                 {
705                     OSReport("Warning: Shader program buffer not aligned correctly. It needs %d byte align buffer.\n", GX2_SHADER_ALIGNMENT);
706                     return NULL;
707                 }
708                 if(pHeader == NULL)
709                     return NULL;
710                 // Set shader program
711                 pHeader->shaderPtr = (char *)pDataStruct;
712                 GFDPRINT("GFD:CSH_PROGRAM: %x -> %x size: %d\n", pDataStruct, pHeader->shaderPtr, pBlockHeader->dataSize);
713             }
714             nPrograms++;
715             break;
716         default:
717             break;
718         }
719         pDataStruct += pBlockHeader->dataSize;
720 
721         // Terminate once the full structure has been found
722         if (nHeaders > index && nPrograms > index)
723             break;
724 
725         if(GFD_BLOCK_TYPE_END == pBlockHeader->type)
726             // terminate read, we have an end block
727             break;
728     }
729 
730     // Failed to find the shader program data
731     if(pHeader && !pHeader->shaderPtr)
732         return NULL;
733 
734     return pHeader;
735 }
736 
737 
738 //
739 // For texture binary file (.gtx)
740 //
741 
GFDGetTextureCount(const void * pData)742 u32 GFDGetTextureCount(const void *pData)
743 {
744     return _GFDGetBlockCount(GFD_BLOCK_TYPE_GX2_TEX_HEADER, pData);
745 }
746 
GFDGetTextureHeaderSize(u32 index,const void * pData)747 u32 GFDGetTextureHeaderSize(u32 index, const void *pData)
748 {
749     return _GFDGetBlockDataSize(GFD_BLOCK_TYPE_GX2_TEX_HEADER, index, pData);
750 }
751 
GFDGetTextureImageSize(u32 index,const void * pData)752 u32 GFDGetTextureImageSize(u32 index, const void *pData)
753 {
754     return _GFDGetBlockDataSize(GFD_BLOCK_TYPE_GX2_TEX_IMAGE, index, pData);
755 }
756 
GFDGetTextureMipImageSize(u32 index,const void * pData)757 u32 GFDGetTextureMipImageSize(u32 index, const void *pData)
758 {
759     return _GFDGetBlockDataSize(GFD_BLOCK_TYPE_GX2_TEX_MIP_IMAGE, index, pData);
760 }
761 
GFDGetTextureAlignmentSize(u32 index,const void * pData)762 u32 GFDGetTextureAlignmentSize(u32 index, const void *pData)
763 {
764     char *pDataStruct;
765     GFDBlockHeader *pBlockHeader;
766     u32 nHeaders    = 0;
767     GX2Texture pHeader;
768 
769     if(pData == NULL)
770         return 0;
771 
772     if(!_GFDCheckHeaderVersions(pData))
773         return 0;
774 
775     pDataStruct = (char*) pData + ((GFDHeader*)pData)->size; // jump over the header
776     pBlockHeader = (GFDBlockHeader *) pDataStruct;
777 
778     while(_GFDCheckBlockHeaderMagicVersions(pBlockHeader))
779     {
780         pBlockHeader = (GFDBlockHeader *) pDataStruct;
781 
782         pDataStruct += pBlockHeader->size;
783 
784         switch(pBlockHeader->type)
785         {
786         case GFD_BLOCK_TYPE_GX2_TEX_HEADER:
787             if(index == nHeaders)
788             {
789                 memcpy(&pHeader, (void *)pDataStruct, pBlockHeader->dataSize);
790                 GFDPRINT("GFD:TEX_ALIGN: %x size: %d align: %d\n", pDataStruct, pBlockHeader->dataSize, pHeader.surface.alignment);
791                 return pHeader.surface.alignment;
792             }
793             nHeaders++;
794             break;
795         default:
796             break;
797         }
798         pDataStruct += pBlockHeader->dataSize;
799 
800         if(GFD_BLOCK_TYPE_END == pBlockHeader->type)
801             // terminate read, we have an end block
802             break;
803     }
804 
805     return 0; // not found. return 0.
806 }
807 
GFDGetTexture(GX2Texture * pHeader,void * pImage,void * pMipImage,u32 index,const void * pData)808 BOOL GFDGetTexture(GX2Texture *pHeader, void *pImage, void *pMipImage, u32 index, const void *pData)
809 {
810     BOOL ret;
811     char *pDataStruct;
812     GFDBlockHeader *pBlockHeader;
813     u32 nHeaders    = 0;
814     BOOL headerFound = FALSE;
815 
816     if(pHeader == NULL || pImage == NULL || pData == NULL)
817         return FALSE;
818 
819     if(!_GFDCheckHeaderVersions(pData))
820         return FALSE;
821 
822     pDataStruct = (char*) pData + ((GFDHeader*)pData)->size; // jump over the header
823     pBlockHeader = (GFDBlockHeader *) pDataStruct;
824 
825     while((ret = _GFDCheckBlockHeaderMagicVersions(pBlockHeader)))
826     {
827         pBlockHeader = (GFDBlockHeader *) pDataStruct;
828         pDataStruct += pBlockHeader->size;
829 
830         switch(pBlockHeader->type)
831         {
832         case GFD_BLOCK_TYPE_GX2_TEX_HEADER:
833             if(index == nHeaders)
834             {
835                 memcpy(pHeader, (void *)pDataStruct, pBlockHeader->dataSize);
836                 GFDPRINT("GFD:TEX_HEADER: %x size: %d align: %d\n", pDataStruct, pBlockHeader->dataSize, pHeader->surface.alignment);
837                 headerFound = TRUE;
838             }
839             else if ( headerFound )
840             {
841                 // Since we've already found the header, it is assumed all blocks for the texture have been found
842                 return (pHeader->surface.imagePtr || pHeader->surface.mipPtr);
843             }
844             nHeaders++;
845             break;
846         case GFD_BLOCK_TYPE_GX2_TEX_IMAGE:
847             if (headerFound)
848             {
849                 if( 0 != (((u32) pImage) & (pHeader->surface.alignment-1)))
850                 {
851                     OSReport("Warning: Texture image data buffers are not aligned correctly. It needs %d byte align buffer.\n", pHeader->surface.alignment);
852                     return FALSE;
853                 }
854 
855                 // Set image pointer
856                 pHeader->surface.imagePtr = pImage;
857                 memcpy(pHeader->surface.imagePtr, (char *)pDataStruct, pBlockHeader->dataSize);
858                 // This is done one layer up (in demoGfd)
859                 // GX2Invalidate(GX2_INVALIDATE_CPU_TEXTURE, pDataStruct, pBlockHeader->dataSize);
860                 GFDPRINT("GFD:TEX_IMAGE: %x size: %d\n", pDataStruct, pBlockHeader->dataSize);
861             }
862             break;
863         case GFD_BLOCK_TYPE_GX2_TEX_MIP_IMAGE:
864             if (headerFound)
865             {
866                 if( 0 != (((u32) pMipImage)  & (pHeader->surface.alignment-1)))
867                 {
868                     OSReport("Warning: Texture image data buffers are not aligned correctly. It needs %d byte align buffer.\n", pHeader->surface.alignment);
869                     return FALSE;
870                 }
871 
872                 // Set image pointer
873                 pHeader->surface.mipPtr = pMipImage;
874                 memcpy(pHeader->surface.mipPtr,  (char *)pDataStruct, pBlockHeader->dataSize);
875                 // This is done one layer up (in demoGfd)
876                 // GX2Invalidate(GX2_INVALIDATE_CPU_TEXTURE, pDataStruct, pBlockHeader->dataSize);
877                 GFDPRINT("GFD:TEX_MIP_IMAGE: %x size: %d\n", pDataStruct, pBlockHeader->dataSize);
878             }
879             break;
880         case GFD_BLOCK_TYPE_PAD:
881             GFDPRINT("GFD:PAD: %x size: %d\n", pDataStruct, pBlockHeader->dataSize);
882             break;
883         default:
884             break;
885         }
886         pDataStruct += pBlockHeader->dataSize;
887 
888         if(GFD_BLOCK_TYPE_END == pBlockHeader->type)
889             // terminate read, we have an end block
890             break;
891     }
892 
893     return (ret && headerFound && (pHeader->surface.imagePtr || pHeader->surface.mipPtr));
894 }
895 
896 
GFDGetGX2RTexture(GX2Texture * pHeader,u32 index,const void * pData)897 BOOL GFDGetGX2RTexture(GX2Texture *pHeader, u32 index, const void *pData)
898 {
899     BOOL ret;
900     char *pDataStruct;
901     GFDBlockHeader *pBlockHeader;
902     u32 nHeaders    = 0;
903     BOOL headerFound = FALSE;
904 
905     if(pHeader == NULL || pData == NULL)
906         return FALSE;
907 
908     if(!_GFDCheckHeaderVersions(pData))
909         return FALSE;
910 
911     pDataStruct = (char*) pData + ((GFDHeader*)pData)->size; // jump over the header
912     pBlockHeader = (GFDBlockHeader *) pDataStruct;
913 
914     while((ret = _GFDCheckBlockHeaderMagicVersions(pBlockHeader)))
915     {
916         pBlockHeader = (GFDBlockHeader *) pDataStruct;
917         pDataStruct += pBlockHeader->size;
918 
919         switch(pBlockHeader->type)
920         {
921         case GFD_BLOCK_TYPE_GX2_TEX_HEADER:
922             if(index == nHeaders)
923             {
924                 memcpy(pHeader, (void *)pDataStruct, pBlockHeader->dataSize);
925                 GFDPRINT("GFD:TEX_HEADER: %x size: %d align: %d\n", pDataStruct, pBlockHeader->dataSize, pHeader->surface.alignment);
926                 headerFound = TRUE;
927             }
928             else if ( headerFound )
929             {
930                 // Since we've already found the header, it is assumed all blocks for the texture have been found
931                 return (pHeader->surface.imagePtr || pHeader->surface.mipPtr);
932             }
933             nHeaders++;
934             break;
935         case GFD_BLOCK_TYPE_GX2_TEX_IMAGE:
936             if (headerFound)
937             {
938                 // Allocate the surface
939                 pHeader->surface.imagePtr=pHeader->surface.mipPtr=NULL;
940                 GX2RCreateSurface(&pHeader->surface, (GX2RResourceFlags)(GX2R_BIND_TEXTURE | GX2R_USAGE_CPU_READWRITE | GX2R_USAGE_GPU_READ));
941 
942                 // Lock
943                 void* pImage = GX2RLockSurface(&pHeader->surface, 0);
944 
945                 if( 0 != (((u32) pImage) & (pHeader->surface.alignment-1)))
946                 {
947                     GX2RDestroySurface(&pHeader->surface);
948                     OSReport("Warning: Texture image data buffers are not aligned correctly. It needs %d byte align buffer.\n", pHeader->surface.alignment);
949                     return FALSE;
950                 }
951 
952                 // Copy in the data
953                 memcpy(pHeader->surface.imagePtr, (char *)pDataStruct, pBlockHeader->dataSize);
954 
955                 // Unlock, skip invalidation until it's all loaded
956                 GX2RUnlockSurfaceEx(&pHeader->surface, 0, GX2R_OPTION_NO_INVALIDATE);
957 
958                 GFDPRINT("GFD:TEX_IMAGE: %x size: %d\n", pDataStruct, pBlockHeader->dataSize);
959             }
960             break;
961         case GFD_BLOCK_TYPE_GX2_TEX_MIP_IMAGE:
962             if (headerFound)
963             {
964                 ASSERT(GX2RSurfaceExists(&pHeader->surface));
965 
966                 GX2RLockSurface(&pHeader->surface, GX2R_SURFACE_ALL_MIPS);
967 
968                 if( 0 != (((u32) pHeader->surface.mipPtr)  & (pHeader->surface.alignment-1)))
969                 {
970                     GX2RDestroySurface(&pHeader->surface);
971                     OSReport("Warning: Texture image data buffers are not aligned correctly. It needs %d byte align buffer.\n", pHeader->surface.alignment);
972                     return FALSE;
973                 }
974 
975                 memcpy(pHeader->surface.mipPtr,  (char *)pDataStruct, pBlockHeader->dataSize);
976 
977                 // Unlock, skip invalidation until it's all loaded
978                 GX2RUnlockSurfaceEx(&pHeader->surface, GX2R_SURFACE_ALL_MIPS, GX2R_OPTION_NO_INVALIDATE);
979 
980                 GFDPRINT("GFD:TEX_MIP_IMAGE: %x size: %d\n", pDataStruct, pBlockHeader->dataSize);
981             }
982             break;
983         case GFD_BLOCK_TYPE_PAD:
984             GFDPRINT("GFD:PAD: %x size: %d\n", pDataStruct, pBlockHeader->dataSize);
985             break;
986         default:
987             break;
988         }
989         pDataStruct += pBlockHeader->dataSize;
990 
991         // If we've started looking at a new header block ignore
992         if (nHeaders > index + 1)
993             break;
994 
995         if (GFD_BLOCK_TYPE_END == pBlockHeader->type)
996             // terminate read, we have an end block
997             break;
998     }
999 
1000     if (ret && headerFound && (pHeader->surface.imagePtr || pHeader->surface.mipPtr))
1001     {
1002         if ( pHeader->surface.imagePtr )
1003             GX2RInvalidateSurface(&pHeader->surface, 0, GX2R_OPTION_NONE);
1004         if ( pHeader->surface.mipPtr )
1005             GX2RInvalidateSurface(&pHeader->surface, GX2R_SURFACE_ALL_MIPS, GX2R_OPTION_NONE);
1006 
1007         return TRUE;
1008     }
1009 
1010     return FALSE;
1011 }
1012 
GFDGetTexturePointer(u32 index,const void * pData)1013 GX2Texture *GFDGetTexturePointer(u32 index, const void *pData)
1014 {
1015     GX2Texture *pHeader = NULL;
1016     char *pDataStruct;
1017     GFDBlockHeader *pBlockHeader;
1018     u32 nHeaders    = 0;
1019     BOOL headerFound = FALSE;
1020 
1021     if(!_GFDCheckHeaderVersions(pData))
1022         return NULL;
1023 
1024     pDataStruct = (char*) pData + ((GFDHeader*)pData)->size; // jump over the header
1025     pBlockHeader = (GFDBlockHeader *) pDataStruct;
1026 
1027     while(_GFDCheckBlockHeaderMagicVersions(pBlockHeader))
1028     {
1029         pBlockHeader = (GFDBlockHeader *) pDataStruct;
1030         pDataStruct += pBlockHeader->size;
1031 
1032         switch(pBlockHeader->type)
1033         {
1034         case GFD_BLOCK_TYPE_GX2_TEX_HEADER:
1035             if(index == nHeaders)
1036             {
1037                 pHeader = (GX2Texture *)pDataStruct;
1038                 headerFound = TRUE;
1039                 GFDPRINT("GFD:TEX_HEADER: %x size: %d align: %d\n", pDataStruct, pBlockHeader->dataSize, pHeader->surface.alignment);
1040             }
1041             else if ( headerFound )
1042             {
1043                 // Since we've already found the header, it is assumed all blocks for the texture have been found
1044                 return (pHeader->surface.imagePtr || pHeader->surface.mipPtr) ? pHeader : NULL;
1045             }
1046             nHeaders++;
1047             break;
1048         case GFD_BLOCK_TYPE_GX2_TEX_IMAGE:
1049             if (headerFound)
1050             {
1051                 if( 0 != (((u32)pDataStruct) & (pHeader->surface.alignment-1)))
1052                 {
1053                     OSReport("Warning: Texture image data buffers are not aligned correctly. It needs %d byte align buffer.\n", pHeader->surface.alignment);
1054                     return NULL;
1055                 }
1056 
1057                 // Set image pointer
1058                 pHeader->surface.imagePtr = (char *)pDataStruct;
1059                 GFDPRINT("GFD:TEX_IMAGE: %x size: %d\n", pDataStruct, pBlockHeader->dataSize);
1060             }
1061             break;
1062         case GFD_BLOCK_TYPE_GX2_TEX_MIP_IMAGE:
1063             if (headerFound)
1064             {
1065                 if( 0 != (((u32)pDataStruct) & (pHeader->surface.alignment-1)))
1066                 {
1067                     OSReport("Warning: Texture image data buffers are not aligned correctly. It needs %d byte align buffer.\n", pHeader->surface.alignment);
1068                     return NULL;
1069                 }
1070 
1071                 // Set image pointer
1072                 pHeader->surface.mipPtr = (char *)pDataStruct;
1073                 GFDPRINT("GFD:TEX_MIP_IMAGE: %x size: %d\n", pDataStruct, pBlockHeader->dataSize);
1074             }
1075             break;
1076         case GFD_BLOCK_TYPE_PAD:
1077             GFDPRINT("GFD:PAD: %x size: %d\n", pDataStruct, pBlockHeader->dataSize);
1078             break;
1079         default:
1080             break;
1081         }
1082         pDataStruct += pBlockHeader->dataSize;
1083 
1084         // If we've started looking at a new header block ignore
1085         if (nHeaders > index + 1)
1086             break;
1087 
1088         if(GFD_BLOCK_TYPE_END == pBlockHeader->type)
1089             // terminate read, we have an end block
1090             break;
1091     }
1092 
1093     // Failed to find the level 0 or mipmap chain
1094     if(pHeader && !(pHeader->surface.imagePtr || pHeader->surface.mipPtr))
1095         return NULL;
1096 
1097     return pHeader;
1098 }
1099 
1100 
GFDGetGX2RTexturePointer(u32 index,const void * pData)1101 GX2Texture *GFDGetGX2RTexturePointer(u32 index, const void *pData)
1102 {
1103     GX2Texture* pHeader = GFDGetTexturePointer(index, pData);
1104 
1105     if (pHeader)
1106     {
1107         // Wrap/cast the surface to GX2R
1108         GX2RCreateSurfaceUserMemory(&pHeader->surface, pHeader->surface.imagePtr, pHeader->surface.mipPtr,
1109                                     (GX2RResourceFlags)(GX2R_BIND_TEXTURE | GX2R_USAGE_CPU_READWRITE | GX2R_USAGE_GPU_READ));
1110         // Invalidate. We _probably_ don't need to invalidate CPU cache, but it's hard to 100% guarantee that,
1111         // seems safer to invalidate it anyway.
1112         if ( pHeader->surface.imagePtr )
1113             GX2RInvalidateSurface(&pHeader->surface, 0, GX2R_OPTION_NONE);
1114         if ( pHeader->surface.mipPtr )
1115             GX2RInvalidateSurface(&pHeader->surface, GX2R_SURFACE_ALL_MIPS, GX2R_OPTION_NONE);
1116     }
1117 
1118     return pHeader;
1119 }
1120 
1121 
GFDGetAlignMode(const void * pData)1122 GFDAlignMode GFDGetAlignMode(const void *pData)
1123 {
1124     ASSERT(pData);
1125     GFDHeader *pHeader = (GFDHeader *)pData;
1126     return pHeader->alignMode;
1127 }
1128 
1129 // --------------------------------------
1130 //
1131 // Internal functions
1132 //
1133 // --------------------------------------
1134 
_GFDCheckHeaderVersions(const void * pData)1135 BOOL _GFDCheckHeaderVersions(const void *pData)
1136 {
1137     u32 verMajor;
1138     u32 verMinor;
1139     u32 verGPU;
1140     u32 kCurrentGPU;
1141 
1142     if(pData == NULL)
1143         return FALSE;
1144 
1145     if(!_GFDGetHeaderVersions(&verMajor, &verMinor, &verGPU, pData))
1146         return FALSE;               // fails if magic numbers not match
1147 
1148     if(GFD_HEADER_MAJOR != verMajor)       // major versions must match exactly
1149         return FALSE;
1150 
1151     if(GFD_HEADER_MINOR < verMinor)
1152     {
1153         OSReport("Warning: File minor version is greater than that of code.");
1154         return FALSE;
1155     }
1156 
1157     kCurrentGPU = GX2TempGetGPUVersion();
1158 
1159     if(kCurrentGPU != verGPU)
1160     {
1161         ASSERT(!"Data is not for this version of the GPU");
1162         return FALSE;
1163     }
1164     return TRUE;
1165 }
1166 
_GFDGetHeaderVersions(u32 * pVerMajor,u32 * pVerMinor,u32 * pVerGPU,const void * pData)1167 BOOL _GFDGetHeaderVersions(u32 *pVerMajor, u32 *pVerMinor, u32 *pVerGPU, const void *pData)
1168 {
1169     u32 VerMagic;
1170     GFDHeader *pVerH = (GFDHeader *)pData;
1171     *pVerMajor = 0;
1172     *pVerMinor = 0;
1173     *pVerGPU   = 0;
1174 
1175     // swap if host side
1176     VerMagic = pVerH->magic;
1177 
1178     if(GFD_HEADER_MAGIC != VerMagic)
1179     {
1180         if(GFD_HEADER_MAGIC == pVerH->magic)
1181         {
1182             ASSERT(!"Swap Byte Failed");
1183         }
1184         return FALSE;
1185     }
1186 
1187     *pVerMajor = pVerH->majorVersion;
1188     *pVerMinor = pVerH->minorVersion;
1189     *pVerGPU   = pVerH->gpuVersion;
1190 
1191     return TRUE;
1192 }
1193 
_GFDCheckBlockHeaderMagicVersions(const GFDBlockHeader * pBlockHeader)1194 BOOL _GFDCheckBlockHeaderMagicVersions(const GFDBlockHeader *pBlockHeader)
1195 {
1196     if (!(GFD_BLOCK_HEADER_MAGIC == pBlockHeader->magic ))
1197     {
1198         OSReport("Warning: Unknown block format. \n");
1199         return FALSE;
1200     }
1201 
1202     if (!(GFD_BLOCK_HEADER_MAJOR == pBlockHeader->majorVersion))
1203     {
1204         OSReport("Warning: Unsupported block version %d. \n", pBlockHeader->majorVersion);
1205         return FALSE;
1206     }
1207 
1208     return TRUE;
1209 }
1210 
_GFDGetBlockCount(GFDBlockType blockType,const void * pData)1211 u32 _GFDGetBlockCount(GFDBlockType blockType, const void *pData)
1212 {
1213     char *pDataStruct;
1214     GFDBlockHeader *pBlockHeader;
1215 
1216     if(pData == NULL)
1217         return 0;
1218 
1219     u32 counts = 0;
1220 
1221     if(!_GFDCheckHeaderVersions(pData))
1222         return 0;
1223 
1224     pDataStruct = (char*) pData + ((GFDHeader*)pData)->size; // jump over the header
1225     pBlockHeader = (GFDBlockHeader *) pDataStruct;
1226 
1227     while(_GFDCheckBlockHeaderMagicVersions(pBlockHeader))
1228     {
1229         pBlockHeader = (GFDBlockHeader *)pDataStruct;
1230 
1231         GFDPRINT("GFD:%x:%d: Block Type: %d, %d\n", pData, (s32)pBlockHeader, blockType, pBlockHeader->type);
1232         if (blockType == pBlockHeader->type)
1233         {
1234             counts++;
1235         }
1236         pDataStruct = pDataStruct + pBlockHeader->size + pBlockHeader->dataSize;
1237 
1238         if(GFD_BLOCK_TYPE_END == pBlockHeader->type)
1239             // terminate read, we have an end block
1240             break;
1241     }
1242 
1243     GFDPRINT("GFD:%x: Total Block counts: %d\n", pData, counts);
1244     return counts;
1245 }
1246 
_GFDGetBlockDataSize(GFDBlockType blockType,u32 index,const void * pData)1247 u32 _GFDGetBlockDataSize(GFDBlockType blockType, u32 index, const void *pData)
1248 {
1249     char *pDataStruct; // jump over the header
1250     GFDBlockHeader *pBlockHeader;
1251 
1252     u32 nIndexs    = 0;
1253 
1254     if(pData == NULL)
1255         return 0;
1256 
1257     // Check Header Version
1258     if(!_GFDCheckHeaderVersions(pData))
1259         return 0;
1260 
1261     pDataStruct = (char*) pData + ((GFDHeader*)pData)->size; // jump over the header
1262     pBlockHeader = (GFDBlockHeader *) pDataStruct;
1263 
1264     while(_GFDCheckBlockHeaderMagicVersions(pBlockHeader))
1265     {
1266         pBlockHeader = (GFDBlockHeader *)pDataStruct;
1267         if (blockType == pBlockHeader->type)
1268         {
1269             if(index == nIndexs)
1270             {
1271                 GFDPRINT("GFD:%x:%x: %d Block dataSize: %d\n", pData, pBlockHeader, nIndexs, pBlockHeader->dataSize);
1272                 return pBlockHeader->dataSize;
1273             }
1274             nIndexs++;
1275         }
1276         pDataStruct = pDataStruct + pBlockHeader->size + pBlockHeader->dataSize;
1277 
1278         if(GFD_BLOCK_TYPE_END == pBlockHeader->type)
1279             // terminate read, we have an end block
1280             break;
1281     }
1282 
1283     GFDPRINT("GFD:%x: %d Block size: %d\n", pData, nIndexs, pBlockHeader->dataSize);
1284     return 0; // 0 if didn't find this index
1285 }
1286 
1287 //
1288 // Main method that uses this structure _GFDRelocateBlock(), which patches addresses
1289 // in structure to new base address.  It stores this base address in basePatchAddress.
1290 // Note one weird wart in the design. Bad things can happen if guts of _GFDRelocateBlock()
1291 // are called twice on the structure.  To avoid this, _GFDRelocateBlock() only does real work if basePatchAddress is zero.
1292 // (This lets us move the block later if we want, simply 1) copy block to new address, 2) read basePatchAddress, 3) Call _GFDRelocateBlockEx()
1293 // to using new address(step1) and old address(step2) to move block.
1294 //
1295 
1296 //  Cleans out extra debug flags attached to offset
GFDCleanTag(u32 Offset)1297 u32 GFDCleanTag(u32 Offset)     {return Offset & ~GFD_TAG_MASK;}
1298 
1299 // Verifies offset stored in file is tagged with GFD_TAG_DAT
GFDCheckTagDAT(u32 Offset)1300 BOOL GFDCheckTagDAT(u32 Offset) {return (Offset & GFD_TAG_MASK) == GFD_TAG_DAT;}
1301 
1302 // Verifies offset stored in file is tagged with GFD_TAG_STR
GFDCheckTagSTR(u32 Offset)1303 BOOL GFDCheckTagSTR(u32 Offset) {return (Offset & GFD_TAG_MASK) == GFD_TAG_STR;}
1304 
_GFDRelocateBlock(u32 nBytesBlock,char * pData)1305 BOOL _GFDRelocateBlock(u32 nBytesBlock, char *pData)
1306 {
1307     // The design places GFDBlockRelocationHeader at the end of the
1308     // GFDBlock. As such the size is fixed.
1309     u32 size = sizeof(GFDBlockRelocationHeader);
1310 
1311     if(pData == NULL)
1312         return FALSE;
1313 
1314     GFDBlockRelocationHeader *pTrailer =  (GFDBlockRelocationHeader *)
1315         (pData + nBytesBlock - size);
1316 
1317     ASSERT(GFD_BLOCK_RELOCATION_HEADER_MAGIC == pTrailer->magic && pTrailer->size == size);
1318 
1319     ASSERT(GFDCheckTagDAT(pTrailer->patchTableOffset ));
1320 
1321     // if block has already been relocated, don't relocate it again
1322     if(pTrailer-> basePatchAddress != 0)
1323         return TRUE;
1324 
1325     // finally, use the patch table to update all the pointers in the structure to
1326     // from relative to the begining of the structure, to absolute in memory
1327     return _GFDRelocateBlockEx(pTrailer, (u32)0, (u32)pData, pData);
1328 }
1329 
1330 // Relocate the structure pointed to by pData by offseting the pointers at the
1331 //   Addresses in it located  all the locations in the patch table.
_GFDRelocateBlockEx(GFDBlockRelocationHeader * pTrailer,u32 fromOffset,u32 toOffset,char * pData)1332 BOOL _GFDRelocateBlockEx(GFDBlockRelocationHeader *pTrailer, u32 fromOffset, u32 toOffset, char *pData)
1333 {
1334     u32 MainOffset   = GFDCleanTag( pTrailer->dataOffset );
1335     u32 PTableOffset = GFDCleanTag( pTrailer->patchTableOffset );
1336     u32 NPatches     = pTrailer->patchTableOffsetNumber;
1337     u32 i;
1338     u32 Offset;
1339 
1340     if(pData == NULL)
1341         return FALSE;
1342 
1343     ASSERT(0 == MainOffset);
1344 
1345     for(i = 0; i < NPatches; i++)
1346     {
1347         Offset = *((u32*) (pData + PTableOffset + 4*i));         // dang!  Be careful with those parens..
1348         if(Offset != 0)
1349         {
1350             u32 *pPatchLoc;
1351 
1352             ASSERT(fromOffset != 0 || GFDCheckTagDAT(Offset) || GFDCheckTagSTR(Offset));
1353             pPatchLoc = ((u32*) (pData +  GFDCleanTag(Offset)) );
1354 
1355             GFDCheckTagSTR(*pPatchLoc);
1356             ASSERT(fromOffset != 0 || GFDCheckTagDAT(*pPatchLoc) || GFDCheckTagSTR(*pPatchLoc));
1357             *pPatchLoc = (u32) ( GFDCleanTag(*pPatchLoc) - fromOffset + toOffset);
1358         }
1359     }
1360 
1361     pTrailer->basePatchAddress = toOffset;            // store offset away so we don't step on ourselves.
1362 
1363     return TRUE;
1364 }
1365 
1366 #ifdef __cplusplus
1367 }
1368 #endif // __cplusplus
1369