diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/hle/service/am/am.cpp | 32 | ||||
| -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 | 27 | ||||
| -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 | 111 | ||||
| -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, 287 insertions, 30 deletions
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index 40922ec3a..12954556d 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp | |||
| @@ -155,7 +155,7 @@ ISelfController::ISelfController(std::shared_ptr<NVFlinger::NVFlinger> nvflinger | |||
| 155 | RegisterHandlers(functions); | 155 | RegisterHandlers(functions); |
| 156 | 156 | ||
| 157 | launchable_event = | 157 | launchable_event = |
| 158 | Kernel::Event::Create(Kernel::ResetType::OneShot, "ISelfController:LaunchableEvent"); | 158 | Kernel::Event::Create(Kernel::ResetType::Sticky, "ISelfController:LaunchableEvent"); |
| 159 | } | 159 | } |
| 160 | 160 | ||
| 161 | void ISelfController::SetFocusHandlingMode(Kernel::HLERequestContext& ctx) { | 161 | void ISelfController::SetFocusHandlingMode(Kernel::HLERequestContext& ctx) { |
| @@ -436,13 +436,13 @@ public: | |||
| 436 | static const FunctionInfo functions[] = { | 436 | static const FunctionInfo functions[] = { |
| 437 | {0, &ILibraryAppletAccessor::GetAppletStateChangedEvent, "GetAppletStateChangedEvent"}, | 437 | {0, &ILibraryAppletAccessor::GetAppletStateChangedEvent, "GetAppletStateChangedEvent"}, |
| 438 | {1, nullptr, "IsCompleted"}, | 438 | {1, nullptr, "IsCompleted"}, |
| 439 | {10, nullptr, "Start"}, | 439 | {10, &ILibraryAppletAccessor::Start, "Start"}, |
| 440 | {20, nullptr, "RequestExit"}, | 440 | {20, nullptr, "RequestExit"}, |
| 441 | {25, nullptr, "Terminate"}, | 441 | {25, nullptr, "Terminate"}, |
| 442 | {30, nullptr, "GetResult"}, | 442 | {30, &ILibraryAppletAccessor::GetResult, "GetResult"}, |
| 443 | {50, nullptr, "SetOutOfFocusApplicationSuspendingEnabled"}, | 443 | {50, nullptr, "SetOutOfFocusApplicationSuspendingEnabled"}, |
| 444 | {100, &ILibraryAppletAccessor::PushInData, "PushInData"}, | 444 | {100, &ILibraryAppletAccessor::PushInData, "PushInData"}, |
| 445 | {101, nullptr, "PopOutData"}, | 445 | {101, &ILibraryAppletAccessor::PopOutData, "PopOutData"}, |
| 446 | {102, nullptr, "PushExtraStorage"}, | 446 | {102, nullptr, "PushExtraStorage"}, |
| 447 | {103, nullptr, "PushInteractiveInData"}, | 447 | {103, nullptr, "PushInteractiveInData"}, |
| 448 | {104, nullptr, "PopInteractiveOutData"}, | 448 | {104, nullptr, "PopInteractiveOutData"}, |
| @@ -470,6 +470,20 @@ private: | |||
| 470 | NGLOG_WARNING(Service_AM, "(STUBBED) called"); | 470 | NGLOG_WARNING(Service_AM, "(STUBBED) called"); |
| 471 | } | 471 | } |
| 472 | 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 | |||
| 473 | void PushInData(Kernel::HLERequestContext& ctx) { | 487 | void PushInData(Kernel::HLERequestContext& ctx) { |
| 474 | IPC::RequestParser rp{ctx}; | 488 | IPC::RequestParser rp{ctx}; |
| 475 | storage_stack.push(rp.PopIpcInterface<AM::IStorage>()); | 489 | storage_stack.push(rp.PopIpcInterface<AM::IStorage>()); |
| @@ -480,6 +494,16 @@ private: | |||
| 480 | NGLOG_DEBUG(Service_AM, "called"); | 494 | NGLOG_DEBUG(Service_AM, "called"); |
| 481 | } | 495 | } |
| 482 | 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 | |||
| 483 | std::stack<std::shared_ptr<AM::IStorage>> storage_stack; | 507 | std::stack<std::shared_ptr<AM::IStorage>> storage_stack; |
| 484 | Kernel::SharedPtr<Kernel::Event> state_changed_event; | 508 | Kernel::SharedPtr<Kernel::Event> state_changed_event; |
| 485 | }; | 509 | }; |
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 14d72920f..22c122fcc 100644 --- a/src/video_core/engines/shader_bytecode.h +++ b/src/video_core/engines/shader_bytecode.h | |||
| @@ -252,15 +252,25 @@ union Instruction { | |||
| 252 | } fsetp; | 252 | } fsetp; |
| 253 | 253 | ||
| 254 | union { | 254 | union { |
| 255 | BitField<0, 3, u64> pred0; | ||
| 256 | BitField<3, 3, u64> pred3; | ||
| 257 | BitField<39, 3, u64> pred39; | ||
| 258 | BitField<42, 1, u64> neg_pred; | ||
| 259 | BitField<45, 2, PredOperation> op; | ||
| 260 | BitField<48, 1, u64> is_signed; | ||
| 261 | BitField<49, 3, PredCondition> cond; | ||
| 262 | } isetp; | ||
| 263 | |||
| 264 | union { | ||
| 255 | BitField<39, 3, u64> pred39; | 265 | BitField<39, 3, u64> pred39; |
| 256 | BitField<42, 1, u64> neg_pred; | 266 | BitField<42, 1, u64> neg_pred; |
| 257 | BitField<43, 1, u64> neg_a; | 267 | BitField<43, 1, u64> neg_a; |
| 258 | BitField<44, 1, u64> abs_b; | 268 | BitField<44, 1, u64> abs_b; |
| 259 | BitField<45, 2, PredOperation> op; | 269 | BitField<45, 2, PredOperation> op; |
| 260 | BitField<48, 4, PredCondition> cond; | 270 | BitField<48, 4, PredCondition> cond; |
| 271 | BitField<52, 1, u64> bf; | ||
| 261 | BitField<53, 1, u64> neg_b; | 272 | BitField<53, 1, u64> neg_b; |
| 262 | BitField<54, 1, u64> abs_a; | 273 | BitField<54, 1, u64> abs_a; |
| 263 | BitField<52, 1, u64> bf; | ||
| 264 | BitField<55, 1, u64> ftz; | 274 | BitField<55, 1, u64> ftz; |
| 265 | BitField<56, 1, u64> neg_imm; | 275 | BitField<56, 1, u64> neg_imm; |
| 266 | } fset; | 276 | } fset; |
| @@ -301,6 +311,19 @@ union Instruction { | |||
| 301 | } | 311 | } |
| 302 | } texs; | 312 | } texs; |
| 303 | 313 | ||
| 314 | union { | ||
| 315 | BitField<20, 5, u64> target; | ||
| 316 | BitField<5, 1, u64> constant_buffer; | ||
| 317 | |||
| 318 | s32 GetBranchTarget() const { | ||
| 319 | // Sign extend the branch target offset | ||
| 320 | u32 mask = 1U << (5 - 1); | ||
| 321 | u32 value = static_cast<u32>(target); | ||
| 322 | // The branch offset is relative to the next instruction, so add 1 to it. | ||
| 323 | return static_cast<s32>((value ^ mask) - mask) + 1; | ||
| 324 | } | ||
| 325 | } bra; | ||
| 326 | |||
| 304 | BitField<61, 1, u64> is_b_imm; | 327 | BitField<61, 1, u64> is_b_imm; |
| 305 | BitField<60, 1, u64> is_b_gpr; | 328 | BitField<60, 1, u64> is_b_gpr; |
| 306 | BitField<59, 1, u64> is_c_gpr; | 329 | BitField<59, 1, u64> is_c_gpr; |
| @@ -319,6 +342,7 @@ class OpCode { | |||
| 319 | public: | 342 | public: |
| 320 | enum class Id { | 343 | enum class Id { |
| 321 | KIL, | 344 | KIL, |
| 345 | BRA, | ||
| 322 | LD_A, | 346 | LD_A, |
| 323 | ST_A, | 347 | ST_A, |
| 324 | TEX, | 348 | TEX, |
| @@ -484,6 +508,7 @@ private: | |||
| 484 | std::vector<Matcher> table = { | 508 | std::vector<Matcher> table = { |
| 485 | #define INST(bitstring, op, type, name) Detail::GetMatcher(bitstring, op, type, name) | 509 | #define INST(bitstring, op, type, name) Detail::GetMatcher(bitstring, op, type, name) |
| 486 | INST("111000110011----", Id::KIL, Type::Flow, "KIL"), | 510 | INST("111000110011----", Id::KIL, Type::Flow, "KIL"), |
| 511 | INST("111000100100----", Id::BRA, Type::Flow, "BRA"), | ||
| 487 | INST("1110111111011---", Id::LD_A, Type::Memory, "LD_A"), | 512 | INST("1110111111011---", Id::LD_A, Type::Memory, "LD_A"), |
| 488 | INST("1110111111110---", Id::ST_A, Type::Memory, "ST_A"), | 513 | INST("1110111111110---", Id::ST_A, Type::Memory, "ST_A"), |
| 489 | INST("1100000000111---", Id::TEX, Type::Memory, "TEX"), | 514 | 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 e29f0a1d3..9943394c6 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 | } |
| @@ -197,6 +219,11 @@ public: | |||
| 197 | return active_type == Type::Integer; | 219 | return active_type == Type::Integer; |
| 198 | } | 220 | } |
| 199 | 221 | ||
| 222 | /// Returns the current active type of the register | ||
| 223 | Type GetActiveType() const { | ||
| 224 | return active_type; | ||
| 225 | } | ||
| 226 | |||
| 200 | /// Returns the index of the register | 227 | /// Returns the index of the register |
| 201 | size_t GetIndex() const { | 228 | size_t GetIndex() const { |
| 202 | return index; | 229 | return index; |
| @@ -328,22 +355,28 @@ public: | |||
| 328 | shader.AddLine(dest + " = " + src + ';'); | 355 | shader.AddLine(dest + " = " + src + ';'); |
| 329 | } | 356 | } |
| 330 | 357 | ||
| 331 | /// Generates code representing a uniform (C buffer) register. | 358 | /// Generates code representing a uniform (C buffer) register, interpreted as the input type. |
| 332 | std::string GetUniform(const Uniform& uniform, const Register& dest_reg) { | 359 | std::string GetUniform(const Uniform& uniform, GLSLRegister::Type type) { |
| 333 | declr_const_buffers[uniform.index].MarkAsUsed(static_cast<unsigned>(uniform.index), | 360 | declr_const_buffers[uniform.index].MarkAsUsed(static_cast<unsigned>(uniform.index), |
| 334 | static_cast<unsigned>(uniform.offset), stage); | 361 | static_cast<unsigned>(uniform.offset), stage); |
| 335 | std::string value = | 362 | std::string value = |
| 336 | 'c' + std::to_string(uniform.index) + '[' + std::to_string(uniform.offset) + ']'; | 363 | 'c' + std::to_string(uniform.index) + '[' + std::to_string(uniform.offset) + ']'; |
| 337 | 364 | ||
| 338 | if (regs[dest_reg].IsFloat()) { | 365 | if (type == GLSLRegister::Type::Float) { |
| 339 | return value; | 366 | return value; |
| 340 | } else if (regs[dest_reg].IsInteger()) { | 367 | } else if (type == GLSLRegister::Type::Integer) { |
| 341 | return "floatBitsToInt(" + value + ')'; | 368 | return "floatBitsToInt(" + value + ')'; |
| 342 | } else { | 369 | } else { |
| 343 | UNREACHABLE(); | 370 | UNREACHABLE(); |
| 344 | } | 371 | } |
| 345 | } | 372 | } |
| 346 | 373 | ||
| 374 | /// Generates code representing a uniform (C buffer) register, interpreted as the type of the | ||
| 375 | /// destination register. | ||
| 376 | std::string GetUniform(const Uniform& uniform, const Register& dest_reg) { | ||
| 377 | return GetUniform(uniform, regs[dest_reg].GetActiveType()); | ||
| 378 | } | ||
| 379 | |||
| 347 | /// Add declarations for registers | 380 | /// Add declarations for registers |
| 348 | void GenerateDeclarations() { | 381 | void GenerateDeclarations() { |
| 349 | for (const auto& reg : regs) { | 382 | for (const auto& reg : regs) { |
| @@ -892,8 +925,7 @@ private: | |||
| 892 | ASSERT_MSG(!instr.conversion.saturate_a, "Unimplemented"); | 925 | ASSERT_MSG(!instr.conversion.saturate_a, "Unimplemented"); |
| 893 | 926 | ||
| 894 | switch (opcode->GetId()) { | 927 | switch (opcode->GetId()) { |
| 895 | case OpCode::Id::I2I_R: | 928 | case OpCode::Id::I2I_R: { |
| 896 | case OpCode::Id::I2F_R: { | ||
| 897 | ASSERT_MSG(!instr.conversion.selector, "Unimplemented"); | 929 | ASSERT_MSG(!instr.conversion.selector, "Unimplemented"); |
| 898 | 930 | ||
| 899 | std::string op_a = | 931 | std::string op_a = |
| @@ -906,6 +938,17 @@ private: | |||
| 906 | regs.SetRegisterToInteger(instr.gpr0, instr.conversion.is_signed, 0, op_a, 1, 1); | 938 | regs.SetRegisterToInteger(instr.gpr0, instr.conversion.is_signed, 0, op_a, 1, 1); |
| 907 | break; | 939 | break; |
| 908 | } | 940 | } |
| 941 | case OpCode::Id::I2F_R: { | ||
| 942 | std::string op_a = | ||
| 943 | regs.GetRegisterAsInteger(instr.gpr20, 0, instr.conversion.is_signed); | ||
| 944 | |||
| 945 | if (instr.conversion.abs_a) { | ||
| 946 | op_a = "abs(" + op_a + ')'; | ||
| 947 | } | ||
| 948 | |||
| 949 | regs.SetRegisterToFloat(instr.gpr0, 0, op_a, 1, 1); | ||
| 950 | break; | ||
| 951 | } | ||
| 909 | case OpCode::Id::F2F_R: { | 952 | case OpCode::Id::F2F_R: { |
| 910 | std::string op_a = regs.GetRegisterAsFloat(instr.gpr20); | 953 | std::string op_a = regs.GetRegisterAsFloat(instr.gpr20); |
| 911 | 954 | ||
| @@ -1029,7 +1072,7 @@ private: | |||
| 1029 | if (instr.is_b_gpr) { | 1072 | if (instr.is_b_gpr) { |
| 1030 | op_b += regs.GetRegisterAsFloat(instr.gpr20); | 1073 | op_b += regs.GetRegisterAsFloat(instr.gpr20); |
| 1031 | } else { | 1074 | } else { |
| 1032 | op_b += regs.GetUniform(instr.uniform, instr.gpr0); | 1075 | op_b += regs.GetUniform(instr.uniform, GLSLRegister::Type::Float); |
| 1033 | } | 1076 | } |
| 1034 | } | 1077 | } |
| 1035 | 1078 | ||
| @@ -1060,6 +1103,42 @@ private: | |||
| 1060 | } | 1103 | } |
| 1061 | break; | 1104 | break; |
| 1062 | } | 1105 | } |
| 1106 | case OpCode::Type::IntegerSetPredicate: { | ||
| 1107 | std::string op_a = regs.GetRegisterAsInteger(instr.gpr8, 0, instr.isetp.is_signed); | ||
| 1108 | |||
| 1109 | std::string op_b{}; | ||
| 1110 | |||
| 1111 | ASSERT_MSG(!instr.is_b_imm, "ISETP_IMM not implemented"); | ||
| 1112 | |||
| 1113 | if (instr.is_b_gpr) { | ||
| 1114 | op_b += regs.GetRegisterAsInteger(instr.gpr20, 0, instr.isetp.is_signed); | ||
| 1115 | } else { | ||
| 1116 | op_b += regs.GetUniform(instr.uniform, GLSLRegister::Type::Integer); | ||
| 1117 | } | ||
| 1118 | |||
| 1119 | using Tegra::Shader::Pred; | ||
| 1120 | // We can't use the constant predicate as destination. | ||
| 1121 | ASSERT(instr.isetp.pred3 != static_cast<u64>(Pred::UnusedIndex)); | ||
| 1122 | |||
| 1123 | std::string second_pred = | ||
| 1124 | GetPredicateCondition(instr.isetp.pred39, instr.isetp.neg_pred != 0); | ||
| 1125 | |||
| 1126 | std::string comparator = GetPredicateComparison(instr.isetp.cond); | ||
| 1127 | std::string combiner = GetPredicateCombiner(instr.isetp.op); | ||
| 1128 | |||
| 1129 | std::string predicate = '(' + op_a + ") " + comparator + " (" + op_b + ')'; | ||
| 1130 | // Set the primary predicate to the result of Predicate OP SecondPredicate | ||
| 1131 | SetPredicate(instr.isetp.pred3, | ||
| 1132 | '(' + predicate + ") " + combiner + " (" + second_pred + ')'); | ||
| 1133 | |||
| 1134 | if (instr.isetp.pred0 != static_cast<u64>(Pred::UnusedIndex)) { | ||
| 1135 | // Set the secondary predicate to the result of !Predicate OP SecondPredicate, | ||
| 1136 | // if enabled | ||
| 1137 | SetPredicate(instr.isetp.pred0, | ||
| 1138 | "!(" + predicate + ") " + combiner + " (" + second_pred + ')'); | ||
| 1139 | } | ||
| 1140 | break; | ||
| 1141 | } | ||
| 1063 | case OpCode::Type::FloatSet: { | 1142 | case OpCode::Type::FloatSet: { |
| 1064 | std::string op_a = instr.fset.neg_a ? "-" : ""; | 1143 | std::string op_a = instr.fset.neg_a ? "-" : ""; |
| 1065 | op_a += regs.GetRegisterAsFloat(instr.gpr8); | 1144 | op_a += regs.GetRegisterAsFloat(instr.gpr8); |
| @@ -1080,7 +1159,7 @@ private: | |||
| 1080 | if (instr.is_b_gpr) { | 1159 | if (instr.is_b_gpr) { |
| 1081 | op_b += regs.GetRegisterAsFloat(instr.gpr20); | 1160 | op_b += regs.GetRegisterAsFloat(instr.gpr20); |
| 1082 | } else { | 1161 | } else { |
| 1083 | op_b += regs.GetUniform(instr.uniform, instr.gpr0); | 1162 | op_b += regs.GetUniform(instr.uniform, GLSLRegister::Type::Float); |
| 1084 | } | 1163 | } |
| 1085 | } | 1164 | } |
| 1086 | 1165 | ||
| @@ -1099,7 +1178,12 @@ private: | |||
| 1099 | std::string predicate = "(((" + op_a + ") " + comparator + " (" + op_b + ")) " + | 1178 | std::string predicate = "(((" + op_a + ") " + comparator + " (" + op_b + ")) " + |
| 1100 | combiner + " (" + second_pred + "))"; | 1179 | combiner + " (" + second_pred + "))"; |
| 1101 | 1180 | ||
| 1102 | regs.SetRegisterToFloat(instr.gpr0, 0, predicate + " ? 1.0 : 0.0", 1, 1); | 1181 | if (instr.fset.bf) { |
| 1182 | regs.SetRegisterToFloat(instr.gpr0, 0, predicate + " ? 1.0 : 0.0", 1, 1); | ||
| 1183 | } else { | ||
| 1184 | regs.SetRegisterToInteger(instr.gpr0, false, 0, predicate + " ? 0xFFFFFFFF : 0", 1, | ||
| 1185 | 1); | ||
| 1186 | } | ||
| 1103 | break; | 1187 | break; |
| 1104 | } | 1188 | } |
| 1105 | default: { | 1189 | default: { |
| @@ -1124,6 +1208,13 @@ private: | |||
| 1124 | shader.AddLine("discard;"); | 1208 | shader.AddLine("discard;"); |
| 1125 | break; | 1209 | break; |
| 1126 | } | 1210 | } |
| 1211 | case OpCode::Id::BRA: { | ||
| 1212 | ASSERT_MSG(instr.bra.constant_buffer == 0, | ||
| 1213 | "BRA with constant buffers are not implemented"); | ||
| 1214 | u32 target = offset + instr.bra.GetBranchTarget(); | ||
| 1215 | shader.AddLine("{ jmp_to = " + std::to_string(target) + "u; break; }"); | ||
| 1216 | break; | ||
| 1217 | } | ||
| 1127 | case OpCode::Id::IPA: { | 1218 | case OpCode::Id::IPA: { |
| 1128 | const auto& attribute = instr.attribute.fmt28; | 1219 | const auto& attribute = instr.attribute.fmt28; |
| 1129 | regs.SetRegisterToInputAttibute(instr.gpr0, attribute.element, attribute.index); | 1220 | 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; |