public static int GetCoordsCountTextureTarget(GalTextureTarget textureTarget) { switch (textureTarget) { case GalTextureTarget.OneD: return(1); case GalTextureTarget.OneDArray: case GalTextureTarget.OneDBuffer: case GalTextureTarget.TwoD: case GalTextureTarget.TwoDNoMipMap: return(2); case GalTextureTarget.ThreeD: case GalTextureTarget.TwoDArray: case GalTextureTarget.CubeMap: return(3); case GalTextureTarget.CubeArray: return(4); default: throw new NotImplementedException($"TextureTarget.{textureTarget} not implemented yet."); } }
public static TextureTarget GetTextureTarget(GalTextureTarget galTextureTarget) { switch (galTextureTarget) { case GalTextureTarget.OneD: return(TextureTarget.Texture1D); case GalTextureTarget.TwoD: case GalTextureTarget.TwoDNoMipMap: return(TextureTarget.Texture2D); case GalTextureTarget.ThreeD: return(TextureTarget.Texture3D); case GalTextureTarget.OneDArray: return(TextureTarget.Texture1DArray); case GalTextureTarget.OneDBuffer: return(TextureTarget.TextureBuffer); case GalTextureTarget.TwoDArray: return(TextureTarget.Texture2DArray); case GalTextureTarget.CubeMap: return(TextureTarget.TextureCubeMap); case GalTextureTarget.CubeArray: return(TextureTarget.TextureCubeMapArray); default: throw new NotSupportedException($"Texture target {galTextureTarget} currently not supported!"); } }
public int Component; // for TLD4(S) public ShaderIrMetaTex(int elem, GalTextureTarget textureTarget, TextureInstructionSuffix textureInstructionSuffix, params ShaderIrNode[] coordinates) { Elem = elem; TextureTarget = textureTarget; TextureInstructionSuffix = textureInstructionSuffix; Coordinates = coordinates; }
public GalImage( int width, int height, int depth, int layerCount, int tileWidth, int gobBlockHeight, int gobBlockDepth, GalMemoryLayout layout, GalImageFormat format, GalTextureTarget textureTarget, int maxMipmapLevel = 1, GalTextureSource xSource = GalTextureSource.Red, GalTextureSource ySource = GalTextureSource.Green, GalTextureSource zSource = GalTextureSource.Blue, GalTextureSource wSource = GalTextureSource.Alpha) { Width = width; Height = height; LayerCount = layerCount; Depth = depth; TileWidth = tileWidth; GobBlockHeight = gobBlockHeight; GobBlockDepth = gobBlockDepth; Layout = layout; Format = format; MaxMipmapLevel = maxMipmapLevel; XSource = xSource; YSource = ySource; ZSource = zSource; WSource = wSource; TextureTarget = textureTarget; Pitch = ImageUtils.GetPitch(format, width); }
public static bool IsArray(GalTextureTarget textureTarget) { switch (textureTarget) { case GalTextureTarget.OneDArray: case GalTextureTarget.TwoDArray: case GalTextureTarget.CubeArray: return(true); default: return(false); } }
public static void Texs(ShaderIrBlock block, long opCode, int position) { TextureInstructionSuffix suffix; int rawSuffix = opCode.Read(0x34, 0x1e); switch (rawSuffix) { case 0: case 0x4: case 0x10: case 0x16: suffix = TextureInstructionSuffix.Lz; break; case 0x6: case 0x1a: suffix = TextureInstructionSuffix.Ll; break; case 0x8: suffix = TextureInstructionSuffix.Dc; break; case 0x2: case 0xe: case 0x14: case 0x18: suffix = TextureInstructionSuffix.None; break; case 0xa: suffix = TextureInstructionSuffix.Ll | TextureInstructionSuffix.Dc; break; case 0xc: case 0x12: suffix = TextureInstructionSuffix.Lz | TextureInstructionSuffix.Dc; break; default: throw new InvalidOperationException($"Invalid Suffix for TEXS instruction {rawSuffix}"); } GalTextureTarget textureTarget = TexsToTextureTarget(opCode.Read(52, 0x1e)); EmitTexs(block, opCode, ShaderIrInst.Texs, textureTarget, suffix); }
public ShaderDeclInfo( string name, int index, bool isCb = false, int cbuf = 0, int size = 1, GalTextureTarget textureTarget = GalTextureTarget.TwoD, TextureInstructionSuffix textureSuffix = TextureInstructionSuffix.None) { Name = name; Index = index; IsCb = isCb; Cbuf = cbuf; Size = size; TextureTarget = textureTarget; TextureSuffix = textureSuffix; }
public static void Tld4(ShaderIrBlock block, long opCode, int position) { TextureInstructionSuffix suffix; int rawSuffix = opCode.Read(0x34, 0xc); switch (rawSuffix) { case 0: suffix = TextureInstructionSuffix.None; break; case 0x4: suffix = TextureInstructionSuffix.AOffI; break; case 0x8: suffix = TextureInstructionSuffix.Ptp; break; default: throw new InvalidOperationException($"Invalid Suffix for TLD4 instruction {rawSuffix}"); } bool isShadow = opCode.Read(0x32); bool isArray = opCode.HasArray(); int chMask = opCode.Read(31, 0xf); GalTextureTarget textureTarget = TexToTextureTarget(opCode.Read(28, 6), isArray); if (isShadow) { suffix |= TextureInstructionSuffix.Dc; } EmitTld4(block, opCode, textureTarget, suffix, chMask, opCode.Read(0x38, 0x3), false); }
private void TextureCopy(NvGpuVmm vmm) { CopyOperation operation = (CopyOperation)ReadRegister(NvGpuEngine2dReg.CopyOperation); int dstFormat = ReadRegister(NvGpuEngine2dReg.DstFormat); bool dstLinear = ReadRegister(NvGpuEngine2dReg.DstLinear) != 0; int dstWidth = ReadRegister(NvGpuEngine2dReg.DstWidth); int dstHeight = ReadRegister(NvGpuEngine2dReg.DstHeight); int dstDepth = ReadRegister(NvGpuEngine2dReg.DstDepth); int dstLayer = ReadRegister(NvGpuEngine2dReg.DstLayer); int dstPitch = ReadRegister(NvGpuEngine2dReg.DstPitch); int dstBlkDim = ReadRegister(NvGpuEngine2dReg.DstBlockDimensions); int srcFormat = ReadRegister(NvGpuEngine2dReg.SrcFormat); bool srcLinear = ReadRegister(NvGpuEngine2dReg.SrcLinear) != 0; int srcWidth = ReadRegister(NvGpuEngine2dReg.SrcWidth); int srcHeight = ReadRegister(NvGpuEngine2dReg.SrcHeight); int srcDepth = ReadRegister(NvGpuEngine2dReg.SrcDepth); int srcLayer = ReadRegister(NvGpuEngine2dReg.SrcLayer); int srcPitch = ReadRegister(NvGpuEngine2dReg.SrcPitch); int srcBlkDim = ReadRegister(NvGpuEngine2dReg.SrcBlockDimensions); int dstBlitX = ReadRegister(NvGpuEngine2dReg.BlitDstX); int dstBlitY = ReadRegister(NvGpuEngine2dReg.BlitDstY); int dstBlitW = ReadRegister(NvGpuEngine2dReg.BlitDstW); int dstBlitH = ReadRegister(NvGpuEngine2dReg.BlitDstH); long blitDuDx = ReadRegisterFixed1_31_32(NvGpuEngine2dReg.BlitDuDxFract); long blitDvDy = ReadRegisterFixed1_31_32(NvGpuEngine2dReg.BlitDvDyFract); long srcBlitX = ReadRegisterFixed1_31_32(NvGpuEngine2dReg.BlitSrcXFract); long srcBlitY = ReadRegisterFixed1_31_32(NvGpuEngine2dReg.BlitSrcYFract); GalImageFormat srcImgFormat = ImageUtils.ConvertSurface((GalSurfaceFormat)srcFormat); GalImageFormat dstImgFormat = ImageUtils.ConvertSurface((GalSurfaceFormat)dstFormat); GalMemoryLayout srcLayout = GetLayout(srcLinear); GalMemoryLayout dstLayout = GetLayout(dstLinear); int srcBlockHeight = 1 << ((srcBlkDim >> 4) & 0xf); int dstBlockHeight = 1 << ((dstBlkDim >> 4) & 0xf); long srcAddress = MakeInt64From2xInt32(NvGpuEngine2dReg.SrcAddress); long dstAddress = MakeInt64From2xInt32(NvGpuEngine2dReg.DstAddress); long srcKey = vmm.GetPhysicalAddress(srcAddress); long dstKey = vmm.GetPhysicalAddress(dstAddress); bool isSrcLayered = false; bool isDstLayered = false; GalTextureTarget srcTarget = GalTextureTarget.TwoD; if (srcDepth != 0) { srcTarget = GalTextureTarget.TwoDArray; srcDepth++; isSrcLayered = true; } else { srcDepth = 1; } GalTextureTarget dstTarget = GalTextureTarget.TwoD; if (dstDepth != 0) { dstTarget = GalTextureTarget.TwoDArray; dstDepth++; isDstLayered = true; } else { dstDepth = 1; } GalImage srcTexture = new GalImage( srcWidth, srcHeight, 1, srcDepth, 1, srcBlockHeight, 1, srcLayout, srcImgFormat, srcTarget); GalImage dstTexture = new GalImage( dstWidth, dstHeight, 1, dstDepth, 1, dstBlockHeight, 1, dstLayout, dstImgFormat, dstTarget); srcTexture.Pitch = srcPitch; dstTexture.Pitch = dstPitch; long GetLayerOffset(GalImage image, int layer) { int targetMipLevel = image.MaxMipmapLevel <= 1 ? 1 : image.MaxMipmapLevel - 1; return(ImageUtils.GetLayerOffset(image, targetMipLevel) * layer); } int srcLayerIndex = -1; if (isSrcLayered && _gpu.ResourceManager.TryGetTextureLayer(srcKey, out srcLayerIndex) && srcLayerIndex != 0) { srcKey = srcKey - GetLayerOffset(srcTexture, srcLayerIndex); } int dstLayerIndex = -1; if (isDstLayered && _gpu.ResourceManager.TryGetTextureLayer(dstKey, out dstLayerIndex) && dstLayerIndex != 0) { dstKey = dstKey - GetLayerOffset(dstTexture, dstLayerIndex); } _gpu.ResourceManager.SendTexture(vmm, srcKey, srcTexture); _gpu.ResourceManager.SendTexture(vmm, dstKey, dstTexture); if (isSrcLayered && srcLayerIndex == -1) { for (int layer = 0; layer < srcTexture.LayerCount; layer++) { _gpu.ResourceManager.SetTextureArrayLayer(srcKey + GetLayerOffset(srcTexture, layer), layer); } srcLayerIndex = 0; } if (isDstLayered && dstLayerIndex == -1) { for (int layer = 0; layer < dstTexture.LayerCount; layer++) { _gpu.ResourceManager.SetTextureArrayLayer(dstKey + GetLayerOffset(dstTexture, layer), layer); } dstLayerIndex = 0; } int srcBlitX1 = (int)(srcBlitX >> 32); int srcBlitY1 = (int)(srcBlitY >> 32); int srcBlitX2 = (int)(srcBlitX + dstBlitW * blitDuDx >> 32); int srcBlitY2 = (int)(srcBlitY + dstBlitH * blitDvDy >> 32); _gpu.Renderer.RenderTarget.Copy( srcTexture, dstTexture, srcKey, dstKey, srcLayerIndex, dstLayerIndex, srcBlitX1, srcBlitY1, srcBlitX2, srcBlitY2, dstBlitX, dstBlitY, dstBlitX + dstBlitW, dstBlitY + dstBlitH); //Do a guest side copy aswell. This is necessary when //the texture is modified by the guest, however it doesn't //work when resources that the gpu can write to are copied, //like framebuffers. // FIXME: SUPPORT MULTILAYER CORRECTLY HERE (this will cause weird stuffs on the first layer) ImageUtils.CopyTexture( vmm, srcTexture, dstTexture, srcAddress, dstAddress, srcBlitX1, srcBlitY1, dstBlitX, dstBlitY, dstBlitW, dstBlitH); vmm.IsRegionModified(dstKey, ImageUtils.GetSize(dstTexture), NvGpuBufferType.Texture); }
private static void EmitTld4(ShaderIrBlock block, long opCode, GalTextureTarget textureType, TextureInstructionSuffix textureInstructionSuffix, int chMask, int component, bool scalar) { ShaderIrOperGpr operA = opCode.Gpr8(); ShaderIrOperGpr operB = opCode.Gpr20(); ShaderIrOperImm operC = opCode.Imm13_36(); ShaderIrOperGpr[] coords = new ShaderIrOperGpr[ImageUtils.GetCoordsCountTextureTarget(textureType)]; ShaderIrOperGpr offset = null; ShaderIrOperGpr depthCompare = null; bool isArray = ImageUtils.IsArray(textureType); int operBIndex = 0; if (scalar) { int coordStartIndex = 0; if (isArray) { coordStartIndex++; coords[coords.Length - 1] = operB; } switch (coords.Length - coordStartIndex) { case 1: coords[0] = opCode.Gpr8(); break; case 2: coords[0] = opCode.Gpr8(); coords[0].Index += coordStartIndex; break; case 3: coords[0] = opCode.Gpr8(); coords[0].Index += coordStartIndex; coords[1] = opCode.Gpr8(); coords[1].Index += 1 + coordStartIndex; break; default: throw new NotSupportedException($"{coords.Length - coordStartIndex} coords textures aren't supported in TLD4S"); } if (coords.Length - coordStartIndex != 1) { coords[coords.Length - coordStartIndex - 1] = operB; operBIndex++; } if (textureInstructionSuffix != TextureInstructionSuffix.None && textureType == GalTextureTarget.TwoD) { coords[coords.Length - coordStartIndex - 1] = opCode.Gpr8(); coords[coords.Length - coordStartIndex - 1].Index += coords.Length - coordStartIndex - 1; operBIndex--; } } else { int indexExtraCoord = 0; if (isArray) { indexExtraCoord++; coords[coords.Length - 1] = opCode.Gpr8(); } for (int index = 0; index < coords.Length - indexExtraCoord; index++) { coords[index] = opCode.Gpr8(); coords[index].Index += index; coords[index].Index += indexExtraCoord; if (coords[index].Index > ShaderIrOperGpr.ZrIndex) { coords[index].Index = ShaderIrOperGpr.ZrIndex; } } } if ((textureInstructionSuffix & TextureInstructionSuffix.AOffI) != 0) { offset = opCode.Gpr20(); offset.Index += operBIndex; operBIndex++; } if ((textureInstructionSuffix & TextureInstructionSuffix.Dc) != 0) { depthCompare = opCode.Gpr20(); depthCompare.Index += operBIndex; operBIndex++; } coords = CoordsRegistersToTempRegisters(block, coords); int regInc = 0; for (int ch = 0; ch < 4; ch++) { if (!IsChannelUsed(chMask, ch)) { continue; } ShaderIrOperGpr dst = opCode.Gpr0(); dst.Index += regInc++; if (!dst.IsValidRegister || dst.IsConst) { continue; } ShaderIrMetaTex meta = new ShaderIrMetaTex(ch, textureType, textureInstructionSuffix, coords) { Component = component, Offset = offset, DepthCompare = depthCompare }; ShaderIrOp op = new ShaderIrOp(ShaderIrInst.Tld4, operA, operB, operC, meta); block.AddNode(opCode.PredNode(new ShaderIrAsg(dst, op))); } }
private static void EmitTexs(ShaderIrBlock block, long opCode, ShaderIrInst inst, GalTextureTarget textureTarget, TextureInstructionSuffix textureInstructionSuffix) { if (inst == ShaderIrInst.Txlf && textureTarget == GalTextureTarget.CubeArray) { throw new InvalidOperationException("TLDS instructions cannot use CUBE modifier!"); } bool isArray = ImageUtils.IsArray(textureTarget); ShaderIrOperGpr[] coords = new ShaderIrOperGpr[ImageUtils.GetCoordsCountTextureTarget(textureTarget)]; ShaderIrOperGpr operA = opCode.Gpr8(); ShaderIrOperGpr operB = opCode.Gpr20(); ShaderIrOperGpr suffixExtra = opCode.Gpr20(); suffixExtra.Index += 1; int coordStartIndex = 0; if (isArray) { coordStartIndex++; coords[coords.Length - 1] = opCode.Gpr8(); } switch (coords.Length - coordStartIndex) { case 1: coords[0] = opCode.Gpr8(); break; case 2: coords[0] = opCode.Gpr8(); coords[0].Index += coordStartIndex; break; case 3: coords[0] = opCode.Gpr8(); coords[0].Index += coordStartIndex; coords[1] = opCode.Gpr8(); coords[1].Index += 1 + coordStartIndex; break; default: throw new NotSupportedException($"{coords.Length - coordStartIndex} coords textures aren't supported in TEXS"); } int operBIndex = 0; ShaderIrOperGpr levelOfDetail = null; ShaderIrOperGpr offset = null; ShaderIrOperGpr depthCompare = null; // OperB is always the last value // Not applicable to 1d textures if (coords.Length - coordStartIndex != 1) { coords[coords.Length - coordStartIndex - 1] = operB; operBIndex++; } // Encoding of TEXS/TLDS is a bit special and change for 2d textures // NOTE: OperA seems to hold at best two args. // On 2D textures, if no suffix need an additional values, Y is stored in OperB, otherwise coords are in OperA and the additional values is in OperB. if (textureInstructionSuffix != TextureInstructionSuffix.None && textureInstructionSuffix != TextureInstructionSuffix.Lz && textureTarget == GalTextureTarget.TwoD) { coords[coords.Length - coordStartIndex - 1] = opCode.Gpr8(); coords[coords.Length - coordStartIndex - 1].Index += coords.Length - coordStartIndex - 1; operBIndex--; } // TODO: Find what MZ does and what changes about the encoding (Maybe Multisample?) if ((textureInstructionSuffix & TextureInstructionSuffix.Ll) != 0) { levelOfDetail = opCode.Gpr20(); levelOfDetail.Index += operBIndex; operBIndex++; } if ((textureInstructionSuffix & TextureInstructionSuffix.AOffI) != 0) { offset = opCode.Gpr20(); offset.Index += operBIndex; operBIndex++; } if ((textureInstructionSuffix & TextureInstructionSuffix.Dc) != 0) { depthCompare = opCode.Gpr20(); depthCompare.Index += operBIndex; operBIndex++; } int lutIndex; lutIndex = !opCode.Gpr0().IsConst ? 1 : 0; lutIndex |= !opCode.Gpr28().IsConst ? 2 : 0; if (lutIndex == 0) { //Both destination registers are RZ, do nothing. return; } bool fp16 = !opCode.Read(59); int dstIncrement = 0; ShaderIrOperGpr GetDst() { ShaderIrOperGpr dst; if (fp16) { //FP16 mode, two components are packed on the two //halfs of a 32-bits register, as two half-float values. int halfPart = dstIncrement & 1; switch (lutIndex) { case 1: dst = opCode.GprHalf0(halfPart); break; case 2: dst = opCode.GprHalf28(halfPart); break; case 3: dst = (dstIncrement >> 1) != 0 ? opCode.GprHalf28(halfPart) : opCode.GprHalf0(halfPart); break; default: throw new InvalidOperationException(); } } else { //32-bits mode, each component uses one register. //Two components uses two consecutive registers. switch (lutIndex) { case 1: dst = opCode.Gpr0(); break; case 2: dst = opCode.Gpr28(); break; case 3: dst = (dstIncrement >> 1) != 0 ? opCode.Gpr28() : opCode.Gpr0(); break; default: throw new InvalidOperationException(); } dst.Index += dstIncrement & 1; } dstIncrement++; return(dst); } int chMask = _maskLut[lutIndex, opCode.Read(50, 7)]; if (chMask == 0) { //All channels are disabled, do nothing. return; } ShaderIrNode operC = opCode.Imm13_36(); coords = CoordsRegistersToTempRegisters(block, coords); for (int ch = 0; ch < 4; ch++) { if (!IsChannelUsed(chMask, ch)) { continue; } ShaderIrMetaTex meta = new ShaderIrMetaTex(ch, textureTarget, textureInstructionSuffix, coords) { LevelOfDetail = levelOfDetail, Offset = offset, DepthCompare = depthCompare }; ShaderIrOp op = new ShaderIrOp(inst, operA, operB, operC, meta); ShaderIrOperGpr dst = GetDst(); if (dst.IsValidRegister && !dst.IsConst) { block.AddNode(opCode.PredNode(new ShaderIrAsg(dst, op))); } } }
private static void EmitTex(ShaderIrBlock block, long opCode, TextureInstructionSuffix textureInstructionSuffix, bool gprHandle) { bool isArray = opCode.HasArray(); GalTextureTarget textureTarget = TexToTextureTarget(opCode.Read(28, 6), isArray); bool hasDepthCompare = opCode.Read(0x32); if (hasDepthCompare) { textureInstructionSuffix |= TextureInstructionSuffix.Dc; } ShaderIrOperGpr[] coords = new ShaderIrOperGpr[ImageUtils.GetCoordsCountTextureTarget(textureTarget)]; int indexExtraCoord = 0; if (isArray) { indexExtraCoord++; coords[coords.Length - 1] = opCode.Gpr8(); } for (int index = 0; index < coords.Length - indexExtraCoord; index++) { ShaderIrOperGpr coordReg = opCode.Gpr8(); coordReg.Index += index; coordReg.Index += indexExtraCoord; if (!coordReg.IsValidRegister) { coordReg.Index = ShaderIrOperGpr.ZrIndex; } coords[index] = coordReg; } int chMask = opCode.Read(31, 0xf); ShaderIrOperGpr levelOfDetail = null; ShaderIrOperGpr offset = null; ShaderIrOperGpr depthCompare = null; // TODO: determine first argument when TEX.B is used int operBIndex = gprHandle ? 1 : 0; if ((textureInstructionSuffix & TextureInstructionSuffix.Ll) != 0 || (textureInstructionSuffix & TextureInstructionSuffix.Lb) != 0 || (textureInstructionSuffix & TextureInstructionSuffix.Lba) != 0 || (textureInstructionSuffix & TextureInstructionSuffix.Lla) != 0) { levelOfDetail = opCode.Gpr20(); levelOfDetail.Index += operBIndex; operBIndex++; } if ((textureInstructionSuffix & TextureInstructionSuffix.AOffI) != 0) { offset = opCode.Gpr20(); offset.Index += operBIndex; operBIndex++; } if ((textureInstructionSuffix & TextureInstructionSuffix.Dc) != 0) { depthCompare = opCode.Gpr20(); depthCompare.Index += operBIndex; operBIndex++; } // ??? ShaderIrNode operC = gprHandle ? (ShaderIrNode)opCode.Gpr20() : (ShaderIrNode)opCode.Imm13_36(); ShaderIrInst inst = gprHandle ? ShaderIrInst.Texb : ShaderIrInst.Texs; coords = CoordsRegistersToTempRegisters(block, coords); int regInc = 0; for (int ch = 0; ch < 4; ch++) { if (!IsChannelUsed(chMask, ch)) { continue; } ShaderIrOperGpr dst = opCode.Gpr0(); dst.Index += regInc++; if (!dst.IsValidRegister || dst.IsConst) { continue; } ShaderIrMetaTex meta = new ShaderIrMetaTex(ch, textureTarget, textureInstructionSuffix, coords) { LevelOfDetail = levelOfDetail, Offset = offset, DepthCompare = depthCompare }; ShaderIrOp op = new ShaderIrOp(inst, coords[0], coords.Length > 1 ? coords[1] : null, operC, meta); block.AddNode(opCode.PredNode(new ShaderIrAsg(dst, op))); } }
public static GalImage MakeTexture(NvGpuVmm vmm, long ticPosition) { int[] tic = ReadWords(vmm, ticPosition, 8); GalImageFormat format = GetImageFormat(tic); GalTextureTarget textureTarget = (GalTextureTarget)((tic[4] >> 23) & 0xF); GalTextureSource xSource = (GalTextureSource)((tic[0] >> 19) & 7); GalTextureSource ySource = (GalTextureSource)((tic[0] >> 22) & 7); GalTextureSource zSource = (GalTextureSource)((tic[0] >> 25) & 7); GalTextureSource wSource = (GalTextureSource)((tic[0] >> 28) & 7); TextureSwizzle swizzle = (TextureSwizzle)((tic[2] >> 21) & 7); int maxMipmapLevel = (tic[3] >> 28) & 0xF + 1; GalMemoryLayout layout; if (swizzle == TextureSwizzle.BlockLinear || swizzle == TextureSwizzle.BlockLinearColorKey) { layout = GalMemoryLayout.BlockLinear; } else { layout = GalMemoryLayout.Pitch; } int gobBlockHeightLog2 = (tic[3] >> 3) & 7; int gobBlockDepthLog2 = (tic[3] >> 6) & 7; int tileWidthLog2 = (tic[3] >> 10) & 7; int gobBlockHeight = 1 << gobBlockHeightLog2; int gobBlockDepth = 1 << gobBlockDepthLog2; int tileWidth = 1 << tileWidthLog2; int width = ((tic[4] >> 0) & 0xffff) + 1; int height = ((tic[5] >> 0) & 0xffff) + 1; int depth = ((tic[5] >> 16) & 0x3fff) + 1; int layoutCount = 1; // TODO: check this if (ImageUtils.IsArray(textureTarget)) { layoutCount = depth; depth = 1; } if (textureTarget == GalTextureTarget.OneD) { height = 1; } if (textureTarget == GalTextureTarget.TwoD || textureTarget == GalTextureTarget.OneD) { depth = 1; } else if (textureTarget == GalTextureTarget.CubeMap) { // FIXME: This is a bit hacky but I guess it's fine for now layoutCount = 6; depth = 1; } else if (textureTarget == GalTextureTarget.CubeArray) { // FIXME: This is a really really hacky but I guess it's fine for now layoutCount *= 6; depth = 1; } GalImage image = new GalImage( width, height, depth, layoutCount, tileWidth, gobBlockHeight, gobBlockDepth, layout, format, textureTarget, maxMipmapLevel, xSource, ySource, zSource, wSource); if (layout == GalMemoryLayout.Pitch) { image.Pitch = (tic[3] & 0xffff) << 5; } return(image); }