diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/hle/service/am/am.cpp | 202 | ||||
| -rw-r--r-- | src/core/hle/service/am/am.h | 1 | ||||
| -rw-r--r-- | src/core/hle/service/nvdrv/devices/nvhost_gpu.h | 47 | ||||
| -rw-r--r-- | src/video_core/engines/maxwell_3d.h | 40 | ||||
| -rw-r--r-- | src/video_core/engines/shader_bytecode.h | 17 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.cpp | 4 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer_cache.cpp | 3 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_decompiler.cpp | 52 | ||||
| -rw-r--r-- | src/yuzu/main.cpp | 26 | ||||
| -rw-r--r-- | src/yuzu/main.h | 1 | ||||
| -rw-r--r-- | src/yuzu_cmd/emu_window/emu_window_sdl2.cpp | 23 | ||||
| -rw-r--r-- | src/yuzu_cmd/emu_window/emu_window_sdl2.h | 3 |
12 files changed, 329 insertions, 90 deletions
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index 6b1d6bf97..12954556d 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp | |||
| @@ -3,6 +3,7 @@ | |||
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <cinttypes> | 5 | #include <cinttypes> |
| 6 | #include <stack> | ||
| 6 | #include "core/file_sys/filesystem.h" | 7 | #include "core/file_sys/filesystem.h" |
| 7 | #include "core/hle/ipc_helpers.h" | 8 | #include "core/hle/ipc_helpers.h" |
| 8 | #include "core/hle/kernel/event.h" | 9 | #include "core/hle/kernel/event.h" |
| @@ -154,7 +155,7 @@ ISelfController::ISelfController(std::shared_ptr<NVFlinger::NVFlinger> nvflinger | |||
| 154 | RegisterHandlers(functions); | 155 | RegisterHandlers(functions); |
| 155 | 156 | ||
| 156 | launchable_event = | 157 | launchable_event = |
| 157 | Kernel::Event::Create(Kernel::ResetType::OneShot, "ISelfController:LaunchableEvent"); | 158 | Kernel::Event::Create(Kernel::ResetType::Sticky, "ISelfController:LaunchableEvent"); |
| 158 | } | 159 | } |
| 159 | 160 | ||
| 160 | void ISelfController::SetFocusHandlingMode(Kernel::HLERequestContext& ctx) { | 161 | void ISelfController::SetFocusHandlingMode(Kernel::HLERequestContext& ctx) { |
| @@ -348,19 +349,100 @@ void ICommonStateGetter::GetPerformanceMode(Kernel::HLERequestContext& ctx) { | |||
| 348 | NGLOG_WARNING(Service_AM, "(STUBBED) called"); | 349 | NGLOG_WARNING(Service_AM, "(STUBBED) called"); |
| 349 | } | 350 | } |
| 350 | 351 | ||
| 352 | class IStorageAccessor final : public ServiceFramework<IStorageAccessor> { | ||
| 353 | public: | ||
| 354 | explicit IStorageAccessor(std::vector<u8> buffer) | ||
| 355 | : ServiceFramework("IStorageAccessor"), buffer(std::move(buffer)) { | ||
| 356 | static const FunctionInfo functions[] = { | ||
| 357 | {0, &IStorageAccessor::GetSize, "GetSize"}, | ||
| 358 | {10, &IStorageAccessor::Write, "Write"}, | ||
| 359 | {11, &IStorageAccessor::Read, "Read"}, | ||
| 360 | }; | ||
| 361 | RegisterHandlers(functions); | ||
| 362 | } | ||
| 363 | |||
| 364 | private: | ||
| 365 | std::vector<u8> buffer; | ||
| 366 | |||
| 367 | void GetSize(Kernel::HLERequestContext& ctx) { | ||
| 368 | IPC::ResponseBuilder rb{ctx, 4}; | ||
| 369 | |||
| 370 | rb.Push(RESULT_SUCCESS); | ||
| 371 | rb.Push(static_cast<u64>(buffer.size())); | ||
| 372 | |||
| 373 | NGLOG_DEBUG(Service_AM, "called"); | ||
| 374 | } | ||
| 375 | |||
| 376 | void Write(Kernel::HLERequestContext& ctx) { | ||
| 377 | IPC::RequestParser rp{ctx}; | ||
| 378 | |||
| 379 | const u64 offset{rp.Pop<u64>()}; | ||
| 380 | const std::vector<u8> data{ctx.ReadBuffer()}; | ||
| 381 | |||
| 382 | ASSERT(offset + data.size() <= buffer.size()); | ||
| 383 | |||
| 384 | std::memcpy(&buffer[offset], data.data(), data.size()); | ||
| 385 | |||
| 386 | IPC::ResponseBuilder rb{rp.MakeBuilder(2, 0, 0)}; | ||
| 387 | rb.Push(RESULT_SUCCESS); | ||
| 388 | |||
| 389 | NGLOG_DEBUG(Service_AM, "called, offset={}", offset); | ||
| 390 | } | ||
| 391 | |||
| 392 | void Read(Kernel::HLERequestContext& ctx) { | ||
| 393 | IPC::RequestParser rp{ctx}; | ||
| 394 | |||
| 395 | const u64 offset{rp.Pop<u64>()}; | ||
| 396 | const size_t size{ctx.GetWriteBufferSize()}; | ||
| 397 | |||
| 398 | ASSERT(offset + size <= buffer.size()); | ||
| 399 | |||
| 400 | ctx.WriteBuffer(buffer.data() + offset, size); | ||
| 401 | |||
| 402 | IPC::ResponseBuilder rb{rp.MakeBuilder(2, 0, 0)}; | ||
| 403 | rb.Push(RESULT_SUCCESS); | ||
| 404 | |||
| 405 | NGLOG_DEBUG(Service_AM, "called, offset={}", offset); | ||
| 406 | } | ||
| 407 | }; | ||
| 408 | |||
| 409 | class IStorage final : public ServiceFramework<IStorage> { | ||
| 410 | public: | ||
| 411 | explicit IStorage(std::vector<u8> buffer) | ||
| 412 | : ServiceFramework("IStorage"), buffer(std::move(buffer)) { | ||
| 413 | static const FunctionInfo functions[] = { | ||
| 414 | {0, &IStorage::Open, "Open"}, | ||
| 415 | {1, nullptr, "OpenTransferStorage"}, | ||
| 416 | }; | ||
| 417 | RegisterHandlers(functions); | ||
| 418 | } | ||
| 419 | |||
| 420 | private: | ||
| 421 | std::vector<u8> buffer; | ||
| 422 | |||
| 423 | void Open(Kernel::HLERequestContext& ctx) { | ||
| 424 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||
| 425 | |||
| 426 | rb.Push(RESULT_SUCCESS); | ||
| 427 | rb.PushIpcInterface<AM::IStorageAccessor>(buffer); | ||
| 428 | |||
| 429 | NGLOG_DEBUG(Service_AM, "called"); | ||
| 430 | } | ||
| 431 | }; | ||
| 432 | |||
| 351 | class ILibraryAppletAccessor final : public ServiceFramework<ILibraryAppletAccessor> { | 433 | class ILibraryAppletAccessor final : public ServiceFramework<ILibraryAppletAccessor> { |
| 352 | public: | 434 | public: |
| 353 | explicit ILibraryAppletAccessor() : ServiceFramework("ILibraryAppletAccessor") { | 435 | explicit ILibraryAppletAccessor() : ServiceFramework("ILibraryAppletAccessor") { |
| 354 | static const FunctionInfo functions[] = { | 436 | static const FunctionInfo functions[] = { |
| 355 | {0, &ILibraryAppletAccessor::GetAppletStateChangedEvent, "GetAppletStateChangedEvent"}, | 437 | {0, &ILibraryAppletAccessor::GetAppletStateChangedEvent, "GetAppletStateChangedEvent"}, |
| 356 | {1, nullptr, "IsCompleted"}, | 438 | {1, nullptr, "IsCompleted"}, |
| 357 | {10, nullptr, "Start"}, | 439 | {10, &ILibraryAppletAccessor::Start, "Start"}, |
| 358 | {20, nullptr, "RequestExit"}, | 440 | {20, nullptr, "RequestExit"}, |
| 359 | {25, nullptr, "Terminate"}, | 441 | {25, nullptr, "Terminate"}, |
| 360 | {30, nullptr, "GetResult"}, | 442 | {30, &ILibraryAppletAccessor::GetResult, "GetResult"}, |
| 361 | {50, nullptr, "SetOutOfFocusApplicationSuspendingEnabled"}, | 443 | {50, nullptr, "SetOutOfFocusApplicationSuspendingEnabled"}, |
| 362 | {100, nullptr, "PushInData"}, | 444 | {100, &ILibraryAppletAccessor::PushInData, "PushInData"}, |
| 363 | {101, nullptr, "PopOutData"}, | 445 | {101, &ILibraryAppletAccessor::PopOutData, "PopOutData"}, |
| 364 | {102, nullptr, "PushExtraStorage"}, | 446 | {102, nullptr, "PushExtraStorage"}, |
| 365 | {103, nullptr, "PushInteractiveInData"}, | 447 | {103, nullptr, "PushInteractiveInData"}, |
| 366 | {104, nullptr, "PopInteractiveOutData"}, | 448 | {104, nullptr, "PopInteractiveOutData"}, |
| @@ -388,6 +470,41 @@ private: | |||
| 388 | NGLOG_WARNING(Service_AM, "(STUBBED) called"); | 470 | NGLOG_WARNING(Service_AM, "(STUBBED) called"); |
| 389 | } | 471 | } |
| 390 | 472 | ||
| 473 | void GetResult(Kernel::HLERequestContext& ctx) { | ||
| 474 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 475 | rb.Push(RESULT_SUCCESS); | ||
| 476 | |||
| 477 | NGLOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 478 | } | ||
| 479 | |||
| 480 | void Start(Kernel::HLERequestContext& ctx) { | ||
| 481 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 482 | rb.Push(RESULT_SUCCESS); | ||
| 483 | |||
| 484 | NGLOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 485 | } | ||
| 486 | |||
| 487 | void PushInData(Kernel::HLERequestContext& ctx) { | ||
| 488 | IPC::RequestParser rp{ctx}; | ||
| 489 | storage_stack.push(rp.PopIpcInterface<AM::IStorage>()); | ||
| 490 | |||
| 491 | IPC::ResponseBuilder rb{rp.MakeBuilder(2, 0, 0)}; | ||
| 492 | rb.Push(RESULT_SUCCESS); | ||
| 493 | |||
| 494 | NGLOG_DEBUG(Service_AM, "called"); | ||
| 495 | } | ||
| 496 | |||
| 497 | void PopOutData(Kernel::HLERequestContext& ctx) { | ||
| 498 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||
| 499 | rb.Push(RESULT_SUCCESS); | ||
| 500 | rb.PushIpcInterface<AM::IStorage>(std::move(storage_stack.top())); | ||
| 501 | |||
| 502 | storage_stack.pop(); | ||
| 503 | |||
| 504 | NGLOG_DEBUG(Service_AM, "called"); | ||
| 505 | } | ||
| 506 | |||
| 507 | std::stack<std::shared_ptr<AM::IStorage>> storage_stack; | ||
| 391 | Kernel::SharedPtr<Kernel::Event> state_changed_event; | 508 | Kernel::SharedPtr<Kernel::Event> state_changed_event; |
| 392 | }; | 509 | }; |
| 393 | 510 | ||
| @@ -396,7 +513,7 @@ ILibraryAppletCreator::ILibraryAppletCreator() : ServiceFramework("ILibraryApple | |||
| 396 | {0, &ILibraryAppletCreator::CreateLibraryApplet, "CreateLibraryApplet"}, | 513 | {0, &ILibraryAppletCreator::CreateLibraryApplet, "CreateLibraryApplet"}, |
| 397 | {1, nullptr, "TerminateAllLibraryApplets"}, | 514 | {1, nullptr, "TerminateAllLibraryApplets"}, |
| 398 | {2, nullptr, "AreAnyLibraryAppletsLeft"}, | 515 | {2, nullptr, "AreAnyLibraryAppletsLeft"}, |
| 399 | {10, nullptr, "CreateStorage"}, | 516 | {10, &ILibraryAppletCreator::CreateStorage, "CreateStorage"}, |
| 400 | {11, nullptr, "CreateTransferMemoryStorage"}, | 517 | {11, nullptr, "CreateTransferMemoryStorage"}, |
| 401 | {12, nullptr, "CreateHandleStorage"}, | 518 | {12, nullptr, "CreateHandleStorage"}, |
| 402 | }; | 519 | }; |
| @@ -412,72 +529,17 @@ void ILibraryAppletCreator::CreateLibraryApplet(Kernel::HLERequestContext& ctx) | |||
| 412 | NGLOG_DEBUG(Service_AM, "called"); | 529 | NGLOG_DEBUG(Service_AM, "called"); |
| 413 | } | 530 | } |
| 414 | 531 | ||
| 415 | class IStorageAccessor final : public ServiceFramework<IStorageAccessor> { | 532 | void ILibraryAppletCreator::CreateStorage(Kernel::HLERequestContext& ctx) { |
| 416 | public: | 533 | IPC::RequestParser rp{ctx}; |
| 417 | explicit IStorageAccessor(std::vector<u8> buffer) | 534 | const u64 size{rp.Pop<u64>()}; |
| 418 | : ServiceFramework("IStorageAccessor"), buffer(std::move(buffer)) { | 535 | std::vector<u8> buffer(size); |
| 419 | static const FunctionInfo functions[] = { | ||
| 420 | {0, &IStorageAccessor::GetSize, "GetSize"}, | ||
| 421 | {10, nullptr, "Write"}, | ||
| 422 | {11, &IStorageAccessor::Read, "Read"}, | ||
| 423 | }; | ||
| 424 | RegisterHandlers(functions); | ||
| 425 | } | ||
| 426 | |||
| 427 | private: | ||
| 428 | std::vector<u8> buffer; | ||
| 429 | |||
| 430 | void GetSize(Kernel::HLERequestContext& ctx) { | ||
| 431 | IPC::ResponseBuilder rb{ctx, 4}; | ||
| 432 | |||
| 433 | rb.Push(RESULT_SUCCESS); | ||
| 434 | rb.Push(static_cast<u64>(buffer.size())); | ||
| 435 | |||
| 436 | NGLOG_DEBUG(Service_AM, "called"); | ||
| 437 | } | ||
| 438 | |||
| 439 | void Read(Kernel::HLERequestContext& ctx) { | ||
| 440 | IPC::RequestParser rp{ctx}; | ||
| 441 | |||
| 442 | u64 offset = rp.Pop<u64>(); | ||
| 443 | |||
| 444 | const size_t size{ctx.GetWriteBufferSize()}; | ||
| 445 | |||
| 446 | ASSERT(offset + size <= buffer.size()); | ||
| 447 | |||
| 448 | ctx.WriteBuffer(buffer.data() + offset, size); | ||
| 449 | |||
| 450 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 451 | |||
| 452 | rb.Push(RESULT_SUCCESS); | ||
| 453 | |||
| 454 | NGLOG_DEBUG(Service_AM, "called"); | ||
| 455 | } | ||
| 456 | }; | ||
| 457 | |||
| 458 | class IStorage final : public ServiceFramework<IStorage> { | ||
| 459 | public: | ||
| 460 | explicit IStorage(std::vector<u8> buffer) | ||
| 461 | : ServiceFramework("IStorage"), buffer(std::move(buffer)) { | ||
| 462 | static const FunctionInfo functions[] = { | ||
| 463 | {0, &IStorage::Open, "Open"}, | ||
| 464 | {1, nullptr, "OpenTransferStorage"}, | ||
| 465 | }; | ||
| 466 | RegisterHandlers(functions); | ||
| 467 | } | ||
| 468 | |||
| 469 | private: | ||
| 470 | std::vector<u8> buffer; | ||
| 471 | |||
| 472 | void Open(Kernel::HLERequestContext& ctx) { | ||
| 473 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||
| 474 | 536 | ||
| 475 | rb.Push(RESULT_SUCCESS); | 537 | IPC::ResponseBuilder rb{rp.MakeBuilder(2, 0, 1)}; |
| 476 | rb.PushIpcInterface<AM::IStorageAccessor>(buffer); | 538 | rb.Push(RESULT_SUCCESS); |
| 539 | rb.PushIpcInterface<AM::IStorage>(std::move(buffer)); | ||
| 477 | 540 | ||
| 478 | NGLOG_DEBUG(Service_AM, "called"); | 541 | NGLOG_DEBUG(Service_AM, "called, size={}", size); |
| 479 | } | 542 | } |
| 480 | }; | ||
| 481 | 543 | ||
| 482 | IApplicationFunctions::IApplicationFunctions() : ServiceFramework("IApplicationFunctions") { | 544 | IApplicationFunctions::IApplicationFunctions() : ServiceFramework("IApplicationFunctions") { |
| 483 | static const FunctionInfo functions[] = { | 545 | static const FunctionInfo functions[] = { |
diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h index ff8eb14d7..301a6c798 100644 --- a/src/core/hle/service/am/am.h +++ b/src/core/hle/service/am/am.h | |||
| @@ -121,6 +121,7 @@ public: | |||
| 121 | 121 | ||
| 122 | private: | 122 | private: |
| 123 | void CreateLibraryApplet(Kernel::HLERequestContext& ctx); | 123 | void CreateLibraryApplet(Kernel::HLERequestContext& ctx); |
| 124 | void CreateStorage(Kernel::HLERequestContext& ctx); | ||
| 124 | }; | 125 | }; |
| 125 | 126 | ||
| 126 | class IApplicationFunctions final : public ServiceFramework<IApplicationFunctions> { | 127 | class IApplicationFunctions final : public ServiceFramework<IApplicationFunctions> { |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h index 2ecf818f3..56b5ed60d 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h | |||
| @@ -26,11 +26,19 @@ public: | |||
| 26 | private: | 26 | private: |
| 27 | enum class IoctlCommand : u32_le { | 27 | enum class IoctlCommand : u32_le { |
| 28 | IocSetNVMAPfdCommand = 0x40044801, | 28 | IocSetNVMAPfdCommand = 0x40044801, |
| 29 | IocAllocGPFIFOCommand = 0x40084805, | ||
| 29 | IocSetClientDataCommand = 0x40084714, | 30 | IocSetClientDataCommand = 0x40084714, |
| 30 | IocGetClientDataCommand = 0x80084715, | 31 | IocGetClientDataCommand = 0x80084715, |
| 31 | IocZCullBind = 0xc010480b, | 32 | IocZCullBind = 0xc010480b, |
| 32 | IocSetErrorNotifierCommand = 0xC018480C, | 33 | IocSetErrorNotifierCommand = 0xC018480C, |
| 33 | IocChannelSetPriorityCommand = 0x4004480D, | 34 | IocChannelSetPriorityCommand = 0x4004480D, |
| 35 | IocEnableCommand = 0x0000480E, | ||
| 36 | IocDisableCommand = 0x0000480F, | ||
| 37 | IocPreemptCommand = 0x00004810, | ||
| 38 | IocForceResetCommand = 0x00004811, | ||
| 39 | IocEventIdControlCommand = 0x40084812, | ||
| 40 | IocGetErrorNotificationCommand = 0xC0104817, | ||
| 41 | IocAllocGPFIFOExCommand = 0x40204818, | ||
| 34 | IocAllocGPFIFOEx2Command = 0xC020481A, | 42 | IocAllocGPFIFOEx2Command = 0xC020481A, |
| 35 | IocAllocObjCtxCommand = 0xC0104809, | 43 | IocAllocObjCtxCommand = 0xC0104809, |
| 36 | IocChannelGetWaitbaseCommand = 0xC0080003, | 44 | IocChannelGetWaitbaseCommand = 0xC0080003, |
| @@ -56,6 +64,12 @@ private: | |||
| 56 | }; | 64 | }; |
| 57 | static_assert(sizeof(IoctlChannelSetTimeout) == 4, "IoctlChannelSetTimeout is incorrect size"); | 65 | static_assert(sizeof(IoctlChannelSetTimeout) == 4, "IoctlChannelSetTimeout is incorrect size"); |
| 58 | 66 | ||
| 67 | struct IoctlAllocGPFIFO { | ||
| 68 | u32_le num_entries; | ||
| 69 | u32_le flags; | ||
| 70 | }; | ||
| 71 | static_assert(sizeof(IoctlAllocGPFIFO) == 8, "IoctlAllocGPFIFO is incorrect size"); | ||
| 72 | |||
| 59 | struct IoctlClientData { | 73 | struct IoctlClientData { |
| 60 | u64_le data; | 74 | u64_le data; |
| 61 | }; | 75 | }; |
| @@ -76,12 +90,45 @@ private: | |||
| 76 | }; | 90 | }; |
| 77 | static_assert(sizeof(IoctlSetErrorNotifier) == 24, "IoctlSetErrorNotifier is incorrect size"); | 91 | static_assert(sizeof(IoctlSetErrorNotifier) == 24, "IoctlSetErrorNotifier is incorrect size"); |
| 78 | 92 | ||
| 93 | struct IoctlChannelSetPriority { | ||
| 94 | u32_le priority; | ||
| 95 | }; | ||
| 96 | static_assert(sizeof(IoctlChannelSetPriority) == 4, | ||
| 97 | "IoctlChannelSetPriority is incorrect size"); | ||
| 98 | |||
| 99 | struct IoctlEventIdControl { | ||
| 100 | u32_le cmd; // 0=disable, 1=enable, 2=clear | ||
| 101 | u32_le id; | ||
| 102 | }; | ||
| 103 | static_assert(sizeof(IoctlEventIdControl) == 8, "IoctlEventIdControl is incorrect size"); | ||
| 104 | |||
| 105 | struct IoctlGetErrorNotification { | ||
| 106 | u64_le timestamp; | ||
| 107 | u32_le info32; | ||
| 108 | u16_le info16; | ||
| 109 | u16_le status; // always 0xFFFF | ||
| 110 | }; | ||
| 111 | static_assert(sizeof(IoctlGetErrorNotification) == 16, | ||
| 112 | "IoctlGetErrorNotification is incorrect size"); | ||
| 113 | |||
| 79 | struct IoctlFence { | 114 | struct IoctlFence { |
| 80 | u32_le id; | 115 | u32_le id; |
| 81 | u32_le value; | 116 | u32_le value; |
| 82 | }; | 117 | }; |
| 83 | static_assert(sizeof(IoctlFence) == 8, "IoctlFence is incorrect size"); | 118 | static_assert(sizeof(IoctlFence) == 8, "IoctlFence is incorrect size"); |
| 84 | 119 | ||
| 120 | struct IoctlAllocGpfifoEx { | ||
| 121 | u32_le num_entries; | ||
| 122 | u32_le flags; | ||
| 123 | u32_le unk0; | ||
| 124 | u32_le unk1; | ||
| 125 | u32_le unk2; | ||
| 126 | u32_le unk3; | ||
| 127 | u32_le unk4; | ||
| 128 | u32_le unk5; | ||
| 129 | }; | ||
| 130 | static_assert(sizeof(IoctlAllocGpfifoEx) == 32, "IoctlAllocGpfifoEx is incorrect size"); | ||
| 131 | |||
| 85 | struct IoctlAllocGpfifoEx2 { | 132 | struct IoctlAllocGpfifoEx2 { |
| 86 | u32_le num_entries; // in | 133 | u32_le num_entries; // in |
| 87 | u32_le flags; // in | 134 | u32_le flags; // in |
diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h index 5cf62fb01..245410c95 100644 --- a/src/video_core/engines/maxwell_3d.h +++ b/src/video_core/engines/maxwell_3d.h | |||
| @@ -354,10 +354,35 @@ public: | |||
| 354 | f32 scale_x; | 354 | f32 scale_x; |
| 355 | f32 scale_y; | 355 | f32 scale_y; |
| 356 | f32 scale_z; | 356 | f32 scale_z; |
| 357 | u32 translate_x; | 357 | f32 translate_x; |
| 358 | u32 translate_y; | 358 | f32 translate_y; |
| 359 | u32 translate_z; | 359 | f32 translate_z; |
| 360 | INSERT_PADDING_WORDS(2); | 360 | INSERT_PADDING_WORDS(2); |
| 361 | |||
| 362 | MathUtil::Rectangle<s32> GetRect() const { | ||
| 363 | return { | ||
| 364 | GetX(), // left | ||
| 365 | GetY() + GetHeight(), // top | ||
| 366 | GetX() + GetWidth(), // right | ||
| 367 | GetY() // bottom | ||
| 368 | }; | ||
| 369 | }; | ||
| 370 | |||
| 371 | s32 GetX() const { | ||
| 372 | return static_cast<s32>(std::max(0.0f, translate_x - std::fabs(scale_x))); | ||
| 373 | } | ||
| 374 | |||
| 375 | s32 GetY() const { | ||
| 376 | return static_cast<s32>(std::max(0.0f, translate_y - std::fabs(scale_y))); | ||
| 377 | } | ||
| 378 | |||
| 379 | s32 GetWidth() const { | ||
| 380 | return static_cast<s32>(translate_x + std::fabs(scale_x)) - GetX(); | ||
| 381 | } | ||
| 382 | |||
| 383 | s32 GetHeight() const { | ||
| 384 | return static_cast<s32>(translate_y + std::fabs(scale_y)) - GetY(); | ||
| 385 | } | ||
| 361 | } viewport_transform[NumViewports]; | 386 | } viewport_transform[NumViewports]; |
| 362 | 387 | ||
| 363 | struct { | 388 | struct { |
| @@ -371,15 +396,6 @@ public: | |||
| 371 | }; | 396 | }; |
| 372 | float depth_range_near; | 397 | float depth_range_near; |
| 373 | float depth_range_far; | 398 | float depth_range_far; |
| 374 | |||
| 375 | MathUtil::Rectangle<s32> GetRect() const { | ||
| 376 | return { | ||
| 377 | static_cast<s32>(x), // left | ||
| 378 | static_cast<s32>(y + height), // top | ||
| 379 | static_cast<s32>(x + width), // right | ||
| 380 | static_cast<s32>(y) // bottom | ||
| 381 | }; | ||
| 382 | }; | ||
| 383 | } viewport[NumViewports]; | 399 | } viewport[NumViewports]; |
| 384 | 400 | ||
| 385 | INSERT_PADDING_WORDS(0x1D); | 401 | INSERT_PADDING_WORDS(0x1D); |
diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h index 83f7cc3a9..3add56155 100644 --- a/src/video_core/engines/shader_bytecode.h +++ b/src/video_core/engines/shader_bytecode.h | |||
| @@ -255,9 +255,9 @@ union Instruction { | |||
| 255 | BitField<44, 1, u64> abs_b; | 255 | BitField<44, 1, u64> abs_b; |
| 256 | BitField<45, 2, PredOperation> op; | 256 | BitField<45, 2, PredOperation> op; |
| 257 | BitField<48, 4, PredCondition> cond; | 257 | BitField<48, 4, PredCondition> cond; |
| 258 | BitField<52, 1, u64> bf; | ||
| 258 | BitField<53, 1, u64> neg_b; | 259 | BitField<53, 1, u64> neg_b; |
| 259 | BitField<54, 1, u64> abs_a; | 260 | BitField<54, 1, u64> abs_a; |
| 260 | BitField<52, 1, u64> bf; | ||
| 261 | BitField<55, 1, u64> ftz; | 261 | BitField<55, 1, u64> ftz; |
| 262 | BitField<56, 1, u64> neg_imm; | 262 | BitField<56, 1, u64> neg_imm; |
| 263 | } fset; | 263 | } fset; |
| @@ -298,6 +298,19 @@ union Instruction { | |||
| 298 | } | 298 | } |
| 299 | } texs; | 299 | } texs; |
| 300 | 300 | ||
| 301 | union { | ||
| 302 | BitField<20, 5, u64> target; | ||
| 303 | BitField<5, 1, u64> constant_buffer; | ||
| 304 | |||
| 305 | s32 GetBranchTarget() const { | ||
| 306 | // Sign extend the branch target offset | ||
| 307 | u32 mask = 1U << (5 - 1); | ||
| 308 | u32 value = static_cast<u32>(target); | ||
| 309 | // The branch offset is relative to the next instruction, so add 1 to it. | ||
| 310 | return static_cast<s32>((value ^ mask) - mask) + 1; | ||
| 311 | } | ||
| 312 | } bra; | ||
| 313 | |||
| 301 | BitField<61, 1, u64> is_b_imm; | 314 | BitField<61, 1, u64> is_b_imm; |
| 302 | BitField<60, 1, u64> is_b_gpr; | 315 | BitField<60, 1, u64> is_b_gpr; |
| 303 | BitField<59, 1, u64> is_c_gpr; | 316 | BitField<59, 1, u64> is_c_gpr; |
| @@ -316,6 +329,7 @@ class OpCode { | |||
| 316 | public: | 329 | public: |
| 317 | enum class Id { | 330 | enum class Id { |
| 318 | KIL, | 331 | KIL, |
| 332 | BRA, | ||
| 319 | LD_A, | 333 | LD_A, |
| 320 | ST_A, | 334 | ST_A, |
| 321 | TEX, | 335 | TEX, |
| @@ -480,6 +494,7 @@ private: | |||
| 480 | std::vector<Matcher> table = { | 494 | std::vector<Matcher> table = { |
| 481 | #define INST(bitstring, op, type, name) Detail::GetMatcher(bitstring, op, type, name) | 495 | #define INST(bitstring, op, type, name) Detail::GetMatcher(bitstring, op, type, name) |
| 482 | INST("111000110011----", Id::KIL, Type::Flow, "KIL"), | 496 | INST("111000110011----", Id::KIL, Type::Flow, "KIL"), |
| 497 | INST("111000100100----", Id::BRA, Type::Flow, "BRA"), | ||
| 483 | INST("1110111111011---", Id::LD_A, Type::Memory, "LD_A"), | 498 | INST("1110111111011---", Id::LD_A, Type::Memory, "LD_A"), |
| 484 | INST("1110111111110---", Id::ST_A, Type::Memory, "ST_A"), | 499 | INST("1110111111110---", Id::ST_A, Type::Memory, "ST_A"), |
| 485 | INST("1100000000111---", Id::TEX, Type::Memory, "TEX"), | 500 | INST("1100000000111---", Id::TEX, Type::Memory, "TEX"), |
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 35c1b1890..0a33868b7 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp | |||
| @@ -298,7 +298,7 @@ void RasterizerOpenGL::DrawArrays() { | |||
| 298 | const bool has_stencil = false; | 298 | const bool has_stencil = false; |
| 299 | const bool using_color_fb = true; | 299 | const bool using_color_fb = true; |
| 300 | const bool using_depth_fb = false; | 300 | const bool using_depth_fb = false; |
| 301 | const MathUtil::Rectangle<s32> viewport_rect{regs.viewport[0].GetRect()}; | 301 | const MathUtil::Rectangle<s32> viewport_rect{regs.viewport_transform[0].GetRect()}; |
| 302 | 302 | ||
| 303 | const bool write_color_fb = | 303 | const bool write_color_fb = |
| 304 | state.color_mask.red_enabled == GL_TRUE || state.color_mask.green_enabled == GL_TRUE || | 304 | state.color_mask.red_enabled == GL_TRUE || state.color_mask.green_enabled == GL_TRUE || |
| @@ -702,7 +702,7 @@ void RasterizerOpenGL::BindFramebufferSurfaces(const Surface& color_surface, | |||
| 702 | 702 | ||
| 703 | void RasterizerOpenGL::SyncViewport(const MathUtil::Rectangle<u32>& surfaces_rect, u16 res_scale) { | 703 | void RasterizerOpenGL::SyncViewport(const MathUtil::Rectangle<u32>& surfaces_rect, u16 res_scale) { |
| 704 | const auto& regs = Core::System().GetInstance().GPU().Maxwell3D().regs; | 704 | const auto& regs = Core::System().GetInstance().GPU().Maxwell3D().regs; |
| 705 | const MathUtil::Rectangle<s32> viewport_rect{regs.viewport[0].GetRect()}; | 705 | const MathUtil::Rectangle<s32> viewport_rect{regs.viewport_transform[0].GetRect()}; |
| 706 | 706 | ||
| 707 | state.viewport.x = static_cast<GLint>(surfaces_rect.left) + viewport_rect.left * res_scale; | 707 | state.viewport.x = static_cast<GLint>(surfaces_rect.left) + viewport_rect.left * res_scale; |
| 708 | state.viewport.y = static_cast<GLint>(surfaces_rect.bottom) + viewport_rect.bottom * res_scale; | 708 | state.viewport.y = static_cast<GLint>(surfaces_rect.bottom) + viewport_rect.bottom * res_scale; |
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp index 65d643447..d6048f639 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp | |||
| @@ -933,7 +933,8 @@ Surface RasterizerCacheOpenGL::GetSurface(const SurfaceParams& params, ScaleMatc | |||
| 933 | // Use GetSurfaceSubRect instead | 933 | // Use GetSurfaceSubRect instead |
| 934 | ASSERT(params.width == params.stride); | 934 | ASSERT(params.width == params.stride); |
| 935 | 935 | ||
| 936 | ASSERT(!params.is_tiled || (params.width % 8 == 0 && params.height % 8 == 0)); | 936 | ASSERT(!params.is_tiled || |
| 937 | (params.GetActualWidth() % 8 == 0 && params.GetActualHeight() % 8 == 0)); | ||
| 937 | 938 | ||
| 938 | // Check for an exact match in existing surfaces | 939 | // Check for an exact match in existing surfaces |
| 939 | Surface surface = | 940 | Surface surface = |
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index 618c603c2..8c263f15f 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp | |||
| @@ -88,6 +88,20 @@ private: | |||
| 88 | return *subroutines.insert(std::move(subroutine)).first; | 88 | return *subroutines.insert(std::move(subroutine)).first; |
| 89 | } | 89 | } |
| 90 | 90 | ||
| 91 | /// Merges exit method of two parallel branches. | ||
| 92 | static ExitMethod ParallelExit(ExitMethod a, ExitMethod b) { | ||
| 93 | if (a == ExitMethod::Undetermined) { | ||
| 94 | return b; | ||
| 95 | } | ||
| 96 | if (b == ExitMethod::Undetermined) { | ||
| 97 | return a; | ||
| 98 | } | ||
| 99 | if (a == b) { | ||
| 100 | return a; | ||
| 101 | } | ||
| 102 | return ExitMethod::Conditional; | ||
| 103 | } | ||
| 104 | |||
| 91 | /// Scans a range of code for labels and determines the exit method. | 105 | /// Scans a range of code for labels and determines the exit method. |
| 92 | ExitMethod Scan(u32 begin, u32 end, std::set<u32>& labels) { | 106 | ExitMethod Scan(u32 begin, u32 end, std::set<u32>& labels) { |
| 93 | auto [iter, inserted] = | 107 | auto [iter, inserted] = |
| @@ -97,11 +111,19 @@ private: | |||
| 97 | return exit_method; | 111 | return exit_method; |
| 98 | 112 | ||
| 99 | for (u32 offset = begin; offset != end && offset != PROGRAM_END; ++offset) { | 113 | for (u32 offset = begin; offset != end && offset != PROGRAM_END; ++offset) { |
| 100 | if (const auto opcode = OpCode::Decode({program_code[offset]})) { | 114 | const Instruction instr = {program_code[offset]}; |
| 115 | if (const auto opcode = OpCode::Decode(instr)) { | ||
| 101 | switch (opcode->GetId()) { | 116 | switch (opcode->GetId()) { |
| 102 | case OpCode::Id::EXIT: { | 117 | case OpCode::Id::EXIT: { |
| 103 | return exit_method = ExitMethod::AlwaysEnd; | 118 | return exit_method = ExitMethod::AlwaysEnd; |
| 104 | } | 119 | } |
| 120 | case OpCode::Id::BRA: { | ||
| 121 | u32 target = offset + instr.bra.GetBranchTarget(); | ||
| 122 | labels.insert(target); | ||
| 123 | ExitMethod no_jmp = Scan(offset + 1, end, labels); | ||
| 124 | ExitMethod jmp = Scan(target, end, labels); | ||
| 125 | return exit_method = ParallelExit(no_jmp, jmp); | ||
| 126 | } | ||
| 105 | } | 127 | } |
| 106 | } | 128 | } |
| 107 | } | 129 | } |
| @@ -860,8 +882,7 @@ private: | |||
| 860 | ASSERT_MSG(!instr.conversion.saturate_a, "Unimplemented"); | 882 | ASSERT_MSG(!instr.conversion.saturate_a, "Unimplemented"); |
| 861 | 883 | ||
| 862 | switch (opcode->GetId()) { | 884 | switch (opcode->GetId()) { |
| 863 | case OpCode::Id::I2I_R: | 885 | case OpCode::Id::I2I_R: { |
| 864 | case OpCode::Id::I2F_R: { | ||
| 865 | ASSERT_MSG(!instr.conversion.selector, "Unimplemented"); | 886 | ASSERT_MSG(!instr.conversion.selector, "Unimplemented"); |
| 866 | 887 | ||
| 867 | std::string op_a = | 888 | std::string op_a = |
| @@ -874,6 +895,17 @@ private: | |||
| 874 | regs.SetRegisterToInteger(instr.gpr0, instr.conversion.is_signed, 0, op_a, 1, 1); | 895 | regs.SetRegisterToInteger(instr.gpr0, instr.conversion.is_signed, 0, op_a, 1, 1); |
| 875 | break; | 896 | break; |
| 876 | } | 897 | } |
| 898 | case OpCode::Id::I2F_R: { | ||
| 899 | std::string op_a = | ||
| 900 | regs.GetRegisterAsInteger(instr.gpr20, 0, instr.conversion.is_signed); | ||
| 901 | |||
| 902 | if (instr.conversion.abs_a) { | ||
| 903 | op_a = "abs(" + op_a + ')'; | ||
| 904 | } | ||
| 905 | |||
| 906 | regs.SetRegisterToFloat(instr.gpr0, 0, op_a, 1, 1); | ||
| 907 | break; | ||
| 908 | } | ||
| 877 | case OpCode::Id::F2F_R: { | 909 | case OpCode::Id::F2F_R: { |
| 878 | std::string op_a = regs.GetRegisterAsFloat(instr.gpr20); | 910 | std::string op_a = regs.GetRegisterAsFloat(instr.gpr20); |
| 879 | 911 | ||
| @@ -1103,7 +1135,12 @@ private: | |||
| 1103 | std::string predicate = "(((" + op_a + ") " + comparator + " (" + op_b + ")) " + | 1135 | std::string predicate = "(((" + op_a + ") " + comparator + " (" + op_b + ")) " + |
| 1104 | combiner + " (" + second_pred + "))"; | 1136 | combiner + " (" + second_pred + "))"; |
| 1105 | 1137 | ||
| 1106 | regs.SetRegisterToFloat(instr.gpr0, 0, predicate + " ? 1.0 : 0.0", 1, 1); | 1138 | if (instr.fset.bf) { |
| 1139 | regs.SetRegisterToFloat(instr.gpr0, 0, predicate + " ? 1.0 : 0.0", 1, 1); | ||
| 1140 | } else { | ||
| 1141 | regs.SetRegisterToInteger(instr.gpr0, false, 0, predicate + " ? 0xFFFFFFFF : 0", 1, | ||
| 1142 | 1); | ||
| 1143 | } | ||
| 1107 | break; | 1144 | break; |
| 1108 | } | 1145 | } |
| 1109 | default: { | 1146 | default: { |
| @@ -1128,6 +1165,13 @@ private: | |||
| 1128 | shader.AddLine("discard;"); | 1165 | shader.AddLine("discard;"); |
| 1129 | break; | 1166 | break; |
| 1130 | } | 1167 | } |
| 1168 | case OpCode::Id::BRA: { | ||
| 1169 | ASSERT_MSG(instr.bra.constant_buffer == 0, | ||
| 1170 | "BRA with constant buffers are not implemented"); | ||
| 1171 | u32 target = offset + instr.bra.GetBranchTarget(); | ||
| 1172 | shader.AddLine("{ jmp_to = " + std::to_string(target) + "u; break; }"); | ||
| 1173 | break; | ||
| 1174 | } | ||
| 1131 | case OpCode::Id::IPA: { | 1175 | case OpCode::Id::IPA: { |
| 1132 | const auto& attribute = instr.attribute.fmt28; | 1176 | const auto& attribute = instr.attribute.fmt28; |
| 1133 | regs.SetRegisterToInputAttibute(instr.gpr0, attribute.element, attribute.index); | 1177 | regs.SetRegisterToInputAttibute(instr.gpr0, attribute.element, attribute.index); |
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index a5d7807e2..3038bd6da 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp | |||
| @@ -335,6 +335,24 @@ void GMainWindow::OnDisplayTitleBars(bool show) { | |||
| 335 | } | 335 | } |
| 336 | } | 336 | } |
| 337 | 337 | ||
| 338 | bool GMainWindow::SupportsRequiredGLExtensions() { | ||
| 339 | QStringList unsupported_ext; | ||
| 340 | |||
| 341 | if (!GLAD_GL_ARB_program_interface_query) | ||
| 342 | unsupported_ext.append("ARB_program_interface_query"); | ||
| 343 | if (!GLAD_GL_ARB_separate_shader_objects) | ||
| 344 | unsupported_ext.append("ARB_separate_shader_objects"); | ||
| 345 | if (!GLAD_GL_ARB_shader_storage_buffer_object) | ||
| 346 | unsupported_ext.append("ARB_shader_storage_buffer_object"); | ||
| 347 | if (!GLAD_GL_ARB_vertex_attrib_binding) | ||
| 348 | unsupported_ext.append("ARB_vertex_attrib_binding"); | ||
| 349 | |||
| 350 | for (const QString& ext : unsupported_ext) | ||
| 351 | NGLOG_CRITICAL(Frontend, "Unsupported GL extension: {}", ext.toStdString()); | ||
| 352 | |||
| 353 | return unsupported_ext.empty(); | ||
| 354 | } | ||
| 355 | |||
| 338 | bool GMainWindow::LoadROM(const QString& filename) { | 356 | bool GMainWindow::LoadROM(const QString& filename) { |
| 339 | // Shutdown previous session if the emu thread is still active... | 357 | // Shutdown previous session if the emu thread is still active... |
| 340 | if (emu_thread != nullptr) | 358 | if (emu_thread != nullptr) |
| @@ -350,6 +368,14 @@ bool GMainWindow::LoadROM(const QString& filename) { | |||
| 350 | return false; | 368 | return false; |
| 351 | } | 369 | } |
| 352 | 370 | ||
| 371 | if (!SupportsRequiredGLExtensions()) { | ||
| 372 | QMessageBox::critical( | ||
| 373 | this, tr("Error while initializing OpenGL Core!"), | ||
| 374 | tr("Your GPU may not support one or more required OpenGL extensions. Please " | ||
| 375 | "ensure you have the latest graphics driver. See the log for more details.")); | ||
| 376 | return false; | ||
| 377 | } | ||
| 378 | |||
| 353 | Core::System& system{Core::System::GetInstance()}; | 379 | Core::System& system{Core::System::GetInstance()}; |
| 354 | 380 | ||
| 355 | system.SetGPUDebugContext(debug_context); | 381 | system.SetGPUDebugContext(debug_context); |
diff --git a/src/yuzu/main.h b/src/yuzu/main.h index 20ff65314..ac3024d8a 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h | |||
| @@ -79,6 +79,7 @@ private: | |||
| 79 | void ConnectWidgetEvents(); | 79 | void ConnectWidgetEvents(); |
| 80 | void ConnectMenuEvents(); | 80 | void ConnectMenuEvents(); |
| 81 | 81 | ||
| 82 | bool SupportsRequiredGLExtensions(); | ||
| 82 | bool LoadROM(const QString& filename); | 83 | bool LoadROM(const QString& filename); |
| 83 | void BootGame(const QString& filename); | 84 | void BootGame(const QString& filename); |
| 84 | void ShutdownGame(); | 85 | void ShutdownGame(); |
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp index e21de6f21..cfd8eb7e6 100644 --- a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp +++ b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp | |||
| @@ -78,6 +78,24 @@ void EmuWindow_SDL2::Fullscreen() { | |||
| 78 | SDL_MaximizeWindow(render_window); | 78 | SDL_MaximizeWindow(render_window); |
| 79 | } | 79 | } |
| 80 | 80 | ||
| 81 | bool EmuWindow_SDL2::SupportsRequiredGLExtensions() { | ||
| 82 | std::vector<std::string> unsupported_ext; | ||
| 83 | |||
| 84 | if (!GLAD_GL_ARB_program_interface_query) | ||
| 85 | unsupported_ext.push_back("ARB_program_interface_query"); | ||
| 86 | if (!GLAD_GL_ARB_separate_shader_objects) | ||
| 87 | unsupported_ext.push_back("ARB_separate_shader_objects"); | ||
| 88 | if (!GLAD_GL_ARB_shader_storage_buffer_object) | ||
| 89 | unsupported_ext.push_back("ARB_shader_storage_buffer_object"); | ||
| 90 | if (!GLAD_GL_ARB_vertex_attrib_binding) | ||
| 91 | unsupported_ext.push_back("ARB_vertex_attrib_binding"); | ||
| 92 | |||
| 93 | for (const std::string& ext : unsupported_ext) | ||
| 94 | NGLOG_CRITICAL(Frontend, "Unsupported GL extension: {}", ext); | ||
| 95 | |||
| 96 | return unsupported_ext.empty(); | ||
| 97 | } | ||
| 98 | |||
| 81 | EmuWindow_SDL2::EmuWindow_SDL2(bool fullscreen) { | 99 | EmuWindow_SDL2::EmuWindow_SDL2(bool fullscreen) { |
| 82 | InputCommon::Init(); | 100 | InputCommon::Init(); |
| 83 | 101 | ||
| @@ -128,6 +146,11 @@ EmuWindow_SDL2::EmuWindow_SDL2(bool fullscreen) { | |||
| 128 | exit(1); | 146 | exit(1); |
| 129 | } | 147 | } |
| 130 | 148 | ||
| 149 | if (!SupportsRequiredGLExtensions()) { | ||
| 150 | NGLOG_CRITICAL(Frontend, "GPU does not support all required OpenGL extensions! Exiting..."); | ||
| 151 | exit(1); | ||
| 152 | } | ||
| 153 | |||
| 131 | OnResize(); | 154 | OnResize(); |
| 132 | OnMinimalClientAreaChangeRequest(GetActiveConfig().min_client_area_size); | 155 | OnMinimalClientAreaChangeRequest(GetActiveConfig().min_client_area_size); |
| 133 | SDL_PumpEvents(); | 156 | SDL_PumpEvents(); |
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2.h b/src/yuzu_cmd/emu_window/emu_window_sdl2.h index 7d5cfffb6..1d835c3c6 100644 --- a/src/yuzu_cmd/emu_window/emu_window_sdl2.h +++ b/src/yuzu_cmd/emu_window/emu_window_sdl2.h | |||
| @@ -46,6 +46,9 @@ private: | |||
| 46 | /// Called when user passes the fullscreen parameter flag | 46 | /// Called when user passes the fullscreen parameter flag |
| 47 | void Fullscreen(); | 47 | void Fullscreen(); |
| 48 | 48 | ||
| 49 | /// Whether the GPU and driver supports the OpenGL extension required | ||
| 50 | bool SupportsRequiredGLExtensions(); | ||
| 51 | |||
| 49 | /// Called when a configuration change affects the minimal size of the window | 52 | /// Called when a configuration change affects the minimal size of the window |
| 50 | void OnMinimalClientAreaChangeRequest( | 53 | void OnMinimalClientAreaChangeRequest( |
| 51 | const std::pair<unsigned, unsigned>& minimal_size) override; | 54 | const std::pair<unsigned, unsigned>& minimal_size) override; |