summaryrefslogtreecommitdiffstats
path: root/src/core/hle/service/vi/vi.h
blob: 81d4f3daa023ae3d8be3dab039eff694beace58d (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
// Copyright 2018 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.

#pragma once

#include <memory>
#include <boost/optional.hpp>
#include "core/hle/kernel/event.h"
#include "core/hle/service/service.h"

namespace CoreTiming {
struct EventType;
}

namespace Service {
namespace VI {

struct IGBPBuffer {
    u32_le magic;
    u32_le width;
    u32_le height;
    u32_le stride;
    u32_le format;
    u32_le usage;
    INSERT_PADDING_WORDS(1);
    u32_le index;
    INSERT_PADDING_WORDS(3);
    u32_le gpu_buffer_id;
    INSERT_PADDING_WORDS(17);
    u32_le nvmap_handle;
    u32_le offset;
    INSERT_PADDING_WORDS(60);
};

static_assert(sizeof(IGBPBuffer) == 0x16C, "IGBPBuffer has wrong size");

class BufferQueue {
public:
    BufferQueue(u32 id, u64 layer_id);
    ~BufferQueue() = default;

    struct Buffer {
        enum class Status { Free = 0, Queued = 1, Dequeued = 2, Acquired = 3 };

        u32 slot;
        Status status = Status::Free;
        IGBPBuffer igbp_buffer;
    };

    void SetPreallocatedBuffer(u32 slot, IGBPBuffer& buffer);
    u32 DequeueBuffer(u32 pixel_format, u32 width, u32 height);
    const IGBPBuffer& RequestBuffer(u32 slot) const;
    void QueueBuffer(u32 slot);
    boost::optional<const Buffer&> AcquireBuffer();
    void ReleaseBuffer(u32 slot);

    u32 GetId() const {
        return id;
    }

    Kernel::SharedPtr<Kernel::Event> GetNativeHandle() const {
        return native_handle;
    }

private:
    u32 id;
    u64 layer_id;

    std::vector<Buffer> queue;
    Kernel::SharedPtr<Kernel::Event> native_handle;
};

struct Layer {
    Layer(u64 id, std::shared_ptr<BufferQueue> queue);
    ~Layer() = default;

    u64 id;
    std::shared_ptr<BufferQueue> buffer_queue;
};

struct Display {
    Display(u64 id, std::string name);
    ~Display() = default;

    u64 id;
    std::string name;

    std::vector<Layer> layers;
    Kernel::SharedPtr<Kernel::Event> vsync_event;
};

class NVFlinger {
public:
    NVFlinger();
    ~NVFlinger();

    /// Opens the specified display and returns the id.
    u64 OpenDisplay(const std::string& name);

    /// Creates a layer on the specified display and returns the layer id.
    u64 CreateLayer(u64 display_id);

    /// Gets the buffer queue id of the specified layer in the specified display.
    u32 GetBufferQueueId(u64 display_id, u64 layer_id);

    /// Gets the vsync event for the specified display.
    Kernel::SharedPtr<Kernel::Event> GetVsyncEvent(u64 display_id);

    /// Obtains a buffer queue identified by the id.
    std::shared_ptr<BufferQueue> GetBufferQueue(u32 id) const;

    /// Performs a composition request to the emulated nvidia GPU and triggers the vsync events when
    /// finished.
    void Compose();

private:
    /// Returns the display identified by the specified id.
    Display& GetDisplay(u64 display_id);

    /// Returns the layer identified by the specified id in the desired display.
    Layer& GetLayer(u64 display_id, u64 layer_id);

    std::vector<Display> displays;
    std::vector<std::shared_ptr<BufferQueue>> buffer_queues;

    /// Id to use for the next layer that is created, this counter is shared among all displays.
    u64 next_layer_id = 1;
    /// Id to use for the next buffer queue that is created, this counter is shared among all
    /// layers.
    u32 next_buffer_queue_id = 1;

    /// CoreTiming event that handles screen composition.
    CoreTiming::EventType* composition_event;
};

class IApplicationDisplayService final : public ServiceFramework<IApplicationDisplayService> {
public:
    IApplicationDisplayService(std::shared_ptr<NVFlinger> nv_flinger);
    ~IApplicationDisplayService() = default;

private:
    void GetRelayService(Kernel::HLERequestContext& ctx);
    void GetSystemDisplayService(Kernel::HLERequestContext& ctx);
    void GetManagerDisplayService(Kernel::HLERequestContext& ctx);
    void GetIndirectDisplayTransactionService(Kernel::HLERequestContext& ctx);
    void OpenDisplay(Kernel::HLERequestContext& ctx);
    void CloseDisplay(Kernel::HLERequestContext& ctx);
    void SetLayerScalingMode(Kernel::HLERequestContext& ctx);
    void OpenLayer(Kernel::HLERequestContext& ctx);
    void CreateStrayLayer(Kernel::HLERequestContext& ctx);
    void DestroyStrayLayer(Kernel::HLERequestContext& ctx);
    void GetDisplayVsyncEvent(Kernel::HLERequestContext& ctx);

    std::shared_ptr<NVFlinger> nv_flinger;
};

/// Registers all VI services with the specified service manager.
void InstallInterfaces(SM::ServiceManager& service_manager);

} // namespace VI
} // namespace Service