diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/hle/service/vi/application_display_service.cpp | 456 | ||||
| -rw-r--r-- | src/core/hle/service/vi/application_display_service.h | 77 | ||||
| -rw-r--r-- | src/core/hle/service/vi/vi_types.h | 4 |
3 files changed, 228 insertions, 309 deletions
diff --git a/src/core/hle/service/vi/application_display_service.cpp b/src/core/hle/service/vi/application_display_service.cpp index ae0cb7a08..78229e30f 100644 --- a/src/core/hle/service/vi/application_display_service.cpp +++ b/src/core/hle/service/vi/application_display_service.cpp | |||
| @@ -1,8 +1,7 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project |
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | 2 | // SPDX-License-Identifier: GPL-2.0-or-later |
| 3 | 3 | ||
| 4 | #include "common/string_util.h" | 4 | #include "core/hle/service/cmif_serialization.h" |
| 5 | #include "core/hle/service/ipc_helpers.h" | ||
| 6 | #include "core/hle/service/nvnflinger/nvnflinger.h" | 5 | #include "core/hle/service/nvnflinger/nvnflinger.h" |
| 7 | #include "core/hle/service/nvnflinger/parcel.h" | 6 | #include "core/hle/service/nvnflinger/parcel.h" |
| 8 | #include "core/hle/service/vi/application_display_service.h" | 7 | #include "core/hle/service/vi/application_display_service.h" |
| @@ -14,406 +13,307 @@ | |||
| 14 | namespace Service::VI { | 13 | namespace Service::VI { |
| 15 | 14 | ||
| 16 | IApplicationDisplayService::IApplicationDisplayService( | 15 | IApplicationDisplayService::IApplicationDisplayService( |
| 17 | Core::System& system_, Nvnflinger::Nvnflinger& nvnflinger_, | 16 | Core::System& system_, Nvnflinger::Nvnflinger& nvnflinger, |
| 18 | Nvnflinger::HosBinderDriverServer& hos_binder_driver_server_) | 17 | Nvnflinger::HosBinderDriverServer& hos_binder_driver_server) |
| 19 | : ServiceFramework{system_, "IApplicationDisplayService"}, nvnflinger{nvnflinger_}, | 18 | : ServiceFramework{system_, "IApplicationDisplayService"}, m_nvnflinger{nvnflinger}, |
| 20 | hos_binder_driver_server{hos_binder_driver_server_} { | 19 | m_hos_binder_driver_server{hos_binder_driver_server} { |
| 21 | 20 | ||
| 21 | // clang-format off | ||
| 22 | static const FunctionInfo functions[] = { | 22 | static const FunctionInfo functions[] = { |
| 23 | {100, &IApplicationDisplayService::GetRelayService, "GetRelayService"}, | 23 | {100, C<&IApplicationDisplayService::GetRelayService>, "GetRelayService"}, |
| 24 | {101, &IApplicationDisplayService::GetSystemDisplayService, "GetSystemDisplayService"}, | 24 | {101, C<&IApplicationDisplayService::GetSystemDisplayService>, "GetSystemDisplayService"}, |
| 25 | {102, &IApplicationDisplayService::GetManagerDisplayService, "GetManagerDisplayService"}, | 25 | {102, C<&IApplicationDisplayService::GetManagerDisplayService>, "GetManagerDisplayService"}, |
| 26 | {103, &IApplicationDisplayService::GetIndirectDisplayTransactionService, | 26 | {103, C<&IApplicationDisplayService::GetIndirectDisplayTransactionService>, "GetIndirectDisplayTransactionService"}, |
| 27 | "GetIndirectDisplayTransactionService"}, | 27 | {1000, C<&IApplicationDisplayService::ListDisplays>, "ListDisplays"}, |
| 28 | {1000, &IApplicationDisplayService::ListDisplays, "ListDisplays"}, | 28 | {1010, C<&IApplicationDisplayService::OpenDisplay>, "OpenDisplay"}, |
| 29 | {1010, &IApplicationDisplayService::OpenDisplay, "OpenDisplay"}, | 29 | {1011, C<&IApplicationDisplayService::OpenDefaultDisplay>, "OpenDefaultDisplay"}, |
| 30 | {1011, &IApplicationDisplayService::OpenDefaultDisplay, "OpenDefaultDisplay"}, | 30 | {1020, C<&IApplicationDisplayService::CloseDisplay>, "CloseDisplay"}, |
| 31 | {1020, &IApplicationDisplayService::CloseDisplay, "CloseDisplay"}, | 31 | {1101, C<&IApplicationDisplayService::SetDisplayEnabled>, "SetDisplayEnabled"}, |
| 32 | {1101, &IApplicationDisplayService::SetDisplayEnabled, "SetDisplayEnabled"}, | 32 | {1102, C<&IApplicationDisplayService::GetDisplayResolution>, "GetDisplayResolution"}, |
| 33 | {1102, &IApplicationDisplayService::GetDisplayResolution, "GetDisplayResolution"}, | 33 | {2020, C<&IApplicationDisplayService::OpenLayer>, "OpenLayer"}, |
| 34 | {2020, &IApplicationDisplayService::OpenLayer, "OpenLayer"}, | 34 | {2021, C<&IApplicationDisplayService::CloseLayer>, "CloseLayer"}, |
| 35 | {2021, &IApplicationDisplayService::CloseLayer, "CloseLayer"}, | 35 | {2030, C<&IApplicationDisplayService::CreateStrayLayer>, "CreateStrayLayer"}, |
| 36 | {2030, &IApplicationDisplayService::CreateStrayLayer, "CreateStrayLayer"}, | 36 | {2031, C<&IApplicationDisplayService::DestroyStrayLayer>, "DestroyStrayLayer"}, |
| 37 | {2031, &IApplicationDisplayService::DestroyStrayLayer, "DestroyStrayLayer"}, | 37 | {2101, C<&IApplicationDisplayService::SetLayerScalingMode>, "SetLayerScalingMode"}, |
| 38 | {2101, &IApplicationDisplayService::SetLayerScalingMode, "SetLayerScalingMode"}, | 38 | {2102, C<&IApplicationDisplayService::ConvertScalingMode>, "ConvertScalingMode"}, |
| 39 | {2102, &IApplicationDisplayService::ConvertScalingMode, "ConvertScalingMode"}, | 39 | {2450, C<&IApplicationDisplayService::GetIndirectLayerImageMap>, "GetIndirectLayerImageMap"}, |
| 40 | {2450, &IApplicationDisplayService::GetIndirectLayerImageMap, "GetIndirectLayerImageMap"}, | ||
| 41 | {2451, nullptr, "GetIndirectLayerImageCropMap"}, | 40 | {2451, nullptr, "GetIndirectLayerImageCropMap"}, |
| 42 | {2460, &IApplicationDisplayService::GetIndirectLayerImageRequiredMemoryInfo, | 41 | {2460, C<&IApplicationDisplayService::GetIndirectLayerImageRequiredMemoryInfo>, "GetIndirectLayerImageRequiredMemoryInfo"}, |
| 43 | "GetIndirectLayerImageRequiredMemoryInfo"}, | 42 | {5202, C<&IApplicationDisplayService::GetDisplayVsyncEvent>, "GetDisplayVsyncEvent"}, |
| 44 | {5202, &IApplicationDisplayService::GetDisplayVsyncEvent, "GetDisplayVsyncEvent"}, | ||
| 45 | {5203, nullptr, "GetDisplayVsyncEventForDebug"}, | 43 | {5203, nullptr, "GetDisplayVsyncEventForDebug"}, |
| 46 | }; | 44 | }; |
| 45 | // clang-format on | ||
| 46 | |||
| 47 | RegisterHandlers(functions); | 47 | RegisterHandlers(functions); |
| 48 | } | 48 | } |
| 49 | 49 | ||
| 50 | IApplicationDisplayService::~IApplicationDisplayService() { | 50 | IApplicationDisplayService::~IApplicationDisplayService() { |
| 51 | for (const auto layer_id : stray_layer_ids) { | 51 | for (const auto layer_id : m_stray_layer_ids) { |
| 52 | nvnflinger.DestroyLayer(layer_id); | 52 | m_nvnflinger.DestroyLayer(layer_id); |
| 53 | } | 53 | } |
| 54 | } | 54 | } |
| 55 | 55 | ||
| 56 | void IApplicationDisplayService::GetRelayService(HLERequestContext& ctx) { | 56 | Result IApplicationDisplayService::GetRelayService( |
| 57 | Out<SharedPointer<IHOSBinderDriver>> out_relay_service) { | ||
| 57 | LOG_WARNING(Service_VI, "(STUBBED) called"); | 58 | LOG_WARNING(Service_VI, "(STUBBED) called"); |
| 58 | 59 | *out_relay_service = std::make_shared<IHOSBinderDriver>(system, m_hos_binder_driver_server); | |
| 59 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 60 | R_SUCCEED(); |
| 60 | rb.Push(ResultSuccess); | ||
| 61 | rb.PushIpcInterface<IHOSBinderDriver>(system, hos_binder_driver_server); | ||
| 62 | } | 61 | } |
| 63 | 62 | ||
| 64 | void IApplicationDisplayService::GetSystemDisplayService(HLERequestContext& ctx) { | 63 | Result IApplicationDisplayService::GetSystemDisplayService( |
| 64 | Out<SharedPointer<ISystemDisplayService>> out_system_display_service) { | ||
| 65 | LOG_WARNING(Service_VI, "(STUBBED) called"); | 65 | LOG_WARNING(Service_VI, "(STUBBED) called"); |
| 66 | 66 | *out_system_display_service = std::make_shared<ISystemDisplayService>(system, m_nvnflinger); | |
| 67 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 67 | R_SUCCEED(); |
| 68 | rb.Push(ResultSuccess); | ||
| 69 | rb.PushIpcInterface<ISystemDisplayService>(system, nvnflinger); | ||
| 70 | } | 68 | } |
| 71 | 69 | ||
| 72 | void IApplicationDisplayService::GetManagerDisplayService(HLERequestContext& ctx) { | 70 | Result IApplicationDisplayService::GetManagerDisplayService( |
| 71 | Out<SharedPointer<IManagerDisplayService>> out_manager_display_service) { | ||
| 73 | LOG_WARNING(Service_VI, "(STUBBED) called"); | 72 | LOG_WARNING(Service_VI, "(STUBBED) called"); |
| 74 | 73 | *out_manager_display_service = std::make_shared<IManagerDisplayService>(system, m_nvnflinger); | |
| 75 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 74 | R_SUCCEED(); |
| 76 | rb.Push(ResultSuccess); | ||
| 77 | rb.PushIpcInterface<IManagerDisplayService>(system, nvnflinger); | ||
| 78 | } | 75 | } |
| 79 | 76 | ||
| 80 | void IApplicationDisplayService::GetIndirectDisplayTransactionService(HLERequestContext& ctx) { | 77 | Result IApplicationDisplayService::GetIndirectDisplayTransactionService( |
| 78 | Out<SharedPointer<IHOSBinderDriver>> out_indirect_display_transaction_service) { | ||
| 81 | LOG_WARNING(Service_VI, "(STUBBED) called"); | 79 | LOG_WARNING(Service_VI, "(STUBBED) called"); |
| 82 | 80 | *out_indirect_display_transaction_service = | |
| 83 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 81 | std::make_shared<IHOSBinderDriver>(system, m_hos_binder_driver_server); |
| 84 | rb.Push(ResultSuccess); | 82 | R_SUCCEED(); |
| 85 | rb.PushIpcInterface<IHOSBinderDriver>(system, hos_binder_driver_server); | ||
| 86 | } | 83 | } |
| 87 | 84 | ||
| 88 | void IApplicationDisplayService::OpenDisplay(HLERequestContext& ctx) { | 85 | Result IApplicationDisplayService::OpenDisplay(Out<u64> out_display_id, DisplayName display_name) { |
| 89 | LOG_WARNING(Service_VI, "(STUBBED) called"); | 86 | LOG_WARNING(Service_VI, "(STUBBED) called"); |
| 90 | 87 | ||
| 91 | IPC::RequestParser rp{ctx}; | 88 | display_name[display_name.size() - 1] = '\0'; |
| 92 | const auto name_buf = rp.PopRaw<std::array<char, 0x40>>(); | 89 | ASSERT_MSG(strcmp(display_name.data(), "Default") == 0, |
| 93 | 90 | "Non-default displays aren't supported yet"); | |
| 94 | OpenDisplayImpl(ctx, std::string_view{name_buf.data(), name_buf.size()}); | ||
| 95 | } | ||
| 96 | |||
| 97 | void IApplicationDisplayService::OpenDefaultDisplay(HLERequestContext& ctx) { | ||
| 98 | LOG_DEBUG(Service_VI, "called"); | ||
| 99 | 91 | ||
| 100 | OpenDisplayImpl(ctx, "Default"); | 92 | const auto display_id = m_nvnflinger.OpenDisplay(display_name.data()); |
| 101 | } | ||
| 102 | |||
| 103 | void IApplicationDisplayService::OpenDisplayImpl(HLERequestContext& ctx, std::string_view name) { | ||
| 104 | const auto trim_pos = name.find('\0'); | ||
| 105 | |||
| 106 | if (trim_pos != std::string_view::npos) { | ||
| 107 | name.remove_suffix(name.size() - trim_pos); | ||
| 108 | } | ||
| 109 | |||
| 110 | ASSERT_MSG(name == "Default", "Non-default displays aren't supported yet"); | ||
| 111 | |||
| 112 | const auto display_id = nvnflinger.OpenDisplay(name); | ||
| 113 | if (!display_id) { | 93 | if (!display_id) { |
| 114 | LOG_ERROR(Service_VI, "Display not found! display_name={}", name); | 94 | LOG_ERROR(Service_VI, "Display not found! display_name={}", display_name.data()); |
| 115 | IPC::ResponseBuilder rb{ctx, 2}; | 95 | R_THROW(VI::ResultNotFound); |
| 116 | rb.Push(ResultNotFound); | ||
| 117 | return; | ||
| 118 | } | 96 | } |
| 119 | 97 | ||
| 120 | IPC::ResponseBuilder rb{ctx, 4}; | 98 | *out_display_id = *display_id; |
| 121 | rb.Push(ResultSuccess); | 99 | R_SUCCEED(); |
| 122 | rb.Push<u64>(*display_id); | ||
| 123 | } | 100 | } |
| 124 | 101 | ||
| 125 | void IApplicationDisplayService::CloseDisplay(HLERequestContext& ctx) { | 102 | Result IApplicationDisplayService::OpenDefaultDisplay(Out<u64> out_display_id) { |
| 126 | IPC::RequestParser rp{ctx}; | 103 | LOG_DEBUG(Service_VI, "called"); |
| 127 | const u64 display_id = rp.Pop<u64>(); | 104 | R_RETURN(this->OpenDisplay(out_display_id, DisplayName{"Default"})); |
| 128 | |||
| 129 | const Result rc = nvnflinger.CloseDisplay(display_id) ? ResultSuccess : ResultUnknown; | ||
| 130 | |||
| 131 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 132 | rb.Push(rc); | ||
| 133 | } | 105 | } |
| 134 | 106 | ||
| 135 | // This literally does nothing internally in the actual service itself, | 107 | Result IApplicationDisplayService::CloseDisplay(u64 display_id) { |
| 136 | // and just returns a successful result code regardless of the input. | 108 | LOG_DEBUG(Service_VI, "called"); |
| 137 | void IApplicationDisplayService::SetDisplayEnabled(HLERequestContext& ctx) { | 109 | R_SUCCEED_IF(m_nvnflinger.CloseDisplay(display_id)); |
| 138 | LOG_DEBUG(Service_VI, "called."); | 110 | R_THROW(ResultUnknown); |
| 139 | |||
| 140 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 141 | rb.Push(ResultSuccess); | ||
| 142 | } | 111 | } |
| 143 | 112 | ||
| 144 | void IApplicationDisplayService::GetDisplayResolution(HLERequestContext& ctx) { | 113 | Result IApplicationDisplayService::SetDisplayEnabled(u32 state, u64 display_id) { |
| 145 | IPC::RequestParser rp{ctx}; | 114 | LOG_DEBUG(Service_VI, "called"); |
| 146 | const u64 display_id = rp.Pop<u64>(); | ||
| 147 | 115 | ||
| 148 | LOG_DEBUG(Service_VI, "called. display_id=0x{:016X}", display_id); | 116 | // This literally does nothing internally in the actual service itself, |
| 117 | // and just returns a successful result code regardless of the input. | ||
| 118 | R_SUCCEED(); | ||
| 119 | } | ||
| 149 | 120 | ||
| 150 | IPC::ResponseBuilder rb{ctx, 6}; | 121 | Result IApplicationDisplayService::GetDisplayResolution(Out<s64> out_width, Out<s64> out_height, |
| 151 | rb.Push(ResultSuccess); | 122 | u64 display_id) { |
| 123 | LOG_DEBUG(Service_VI, "called. display_id={}", display_id); | ||
| 152 | 124 | ||
| 153 | // This only returns the fixed values of 1280x720 and makes no distinguishing | 125 | // This only returns the fixed values of 1280x720 and makes no distinguishing |
| 154 | // between docked and undocked dimensions. We take the liberty of applying | 126 | // between docked and undocked dimensions. |
| 155 | // the resolution scaling factor here. | 127 | *out_width = static_cast<s64>(DisplayResolution::UndockedWidth); |
| 156 | rb.Push(static_cast<u64>(DisplayResolution::UndockedWidth)); | 128 | *out_height = static_cast<s64>(DisplayResolution::UndockedHeight); |
| 157 | rb.Push(static_cast<u64>(DisplayResolution::UndockedHeight)); | 129 | R_SUCCEED(); |
| 158 | } | 130 | } |
| 159 | 131 | ||
| 160 | void IApplicationDisplayService::SetLayerScalingMode(HLERequestContext& ctx) { | 132 | Result IApplicationDisplayService::SetLayerScalingMode(NintendoScaleMode scale_mode, u64 layer_id) { |
| 161 | IPC::RequestParser rp{ctx}; | 133 | LOG_DEBUG(Service_VI, "called. scale_mode={}, unknown=0x{:016X}", scale_mode, layer_id); |
| 162 | const auto scaling_mode = rp.PopEnum<NintendoScaleMode>(); | ||
| 163 | const u64 unknown = rp.Pop<u64>(); | ||
| 164 | |||
| 165 | LOG_DEBUG(Service_VI, "called. scaling_mode=0x{:08X}, unknown=0x{:016X}", scaling_mode, | ||
| 166 | unknown); | ||
| 167 | 134 | ||
| 168 | IPC::ResponseBuilder rb{ctx, 2}; | 135 | if (scale_mode > NintendoScaleMode::PreserveAspectRatio) { |
| 169 | |||
| 170 | if (scaling_mode > NintendoScaleMode::PreserveAspectRatio) { | ||
| 171 | LOG_ERROR(Service_VI, "Invalid scaling mode provided."); | 136 | LOG_ERROR(Service_VI, "Invalid scaling mode provided."); |
| 172 | rb.Push(ResultOperationFailed); | 137 | R_THROW(VI::ResultOperationFailed); |
| 173 | return; | ||
| 174 | } | 138 | } |
| 175 | 139 | ||
| 176 | if (scaling_mode != NintendoScaleMode::ScaleToWindow && | 140 | if (scale_mode != NintendoScaleMode::ScaleToWindow && |
| 177 | scaling_mode != NintendoScaleMode::PreserveAspectRatio) { | 141 | scale_mode != NintendoScaleMode::PreserveAspectRatio) { |
| 178 | LOG_ERROR(Service_VI, "Unsupported scaling mode supplied."); | 142 | LOG_ERROR(Service_VI, "Unsupported scaling mode supplied."); |
| 179 | rb.Push(ResultNotSupported); | 143 | R_THROW(VI::ResultNotSupported); |
| 180 | return; | ||
| 181 | } | 144 | } |
| 182 | 145 | ||
| 183 | rb.Push(ResultSuccess); | 146 | R_SUCCEED(); |
| 184 | } | 147 | } |
| 185 | 148 | ||
| 186 | void IApplicationDisplayService::ListDisplays(HLERequestContext& ctx) { | 149 | Result IApplicationDisplayService::ListDisplays( |
| 150 | Out<u64> out_count, OutArray<DisplayInfo, BufferAttr_HipcMapAlias> out_displays) { | ||
| 187 | LOG_WARNING(Service_VI, "(STUBBED) called"); | 151 | LOG_WARNING(Service_VI, "(STUBBED) called"); |
| 188 | 152 | ||
| 189 | const DisplayInfo display_info; | 153 | if (out_displays.size() > 0) { |
| 190 | ctx.WriteBuffer(&display_info, sizeof(DisplayInfo)); | 154 | out_displays[0] = DisplayInfo{}; |
| 191 | IPC::ResponseBuilder rb{ctx, 4}; | 155 | *out_count = 1; |
| 192 | rb.Push(ResultSuccess); | 156 | } else { |
| 193 | rb.Push<u64>(1); | 157 | *out_count = 0; |
| 194 | } | 158 | } |
| 195 | 159 | ||
| 196 | void IApplicationDisplayService::OpenLayer(HLERequestContext& ctx) { | 160 | R_SUCCEED(); |
| 197 | IPC::RequestParser rp{ctx}; | 161 | } |
| 198 | const auto name_buf = rp.PopRaw<std::array<u8, 0x40>>(); | ||
| 199 | const std::string display_name(Common::StringFromBuffer(name_buf)); | ||
| 200 | 162 | ||
| 201 | const u64 layer_id = rp.Pop<u64>(); | 163 | Result IApplicationDisplayService::OpenLayer(Out<u64> out_size, |
| 202 | const u64 aruid = rp.Pop<u64>(); | 164 | OutBuffer<BufferAttr_HipcMapAlias> out_native_window, |
| 165 | DisplayName display_name, u64 layer_id, | ||
| 166 | ClientAppletResourceUserId aruid) { | ||
| 167 | display_name[display_name.size() - 1] = '\0'; | ||
| 203 | 168 | ||
| 204 | LOG_DEBUG(Service_VI, "called. layer_id=0x{:016X}, aruid=0x{:016X}", layer_id, aruid); | 169 | LOG_DEBUG(Service_VI, "called. layer_id={}, aruid={:#x}", layer_id, aruid.pid); |
| 205 | 170 | ||
| 206 | const auto display_id = nvnflinger.OpenDisplay(display_name); | 171 | const auto display_id = m_nvnflinger.OpenDisplay(display_name.data()); |
| 207 | if (!display_id) { | 172 | if (!display_id) { |
| 208 | LOG_ERROR(Service_VI, "Layer not found! layer_id={}", layer_id); | 173 | LOG_ERROR(Service_VI, "Layer not found! layer_id={}", layer_id); |
| 209 | IPC::ResponseBuilder rb{ctx, 2}; | 174 | R_THROW(VI::ResultNotFound); |
| 210 | rb.Push(ResultNotFound); | ||
| 211 | return; | ||
| 212 | } | 175 | } |
| 213 | 176 | ||
| 214 | const auto buffer_queue_id = nvnflinger.FindBufferQueueId(*display_id, layer_id); | 177 | const auto buffer_queue_id = m_nvnflinger.FindBufferQueueId(*display_id, layer_id); |
| 215 | if (!buffer_queue_id) { | 178 | if (!buffer_queue_id) { |
| 216 | LOG_ERROR(Service_VI, "Buffer queue id not found! display_id={}", *display_id); | 179 | LOG_ERROR(Service_VI, "Buffer queue id not found! display_id={}", *display_id); |
| 217 | IPC::ResponseBuilder rb{ctx, 2}; | 180 | R_THROW(VI::ResultNotFound); |
| 218 | rb.Push(ResultNotFound); | ||
| 219 | return; | ||
| 220 | } | 181 | } |
| 221 | 182 | ||
| 222 | if (!nvnflinger.OpenLayer(layer_id)) { | 183 | if (!m_nvnflinger.OpenLayer(layer_id)) { |
| 223 | LOG_WARNING(Service_VI, "Tried to open layer which was already open"); | 184 | LOG_WARNING(Service_VI, "Tried to open layer which was already open"); |
| 224 | IPC::ResponseBuilder rb{ctx, 2}; | 185 | R_THROW(VI::ResultOperationFailed); |
| 225 | rb.Push(ResultOperationFailed); | ||
| 226 | return; | ||
| 227 | } | 186 | } |
| 228 | 187 | ||
| 229 | android::OutputParcel parcel; | 188 | android::OutputParcel parcel; |
| 230 | parcel.WriteInterface(NativeWindow{*buffer_queue_id}); | 189 | parcel.WriteInterface(NativeWindow{*buffer_queue_id}); |
| 231 | 190 | ||
| 232 | const auto buffer_size = ctx.WriteBuffer(parcel.Serialize()); | 191 | const auto buffer = parcel.Serialize(); |
| 192 | std::memcpy(out_native_window.data(), buffer.data(), | ||
| 193 | std::min(out_native_window.size(), buffer.size())); | ||
| 194 | *out_size = buffer.size(); | ||
| 233 | 195 | ||
| 234 | IPC::ResponseBuilder rb{ctx, 4}; | 196 | R_SUCCEED(); |
| 235 | rb.Push(ResultSuccess); | ||
| 236 | rb.Push<u64>(buffer_size); | ||
| 237 | } | 197 | } |
| 238 | 198 | ||
| 239 | void IApplicationDisplayService::CloseLayer(HLERequestContext& ctx) { | 199 | Result IApplicationDisplayService::CloseLayer(u64 layer_id) { |
| 240 | IPC::RequestParser rp{ctx}; | 200 | LOG_DEBUG(Service_VI, "called. layer_id={}", layer_id); |
| 241 | const auto layer_id{rp.Pop<u64>()}; | ||
| 242 | |||
| 243 | LOG_DEBUG(Service_VI, "called. layer_id=0x{:016X}", layer_id); | ||
| 244 | 201 | ||
| 245 | if (!nvnflinger.CloseLayer(layer_id)) { | 202 | if (!m_nvnflinger.CloseLayer(layer_id)) { |
| 246 | LOG_WARNING(Service_VI, "Tried to close layer which was not open"); | 203 | LOG_WARNING(Service_VI, "Tried to close layer which was not open"); |
| 247 | IPC::ResponseBuilder rb{ctx, 2}; | 204 | R_THROW(VI::ResultOperationFailed); |
| 248 | rb.Push(ResultOperationFailed); | ||
| 249 | return; | ||
| 250 | } | 205 | } |
| 251 | 206 | ||
| 252 | IPC::ResponseBuilder rb{ctx, 2}; | 207 | R_SUCCEED(); |
| 253 | rb.Push(ResultSuccess); | ||
| 254 | } | 208 | } |
| 255 | 209 | ||
| 256 | void IApplicationDisplayService::CreateStrayLayer(HLERequestContext& ctx) { | 210 | Result IApplicationDisplayService::CreateStrayLayer( |
| 257 | IPC::RequestParser rp{ctx}; | 211 | Out<u64> out_layer_id, Out<u64> out_size, OutBuffer<BufferAttr_HipcMapAlias> out_native_window, |
| 258 | const u32 flags = rp.Pop<u32>(); | 212 | u32 flags, u64 display_id) { |
| 259 | rp.Pop<u32>(); // padding | 213 | LOG_DEBUG(Service_VI, "called. flags={}, display_id={}", flags, display_id); |
| 260 | const u64 display_id = rp.Pop<u64>(); | ||
| 261 | 214 | ||
| 262 | LOG_DEBUG(Service_VI, "called. flags=0x{:08X}, display_id=0x{:016X}", flags, display_id); | 215 | const auto layer_id = m_nvnflinger.CreateLayer(display_id); |
| 263 | |||
| 264 | // TODO(Subv): What's the difference between a Stray and a Managed layer? | ||
| 265 | |||
| 266 | const auto layer_id = nvnflinger.CreateLayer(display_id); | ||
| 267 | if (!layer_id) { | 216 | if (!layer_id) { |
| 268 | LOG_ERROR(Service_VI, "Layer not found! display_id={}", display_id); | 217 | LOG_ERROR(Service_VI, "Layer not found! display_id={}", display_id); |
| 269 | IPC::ResponseBuilder rb{ctx, 2}; | 218 | R_THROW(VI::ResultNotFound); |
| 270 | rb.Push(ResultNotFound); | ||
| 271 | return; | ||
| 272 | } | 219 | } |
| 273 | 220 | ||
| 274 | stray_layer_ids.push_back(*layer_id); | 221 | m_stray_layer_ids.push_back(*layer_id); |
| 275 | const auto buffer_queue_id = nvnflinger.FindBufferQueueId(display_id, *layer_id); | 222 | const auto buffer_queue_id = m_nvnflinger.FindBufferQueueId(display_id, *layer_id); |
| 276 | if (!buffer_queue_id) { | 223 | if (!buffer_queue_id) { |
| 277 | LOG_ERROR(Service_VI, "Buffer queue id not found! display_id={}", display_id); | 224 | LOG_ERROR(Service_VI, "Buffer queue id not found! display_id={}", display_id); |
| 278 | IPC::ResponseBuilder rb{ctx, 2}; | 225 | R_THROW(VI::ResultNotFound); |
| 279 | rb.Push(ResultNotFound); | ||
| 280 | return; | ||
| 281 | } | 226 | } |
| 282 | 227 | ||
| 283 | android::OutputParcel parcel; | 228 | android::OutputParcel parcel; |
| 284 | parcel.WriteInterface(NativeWindow{*buffer_queue_id}); | 229 | parcel.WriteInterface(NativeWindow{*buffer_queue_id}); |
| 285 | 230 | ||
| 286 | const auto buffer_size = ctx.WriteBuffer(parcel.Serialize()); | 231 | const auto buffer = parcel.Serialize(); |
| 287 | 232 | std::memcpy(out_native_window.data(), buffer.data(), | |
| 288 | IPC::ResponseBuilder rb{ctx, 6}; | 233 | std::min(out_native_window.size(), buffer.size())); |
| 289 | rb.Push(ResultSuccess); | ||
| 290 | rb.Push(*layer_id); | ||
| 291 | rb.Push<u64>(buffer_size); | ||
| 292 | } | ||
| 293 | 234 | ||
| 294 | void IApplicationDisplayService::DestroyStrayLayer(HLERequestContext& ctx) { | 235 | *out_layer_id = *layer_id; |
| 295 | IPC::RequestParser rp{ctx}; | 236 | *out_size = buffer.size(); |
| 296 | const u64 layer_id = rp.Pop<u64>(); | ||
| 297 | 237 | ||
| 298 | LOG_WARNING(Service_VI, "(STUBBED) called. layer_id=0x{:016X}", layer_id); | 238 | R_SUCCEED(); |
| 299 | nvnflinger.DestroyLayer(layer_id); | ||
| 300 | |||
| 301 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 302 | rb.Push(ResultSuccess); | ||
| 303 | } | 239 | } |
| 304 | 240 | ||
| 305 | void IApplicationDisplayService::GetDisplayVsyncEvent(HLERequestContext& ctx) { | 241 | Result IApplicationDisplayService::DestroyStrayLayer(u64 layer_id) { |
| 306 | IPC::RequestParser rp{ctx}; | 242 | LOG_WARNING(Service_VI, "(STUBBED) called. layer_id={}", layer_id); |
| 307 | const u64 display_id = rp.Pop<u64>(); | 243 | m_nvnflinger.DestroyLayer(layer_id); |
| 244 | R_SUCCEED(); | ||
| 245 | } | ||
| 308 | 246 | ||
| 247 | Result IApplicationDisplayService::GetDisplayVsyncEvent( | ||
| 248 | OutCopyHandle<Kernel::KReadableEvent> out_vsync_event, u64 display_id) { | ||
| 309 | LOG_DEBUG(Service_VI, "called. display_id={}", display_id); | 249 | LOG_DEBUG(Service_VI, "called. display_id={}", display_id); |
| 310 | 250 | ||
| 311 | Kernel::KReadableEvent* vsync_event{}; | 251 | const auto result = m_nvnflinger.FindVsyncEvent(out_vsync_event, display_id); |
| 312 | const auto result = nvnflinger.FindVsyncEvent(&vsync_event, display_id); | ||
| 313 | if (result != ResultSuccess) { | 252 | if (result != ResultSuccess) { |
| 314 | if (result == ResultNotFound) { | 253 | if (result == ResultNotFound) { |
| 315 | LOG_ERROR(Service_VI, "Vsync event was not found for display_id={}", display_id); | 254 | LOG_ERROR(Service_VI, "Vsync event was not found for display_id={}", display_id); |
| 316 | } | 255 | } |
| 317 | 256 | ||
| 318 | IPC::ResponseBuilder rb{ctx, 2}; | 257 | R_THROW(result); |
| 319 | rb.Push(result); | ||
| 320 | return; | ||
| 321 | } | ||
| 322 | if (vsync_event_fetched) { | ||
| 323 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 324 | rb.Push(VI::ResultPermissionDenied); | ||
| 325 | return; | ||
| 326 | } | 258 | } |
| 327 | vsync_event_fetched = true; | ||
| 328 | 259 | ||
| 329 | IPC::ResponseBuilder rb{ctx, 2, 1}; | 260 | R_UNLESS(!m_vsync_event_fetched, VI::ResultPermissionDenied); |
| 330 | rb.Push(ResultSuccess); | 261 | m_vsync_event_fetched = true; |
| 331 | rb.PushCopyObjects(vsync_event); | ||
| 332 | } | ||
| 333 | 262 | ||
| 334 | void IApplicationDisplayService::ConvertScalingMode(HLERequestContext& ctx) { | 263 | R_SUCCEED(); |
| 335 | IPC::RequestParser rp{ctx}; | ||
| 336 | const auto mode = rp.PopEnum<NintendoScaleMode>(); | ||
| 337 | LOG_DEBUG(Service_VI, "called mode={}", mode); | ||
| 338 | |||
| 339 | ConvertedScaleMode converted_mode{}; | ||
| 340 | const auto result = ConvertScalingModeImpl(&converted_mode, mode); | ||
| 341 | |||
| 342 | if (result == ResultSuccess) { | ||
| 343 | IPC::ResponseBuilder rb{ctx, 4}; | ||
| 344 | rb.Push(ResultSuccess); | ||
| 345 | rb.PushEnum(converted_mode); | ||
| 346 | } else { | ||
| 347 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 348 | rb.Push(result); | ||
| 349 | } | ||
| 350 | } | 264 | } |
| 351 | 265 | ||
| 352 | void IApplicationDisplayService::GetIndirectLayerImageMap(HLERequestContext& ctx) { | 266 | Result IApplicationDisplayService::ConvertScalingMode(Out<ConvertedScaleMode> out_scaling_mode, |
| 353 | IPC::RequestParser rp{ctx}; | 267 | NintendoScaleMode mode) { |
| 354 | const auto width = rp.Pop<s64>(); | 268 | LOG_DEBUG(Service_VI, "called mode={}", mode); |
| 355 | const auto height = rp.Pop<s64>(); | ||
| 356 | const auto indirect_layer_consumer_handle = rp.Pop<u64>(); | ||
| 357 | const auto applet_resource_user_id = rp.Pop<u64>(); | ||
| 358 | |||
| 359 | LOG_WARNING(Service_VI, | ||
| 360 | "(STUBBED) called, width={}, height={}, indirect_layer_consumer_handle={}, " | ||
| 361 | "applet_resource_user_id={}", | ||
| 362 | width, height, indirect_layer_consumer_handle, applet_resource_user_id); | ||
| 363 | |||
| 364 | std::vector<u8> out_buffer(0x46); | ||
| 365 | ctx.WriteBuffer(out_buffer); | ||
| 366 | |||
| 367 | // TODO: Figure out what these are | ||
| 368 | |||
| 369 | constexpr s64 unknown_result_1 = 0; | ||
| 370 | constexpr s64 unknown_result_2 = 0; | ||
| 371 | |||
| 372 | IPC::ResponseBuilder rb{ctx, 6}; | ||
| 373 | rb.Push(unknown_result_1); | ||
| 374 | rb.Push(unknown_result_2); | ||
| 375 | rb.Push(ResultSuccess); | ||
| 376 | } | ||
| 377 | |||
| 378 | void IApplicationDisplayService::GetIndirectLayerImageRequiredMemoryInfo(HLERequestContext& ctx) { | ||
| 379 | IPC::RequestParser rp{ctx}; | ||
| 380 | const auto width = rp.Pop<u64>(); | ||
| 381 | const auto height = rp.Pop<u64>(); | ||
| 382 | LOG_DEBUG(Service_VI, "called width={}, height={}", width, height); | ||
| 383 | |||
| 384 | constexpr u64 base_size = 0x20000; | ||
| 385 | constexpr u64 alignment = 0x1000; | ||
| 386 | const auto texture_size = width * height * 4; | ||
| 387 | const auto out_size = (texture_size + base_size - 1) / base_size * base_size; | ||
| 388 | |||
| 389 | IPC::ResponseBuilder rb{ctx, 6}; | ||
| 390 | rb.Push(ResultSuccess); | ||
| 391 | rb.Push(out_size); | ||
| 392 | rb.Push(alignment); | ||
| 393 | } | ||
| 394 | 269 | ||
| 395 | Result IApplicationDisplayService::ConvertScalingModeImpl(ConvertedScaleMode* out_scaling_mode, | ||
| 396 | NintendoScaleMode mode) { | ||
| 397 | switch (mode) { | 270 | switch (mode) { |
| 398 | case NintendoScaleMode::None: | 271 | case NintendoScaleMode::None: |
| 399 | *out_scaling_mode = ConvertedScaleMode::None; | 272 | *out_scaling_mode = ConvertedScaleMode::None; |
| 400 | return ResultSuccess; | 273 | R_SUCCEED(); |
| 401 | case NintendoScaleMode::Freeze: | 274 | case NintendoScaleMode::Freeze: |
| 402 | *out_scaling_mode = ConvertedScaleMode::Freeze; | 275 | *out_scaling_mode = ConvertedScaleMode::Freeze; |
| 403 | return ResultSuccess; | 276 | R_SUCCEED(); |
| 404 | case NintendoScaleMode::ScaleToWindow: | 277 | case NintendoScaleMode::ScaleToWindow: |
| 405 | *out_scaling_mode = ConvertedScaleMode::ScaleToWindow; | 278 | *out_scaling_mode = ConvertedScaleMode::ScaleToWindow; |
| 406 | return ResultSuccess; | 279 | R_SUCCEED(); |
| 407 | case NintendoScaleMode::ScaleAndCrop: | 280 | case NintendoScaleMode::ScaleAndCrop: |
| 408 | *out_scaling_mode = ConvertedScaleMode::ScaleAndCrop; | 281 | *out_scaling_mode = ConvertedScaleMode::ScaleAndCrop; |
| 409 | return ResultSuccess; | 282 | R_SUCCEED(); |
| 410 | case NintendoScaleMode::PreserveAspectRatio: | 283 | case NintendoScaleMode::PreserveAspectRatio: |
| 411 | *out_scaling_mode = ConvertedScaleMode::PreserveAspectRatio; | 284 | *out_scaling_mode = ConvertedScaleMode::PreserveAspectRatio; |
| 412 | return ResultSuccess; | 285 | R_SUCCEED(); |
| 413 | default: | 286 | default: |
| 414 | LOG_ERROR(Service_VI, "Invalid scaling mode specified, mode={}", mode); | 287 | LOG_ERROR(Service_VI, "Invalid scaling mode specified, mode={}", mode); |
| 415 | return ResultOperationFailed; | 288 | R_THROW(VI::ResultOperationFailed); |
| 416 | } | 289 | } |
| 417 | } | 290 | } |
| 418 | 291 | ||
| 292 | Result IApplicationDisplayService::GetIndirectLayerImageMap( | ||
| 293 | Out<u64> out_size, Out<u64> out_stride, | ||
| 294 | OutBuffer<BufferAttr_HipcMapTransferAllowsNonSecure | BufferAttr_HipcMapAlias> out_buffer, | ||
| 295 | s64 width, s64 height, u64 indirect_layer_consumer_handle, ClientAppletResourceUserId aruid) { | ||
| 296 | LOG_WARNING( | ||
| 297 | Service_VI, | ||
| 298 | "(STUBBED) called, width={}, height={}, indirect_layer_consumer_handle={}, aruid={:#x}", | ||
| 299 | width, height, indirect_layer_consumer_handle, aruid.pid); | ||
| 300 | *out_size = 0; | ||
| 301 | *out_stride = 0; | ||
| 302 | R_SUCCEED(); | ||
| 303 | } | ||
| 304 | |||
| 305 | Result IApplicationDisplayService::GetIndirectLayerImageRequiredMemoryInfo(Out<s64> out_size, | ||
| 306 | Out<s64> out_alignment, | ||
| 307 | s64 width, s64 height) { | ||
| 308 | LOG_DEBUG(Service_VI, "called width={}, height={}", width, height); | ||
| 309 | |||
| 310 | constexpr u64 base_size = 0x20000; | ||
| 311 | const auto texture_size = width * height * 4; | ||
| 312 | |||
| 313 | *out_alignment = 0x1000; | ||
| 314 | *out_size = (texture_size + base_size - 1) / base_size * base_size; | ||
| 315 | |||
| 316 | R_SUCCEED(); | ||
| 317 | } | ||
| 318 | |||
| 419 | } // namespace Service::VI | 319 | } // namespace Service::VI |
diff --git a/src/core/hle/service/vi/application_display_service.h b/src/core/hle/service/vi/application_display_service.h index 51ae2c472..5dff4bb31 100644 --- a/src/core/hle/service/vi/application_display_service.h +++ b/src/core/hle/service/vi/application_display_service.h | |||
| @@ -1,48 +1,65 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project |
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | 2 | // SPDX-License-Identifier: GPL-2.0-or-later |
| 3 | 3 | ||
| 4 | #include "core/hle/service/cmif_types.h" | ||
| 4 | #include "core/hle/service/service.h" | 5 | #include "core/hle/service/service.h" |
| 5 | #include "core/hle/service/vi/vi_types.h" | 6 | #include "core/hle/service/vi/vi_types.h" |
| 6 | 7 | ||
| 8 | namespace Kernel { | ||
| 9 | class KReadableEvent; | ||
| 10 | } | ||
| 11 | |||
| 7 | namespace Service::VI { | 12 | namespace Service::VI { |
| 8 | 13 | ||
| 14 | class IHOSBinderDriver; | ||
| 15 | class IManagerDisplayService; | ||
| 16 | class ISystemDisplayService; | ||
| 17 | |||
| 9 | class IApplicationDisplayService final : public ServiceFramework<IApplicationDisplayService> { | 18 | class IApplicationDisplayService final : public ServiceFramework<IApplicationDisplayService> { |
| 10 | public: | 19 | public: |
| 11 | IApplicationDisplayService(Core::System& system_, Nvnflinger::Nvnflinger& nvnflinger_, | 20 | IApplicationDisplayService(Core::System& system_, Nvnflinger::Nvnflinger& nvnflinger, |
| 12 | Nvnflinger::HosBinderDriverServer& hos_binder_driver_server_); | 21 | Nvnflinger::HosBinderDriverServer& hos_binder_driver_server); |
| 13 | ~IApplicationDisplayService() override; | 22 | ~IApplicationDisplayService() override; |
| 14 | 23 | ||
| 15 | private: | 24 | private: |
| 16 | void GetRelayService(HLERequestContext& ctx); | 25 | Result GetRelayService(Out<SharedPointer<IHOSBinderDriver>> out_relay_service); |
| 17 | void GetSystemDisplayService(HLERequestContext& ctx); | 26 | Result GetSystemDisplayService( |
| 18 | void GetManagerDisplayService(HLERequestContext& ctx); | 27 | Out<SharedPointer<ISystemDisplayService>> out_system_display_service); |
| 19 | void GetIndirectDisplayTransactionService(HLERequestContext& ctx); | 28 | Result GetManagerDisplayService( |
| 20 | void OpenDisplay(HLERequestContext& ctx); | 29 | Out<SharedPointer<IManagerDisplayService>> out_manager_display_service); |
| 21 | void OpenDefaultDisplay(HLERequestContext& ctx); | 30 | Result GetIndirectDisplayTransactionService( |
| 22 | void OpenDisplayImpl(HLERequestContext& ctx, std::string_view name); | 31 | Out<SharedPointer<IHOSBinderDriver>> out_indirect_display_transaction_service); |
| 23 | void CloseDisplay(HLERequestContext& ctx); | 32 | Result OpenDisplay(Out<u64> out_display_id, DisplayName display_name); |
| 24 | void SetDisplayEnabled(HLERequestContext& ctx); | 33 | Result OpenDefaultDisplay(Out<u64> out_display_id); |
| 25 | void GetDisplayResolution(HLERequestContext& ctx); | 34 | Result CloseDisplay(u64 display_id); |
| 26 | void SetLayerScalingMode(HLERequestContext& ctx); | 35 | Result SetDisplayEnabled(u32 state, u64 display_id); |
| 27 | void ListDisplays(HLERequestContext& ctx); | 36 | Result GetDisplayResolution(Out<s64> out_width, Out<s64> out_height, u64 display_id); |
| 28 | void OpenLayer(HLERequestContext& ctx); | 37 | Result SetLayerScalingMode(NintendoScaleMode scale_mode, u64 layer_id); |
| 29 | void CloseLayer(HLERequestContext& ctx); | 38 | Result ListDisplays(Out<u64> out_count, |
| 30 | void CreateStrayLayer(HLERequestContext& ctx); | 39 | OutArray<DisplayInfo, BufferAttr_HipcMapAlias> out_displays); |
| 31 | void DestroyStrayLayer(HLERequestContext& ctx); | 40 | Result OpenLayer(Out<u64> out_size, OutBuffer<BufferAttr_HipcMapAlias> out_native_window, |
| 32 | void GetDisplayVsyncEvent(HLERequestContext& ctx); | 41 | DisplayName display_name, u64 layer_id, ClientAppletResourceUserId aruid); |
| 33 | void ConvertScalingMode(HLERequestContext& ctx); | 42 | Result CloseLayer(u64 layer_id); |
| 34 | void GetIndirectLayerImageMap(HLERequestContext& ctx); | 43 | Result CreateStrayLayer(Out<u64> out_layer_id, Out<u64> out_size, |
| 35 | void GetIndirectLayerImageRequiredMemoryInfo(HLERequestContext& ctx); | 44 | OutBuffer<BufferAttr_HipcMapAlias> out_native_window, u32 flags, |
| 36 | 45 | u64 display_id); | |
| 37 | private: | 46 | Result DestroyStrayLayer(u64 layer_id); |
| 38 | static Result ConvertScalingModeImpl(ConvertedScaleMode* out_scaling_mode, | 47 | Result GetDisplayVsyncEvent(OutCopyHandle<Kernel::KReadableEvent> out_vsync_event, |
| 39 | NintendoScaleMode mode); | 48 | u64 display_id); |
| 49 | Result ConvertScalingMode(Out<ConvertedScaleMode> out_scaling_mode, NintendoScaleMode mode); | ||
| 50 | Result GetIndirectLayerImageMap( | ||
| 51 | Out<u64> out_size, Out<u64> out_stride, | ||
| 52 | OutBuffer<BufferAttr_HipcMapTransferAllowsNonSecure | BufferAttr_HipcMapAlias> out_buffer, | ||
| 53 | s64 width, s64 height, u64 indirect_layer_consumer_handle, | ||
| 54 | ClientAppletResourceUserId aruid); | ||
| 55 | Result GetIndirectLayerImageRequiredMemoryInfo(Out<s64> out_size, Out<s64> out_alignment, | ||
| 56 | s64 width, s64 height); | ||
| 40 | 57 | ||
| 41 | private: | 58 | private: |
| 42 | Nvnflinger::Nvnflinger& nvnflinger; | 59 | Nvnflinger::Nvnflinger& m_nvnflinger; |
| 43 | Nvnflinger::HosBinderDriverServer& hos_binder_driver_server; | 60 | Nvnflinger::HosBinderDriverServer& m_hos_binder_driver_server; |
| 44 | std::vector<u64> stray_layer_ids; | 61 | std::vector<u64> m_stray_layer_ids; |
| 45 | bool vsync_event_fetched{false}; | 62 | bool m_vsync_event_fetched{false}; |
| 46 | }; | 63 | }; |
| 47 | 64 | ||
| 48 | } // namespace Service::VI | 65 | } // namespace Service::VI |
diff --git a/src/core/hle/service/vi/vi_types.h b/src/core/hle/service/vi/vi_types.h index 47fe2d11c..91e4b380c 100644 --- a/src/core/hle/service/vi/vi_types.h +++ b/src/core/hle/service/vi/vi_types.h | |||
| @@ -44,9 +44,11 @@ enum class NintendoScaleMode : u32 { | |||
| 44 | PreserveAspectRatio = 4, | 44 | PreserveAspectRatio = 4, |
| 45 | }; | 45 | }; |
| 46 | 46 | ||
| 47 | using DisplayName = std::array<char, 0x40>; | ||
| 48 | |||
| 47 | struct DisplayInfo { | 49 | struct DisplayInfo { |
| 48 | /// The name of this particular display. | 50 | /// The name of this particular display. |
| 49 | char display_name[0x40]{"Default"}; | 51 | DisplayName display_name{"Default"}; |
| 50 | 52 | ||
| 51 | /// Whether or not the display has a limited number of layers. | 53 | /// Whether or not the display has a limited number of layers. |
| 52 | u8 has_limited_layers{1}; | 54 | u8 has_limited_layers{1}; |