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 <stdio.h>
14 
15 #if defined(WIN32) || defined(WIN64)
16 #include <pc/gx2.h>
17 #endif
18 #include <cafe/os.h>
19 #include <cafe/mem.h>
20 #include <cafe/gx2.h>
21 
22 #include <cafe/gx2ut.h>
23 
GX2UTGetSurfaceMipSliceSwizzle(const GX2Surface * pSurf,u32 mipLevel,u32 slice)24 u32 GX2UTGetSurfaceMipSliceSwizzle(const GX2Surface* pSurf, u32 mipLevel, u32 slice)
25 {
26     // Constants used by GPU7 (commented out values left for reference)
27     const u32 num_banks = 4;
28     const u32 num_channels = 2;
29     //const u32 group_size = 256;
30     //const u32 row_bytes = 2048;
31     //const u32 bank_swap_bytes = 256;
32     //const u32 sample_split_bytes = 2048;
33 
34     // Make sure that swizzling is needed (not needed for small mipmaps)
35     if ( ((pSurf->swizzle >> 16) & 0xFF) <= mipLevel )
36         return 0;
37 
38     u32 swizzle = GX2GetSurfaceSwizzle((GX2Surface*)pSurf);
39     u32 channel_swizzle = swizzle & 1; // bit 0
40     u32 bank_swizzle = (swizzle & 6) >> 1;    // bit 1-2
41     u32 bank_slice_rotation = 0;
42     u32 channel_slice_rotation = 0;
43     u32 channel = 0; // Normally more complicated but we're only worried
44                      // about the first micro-tile
45     u32 bank = 0;    // Same as channel.
46     u32 sample_slice_rotation = 0; // sample_slice = 0 so it's fixed
47 
48     switch (pSurf->tileMode)
49     {
50         // 3D/3B Thick rotate channels and banks every 4 slices
51         case GX2_TILE_MODE_3D_TILED_THICK:
52         case GX2_TILE_MODE_3B_TILED_THICK:
53             bank_slice_rotation = GX2Max(1, (num_channels/2)-1) * (slice / 4) / num_channels;
54             channel_slice_rotation = GX2Max(1, (num_channels/2)-1) * (slice / 4);
55             break;
56 
57         // 3D/3B Thin rotate bank/channel every slice
58         case GX2_TILE_MODE_3D_TILED_THIN1:
59         case GX2_TILE_MODE_3B_TILED_THIN1:
60             bank_slice_rotation = GX2Max(1, (num_channels/2)-1) * slice / num_channels;
61             channel_slice_rotation = GX2Max(1, (num_channels/2)-1) * slice;
62             break;
63 
64         // 2D/2B Thick rotate only banks every 4 slices
65         case GX2_TILE_MODE_2D_TILED_THICK:
66         case GX2_TILE_MODE_2B_TILED_THICK:
67             bank_slice_rotation = (((num_banks / 2) - 1) * (slice / 4));
68             break;
69 
70         default: // All 2B/2D Thin Formats (rotate bank every slice)
71             // Good
72             bank_slice_rotation = (((num_banks / 2) - 1) * slice);
73             break;
74     }
75 
76     bank ^= (bank_swizzle + bank_slice_rotation) & (num_banks - 1);
77     bank ^= sample_slice_rotation;
78     //bank ^= bank_swap_rotation; // This is 0 since we're always at macro
79                                   // tile (0, 0)
80     channel ^= (channel_swizzle + channel_slice_rotation) & (num_channels - 1);
81 
82     swizzle = channel | (bank << 1);
83 
84     return swizzle;
85 }
86 
87 // Function to select the tiling mode depending on the mipmap level
GX2UTGetSurfaceMipSliceTileMode(const GX2Surface * pSurf,u32 mipLevel)88 GX2TileMode GX2UTGetSurfaceMipSliceTileMode(const GX2Surface* pSurf, u32 mipLevel)
89 {
90     ASSERT(pSurf);
91     ASSERT(mipLevel < pSurf->numMips);
92 
93     // Small mipmaps change tiling mode to save memory.
94     if ( ((pSurf->swizzle >> 16) & 0xFF) <= mipLevel )
95     {
96         switch (pSurf->tileMode)
97         {
98             case GX2_TILE_MODE_LINEAR_ALIGNED:
99                 return GX2_TILE_MODE_LINEAR_ALIGNED;
100 
101             case GX2_TILE_MODE_1D_TILED_THIN1:
102                 return GX2_TILE_MODE_1D_TILED_THIN1;
103 
104             case GX2_TILE_MODE_1D_TILED_THICK:
105                 if (pSurf->dim == GX2_SURFACE_DIM_3D)
106                     return GX2_TILE_MODE_1D_TILED_THIN1;
107                 else
108                     return GX2_TILE_MODE_1D_TILED_THICK;
109 
110             case GX2_TILE_MODE_2D_TILED_THIN1:
111             case GX2_TILE_MODE_2D_TILED_THIN2:
112             case GX2_TILE_MODE_2D_TILED_THIN4:
113             case GX2_TILE_MODE_2B_TILED_THIN1:
114             case GX2_TILE_MODE_2B_TILED_THIN2:
115             case GX2_TILE_MODE_2B_TILED_THIN4:
116             case GX2_TILE_MODE_3D_TILED_THIN1:
117             case GX2_TILE_MODE_3B_TILED_THIN1:
118                 return GX2_TILE_MODE_1D_TILED_THIN1;
119 
120             case GX2_TILE_MODE_2D_TILED_THICK:
121             case GX2_TILE_MODE_2B_TILED_THICK:
122             case GX2_TILE_MODE_3D_TILED_THICK:
123             case GX2_TILE_MODE_3B_TILED_THICK:
124                 if (pSurf->dim == GX2_SURFACE_DIM_3D)
125                     return GX2_TILE_MODE_1D_TILED_THIN1;
126                 else
127                     return GX2_TILE_MODE_1D_TILED_THICK;
128         }
129     }
130     else if (pSurf->dim == GX2_SURFACE_DIM_3D)
131     {
132         // For Thick tiling modes, the HW will switch to thin
133         // tiling once the depth decreases below 4 to conserve space
134         switch (pSurf->tileMode)
135         {
136             case GX2_TILE_MODE_2D_TILED_THICK:
137                 if ( pSurf->depth >> mipLevel < 4 )
138                     return GX2_TILE_MODE_2D_TILED_THIN1;
139                 break;
140             case GX2_TILE_MODE_2B_TILED_THICK:
141                 if ( pSurf->depth >> mipLevel < 4 )
142                     return GX2_TILE_MODE_2B_TILED_THIN1;
143                 break;
144             case GX2_TILE_MODE_3D_TILED_THICK:
145                 if ( pSurf->depth >> mipLevel < 4 )
146                     return GX2_TILE_MODE_3D_TILED_THIN1;
147                 break;
148             case GX2_TILE_MODE_3B_TILED_THICK:
149                 if ( pSurf->depth >> mipLevel < 4 )
150                     return GX2_TILE_MODE_3B_TILED_THIN1;
151                 break;
152         }
153     }
154 
155     // Default to using the same tiling mode
156     return pSurf->tileMode;
157 }
158 
GX2UTGetSurfaceMipSize(const GX2Surface * pSurf,u32 mipLevel)159 u32 GX2UTGetSurfaceMipSize(const GX2Surface* pSurf, u32 mipLevel)
160 {
161     u32 size;
162 
163     ASSERT(pSurf);
164     ASSERT(mipLevel < pSurf->numMips);
165 
166     switch (mipLevel)
167     {
168         case 0:
169             size = pSurf->imageSize;
170             break;
171         case 1:
172             size = pSurf->mipOffset[1];
173             break;
174         default:
175             if ( mipLevel == pSurf->numMips - 1)
176             {
177                 size = pSurf->mipSize - pSurf->mipOffset[mipLevel - 1];
178             }
179             else
180             {
181                 size = pSurf->mipOffset[mipLevel] - pSurf->mipOffset[mipLevel-1];
182             }
183             break;
184     }
185 
186     return size;
187 }
188 
GX2UTGetSurfaceMipSlicePtr(const GX2Surface * pSurf,u32 mipLevel,u32 slice)189 void* GX2UTGetSurfaceMipSlicePtr(const GX2Surface* pSurf, u32 mipLevel, u32 slice)
190 {
191     u8* ptr = NULL;
192 
193     ASSERT(pSurf);
194     ASSERT(mipLevel < pSurf->numMips);
195     ASSERT(slice < pSurf->depth);
196 
197     switch (mipLevel)
198     {
199         case 0:
200             ptr = (u8*)pSurf->imagePtr;
201             break;
202         case 1:
203             ptr = (u8*)pSurf->mipPtr;
204             break;
205         default:
206             ptr = (u8*)pSurf->mipPtr + pSurf->mipOffset[mipLevel-1];
207             break;
208     }
209 
210     // Offset to the start of the slice
211     if ( slice )
212     {
213         u32 levelSize = GX2UTGetSurfaceMipSize(pSurf, mipLevel);
214         u32 depth = pSurf->depth;
215 
216         // All mipLevels > 0 round the depth to the nearest power of
217         // 2 when determining the size. This is a HW limitation.
218         if ( mipLevel && (((depth - 1) & depth) != 0) )
219         {
220             depth = GX2UTRoundNearestPow2(depth);
221         }
222         ptr += levelSize * slice / depth;
223     }
224 
225     return (void*)ptr;
226 }
227 
228 
GX2UTSetCommonState()229 void GX2UTSetCommonState()
230 {
231     GX2UTDebugTagIndent(__func__);
232 
233     GX2SetShaderMode(GX2_SHADER_MODE_UNIFORM_REGISTER);
234 
235     // Set polygon Control Register
236     GX2SetPolygonControl(GX2_FRONT_FACE_CCW,       // frontFaceMode
237                            GX2_DISABLE,              // cullBack
238                            GX2_DISABLE,              // cullFront
239                            GX2_DISABLE,              // enablePolygonModes
240                            GX2_POLYGON_MODE_TRIANGLE,// polygonModeFront
241                            GX2_POLYGON_MODE_TRIANGLE,// polygonModeBack
242                            GX2_DISABLE,              // polyOffsetFrontEnable
243                            GX2_DISABLE,              // polyOffsetBackEnable
244                            GX2_DISABLE);             // pointLineOffsetEnable
245 
246     GX2SetPrimitiveRestartIndex(0xffffffff);
247 
248     // Set Alpha Test Values
249     GX2SetAlphaTest(GX2_DISABLE, GX2_COMPARE_LESS, 0.0f);
250 
251     GX2SetAlphaToMask(GX2_FALSE, GX2_ALPHA_TO_MASK_0);
252 
253     GX2SetTargetChannelMasks(
254         GX2_CHANNEL_MASK_RGBA,
255         GX2_CHANNEL_MASK_RGBA,
256         GX2_CHANNEL_MASK_RGBA,
257         GX2_CHANNEL_MASK_RGBA,
258         GX2_CHANNEL_MASK_RGBA,
259         GX2_CHANNEL_MASK_RGBA,
260         GX2_CHANNEL_MASK_RGBA,
261         GX2_CHANNEL_MASK_RGBA);
262 
263 
264     // Disable Stream out
265     GX2SetStreamOutEnable(GX2_FALSE);
266 
267     // Enable the Rasterizer and clipping
268     GX2SetRasterizerClipControl(GX2_ENABLE, GX2_ENABLE);
269 
270     // Setup Tessellation
271     GX2SetTessellation(GX2_TESSELLATION_MODE_DISCRETE,
272                        GX2_PRIMITIVE_TESSELLATE_TRIANGLES,
273                        GX2_INDEX_FORMAT_U32);
274     GX2SetMaxTessellationLevel(1.0f);
275     GX2SetMinTessellationLevel(1.0f);
276 
277     GX2UTDebugTagUndent();
278 }
279 
GX2UTIsTileModeThick(const GX2Surface * pSurf)280 GX2Boolean GX2UTIsTileModeThick(const GX2Surface* pSurf)
281 {
282     switch (pSurf->tileMode)
283     {
284         case GX2_TILE_MODE_2D_TILED_THICK:
285         case GX2_TILE_MODE_2B_TILED_THICK:
286         case GX2_TILE_MODE_3D_TILED_THICK:
287         case GX2_TILE_MODE_3B_TILED_THICK:
288             return GX2_TRUE;
289     }
290 
291     return GX2_FALSE;
292 }
293 
294