aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Graphics.Texture/OffsetCalculator.cs
blob: 1f5d9614a846dcc1482a773dc19fb6d5bacb72e2 (plain)
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.Common;
using System.Runtime.CompilerServices;
using static Ryujinx.Graphics.Texture.BlockLinearConstants;

namespace Ryujinx.Graphics.Texture
{
    public class OffsetCalculator
    {
        private int  _width;
        private int  _height;
        private int  _stride;
        private bool _isLinear;
        private int  _bytesPerPixel;

        private BlockLinearLayout _layoutConverter;

        // Variables for built in iteration.
        private int _yPart;

        public OffsetCalculator(
            int  width,
            int  height,
            int  stride,
            bool isLinear,
            int  gobBlocksInY,
            int  bytesPerPixel)
        {
            _width         = width;
            _height        = height;
            _stride        = stride;
            _isLinear      = isLinear;
            _bytesPerPixel = bytesPerPixel;

            int wAlignment = GobStride / bytesPerPixel;

            int wAligned = BitUtils.AlignUp(width, wAlignment);

            if (!isLinear)
            {
                _layoutConverter = new BlockLinearLayout(
                    wAligned,
                    height,
                    1,
                    gobBlocksInY,
                    1,
                    bytesPerPixel);
            }
        }

        public void SetY(int y)
        {
            if (_isLinear)
            {
                _yPart = y * _stride;
            }
            else
            {
                _layoutConverter.SetY(y);
            }
        }

        public int GetOffset(int x, int y)
        {
            if (_isLinear)
            {
                return x * _bytesPerPixel + y * _stride;
            }
            else
            {
                return _layoutConverter.GetOffset(x, y, 0);
            }
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public int GetOffset(int x)
        {
            if (_isLinear)
            {
                return x * _bytesPerPixel + _yPart;
            }
            else
            {
                return _layoutConverter.GetOffset(x);
            }
        }

        public (int offset, int size) GetRectangleRange(int x, int y, int width, int height)
        {
            if (_isLinear)
            {
                int start = y * _stride + x * _bytesPerPixel;
                int end = (y + height - 1) * _stride + (x + width) * _bytesPerPixel;
                return (start, end - start);
            }
            else
            {
                return _layoutConverter.GetRectangleRange(x, y, width, height);
            }
        }

        public bool LayoutMatches(OffsetCalculator other)
        {
            if (_isLinear)
            {
                return other._isLinear &&
                       _width == other._width &&
                       _height == other._height &&
                       _stride == other._stride &&
                       _bytesPerPixel == other._bytesPerPixel;
            }
            else
            {
                return !other._isLinear && _layoutConverter.LayoutMatches(other._layoutConverter);
            }
        }
    }
}