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 #include "types.h"
14 #include <stdio.h>
15 #include <string.h>
16 #include <assert.h>
17 #include <types.h>
18 #include <stdlib.h>
19 #include <string>
20 
21 #include "windows/gx2.h"
22 
23 #include "cafe/gfd.h"
24 #include "gfdFile.h"
25 
26 #define GTX_DEFAULT_FILENAME "out.gtx"
27 
28 // ------------------------------------------------------------
29 
30 // GFD specific Surface structures to repack structure between 32 bit and 64 bit
31 
32 typedef struct _GFDSurface
33 {
34     GX2SurfaceDim    dim;
35     u32              width;
36     u32              height;
37     u32              depth;
38     u32              numMips;
39     GX2SurfaceFormat format;
40     GX2AAMode        aa;
41     GX2SurfaceUse    use;
42     u32              imageSize;
43     u32              imagePtr;
44     u32              mipSize;
45     u32              mipPtr;
46     GX2TileMode      tileMode;
47     u32              swizzle;
48     u32              alignment;
49     u32              pitch;
50     u32              mipOffset[ 13 ];
51 
52 } GFDSurface;
53 
54 // GFD specific Texture structures to repack structure between 32 bit and 64 bit
55 
56 typedef struct _GFDTexture
57 {
58     GFDSurface surface;
59     u32        viewFirstMip;
60     u32        viewNumMips;
61     u32        viewFirstSlice;
62     u32        viewNumSlices;
63     GX2CompSel compSel;
64     u32        _regs[GX2_NUM_TEXTURE_REGISTERS];
65 
66 } GFDTexture;
67 
68 /// Repack a texture from a (possibly) 64-bit structure to a 32-bit structure.
69 /// We output a GX2Texture * for convenience, but it is not valid for 64-bit.
70 /// All pointers are cast to 32-bit integers. It is therefore 2*4 bytes shorter.
71 /// The return value is the resulting 32-bit structure size.
GFDRepackTexture32Bit(GX2Texture * pTXin64,GFDTexture * pTXout32)72 u32 GFDRepackTexture32Bit(GX2Texture *pTXin64, GFDTexture *pTXout32)
73 {
74     // First, the enclosed surface structure:
75     pTXout32->surface.dim       =       pTXin64->surface.dim;
76     pTXout32->surface.width     =       pTXin64->surface.width;
77     pTXout32->surface.height    =       pTXin64->surface.height;
78     pTXout32->surface.depth     =       pTXin64->surface.depth;
79     pTXout32->surface.numMips   =       pTXin64->surface.numMips;
80     pTXout32->surface.format    =       pTXin64->surface.format;
81     pTXout32->surface.aa        =       pTXin64->surface.aa;
82     pTXout32->surface.use       =       pTXin64->surface.use;
83     pTXout32->surface.imageSize =       pTXin64->surface.imageSize;
84     pTXout32->surface.imagePtr  = (u32) pTXin64->surface.imagePtr;
85     pTXout32->surface.mipSize   =       pTXin64->surface.mipSize;
86     pTXout32->surface.mipPtr    = (u32) pTXin64->surface.mipPtr;
87     pTXout32->surface.tileMode  =       pTXin64->surface.tileMode;
88     pTXout32->surface.swizzle   =       pTXin64->surface.swizzle;
89     pTXout32->surface.alignment =       pTXin64->surface.alignment;
90     pTXout32->surface.pitch     =       pTXin64->surface.pitch;
91     for(u32 i=0; i<13; i++) {
92         pTXout32->surface.mipOffset[i] =   pTXin64->surface.mipOffset[i];
93     }
94     // Then, the rest of the texture structure:
95     pTXout32->viewFirstMip   =       pTXin64->viewFirstMip;
96     pTXout32->viewNumMips    =       pTXin64->viewNumMips;
97     pTXout32->viewFirstSlice =       pTXin64->viewFirstSlice;
98     pTXout32->viewNumSlices  =       pTXin64->viewNumSlices;
99     pTXout32->compSel        =       pTXin64->compSel;
100     for(u32 i=0; i<GX2_NUM_TEXTURE_REGISTERS; i++) {
101         pTXout32->_regs[i]   =       pTXin64->_regs[i];
102     }
103 
104     return sizeof(GFDTexture);
105 }
106 
107 /// Repack a texture from a 32-bit structure to a 64-bit structure.
GFDRepackTexture64Bit(GFDTexture * pTXin32,GX2Texture * pTXout64)108 u32 GFDRepackTexture64Bit(GFDTexture *pTXin32, GX2Texture *pTXout64)
109 {
110     // First, the enclosed surface structure:
111     pTXout64->surface.dim       = pTXin32->surface.dim;
112     pTXout64->surface.width     = pTXin32->surface.width;
113     pTXout64->surface.height    = pTXin32->surface.height;
114     pTXout64->surface.depth     = pTXin32->surface.depth;
115     pTXout64->surface.numMips   = pTXin32->surface.numMips;
116     pTXout64->surface.format    = pTXin32->surface.format;
117     pTXout64->surface.aa        = pTXin32->surface.aa;
118     pTXout64->surface.use       = pTXin32->surface.use;
119     pTXout64->surface.imageSize = pTXin32->surface.imageSize;
120     pTXout64->surface.imagePtr  = (void*)pTXin32->surface.imagePtr;
121     pTXout64->surface.mipSize   = pTXin32->surface.mipSize;
122     pTXout64->surface.mipPtr    = (void*)pTXin32->surface.mipPtr;
123     pTXout64->surface.tileMode  = pTXin32->surface.tileMode;
124     pTXout64->surface.swizzle   = pTXin32->surface.swizzle;
125     pTXout64->surface.alignment = pTXin32->surface.alignment;
126     pTXout64->surface.pitch     = pTXin32->surface.pitch;
127     for(u32 i=0; i<13; i++) {
128         pTXout64->surface.mipOffset[i] = pTXin32->surface.mipOffset[i];
129     }
130     // Then, the rest of the texture structure:
131     pTXout64->viewFirstMip   = pTXin32->viewFirstMip;
132     pTXout64->viewNumMips    = pTXin32->viewNumMips;
133     pTXout64->viewFirstSlice = pTXin32->viewFirstSlice;
134     pTXout64->viewNumSlices  = pTXin32->viewNumSlices;
135     pTXout64->compSel        = pTXin32->compSel;
136     for(u32 i=0; i<GX2_NUM_TEXTURE_REGISTERS; i++) {
137         pTXout64->_regs[i]   = pTXin32->_regs[i];
138     }
139 
140     return sizeof(GX2Texture);
141 }
142 
143 // ------------------------------------------------------------
144 
GFDWriteFileTextureBlock(FILE * fp,GFDEndianSwapMode swapMode,GFDAlignMode alignMode,GX2Texture * pTexture)145 bool GFDWriteFileTextureBlock(FILE *fp, GFDEndianSwapMode swapMode, GFDAlignMode alignMode, GX2Texture *pTexture)
146 {
147     if(pTexture == NULL)
148         return false;
149 
150     // get info about the actual bitmap and mipmap
151     u32   nBytesTex = GFD_ROUND_UP(pTexture->surface.imageSize, sizeof(u32));
152     void* pDataTex  = pTexture->surface.imagePtr;
153 
154     u32 nBytesMip  = GFD_ROUND_UP(pTexture->surface.mipSize, sizeof(u32));
155     void* pDataMip = pTexture->surface.mipPtr;
156 
157     u32 alignment  = pTexture->surface.alignment;
158     u32 padSize = 0;
159 
160     // zero out these pointers, so they don't get stored in file
161     // (Not actually read in, but they aren't real, so let's zap them)
162     // they are restored later on before we return
163     pTexture->surface.imagePtr = NULL;
164     pTexture->surface.mipPtr = NULL;
165 
166     // add GX2Surface struct header
167     GFDTexture tex32;
168     u32 size = GFDRepackTexture32Bit(pTexture, &tex32);
169 
170     // write header for Texture header
171     if(!GFDWriteFileBlockHeader(fp, GFD_BLOCK_TYPE_GX2_TEX_HEADER, size))
172         return false;
173 
174     // write the texture data (not image data)
175     if(!GFDWriteFilePPCData(fp, size/sizeof(u32), GFD_ELEMENT_SIZE_32, (u32 *) &tex32))
176         return false;
177 
178     // calc padding size for texture align
179     // 2 more block headers will be written for pad + texture image data
180     u32 currentSize = (u32)ftell(fp) + 2 * GFD_BLOCK_HEADER_SIZE;
181     padSize = (alignment - (currentSize % alignment)) % alignment;
182 
183     // add pad block
184     if(alignMode)
185         if(!GFDWriteFilePadBlock(fp, padSize))
186             return false;
187 
188     // write out Header for texture block
189     if(!GFDWriteFileBlockHeader(fp,  GFD_BLOCK_TYPE_GX2_TEX_IMAGE, nBytesTex))
190         return false;
191 
192     // printf("%d <- %d \n", (u32)ftell(fp) & (pTexture->surface.alignment-1), pTexture->surface.alignment);
193 
194     // write out the image data for the texture
195     if(!GFDWriteFileGPUData(fp, nBytesTex/sizeof(u32), GFD_ELEMENT_SIZE_32, swapMode, (u32 *) pDataTex))
196         return false;
197 
198     // zero if there is no mipmap
199     if(nBytesMip > 0)
200     {
201         // calc padding size for texture align
202         // 2 more block headers will be written for pad + texture mip data
203         currentSize = (u32)ftell(fp) + 2 * GFD_BLOCK_HEADER_SIZE;
204         padSize = (alignment - (currentSize % alignment)) % alignment;
205 
206         // add pad block
207         if(alignMode)
208             if(!GFDWriteFilePadBlock(fp, padSize))
209                 return false;
210 
211         // write out Header for texture mips
212         if(!GFDWriteFileBlockHeader(fp, GFD_BLOCK_TYPE_GX2_TEX_MIP_IMAGE, nBytesMip))
213             return false;
214 
215         // write out the mip image data for the texture
216         if(!GFDWriteFileGPUData(fp, nBytesMip/sizeof(u32), GFD_ELEMENT_SIZE_32, swapMode, (u32 *) pDataMip))
217             return false;
218     }
219 
220     // restore the pointers so our structure is still useable
221     pTexture->surface.imagePtr = pDataTex;
222     pTexture->surface.mipPtr = pDataMip;
223 
224     return true;
225 }
226 
GFDWriteFileTexture(char * pFilename,GFDGPUVersion gpuVer,GFDEndianSwapMode swapMode,GFDAlignMode alignMode,u32 numTexture,GX2Texture * pTexture)227 bool GFD_API GFDWriteFileTexture(char* pFilename, GFDGPUVersion gpuVer, GFDEndianSwapMode swapMode, GFDAlignMode alignMode, u32 numTexture, GX2Texture* pTexture)
228 {
229     FILE               *fpout = NULL;
230     u32                 count = 0;
231 
232     if (!pFilename)
233     {
234         pFilename = GTX_DEFAULT_FILENAME;
235     }
236 
237     // open file
238     if(GFDOpenFile(&fpout, pFilename, "wb") != 0)
239     {
240         printf("Error: Can't open %s\n", pFilename);
241         return false;
242     }
243 
244     // check gpu version
245     switch(gpuVer) {
246         case GFD_GPU_VERSION_0:
247             break;
248         case GFD_GPU_VERSION_1:
249             break;
250         case GFD_GPU_VERSION_GPU7:
251             break;
252         default:
253             printf("Warning: Unsupported GPU %d, using default.\n", gpuVer);
254             gpuVer = GFD_GPU_VERSION_GPU7;
255             break;
256     }
257 
258     // writes the file header
259     if(!GFDWriteFileHeader(fpout, gpuVer, alignMode))
260     {
261         printf("Error: Can't write file header\n");
262         GFDCloseFile(fpout);
263         return false;
264     }
265 
266     // writes multiple texture blocks
267     for (count = 0; count < numTexture; count++)
268     {
269         if(NULL != &pTexture[count])
270         {
271             // write the texture header, registers, then the texture data
272             if(!GFDWriteFileTextureBlock(fpout, swapMode, alignMode, &pTexture[count]))
273             {
274                 printf("Error: Can't write texture block %d.\n", count);
275                 GFDCloseFile(fpout);
276                 return false;
277             }
278         }
279     }
280 
281     // writes an 'End' block to the file
282     if(!GFDWriteFileBlockHeader(fpout, GFD_BLOCK_TYPE_END, 0))
283     {
284         printf("Error: Can't write end block header\n");
285         GFDCloseFile(fpout);
286         return false;
287     }
288 
289     GFDCloseFile(fpout);
290     return true;
291 }
292 
GFDAppendWriteFileTexture(char * pFilename,GFDGPUVersion gpuVer,GFDEndianSwapMode swapMode,GFDAlignMode alignMode,u32 numTexture,GX2Texture * pTexture)293 bool GFD_API GFDAppendWriteFileTexture(char* pFilename, GFDGPUVersion gpuVer, GFDEndianSwapMode swapMode, GFDAlignMode alignMode, u32 numTexture, GX2Texture* pTexture)
294 {
295     FILE               *fpout = NULL;
296     u32                 count = 0;
297     GFDHeader           fileHeader;
298 
299     // open file
300     if(GFDOpenFile(&fpout, pFilename, "rb+") != 0)
301     {
302         printf("Error: Can't open %s\n", pFilename);
303         return false;
304     }
305 
306     // Read File Header
307     if(!GFDReadFilePPCData(&fileHeader, (GFD_HEADER_SIZE + 3) / 4, GFD_ELEMENT_SIZE_32, fpout))
308     {
309         GFDCloseFile(fpout);
310         printf("Error: Can't read file header.\n");
311         return false;
312     }
313 
314     // check gpu version
315     if(fileHeader.gpuVersion != gpuVer)
316     {
317         GFDCloseFile(fpout);
318         printf("Error: GPU version is different.\n");
319         return false;
320     }
321 
322     // check header version
323     if(!GFDCheckHeaderMagicVersions(&fileHeader))
324     {
325         GFDCloseFile(fpout);
326         printf("Error: Format version is different.\n");
327         return false;
328     }
329 
330     // seeks to beginning of 'End' block
331     fseek(fpout, -(s32)GFD_BLOCK_HEADER_SIZE, SEEK_END);
332 
333     // appened writes multiple texture blocks
334     for (count = 0; count < numTexture; count++)
335     {
336         if(NULL != &pTexture[count])
337         {
338             // write the texture header, registers, then the texture data
339             if(!GFDWriteFileTextureBlock(fpout, swapMode, alignMode, &pTexture[count]))
340             {
341                 printf("Error: Can't write texture block %d.\n", count);
342                 GFDCloseFile(fpout);
343                 return false;
344             }
345         }
346     }
347 
348     // writes an 'End' block to the file
349     if(!GFDWriteFileBlockHeader(fpout, GFD_BLOCK_TYPE_END, 0))
350     {
351         printf("Error: Can't write end block header\n");
352         GFDCloseFile(fpout);
353         return false;
354     }
355 
356     GFDCloseFile(fpout);
357     return true;
358 }
359 
GFDReadFileTexture(GX2Texture * pTexture,GFDGPUVersion gpuVer,GFDEndianSwapMode swapMode,const char * pFilename)360 GFD_DECLSPEC bool GFD_API GFDReadFileTexture(GX2Texture* pTexture, GFDGPUVersion gpuVer, GFDEndianSwapMode swapMode, const char* pFilename)
361 {
362     FILE  *pFile = NULL;
363     GFDHeader gfdHeader;
364     GFDBlockHeader gfdBlockHeader;
365     u32 *imageData;
366     u32 *mipData;
367 
368     int id = 0;
369 
370     if(GFDOpenFile(&pFile, pFilename, "rb"))
371     {
372         printf("Error: loading GTX file. Exiting.\n");
373         return false;
374     }
375 
376     // check gpu version
377     switch(gpuVer) {
378         case GFD_GPU_VERSION_0:
379             break;
380         case GFD_GPU_VERSION_1:
381             break;
382         case GFD_GPU_VERSION_GPU7:
383             break;
384         default:
385             printf("Warning: Unsupported GPU %d, using default.\n", gpuVer);
386             gpuVer = GFD_GPU_VERSION_GPU7;
387             break;
388     }
389 
390     // Read File Header
391     if(!GFDReadFilePPCData(&gfdHeader, (GFD_HEADER_SIZE + 3) / 4, GFD_ELEMENT_SIZE_32, pFile))
392     {
393         GFDCloseFile(pFile);
394         printf("Error: reading file header. Exiting.\n");
395         return false;
396     }
397 
398     // Read Block Header
399     if(!GFDReadFilePPCData(&gfdBlockHeader, (GFD_BLOCK_HEADER_SIZE + 3) / 4, GFD_ELEMENT_SIZE_32, pFile))
400     {
401         GFDCloseFile(pFile);
402         printf("Error: reading block header. Exiting.\n");
403         return false;
404     }
405 
406     while(GFDCheckBlockHeaderMagicVersions(&gfdBlockHeader))
407     {
408         switch(gfdBlockHeader.type)
409         {
410         case GFD_BLOCK_TYPE_GX2_TEX_HEADER:
411 			GFDTexture outTexture;
412             // Read GX2 Header
413             if(!GFDReadFilePPCData(&outTexture, (gfdBlockHeader.dataSize + 3) / 4, GFD_ELEMENT_SIZE_32, pFile))
414             {
415                 GFDCloseFile(pFile);
416                 printf("Error reading gx2 header. Exiting.\n");
417                 if(pTexture->surface.imagePtr != NULL)
418                     free(pTexture->surface.imagePtr);
419                 if(pTexture->surface.mipPtr != NULL)
420                     free(pTexture->surface.mipPtr);
421                 return false;
422             }
423 
424 			GFDRepackTexture64Bit(&outTexture, pTexture);
425 
426             // Print Information
427             //PrintTextureSurfaceInfo(config.printinfo, id, pTexture);
428 
429             // Inc id
430             id++;
431             break;
432         case GFD_BLOCK_TYPE_GX2_TEX_IMAGE:
433             // malloc image data
434             imageData = (u32*)malloc(((gfdBlockHeader.dataSize + 3) / 4)*GFD_ELEMENT_SIZE_32);
435 
436             // Read Texture Image Data
437             if(!GFDReadFileGPUData(imageData, (gfdBlockHeader.dataSize + 3) / 4, GFD_ELEMENT_SIZE_32, swapMode, pFile))
438             {
439                 GFDCloseFile(pFile);
440                 printf("Error: reading gx2 header. Exiting.\n");
441                 if(imageData != NULL)
442                     free(imageData);
443                 if(pTexture->surface.mipPtr != NULL)
444                     free(pTexture->surface.mipPtr);
445                 return false;
446             }
447 
448             // set pointer
449             pTexture->surface.imagePtr = imageData;
450 
451             break;
452         case GFD_BLOCK_TYPE_GX2_TEX_MIP_IMAGE:
453             // malloc mip data
454             mipData = (u32*)malloc(((gfdBlockHeader.dataSize + 3) / 4)*GFD_ELEMENT_SIZE_32);
455 
456             // Read Texture Image Data
457             if(!GFDReadFileGPUData(mipData, (gfdBlockHeader.dataSize + 3) / 4, GFD_ELEMENT_SIZE_32, swapMode, pFile))
458             {
459                 GFDCloseFile(pFile);
460                 printf("Error: reading gx2 header. Exiting.\n");
461                 if(pTexture->surface.imagePtr != NULL)
462                     free(pTexture->surface.imagePtr);
463                 if(mipData != NULL)
464                     free(mipData);
465                 return false;
466             }
467 
468             // set pointer
469             pTexture->surface.mipPtr = mipData;
470 
471             break;
472         case GFD_BLOCK_TYPE_PAD:
473             fseek(pFile, gfdBlockHeader.dataSize, SEEK_CUR);
474             break;
475         default:
476             break;
477         }
478 
479         memset(&gfdBlockHeader, 0, sizeof(gfdBlockHeader));
480 
481         // Read Block Header
482         if(!GFDReadFilePPCData(&gfdBlockHeader, (GFD_BLOCK_HEADER_SIZE + 3) / 4, GFD_ELEMENT_SIZE_32, pFile))
483         {
484             GFDCloseFile(pFile);
485             printf("Error: reading block header. Exiting.\n");
486             if(pTexture->surface.imagePtr != NULL)
487                 free(pTexture->surface.imagePtr);
488             if(pTexture->surface.mipPtr != NULL)
489                 free(pTexture->surface.mipPtr);
490             return false;
491         }
492 
493         // End Block
494         if(GFD_BLOCK_TYPE_END == gfdBlockHeader.type)
495         {
496             GFDCloseFile(pFile);
497             // terminate read, we have an end block
498             break;
499         }
500 
501     }
502     return true;
503 }
504 
GFDFreeFileTexture(GX2Texture * pTexture)505 GFD_DECLSPEC void GFD_API GFDFreeFileTexture(GX2Texture* pTexture)
506 {
507         if(pTexture->surface.imagePtr != NULL)
508             free(pTexture->surface.imagePtr);
509         if(pTexture->surface.mipPtr != NULL)
510             free(pTexture->surface.mipPtr);
511 }
512