summaryrefslogtreecommitdiffstats
path: root/src/video_core/engines/fermi_2d.h
blob: 50009bf75391dd933935321ad6a94d3e2b11548c (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
// Copyright 2018 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.

#pragma once

#include <array>
#include "common/assert.h"
#include "common/bit_field.h"
#include "common/common_funcs.h"
#include "common/common_types.h"
#include "video_core/gpu.h"
#include "video_core/memory_manager.h"

namespace VideoCore {
class RasterizerInterface;
}

namespace Tegra::Engines {

#define FERMI2D_REG_INDEX(field_name)                                                              \
    (offsetof(Tegra::Engines::Fermi2D::Regs, field_name) / sizeof(u32))

class Fermi2D final {
public:
    explicit Fermi2D(VideoCore::RasterizerInterface& rasterizer, MemoryManager& memory_manager);
    ~Fermi2D() = default;

    /// Write the value to the register identified by method.
    void CallMethod(const GPU::MethodCall& method_call);

    struct Regs {
        static constexpr std::size_t NUM_REGS = 0x258;

        struct Surface {
            RenderTargetFormat format;
            BitField<0, 1, u32> linear;
            union {
                BitField<0, 4, u32> block_width;
                BitField<4, 4, u32> block_height;
                BitField<8, 4, u32> block_depth;
            };
            u32 depth;
            u32 layer;
            u32 pitch;
            u32 width;
            u32 height;
            u32 address_high;
            u32 address_low;

            GPUVAddr Address() const {
                return static_cast<GPUVAddr>((static_cast<GPUVAddr>(address_high) << 32) |
                                             address_low);
            }

            u32 BlockWidth() const {
                // The block width is stored in log2 format.
                return 1 << block_width;
            }

            u32 BlockHeight() const {
                // The block height is stored in log2 format.
                return 1 << block_height;
            }

            u32 BlockDepth() const {
                // The block depth is stored in log2 format.
                return 1 << block_depth;
            }
        };
        static_assert(sizeof(Surface) == 0x28, "Surface has incorrect size");

        enum class Operation : u32 {
            SrcCopyAnd = 0,
            ROPAnd = 1,
            Blend = 2,
            SrcCopy = 3,
            ROP = 4,
            SrcCopyPremult = 5,
            BlendPremult = 6,
        };

        union {
            struct {
                INSERT_PADDING_WORDS(0x80);

                Surface dst;

                INSERT_PADDING_WORDS(2);

                Surface src;

                INSERT_PADDING_WORDS(0x15);

                Operation operation;

                INSERT_PADDING_WORDS(0x9);

                // TODO(Subv): This is only a guess.
                u32 trigger;

                INSERT_PADDING_WORDS(0x1A3);
            };
            std::array<u32, NUM_REGS> reg_array;
        };
    } regs{};

    MemoryManager& memory_manager;

private:
    VideoCore::RasterizerInterface& rasterizer;

    /// Performs the copy from the source surface to the destination surface as configured in the
    /// registers.
    void HandleSurfaceCopy();
};

#define ASSERT_REG_POSITION(field_name, position)                                                  \
    static_assert(offsetof(Fermi2D::Regs, field_name) == position * 4,                             \
                  "Field " #field_name " has invalid position")

ASSERT_REG_POSITION(dst, 0x80);
ASSERT_REG_POSITION(src, 0x8C);
ASSERT_REG_POSITION(operation, 0xAB);
ASSERT_REG_POSITION(trigger, 0xB5);
#undef ASSERT_REG_POSITION

} // namespace Tegra::Engines