aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Graphics.OpenGL/TextureCopyUnscaled.cs
blob: 5ae75d9c0fbdf7188690f8cc11c5d32e7805f528 (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
using OpenTK.Graphics.OpenGL;
using Ryujinx.Common;
using Ryujinx.Graphics.GAL;
using System;

namespace Ryujinx.Graphics.OpenGL
{
    static class TextureCopyUnscaled
    {
        public static void Copy(
            TextureCreateInfo srcInfo,
            TextureCreateInfo dstInfo,
            int srcHandle,
            int dstHandle,
            int srcLayer,
            int dstLayer,
            int srcLevel,
            int dstLevel)
        {
            int srcWidth  = srcInfo.Width;
            int srcHeight = srcInfo.Height;
            int srcDepth  = srcInfo.GetDepthOrLayers();
            int srcLevels = srcInfo.Levels;

            int dstWidth  = dstInfo.Width;
            int dstHeight = dstInfo.Height;
            int dstDepth  = dstInfo.GetDepthOrLayers();
            int dstLevels = dstInfo.Levels;

            dstWidth = Math.Max(1, dstWidth >> dstLevel);
            dstHeight = Math.Max(1, dstHeight >> dstLevel);

            if (dstInfo.Target == Target.Texture3D)
            {
                dstDepth = Math.Max(1, dstDepth >> dstLevel);
            }

            // When copying from a compressed to a non-compressed format,
            // the non-compressed texture will have the size of the texture
            // in blocks (not in texels), so we must adjust that size to
            // match the size in texels of the compressed texture.
            if (!srcInfo.IsCompressed && dstInfo.IsCompressed)
            {
                dstWidth  = BitUtils.DivRoundUp(dstWidth,  dstInfo.BlockWidth);
                dstHeight = BitUtils.DivRoundUp(dstHeight, dstInfo.BlockHeight);
            }
            else if (srcInfo.IsCompressed && !dstInfo.IsCompressed)
            {
                dstWidth  *= dstInfo.BlockWidth;
                dstHeight *= dstInfo.BlockHeight;
            }

            int width  = Math.Min(srcWidth,  dstWidth);
            int height = Math.Min(srcHeight, dstHeight);
            int depth  = Math.Min(srcDepth,  dstDepth);
            int levels = Math.Min(srcLevels, dstLevels);

            for (int level = 0; level < levels; level++)
            {
                // Stop copy if we are already out of the levels range.
                if (level >= srcInfo.Levels || dstLevel + level >= dstInfo.Levels)
                {
                    break;
                }

                GL.CopyImageSubData(
                    srcHandle,
                    srcInfo.Target.ConvertToImageTarget(),
                    srcLevel + level,
                    0,
                    0,
                    srcLayer,
                    dstHandle,
                    dstInfo.Target.ConvertToImageTarget(),
                    dstLevel + level,
                    0,
                    0,
                    dstLayer,
                    width,
                    height,
                    depth);

                width = Math.Max(1, width >> 1);
                height = Math.Max(1, height >> 1);

                if (srcInfo.Target == Target.Texture3D)
                {
                    depth = Math.Max(1, depth >> 1);
                }
            }
        }
    }
}