예제 #1
0
        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.");
            }
        }
예제 #2
0
        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!");
            }
        }
예제 #3
0
        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;
        }
예제 #4
0
파일: GalImage.cs 프로젝트: zpoo32/Ryujinx
        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);
        }
예제 #5
0
        public static bool IsArray(GalTextureTarget textureTarget)
        {
            switch (textureTarget)
            {
            case GalTextureTarget.OneDArray:
            case GalTextureTarget.TwoDArray:
            case GalTextureTarget.CubeArray:
                return(true);

            default:
                return(false);
            }
        }
예제 #6
0
        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);
        }
예제 #7
0
        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;
        }
예제 #8
0
        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);
        }
예제 #9
0
        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);
        }
예제 #10
0
        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)));
            }
        }
예제 #11
0
        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)));
                }
            }
        }
예제 #12
0
        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)));
            }
        }
예제 #13
0
        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);
        }