diff options
| -rw-r--r-- | appveyor.yml | 2 | ||||
| -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/renderer_opengl/gl_rasterizer.cpp | 4 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer_cache.cpp | 3 | ||||
| -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 |
11 files changed, 266 insertions, 86 deletions
diff --git a/appveyor.yml b/appveyor.yml index 72cda26a7..4f928adb5 100644 --- a/appveyor.yml +++ b/appveyor.yml | |||
| @@ -53,7 +53,7 @@ build_script: | |||
| 53 | # https://www.appveyor.com/docs/build-phase | 53 | # https://www.appveyor.com/docs/build-phase |
| 54 | msbuild msvc_build/yuzu.sln /maxcpucount /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" | 54 | msbuild msvc_build/yuzu.sln /maxcpucount /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" |
| 55 | } else { | 55 | } else { |
| 56 | C:\msys64\usr\bin\bash.exe -lc 'mingw32-make -C mingw_build/ 2>&1' | 56 | C:\msys64\usr\bin\bash.exe -lc 'mingw32-make -j4 -C mingw_build/ 2>&1' |
| 57 | } | 57 | } |
| 58 | 58 | ||
| 59 | after_build: | 59 | after_build: |
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/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/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; |