summaryrefslogtreecommitdiffstats
path: root/src/video_core/texture_cache/surface_params.h
blob: 13a08a60ffe3e15b69ef307b8a6d82612b193238 (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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
// Copyright 2019 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.

#pragma once

#include <map>

#include "common/alignment.h"
#include "common/bit_util.h"
#include "common/common_types.h"
#include "video_core/engines/fermi_2d.h"
#include "video_core/engines/maxwell_3d.h"
#include "video_core/shader/shader_ir.h"
#include "video_core/surface.h"
#include "video_core/textures/decoders.h"

namespace VideoCommon {

using VideoCore::Surface::SurfaceCompression;

class SurfaceParams {
public:
    /// Creates SurfaceCachedParams from a texture configuration.
    static SurfaceParams CreateForTexture(Core::System& system,
                                          const Tegra::Texture::FullTextureInfo& config,
                                          const VideoCommon::Shader::Sampler& entry);

    /// Creates SurfaceCachedParams for a depth buffer configuration.
    static SurfaceParams CreateForDepthBuffer(
        Core::System& system, u32 zeta_width, u32 zeta_height, Tegra::DepthFormat format,
        u32 block_width, u32 block_height, u32 block_depth,
        Tegra::Engines::Maxwell3D::Regs::InvMemoryLayout type);

    /// Creates SurfaceCachedParams from a framebuffer configuration.
    static SurfaceParams CreateForFramebuffer(Core::System& system, std::size_t index);

    /// Creates SurfaceCachedParams from a Fermi2D surface configuration.
    static SurfaceParams CreateForFermiCopySurface(
        const Tegra::Engines::Fermi2D::Regs::Surface& config);

    std::size_t Hash() const;

    bool operator==(const SurfaceParams& rhs) const;

    bool operator!=(const SurfaceParams& rhs) const {
        return !operator==(rhs);
    }

    std::size_t GetGuestSizeInBytes() const {
        return GetInnerMemorySize(false, false, false);
    }

    std::size_t GetHostSizeInBytes() const {
        std::size_t host_size_in_bytes;
        if (GetCompressionType() == SurfaceCompression::Converted) {
            constexpr std::size_t rgb8_bpp = 4ULL;
            // ASTC is uncompressed in software, in emulated as RGBA8
            host_size_in_bytes = 0;
            for (u32 level = 0; level < num_levels; ++level) {
                host_size_in_bytes += GetConvertedMipmapSize(level);
            }
        } else {
            host_size_in_bytes = GetInnerMemorySize(true, false, false);
        }
        return host_size_in_bytes;
    }

    u32 GetBlockAlignedWidth() const {
        return Common::AlignUp(width, 64 / GetBytesPerPixel());
    }

    /// Returns the width of a given mipmap level.
    u32 GetMipWidth(u32 level) const {
        return std::max(1U, width >> level);
    }

    /// Returns the height of a given mipmap level.
    u32 GetMipHeight(u32 level) const {
        return std::max(1U, height >> level);
    }

    /// Returns the depth of a given mipmap level.
    u32 GetMipDepth(u32 level) const {
        return is_layered ? depth : std::max(1U, depth >> level);
    }

    /// Returns the block height of a given mipmap level.
    u32 GetMipBlockHeight(u32 level) const;

    /// Returns the block depth of a given mipmap level.
    u32 GetMipBlockDepth(u32 level) const;

    u32 GetRowAlignment(u32 level) const {
        const u32 bpp =
            GetCompressionType() == SurfaceCompression::Converted ? 4 : GetBytesPerPixel();
        return 1U << Common::CountTrailingZeroes32(GetMipWidth(level) * bpp);
    }

    // Helper used for out of class size calculations
    static std::size_t AlignLayered(const std::size_t out_size, const u32 block_height,
                                    const u32 block_depth) {
        return Common::AlignBits(out_size,
                                 Tegra::Texture::GetGOBSizeShift() + block_height + block_depth);
    }

    /// Returns the offset in bytes in guest memory of a given mipmap level.
    std::size_t GetGuestMipmapLevelOffset(u32 level) const;

    /// Returns the offset in bytes in host memory (linear) of a given mipmap level.
    std::size_t GetHostMipmapLevelOffset(u32 level) const;

    std::size_t GetConvertedMipmapOffset(u32 level) const;

    /// Returns the size in bytes in guest memory of a given mipmap level.
    std::size_t GetGuestMipmapSize(u32 level) const;

    /// Returns the size in bytes in host memory (linear) of a given mipmap level.
    std::size_t GetHostMipmapSize(u32 level) const;

    std::size_t GetConvertedMipmapSize(u32 level) const;

    /// Returns the size of a layer in bytes in guest memory.
    std::size_t GetGuestLayerSize() const;

    /// Returns the size of a layer in bytes in host memory for a given mipmap level.
    std::size_t GetHostLayerSize(u32 level) const;

    static u32 ConvertWidth(u32 width, VideoCore::Surface::PixelFormat pixel_format_from,
                            VideoCore::Surface::PixelFormat pixel_format_to) {
        const u32 bw1 = VideoCore::Surface::GetDefaultBlockWidth(pixel_format_from);
        const u32 bw2 = VideoCore::Surface::GetDefaultBlockWidth(pixel_format_to);
        return (width * bw2 + bw1 - 1) / bw1;
    }

    static u32 ConvertHeight(u32 height, VideoCore::Surface::PixelFormat pixel_format_from,
                             VideoCore::Surface::PixelFormat pixel_format_to) {
        const u32 bh1 = VideoCore::Surface::GetDefaultBlockHeight(pixel_format_from);
        const u32 bh2 = VideoCore::Surface::GetDefaultBlockHeight(pixel_format_to);
        return (height * bh2 + bh1 - 1) / bh1;
    }

    /// Returns the default block width.
    u32 GetDefaultBlockWidth() const {
        return VideoCore::Surface::GetDefaultBlockWidth(pixel_format);
    }

    /// Returns the default block height.
    u32 GetDefaultBlockHeight() const {
        return VideoCore::Surface::GetDefaultBlockHeight(pixel_format);
    }

    /// Returns the bits per pixel.
    u32 GetBitsPerPixel() const {
        return VideoCore::Surface::GetFormatBpp(pixel_format);
    }

    /// Returns the bytes per pixel.
    u32 GetBytesPerPixel() const {
        return VideoCore::Surface::GetBytesPerPixel(pixel_format);
    }

    /// Returns true if the pixel format is a depth and/or stencil format.
    bool IsPixelFormatZeta() const;

    SurfaceCompression GetCompressionType() const {
        return VideoCore::Surface::GetFormatCompressionType(pixel_format);
    }

    std::string TargetName() const;

    bool is_tiled;
    bool srgb_conversion;
    bool is_layered;
    u32 block_width;
    u32 block_height;
    u32 block_depth;
    u32 tile_width_spacing;
    u32 width;
    u32 height;
    u32 depth;
    u32 pitch;
    u32 num_levels;
    VideoCore::Surface::PixelFormat pixel_format;
    VideoCore::Surface::ComponentType component_type;
    VideoCore::Surface::SurfaceType type;
    VideoCore::Surface::SurfaceTarget target;

private:
    /// Returns the size of a given mipmap level inside a layer.
    std::size_t GetInnerMipmapMemorySize(u32 level, bool as_host_size, bool uncompressed) const;

    /// Returns the size of all mipmap levels and aligns as needed.
    std::size_t GetInnerMemorySize(bool as_host_size, bool layer_only, bool uncompressed) const;

    /// Returns the size of a layer
    std::size_t GetLayerSize(bool as_host_size, bool uncompressed) const;

    std::size_t GetNumLayers() const {
        return is_layered ? depth : 1;
    }

    /// Returns true if these parameters are from a layered surface.
    bool IsLayered() const;
};

} // namespace VideoCommon

namespace std {

template <>
struct hash<VideoCommon::SurfaceParams> {
    std::size_t operator()(const VideoCommon::SurfaceParams& k) const noexcept {
        return k.Hash();
    }
};

} // namespace std