summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Subv2018-01-08 21:30:22 -0500
committerGravatar bunnei2018-01-10 23:28:29 -0500
commit34ae2ec644f49b04d6c6b82742812b6a8a3ef8b5 (patch)
treeb3b01b63dd0fa4fdc240a549257b685595f277cf
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.
-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");