summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--appveyor.yml2
-rw-r--r--src/core/hle/service/am/am.cpp32
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_gpu.h47
-rw-r--r--src/video_core/engines/maxwell_3d.h40
-rw-r--r--src/video_core/engines/shader_bytecode.h27
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp4
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.cpp3
-rw-r--r--src/video_core/renderer_opengl/gl_shader_decompiler.cpp111
-rw-r--r--src/yuzu/main.cpp26
-rw-r--r--src/yuzu/main.h1
-rw-r--r--src/yuzu_cmd/emu_window/emu_window_sdl2.cpp23
-rw-r--r--src/yuzu_cmd/emu_window/emu_window_sdl2.h3
12 files changed, 288 insertions, 31 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
59after_build: 59after_build:
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
161void ISelfController::SetFocusHandlingMode(Kernel::HLERequestContext& ctx) { 161void 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:
26private: 26private:
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 {
319public: 342public:
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
703void RasterizerOpenGL::SyncViewport(const MathUtil::Rectangle<u32>& surfaces_rect, u16 res_scale) { 703void 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
338bool 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
338bool GMainWindow::LoadROM(const QString& filename) { 356bool 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
81bool 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
81EmuWindow_SDL2::EmuWindow_SDL2(bool fullscreen) { 99EmuWindow_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;