summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar Subv2018-01-08 21:30:22 -0500
committerGravatar bunnei2018-01-10 23:28:29 -0500
commit34ae2ec644f49b04d6c6b82742812b6a8a3ef8b5 (patch)
treeb3b01b63dd0fa4fdc240a549257b685595f277cf /src
parentNV: Determine what buffer to draw for each layer of each display. (diff)
downloadyuzu-34ae2ec644f49b04d6c6b82742812b6a8a3ef8b5.tar.gz
yuzu-34ae2ec644f49b04d6c6b82742812b6a8a3ef8b5.tar.xz
yuzu-34ae2ec644f49b04d6c6b82742812b6a8a3ef8b5.zip
NV: Expose the nvdisp_disp0 device and a weak reference to the nvdrv:a service.
NVFlinger will call into the nvdisp_disp0 device to perform screen flips, bypassing the ioctl interface. We now have the address of the framebuffer to draw, we just need to actually put it on the screen.
Diffstat (limited to 'src')
-rw-r--r--src/core/hle/service/nvdrv/nvdrv.cpp8
-rw-r--r--src/core/hle/service/nvdrv/nvdrv.h94
-rw-r--r--src/core/hle/service/nvdrv/nvdrv_a.cpp290
-rw-r--r--src/core/hle/service/nvdrv/nvdrv_a.h14
-rw-r--r--src/core/hle/service/vi/vi.cpp15
-rw-r--r--src/core/hle/service/vi/vi.h3
6 files changed, 252 insertions, 172 deletions
diff --git a/src/core/hle/service/nvdrv/nvdrv.cpp b/src/core/hle/service/nvdrv/nvdrv.cpp
index a2d55eaee..7923e1c0d 100644
--- a/src/core/hle/service/nvdrv/nvdrv.cpp
+++ b/src/core/hle/service/nvdrv/nvdrv.cpp
@@ -8,9 +8,13 @@
8namespace Service { 8namespace Service {
9namespace NVDRV { 9namespace NVDRV {
10 10
11std::weak_ptr<NVDRV_A> nvdrv_a;
12
11void InstallInterfaces(SM::ServiceManager& service_manager) { 13void InstallInterfaces(SM::ServiceManager& service_manager) {
12 std::make_shared<NVDRV_A>()->InstallAsService(service_manager); 14 auto nvdrv = std::make_shared<NVDRV_A>();
15 nvdrv->InstallAsService(service_manager);
16 nvdrv_a = nvdrv;
13} 17}
14 18
15} // namespace nvdrv 19} // namespace NVDRV
16} // namespace Service 20} // namespace Service
diff --git a/src/core/hle/service/nvdrv/nvdrv.h b/src/core/hle/service/nvdrv/nvdrv.h
index a8f305d33..fd59c1dba 100644
--- a/src/core/hle/service/nvdrv/nvdrv.h
+++ b/src/core/hle/service/nvdrv/nvdrv.h
@@ -4,6 +4,8 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <memory>
8#include <unordered_map>
7#include <vector> 9#include <vector>
8#include "common/common_types.h" 10#include "common/common_types.h"
9#include "core/hle/service/service.h" 11#include "core/hle/service/service.h"
@@ -18,6 +20,98 @@ public:
18 virtual u32 ioctl(u32 command, const std::vector<u8>& input, std::vector<u8>& output) = 0; 20 virtual u32 ioctl(u32 command, const std::vector<u8>& input, std::vector<u8>& output) = 0;
19}; 21};
20 22
23class nvmap : public nvdevice {
24public:
25 /// Returns the allocated address of an nvmap object given its handle.
26 VAddr GetObjectAddress(u32 handle) const;
27
28 u32 ioctl(u32 command, const std::vector<u8>& input, std::vector<u8>& output) override;
29private:
30 // Represents an nvmap object.
31 struct Object {
32 enum class Status { Created, Allocated };
33 u32 id;
34 u32 size;
35 u32 flags;
36 u32 align;
37 u8 kind;
38 VAddr addr;
39 Status status;
40 };
41
42 u32 next_handle = 1;
43 u32 next_id = 1;
44 std::unordered_map<u32, std::shared_ptr<Object>> handles;
45
46 enum IoctlCommands {
47 IocCreateCommand = 0xC0080101,
48 IocFromIdCommand = 0xC0080103,
49 IocAllocCommand = 0xC0200104,
50 IocParamCommand = 0xC00C0109,
51 IocGetIdCommand = 0xC008010E
52 };
53
54 struct IocCreateParams {
55 // Input
56 u32_le size;
57 // Output
58 u32_le handle;
59 };
60
61 struct IocAllocParams {
62 // Input
63 u32_le handle;
64 u32_le heap_mask;
65 u32_le flags;
66 u32_le align;
67 u8 kind;
68 INSERT_PADDING_BYTES(7);
69 u64_le addr;
70 };
71
72 struct IocGetIdParams {
73 // Output
74 u32_le id;
75 // Input
76 u32_le handle;
77 };
78
79 struct IocFromIdParams {
80 // Input
81 u32_le id;
82 // Output
83 u32_le handle;
84 };
85
86 struct IocParamParams {
87 // Input
88 u32_le handle;
89 u32_le type;
90 // Output
91 u32_le value;
92 };
93
94 u32 IocCreate(const std::vector<u8>& input, std::vector<u8>& output);
95 u32 IocAlloc(const std::vector<u8>& input, std::vector<u8>& output);
96 u32 IocGetId(const std::vector<u8>& input, std::vector<u8>& output);
97 u32 IocFromId(const std::vector<u8>& input, std::vector<u8>& output);
98 u32 IocParam(const std::vector<u8>& input, std::vector<u8>& output);
99};
100
101class nvdisp_disp0 : public nvdevice {
102public:
103 nvdisp_disp0(std::shared_ptr<nvmap> nvmap_dev) : nvdevice(), nvmap_dev(std::move(nvmap_dev)) {}
104 ~nvdisp_disp0() = default;
105
106 u32 ioctl(u32 command, const std::vector<u8>& input, std::vector<u8>& output) override;
107
108 /// Performs a screen flip, drawing the buffer pointed to by the handle.
109 void flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u32 height, u32 stride);
110
111private:
112 std::shared_ptr<nvmap> nvmap_dev;
113};
114
21/// Registers all NVDRV services with the specified service manager. 115/// Registers all NVDRV services with the specified service manager.
22void InstallInterfaces(SM::ServiceManager& service_manager); 116void InstallInterfaces(SM::ServiceManager& service_manager);
23 117
diff --git a/src/core/hle/service/nvdrv/nvdrv_a.cpp b/src/core/hle/service/nvdrv/nvdrv_a.cpp
index af6b7f7aa..cede4a883 100644
--- a/src/core/hle/service/nvdrv/nvdrv_a.cpp
+++ b/src/core/hle/service/nvdrv/nvdrv_a.cpp
@@ -18,202 +18,156 @@ public:
18 } 18 }
19}; 19};
20 20
21class nvmap : public nvdevice { 21VAddr nvmap::GetObjectAddress(u32 handle) const {
22public: 22 auto itr = handles.find(handle);
23 u32 ioctl(u32 command, const std::vector<u8>& input, std::vector<u8>& output) override { 23 ASSERT(itr != handles.end());
24 switch (command) {
25 case IocCreateCommand:
26 return IocCreate(input, output);
27 case IocAllocCommand:
28 return IocAlloc(input, output);
29 case IocGetIdCommand:
30 return IocGetId(input, output);
31 case IocFromIdCommand:
32 return IocFromId(input, output);
33 case IocParamCommand:
34 return IocParam(input, output);
35 }
36 24
37 ASSERT(false, "Unimplemented"); 25 auto object = itr->second;
26 ASSERT(object->status == Object::Status::Allocated);
27 return object->addr;
28}
29
30u32 nvmap::ioctl(u32 command, const std::vector<u8>& input, std::vector<u8>& output) {
31 switch (command) {
32 case IocCreateCommand:
33 return IocCreate(input, output);
34 case IocAllocCommand:
35 return IocAlloc(input, output);
36 case IocGetIdCommand:
37 return IocGetId(input, output);
38 case IocFromIdCommand:
39 return IocFromId(input, output);
40 case IocParamCommand:
41 return IocParam(input, output);
38 } 42 }
39 43
40private: 44 ASSERT(false, "Unimplemented");
41 // Represents an nvmap object. 45}
42 struct Object {
43 enum class Status { Created, Allocated };
44 u32 id;
45 u32 size;
46 u32 flags;
47 u32 align;
48 u8 kind;
49 u64 addr;
50 Status status;
51 };
52 46
53 u32 next_handle = 1; 47u32 nvmap::IocCreate(const std::vector<u8>& input, std::vector<u8>& output) {
54 u32 next_id = 1; 48 IocCreateParams params;
55 std::unordered_map<u32, std::shared_ptr<Object>> handles; 49 std::memcpy(&params, input.data(), sizeof(params));
56 50
57 enum IoctlCommands { 51 // Create a new nvmap object and obtain a handle to it.
58 IocCreateCommand = 0xC0080101, 52 auto object = std::make_shared<Object>();
59 IocFromIdCommand = 0xC0080103, 53 object->id = next_id++;
60 IocAllocCommand = 0xC0200104, 54 object->size = params.size;
61 IocParamCommand = 0xC00C0109, 55 object->status = Object::Status::Created;
62 IocGetIdCommand = 0xC008010E
63 };
64 56
65 struct IocCreateParams { 57 u32 handle = next_handle++;
66 // Input 58 handles[handle] = std::move(object);
67 u32_le size;
68 // Output
69 u32_le handle;
70 };
71 59
72 struct IocAllocParams { 60 LOG_WARNING(Service, "(STUBBED) size 0x%08X", params.size);
73 // Input
74 u32_le handle;
75 u32_le heap_mask;
76 u32_le flags;
77 u32_le align;
78 u8 kind;
79 INSERT_PADDING_BYTES(7);
80 u64_le addr;
81 };
82 61
83 struct IocGetIdParams { 62 params.handle = handle;
84 // Output
85 u32_le id;
86 // Input
87 u32_le handle;
88 };
89 63
90 struct IocFromIdParams { 64 std::memcpy(output.data(), &params, sizeof(params));
91 // Input 65 return 0;
92 u32_le id; 66}
93 // Output
94 u32_le handle;
95 };
96 67
97 struct IocParamParams { 68u32 nvmap::IocAlloc(const std::vector<u8>& input, std::vector<u8>& output) {
98 // Input 69 IocAllocParams params;
99 u32_le handle; 70 std::memcpy(&params, input.data(), sizeof(params));
100 u32_le type;
101 // Output
102 u32_le value;
103 };
104 71
105 u32 IocCreate(const std::vector<u8>& input, std::vector<u8>& output) { 72 auto itr = handles.find(params.handle);
106 IocCreateParams params; 73 ASSERT(itr != handles.end());
107 std::memcpy(&params, input.data(), sizeof(params));
108 74
109 // Create a new nvmap object and obtain a handle to it. 75 auto object = itr->second;
110 auto object = std::make_shared<Object>(); 76 object->flags = params.flags;
111 object->id = next_id++; 77 object->align = params.align;
112 object->size = params.size; 78 object->kind = params.kind;
113 object->status = Object::Status::Created; 79 object->addr = params.addr;
80 object->status = Object::Status::Allocated;
114 81
115 u32 handle = next_handle++; 82 LOG_WARNING(Service, "(STUBBED) Allocated address 0x%llx", params.addr);
116 handles[handle] = std::move(object);
117 83
118 LOG_WARNING(Service, "(STUBBED) size 0x%08X", params.size); 84 std::memcpy(output.data(), &params, sizeof(params));
85 return 0;
86}
119 87
120 params.handle = handle; 88u32 nvmap::IocGetId(const std::vector<u8>& input, std::vector<u8>& output) {
89 IocGetIdParams params;
90 std::memcpy(&params, input.data(), sizeof(params));
121 91
122 std::memcpy(output.data(), &params, sizeof(params)); 92 LOG_WARNING(Service, "called");
123 return 0;
124 }
125 93
126 u32 IocAlloc(const std::vector<u8>& input, std::vector<u8>& output) { 94 auto itr = handles.find(params.handle);
127 IocAllocParams params; 95 ASSERT(itr != handles.end());
128 std::memcpy(&params, input.data(), sizeof(params));
129 96
130 auto itr = handles.find(params.handle); 97 params.id = itr->second->id;
131 ASSERT(itr != handles.end());
132 98
133 auto object = itr->second; 99 std::memcpy(output.data(), &params, sizeof(params));
134 object->flags = params.flags; 100 return 0;
135 object->align = params.align; 101}
136 object->kind = params.kind;
137 object->addr = params.addr;
138 object->status = Object::Status::Allocated;
139 102
140 LOG_WARNING(Service, "(STUBBED) Allocated address 0x%llx", params.addr); 103u32 nvmap::IocFromId(const std::vector<u8>& input, std::vector<u8>& output) {
104 IocFromIdParams params;
105 std::memcpy(&params, input.data(), sizeof(params));
141 106
142 std::memcpy(output.data(), &params, sizeof(params)); 107 LOG_WARNING(Service, "(STUBBED) called");
143 return 0;
144 }
145 108
146 u32 IocGetId(const std::vector<u8>& input, std::vector<u8>& output) { 109 auto itr = std::find_if(handles.begin(), handles.end(),
147 IocGetIdParams params; 110 [&](const auto& entry) { return entry.second->id == params.id; });
148 std::memcpy(&params, input.data(), sizeof(params)); 111 ASSERT(itr != handles.end());
149 112
150 LOG_WARNING(Service, "called"); 113 // Make a new handle for the object
114 u32 handle = next_handle++;
115 handles[handle] = itr->second;
151 116
152 auto itr = handles.find(params.handle); 117 params.handle = handle;
153 ASSERT(itr != handles.end());
154 118
155 params.id = itr->second->id; 119 std::memcpy(output.data(), &params, sizeof(params));
120 return 0;
121}
156 122
157 std::memcpy(output.data(), &params, sizeof(params)); 123u32 nvmap::IocParam(const std::vector<u8>& input, std::vector<u8>& output) {
158 return 0; 124 enum class ParamTypes { Size = 1, Alignment = 2, Base = 3, Heap = 4, Kind = 5, Compr = 6 };
125
126 IocParamParams params;
127 std::memcpy(&params, input.data(), sizeof(params));
128
129 LOG_WARNING(Service, "(STUBBED) called type=%u", params.type);
130
131 auto itr = handles.find(params.handle);
132 ASSERT(itr != handles.end());
133
134 auto object = itr->second;
135 ASSERT(object->status == Object::Status::Allocated);
136
137 switch (static_cast<ParamTypes>(params.type)) {
138 case ParamTypes::Size:
139 params.value = object->size;
140 break;
141 case ParamTypes::Alignment:
142 params.value = object->align;
143 break;
144 case ParamTypes::Heap:
145 // TODO(Subv): Seems to be a hardcoded value?
146 params.value = 0x40000000;
147 break;
148 case ParamTypes::Kind:
149 params.value = object->kind;
150 break;
151 default:
152 ASSERT(false, "Unimplemented");
159 } 153 }
160 154
161 u32 IocFromId(const std::vector<u8>& input, std::vector<u8>& output) { 155 std::memcpy(output.data(), &params, sizeof(params));
162 IocFromIdParams params; 156 return 0;
163 std::memcpy(&params, input.data(), sizeof(params)); 157}
164
165 LOG_WARNING(Service, "(STUBBED) called");
166
167 auto itr = std::find_if(handles.begin(), handles.end(),
168 [&](const auto& entry) { return entry.second->id == params.id; });
169 ASSERT(itr != handles.end());
170
171 // Make a new handle for the object
172 u32 handle = next_handle++;
173 handles[handle] = itr->second;
174
175 params.handle = handle;
176 158
177 std::memcpy(output.data(), &params, sizeof(params)); 159u32 nvdisp_disp0::ioctl(u32 command, const std::vector<u8>& input, std::vector<u8>& output) {
178 return 0; 160 ASSERT(false, "Unimplemented");
179 } 161 return 0;
162}
180 163
181 u32 IocParam(const std::vector<u8>& input, std::vector<u8>& output) { 164void nvdisp_disp0::flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u32 height,
182 enum class ParamTypes { Size = 1, Alignment = 2, Base = 3, Heap = 4, Kind = 5, Compr = 6 }; 165 u32 stride) {
183 166 VAddr addr = nvmap_dev->GetObjectAddress(buffer_handle);
184 IocParamParams params; 167 LOG_WARNING(Service,
185 std::memcpy(&params, input.data(), sizeof(params)); 168 "Drawing from address %llx offset %08X Width %u Height %u Stride %u Format %u",
186 169 addr, offset, width, height, stride, format);
187 LOG_WARNING(Service, "(STUBBED) called type=%u", params.type); 170}
188
189 auto itr = handles.find(params.handle);
190 ASSERT(itr != handles.end());
191
192 auto object = itr->second;
193 ASSERT(object->status == Object::Status::Allocated);
194
195 switch (static_cast<ParamTypes>(params.type)) {
196 case ParamTypes::Size:
197 params.value = object->size;
198 break;
199 case ParamTypes::Alignment:
200 params.value = object->align;
201 break;
202 case ParamTypes::Heap:
203 // TODO(Subv): Seems to be a hardcoded value?
204 params.value = 0x40000000;
205 break;
206 case ParamTypes::Kind:
207 params.value = object->kind;
208 break;
209 default:
210 ASSERT(false, "Unimplemented");
211 }
212
213 std::memcpy(output.data(), &params, sizeof(params));
214 return 0;
215 }
216};
217 171
218void NVDRV_A::Open(Kernel::HLERequestContext& ctx) { 172void NVDRV_A::Open(Kernel::HLERequestContext& ctx) {
219 LOG_WARNING(Service, "(STUBBED) called"); 173 LOG_WARNING(Service, "(STUBBED) called");
@@ -275,8 +229,10 @@ NVDRV_A::NVDRV_A() : ServiceFramework("nvdrv:a") {
275 }; 229 };
276 RegisterHandlers(functions); 230 RegisterHandlers(functions);
277 231
232 auto nvmap_dev = std::make_shared<nvmap>();
278 devices["/dev/nvhost-as-gpu"] = std::make_shared<nvhost_as_gpu>(); 233 devices["/dev/nvhost-as-gpu"] = std::make_shared<nvhost_as_gpu>();
279 devices["/dev/nvmap"] = std::make_shared<nvmap>(); 234 devices["/dev/nvmap"] = nvmap_dev;
235 devices["/dev/nvdisp_disp0"] = std::make_shared<nvdisp_disp0>(nvmap_dev);
280} 236}
281 237
282} // namespace NVDRV 238} // namespace NVDRV
diff --git a/src/core/hle/service/nvdrv/nvdrv_a.h b/src/core/hle/service/nvdrv/nvdrv_a.h
index 09522a486..af1017881 100644
--- a/src/core/hle/service/nvdrv/nvdrv_a.h
+++ b/src/core/hle/service/nvdrv/nvdrv_a.h
@@ -4,8 +4,9 @@
4 4
5#pragma once 5#pragma once
6 6
7#include "core/hle/service/service.h"
8#include <memory> 7#include <memory>
8#include "core/hle/service/service.h"
9#include "core/hle/service/nvdrv/nvdrv.h"
9 10
10namespace Service { 11namespace Service {
11namespace NVDRV { 12namespace NVDRV {
@@ -15,6 +16,15 @@ public:
15 NVDRV_A(); 16 NVDRV_A();
16 ~NVDRV_A() = default; 17 ~NVDRV_A() = default;
17 18
19 /// Returns a pointer to one of the available devices, identified by its name.
20 template <typename T>
21 std::shared_ptr<T> GetDevice(std::string name) {
22 auto itr = devices.find(name);
23 if (itr == devices.end())
24 return nullptr;
25 return std::static_pointer_cast<T>(itr->second);
26 }
27
18private: 28private:
19 void Open(Kernel::HLERequestContext& ctx); 29 void Open(Kernel::HLERequestContext& ctx);
20 void Ioctl(Kernel::HLERequestContext& ctx); 30 void Ioctl(Kernel::HLERequestContext& ctx);
@@ -26,5 +36,7 @@ private:
26 std::unordered_map<std::string, std::shared_ptr<nvdevice>> devices; 36 std::unordered_map<std::string, std::shared_ptr<nvdevice>> devices;
27}; 37};
28 38
39extern std::weak_ptr<NVDRV_A> nvdrv_a;
40
29} // namespace NVDRV 41} // namespace NVDRV
30} // namespace Service 42} // namespace Service
diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp
index 67d82c2bf..56aafe6bf 100644
--- a/src/core/hle/service/vi/vi.cpp
+++ b/src/core/hle/service/vi/vi.cpp
@@ -6,6 +6,7 @@
6#include "common/scope_exit.h" 6#include "common/scope_exit.h"
7#include "core/core_timing.h" 7#include "core/core_timing.h"
8#include "core/hle/ipc_helpers.h" 8#include "core/hle/ipc_helpers.h"
9#include "core/hle/service/nvdrv/nvdrv_a.h"
9#include "core/hle/service/vi/vi.h" 10#include "core/hle/service/vi/vi.h"
10#include "core/hle/service/vi/vi_m.h" 11#include "core/hle/service/vi/vi_m.h"
11 12
@@ -743,7 +744,19 @@ void NVFlinger::Compose() {
743 continue; 744 continue;
744 } 745 }
745 746
746 // TODO(Subv): Send the buffer to the GPU for drawing. 747 auto& igbp_buffer = buffer->igbp_buffer;
748
749 // Now send the buffer to the GPU for drawing.
750 auto nvdrv = NVDRV::nvdrv_a.lock();
751 ASSERT(nvdrv);
752
753 // TODO(Subv): Support more than just disp0. The display device selection is probably based
754 // on which display we're drawing (Default, Internal, External, etc)
755 auto nvdisp = nvdrv->GetDevice<NVDRV::nvdisp_disp0>("/dev/nvdisp_disp0");
756 ASSERT(nvdisp);
757
758 nvdisp->flip(igbp_buffer.gpu_buffer_id, igbp_buffer.offset, igbp_buffer.format,
759 igbp_buffer.width, igbp_buffer.height, igbp_buffer.stride);
747 760
748 buffer_queue->ReleaseBuffer(buffer->slot); 761 buffer_queue->ReleaseBuffer(buffer->slot);
749 } 762 }
diff --git a/src/core/hle/service/vi/vi.h b/src/core/hle/service/vi/vi.h
index 576c4ce32..9604bd1c2 100644
--- a/src/core/hle/service/vi/vi.h
+++ b/src/core/hle/service/vi/vi.h
@@ -25,7 +25,8 @@ struct IGBPBuffer {
25 u32_le gpu_buffer_id; 25 u32_le gpu_buffer_id;
26 INSERT_PADDING_WORDS(17); 26 INSERT_PADDING_WORDS(17);
27 u32_le nvmap_handle; 27 u32_le nvmap_handle;
28 INSERT_PADDING_WORDS(61); 28 u32_le offset;
29 INSERT_PADDING_WORDS(60);
29}; 30};
30 31
31static_assert(sizeof(IGBPBuffer) == 0x16C, "IGBPBuffer has wrong size"); 32static_assert(sizeof(IGBPBuffer) == 0x16C, "IGBPBuffer has wrong size");