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