/*---------------------------------------------------------------------------* Copyright (C) Nintendo. All rights reserved. These coded instructions, statements, and computer programs contain proprietary information of Nintendo of America Inc. and/or Nintendo Company Ltd., and are protected by Federal copyright law. They may not be disclosed to third parties or copied or duplicated in any form, in whole or in part, without the prior written consent of Nintendo. *---------------------------------------------------------------------------*/ #include #if defined(WIN32) || defined(WIN64) #include #endif #include #include #include #include u32 GX2UTGetSurfaceMipSliceSwizzle(const GX2Surface* pSurf, u32 mipLevel, u32 slice) { // Constants used by GPU7 (commented out values left for reference) const u32 num_banks = 4; const u32 num_channels = 2; //const u32 group_size = 256; //const u32 row_bytes = 2048; //const u32 bank_swap_bytes = 256; //const u32 sample_split_bytes = 2048; // Make sure that swizzling is needed (not needed for small mipmaps) if ( ((pSurf->swizzle >> 16) & 0xFF) <= mipLevel ) return 0; u32 swizzle = GX2GetSurfaceSwizzle((GX2Surface*)pSurf); u32 channel_swizzle = swizzle & 1; // bit 0 u32 bank_swizzle = (swizzle & 6) >> 1; // bit 1-2 u32 bank_slice_rotation = 0; u32 channel_slice_rotation = 0; u32 channel = 0; // Normally more complicated but we're only worried // about the first micro-tile u32 bank = 0; // Same as channel. u32 sample_slice_rotation = 0; // sample_slice = 0 so it's fixed switch (pSurf->tileMode) { // 3D/3B Thick rotate channels and banks every 4 slices case GX2_TILE_MODE_3D_TILED_THICK: case GX2_TILE_MODE_3B_TILED_THICK: bank_slice_rotation = GX2Max(1, (num_channels/2)-1) * (slice / 4) / num_channels; channel_slice_rotation = GX2Max(1, (num_channels/2)-1) * (slice / 4); break; // 3D/3B Thin rotate bank/channel every slice case GX2_TILE_MODE_3D_TILED_THIN1: case GX2_TILE_MODE_3B_TILED_THIN1: bank_slice_rotation = GX2Max(1, (num_channels/2)-1) * slice / num_channels; channel_slice_rotation = GX2Max(1, (num_channels/2)-1) * slice; break; // 2D/2B Thick rotate only banks every 4 slices case GX2_TILE_MODE_2D_TILED_THICK: case GX2_TILE_MODE_2B_TILED_THICK: bank_slice_rotation = (((num_banks / 2) - 1) * (slice / 4)); break; default: // All 2B/2D Thin Formats (rotate bank every slice) // Good bank_slice_rotation = (((num_banks / 2) - 1) * slice); break; } bank ^= (bank_swizzle + bank_slice_rotation) & (num_banks - 1); bank ^= sample_slice_rotation; //bank ^= bank_swap_rotation; // This is 0 since we're always at macro // tile (0, 0) channel ^= (channel_swizzle + channel_slice_rotation) & (num_channels - 1); swizzle = channel | (bank << 1); return swizzle; } // Function to select the tiling mode depending on the mipmap level GX2TileMode GX2UTGetSurfaceMipSliceTileMode(const GX2Surface* pSurf, u32 mipLevel) { ASSERT(pSurf); ASSERT(mipLevel < pSurf->numMips); // Small mipmaps change tiling mode to save memory. if ( ((pSurf->swizzle >> 16) & 0xFF) <= mipLevel ) { switch (pSurf->tileMode) { case GX2_TILE_MODE_LINEAR_ALIGNED: return GX2_TILE_MODE_LINEAR_ALIGNED; case GX2_TILE_MODE_1D_TILED_THIN1: return GX2_TILE_MODE_1D_TILED_THIN1; case GX2_TILE_MODE_1D_TILED_THICK: if (pSurf->dim == GX2_SURFACE_DIM_3D) return GX2_TILE_MODE_1D_TILED_THIN1; else return GX2_TILE_MODE_1D_TILED_THICK; case GX2_TILE_MODE_2D_TILED_THIN1: case GX2_TILE_MODE_2D_TILED_THIN2: case GX2_TILE_MODE_2D_TILED_THIN4: case GX2_TILE_MODE_2B_TILED_THIN1: case GX2_TILE_MODE_2B_TILED_THIN2: case GX2_TILE_MODE_2B_TILED_THIN4: case GX2_TILE_MODE_3D_TILED_THIN1: case GX2_TILE_MODE_3B_TILED_THIN1: return GX2_TILE_MODE_1D_TILED_THIN1; case GX2_TILE_MODE_2D_TILED_THICK: case GX2_TILE_MODE_2B_TILED_THICK: case GX2_TILE_MODE_3D_TILED_THICK: case GX2_TILE_MODE_3B_TILED_THICK: if (pSurf->dim == GX2_SURFACE_DIM_3D) return GX2_TILE_MODE_1D_TILED_THIN1; else return GX2_TILE_MODE_1D_TILED_THICK; } } else if (pSurf->dim == GX2_SURFACE_DIM_3D) { // For Thick tiling modes, the HW will switch to thin // tiling once the depth decreases below 4 to conserve space switch (pSurf->tileMode) { case GX2_TILE_MODE_2D_TILED_THICK: if ( pSurf->depth >> mipLevel < 4 ) return GX2_TILE_MODE_2D_TILED_THIN1; break; case GX2_TILE_MODE_2B_TILED_THICK: if ( pSurf->depth >> mipLevel < 4 ) return GX2_TILE_MODE_2B_TILED_THIN1; break; case GX2_TILE_MODE_3D_TILED_THICK: if ( pSurf->depth >> mipLevel < 4 ) return GX2_TILE_MODE_3D_TILED_THIN1; break; case GX2_TILE_MODE_3B_TILED_THICK: if ( pSurf->depth >> mipLevel < 4 ) return GX2_TILE_MODE_3B_TILED_THIN1; break; } } // Default to using the same tiling mode return pSurf->tileMode; } u32 GX2UTGetSurfaceMipSize(const GX2Surface* pSurf, u32 mipLevel) { u32 size; ASSERT(pSurf); ASSERT(mipLevel < pSurf->numMips); switch (mipLevel) { case 0: size = pSurf->imageSize; break; case 1: size = pSurf->mipOffset[1]; break; default: if ( mipLevel == pSurf->numMips - 1) { size = pSurf->mipSize - pSurf->mipOffset[mipLevel - 1]; } else { size = pSurf->mipOffset[mipLevel] - pSurf->mipOffset[mipLevel-1]; } break; } return size; } void* GX2UTGetSurfaceMipSlicePtr(const GX2Surface* pSurf, u32 mipLevel, u32 slice) { u8* ptr = NULL; ASSERT(pSurf); ASSERT(mipLevel < pSurf->numMips); ASSERT(slice < pSurf->depth); switch (mipLevel) { case 0: ptr = (u8*)pSurf->imagePtr; break; case 1: ptr = (u8*)pSurf->mipPtr; break; default: ptr = (u8*)pSurf->mipPtr + pSurf->mipOffset[mipLevel-1]; break; } // Offset to the start of the slice if ( slice ) { u32 levelSize = GX2UTGetSurfaceMipSize(pSurf, mipLevel); u32 depth = pSurf->depth; // All mipLevels > 0 round the depth to the nearest power of // 2 when determining the size. This is a HW limitation. if ( mipLevel && (((depth - 1) & depth) != 0) ) { depth = GX2UTRoundNearestPow2(depth); } ptr += levelSize * slice / depth; } return (void*)ptr; } void GX2UTSetCommonState() { GX2UTDebugTagIndent(__func__); GX2SetShaderMode(GX2_SHADER_MODE_UNIFORM_REGISTER); // Set polygon Control Register GX2SetPolygonControl(GX2_FRONT_FACE_CCW, // frontFaceMode GX2_DISABLE, // cullBack GX2_DISABLE, // cullFront GX2_DISABLE, // enablePolygonModes GX2_POLYGON_MODE_TRIANGLE,// polygonModeFront GX2_POLYGON_MODE_TRIANGLE,// polygonModeBack GX2_DISABLE, // polyOffsetFrontEnable GX2_DISABLE, // polyOffsetBackEnable GX2_DISABLE); // pointLineOffsetEnable GX2SetPrimitiveRestartIndex(0xffffffff); // Set Alpha Test Values GX2SetAlphaTest(GX2_DISABLE, GX2_COMPARE_LESS, 0.0f); GX2SetAlphaToMask(GX2_FALSE, GX2_ALPHA_TO_MASK_0); GX2SetTargetChannelMasks( GX2_CHANNEL_MASK_RGBA, GX2_CHANNEL_MASK_RGBA, GX2_CHANNEL_MASK_RGBA, GX2_CHANNEL_MASK_RGBA, GX2_CHANNEL_MASK_RGBA, GX2_CHANNEL_MASK_RGBA, GX2_CHANNEL_MASK_RGBA, GX2_CHANNEL_MASK_RGBA); // Disable Stream out GX2SetStreamOutEnable(GX2_FALSE); // Enable the Rasterizer and clipping GX2SetRasterizerClipControl(GX2_ENABLE, GX2_ENABLE); // Setup Tessellation GX2SetTessellation(GX2_TESSELLATION_MODE_DISCRETE, GX2_PRIMITIVE_TESSELLATE_TRIANGLES, GX2_INDEX_FORMAT_U32); GX2SetMaxTessellationLevel(1.0f); GX2SetMinTessellationLevel(1.0f); GX2UTDebugTagUndent(); } GX2Boolean GX2UTIsTileModeThick(const GX2Surface* pSurf) { switch (pSurf->tileMode) { case GX2_TILE_MODE_2D_TILED_THICK: case GX2_TILE_MODE_2B_TILED_THICK: case GX2_TILE_MODE_3D_TILED_THICK: case GX2_TILE_MODE_3B_TILED_THICK: return GX2_TRUE; } return GX2_FALSE; }