aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Graphics/Texture/TextureFactory.cs
blob: 1f2d625ec4c881361e15e699ba95513bc616a7b8 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
using Ryujinx.Graphics.Gal;
using Ryujinx.Graphics.Memory;
using System;

namespace Ryujinx.Graphics.Texture
{
    static class TextureFactory
    {
        public static GalImage MakeTexture(NvGpuVmm Vmm, long TicPosition)
        {
            int[] Tic = ReadWords(Vmm, TicPosition, 8);

            GalImageFormat Format = GetImageFormat(Tic);

            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);

            GalMemoryLayout Layout;

            if (Swizzle == TextureSwizzle.BlockLinear ||
                Swizzle == TextureSwizzle.BlockLinearColorKey)
            {
                Layout = GalMemoryLayout.BlockLinear;
            }
            else
            {
                Layout = GalMemoryLayout.Pitch;
            }

            int BlockHeightLog2 = (Tic[3] >> 3)  & 7;
            int TileWidthLog2   = (Tic[3] >> 10) & 7;

            int BlockHeight = 1 << BlockHeightLog2;
            int TileWidth   = 1 << TileWidthLog2;

            int Width  = (Tic[4] & 0xffff) + 1;
            int Height = (Tic[5] & 0xffff) + 1;

            GalImage Image = new GalImage(
                Width,
                Height,
                TileWidth,
                BlockHeight,
                Layout,
                Format,
                XSource,
                YSource,
                ZSource,
                WSource);

            if (Layout == GalMemoryLayout.Pitch)
            {
                Image.Pitch = (Tic[3] & 0xffff) << 5;
            }

            return Image;
        }

        public static GalTextureSampler MakeSampler(NvGpu Gpu, NvGpuVmm Vmm, long TscPosition)
        {
            int[] Tsc = ReadWords(Vmm, TscPosition, 8);

            GalTextureWrap AddressU = (GalTextureWrap)((Tsc[0] >> 0) & 7);
            GalTextureWrap AddressV = (GalTextureWrap)((Tsc[0] >> 3) & 7);
            GalTextureWrap AddressP = (GalTextureWrap)((Tsc[0] >> 6) & 7);

            GalTextureFilter    MagFilter = (GalTextureFilter)   ((Tsc[1] >> 0) & 3);
            GalTextureFilter    MinFilter = (GalTextureFilter)   ((Tsc[1] >> 4) & 3);
            GalTextureMipFilter MipFilter = (GalTextureMipFilter)((Tsc[1] >> 6) & 3);

            GalColorF BorderColor = new GalColorF(
                BitConverter.Int32BitsToSingle(Tsc[4]),
                BitConverter.Int32BitsToSingle(Tsc[5]),
                BitConverter.Int32BitsToSingle(Tsc[6]),
                BitConverter.Int32BitsToSingle(Tsc[7]));

            return new GalTextureSampler(
                AddressU,
                AddressV,
                AddressP,
                MinFilter,
                MagFilter,
                MipFilter,
                BorderColor);
        }

        private static GalImageFormat GetImageFormat(int[] Tic)
        {
            GalTextureType RType = (GalTextureType)((Tic[0] >> 7)  & 7);
            GalTextureType GType = (GalTextureType)((Tic[0] >> 10) & 7);
            GalTextureType BType = (GalTextureType)((Tic[0] >> 13) & 7);
            GalTextureType AType = (GalTextureType)((Tic[0] >> 16) & 7);

            GalTextureFormat Format = (GalTextureFormat)(Tic[0] & 0x7f);

            bool ConvSrgb = ((Tic[4] >> 22) & 1) != 0;

            return ImageUtils.ConvertTexture(Format, RType, GType, BType, AType, ConvSrgb);
        }

        private static int[] ReadWords(NvGpuVmm Vmm, long Position, int Count)
        {
            int[] Words = new int[Count];

            for (int Index = 0; Index < Count; Index++, Position += 4)
            {
                Words[Index] = Vmm.ReadInt32(Position);
            }

            return Words;
        }
    }
}