summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core/hle/kernel/address_arbiter.cpp53
-rw-r--r--src/core/hle/kernel/address_arbiter.h2
-rw-r--r--src/core/hle/kernel/thread.cpp4
-rw-r--r--src/core/hle/service/audio/hwopus.cpp6
-rw-r--r--src/core/hle/service/bcat/backend/backend.cpp4
-rw-r--r--src/video_core/engines/maxwell_3d.cpp91
-rw-r--r--src/video_core/engines/maxwell_3d.h23
-rw-r--r--src/video_core/engines/shader_bytecode.h4
-rw-r--r--src/video_core/gpu.cpp16
-rw-r--r--src/video_core/gpu.h2
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp1
-rw-r--r--src/video_core/renderer_opengl/gl_state.cpp1
-rw-r--r--src/video_core/renderer_opengl/gl_state.h1
-rw-r--r--src/video_core/shader/decode/arithmetic_integer.cpp4
-rw-r--r--src/video_core/shader/decode/bfi.cpp2
15 files changed, 121 insertions, 93 deletions
diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp
index 2ea3dcb61..8475b698c 100644
--- a/src/core/hle/kernel/address_arbiter.cpp
+++ b/src/core/hle/kernel/address_arbiter.cpp
@@ -201,42 +201,39 @@ void AddressArbiter::HandleWakeupThread(std::shared_ptr<Thread> thread) {
201void AddressArbiter::InsertThread(std::shared_ptr<Thread> thread) { 201void AddressArbiter::InsertThread(std::shared_ptr<Thread> thread) {
202 const VAddr arb_addr = thread->GetArbiterWaitAddress(); 202 const VAddr arb_addr = thread->GetArbiterWaitAddress();
203 std::list<std::shared_ptr<Thread>>& thread_list = arb_threads[arb_addr]; 203 std::list<std::shared_ptr<Thread>>& thread_list = arb_threads[arb_addr];
204 auto it = thread_list.begin(); 204
205 while (it != thread_list.end()) { 205 const auto iter =
206 const std::shared_ptr<Thread>& current_thread = *it; 206 std::find_if(thread_list.cbegin(), thread_list.cend(), [&thread](const auto& entry) {
207 if (current_thread->GetPriority() >= thread->GetPriority()) { 207 return entry->GetPriority() >= thread->GetPriority();
208 thread_list.insert(it, thread); 208 });
209 return; 209
210 } 210 if (iter == thread_list.cend()) {
211 ++it; 211 thread_list.push_back(std::move(thread));
212 } else {
213 thread_list.insert(iter, std::move(thread));
212 } 214 }
213 thread_list.push_back(std::move(thread));
214} 215}
215 216
216void AddressArbiter::RemoveThread(std::shared_ptr<Thread> thread) { 217void AddressArbiter::RemoveThread(std::shared_ptr<Thread> thread) {
217 const VAddr arb_addr = thread->GetArbiterWaitAddress(); 218 const VAddr arb_addr = thread->GetArbiterWaitAddress();
218 std::list<std::shared_ptr<Thread>>& thread_list = arb_threads[arb_addr]; 219 std::list<std::shared_ptr<Thread>>& thread_list = arb_threads[arb_addr];
219 auto it = thread_list.begin(); 220
220 while (it != thread_list.end()) { 221 const auto iter = std::find_if(thread_list.cbegin(), thread_list.cend(),
221 const std::shared_ptr<Thread>& current_thread = *it; 222 [&thread](const auto& entry) { return thread == entry; });
222 if (current_thread.get() == thread.get()) { 223
223 thread_list.erase(it); 224 ASSERT(iter != thread_list.cend());
224 return; 225
225 } 226 thread_list.erase(iter);
226 ++it;
227 }
228 UNREACHABLE();
229} 227}
230 228
231std::vector<std::shared_ptr<Thread>> AddressArbiter::GetThreadsWaitingOnAddress(VAddr address) { 229std::vector<std::shared_ptr<Thread>> AddressArbiter::GetThreadsWaitingOnAddress(
232 std::vector<std::shared_ptr<Thread>> result; 230 VAddr address) const {
233 std::list<std::shared_ptr<Thread>>& thread_list = arb_threads[address]; 231 const auto iter = arb_threads.find(address);
234 auto it = thread_list.begin(); 232 if (iter == arb_threads.cend()) {
235 while (it != thread_list.end()) { 233 return {};
236 std::shared_ptr<Thread> current_thread = *it;
237 result.push_back(std::move(current_thread));
238 ++it;
239 } 234 }
240 return result; 235
236 const std::list<std::shared_ptr<Thread>>& thread_list = iter->second;
237 return {thread_list.cbegin(), thread_list.cend()};
241} 238}
242} // namespace Kernel 239} // namespace Kernel
diff --git a/src/core/hle/kernel/address_arbiter.h b/src/core/hle/kernel/address_arbiter.h
index 386983e54..f958eee5a 100644
--- a/src/core/hle/kernel/address_arbiter.h
+++ b/src/core/hle/kernel/address_arbiter.h
@@ -86,7 +86,7 @@ private:
86 void RemoveThread(std::shared_ptr<Thread> thread); 86 void RemoveThread(std::shared_ptr<Thread> thread);
87 87
88 // Gets the threads waiting on an address. 88 // Gets the threads waiting on an address.
89 std::vector<std::shared_ptr<Thread>> GetThreadsWaitingOnAddress(VAddr address); 89 std::vector<std::shared_ptr<Thread>> GetThreadsWaitingOnAddress(VAddr address) const;
90 90
91 /// List of threads waiting for a address arbiter 91 /// List of threads waiting for a address arbiter
92 std::unordered_map<VAddr, std::list<std::shared_ptr<Thread>>> arb_threads; 92 std::unordered_map<VAddr, std::list<std::shared_ptr<Thread>>> arb_threads;
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index 43b30dd3d..ae5f2c8bd 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -481,7 +481,7 @@ void Thread::AdjustSchedulingOnPriority(u32 old_priority) {
481 if (GetSchedulingStatus() != ThreadSchedStatus::Runnable) { 481 if (GetSchedulingStatus() != ThreadSchedStatus::Runnable) {
482 return; 482 return;
483 } 483 }
484 auto& scheduler = Core::System::GetInstance().GlobalScheduler(); 484 auto& scheduler = kernel.GlobalScheduler();
485 if (processor_id >= 0) { 485 if (processor_id >= 0) {
486 scheduler.Unschedule(old_priority, static_cast<u32>(processor_id), this); 486 scheduler.Unschedule(old_priority, static_cast<u32>(processor_id), this);
487 } 487 }
@@ -513,7 +513,7 @@ void Thread::AdjustSchedulingOnPriority(u32 old_priority) {
513} 513}
514 514
515void Thread::AdjustSchedulingOnAffinity(u64 old_affinity_mask, s32 old_core) { 515void Thread::AdjustSchedulingOnAffinity(u64 old_affinity_mask, s32 old_core) {
516 auto& scheduler = Core::System::GetInstance().GlobalScheduler(); 516 auto& scheduler = kernel.GlobalScheduler();
517 if (GetSchedulingStatus() != ThreadSchedStatus::Runnable || 517 if (GetSchedulingStatus() != ThreadSchedStatus::Runnable ||
518 current_priority >= THREADPRIO_COUNT) { 518 current_priority >= THREADPRIO_COUNT) {
519 return; 519 return;
diff --git a/src/core/hle/service/audio/hwopus.cpp b/src/core/hle/service/audio/hwopus.cpp
index cb839e4a2..d19513cbb 100644
--- a/src/core/hle/service/audio/hwopus.cpp
+++ b/src/core/hle/service/audio/hwopus.cpp
@@ -170,8 +170,10 @@ public:
170 {3, nullptr, "SetContextForMultiStream"}, 170 {3, nullptr, "SetContextForMultiStream"},
171 {4, &IHardwareOpusDecoderManager::DecodeInterleavedWithPerfOld, "DecodeInterleavedWithPerfOld"}, 171 {4, &IHardwareOpusDecoderManager::DecodeInterleavedWithPerfOld, "DecodeInterleavedWithPerfOld"},
172 {5, nullptr, "DecodeInterleavedForMultiStreamWithPerfOld"}, 172 {5, nullptr, "DecodeInterleavedForMultiStreamWithPerfOld"},
173 {6, &IHardwareOpusDecoderManager::DecodeInterleaved, "DecodeInterleaved"}, 173 {6, &IHardwareOpusDecoderManager::DecodeInterleaved, "DecodeInterleavedWithPerfAndResetOld"},
174 {7, nullptr, "DecodeInterleavedForMultiStream"}, 174 {7, nullptr, "DecodeInterleavedForMultiStreamWithPerfAndResetOld"},
175 {8, &IHardwareOpusDecoderManager::DecodeInterleaved, "DecodeInterleaved"},
176 {9, nullptr, "DecodeInterleavedForMultiStream"},
175 }; 177 };
176 // clang-format on 178 // clang-format on
177 179
diff --git a/src/core/hle/service/bcat/backend/backend.cpp b/src/core/hle/service/bcat/backend/backend.cpp
index 6f5ea095a..def3410cc 100644
--- a/src/core/hle/service/bcat/backend/backend.cpp
+++ b/src/core/hle/service/bcat/backend/backend.cpp
@@ -117,13 +117,13 @@ bool NullBackend::SynchronizeDirectory(TitleIDVersion title, std::string name,
117} 117}
118 118
119bool NullBackend::Clear(u64 title_id) { 119bool NullBackend::Clear(u64 title_id) {
120 LOG_DEBUG(Service_BCAT, "called, title_id={:016X}"); 120 LOG_DEBUG(Service_BCAT, "called, title_id={:016X}", title_id);
121 121
122 return true; 122 return true;
123} 123}
124 124
125void NullBackend::SetPassphrase(u64 title_id, const Passphrase& passphrase) { 125void NullBackend::SetPassphrase(u64 title_id, const Passphrase& passphrase) {
126 LOG_DEBUG(Service_BCAT, "called, title_id={:016X}, passphrase = {}", title_id, 126 LOG_DEBUG(Service_BCAT, "called, title_id={:016X}, passphrase={}", title_id,
127 Common::HexToString(passphrase)); 127 Common::HexToString(passphrase));
128} 128}
129 129
diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp
index 7cea146f0..0b3e8749b 100644
--- a/src/video_core/engines/maxwell_3d.cpp
+++ b/src/video_core/engines/maxwell_3d.cpp
@@ -9,6 +9,7 @@
9#include "core/core_timing.h" 9#include "core/core_timing.h"
10#include "video_core/engines/maxwell_3d.h" 10#include "video_core/engines/maxwell_3d.h"
11#include "video_core/engines/shader_type.h" 11#include "video_core/engines/shader_type.h"
12#include "video_core/gpu.h"
12#include "video_core/memory_manager.h" 13#include "video_core/memory_manager.h"
13#include "video_core/rasterizer_interface.h" 14#include "video_core/rasterizer_interface.h"
14#include "video_core/textures/texture.h" 15#include "video_core/textures/texture.h"
@@ -519,61 +520,63 @@ void Maxwell3D::ProcessFirmwareCall4() {
519 regs.reg_array[0xd00] = 1; 520 regs.reg_array[0xd00] = 1;
520} 521}
521 522
522void Maxwell3D::ProcessQueryGet() { 523void Maxwell3D::StampQueryResult(u64 payload, bool long_query) {
524 struct LongQueryResult {
525 u64_le value;
526 u64_le timestamp;
527 };
528 static_assert(sizeof(LongQueryResult) == 16, "LongQueryResult has wrong size");
523 const GPUVAddr sequence_address{regs.query.QueryAddress()}; 529 const GPUVAddr sequence_address{regs.query.QueryAddress()};
524 // Since the sequence address is given as a GPU VAddr, we have to convert it to an application 530 if (long_query) {
525 // VAddr before writing. 531 // Write the 128-bit result structure in long mode. Note: We emulate an infinitely fast
532 // GPU, this command may actually take a while to complete in real hardware due to GPU
533 // wait queues.
534 LongQueryResult query_result{payload, system.GPU().GetTicks()};
535 memory_manager.WriteBlock(sequence_address, &query_result, sizeof(query_result));
536 } else {
537 memory_manager.Write<u32>(sequence_address, static_cast<u32>(payload));
538 }
539}
526 540
541void Maxwell3D::ProcessQueryGet() {
527 // TODO(Subv): Support the other query units. 542 // TODO(Subv): Support the other query units.
528 ASSERT_MSG(regs.query.query_get.unit == Regs::QueryUnit::Crop, 543 ASSERT_MSG(regs.query.query_get.unit == Regs::QueryUnit::Crop,
529 "Units other than CROP are unimplemented"); 544 "Units other than CROP are unimplemented");
530 545
531 u64 result = 0; 546 switch (regs.query.query_get.operation) {
532 547 case Regs::QueryOperation::Release: {
533 // TODO(Subv): Support the other query variables 548 const u64 result = regs.query.query_sequence;
534 switch (regs.query.query_get.select) { 549 StampQueryResult(result, regs.query.query_get.short_query == 0);
535 case Regs::QuerySelect::Zero:
536 // This seems to actually write the query sequence to the query address.
537 result = regs.query.query_sequence;
538 break; 550 break;
539 default:
540 result = 1;
541 UNIMPLEMENTED_MSG("Unimplemented query select type {}",
542 static_cast<u32>(regs.query.query_get.select.Value()));
543 } 551 }
544 552 case Regs::QueryOperation::Acquire: {
545 // TODO(Subv): Research and implement how query sync conditions work. 553 // Todo(Blinkhawk): Under this operation, the GPU waits for the CPU
546 554 // to write a value that matches the current payload.
547 struct LongQueryResult { 555 UNIMPLEMENTED_MSG("Unimplemented query operation ACQUIRE");
548 u64_le value; 556 break;
549 u64_le timestamp; 557 }
550 }; 558 case Regs::QueryOperation::Counter: {
551 static_assert(sizeof(LongQueryResult) == 16, "LongQueryResult has wrong size"); 559 u64 result{};
552 560 switch (regs.query.query_get.select) {
553 switch (regs.query.query_get.mode) { 561 case Regs::QuerySelect::Zero:
554 case Regs::QueryMode::Write: 562 result = 0;
555 case Regs::QueryMode::Write2: { 563 break;
556 u32 sequence = regs.query.query_sequence; 564 default:
557 if (regs.query.query_get.short_query) { 565 result = 1;
558 // Write the current query sequence to the sequence address. 566 UNIMPLEMENTED_MSG("Unimplemented query select type {}",
559 // TODO(Subv): Find out what happens if you use a long query type but mark it as a short 567 static_cast<u32>(regs.query.query_get.select.Value()));
560 // query.
561 memory_manager.Write<u32>(sequence_address, sequence);
562 } else {
563 // Write the 128-bit result structure in long mode. Note: We emulate an infinitely fast
564 // GPU, this command may actually take a while to complete in real hardware due to GPU
565 // wait queues.
566 LongQueryResult query_result{};
567 query_result.value = result;
568 // TODO(Subv): Generate a real GPU timestamp and write it here instead of CoreTiming
569 query_result.timestamp = system.CoreTiming().GetTicks();
570 memory_manager.WriteBlock(sequence_address, &query_result, sizeof(query_result));
571 } 568 }
569 StampQueryResult(result, regs.query.query_get.short_query == 0);
570 break;
571 }
572 case Regs::QueryOperation::Trap: {
573 UNIMPLEMENTED_MSG("Unimplemented query operation TRAP");
574 break;
575 }
576 default: {
577 UNIMPLEMENTED_MSG("Unknown query operation");
572 break; 578 break;
573 } 579 }
574 default:
575 UNIMPLEMENTED_MSG("Query mode {} not implemented",
576 static_cast<u32>(regs.query.query_get.mode.Value()));
577 } 580 }
578} 581}
579 582
diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h
index e437bacb7..0a2af54e5 100644
--- a/src/video_core/engines/maxwell_3d.h
+++ b/src/video_core/engines/maxwell_3d.h
@@ -71,12 +71,11 @@ public:
71 static constexpr std::size_t MaxConstBuffers = 18; 71 static constexpr std::size_t MaxConstBuffers = 18;
72 static constexpr std::size_t MaxConstBufferSize = 0x10000; 72 static constexpr std::size_t MaxConstBufferSize = 0x10000;
73 73
74 enum class QueryMode : u32 { 74 enum class QueryOperation : u32 {
75 Write = 0, 75 Release = 0,
76 Sync = 1, 76 Acquire = 1,
77 // TODO(Subv): It is currently unknown what the difference between method 2 and method 0 77 Counter = 2,
78 // is. 78 Trap = 3,
79 Write2 = 2,
80 }; 79 };
81 80
82 enum class QueryUnit : u32 { 81 enum class QueryUnit : u32 {
@@ -862,7 +861,11 @@ public:
862 861
863 float point_size; 862 float point_size;
864 863
865 INSERT_UNION_PADDING_WORDS(0x7); 864 INSERT_UNION_PADDING_WORDS(0x1);
865
866 u32 point_sprite_enable;
867
868 INSERT_UNION_PADDING_WORDS(0x5);
866 869
867 u32 zeta_enable; 870 u32 zeta_enable;
868 871
@@ -1077,7 +1080,7 @@ public:
1077 u32 query_sequence; 1080 u32 query_sequence;
1078 union { 1081 union {
1079 u32 raw; 1082 u32 raw;
1080 BitField<0, 2, QueryMode> mode; 1083 BitField<0, 2, QueryOperation> operation;
1081 BitField<4, 1, u32> fence; 1084 BitField<4, 1, u32> fence;
1082 BitField<12, 4, QueryUnit> unit; 1085 BitField<12, 4, QueryUnit> unit;
1083 BitField<16, 1, QuerySyncCondition> sync_cond; 1086 BitField<16, 1, QuerySyncCondition> sync_cond;
@@ -1409,6 +1412,9 @@ private:
1409 /// Handles a write to the QUERY_GET register. 1412 /// Handles a write to the QUERY_GET register.
1410 void ProcessQueryGet(); 1413 void ProcessQueryGet();
1411 1414
1415 // Writes the query result accordingly
1416 void StampQueryResult(u64 payload, bool long_query);
1417
1412 // Handles Conditional Rendering 1418 // Handles Conditional Rendering
1413 void ProcessQueryCondition(); 1419 void ProcessQueryCondition();
1414 1420
@@ -1494,6 +1500,7 @@ ASSERT_REG_POSITION(vb_element_base, 0x50D);
1494ASSERT_REG_POSITION(vb_base_instance, 0x50E); 1500ASSERT_REG_POSITION(vb_base_instance, 0x50E);
1495ASSERT_REG_POSITION(clip_distance_enabled, 0x544); 1501ASSERT_REG_POSITION(clip_distance_enabled, 0x544);
1496ASSERT_REG_POSITION(point_size, 0x546); 1502ASSERT_REG_POSITION(point_size, 0x546);
1503ASSERT_REG_POSITION(point_sprite_enable, 0x548);
1497ASSERT_REG_POSITION(zeta_enable, 0x54E); 1504ASSERT_REG_POSITION(zeta_enable, 0x54E);
1498ASSERT_REG_POSITION(multisample_control, 0x54F); 1505ASSERT_REG_POSITION(multisample_control, 0x54F);
1499ASSERT_REG_POSITION(condition, 0x554); 1506ASSERT_REG_POSITION(condition, 0x554);
diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h
index 402869fde..c9bc83cd7 100644
--- a/src/video_core/engines/shader_bytecode.h
+++ b/src/video_core/engines/shader_bytecode.h
@@ -1677,11 +1677,11 @@ union Instruction {
1677 } xmad; 1677 } xmad;
1678 1678
1679 union { 1679 union {
1680 BitField<20, 14, u64> offset; 1680 BitField<20, 14, u64> shifted_offset;
1681 BitField<34, 5, u64> index; 1681 BitField<34, 5, u64> index;
1682 1682
1683 u64 GetOffset() const { 1683 u64 GetOffset() const {
1684 return offset * 4; 1684 return shifted_offset * 4;
1685 } 1685 }
1686 } cbuf34; 1686 } cbuf34;
1687 1687
diff --git a/src/video_core/gpu.cpp b/src/video_core/gpu.cpp
index 062ca83b8..4419ab735 100644
--- a/src/video_core/gpu.cpp
+++ b/src/video_core/gpu.cpp
@@ -6,6 +6,7 @@
6#include "common/microprofile.h" 6#include "common/microprofile.h"
7#include "core/core.h" 7#include "core/core.h"
8#include "core/core_timing.h" 8#include "core/core_timing.h"
9#include "core/core_timing_util.h"
9#include "core/memory.h" 10#include "core/memory.h"
10#include "video_core/engines/fermi_2d.h" 11#include "video_core/engines/fermi_2d.h"
11#include "video_core/engines/kepler_compute.h" 12#include "video_core/engines/kepler_compute.h"
@@ -122,6 +123,19 @@ bool GPU::CancelSyncptInterrupt(const u32 syncpoint_id, const u32 value) {
122 return true; 123 return true;
123} 124}
124 125
126u64 GPU::GetTicks() const {
127 // This values were reversed engineered by fincs from NVN
128 // The gpu clock is reported in units of 385/625 nanoseconds
129 constexpr u64 gpu_ticks_num = 384;
130 constexpr u64 gpu_ticks_den = 625;
131
132 const u64 cpu_ticks = system.CoreTiming().GetTicks();
133 const u64 nanoseconds = Core::Timing::CyclesToNs(cpu_ticks).count();
134 const u64 nanoseconds_num = nanoseconds / gpu_ticks_den;
135 const u64 nanoseconds_rem = nanoseconds % gpu_ticks_den;
136 return nanoseconds_num * gpu_ticks_num + (nanoseconds_rem * gpu_ticks_num) / gpu_ticks_den;
137}
138
125void GPU::FlushCommands() { 139void GPU::FlushCommands() {
126 renderer.Rasterizer().FlushCommands(); 140 renderer.Rasterizer().FlushCommands();
127} 141}
@@ -340,7 +354,7 @@ void GPU::ProcessSemaphoreTriggerMethod() {
340 block.sequence = regs.semaphore_sequence; 354 block.sequence = regs.semaphore_sequence;
341 // TODO(Kmather73): Generate a real GPU timestamp and write it here instead of 355 // TODO(Kmather73): Generate a real GPU timestamp and write it here instead of
342 // CoreTiming 356 // CoreTiming
343 block.timestamp = system.CoreTiming().GetTicks(); 357 block.timestamp = GetTicks();
344 memory_manager->WriteBlock(regs.semaphore_address.SemaphoreAddress(), &block, 358 memory_manager->WriteBlock(regs.semaphore_address.SemaphoreAddress(), &block,
345 sizeof(block)); 359 sizeof(block));
346 } else { 360 } else {
diff --git a/src/video_core/gpu.h b/src/video_core/gpu.h
index b648317bb..07727210c 100644
--- a/src/video_core/gpu.h
+++ b/src/video_core/gpu.h
@@ -192,6 +192,8 @@ public:
192 192
193 bool CancelSyncptInterrupt(u32 syncpoint_id, u32 value); 193 bool CancelSyncptInterrupt(u32 syncpoint_id, u32 value);
194 194
195 u64 GetTicks() const;
196
195 std::unique_lock<std::mutex> LockSync() { 197 std::unique_lock<std::mutex> LockSync() {
196 return std::unique_lock{sync_mutex}; 198 return std::unique_lock{sync_mutex};
197 } 199 }
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index 46a7433ea..b0eb14c8b 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -1220,6 +1220,7 @@ void RasterizerOpenGL::SyncPointState() {
1220 // Limit the point size to 1 since nouveau sometimes sets a point size of 0 (and that's invalid 1220 // Limit the point size to 1 since nouveau sometimes sets a point size of 0 (and that's invalid
1221 // in OpenGL). 1221 // in OpenGL).
1222 state.point.program_control = regs.vp_point_size.enable != 0; 1222 state.point.program_control = regs.vp_point_size.enable != 0;
1223 state.point.sprite = regs.point_sprite_enable != 0;
1223 state.point.size = std::max(1.0f, regs.point_size); 1224 state.point.size = std::max(1.0f, regs.point_size);
1224} 1225}
1225 1226
diff --git a/src/video_core/renderer_opengl/gl_state.cpp b/src/video_core/renderer_opengl/gl_state.cpp
index cc185e9e1..ab1f7983c 100644
--- a/src/video_core/renderer_opengl/gl_state.cpp
+++ b/src/video_core/renderer_opengl/gl_state.cpp
@@ -128,6 +128,7 @@ void OpenGLState::ApplyClipDistances() {
128 128
129void OpenGLState::ApplyPointSize() { 129void OpenGLState::ApplyPointSize() {
130 Enable(GL_PROGRAM_POINT_SIZE, cur_state.point.program_control, point.program_control); 130 Enable(GL_PROGRAM_POINT_SIZE, cur_state.point.program_control, point.program_control);
131 Enable(GL_POINT_SPRITE, cur_state.point.sprite, point.sprite);
131 if (UpdateValue(cur_state.point.size, point.size)) { 132 if (UpdateValue(cur_state.point.size, point.size)) {
132 glPointSize(point.size); 133 glPointSize(point.size);
133 } 134 }
diff --git a/src/video_core/renderer_opengl/gl_state.h b/src/video_core/renderer_opengl/gl_state.h
index 678e5cd89..4953eeda2 100644
--- a/src/video_core/renderer_opengl/gl_state.h
+++ b/src/video_core/renderer_opengl/gl_state.h
@@ -132,6 +132,7 @@ public:
132 132
133 struct { 133 struct {
134 bool program_control = false; // GL_PROGRAM_POINT_SIZE 134 bool program_control = false; // GL_PROGRAM_POINT_SIZE
135 bool sprite = false; // GL_POINT_SPRITE
135 GLfloat size = 1.0f; // GL_POINT_SIZE 136 GLfloat size = 1.0f; // GL_POINT_SIZE
136 } point; 137 } point;
137 138
diff --git a/src/video_core/shader/decode/arithmetic_integer.cpp b/src/video_core/shader/decode/arithmetic_integer.cpp
index e60875cc4..21366869d 100644
--- a/src/video_core/shader/decode/arithmetic_integer.cpp
+++ b/src/video_core/shader/decode/arithmetic_integer.cpp
@@ -166,13 +166,13 @@ u32 ShaderIR::DecodeArithmeticInteger(NodeBlock& bb, u32 pc) {
166 const auto [op_rhs, test] = [&]() -> std::pair<Node, Node> { 166 const auto [op_rhs, test] = [&]() -> std::pair<Node, Node> {
167 switch (opcode->get().GetId()) { 167 switch (opcode->get().GetId()) {
168 case OpCode::Id::ICMP_CR: 168 case OpCode::Id::ICMP_CR:
169 return {GetConstBuffer(instr.cbuf34.index, instr.cbuf34.offset), 169 return {GetConstBuffer(instr.cbuf34.index, instr.cbuf34.GetOffset()),
170 GetRegister(instr.gpr39)}; 170 GetRegister(instr.gpr39)};
171 case OpCode::Id::ICMP_R: 171 case OpCode::Id::ICMP_R:
172 return {GetRegister(instr.gpr20), GetRegister(instr.gpr39)}; 172 return {GetRegister(instr.gpr20), GetRegister(instr.gpr39)};
173 case OpCode::Id::ICMP_RC: 173 case OpCode::Id::ICMP_RC:
174 return {GetRegister(instr.gpr39), 174 return {GetRegister(instr.gpr39),
175 GetConstBuffer(instr.cbuf34.index, instr.cbuf34.offset)}; 175 GetConstBuffer(instr.cbuf34.index, instr.cbuf34.GetOffset())};
176 case OpCode::Id::ICMP_IMM: 176 case OpCode::Id::ICMP_IMM:
177 return {Immediate(instr.alu.GetSignedImm20_20()), GetRegister(instr.gpr39)}; 177 return {Immediate(instr.alu.GetSignedImm20_20()), GetRegister(instr.gpr39)};
178 default: 178 default:
diff --git a/src/video_core/shader/decode/bfi.cpp b/src/video_core/shader/decode/bfi.cpp
index f992bbe2a..70d1c055b 100644
--- a/src/video_core/shader/decode/bfi.cpp
+++ b/src/video_core/shader/decode/bfi.cpp
@@ -21,7 +21,7 @@ u32 ShaderIR::DecodeBfi(NodeBlock& bb, u32 pc) {
21 switch (opcode->get().GetId()) { 21 switch (opcode->get().GetId()) {
22 case OpCode::Id::BFI_RC: 22 case OpCode::Id::BFI_RC:
23 return {GetRegister(instr.gpr39), 23 return {GetRegister(instr.gpr39),
24 GetConstBuffer(instr.cbuf34.index, instr.cbuf34.offset)}; 24 GetConstBuffer(instr.cbuf34.index, instr.cbuf34.GetOffset())};
25 case OpCode::Id::BFI_IMM_R: 25 case OpCode::Id::BFI_IMM_R:
26 return {Immediate(instr.alu.GetSignedImm20_20()), GetRegister(instr.gpr39)}; 26 return {Immediate(instr.alu.GetSignedImm20_20()), GetRegister(instr.gpr39)};
27 default: 27 default: