1 /*---------------------------------------------------------------------------*
2
3 Copyright 2010-2011 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