diff options
Diffstat (limited to 'src')
53 files changed, 818 insertions, 425 deletions
diff --git a/src/audio_core/stream.cpp b/src/audio_core/stream.cpp index 4ce2d374e..8ab5649df 100644 --- a/src/audio_core/stream.cpp +++ b/src/audio_core/stream.cpp | |||
| @@ -37,7 +37,7 @@ Stream::Stream(u32 sample_rate, Format format, ReleaseCallback&& release_callbac | |||
| 37 | : sample_rate{sample_rate}, format{format}, release_callback{std::move(release_callback)}, | 37 | : sample_rate{sample_rate}, format{format}, release_callback{std::move(release_callback)}, |
| 38 | sink_stream{sink_stream}, name{std::move(name_)} { | 38 | sink_stream{sink_stream}, name{std::move(name_)} { |
| 39 | 39 | ||
| 40 | release_event = CoreTiming::RegisterEvent( | 40 | release_event = Core::Timing::RegisterEvent( |
| 41 | name, [this](u64 userdata, int cycles_late) { ReleaseActiveBuffer(); }); | 41 | name, [this](u64 userdata, int cycles_late) { ReleaseActiveBuffer(); }); |
| 42 | } | 42 | } |
| 43 | 43 | ||
| @@ -57,7 +57,7 @@ Stream::State Stream::GetState() const { | |||
| 57 | 57 | ||
| 58 | s64 Stream::GetBufferReleaseCycles(const Buffer& buffer) const { | 58 | s64 Stream::GetBufferReleaseCycles(const Buffer& buffer) const { |
| 59 | const std::size_t num_samples{buffer.GetSamples().size() / GetNumChannels()}; | 59 | const std::size_t num_samples{buffer.GetSamples().size() / GetNumChannels()}; |
| 60 | return CoreTiming::usToCycles((static_cast<u64>(num_samples) * 1000000) / sample_rate); | 60 | return Core::Timing::usToCycles((static_cast<u64>(num_samples) * 1000000) / sample_rate); |
| 61 | } | 61 | } |
| 62 | 62 | ||
| 63 | static void VolumeAdjustSamples(std::vector<s16>& samples) { | 63 | static void VolumeAdjustSamples(std::vector<s16>& samples) { |
| @@ -99,7 +99,8 @@ void Stream::PlayNextBuffer() { | |||
| 99 | 99 | ||
| 100 | sink_stream.EnqueueSamples(GetNumChannels(), active_buffer->GetSamples()); | 100 | sink_stream.EnqueueSamples(GetNumChannels(), active_buffer->GetSamples()); |
| 101 | 101 | ||
| 102 | CoreTiming::ScheduleEventThreadsafe(GetBufferReleaseCycles(*active_buffer), release_event, {}); | 102 | Core::Timing::ScheduleEventThreadsafe(GetBufferReleaseCycles(*active_buffer), release_event, |
| 103 | {}); | ||
| 103 | } | 104 | } |
| 104 | 105 | ||
| 105 | void Stream::ReleaseActiveBuffer() { | 106 | void Stream::ReleaseActiveBuffer() { |
diff --git a/src/audio_core/stream.h b/src/audio_core/stream.h index aebfeb51d..caa775544 100644 --- a/src/audio_core/stream.h +++ b/src/audio_core/stream.h | |||
| @@ -13,7 +13,7 @@ | |||
| 13 | #include "audio_core/buffer.h" | 13 | #include "audio_core/buffer.h" |
| 14 | #include "common/common_types.h" | 14 | #include "common/common_types.h" |
| 15 | 15 | ||
| 16 | namespace CoreTiming { | 16 | namespace Core::Timing { |
| 17 | struct EventType; | 17 | struct EventType; |
| 18 | } | 18 | } |
| 19 | 19 | ||
| @@ -91,16 +91,16 @@ private: | |||
| 91 | /// Gets the number of core cycles when the specified buffer will be released | 91 | /// Gets the number of core cycles when the specified buffer will be released |
| 92 | s64 GetBufferReleaseCycles(const Buffer& buffer) const; | 92 | s64 GetBufferReleaseCycles(const Buffer& buffer) const; |
| 93 | 93 | ||
| 94 | u32 sample_rate; ///< Sample rate of the stream | 94 | u32 sample_rate; ///< Sample rate of the stream |
| 95 | Format format; ///< Format of the stream | 95 | Format format; ///< Format of the stream |
| 96 | ReleaseCallback release_callback; ///< Buffer release callback for the stream | 96 | ReleaseCallback release_callback; ///< Buffer release callback for the stream |
| 97 | State state{State::Stopped}; ///< Playback state of the stream | 97 | State state{State::Stopped}; ///< Playback state of the stream |
| 98 | CoreTiming::EventType* release_event{}; ///< Core timing release event for the stream | 98 | Core::Timing::EventType* release_event{}; ///< Core timing release event for the stream |
| 99 | BufferPtr active_buffer; ///< Actively playing buffer in the stream | 99 | BufferPtr active_buffer; ///< Actively playing buffer in the stream |
| 100 | std::queue<BufferPtr> queued_buffers; ///< Buffers queued to be played in the stream | 100 | std::queue<BufferPtr> queued_buffers; ///< Buffers queued to be played in the stream |
| 101 | std::queue<BufferPtr> released_buffers; ///< Buffers recently released from the stream | 101 | std::queue<BufferPtr> released_buffers; ///< Buffers recently released from the stream |
| 102 | SinkStream& sink_stream; ///< Output sink for the stream | 102 | SinkStream& sink_stream; ///< Output sink for the stream |
| 103 | std::string name; ///< Name of the stream, must be unique | 103 | std::string name; ///< Name of the stream, must be unique |
| 104 | }; | 104 | }; |
| 105 | 105 | ||
| 106 | using StreamPtr = std::shared_ptr<Stream>; | 106 | using StreamPtr = std::shared_ptr<Stream>; |
diff --git a/src/common/logging/backend.cpp b/src/common/logging/backend.cpp index 12f6d0114..a5e031189 100644 --- a/src/common/logging/backend.cpp +++ b/src/common/logging/backend.cpp | |||
| @@ -232,6 +232,7 @@ void DebuggerBackend::Write(const Entry& entry) { | |||
| 232 | CLS(Render) \ | 232 | CLS(Render) \ |
| 233 | SUB(Render, Software) \ | 233 | SUB(Render, Software) \ |
| 234 | SUB(Render, OpenGL) \ | 234 | SUB(Render, OpenGL) \ |
| 235 | SUB(Render, Vulkan) \ | ||
| 235 | CLS(Audio) \ | 236 | CLS(Audio) \ |
| 236 | SUB(Audio, DSP) \ | 237 | SUB(Audio, DSP) \ |
| 237 | SUB(Audio, Sink) \ | 238 | SUB(Audio, Sink) \ |
diff --git a/src/common/logging/log.h b/src/common/logging/log.h index d4ec31ec3..8ed6d5050 100644 --- a/src/common/logging/log.h +++ b/src/common/logging/log.h | |||
| @@ -112,6 +112,7 @@ enum class Class : ClassType { | |||
| 112 | Render, ///< Emulator video output and hardware acceleration | 112 | Render, ///< Emulator video output and hardware acceleration |
| 113 | Render_Software, ///< Software renderer backend | 113 | Render_Software, ///< Software renderer backend |
| 114 | Render_OpenGL, ///< OpenGL backend | 114 | Render_OpenGL, ///< OpenGL backend |
| 115 | Render_Vulkan, ///< Vulkan backend | ||
| 115 | Audio, ///< Audio emulation | 116 | Audio, ///< Audio emulation |
| 116 | Audio_DSP, ///< The HLE implementation of the DSP | 117 | Audio_DSP, ///< The HLE implementation of the DSP |
| 117 | Audio_Sink, ///< Emulator audio output backend | 118 | Audio_Sink, ///< Emulator audio output backend |
diff --git a/src/common/threadsafe_queue.h b/src/common/threadsafe_queue.h index edf13bc49..f553efdc9 100644 --- a/src/common/threadsafe_queue.h +++ b/src/common/threadsafe_queue.h | |||
| @@ -7,17 +7,16 @@ | |||
| 7 | // a simple lockless thread-safe, | 7 | // a simple lockless thread-safe, |
| 8 | // single reader, single writer queue | 8 | // single reader, single writer queue |
| 9 | 9 | ||
| 10 | #include <algorithm> | ||
| 11 | #include <atomic> | 10 | #include <atomic> |
| 12 | #include <cstddef> | 11 | #include <cstddef> |
| 13 | #include <mutex> | 12 | #include <mutex> |
| 14 | #include "common/common_types.h" | 13 | #include <utility> |
| 15 | 14 | ||
| 16 | namespace Common { | 15 | namespace Common { |
| 17 | template <typename T, bool NeedSize = true> | 16 | template <typename T> |
| 18 | class SPSCQueue { | 17 | class SPSCQueue { |
| 19 | public: | 18 | public: |
| 20 | SPSCQueue() : size(0) { | 19 | SPSCQueue() { |
| 21 | write_ptr = read_ptr = new ElementPtr(); | 20 | write_ptr = read_ptr = new ElementPtr(); |
| 22 | } | 21 | } |
| 23 | ~SPSCQueue() { | 22 | ~SPSCQueue() { |
| @@ -25,13 +24,12 @@ public: | |||
| 25 | delete read_ptr; | 24 | delete read_ptr; |
| 26 | } | 25 | } |
| 27 | 26 | ||
| 28 | u32 Size() const { | 27 | std::size_t Size() const { |
| 29 | static_assert(NeedSize, "using Size() on FifoQueue without NeedSize"); | ||
| 30 | return size.load(); | 28 | return size.load(); |
| 31 | } | 29 | } |
| 32 | 30 | ||
| 33 | bool Empty() const { | 31 | bool Empty() const { |
| 34 | return !read_ptr->next.load(); | 32 | return Size() == 0; |
| 35 | } | 33 | } |
| 36 | 34 | ||
| 37 | T& Front() const { | 35 | T& Front() const { |
| @@ -47,13 +45,13 @@ public: | |||
| 47 | ElementPtr* new_ptr = new ElementPtr(); | 45 | ElementPtr* new_ptr = new ElementPtr(); |
| 48 | write_ptr->next.store(new_ptr, std::memory_order_release); | 46 | write_ptr->next.store(new_ptr, std::memory_order_release); |
| 49 | write_ptr = new_ptr; | 47 | write_ptr = new_ptr; |
| 50 | if (NeedSize) | 48 | |
| 51 | size++; | 49 | ++size; |
| 52 | } | 50 | } |
| 53 | 51 | ||
| 54 | void Pop() { | 52 | void Pop() { |
| 55 | if (NeedSize) | 53 | --size; |
| 56 | size--; | 54 | |
| 57 | ElementPtr* tmpptr = read_ptr; | 55 | ElementPtr* tmpptr = read_ptr; |
| 58 | // advance the read pointer | 56 | // advance the read pointer |
| 59 | read_ptr = tmpptr->next.load(); | 57 | read_ptr = tmpptr->next.load(); |
| @@ -66,8 +64,7 @@ public: | |||
| 66 | if (Empty()) | 64 | if (Empty()) |
| 67 | return false; | 65 | return false; |
| 68 | 66 | ||
| 69 | if (NeedSize) | 67 | --size; |
| 70 | size--; | ||
| 71 | 68 | ||
| 72 | ElementPtr* tmpptr = read_ptr; | 69 | ElementPtr* tmpptr = read_ptr; |
| 73 | read_ptr = tmpptr->next.load(std::memory_order_acquire); | 70 | read_ptr = tmpptr->next.load(std::memory_order_acquire); |
| @@ -89,7 +86,7 @@ private: | |||
| 89 | // and a pointer to the next ElementPtr | 86 | // and a pointer to the next ElementPtr |
| 90 | class ElementPtr { | 87 | class ElementPtr { |
| 91 | public: | 88 | public: |
| 92 | ElementPtr() : next(nullptr) {} | 89 | ElementPtr() {} |
| 93 | ~ElementPtr() { | 90 | ~ElementPtr() { |
| 94 | ElementPtr* next_ptr = next.load(); | 91 | ElementPtr* next_ptr = next.load(); |
| 95 | 92 | ||
| @@ -98,21 +95,21 @@ private: | |||
| 98 | } | 95 | } |
| 99 | 96 | ||
| 100 | T current; | 97 | T current; |
| 101 | std::atomic<ElementPtr*> next; | 98 | std::atomic<ElementPtr*> next{nullptr}; |
| 102 | }; | 99 | }; |
| 103 | 100 | ||
| 104 | ElementPtr* write_ptr; | 101 | ElementPtr* write_ptr; |
| 105 | ElementPtr* read_ptr; | 102 | ElementPtr* read_ptr; |
| 106 | std::atomic<u32> size; | 103 | std::atomic_size_t size{0}; |
| 107 | }; | 104 | }; |
| 108 | 105 | ||
| 109 | // a simple thread-safe, | 106 | // a simple thread-safe, |
| 110 | // single reader, multiple writer queue | 107 | // single reader, multiple writer queue |
| 111 | 108 | ||
| 112 | template <typename T, bool NeedSize = true> | 109 | template <typename T> |
| 113 | class MPSCQueue { | 110 | class MPSCQueue { |
| 114 | public: | 111 | public: |
| 115 | u32 Size() const { | 112 | std::size_t Size() const { |
| 116 | return spsc_queue.Size(); | 113 | return spsc_queue.Size(); |
| 117 | } | 114 | } |
| 118 | 115 | ||
| @@ -144,7 +141,7 @@ public: | |||
| 144 | } | 141 | } |
| 145 | 142 | ||
| 146 | private: | 143 | private: |
| 147 | SPSCQueue<T, NeedSize> spsc_queue; | 144 | SPSCQueue<T> spsc_queue; |
| 148 | std::mutex write_lock; | 145 | std::mutex write_lock; |
| 149 | }; | 146 | }; |
| 150 | } // namespace Common | 147 | } // namespace Common |
diff --git a/src/core/arm/dynarmic/arm_dynarmic.cpp b/src/core/arm/dynarmic/arm_dynarmic.cpp index afbda8d8b..f28951f8a 100644 --- a/src/core/arm/dynarmic/arm_dynarmic.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic.cpp | |||
| @@ -112,14 +112,14 @@ public: | |||
| 112 | // Always execute at least one tick. | 112 | // Always execute at least one tick. |
| 113 | amortized_ticks = std::max<u64>(amortized_ticks, 1); | 113 | amortized_ticks = std::max<u64>(amortized_ticks, 1); |
| 114 | 114 | ||
| 115 | CoreTiming::AddTicks(amortized_ticks); | 115 | Timing::AddTicks(amortized_ticks); |
| 116 | num_interpreted_instructions = 0; | 116 | num_interpreted_instructions = 0; |
| 117 | } | 117 | } |
| 118 | u64 GetTicksRemaining() override { | 118 | u64 GetTicksRemaining() override { |
| 119 | return std::max(CoreTiming::GetDowncount(), 0); | 119 | return std::max(Timing::GetDowncount(), 0); |
| 120 | } | 120 | } |
| 121 | u64 GetCNTPCT() override { | 121 | u64 GetCNTPCT() override { |
| 122 | return CoreTiming::GetTicks(); | 122 | return Timing::GetTicks(); |
| 123 | } | 123 | } |
| 124 | 124 | ||
| 125 | ARM_Dynarmic& parent; | 125 | ARM_Dynarmic& parent; |
diff --git a/src/core/arm/unicorn/arm_unicorn.cpp b/src/core/arm/unicorn/arm_unicorn.cpp index c455c81fb..c36c15c02 100644 --- a/src/core/arm/unicorn/arm_unicorn.cpp +++ b/src/core/arm/unicorn/arm_unicorn.cpp | |||
| @@ -177,7 +177,7 @@ void ARM_Unicorn::Run() { | |||
| 177 | if (GDBStub::IsServerEnabled()) { | 177 | if (GDBStub::IsServerEnabled()) { |
| 178 | ExecuteInstructions(std::max(4000000, 0)); | 178 | ExecuteInstructions(std::max(4000000, 0)); |
| 179 | } else { | 179 | } else { |
| 180 | ExecuteInstructions(std::max(CoreTiming::GetDowncount(), 0)); | 180 | ExecuteInstructions(std::max(Timing::GetDowncount(), 0)); |
| 181 | } | 181 | } |
| 182 | } | 182 | } |
| 183 | 183 | ||
| @@ -190,7 +190,7 @@ MICROPROFILE_DEFINE(ARM_Jit_Unicorn, "ARM JIT", "Unicorn", MP_RGB(255, 64, 64)); | |||
| 190 | void ARM_Unicorn::ExecuteInstructions(int num_instructions) { | 190 | void ARM_Unicorn::ExecuteInstructions(int num_instructions) { |
| 191 | MICROPROFILE_SCOPE(ARM_Jit_Unicorn); | 191 | MICROPROFILE_SCOPE(ARM_Jit_Unicorn); |
| 192 | CHECKED(uc_emu_start(uc, GetPC(), 1ULL << 63, 0, num_instructions)); | 192 | CHECKED(uc_emu_start(uc, GetPC(), 1ULL << 63, 0, num_instructions)); |
| 193 | CoreTiming::AddTicks(num_instructions); | 193 | Timing::AddTicks(num_instructions); |
| 194 | if (GDBStub::IsServerEnabled()) { | 194 | if (GDBStub::IsServerEnabled()) { |
| 195 | if (last_bkpt_hit) { | 195 | if (last_bkpt_hit) { |
| 196 | uc_reg_write(uc, UC_ARM64_REG_PC, &last_bkpt.address); | 196 | uc_reg_write(uc, UC_ARM64_REG_PC, &last_bkpt.address); |
diff --git a/src/core/core.cpp b/src/core/core.cpp index 1dd576c26..4d9d21ee4 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp | |||
| @@ -94,7 +94,7 @@ struct System::Impl { | |||
| 94 | ResultStatus Init(System& system, Frontend::EmuWindow& emu_window) { | 94 | ResultStatus Init(System& system, Frontend::EmuWindow& emu_window) { |
| 95 | LOG_DEBUG(HW_Memory, "initialized OK"); | 95 | LOG_DEBUG(HW_Memory, "initialized OK"); |
| 96 | 96 | ||
| 97 | CoreTiming::Init(); | 97 | Timing::Init(); |
| 98 | kernel.Initialize(); | 98 | kernel.Initialize(); |
| 99 | 99 | ||
| 100 | const auto current_time = std::chrono::duration_cast<std::chrono::seconds>( | 100 | const auto current_time = std::chrono::duration_cast<std::chrono::seconds>( |
| @@ -205,7 +205,7 @@ struct System::Impl { | |||
| 205 | 205 | ||
| 206 | // Shutdown kernel and core timing | 206 | // Shutdown kernel and core timing |
| 207 | kernel.Shutdown(); | 207 | kernel.Shutdown(); |
| 208 | CoreTiming::Shutdown(); | 208 | Timing::Shutdown(); |
| 209 | 209 | ||
| 210 | // Close app loader | 210 | // Close app loader |
| 211 | app_loader.reset(); | 211 | app_loader.reset(); |
| @@ -232,7 +232,7 @@ struct System::Impl { | |||
| 232 | } | 232 | } |
| 233 | 233 | ||
| 234 | PerfStatsResults GetAndResetPerfStats() { | 234 | PerfStatsResults GetAndResetPerfStats() { |
| 235 | return perf_stats.GetAndResetStats(CoreTiming::GetGlobalTimeUs()); | 235 | return perf_stats.GetAndResetStats(Timing::GetGlobalTimeUs()); |
| 236 | } | 236 | } |
| 237 | 237 | ||
| 238 | Kernel::KernelCore kernel; | 238 | Kernel::KernelCore kernel; |
diff --git a/src/core/core_cpu.cpp b/src/core/core_cpu.cpp index fffda8a99..452366250 100644 --- a/src/core/core_cpu.cpp +++ b/src/core/core_cpu.cpp | |||
| @@ -93,14 +93,14 @@ void Cpu::RunLoop(bool tight_loop) { | |||
| 93 | 93 | ||
| 94 | if (IsMainCore()) { | 94 | if (IsMainCore()) { |
| 95 | // TODO(Subv): Only let CoreTiming idle if all 4 cores are idling. | 95 | // TODO(Subv): Only let CoreTiming idle if all 4 cores are idling. |
| 96 | CoreTiming::Idle(); | 96 | Timing::Idle(); |
| 97 | CoreTiming::Advance(); | 97 | Timing::Advance(); |
| 98 | } | 98 | } |
| 99 | 99 | ||
| 100 | PrepareReschedule(); | 100 | PrepareReschedule(); |
| 101 | } else { | 101 | } else { |
| 102 | if (IsMainCore()) { | 102 | if (IsMainCore()) { |
| 103 | CoreTiming::Advance(); | 103 | Timing::Advance(); |
| 104 | } | 104 | } |
| 105 | 105 | ||
| 106 | if (tight_loop) { | 106 | if (tight_loop) { |
diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp index 7953c8720..4ea00c277 100644 --- a/src/core/core_timing.cpp +++ b/src/core/core_timing.cpp | |||
| @@ -15,7 +15,7 @@ | |||
| 15 | #include "common/threadsafe_queue.h" | 15 | #include "common/threadsafe_queue.h" |
| 16 | #include "core/core_timing_util.h" | 16 | #include "core/core_timing_util.h" |
| 17 | 17 | ||
| 18 | namespace CoreTiming { | 18 | namespace Core::Timing { |
| 19 | 19 | ||
| 20 | static s64 global_timer; | 20 | static s64 global_timer; |
| 21 | static int slice_length; | 21 | static int slice_length; |
| @@ -54,10 +54,10 @@ static std::vector<Event> event_queue; | |||
| 54 | static u64 event_fifo_id; | 54 | static u64 event_fifo_id; |
| 55 | // the queue for storing the events from other threads threadsafe until they will be added | 55 | // the queue for storing the events from other threads threadsafe until they will be added |
| 56 | // to the event_queue by the emu thread | 56 | // to the event_queue by the emu thread |
| 57 | static Common::MPSCQueue<Event, false> ts_queue; | 57 | static Common::MPSCQueue<Event> ts_queue; |
| 58 | 58 | ||
| 59 | // the queue for unscheduling the events from other threads threadsafe | 59 | // the queue for unscheduling the events from other threads threadsafe |
| 60 | static Common::MPSCQueue<std::pair<const EventType*, u64>, false> unschedule_queue; | 60 | static Common::MPSCQueue<std::pair<const EventType*, u64>> unschedule_queue; |
| 61 | 61 | ||
| 62 | constexpr int MAX_SLICE_LENGTH = 20000; | 62 | constexpr int MAX_SLICE_LENGTH = 20000; |
| 63 | 63 | ||
| @@ -70,8 +70,6 @@ static bool is_global_timer_sane; | |||
| 70 | 70 | ||
| 71 | static EventType* ev_lost = nullptr; | 71 | static EventType* ev_lost = nullptr; |
| 72 | 72 | ||
| 73 | static void EmptyTimedCallback(u64 userdata, s64 cyclesLate) {} | ||
| 74 | |||
| 75 | EventType* RegisterEvent(const std::string& name, TimedCallback callback) { | 73 | EventType* RegisterEvent(const std::string& name, TimedCallback callback) { |
| 76 | // check for existing type with same name. | 74 | // check for existing type with same name. |
| 77 | // we want event type names to remain unique so that we can use them for serialization. | 75 | // we want event type names to remain unique so that we can use them for serialization. |
| @@ -104,7 +102,9 @@ void Init() { | |||
| 104 | is_global_timer_sane = true; | 102 | is_global_timer_sane = true; |
| 105 | 103 | ||
| 106 | event_fifo_id = 0; | 104 | event_fifo_id = 0; |
| 107 | ev_lost = RegisterEvent("_lost_event", &EmptyTimedCallback); | 105 | |
| 106 | const auto empty_timed_callback = [](u64, s64) {}; | ||
| 107 | ev_lost = RegisterEvent("_lost_event", empty_timed_callback); | ||
| 108 | } | 108 | } |
| 109 | 109 | ||
| 110 | void Shutdown() { | 110 | void Shutdown() { |
| @@ -242,4 +242,4 @@ int GetDowncount() { | |||
| 242 | return downcount; | 242 | return downcount; |
| 243 | } | 243 | } |
| 244 | 244 | ||
| 245 | } // namespace CoreTiming | 245 | } // namespace Core::Timing |
diff --git a/src/core/core_timing.h b/src/core/core_timing.h index 9ed757bd7..093989d4c 100644 --- a/src/core/core_timing.h +++ b/src/core/core_timing.h | |||
| @@ -22,7 +22,7 @@ | |||
| 22 | #include <string> | 22 | #include <string> |
| 23 | #include "common/common_types.h" | 23 | #include "common/common_types.h" |
| 24 | 24 | ||
| 25 | namespace CoreTiming { | 25 | namespace Core::Timing { |
| 26 | 26 | ||
| 27 | struct EventType; | 27 | struct EventType; |
| 28 | 28 | ||
| @@ -92,4 +92,4 @@ std::chrono::microseconds GetGlobalTimeUs(); | |||
| 92 | 92 | ||
| 93 | int GetDowncount(); | 93 | int GetDowncount(); |
| 94 | 94 | ||
| 95 | } // namespace CoreTiming | 95 | } // namespace Core::Timing |
diff --git a/src/core/core_timing_util.cpp b/src/core/core_timing_util.cpp index 73dea4edb..88ff70233 100644 --- a/src/core/core_timing_util.cpp +++ b/src/core/core_timing_util.cpp | |||
| @@ -8,7 +8,7 @@ | |||
| 8 | #include <limits> | 8 | #include <limits> |
| 9 | #include "common/logging/log.h" | 9 | #include "common/logging/log.h" |
| 10 | 10 | ||
| 11 | namespace CoreTiming { | 11 | namespace Core::Timing { |
| 12 | 12 | ||
| 13 | constexpr u64 MAX_VALUE_TO_MULTIPLY = std::numeric_limits<s64>::max() / BASE_CLOCK_RATE; | 13 | constexpr u64 MAX_VALUE_TO_MULTIPLY = std::numeric_limits<s64>::max() / BASE_CLOCK_RATE; |
| 14 | 14 | ||
| @@ -60,4 +60,4 @@ s64 nsToCycles(u64 ns) { | |||
| 60 | return (BASE_CLOCK_RATE * static_cast<s64>(ns)) / 1000000000; | 60 | return (BASE_CLOCK_RATE * static_cast<s64>(ns)) / 1000000000; |
| 61 | } | 61 | } |
| 62 | 62 | ||
| 63 | } // namespace CoreTiming | 63 | } // namespace Core::Timing |
diff --git a/src/core/core_timing_util.h b/src/core/core_timing_util.h index 5c3718782..513cfac1b 100644 --- a/src/core/core_timing_util.h +++ b/src/core/core_timing_util.h | |||
| @@ -6,7 +6,7 @@ | |||
| 6 | 6 | ||
| 7 | #include "common/common_types.h" | 7 | #include "common/common_types.h" |
| 8 | 8 | ||
| 9 | namespace CoreTiming { | 9 | namespace Core::Timing { |
| 10 | 10 | ||
| 11 | // The below clock rate is based on Switch's clockspeed being widely known as 1.020GHz | 11 | // The below clock rate is based on Switch's clockspeed being widely known as 1.020GHz |
| 12 | // The exact value used is of course unverified. | 12 | // The exact value used is of course unverified. |
| @@ -61,4 +61,4 @@ inline u64 cyclesToMs(s64 cycles) { | |||
| 61 | return cycles * 1000 / BASE_CLOCK_RATE; | 61 | return cycles * 1000 / BASE_CLOCK_RATE; |
| 62 | } | 62 | } |
| 63 | 63 | ||
| 64 | } // namespace CoreTiming | 64 | } // namespace Core::Timing |
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 7a524ce5a..3721ae8fe 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp | |||
| @@ -124,7 +124,7 @@ struct KernelCore::Impl { | |||
| 124 | 124 | ||
| 125 | void InitializeThreads() { | 125 | void InitializeThreads() { |
| 126 | thread_wakeup_event_type = | 126 | thread_wakeup_event_type = |
| 127 | CoreTiming::RegisterEvent("ThreadWakeupCallback", ThreadWakeupCallback); | 127 | Core::Timing::RegisterEvent("ThreadWakeupCallback", ThreadWakeupCallback); |
| 128 | } | 128 | } |
| 129 | 129 | ||
| 130 | std::atomic<u32> next_object_id{0}; | 130 | std::atomic<u32> next_object_id{0}; |
| @@ -137,7 +137,7 @@ struct KernelCore::Impl { | |||
| 137 | 137 | ||
| 138 | SharedPtr<ResourceLimit> system_resource_limit; | 138 | SharedPtr<ResourceLimit> system_resource_limit; |
| 139 | 139 | ||
| 140 | CoreTiming::EventType* thread_wakeup_event_type = nullptr; | 140 | Core::Timing::EventType* thread_wakeup_event_type = nullptr; |
| 141 | // TODO(yuriks): This can be removed if Thread objects are explicitly pooled in the future, | 141 | // TODO(yuriks): This can be removed if Thread objects are explicitly pooled in the future, |
| 142 | // allowing us to simply use a pool index or similar. | 142 | // allowing us to simply use a pool index or similar. |
| 143 | Kernel::HandleTable thread_wakeup_callback_handle_table; | 143 | Kernel::HandleTable thread_wakeup_callback_handle_table; |
| @@ -213,7 +213,7 @@ u64 KernelCore::CreateNewProcessID() { | |||
| 213 | return impl->next_process_id++; | 213 | return impl->next_process_id++; |
| 214 | } | 214 | } |
| 215 | 215 | ||
| 216 | CoreTiming::EventType* KernelCore::ThreadWakeupCallbackEventType() const { | 216 | Core::Timing::EventType* KernelCore::ThreadWakeupCallbackEventType() const { |
| 217 | return impl->thread_wakeup_event_type; | 217 | return impl->thread_wakeup_event_type; |
| 218 | } | 218 | } |
| 219 | 219 | ||
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index c643a6401..7406f107e 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h | |||
| @@ -11,7 +11,7 @@ | |||
| 11 | template <typename T> | 11 | template <typename T> |
| 12 | class ResultVal; | 12 | class ResultVal; |
| 13 | 13 | ||
| 14 | namespace CoreTiming { | 14 | namespace Core::Timing { |
| 15 | struct EventType; | 15 | struct EventType; |
| 16 | } | 16 | } |
| 17 | 17 | ||
| @@ -89,7 +89,7 @@ private: | |||
| 89 | u64 CreateNewThreadID(); | 89 | u64 CreateNewThreadID(); |
| 90 | 90 | ||
| 91 | /// Retrieves the event type used for thread wakeup callbacks. | 91 | /// Retrieves the event type used for thread wakeup callbacks. |
| 92 | CoreTiming::EventType* ThreadWakeupCallbackEventType() const; | 92 | Core::Timing::EventType* ThreadWakeupCallbackEventType() const; |
| 93 | 93 | ||
| 94 | /// Provides a reference to the thread wakeup callback handle table. | 94 | /// Provides a reference to the thread wakeup callback handle table. |
| 95 | Kernel::HandleTable& ThreadWakeupCallbackHandleTable(); | 95 | Kernel::HandleTable& ThreadWakeupCallbackHandleTable(); |
diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index df4d6cf0a..9e2517e1b 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp | |||
| @@ -111,7 +111,7 @@ void Scheduler::SwitchContext(Thread* new_thread) { | |||
| 111 | 111 | ||
| 112 | void Scheduler::UpdateLastContextSwitchTime(Thread* thread, Process* process) { | 112 | void Scheduler::UpdateLastContextSwitchTime(Thread* thread, Process* process) { |
| 113 | const u64 prev_switch_ticks = last_context_switch_time; | 113 | const u64 prev_switch_ticks = last_context_switch_time; |
| 114 | const u64 most_recent_switch_ticks = CoreTiming::GetTicks(); | 114 | const u64 most_recent_switch_ticks = Core::Timing::GetTicks(); |
| 115 | const u64 update_ticks = most_recent_switch_ticks - prev_switch_ticks; | 115 | const u64 update_ticks = most_recent_switch_ticks - prev_switch_ticks; |
| 116 | 116 | ||
| 117 | if (thread != nullptr) { | 117 | if (thread != nullptr) { |
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 7cfecb68c..5f040f79f 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp | |||
| @@ -927,9 +927,9 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id) | |||
| 927 | if (same_thread && info_sub_id == 0xFFFFFFFFFFFFFFFF) { | 927 | if (same_thread && info_sub_id == 0xFFFFFFFFFFFFFFFF) { |
| 928 | const u64 thread_ticks = current_thread->GetTotalCPUTimeTicks(); | 928 | const u64 thread_ticks = current_thread->GetTotalCPUTimeTicks(); |
| 929 | 929 | ||
| 930 | out_ticks = thread_ticks + (CoreTiming::GetTicks() - prev_ctx_ticks); | 930 | out_ticks = thread_ticks + (Core::Timing::GetTicks() - prev_ctx_ticks); |
| 931 | } else if (same_thread && info_sub_id == system.CurrentCoreIndex()) { | 931 | } else if (same_thread && info_sub_id == system.CurrentCoreIndex()) { |
| 932 | out_ticks = CoreTiming::GetTicks() - prev_ctx_ticks; | 932 | out_ticks = Core::Timing::GetTicks() - prev_ctx_ticks; |
| 933 | } | 933 | } |
| 934 | 934 | ||
| 935 | *result = out_ticks; | 935 | *result = out_ticks; |
| @@ -1546,10 +1546,10 @@ static ResultCode SignalToAddress(VAddr address, u32 type, s32 value, s32 num_to | |||
| 1546 | static u64 GetSystemTick() { | 1546 | static u64 GetSystemTick() { |
| 1547 | LOG_TRACE(Kernel_SVC, "called"); | 1547 | LOG_TRACE(Kernel_SVC, "called"); |
| 1548 | 1548 | ||
| 1549 | const u64 result{CoreTiming::GetTicks()}; | 1549 | const u64 result{Core::Timing::GetTicks()}; |
| 1550 | 1550 | ||
| 1551 | // Advance time to defeat dumb games that busy-wait for the frame to end. | 1551 | // Advance time to defeat dumb games that busy-wait for the frame to end. |
| 1552 | CoreTiming::AddTicks(400); | 1552 | Core::Timing::AddTicks(400); |
| 1553 | 1553 | ||
| 1554 | return result; | 1554 | return result; |
| 1555 | } | 1555 | } |
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index d3984dfc4..7881c2b90 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp | |||
| @@ -43,7 +43,7 @@ Thread::~Thread() = default; | |||
| 43 | 43 | ||
| 44 | void Thread::Stop() { | 44 | void Thread::Stop() { |
| 45 | // Cancel any outstanding wakeup events for this thread | 45 | // Cancel any outstanding wakeup events for this thread |
| 46 | CoreTiming::UnscheduleEvent(kernel.ThreadWakeupCallbackEventType(), callback_handle); | 46 | Core::Timing::UnscheduleEvent(kernel.ThreadWakeupCallbackEventType(), callback_handle); |
| 47 | kernel.ThreadWakeupCallbackHandleTable().Close(callback_handle); | 47 | kernel.ThreadWakeupCallbackHandleTable().Close(callback_handle); |
| 48 | callback_handle = 0; | 48 | callback_handle = 0; |
| 49 | 49 | ||
| @@ -85,12 +85,13 @@ void Thread::WakeAfterDelay(s64 nanoseconds) { | |||
| 85 | 85 | ||
| 86 | // This function might be called from any thread so we have to be cautious and use the | 86 | // This function might be called from any thread so we have to be cautious and use the |
| 87 | // thread-safe version of ScheduleEvent. | 87 | // thread-safe version of ScheduleEvent. |
| 88 | CoreTiming::ScheduleEventThreadsafe(CoreTiming::nsToCycles(nanoseconds), | 88 | Core::Timing::ScheduleEventThreadsafe(Core::Timing::nsToCycles(nanoseconds), |
| 89 | kernel.ThreadWakeupCallbackEventType(), callback_handle); | 89 | kernel.ThreadWakeupCallbackEventType(), callback_handle); |
| 90 | } | 90 | } |
| 91 | 91 | ||
| 92 | void Thread::CancelWakeupTimer() { | 92 | void Thread::CancelWakeupTimer() { |
| 93 | CoreTiming::UnscheduleEventThreadsafe(kernel.ThreadWakeupCallbackEventType(), callback_handle); | 93 | Core::Timing::UnscheduleEventThreadsafe(kernel.ThreadWakeupCallbackEventType(), |
| 94 | callback_handle); | ||
| 94 | } | 95 | } |
| 95 | 96 | ||
| 96 | static std::optional<s32> GetNextProcessorId(u64 mask) { | 97 | static std::optional<s32> GetNextProcessorId(u64 mask) { |
| @@ -197,7 +198,7 @@ ResultVal<SharedPtr<Thread>> Thread::Create(KernelCore& kernel, std::string name | |||
| 197 | thread->stack_top = stack_top; | 198 | thread->stack_top = stack_top; |
| 198 | thread->tpidr_el0 = 0; | 199 | thread->tpidr_el0 = 0; |
| 199 | thread->nominal_priority = thread->current_priority = priority; | 200 | thread->nominal_priority = thread->current_priority = priority; |
| 200 | thread->last_running_ticks = CoreTiming::GetTicks(); | 201 | thread->last_running_ticks = Core::Timing::GetTicks(); |
| 201 | thread->processor_id = processor_id; | 202 | thread->processor_id = processor_id; |
| 202 | thread->ideal_core = processor_id; | 203 | thread->ideal_core = processor_id; |
| 203 | thread->affinity_mask = 1ULL << processor_id; | 204 | thread->affinity_mask = 1ULL << processor_id; |
| @@ -257,7 +258,7 @@ void Thread::SetStatus(ThreadStatus new_status) { | |||
| 257 | } | 258 | } |
| 258 | 259 | ||
| 259 | if (status == ThreadStatus::Running) { | 260 | if (status == ThreadStatus::Running) { |
| 260 | last_running_ticks = CoreTiming::GetTicks(); | 261 | last_running_ticks = Core::Timing::GetTicks(); |
| 261 | } | 262 | } |
| 262 | 263 | ||
| 263 | status = new_status; | 264 | status = new_status; |
diff --git a/src/core/hle/service/hid/controllers/debug_pad.cpp b/src/core/hle/service/hid/controllers/debug_pad.cpp index c22357d8c..b264c9503 100644 --- a/src/core/hle/service/hid/controllers/debug_pad.cpp +++ b/src/core/hle/service/hid/controllers/debug_pad.cpp | |||
| @@ -22,7 +22,7 @@ void Controller_DebugPad::OnInit() {} | |||
| 22 | void Controller_DebugPad::OnRelease() {} | 22 | void Controller_DebugPad::OnRelease() {} |
| 23 | 23 | ||
| 24 | void Controller_DebugPad::OnUpdate(u8* data, std::size_t size) { | 24 | void Controller_DebugPad::OnUpdate(u8* data, std::size_t size) { |
| 25 | shared_memory.header.timestamp = CoreTiming::GetTicks(); | 25 | shared_memory.header.timestamp = Core::Timing::GetTicks(); |
| 26 | shared_memory.header.total_entry_count = 17; | 26 | shared_memory.header.total_entry_count = 17; |
| 27 | 27 | ||
| 28 | if (!IsControllerActivated()) { | 28 | if (!IsControllerActivated()) { |
diff --git a/src/core/hle/service/hid/controllers/gesture.cpp b/src/core/hle/service/hid/controllers/gesture.cpp index 898572277..6d21f1a7d 100644 --- a/src/core/hle/service/hid/controllers/gesture.cpp +++ b/src/core/hle/service/hid/controllers/gesture.cpp | |||
| @@ -18,7 +18,7 @@ void Controller_Gesture::OnInit() {} | |||
| 18 | void Controller_Gesture::OnRelease() {} | 18 | void Controller_Gesture::OnRelease() {} |
| 19 | 19 | ||
| 20 | void Controller_Gesture::OnUpdate(u8* data, std::size_t size) { | 20 | void Controller_Gesture::OnUpdate(u8* data, std::size_t size) { |
| 21 | shared_memory.header.timestamp = CoreTiming::GetTicks(); | 21 | shared_memory.header.timestamp = Core::Timing::GetTicks(); |
| 22 | shared_memory.header.total_entry_count = 17; | 22 | shared_memory.header.total_entry_count = 17; |
| 23 | 23 | ||
| 24 | if (!IsControllerActivated()) { | 24 | if (!IsControllerActivated()) { |
diff --git a/src/core/hle/service/hid/controllers/keyboard.cpp b/src/core/hle/service/hid/controllers/keyboard.cpp index ca75adc2b..798f30436 100644 --- a/src/core/hle/service/hid/controllers/keyboard.cpp +++ b/src/core/hle/service/hid/controllers/keyboard.cpp | |||
| @@ -20,7 +20,7 @@ void Controller_Keyboard::OnInit() {} | |||
| 20 | void Controller_Keyboard::OnRelease() {} | 20 | void Controller_Keyboard::OnRelease() {} |
| 21 | 21 | ||
| 22 | void Controller_Keyboard::OnUpdate(u8* data, std::size_t size) { | 22 | void Controller_Keyboard::OnUpdate(u8* data, std::size_t size) { |
| 23 | shared_memory.header.timestamp = CoreTiming::GetTicks(); | 23 | shared_memory.header.timestamp = Core::Timing::GetTicks(); |
| 24 | shared_memory.header.total_entry_count = 17; | 24 | shared_memory.header.total_entry_count = 17; |
| 25 | 25 | ||
| 26 | if (!IsControllerActivated()) { | 26 | if (!IsControllerActivated()) { |
diff --git a/src/core/hle/service/hid/controllers/mouse.cpp b/src/core/hle/service/hid/controllers/mouse.cpp index 63391dbe9..4985037be 100644 --- a/src/core/hle/service/hid/controllers/mouse.cpp +++ b/src/core/hle/service/hid/controllers/mouse.cpp | |||
| @@ -18,7 +18,7 @@ void Controller_Mouse::OnInit() {} | |||
| 18 | void Controller_Mouse::OnRelease() {} | 18 | void Controller_Mouse::OnRelease() {} |
| 19 | 19 | ||
| 20 | void Controller_Mouse::OnUpdate(u8* data, std::size_t size) { | 20 | void Controller_Mouse::OnUpdate(u8* data, std::size_t size) { |
| 21 | shared_memory.header.timestamp = CoreTiming::GetTicks(); | 21 | shared_memory.header.timestamp = Core::Timing::GetTicks(); |
| 22 | shared_memory.header.total_entry_count = 17; | 22 | shared_memory.header.total_entry_count = 17; |
| 23 | 23 | ||
| 24 | if (!IsControllerActivated()) { | 24 | if (!IsControllerActivated()) { |
diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp index 04c8c35a8..ffdd1c593 100644 --- a/src/core/hle/service/hid/controllers/npad.cpp +++ b/src/core/hle/service/hid/controllers/npad.cpp | |||
| @@ -308,7 +308,7 @@ void Controller_NPad::OnUpdate(u8* data, std::size_t data_len) { | |||
| 308 | const auto& last_entry = | 308 | const auto& last_entry = |
| 309 | main_controller->npad[main_controller->common.last_entry_index]; | 309 | main_controller->npad[main_controller->common.last_entry_index]; |
| 310 | 310 | ||
| 311 | main_controller->common.timestamp = CoreTiming::GetTicks(); | 311 | main_controller->common.timestamp = Core::Timing::GetTicks(); |
| 312 | main_controller->common.last_entry_index = | 312 | main_controller->common.last_entry_index = |
| 313 | (main_controller->common.last_entry_index + 1) % 17; | 313 | (main_controller->common.last_entry_index + 1) % 17; |
| 314 | 314 | ||
diff --git a/src/core/hle/service/hid/controllers/stubbed.cpp b/src/core/hle/service/hid/controllers/stubbed.cpp index 02fcfadd9..cca4dca1d 100644 --- a/src/core/hle/service/hid/controllers/stubbed.cpp +++ b/src/core/hle/service/hid/controllers/stubbed.cpp | |||
| @@ -22,7 +22,7 @@ void Controller_Stubbed::OnUpdate(u8* data, std::size_t size) { | |||
| 22 | } | 22 | } |
| 23 | 23 | ||
| 24 | CommonHeader header{}; | 24 | CommonHeader header{}; |
| 25 | header.timestamp = CoreTiming::GetTicks(); | 25 | header.timestamp = Core::Timing::GetTicks(); |
| 26 | header.total_entry_count = 17; | 26 | header.total_entry_count = 17; |
| 27 | header.entry_count = 0; | 27 | header.entry_count = 0; |
| 28 | header.last_entry_index = 0; | 28 | header.last_entry_index = 0; |
diff --git a/src/core/hle/service/hid/controllers/touchscreen.cpp b/src/core/hle/service/hid/controllers/touchscreen.cpp index f666b1bd8..a7c8acc72 100644 --- a/src/core/hle/service/hid/controllers/touchscreen.cpp +++ b/src/core/hle/service/hid/controllers/touchscreen.cpp | |||
| @@ -21,7 +21,7 @@ void Controller_Touchscreen::OnInit() {} | |||
| 21 | void Controller_Touchscreen::OnRelease() {} | 21 | void Controller_Touchscreen::OnRelease() {} |
| 22 | 22 | ||
| 23 | void Controller_Touchscreen::OnUpdate(u8* data, std::size_t size) { | 23 | void Controller_Touchscreen::OnUpdate(u8* data, std::size_t size) { |
| 24 | shared_memory.header.timestamp = CoreTiming::GetTicks(); | 24 | shared_memory.header.timestamp = Core::Timing::GetTicks(); |
| 25 | shared_memory.header.total_entry_count = 17; | 25 | shared_memory.header.total_entry_count = 17; |
| 26 | 26 | ||
| 27 | if (!IsControllerActivated()) { | 27 | if (!IsControllerActivated()) { |
| @@ -48,7 +48,7 @@ void Controller_Touchscreen::OnUpdate(u8* data, std::size_t size) { | |||
| 48 | touch_entry.diameter_x = Settings::values.touchscreen.diameter_x; | 48 | touch_entry.diameter_x = Settings::values.touchscreen.diameter_x; |
| 49 | touch_entry.diameter_y = Settings::values.touchscreen.diameter_y; | 49 | touch_entry.diameter_y = Settings::values.touchscreen.diameter_y; |
| 50 | touch_entry.rotation_angle = Settings::values.touchscreen.rotation_angle; | 50 | touch_entry.rotation_angle = Settings::values.touchscreen.rotation_angle; |
| 51 | const u64 tick = CoreTiming::GetTicks(); | 51 | const u64 tick = Core::Timing::GetTicks(); |
| 52 | touch_entry.delta_time = tick - last_touch; | 52 | touch_entry.delta_time = tick - last_touch; |
| 53 | last_touch = tick; | 53 | last_touch = tick; |
| 54 | touch_entry.finger = Settings::values.touchscreen.finger; | 54 | touch_entry.finger = Settings::values.touchscreen.finger; |
diff --git a/src/core/hle/service/hid/controllers/xpad.cpp b/src/core/hle/service/hid/controllers/xpad.cpp index cd397c70b..eff03d14e 100644 --- a/src/core/hle/service/hid/controllers/xpad.cpp +++ b/src/core/hle/service/hid/controllers/xpad.cpp | |||
| @@ -19,7 +19,7 @@ void Controller_XPad::OnRelease() {} | |||
| 19 | 19 | ||
| 20 | void Controller_XPad::OnUpdate(u8* data, std::size_t size) { | 20 | void Controller_XPad::OnUpdate(u8* data, std::size_t size) { |
| 21 | for (auto& xpad_entry : shared_memory.shared_memory_entries) { | 21 | for (auto& xpad_entry : shared_memory.shared_memory_entries) { |
| 22 | xpad_entry.header.timestamp = CoreTiming::GetTicks(); | 22 | xpad_entry.header.timestamp = Core::Timing::GetTicks(); |
| 23 | xpad_entry.header.total_entry_count = 17; | 23 | xpad_entry.header.total_entry_count = 17; |
| 24 | 24 | ||
| 25 | if (!IsControllerActivated()) { | 25 | if (!IsControllerActivated()) { |
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index 008bf3f02..79c320d04 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp | |||
| @@ -36,9 +36,9 @@ namespace Service::HID { | |||
| 36 | 36 | ||
| 37 | // Updating period for each HID device. | 37 | // Updating period for each HID device. |
| 38 | // TODO(ogniK): Find actual polling rate of hid | 38 | // TODO(ogniK): Find actual polling rate of hid |
| 39 | constexpr u64 pad_update_ticks = CoreTiming::BASE_CLOCK_RATE / 66; | 39 | constexpr u64 pad_update_ticks = Core::Timing::BASE_CLOCK_RATE / 66; |
| 40 | constexpr u64 accelerometer_update_ticks = CoreTiming::BASE_CLOCK_RATE / 100; | 40 | constexpr u64 accelerometer_update_ticks = Core::Timing::BASE_CLOCK_RATE / 100; |
| 41 | constexpr u64 gyroscope_update_ticks = CoreTiming::BASE_CLOCK_RATE / 100; | 41 | constexpr u64 gyroscope_update_ticks = Core::Timing::BASE_CLOCK_RATE / 100; |
| 42 | constexpr std::size_t SHARED_MEMORY_SIZE = 0x40000; | 42 | constexpr std::size_t SHARED_MEMORY_SIZE = 0x40000; |
| 43 | 43 | ||
| 44 | IAppletResource::IAppletResource() : ServiceFramework("IAppletResource") { | 44 | IAppletResource::IAppletResource() : ServiceFramework("IAppletResource") { |
| @@ -73,14 +73,13 @@ IAppletResource::IAppletResource() : ServiceFramework("IAppletResource") { | |||
| 73 | GetController<Controller_Stubbed>(HidController::Unknown3).SetCommonHeaderOffset(0x5000); | 73 | GetController<Controller_Stubbed>(HidController::Unknown3).SetCommonHeaderOffset(0x5000); |
| 74 | 74 | ||
| 75 | // Register update callbacks | 75 | // Register update callbacks |
| 76 | pad_update_event = | 76 | pad_update_event = Core::Timing::RegisterEvent( |
| 77 | CoreTiming::RegisterEvent("HID::UpdatePadCallback", [this](u64 userdata, int cycles_late) { | 77 | "HID::UpdatePadCallback", |
| 78 | UpdateControllers(userdata, cycles_late); | 78 | [this](u64 userdata, int cycles_late) { UpdateControllers(userdata, cycles_late); }); |
| 79 | }); | ||
| 80 | 79 | ||
| 81 | // TODO(shinyquagsire23): Other update callbacks? (accel, gyro?) | 80 | // TODO(shinyquagsire23): Other update callbacks? (accel, gyro?) |
| 82 | 81 | ||
| 83 | CoreTiming::ScheduleEvent(pad_update_ticks, pad_update_event); | 82 | Core::Timing::ScheduleEvent(pad_update_ticks, pad_update_event); |
| 84 | 83 | ||
| 85 | ReloadInputDevices(); | 84 | ReloadInputDevices(); |
| 86 | } | 85 | } |
| @@ -94,7 +93,7 @@ void IAppletResource::DeactivateController(HidController controller) { | |||
| 94 | } | 93 | } |
| 95 | 94 | ||
| 96 | IAppletResource ::~IAppletResource() { | 95 | IAppletResource ::~IAppletResource() { |
| 97 | CoreTiming::UnscheduleEvent(pad_update_event, 0); | 96 | Core::Timing::UnscheduleEvent(pad_update_event, 0); |
| 98 | } | 97 | } |
| 99 | 98 | ||
| 100 | void IAppletResource::GetSharedMemoryHandle(Kernel::HLERequestContext& ctx) { | 99 | void IAppletResource::GetSharedMemoryHandle(Kernel::HLERequestContext& ctx) { |
| @@ -114,7 +113,7 @@ void IAppletResource::UpdateControllers(u64 userdata, int cycles_late) { | |||
| 114 | controller->OnUpdate(shared_mem->GetPointer(), SHARED_MEMORY_SIZE); | 113 | controller->OnUpdate(shared_mem->GetPointer(), SHARED_MEMORY_SIZE); |
| 115 | } | 114 | } |
| 116 | 115 | ||
| 117 | CoreTiming::ScheduleEvent(pad_update_ticks - cycles_late, pad_update_event); | 116 | Core::Timing::ScheduleEvent(pad_update_ticks - cycles_late, pad_update_event); |
| 118 | } | 117 | } |
| 119 | 118 | ||
| 120 | class IActiveVibrationDeviceList final : public ServiceFramework<IActiveVibrationDeviceList> { | 119 | class IActiveVibrationDeviceList final : public ServiceFramework<IActiveVibrationDeviceList> { |
diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h index eca27c056..6d897c842 100644 --- a/src/core/hle/service/hid/hid.h +++ b/src/core/hle/service/hid/hid.h | |||
| @@ -7,7 +7,7 @@ | |||
| 7 | #include "controllers/controller_base.h" | 7 | #include "controllers/controller_base.h" |
| 8 | #include "core/hle/service/service.h" | 8 | #include "core/hle/service/service.h" |
| 9 | 9 | ||
| 10 | namespace CoreTiming { | 10 | namespace Core::Timing { |
| 11 | struct EventType; | 11 | struct EventType; |
| 12 | } | 12 | } |
| 13 | 13 | ||
| @@ -66,7 +66,7 @@ private: | |||
| 66 | 66 | ||
| 67 | Kernel::SharedPtr<Kernel::SharedMemory> shared_mem; | 67 | Kernel::SharedPtr<Kernel::SharedMemory> shared_mem; |
| 68 | 68 | ||
| 69 | CoreTiming::EventType* pad_update_event; | 69 | Core::Timing::EventType* pad_update_event; |
| 70 | 70 | ||
| 71 | std::array<std::unique_ptr<ControllerBase>, static_cast<size_t>(HidController::MaxControllers)> | 71 | std::array<std::unique_ptr<ControllerBase>, static_cast<size_t>(HidController::MaxControllers)> |
| 72 | controllers{}; | 72 | controllers{}; |
diff --git a/src/core/hle/service/hid/irs.cpp b/src/core/hle/service/hid/irs.cpp index 3c7f8b1ee..b427d4068 100644 --- a/src/core/hle/service/hid/irs.cpp +++ b/src/core/hle/service/hid/irs.cpp | |||
| @@ -98,7 +98,7 @@ void IRS::GetImageTransferProcessorState(Kernel::HLERequestContext& ctx) { | |||
| 98 | 98 | ||
| 99 | IPC::ResponseBuilder rb{ctx, 5}; | 99 | IPC::ResponseBuilder rb{ctx, 5}; |
| 100 | rb.Push(RESULT_SUCCESS); | 100 | rb.Push(RESULT_SUCCESS); |
| 101 | rb.PushRaw<u64>(CoreTiming::GetTicks()); | 101 | rb.PushRaw<u64>(Core::Timing::GetTicks()); |
| 102 | rb.PushRaw<u32>(0); | 102 | rb.PushRaw<u32>(0); |
| 103 | } | 103 | } |
| 104 | 104 | ||
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp index d57a54ee8..88d80ba06 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp | |||
| @@ -184,7 +184,7 @@ u32 nvhost_ctrl_gpu::GetGpuTime(const std::vector<u8>& input, std::vector<u8>& o | |||
| 184 | 184 | ||
| 185 | IoctlGetGpuTime params{}; | 185 | IoctlGetGpuTime params{}; |
| 186 | std::memcpy(¶ms, input.data(), input.size()); | 186 | std::memcpy(¶ms, input.data(), input.size()); |
| 187 | params.gpu_time = CoreTiming::cyclesToNs(CoreTiming::GetTicks()); | 187 | params.gpu_time = Core::Timing::cyclesToNs(Core::Timing::GetTicks()); |
| 188 | std::memcpy(output.data(), ¶ms, output.size()); | 188 | std::memcpy(output.data(), ¶ms, output.size()); |
| 189 | return 0; | 189 | return 0; |
| 190 | } | 190 | } |
diff --git a/src/core/hle/service/nvflinger/buffer_queue.h b/src/core/hle/service/nvflinger/buffer_queue.h index b171f256c..ab90d591e 100644 --- a/src/core/hle/service/nvflinger/buffer_queue.h +++ b/src/core/hle/service/nvflinger/buffer_queue.h | |||
| @@ -13,10 +13,6 @@ | |||
| 13 | #include "core/hle/kernel/object.h" | 13 | #include "core/hle/kernel/object.h" |
| 14 | #include "core/hle/kernel/writable_event.h" | 14 | #include "core/hle/kernel/writable_event.h" |
| 15 | 15 | ||
| 16 | namespace CoreTiming { | ||
| 17 | struct EventType; | ||
| 18 | } | ||
| 19 | |||
| 20 | namespace Service::NVFlinger { | 16 | namespace Service::NVFlinger { |
| 21 | 17 | ||
| 22 | struct IGBPBuffer { | 18 | struct IGBPBuffer { |
diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp index cde06916d..ce1b59860 100644 --- a/src/core/hle/service/nvflinger/nvflinger.cpp +++ b/src/core/hle/service/nvflinger/nvflinger.cpp | |||
| @@ -25,21 +25,21 @@ | |||
| 25 | namespace Service::NVFlinger { | 25 | namespace Service::NVFlinger { |
| 26 | 26 | ||
| 27 | constexpr std::size_t SCREEN_REFRESH_RATE = 60; | 27 | constexpr std::size_t SCREEN_REFRESH_RATE = 60; |
| 28 | constexpr u64 frame_ticks = static_cast<u64>(CoreTiming::BASE_CLOCK_RATE / SCREEN_REFRESH_RATE); | 28 | constexpr u64 frame_ticks = static_cast<u64>(Core::Timing::BASE_CLOCK_RATE / SCREEN_REFRESH_RATE); |
| 29 | 29 | ||
| 30 | NVFlinger::NVFlinger() { | 30 | NVFlinger::NVFlinger() { |
| 31 | // Schedule the screen composition events | 31 | // Schedule the screen composition events |
| 32 | composition_event = | 32 | composition_event = |
| 33 | CoreTiming::RegisterEvent("ScreenComposition", [this](u64 userdata, int cycles_late) { | 33 | Core::Timing::RegisterEvent("ScreenComposition", [this](u64 userdata, int cycles_late) { |
| 34 | Compose(); | 34 | Compose(); |
| 35 | CoreTiming::ScheduleEvent(frame_ticks - cycles_late, composition_event); | 35 | Core::Timing::ScheduleEvent(frame_ticks - cycles_late, composition_event); |
| 36 | }); | 36 | }); |
| 37 | 37 | ||
| 38 | CoreTiming::ScheduleEvent(frame_ticks, composition_event); | 38 | Core::Timing::ScheduleEvent(frame_ticks, composition_event); |
| 39 | } | 39 | } |
| 40 | 40 | ||
| 41 | NVFlinger::~NVFlinger() { | 41 | NVFlinger::~NVFlinger() { |
| 42 | CoreTiming::UnscheduleEvent(composition_event, 0); | 42 | Core::Timing::UnscheduleEvent(composition_event, 0); |
| 43 | } | 43 | } |
| 44 | 44 | ||
| 45 | void NVFlinger::SetNVDrvInstance(std::shared_ptr<Nvidia::Module> instance) { | 45 | void NVFlinger::SetNVDrvInstance(std::shared_ptr<Nvidia::Module> instance) { |
diff --git a/src/core/hle/service/nvflinger/nvflinger.h b/src/core/hle/service/nvflinger/nvflinger.h index 4c55e99f4..6d8bcbd30 100644 --- a/src/core/hle/service/nvflinger/nvflinger.h +++ b/src/core/hle/service/nvflinger/nvflinger.h | |||
| @@ -14,7 +14,7 @@ | |||
| 14 | #include "common/common_types.h" | 14 | #include "common/common_types.h" |
| 15 | #include "core/hle/kernel/object.h" | 15 | #include "core/hle/kernel/object.h" |
| 16 | 16 | ||
| 17 | namespace CoreTiming { | 17 | namespace Core::Timing { |
| 18 | struct EventType; | 18 | struct EventType; |
| 19 | } | 19 | } |
| 20 | 20 | ||
| @@ -115,8 +115,8 @@ private: | |||
| 115 | /// layers. | 115 | /// layers. |
| 116 | u32 next_buffer_queue_id = 1; | 116 | u32 next_buffer_queue_id = 1; |
| 117 | 117 | ||
| 118 | /// CoreTiming event that handles screen composition. | 118 | /// Event that handles screen composition. |
| 119 | CoreTiming::EventType* composition_event; | 119 | Core::Timing::EventType* composition_event; |
| 120 | }; | 120 | }; |
| 121 | 121 | ||
| 122 | } // namespace Service::NVFlinger | 122 | } // namespace Service::NVFlinger |
diff --git a/src/core/hle/service/time/time.cpp b/src/core/hle/service/time/time.cpp index c13640ad8..efebd1b24 100644 --- a/src/core/hle/service/time/time.cpp +++ b/src/core/hle/service/time/time.cpp | |||
| @@ -106,8 +106,8 @@ private: | |||
| 106 | void GetCurrentTimePoint(Kernel::HLERequestContext& ctx) { | 106 | void GetCurrentTimePoint(Kernel::HLERequestContext& ctx) { |
| 107 | LOG_DEBUG(Service_Time, "called"); | 107 | LOG_DEBUG(Service_Time, "called"); |
| 108 | 108 | ||
| 109 | SteadyClockTimePoint steady_clock_time_point{ | 109 | const SteadyClockTimePoint steady_clock_time_point{ |
| 110 | CoreTiming::cyclesToMs(CoreTiming::GetTicks()) / 1000}; | 110 | Core::Timing::cyclesToMs(Core::Timing::GetTicks()) / 1000}; |
| 111 | IPC::ResponseBuilder rb{ctx, (sizeof(SteadyClockTimePoint) / 4) + 2}; | 111 | IPC::ResponseBuilder rb{ctx, (sizeof(SteadyClockTimePoint) / 4) + 2}; |
| 112 | rb.Push(RESULT_SUCCESS); | 112 | rb.Push(RESULT_SUCCESS); |
| 113 | rb.PushRaw(steady_clock_time_point); | 113 | rb.PushRaw(steady_clock_time_point); |
| @@ -282,7 +282,7 @@ void Module::Interface::GetClockSnapshot(Kernel::HLERequestContext& ctx) { | |||
| 282 | } | 282 | } |
| 283 | 283 | ||
| 284 | const SteadyClockTimePoint steady_clock_time_point{ | 284 | const SteadyClockTimePoint steady_clock_time_point{ |
| 285 | CoreTiming::cyclesToMs(CoreTiming::GetTicks()) / 1000, {}}; | 285 | Core::Timing::cyclesToMs(Core::Timing::GetTicks()) / 1000, {}}; |
| 286 | 286 | ||
| 287 | CalendarTime calendar_time{}; | 287 | CalendarTime calendar_time{}; |
| 288 | calendar_time.year = tm->tm_year + 1900; | 288 | calendar_time.year = tm->tm_year + 1900; |
diff --git a/src/tests/core/core_timing.cpp b/src/tests/core/core_timing.cpp index 2242c14cf..77607a755 100644 --- a/src/tests/core/core_timing.cpp +++ b/src/tests/core/core_timing.cpp | |||
| @@ -31,10 +31,10 @@ void CallbackTemplate(u64 userdata, s64 cycles_late) { | |||
| 31 | class ScopeInit final { | 31 | class ScopeInit final { |
| 32 | public: | 32 | public: |
| 33 | ScopeInit() { | 33 | ScopeInit() { |
| 34 | CoreTiming::Init(); | 34 | Core::Timing::Init(); |
| 35 | } | 35 | } |
| 36 | ~ScopeInit() { | 36 | ~ScopeInit() { |
| 37 | CoreTiming::Shutdown(); | 37 | Core::Timing::Shutdown(); |
| 38 | } | 38 | } |
| 39 | }; | 39 | }; |
| 40 | 40 | ||
| @@ -44,37 +44,37 @@ static void AdvanceAndCheck(u32 idx, int downcount, int expected_lateness = 0, | |||
| 44 | expected_callback = CB_IDS[idx]; | 44 | expected_callback = CB_IDS[idx]; |
| 45 | lateness = expected_lateness; | 45 | lateness = expected_lateness; |
| 46 | 46 | ||
| 47 | CoreTiming::AddTicks(CoreTiming::GetDowncount() - | 47 | // Pretend we executed X cycles of instructions. |
| 48 | cpu_downcount); // Pretend we executed X cycles of instructions. | 48 | Core::Timing::AddTicks(Core::Timing::GetDowncount() - cpu_downcount); |
| 49 | CoreTiming::Advance(); | 49 | Core::Timing::Advance(); |
| 50 | 50 | ||
| 51 | REQUIRE(decltype(callbacks_ran_flags)().set(idx) == callbacks_ran_flags); | 51 | REQUIRE(decltype(callbacks_ran_flags)().set(idx) == callbacks_ran_flags); |
| 52 | REQUIRE(downcount == CoreTiming::GetDowncount()); | 52 | REQUIRE(downcount == Core::Timing::GetDowncount()); |
| 53 | } | 53 | } |
| 54 | 54 | ||
| 55 | TEST_CASE("CoreTiming[BasicOrder]", "[core]") { | 55 | TEST_CASE("CoreTiming[BasicOrder]", "[core]") { |
| 56 | ScopeInit guard; | 56 | ScopeInit guard; |
| 57 | 57 | ||
| 58 | CoreTiming::EventType* cb_a = CoreTiming::RegisterEvent("callbackA", CallbackTemplate<0>); | 58 | Core::Timing::EventType* cb_a = Core::Timing::RegisterEvent("callbackA", CallbackTemplate<0>); |
| 59 | CoreTiming::EventType* cb_b = CoreTiming::RegisterEvent("callbackB", CallbackTemplate<1>); | 59 | Core::Timing::EventType* cb_b = Core::Timing::RegisterEvent("callbackB", CallbackTemplate<1>); |
| 60 | CoreTiming::EventType* cb_c = CoreTiming::RegisterEvent("callbackC", CallbackTemplate<2>); | 60 | Core::Timing::EventType* cb_c = Core::Timing::RegisterEvent("callbackC", CallbackTemplate<2>); |
| 61 | CoreTiming::EventType* cb_d = CoreTiming::RegisterEvent("callbackD", CallbackTemplate<3>); | 61 | Core::Timing::EventType* cb_d = Core::Timing::RegisterEvent("callbackD", CallbackTemplate<3>); |
| 62 | CoreTiming::EventType* cb_e = CoreTiming::RegisterEvent("callbackE", CallbackTemplate<4>); | 62 | Core::Timing::EventType* cb_e = Core::Timing::RegisterEvent("callbackE", CallbackTemplate<4>); |
| 63 | 63 | ||
| 64 | // Enter slice 0 | 64 | // Enter slice 0 |
| 65 | CoreTiming::Advance(); | 65 | Core::Timing::Advance(); |
| 66 | 66 | ||
| 67 | // D -> B -> C -> A -> E | 67 | // D -> B -> C -> A -> E |
| 68 | CoreTiming::ScheduleEvent(1000, cb_a, CB_IDS[0]); | 68 | Core::Timing::ScheduleEvent(1000, cb_a, CB_IDS[0]); |
| 69 | REQUIRE(1000 == CoreTiming::GetDowncount()); | 69 | REQUIRE(1000 == Core::Timing::GetDowncount()); |
| 70 | CoreTiming::ScheduleEvent(500, cb_b, CB_IDS[1]); | 70 | Core::Timing::ScheduleEvent(500, cb_b, CB_IDS[1]); |
| 71 | REQUIRE(500 == CoreTiming::GetDowncount()); | 71 | REQUIRE(500 == Core::Timing::GetDowncount()); |
| 72 | CoreTiming::ScheduleEvent(800, cb_c, CB_IDS[2]); | 72 | Core::Timing::ScheduleEvent(800, cb_c, CB_IDS[2]); |
| 73 | REQUIRE(500 == CoreTiming::GetDowncount()); | 73 | REQUIRE(500 == Core::Timing::GetDowncount()); |
| 74 | CoreTiming::ScheduleEvent(100, cb_d, CB_IDS[3]); | 74 | Core::Timing::ScheduleEvent(100, cb_d, CB_IDS[3]); |
| 75 | REQUIRE(100 == CoreTiming::GetDowncount()); | 75 | REQUIRE(100 == Core::Timing::GetDowncount()); |
| 76 | CoreTiming::ScheduleEvent(1200, cb_e, CB_IDS[4]); | 76 | Core::Timing::ScheduleEvent(1200, cb_e, CB_IDS[4]); |
| 77 | REQUIRE(100 == CoreTiming::GetDowncount()); | 77 | REQUIRE(100 == Core::Timing::GetDowncount()); |
| 78 | 78 | ||
| 79 | AdvanceAndCheck(3, 400); | 79 | AdvanceAndCheck(3, 400); |
| 80 | AdvanceAndCheck(1, 300); | 80 | AdvanceAndCheck(1, 300); |
| @@ -86,36 +86,36 @@ TEST_CASE("CoreTiming[BasicOrder]", "[core]") { | |||
| 86 | TEST_CASE("CoreTiming[Threadsave]", "[core]") { | 86 | TEST_CASE("CoreTiming[Threadsave]", "[core]") { |
| 87 | ScopeInit guard; | 87 | ScopeInit guard; |
| 88 | 88 | ||
| 89 | CoreTiming::EventType* cb_a = CoreTiming::RegisterEvent("callbackA", CallbackTemplate<0>); | 89 | Core::Timing::EventType* cb_a = Core::Timing::RegisterEvent("callbackA", CallbackTemplate<0>); |
| 90 | CoreTiming::EventType* cb_b = CoreTiming::RegisterEvent("callbackB", CallbackTemplate<1>); | 90 | Core::Timing::EventType* cb_b = Core::Timing::RegisterEvent("callbackB", CallbackTemplate<1>); |
| 91 | CoreTiming::EventType* cb_c = CoreTiming::RegisterEvent("callbackC", CallbackTemplate<2>); | 91 | Core::Timing::EventType* cb_c = Core::Timing::RegisterEvent("callbackC", CallbackTemplate<2>); |
| 92 | CoreTiming::EventType* cb_d = CoreTiming::RegisterEvent("callbackD", CallbackTemplate<3>); | 92 | Core::Timing::EventType* cb_d = Core::Timing::RegisterEvent("callbackD", CallbackTemplate<3>); |
| 93 | CoreTiming::EventType* cb_e = CoreTiming::RegisterEvent("callbackE", CallbackTemplate<4>); | 93 | Core::Timing::EventType* cb_e = Core::Timing::RegisterEvent("callbackE", CallbackTemplate<4>); |
| 94 | 94 | ||
| 95 | // Enter slice 0 | 95 | // Enter slice 0 |
| 96 | CoreTiming::Advance(); | 96 | Core::Timing::Advance(); |
| 97 | 97 | ||
| 98 | // D -> B -> C -> A -> E | 98 | // D -> B -> C -> A -> E |
| 99 | CoreTiming::ScheduleEventThreadsafe(1000, cb_a, CB_IDS[0]); | 99 | Core::Timing::ScheduleEventThreadsafe(1000, cb_a, CB_IDS[0]); |
| 100 | // Manually force since ScheduleEventThreadsafe doesn't call it | 100 | // Manually force since ScheduleEventThreadsafe doesn't call it |
| 101 | CoreTiming::ForceExceptionCheck(1000); | 101 | Core::Timing::ForceExceptionCheck(1000); |
| 102 | REQUIRE(1000 == CoreTiming::GetDowncount()); | 102 | REQUIRE(1000 == Core::Timing::GetDowncount()); |
| 103 | CoreTiming::ScheduleEventThreadsafe(500, cb_b, CB_IDS[1]); | 103 | Core::Timing::ScheduleEventThreadsafe(500, cb_b, CB_IDS[1]); |
| 104 | // Manually force since ScheduleEventThreadsafe doesn't call it | 104 | // Manually force since ScheduleEventThreadsafe doesn't call it |
| 105 | CoreTiming::ForceExceptionCheck(500); | 105 | Core::Timing::ForceExceptionCheck(500); |
| 106 | REQUIRE(500 == CoreTiming::GetDowncount()); | 106 | REQUIRE(500 == Core::Timing::GetDowncount()); |
| 107 | CoreTiming::ScheduleEventThreadsafe(800, cb_c, CB_IDS[2]); | 107 | Core::Timing::ScheduleEventThreadsafe(800, cb_c, CB_IDS[2]); |
| 108 | // Manually force since ScheduleEventThreadsafe doesn't call it | 108 | // Manually force since ScheduleEventThreadsafe doesn't call it |
| 109 | CoreTiming::ForceExceptionCheck(800); | 109 | Core::Timing::ForceExceptionCheck(800); |
| 110 | REQUIRE(500 == CoreTiming::GetDowncount()); | 110 | REQUIRE(500 == Core::Timing::GetDowncount()); |
| 111 | CoreTiming::ScheduleEventThreadsafe(100, cb_d, CB_IDS[3]); | 111 | Core::Timing::ScheduleEventThreadsafe(100, cb_d, CB_IDS[3]); |
| 112 | // Manually force since ScheduleEventThreadsafe doesn't call it | 112 | // Manually force since ScheduleEventThreadsafe doesn't call it |
| 113 | CoreTiming::ForceExceptionCheck(100); | 113 | Core::Timing::ForceExceptionCheck(100); |
| 114 | REQUIRE(100 == CoreTiming::GetDowncount()); | 114 | REQUIRE(100 == Core::Timing::GetDowncount()); |
| 115 | CoreTiming::ScheduleEventThreadsafe(1200, cb_e, CB_IDS[4]); | 115 | Core::Timing::ScheduleEventThreadsafe(1200, cb_e, CB_IDS[4]); |
| 116 | // Manually force since ScheduleEventThreadsafe doesn't call it | 116 | // Manually force since ScheduleEventThreadsafe doesn't call it |
| 117 | CoreTiming::ForceExceptionCheck(1200); | 117 | Core::Timing::ForceExceptionCheck(1200); |
| 118 | REQUIRE(100 == CoreTiming::GetDowncount()); | 118 | REQUIRE(100 == Core::Timing::GetDowncount()); |
| 119 | 119 | ||
| 120 | AdvanceAndCheck(3, 400); | 120 | AdvanceAndCheck(3, 400); |
| 121 | AdvanceAndCheck(1, 300); | 121 | AdvanceAndCheck(1, 300); |
| @@ -143,42 +143,42 @@ TEST_CASE("CoreTiming[SharedSlot]", "[core]") { | |||
| 143 | 143 | ||
| 144 | ScopeInit guard; | 144 | ScopeInit guard; |
| 145 | 145 | ||
| 146 | CoreTiming::EventType* cb_a = CoreTiming::RegisterEvent("callbackA", FifoCallback<0>); | 146 | Core::Timing::EventType* cb_a = Core::Timing::RegisterEvent("callbackA", FifoCallback<0>); |
| 147 | CoreTiming::EventType* cb_b = CoreTiming::RegisterEvent("callbackB", FifoCallback<1>); | 147 | Core::Timing::EventType* cb_b = Core::Timing::RegisterEvent("callbackB", FifoCallback<1>); |
| 148 | CoreTiming::EventType* cb_c = CoreTiming::RegisterEvent("callbackC", FifoCallback<2>); | 148 | Core::Timing::EventType* cb_c = Core::Timing::RegisterEvent("callbackC", FifoCallback<2>); |
| 149 | CoreTiming::EventType* cb_d = CoreTiming::RegisterEvent("callbackD", FifoCallback<3>); | 149 | Core::Timing::EventType* cb_d = Core::Timing::RegisterEvent("callbackD", FifoCallback<3>); |
| 150 | CoreTiming::EventType* cb_e = CoreTiming::RegisterEvent("callbackE", FifoCallback<4>); | 150 | Core::Timing::EventType* cb_e = Core::Timing::RegisterEvent("callbackE", FifoCallback<4>); |
| 151 | 151 | ||
| 152 | CoreTiming::ScheduleEvent(1000, cb_a, CB_IDS[0]); | 152 | Core::Timing::ScheduleEvent(1000, cb_a, CB_IDS[0]); |
| 153 | CoreTiming::ScheduleEvent(1000, cb_b, CB_IDS[1]); | 153 | Core::Timing::ScheduleEvent(1000, cb_b, CB_IDS[1]); |
| 154 | CoreTiming::ScheduleEvent(1000, cb_c, CB_IDS[2]); | 154 | Core::Timing::ScheduleEvent(1000, cb_c, CB_IDS[2]); |
| 155 | CoreTiming::ScheduleEvent(1000, cb_d, CB_IDS[3]); | 155 | Core::Timing::ScheduleEvent(1000, cb_d, CB_IDS[3]); |
| 156 | CoreTiming::ScheduleEvent(1000, cb_e, CB_IDS[4]); | 156 | Core::Timing::ScheduleEvent(1000, cb_e, CB_IDS[4]); |
| 157 | 157 | ||
| 158 | // Enter slice 0 | 158 | // Enter slice 0 |
| 159 | CoreTiming::Advance(); | 159 | Core::Timing::Advance(); |
| 160 | REQUIRE(1000 == CoreTiming::GetDowncount()); | 160 | REQUIRE(1000 == Core::Timing::GetDowncount()); |
| 161 | 161 | ||
| 162 | callbacks_ran_flags = 0; | 162 | callbacks_ran_flags = 0; |
| 163 | counter = 0; | 163 | counter = 0; |
| 164 | lateness = 0; | 164 | lateness = 0; |
| 165 | CoreTiming::AddTicks(CoreTiming::GetDowncount()); | 165 | Core::Timing::AddTicks(Core::Timing::GetDowncount()); |
| 166 | CoreTiming::Advance(); | 166 | Core::Timing::Advance(); |
| 167 | REQUIRE(MAX_SLICE_LENGTH == CoreTiming::GetDowncount()); | 167 | REQUIRE(MAX_SLICE_LENGTH == Core::Timing::GetDowncount()); |
| 168 | REQUIRE(0x1FULL == callbacks_ran_flags.to_ullong()); | 168 | REQUIRE(0x1FULL == callbacks_ran_flags.to_ullong()); |
| 169 | } | 169 | } |
| 170 | 170 | ||
| 171 | TEST_CASE("CoreTiming[PredictableLateness]", "[core]") { | 171 | TEST_CASE("Core::Timing[PredictableLateness]", "[core]") { |
| 172 | ScopeInit guard; | 172 | ScopeInit guard; |
| 173 | 173 | ||
| 174 | CoreTiming::EventType* cb_a = CoreTiming::RegisterEvent("callbackA", CallbackTemplate<0>); | 174 | Core::Timing::EventType* cb_a = Core::Timing::RegisterEvent("callbackA", CallbackTemplate<0>); |
| 175 | CoreTiming::EventType* cb_b = CoreTiming::RegisterEvent("callbackB", CallbackTemplate<1>); | 175 | Core::Timing::EventType* cb_b = Core::Timing::RegisterEvent("callbackB", CallbackTemplate<1>); |
| 176 | 176 | ||
| 177 | // Enter slice 0 | 177 | // Enter slice 0 |
| 178 | CoreTiming::Advance(); | 178 | Core::Timing::Advance(); |
| 179 | 179 | ||
| 180 | CoreTiming::ScheduleEvent(100, cb_a, CB_IDS[0]); | 180 | Core::Timing::ScheduleEvent(100, cb_a, CB_IDS[0]); |
| 181 | CoreTiming::ScheduleEvent(200, cb_b, CB_IDS[1]); | 181 | Core::Timing::ScheduleEvent(200, cb_b, CB_IDS[1]); |
| 182 | 182 | ||
| 183 | AdvanceAndCheck(0, 90, 10, -10); // (100 - 10) | 183 | AdvanceAndCheck(0, 90, 10, -10); // (100 - 10) |
| 184 | AdvanceAndCheck(1, MAX_SLICE_LENGTH, 50, -50); | 184 | AdvanceAndCheck(1, MAX_SLICE_LENGTH, 50, -50); |
| @@ -192,9 +192,10 @@ static void RescheduleCallback(u64 userdata, s64 cycles_late) { | |||
| 192 | REQUIRE(reschedules >= 0); | 192 | REQUIRE(reschedules >= 0); |
| 193 | REQUIRE(lateness == cycles_late); | 193 | REQUIRE(lateness == cycles_late); |
| 194 | 194 | ||
| 195 | if (reschedules > 0) | 195 | if (reschedules > 0) { |
| 196 | CoreTiming::ScheduleEvent(1000, reinterpret_cast<CoreTiming::EventType*>(userdata), | 196 | Core::Timing::ScheduleEvent(1000, reinterpret_cast<Core::Timing::EventType*>(userdata), |
| 197 | userdata); | 197 | userdata); |
| 198 | } | ||
| 198 | } | 199 | } |
| 199 | } // namespace ChainSchedulingTest | 200 | } // namespace ChainSchedulingTest |
| 200 | 201 | ||
| @@ -203,35 +204,35 @@ TEST_CASE("CoreTiming[ChainScheduling]", "[core]") { | |||
| 203 | 204 | ||
| 204 | ScopeInit guard; | 205 | ScopeInit guard; |
| 205 | 206 | ||
| 206 | CoreTiming::EventType* cb_a = CoreTiming::RegisterEvent("callbackA", CallbackTemplate<0>); | 207 | Core::Timing::EventType* cb_a = Core::Timing::RegisterEvent("callbackA", CallbackTemplate<0>); |
| 207 | CoreTiming::EventType* cb_b = CoreTiming::RegisterEvent("callbackB", CallbackTemplate<1>); | 208 | Core::Timing::EventType* cb_b = Core::Timing::RegisterEvent("callbackB", CallbackTemplate<1>); |
| 208 | CoreTiming::EventType* cb_c = CoreTiming::RegisterEvent("callbackC", CallbackTemplate<2>); | 209 | Core::Timing::EventType* cb_c = Core::Timing::RegisterEvent("callbackC", CallbackTemplate<2>); |
| 209 | CoreTiming::EventType* cb_rs = | 210 | Core::Timing::EventType* cb_rs = |
| 210 | CoreTiming::RegisterEvent("callbackReschedule", RescheduleCallback); | 211 | Core::Timing::RegisterEvent("callbackReschedule", RescheduleCallback); |
| 211 | 212 | ||
| 212 | // Enter slice 0 | 213 | // Enter slice 0 |
| 213 | CoreTiming::Advance(); | 214 | Core::Timing::Advance(); |
| 214 | 215 | ||
| 215 | CoreTiming::ScheduleEvent(800, cb_a, CB_IDS[0]); | 216 | Core::Timing::ScheduleEvent(800, cb_a, CB_IDS[0]); |
| 216 | CoreTiming::ScheduleEvent(1000, cb_b, CB_IDS[1]); | 217 | Core::Timing::ScheduleEvent(1000, cb_b, CB_IDS[1]); |
| 217 | CoreTiming::ScheduleEvent(2200, cb_c, CB_IDS[2]); | 218 | Core::Timing::ScheduleEvent(2200, cb_c, CB_IDS[2]); |
| 218 | CoreTiming::ScheduleEvent(1000, cb_rs, reinterpret_cast<u64>(cb_rs)); | 219 | Core::Timing::ScheduleEvent(1000, cb_rs, reinterpret_cast<u64>(cb_rs)); |
| 219 | REQUIRE(800 == CoreTiming::GetDowncount()); | 220 | REQUIRE(800 == Core::Timing::GetDowncount()); |
| 220 | 221 | ||
| 221 | reschedules = 3; | 222 | reschedules = 3; |
| 222 | AdvanceAndCheck(0, 200); // cb_a | 223 | AdvanceAndCheck(0, 200); // cb_a |
| 223 | AdvanceAndCheck(1, 1000); // cb_b, cb_rs | 224 | AdvanceAndCheck(1, 1000); // cb_b, cb_rs |
| 224 | REQUIRE(2 == reschedules); | 225 | REQUIRE(2 == reschedules); |
| 225 | 226 | ||
| 226 | CoreTiming::AddTicks(CoreTiming::GetDowncount()); | 227 | Core::Timing::AddTicks(Core::Timing::GetDowncount()); |
| 227 | CoreTiming::Advance(); // cb_rs | 228 | Core::Timing::Advance(); // cb_rs |
| 228 | REQUIRE(1 == reschedules); | 229 | REQUIRE(1 == reschedules); |
| 229 | REQUIRE(200 == CoreTiming::GetDowncount()); | 230 | REQUIRE(200 == Core::Timing::GetDowncount()); |
| 230 | 231 | ||
| 231 | AdvanceAndCheck(2, 800); // cb_c | 232 | AdvanceAndCheck(2, 800); // cb_c |
| 232 | 233 | ||
| 233 | CoreTiming::AddTicks(CoreTiming::GetDowncount()); | 234 | Core::Timing::AddTicks(Core::Timing::GetDowncount()); |
| 234 | CoreTiming::Advance(); // cb_rs | 235 | Core::Timing::Advance(); // cb_rs |
| 235 | REQUIRE(0 == reschedules); | 236 | REQUIRE(0 == reschedules); |
| 236 | REQUIRE(MAX_SLICE_LENGTH == CoreTiming::GetDowncount()); | 237 | REQUIRE(MAX_SLICE_LENGTH == Core::Timing::GetDowncount()); |
| 237 | } | 238 | } |
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index 33e507e69..d35a738d5 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt | |||
| @@ -5,12 +5,12 @@ add_library(video_core STATIC | |||
| 5 | debug_utils/debug_utils.h | 5 | debug_utils/debug_utils.h |
| 6 | engines/fermi_2d.cpp | 6 | engines/fermi_2d.cpp |
| 7 | engines/fermi_2d.h | 7 | engines/fermi_2d.h |
| 8 | engines/kepler_compute.cpp | ||
| 9 | engines/kepler_compute.h | ||
| 8 | engines/kepler_memory.cpp | 10 | engines/kepler_memory.cpp |
| 9 | engines/kepler_memory.h | 11 | engines/kepler_memory.h |
| 10 | engines/maxwell_3d.cpp | 12 | engines/maxwell_3d.cpp |
| 11 | engines/maxwell_3d.h | 13 | engines/maxwell_3d.h |
| 12 | engines/maxwell_compute.cpp | ||
| 13 | engines/maxwell_compute.h | ||
| 14 | engines/maxwell_dma.cpp | 14 | engines/maxwell_dma.cpp |
| 15 | engines/maxwell_dma.h | 15 | engines/maxwell_dma.h |
| 16 | engines/shader_bytecode.h | 16 | engines/shader_bytecode.h |
| @@ -101,6 +101,16 @@ add_library(video_core STATIC | |||
| 101 | video_core.h | 101 | video_core.h |
| 102 | ) | 102 | ) |
| 103 | 103 | ||
| 104 | if (ENABLE_VULKAN) | ||
| 105 | target_sources(video_core PRIVATE | ||
| 106 | renderer_vulkan/declarations.h | ||
| 107 | renderer_vulkan/vk_device.cpp | ||
| 108 | renderer_vulkan/vk_device.h) | ||
| 109 | |||
| 110 | target_include_directories(video_core PRIVATE ../../externals/Vulkan-Headers/include) | ||
| 111 | target_compile_definitions(video_core PRIVATE HAS_VULKAN) | ||
| 112 | endif() | ||
| 113 | |||
| 104 | create_target_directory_groups(video_core) | 114 | create_target_directory_groups(video_core) |
| 105 | 115 | ||
| 106 | target_link_libraries(video_core PUBLIC common core) | 116 | target_link_libraries(video_core PUBLIC common core) |
diff --git a/src/video_core/engines/kepler_compute.cpp b/src/video_core/engines/kepler_compute.cpp new file mode 100644 index 000000000..4ca856b6b --- /dev/null +++ b/src/video_core/engines/kepler_compute.cpp | |||
| @@ -0,0 +1,34 @@ | |||
| 1 | // Copyright 2018 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "common/logging/log.h" | ||
| 6 | #include "core/core.h" | ||
| 7 | #include "core/memory.h" | ||
| 8 | #include "video_core/engines/kepler_compute.h" | ||
| 9 | #include "video_core/memory_manager.h" | ||
| 10 | |||
| 11 | namespace Tegra::Engines { | ||
| 12 | |||
| 13 | KeplerCompute::KeplerCompute(MemoryManager& memory_manager) : memory_manager{memory_manager} {} | ||
| 14 | |||
| 15 | KeplerCompute::~KeplerCompute() = default; | ||
| 16 | |||
| 17 | void KeplerCompute::CallMethod(const GPU::MethodCall& method_call) { | ||
| 18 | ASSERT_MSG(method_call.method < Regs::NUM_REGS, | ||
| 19 | "Invalid KeplerCompute register, increase the size of the Regs structure"); | ||
| 20 | |||
| 21 | regs.reg_array[method_call.method] = method_call.argument; | ||
| 22 | |||
| 23 | switch (method_call.method) { | ||
| 24 | case KEPLER_COMPUTE_REG_INDEX(launch): | ||
| 25 | // Abort execution since compute shaders can be used to alter game memory (e.g. CUDA | ||
| 26 | // kernels) | ||
| 27 | UNREACHABLE_MSG("Compute shaders are not implemented"); | ||
| 28 | break; | ||
| 29 | default: | ||
| 30 | break; | ||
| 31 | } | ||
| 32 | } | ||
| 33 | |||
| 34 | } // namespace Tegra::Engines | ||
diff --git a/src/video_core/engines/maxwell_compute.h b/src/video_core/engines/kepler_compute.h index 1d71f11bd..df0a32e0f 100644 --- a/src/video_core/engines/maxwell_compute.h +++ b/src/video_core/engines/kepler_compute.h | |||
| @@ -10,47 +10,48 @@ | |||
| 10 | #include "common/common_funcs.h" | 10 | #include "common/common_funcs.h" |
| 11 | #include "common/common_types.h" | 11 | #include "common/common_types.h" |
| 12 | #include "video_core/gpu.h" | 12 | #include "video_core/gpu.h" |
| 13 | #include "video_core/memory_manager.h" | ||
| 13 | 14 | ||
| 14 | namespace Tegra::Engines { | 15 | namespace Tegra::Engines { |
| 15 | 16 | ||
| 16 | #define MAXWELL_COMPUTE_REG_INDEX(field_name) \ | 17 | #define KEPLER_COMPUTE_REG_INDEX(field_name) \ |
| 17 | (offsetof(Tegra::Engines::MaxwellCompute::Regs, field_name) / sizeof(u32)) | 18 | (offsetof(Tegra::Engines::KeplerCompute::Regs, field_name) / sizeof(u32)) |
| 18 | 19 | ||
| 19 | class MaxwellCompute final { | 20 | class KeplerCompute final { |
| 20 | public: | 21 | public: |
| 21 | MaxwellCompute() = default; | 22 | explicit KeplerCompute(MemoryManager& memory_manager); |
| 22 | ~MaxwellCompute() = default; | 23 | ~KeplerCompute(); |
| 24 | |||
| 25 | static constexpr std::size_t NumConstBuffers = 8; | ||
| 23 | 26 | ||
| 24 | struct Regs { | 27 | struct Regs { |
| 25 | static constexpr std::size_t NUM_REGS = 0xCF8; | 28 | static constexpr std::size_t NUM_REGS = 0xCF8; |
| 26 | 29 | ||
| 27 | union { | 30 | union { |
| 28 | struct { | 31 | struct { |
| 29 | INSERT_PADDING_WORDS(0x281); | 32 | INSERT_PADDING_WORDS(0xAF); |
| 30 | 33 | ||
| 31 | union { | 34 | u32 launch; |
| 32 | u32 compute_end; | ||
| 33 | BitField<0, 1, u32> unknown; | ||
| 34 | } compute; | ||
| 35 | 35 | ||
| 36 | INSERT_PADDING_WORDS(0xA76); | 36 | INSERT_PADDING_WORDS(0xC48); |
| 37 | }; | 37 | }; |
| 38 | std::array<u32, NUM_REGS> reg_array; | 38 | std::array<u32, NUM_REGS> reg_array; |
| 39 | }; | 39 | }; |
| 40 | } regs{}; | 40 | } regs{}; |
| 41 | |||
| 42 | static_assert(sizeof(Regs) == Regs::NUM_REGS * sizeof(u32), | 41 | static_assert(sizeof(Regs) == Regs::NUM_REGS * sizeof(u32), |
| 43 | "MaxwellCompute Regs has wrong size"); | 42 | "KeplerCompute Regs has wrong size"); |
| 43 | |||
| 44 | MemoryManager& memory_manager; | ||
| 44 | 45 | ||
| 45 | /// Write the value to the register identified by method. | 46 | /// Write the value to the register identified by method. |
| 46 | void CallMethod(const GPU::MethodCall& method_call); | 47 | void CallMethod(const GPU::MethodCall& method_call); |
| 47 | }; | 48 | }; |
| 48 | 49 | ||
| 49 | #define ASSERT_REG_POSITION(field_name, position) \ | 50 | #define ASSERT_REG_POSITION(field_name, position) \ |
| 50 | static_assert(offsetof(MaxwellCompute::Regs, field_name) == position * 4, \ | 51 | static_assert(offsetof(KeplerCompute::Regs, field_name) == position * 4, \ |
| 51 | "Field " #field_name " has invalid position") | 52 | "Field " #field_name " has invalid position") |
| 52 | 53 | ||
| 53 | ASSERT_REG_POSITION(compute, 0x281); | 54 | ASSERT_REG_POSITION(launch, 0xAF); |
| 54 | 55 | ||
| 55 | #undef ASSERT_REG_POSITION | 56 | #undef ASSERT_REG_POSITION |
| 56 | 57 | ||
diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp index 10eae6a65..19b6b14b2 100644 --- a/src/video_core/engines/maxwell_3d.cpp +++ b/src/video_core/engines/maxwell_3d.cpp | |||
| @@ -317,7 +317,7 @@ void Maxwell3D::ProcessQueryGet() { | |||
| 317 | LongQueryResult query_result{}; | 317 | LongQueryResult query_result{}; |
| 318 | query_result.value = result; | 318 | query_result.value = result; |
| 319 | // TODO(Subv): Generate a real GPU timestamp and write it here instead of CoreTiming | 319 | // TODO(Subv): Generate a real GPU timestamp and write it here instead of CoreTiming |
| 320 | query_result.timestamp = CoreTiming::GetTicks(); | 320 | query_result.timestamp = Core::Timing::GetTicks(); |
| 321 | Memory::WriteBlock(*address, &query_result, sizeof(query_result)); | 321 | Memory::WriteBlock(*address, &query_result, sizeof(query_result)); |
| 322 | } | 322 | } |
| 323 | dirty_flags.OnMemoryWrite(); | 323 | dirty_flags.OnMemoryWrite(); |
diff --git a/src/video_core/engines/maxwell_compute.cpp b/src/video_core/engines/maxwell_compute.cpp deleted file mode 100644 index 656db6a61..000000000 --- a/src/video_core/engines/maxwell_compute.cpp +++ /dev/null | |||
| @@ -1,28 +0,0 @@ | |||
| 1 | // Copyright 2018 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "common/logging/log.h" | ||
| 6 | #include "core/core.h" | ||
| 7 | #include "video_core/engines/maxwell_compute.h" | ||
| 8 | |||
| 9 | namespace Tegra::Engines { | ||
| 10 | |||
| 11 | void MaxwellCompute::CallMethod(const GPU::MethodCall& method_call) { | ||
| 12 | ASSERT_MSG(method_call.method < Regs::NUM_REGS, | ||
| 13 | "Invalid MaxwellCompute register, increase the size of the Regs structure"); | ||
| 14 | |||
| 15 | regs.reg_array[method_call.method] = method_call.argument; | ||
| 16 | |||
| 17 | switch (method_call.method) { | ||
| 18 | case MAXWELL_COMPUTE_REG_INDEX(compute): { | ||
| 19 | LOG_CRITICAL(HW_GPU, "Compute shaders are not implemented"); | ||
| 20 | UNREACHABLE(); | ||
| 21 | break; | ||
| 22 | } | ||
| 23 | default: | ||
| 24 | break; | ||
| 25 | } | ||
| 26 | } | ||
| 27 | |||
| 28 | } // namespace Tegra::Engines | ||
diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h index 269df9437..1f425f90b 100644 --- a/src/video_core/engines/shader_bytecode.h +++ b/src/video_core/engines/shader_bytecode.h | |||
| @@ -186,7 +186,7 @@ enum class SubOp : u64 { | |||
| 186 | }; | 186 | }; |
| 187 | 187 | ||
| 188 | enum class F2iRoundingOp : u64 { | 188 | enum class F2iRoundingOp : u64 { |
| 189 | None = 0, | 189 | RoundEven = 0, |
| 190 | Floor = 1, | 190 | Floor = 1, |
| 191 | Ceil = 2, | 191 | Ceil = 2, |
| 192 | Trunc = 3, | 192 | Trunc = 3, |
diff --git a/src/video_core/gpu.cpp b/src/video_core/gpu.cpp index d3d32a359..3d00c308b 100644 --- a/src/video_core/gpu.cpp +++ b/src/video_core/gpu.cpp | |||
| @@ -6,9 +6,9 @@ | |||
| 6 | #include "core/core_timing.h" | 6 | #include "core/core_timing.h" |
| 7 | #include "core/memory.h" | 7 | #include "core/memory.h" |
| 8 | #include "video_core/engines/fermi_2d.h" | 8 | #include "video_core/engines/fermi_2d.h" |
| 9 | #include "video_core/engines/kepler_compute.h" | ||
| 9 | #include "video_core/engines/kepler_memory.h" | 10 | #include "video_core/engines/kepler_memory.h" |
| 10 | #include "video_core/engines/maxwell_3d.h" | 11 | #include "video_core/engines/maxwell_3d.h" |
| 11 | #include "video_core/engines/maxwell_compute.h" | ||
| 12 | #include "video_core/engines/maxwell_dma.h" | 12 | #include "video_core/engines/maxwell_dma.h" |
| 13 | #include "video_core/gpu.h" | 13 | #include "video_core/gpu.h" |
| 14 | #include "video_core/rasterizer_interface.h" | 14 | #include "video_core/rasterizer_interface.h" |
| @@ -18,6 +18,7 @@ namespace Tegra { | |||
| 18 | u32 FramebufferConfig::BytesPerPixel(PixelFormat format) { | 18 | u32 FramebufferConfig::BytesPerPixel(PixelFormat format) { |
| 19 | switch (format) { | 19 | switch (format) { |
| 20 | case PixelFormat::ABGR8: | 20 | case PixelFormat::ABGR8: |
| 21 | case PixelFormat::BGRA8: | ||
| 21 | return 4; | 22 | return 4; |
| 22 | default: | 23 | default: |
| 23 | return 4; | 24 | return 4; |
| @@ -31,7 +32,7 @@ GPU::GPU(VideoCore::RasterizerInterface& rasterizer) { | |||
| 31 | dma_pusher = std::make_unique<Tegra::DmaPusher>(*this); | 32 | dma_pusher = std::make_unique<Tegra::DmaPusher>(*this); |
| 32 | maxwell_3d = std::make_unique<Engines::Maxwell3D>(rasterizer, *memory_manager); | 33 | maxwell_3d = std::make_unique<Engines::Maxwell3D>(rasterizer, *memory_manager); |
| 33 | fermi_2d = std::make_unique<Engines::Fermi2D>(rasterizer, *memory_manager); | 34 | fermi_2d = std::make_unique<Engines::Fermi2D>(rasterizer, *memory_manager); |
| 34 | maxwell_compute = std::make_unique<Engines::MaxwellCompute>(); | 35 | kepler_compute = std::make_unique<Engines::KeplerCompute>(*memory_manager); |
| 35 | maxwell_dma = std::make_unique<Engines::MaxwellDMA>(rasterizer, *memory_manager); | 36 | maxwell_dma = std::make_unique<Engines::MaxwellDMA>(rasterizer, *memory_manager); |
| 36 | kepler_memory = std::make_unique<Engines::KeplerMemory>(rasterizer, *memory_manager); | 37 | kepler_memory = std::make_unique<Engines::KeplerMemory>(rasterizer, *memory_manager); |
| 37 | } | 38 | } |
| @@ -245,8 +246,8 @@ void GPU::CallEngineMethod(const MethodCall& method_call) { | |||
| 245 | case EngineID::MAXWELL_B: | 246 | case EngineID::MAXWELL_B: |
| 246 | maxwell_3d->CallMethod(method_call); | 247 | maxwell_3d->CallMethod(method_call); |
| 247 | break; | 248 | break; |
| 248 | case EngineID::MAXWELL_COMPUTE_B: | 249 | case EngineID::KEPLER_COMPUTE_B: |
| 249 | maxwell_compute->CallMethod(method_call); | 250 | kepler_compute->CallMethod(method_call); |
| 250 | break; | 251 | break; |
| 251 | case EngineID::MAXWELL_DMA_COPY_A: | 252 | case EngineID::MAXWELL_DMA_COPY_A: |
| 252 | maxwell_dma->CallMethod(method_call); | 253 | maxwell_dma->CallMethod(method_call); |
| @@ -282,7 +283,7 @@ void GPU::ProcessSemaphoreTriggerMethod() { | |||
| 282 | block.sequence = regs.semaphore_sequence; | 283 | block.sequence = regs.semaphore_sequence; |
| 283 | // TODO(Kmather73): Generate a real GPU timestamp and write it here instead of | 284 | // TODO(Kmather73): Generate a real GPU timestamp and write it here instead of |
| 284 | // CoreTiming | 285 | // CoreTiming |
| 285 | block.timestamp = CoreTiming::GetTicks(); | 286 | block.timestamp = Core::Timing::GetTicks(); |
| 286 | Memory::WriteBlock(*address, &block, sizeof(block)); | 287 | Memory::WriteBlock(*address, &block, sizeof(block)); |
| 287 | } else { | 288 | } else { |
| 288 | const auto address = | 289 | const auto address = |
diff --git a/src/video_core/gpu.h b/src/video_core/gpu.h index fb8975811..a482196ea 100644 --- a/src/video_core/gpu.h +++ b/src/video_core/gpu.h | |||
| @@ -80,6 +80,7 @@ class DebugContext; | |||
| 80 | struct FramebufferConfig { | 80 | struct FramebufferConfig { |
| 81 | enum class PixelFormat : u32 { | 81 | enum class PixelFormat : u32 { |
| 82 | ABGR8 = 1, | 82 | ABGR8 = 1, |
| 83 | BGRA8 = 5, | ||
| 83 | }; | 84 | }; |
| 84 | 85 | ||
| 85 | /** | 86 | /** |
| @@ -102,15 +103,15 @@ struct FramebufferConfig { | |||
| 102 | namespace Engines { | 103 | namespace Engines { |
| 103 | class Fermi2D; | 104 | class Fermi2D; |
| 104 | class Maxwell3D; | 105 | class Maxwell3D; |
| 105 | class MaxwellCompute; | ||
| 106 | class MaxwellDMA; | 106 | class MaxwellDMA; |
| 107 | class KeplerCompute; | ||
| 107 | class KeplerMemory; | 108 | class KeplerMemory; |
| 108 | } // namespace Engines | 109 | } // namespace Engines |
| 109 | 110 | ||
| 110 | enum class EngineID { | 111 | enum class EngineID { |
| 111 | FERMI_TWOD_A = 0x902D, // 2D Engine | 112 | FERMI_TWOD_A = 0x902D, // 2D Engine |
| 112 | MAXWELL_B = 0xB197, // 3D Engine | 113 | MAXWELL_B = 0xB197, // 3D Engine |
| 113 | MAXWELL_COMPUTE_B = 0xB1C0, | 114 | KEPLER_COMPUTE_B = 0xB1C0, |
| 114 | KEPLER_INLINE_TO_MEMORY_B = 0xA140, | 115 | KEPLER_INLINE_TO_MEMORY_B = 0xA140, |
| 115 | MAXWELL_DMA_COPY_A = 0xB0B5, | 116 | MAXWELL_DMA_COPY_A = 0xB0B5, |
| 116 | }; | 117 | }; |
| @@ -208,7 +209,7 @@ private: | |||
| 208 | /// 2D engine | 209 | /// 2D engine |
| 209 | std::unique_ptr<Engines::Fermi2D> fermi_2d; | 210 | std::unique_ptr<Engines::Fermi2D> fermi_2d; |
| 210 | /// Compute engine | 211 | /// Compute engine |
| 211 | std::unique_ptr<Engines::MaxwellCompute> maxwell_compute; | 212 | std::unique_ptr<Engines::KeplerCompute> kepler_compute; |
| 212 | /// DMA engine | 213 | /// DMA engine |
| 213 | std::unique_ptr<Engines::MaxwellDMA> maxwell_dma; | 214 | std::unique_ptr<Engines::MaxwellDMA> maxwell_dma; |
| 214 | /// Inline memory engine | 215 | /// Inline memory engine |
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index 70e124dc4..db18f4dbe 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp | |||
| @@ -616,17 +616,8 @@ private: | |||
| 616 | 616 | ||
| 617 | std::string VisitOperand(Operation operation, std::size_t operand_index, Type type) { | 617 | std::string VisitOperand(Operation operation, std::size_t operand_index, Type type) { |
| 618 | std::string value = VisitOperand(operation, operand_index); | 618 | std::string value = VisitOperand(operation, operand_index); |
| 619 | |||
| 620 | switch (type) { | 619 | switch (type) { |
| 621 | case Type::Bool: | 620 | case Type::HalfFloat: { |
| 622 | case Type::Bool2: | ||
| 623 | case Type::Float: | ||
| 624 | return value; | ||
| 625 | case Type::Int: | ||
| 626 | return "ftoi(" + value + ')'; | ||
| 627 | case Type::Uint: | ||
| 628 | return "ftou(" + value + ')'; | ||
| 629 | case Type::HalfFloat: | ||
| 630 | const auto half_meta = std::get_if<MetaHalfArithmetic>(&operation.GetMeta()); | 621 | const auto half_meta = std::get_if<MetaHalfArithmetic>(&operation.GetMeta()); |
| 631 | if (!half_meta) { | 622 | if (!half_meta) { |
| 632 | value = "toHalf2(" + value + ')'; | 623 | value = "toHalf2(" + value + ')'; |
| @@ -643,6 +634,26 @@ private: | |||
| 643 | return "vec2(toHalf2(" + value + ")[1])"; | 634 | return "vec2(toHalf2(" + value + ")[1])"; |
| 644 | } | 635 | } |
| 645 | } | 636 | } |
| 637 | default: | ||
| 638 | return CastOperand(value, type); | ||
| 639 | } | ||
| 640 | } | ||
| 641 | |||
| 642 | std::string CastOperand(const std::string& value, Type type) const { | ||
| 643 | switch (type) { | ||
| 644 | case Type::Bool: | ||
| 645 | case Type::Bool2: | ||
| 646 | case Type::Float: | ||
| 647 | return value; | ||
| 648 | case Type::Int: | ||
| 649 | return "ftoi(" + value + ')'; | ||
| 650 | case Type::Uint: | ||
| 651 | return "ftou(" + value + ')'; | ||
| 652 | case Type::HalfFloat: | ||
| 653 | // Can't be handled as a stand-alone value | ||
| 654 | UNREACHABLE(); | ||
| 655 | return value; | ||
| 656 | } | ||
| 646 | UNREACHABLE(); | 657 | UNREACHABLE(); |
| 647 | return value; | 658 | return value; |
| 648 | } | 659 | } |
| @@ -650,6 +661,7 @@ private: | |||
| 650 | std::string BitwiseCastResult(std::string value, Type type, bool needs_parenthesis = false) { | 661 | std::string BitwiseCastResult(std::string value, Type type, bool needs_parenthesis = false) { |
| 651 | switch (type) { | 662 | switch (type) { |
| 652 | case Type::Bool: | 663 | case Type::Bool: |
| 664 | case Type::Bool2: | ||
| 653 | case Type::Float: | 665 | case Type::Float: |
| 654 | if (needs_parenthesis) { | 666 | if (needs_parenthesis) { |
| 655 | return '(' + value + ')'; | 667 | return '(' + value + ')'; |
| @@ -719,45 +731,51 @@ private: | |||
| 719 | constexpr std::array<const char*, 4> coord_constructors = {"float", "vec2", "vec3", "vec4"}; | 731 | constexpr std::array<const char*, 4> coord_constructors = {"float", "vec2", "vec3", "vec4"}; |
| 720 | 732 | ||
| 721 | const auto meta = std::get_if<MetaTexture>(&operation.GetMeta()); | 733 | const auto meta = std::get_if<MetaTexture>(&operation.GetMeta()); |
| 722 | const auto count = static_cast<u32>(operation.GetOperandsCount()); | ||
| 723 | ASSERT(meta); | 734 | ASSERT(meta); |
| 724 | 735 | ||
| 736 | const std::size_t count = operation.GetOperandsCount(); | ||
| 737 | const bool has_array = meta->sampler.IsArray(); | ||
| 738 | const bool has_shadow = meta->sampler.IsShadow(); | ||
| 739 | |||
| 725 | std::string expr = func; | 740 | std::string expr = func; |
| 726 | expr += '('; | 741 | expr += '('; |
| 727 | expr += GetSampler(meta->sampler); | 742 | expr += GetSampler(meta->sampler); |
| 728 | expr += ", "; | 743 | expr += ", "; |
| 729 | 744 | ||
| 730 | expr += coord_constructors[meta->coords_count - 1]; | 745 | expr += coord_constructors.at(count + (has_array ? 1 : 0) + (has_shadow ? 1 : 0) - 1); |
| 731 | expr += '('; | 746 | expr += '('; |
| 732 | for (u32 i = 0; i < count; ++i) { | 747 | for (std::size_t i = 0; i < count; ++i) { |
| 733 | const bool is_extra = i >= meta->coords_count; | 748 | expr += Visit(operation[i]); |
| 734 | const bool is_array = i == meta->array_index; | ||
| 735 | |||
| 736 | std::string operand = [&]() { | ||
| 737 | if (is_extra && is_extra_int) { | ||
| 738 | if (const auto immediate = std::get_if<ImmediateNode>(operation[i])) { | ||
| 739 | return std::to_string(static_cast<s32>(immediate->GetValue())); | ||
| 740 | } else { | ||
| 741 | return "ftoi(" + Visit(operation[i]) + ')'; | ||
| 742 | } | ||
| 743 | } else { | ||
| 744 | return Visit(operation[i]); | ||
| 745 | } | ||
| 746 | }(); | ||
| 747 | if (is_array) { | ||
| 748 | ASSERT(!is_extra); | ||
| 749 | operand = "float(ftoi(" + operand + "))"; | ||
| 750 | } | ||
| 751 | 749 | ||
| 752 | expr += operand; | 750 | const std::size_t next = i + 1; |
| 753 | 751 | if (next < count || has_array || has_shadow) | |
| 754 | if (i + 1 == meta->coords_count) { | 752 | expr += ", "; |
| 755 | expr += ')'; | 753 | } |
| 756 | } | 754 | if (has_array) { |
| 757 | if (i + 1 < count) { | 755 | expr += "float(ftoi(" + Visit(meta->array) + "))"; |
| 756 | } | ||
| 757 | if (has_shadow) { | ||
| 758 | if (has_array) | ||
| 758 | expr += ", "; | 759 | expr += ", "; |
| 760 | expr += Visit(meta->depth_compare); | ||
| 761 | } | ||
| 762 | expr += ')'; | ||
| 763 | |||
| 764 | for (const Node extra : meta->extras) { | ||
| 765 | expr += ", "; | ||
| 766 | if (is_extra_int) { | ||
| 767 | if (const auto immediate = std::get_if<ImmediateNode>(extra)) { | ||
| 768 | // Inline the string as an immediate integer in GLSL (some extra arguments are | ||
| 769 | // required to be constant) | ||
| 770 | expr += std::to_string(static_cast<s32>(immediate->GetValue())); | ||
| 771 | } else { | ||
| 772 | expr += "ftoi(" + Visit(extra) + ')'; | ||
| 773 | } | ||
| 774 | } else { | ||
| 775 | expr += Visit(extra); | ||
| 759 | } | 776 | } |
| 760 | } | 777 | } |
| 778 | |||
| 761 | expr += ')'; | 779 | expr += ')'; |
| 762 | return expr; | 780 | return expr; |
| 763 | } | 781 | } |
| @@ -1134,7 +1152,7 @@ private: | |||
| 1134 | Type::HalfFloat); | 1152 | Type::HalfFloat); |
| 1135 | } | 1153 | } |
| 1136 | 1154 | ||
| 1137 | std::string F4Texture(Operation operation) { | 1155 | std::string Texture(Operation operation) { |
| 1138 | const auto meta = std::get_if<MetaTexture>(&operation.GetMeta()); | 1156 | const auto meta = std::get_if<MetaTexture>(&operation.GetMeta()); |
| 1139 | ASSERT(meta); | 1157 | ASSERT(meta); |
| 1140 | 1158 | ||
| @@ -1145,7 +1163,7 @@ private: | |||
| 1145 | return expr + GetSwizzle(meta->element); | 1163 | return expr + GetSwizzle(meta->element); |
| 1146 | } | 1164 | } |
| 1147 | 1165 | ||
| 1148 | std::string F4TextureLod(Operation operation) { | 1166 | std::string TextureLod(Operation operation) { |
| 1149 | const auto meta = std::get_if<MetaTexture>(&operation.GetMeta()); | 1167 | const auto meta = std::get_if<MetaTexture>(&operation.GetMeta()); |
| 1150 | ASSERT(meta); | 1168 | ASSERT(meta); |
| 1151 | 1169 | ||
| @@ -1156,7 +1174,7 @@ private: | |||
| 1156 | return expr + GetSwizzle(meta->element); | 1174 | return expr + GetSwizzle(meta->element); |
| 1157 | } | 1175 | } |
| 1158 | 1176 | ||
| 1159 | std::string F4TextureGather(Operation operation) { | 1177 | std::string TextureGather(Operation operation) { |
| 1160 | const auto meta = std::get_if<MetaTexture>(&operation.GetMeta()); | 1178 | const auto meta = std::get_if<MetaTexture>(&operation.GetMeta()); |
| 1161 | ASSERT(meta); | 1179 | ASSERT(meta); |
| 1162 | 1180 | ||
| @@ -1164,7 +1182,7 @@ private: | |||
| 1164 | GetSwizzle(meta->element); | 1182 | GetSwizzle(meta->element); |
| 1165 | } | 1183 | } |
| 1166 | 1184 | ||
| 1167 | std::string F4TextureQueryDimensions(Operation operation) { | 1185 | std::string TextureQueryDimensions(Operation operation) { |
| 1168 | const auto meta = std::get_if<MetaTexture>(&operation.GetMeta()); | 1186 | const auto meta = std::get_if<MetaTexture>(&operation.GetMeta()); |
| 1169 | ASSERT(meta); | 1187 | ASSERT(meta); |
| 1170 | 1188 | ||
| @@ -1184,7 +1202,7 @@ private: | |||
| 1184 | return "0"; | 1202 | return "0"; |
| 1185 | } | 1203 | } |
| 1186 | 1204 | ||
| 1187 | std::string F4TextureQueryLod(Operation operation) { | 1205 | std::string TextureQueryLod(Operation operation) { |
| 1188 | const auto meta = std::get_if<MetaTexture>(&operation.GetMeta()); | 1206 | const auto meta = std::get_if<MetaTexture>(&operation.GetMeta()); |
| 1189 | ASSERT(meta); | 1207 | ASSERT(meta); |
| 1190 | 1208 | ||
| @@ -1195,29 +1213,33 @@ private: | |||
| 1195 | return "0"; | 1213 | return "0"; |
| 1196 | } | 1214 | } |
| 1197 | 1215 | ||
| 1198 | std::string F4TexelFetch(Operation operation) { | 1216 | std::string TexelFetch(Operation operation) { |
| 1199 | constexpr std::array<const char*, 4> constructors = {"int", "ivec2", "ivec3", "ivec4"}; | 1217 | constexpr std::array<const char*, 4> constructors = {"int", "ivec2", "ivec3", "ivec4"}; |
| 1200 | const auto meta = std::get_if<MetaTexture>(&operation.GetMeta()); | 1218 | const auto meta = std::get_if<MetaTexture>(&operation.GetMeta()); |
| 1201 | const auto count = static_cast<u32>(operation.GetOperandsCount()); | ||
| 1202 | ASSERT(meta); | 1219 | ASSERT(meta); |
| 1220 | UNIMPLEMENTED_IF(meta->sampler.IsArray()); | ||
| 1221 | const std::size_t count = operation.GetOperandsCount(); | ||
| 1203 | 1222 | ||
| 1204 | std::string expr = "texelFetch("; | 1223 | std::string expr = "texelFetch("; |
| 1205 | expr += GetSampler(meta->sampler); | 1224 | expr += GetSampler(meta->sampler); |
| 1206 | expr += ", "; | 1225 | expr += ", "; |
| 1207 | 1226 | ||
| 1208 | expr += constructors[meta->coords_count - 1]; | 1227 | expr += constructors.at(operation.GetOperandsCount() - 1); |
| 1209 | expr += '('; | 1228 | expr += '('; |
| 1210 | for (u32 i = 0; i < count; ++i) { | 1229 | for (std::size_t i = 0; i < count; ++i) { |
| 1211 | expr += VisitOperand(operation, i, Type::Int); | 1230 | expr += VisitOperand(operation, i, Type::Int); |
| 1212 | 1231 | const std::size_t next = i + 1; | |
| 1213 | if (i + 1 == meta->coords_count) { | 1232 | if (next == count) |
| 1214 | expr += ')'; | 1233 | expr += ')'; |
| 1215 | } | 1234 | else if (next < count) |
| 1216 | if (i + 1 < count) { | ||
| 1217 | expr += ", "; | 1235 | expr += ", "; |
| 1218 | } | 1236 | } |
| 1237 | for (std::size_t i = 0; i < meta->extras.size(); ++i) { | ||
| 1238 | expr += ", "; | ||
| 1239 | expr += CastOperand(Visit(meta->extras.at(i)), Type::Int); | ||
| 1219 | } | 1240 | } |
| 1220 | expr += ')'; | 1241 | expr += ')'; |
| 1242 | |||
| 1221 | return expr + GetSwizzle(meta->element); | 1243 | return expr + GetSwizzle(meta->element); |
| 1222 | } | 1244 | } |
| 1223 | 1245 | ||
| @@ -1454,12 +1476,12 @@ private: | |||
| 1454 | &GLSLDecompiler::Logical2HNotEqual, | 1476 | &GLSLDecompiler::Logical2HNotEqual, |
| 1455 | &GLSLDecompiler::Logical2HGreaterEqual, | 1477 | &GLSLDecompiler::Logical2HGreaterEqual, |
| 1456 | 1478 | ||
| 1457 | &GLSLDecompiler::F4Texture, | 1479 | &GLSLDecompiler::Texture, |
| 1458 | &GLSLDecompiler::F4TextureLod, | 1480 | &GLSLDecompiler::TextureLod, |
| 1459 | &GLSLDecompiler::F4TextureGather, | 1481 | &GLSLDecompiler::TextureGather, |
| 1460 | &GLSLDecompiler::F4TextureQueryDimensions, | 1482 | &GLSLDecompiler::TextureQueryDimensions, |
| 1461 | &GLSLDecompiler::F4TextureQueryLod, | 1483 | &GLSLDecompiler::TextureQueryLod, |
| 1462 | &GLSLDecompiler::F4TexelFetch, | 1484 | &GLSLDecompiler::TexelFetch, |
| 1463 | 1485 | ||
| 1464 | &GLSLDecompiler::Branch, | 1486 | &GLSLDecompiler::Branch, |
| 1465 | &GLSLDecompiler::PushFlowStack, | 1487 | &GLSLDecompiler::PushFlowStack, |
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index 6476a9e1a..cca2ed708 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp | |||
| @@ -107,7 +107,7 @@ RendererOpenGL::~RendererOpenGL() = default; | |||
| 107 | void RendererOpenGL::SwapBuffers( | 107 | void RendererOpenGL::SwapBuffers( |
| 108 | std::optional<std::reference_wrapper<const Tegra::FramebufferConfig>> framebuffer) { | 108 | std::optional<std::reference_wrapper<const Tegra::FramebufferConfig>> framebuffer) { |
| 109 | 109 | ||
| 110 | Core::System::GetInstance().GetPerfStats().EndSystemFrame(); | 110 | system.GetPerfStats().EndSystemFrame(); |
| 111 | 111 | ||
| 112 | // Maintain the rasterizer's state as a priority | 112 | // Maintain the rasterizer's state as a priority |
| 113 | OpenGLState prev_state = OpenGLState::GetCurState(); | 113 | OpenGLState prev_state = OpenGLState::GetCurState(); |
| @@ -137,8 +137,8 @@ void RendererOpenGL::SwapBuffers( | |||
| 137 | 137 | ||
| 138 | render_window.PollEvents(); | 138 | render_window.PollEvents(); |
| 139 | 139 | ||
| 140 | Core::System::GetInstance().FrameLimiter().DoFrameLimiting(CoreTiming::GetGlobalTimeUs()); | 140 | system.FrameLimiter().DoFrameLimiting(Core::Timing::GetGlobalTimeUs()); |
| 141 | Core::System::GetInstance().GetPerfStats().BeginSystemFrame(); | 141 | system.GetPerfStats().BeginSystemFrame(); |
| 142 | 142 | ||
| 143 | // Restore the rasterizer state | 143 | // Restore the rasterizer state |
| 144 | prev_state.Apply(); | 144 | prev_state.Apply(); |
diff --git a/src/video_core/renderer_vulkan/declarations.h b/src/video_core/renderer_vulkan/declarations.h new file mode 100644 index 000000000..ba25b5bc7 --- /dev/null +++ b/src/video_core/renderer_vulkan/declarations.h | |||
| @@ -0,0 +1,45 @@ | |||
| 1 | // Copyright 2019 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <vulkan/vulkan.hpp> | ||
| 8 | |||
| 9 | namespace Vulkan { | ||
| 10 | |||
| 11 | // vulkan.hpp unique handlers use DispatchLoaderStatic | ||
| 12 | template <typename T> | ||
| 13 | using UniqueHandle = vk::UniqueHandle<T, vk::DispatchLoaderDynamic>; | ||
| 14 | |||
| 15 | using UniqueAccelerationStructureNV = UniqueHandle<vk::AccelerationStructureNV>; | ||
| 16 | using UniqueBuffer = UniqueHandle<vk::Buffer>; | ||
| 17 | using UniqueBufferView = UniqueHandle<vk::BufferView>; | ||
| 18 | using UniqueCommandBuffer = UniqueHandle<vk::CommandBuffer>; | ||
| 19 | using UniqueCommandPool = UniqueHandle<vk::CommandPool>; | ||
| 20 | using UniqueDescriptorPool = UniqueHandle<vk::DescriptorPool>; | ||
| 21 | using UniqueDescriptorSet = UniqueHandle<vk::DescriptorSet>; | ||
| 22 | using UniqueDescriptorSetLayout = UniqueHandle<vk::DescriptorSetLayout>; | ||
| 23 | using UniqueDescriptorUpdateTemplate = UniqueHandle<vk::DescriptorUpdateTemplate>; | ||
| 24 | using UniqueDevice = UniqueHandle<vk::Device>; | ||
| 25 | using UniqueDeviceMemory = UniqueHandle<vk::DeviceMemory>; | ||
| 26 | using UniqueEvent = UniqueHandle<vk::Event>; | ||
| 27 | using UniqueFence = UniqueHandle<vk::Fence>; | ||
| 28 | using UniqueFramebuffer = UniqueHandle<vk::Framebuffer>; | ||
| 29 | using UniqueImage = UniqueHandle<vk::Image>; | ||
| 30 | using UniqueImageView = UniqueHandle<vk::ImageView>; | ||
| 31 | using UniqueIndirectCommandsLayoutNVX = UniqueHandle<vk::IndirectCommandsLayoutNVX>; | ||
| 32 | using UniqueObjectTableNVX = UniqueHandle<vk::ObjectTableNVX>; | ||
| 33 | using UniquePipeline = UniqueHandle<vk::Pipeline>; | ||
| 34 | using UniquePipelineCache = UniqueHandle<vk::PipelineCache>; | ||
| 35 | using UniquePipelineLayout = UniqueHandle<vk::PipelineLayout>; | ||
| 36 | using UniqueQueryPool = UniqueHandle<vk::QueryPool>; | ||
| 37 | using UniqueRenderPass = UniqueHandle<vk::RenderPass>; | ||
| 38 | using UniqueSampler = UniqueHandle<vk::Sampler>; | ||
| 39 | using UniqueSamplerYcbcrConversion = UniqueHandle<vk::SamplerYcbcrConversion>; | ||
| 40 | using UniqueSemaphore = UniqueHandle<vk::Semaphore>; | ||
| 41 | using UniqueShaderModule = UniqueHandle<vk::ShaderModule>; | ||
| 42 | using UniqueSwapchainKHR = UniqueHandle<vk::SwapchainKHR>; | ||
| 43 | using UniqueValidationCacheEXT = UniqueHandle<vk::ValidationCacheEXT>; | ||
| 44 | |||
| 45 | } // namespace Vulkan | ||
diff --git a/src/video_core/renderer_vulkan/vk_device.cpp b/src/video_core/renderer_vulkan/vk_device.cpp new file mode 100644 index 000000000..78a4e5f0e --- /dev/null +++ b/src/video_core/renderer_vulkan/vk_device.cpp | |||
| @@ -0,0 +1,231 @@ | |||
| 1 | // Copyright 2018 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <map> | ||
| 6 | #include <optional> | ||
| 7 | #include <set> | ||
| 8 | #include <vector> | ||
| 9 | #include "common/assert.h" | ||
| 10 | #include "video_core/renderer_vulkan/declarations.h" | ||
| 11 | #include "video_core/renderer_vulkan/vk_device.h" | ||
| 12 | |||
| 13 | namespace Vulkan { | ||
| 14 | |||
| 15 | namespace Alternatives { | ||
| 16 | |||
| 17 | constexpr std::array<vk::Format, 3> Depth24UnormS8Uint = { | ||
| 18 | vk::Format::eD32SfloatS8Uint, vk::Format::eD16UnormS8Uint, {}}; | ||
| 19 | constexpr std::array<vk::Format, 3> Depth16UnormS8Uint = { | ||
| 20 | vk::Format::eD24UnormS8Uint, vk::Format::eD32SfloatS8Uint, {}}; | ||
| 21 | |||
| 22 | } // namespace Alternatives | ||
| 23 | |||
| 24 | constexpr const vk::Format* GetFormatAlternatives(vk::Format format) { | ||
| 25 | switch (format) { | ||
| 26 | case vk::Format::eD24UnormS8Uint: | ||
| 27 | return Alternatives::Depth24UnormS8Uint.data(); | ||
| 28 | case vk::Format::eD16UnormS8Uint: | ||
| 29 | return Alternatives::Depth16UnormS8Uint.data(); | ||
| 30 | default: | ||
| 31 | return nullptr; | ||
| 32 | } | ||
| 33 | } | ||
| 34 | |||
| 35 | constexpr vk::FormatFeatureFlags GetFormatFeatures(vk::FormatProperties properties, | ||
| 36 | FormatType format_type) { | ||
| 37 | switch (format_type) { | ||
| 38 | case FormatType::Linear: | ||
| 39 | return properties.linearTilingFeatures; | ||
| 40 | case FormatType::Optimal: | ||
| 41 | return properties.optimalTilingFeatures; | ||
| 42 | case FormatType::Buffer: | ||
| 43 | return properties.bufferFeatures; | ||
| 44 | default: | ||
| 45 | return {}; | ||
| 46 | } | ||
| 47 | } | ||
| 48 | |||
| 49 | VKDevice::VKDevice(const vk::DispatchLoaderDynamic& dldi, vk::PhysicalDevice physical, | ||
| 50 | vk::SurfaceKHR surface) | ||
| 51 | : physical{physical}, format_properties{GetFormatProperties(dldi, physical)} { | ||
| 52 | SetupFamilies(dldi, surface); | ||
| 53 | SetupProperties(dldi); | ||
| 54 | } | ||
| 55 | |||
| 56 | VKDevice::~VKDevice() = default; | ||
| 57 | |||
| 58 | bool VKDevice::Create(const vk::DispatchLoaderDynamic& dldi, vk::Instance instance) { | ||
| 59 | const auto queue_cis = GetDeviceQueueCreateInfos(); | ||
| 60 | vk::PhysicalDeviceFeatures device_features{}; | ||
| 61 | |||
| 62 | const std::vector<const char*> extensions = {VK_KHR_SWAPCHAIN_EXTENSION_NAME}; | ||
| 63 | const vk::DeviceCreateInfo device_ci({}, static_cast<u32>(queue_cis.size()), queue_cis.data(), | ||
| 64 | 0, nullptr, static_cast<u32>(extensions.size()), | ||
| 65 | extensions.data(), &device_features); | ||
| 66 | vk::Device dummy_logical; | ||
| 67 | if (physical.createDevice(&device_ci, nullptr, &dummy_logical, dldi) != vk::Result::eSuccess) { | ||
| 68 | LOG_CRITICAL(Render_Vulkan, "Logical device failed to be created!"); | ||
| 69 | return false; | ||
| 70 | } | ||
| 71 | |||
| 72 | dld.init(instance, dldi.vkGetInstanceProcAddr, dummy_logical, dldi.vkGetDeviceProcAddr); | ||
| 73 | logical = UniqueDevice( | ||
| 74 | dummy_logical, vk::ObjectDestroy<vk::NoParent, vk::DispatchLoaderDynamic>(nullptr, dld)); | ||
| 75 | |||
| 76 | graphics_queue = logical->getQueue(graphics_family, 0, dld); | ||
| 77 | present_queue = logical->getQueue(present_family, 0, dld); | ||
| 78 | return true; | ||
| 79 | } | ||
| 80 | |||
| 81 | vk::Format VKDevice::GetSupportedFormat(vk::Format wanted_format, | ||
| 82 | vk::FormatFeatureFlags wanted_usage, | ||
| 83 | FormatType format_type) const { | ||
| 84 | if (IsFormatSupported(wanted_format, wanted_usage, format_type)) { | ||
| 85 | return wanted_format; | ||
| 86 | } | ||
| 87 | // The wanted format is not supported by hardware, search for alternatives | ||
| 88 | const vk::Format* alternatives = GetFormatAlternatives(wanted_format); | ||
| 89 | if (alternatives == nullptr) { | ||
| 90 | LOG_CRITICAL(Render_Vulkan, | ||
| 91 | "Format={} with usage={} and type={} has no defined alternatives and host " | ||
| 92 | "hardware does not support it", | ||
| 93 | static_cast<u32>(wanted_format), static_cast<u32>(wanted_usage), | ||
| 94 | static_cast<u32>(format_type)); | ||
| 95 | UNREACHABLE(); | ||
| 96 | return wanted_format; | ||
| 97 | } | ||
| 98 | |||
| 99 | std::size_t i = 0; | ||
| 100 | for (vk::Format alternative = alternatives[0]; alternative != vk::Format{}; | ||
| 101 | alternative = alternatives[++i]) { | ||
| 102 | if (!IsFormatSupported(alternative, wanted_usage, format_type)) | ||
| 103 | continue; | ||
| 104 | LOG_WARNING(Render_Vulkan, | ||
| 105 | "Emulating format={} with alternative format={} with usage={} and type={}", | ||
| 106 | static_cast<u32>(wanted_format), static_cast<u32>(alternative), | ||
| 107 | static_cast<u32>(wanted_usage), static_cast<u32>(format_type)); | ||
| 108 | return alternative; | ||
| 109 | } | ||
| 110 | |||
| 111 | // No alternatives found, panic | ||
| 112 | LOG_CRITICAL(Render_Vulkan, | ||
| 113 | "Format={} with usage={} and type={} is not supported by the host hardware and " | ||
| 114 | "doesn't support any of the alternatives", | ||
| 115 | static_cast<u32>(wanted_format), static_cast<u32>(wanted_usage), | ||
| 116 | static_cast<u32>(format_type)); | ||
| 117 | UNREACHABLE(); | ||
| 118 | return wanted_format; | ||
| 119 | } | ||
| 120 | |||
| 121 | bool VKDevice::IsFormatSupported(vk::Format wanted_format, vk::FormatFeatureFlags wanted_usage, | ||
| 122 | FormatType format_type) const { | ||
| 123 | const auto it = format_properties.find(wanted_format); | ||
| 124 | if (it == format_properties.end()) { | ||
| 125 | LOG_CRITICAL(Render_Vulkan, "Unimplemented format query={}", | ||
| 126 | static_cast<u32>(wanted_format)); | ||
| 127 | UNREACHABLE(); | ||
| 128 | return true; | ||
| 129 | } | ||
| 130 | const vk::FormatFeatureFlags supported_usage = GetFormatFeatures(it->second, format_type); | ||
| 131 | return (supported_usage & wanted_usage) == wanted_usage; | ||
| 132 | } | ||
| 133 | |||
| 134 | bool VKDevice::IsSuitable(const vk::DispatchLoaderDynamic& dldi, vk::PhysicalDevice physical, | ||
| 135 | vk::SurfaceKHR surface) { | ||
| 136 | const std::string swapchain_extension = VK_KHR_SWAPCHAIN_EXTENSION_NAME; | ||
| 137 | |||
| 138 | bool has_swapchain{}; | ||
| 139 | for (const auto& prop : physical.enumerateDeviceExtensionProperties(nullptr, dldi)) { | ||
| 140 | has_swapchain |= prop.extensionName == swapchain_extension; | ||
| 141 | } | ||
| 142 | if (!has_swapchain) { | ||
| 143 | // The device doesn't support creating swapchains. | ||
| 144 | return false; | ||
| 145 | } | ||
| 146 | |||
| 147 | bool has_graphics{}, has_present{}; | ||
| 148 | const auto queue_family_properties = physical.getQueueFamilyProperties(dldi); | ||
| 149 | for (u32 i = 0; i < static_cast<u32>(queue_family_properties.size()); ++i) { | ||
| 150 | const auto& family = queue_family_properties[i]; | ||
| 151 | if (family.queueCount == 0) | ||
| 152 | continue; | ||
| 153 | |||
| 154 | has_graphics |= | ||
| 155 | (family.queueFlags & vk::QueueFlagBits::eGraphics) != static_cast<vk::QueueFlagBits>(0); | ||
| 156 | has_present |= physical.getSurfaceSupportKHR(i, surface, dldi) != 0; | ||
| 157 | } | ||
| 158 | if (!has_graphics || !has_present) { | ||
| 159 | // The device doesn't have a graphics and present queue. | ||
| 160 | return false; | ||
| 161 | } | ||
| 162 | |||
| 163 | // TODO(Rodrigo): Check if the device matches all requeriments. | ||
| 164 | const vk::PhysicalDeviceProperties props = physical.getProperties(dldi); | ||
| 165 | if (props.limits.maxUniformBufferRange < 65536) { | ||
| 166 | return false; | ||
| 167 | } | ||
| 168 | |||
| 169 | // Device is suitable. | ||
| 170 | return true; | ||
| 171 | } | ||
| 172 | |||
| 173 | void VKDevice::SetupFamilies(const vk::DispatchLoaderDynamic& dldi, vk::SurfaceKHR surface) { | ||
| 174 | std::optional<u32> graphics_family_, present_family_; | ||
| 175 | |||
| 176 | const auto queue_family_properties = physical.getQueueFamilyProperties(dldi); | ||
| 177 | for (u32 i = 0; i < static_cast<u32>(queue_family_properties.size()); ++i) { | ||
| 178 | if (graphics_family_ && present_family_) | ||
| 179 | break; | ||
| 180 | |||
| 181 | const auto& queue_family = queue_family_properties[i]; | ||
| 182 | if (queue_family.queueCount == 0) | ||
| 183 | continue; | ||
| 184 | |||
| 185 | if (queue_family.queueFlags & vk::QueueFlagBits::eGraphics) | ||
| 186 | graphics_family_ = i; | ||
| 187 | if (physical.getSurfaceSupportKHR(i, surface, dldi)) | ||
| 188 | present_family_ = i; | ||
| 189 | } | ||
| 190 | ASSERT(graphics_family_ && present_family_); | ||
| 191 | |||
| 192 | graphics_family = *graphics_family_; | ||
| 193 | present_family = *present_family_; | ||
| 194 | } | ||
| 195 | |||
| 196 | void VKDevice::SetupProperties(const vk::DispatchLoaderDynamic& dldi) { | ||
| 197 | const vk::PhysicalDeviceProperties props = physical.getProperties(dldi); | ||
| 198 | device_type = props.deviceType; | ||
| 199 | uniform_buffer_alignment = static_cast<u64>(props.limits.minUniformBufferOffsetAlignment); | ||
| 200 | } | ||
| 201 | |||
| 202 | std::vector<vk::DeviceQueueCreateInfo> VKDevice::GetDeviceQueueCreateInfos() const { | ||
| 203 | static const float QUEUE_PRIORITY = 1.f; | ||
| 204 | |||
| 205 | std::set<u32> unique_queue_families = {graphics_family, present_family}; | ||
| 206 | std::vector<vk::DeviceQueueCreateInfo> queue_cis; | ||
| 207 | |||
| 208 | for (u32 queue_family : unique_queue_families) | ||
| 209 | queue_cis.push_back({{}, queue_family, 1, &QUEUE_PRIORITY}); | ||
| 210 | |||
| 211 | return queue_cis; | ||
| 212 | } | ||
| 213 | |||
| 214 | std::map<vk::Format, vk::FormatProperties> VKDevice::GetFormatProperties( | ||
| 215 | const vk::DispatchLoaderDynamic& dldi, vk::PhysicalDevice physical) { | ||
| 216 | std::map<vk::Format, vk::FormatProperties> format_properties; | ||
| 217 | |||
| 218 | const auto AddFormatQuery = [&format_properties, &dldi, physical](vk::Format format) { | ||
| 219 | format_properties.emplace(format, physical.getFormatProperties(format, dldi)); | ||
| 220 | }; | ||
| 221 | AddFormatQuery(vk::Format::eA8B8G8R8UnormPack32); | ||
| 222 | AddFormatQuery(vk::Format::eR5G6B5UnormPack16); | ||
| 223 | AddFormatQuery(vk::Format::eD32Sfloat); | ||
| 224 | AddFormatQuery(vk::Format::eD16UnormS8Uint); | ||
| 225 | AddFormatQuery(vk::Format::eD24UnormS8Uint); | ||
| 226 | AddFormatQuery(vk::Format::eD32SfloatS8Uint); | ||
| 227 | |||
| 228 | return format_properties; | ||
| 229 | } | ||
| 230 | |||
| 231 | } // namespace Vulkan | ||
diff --git a/src/video_core/renderer_vulkan/vk_device.h b/src/video_core/renderer_vulkan/vk_device.h new file mode 100644 index 000000000..e87c7a508 --- /dev/null +++ b/src/video_core/renderer_vulkan/vk_device.h | |||
| @@ -0,0 +1,116 @@ | |||
| 1 | // Copyright 2018 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <map> | ||
| 8 | #include <vector> | ||
| 9 | #include "common/common_types.h" | ||
| 10 | #include "video_core/renderer_vulkan/declarations.h" | ||
| 11 | |||
| 12 | namespace Vulkan { | ||
| 13 | |||
| 14 | /// Format usage descriptor | ||
| 15 | enum class FormatType { Linear, Optimal, Buffer }; | ||
| 16 | |||
| 17 | /// Handles data specific to a physical device. | ||
| 18 | class VKDevice final { | ||
| 19 | public: | ||
| 20 | explicit VKDevice(const vk::DispatchLoaderDynamic& dldi, vk::PhysicalDevice physical, | ||
| 21 | vk::SurfaceKHR surface); | ||
| 22 | ~VKDevice(); | ||
| 23 | |||
| 24 | /// Initializes the device. Returns true on success. | ||
| 25 | bool Create(const vk::DispatchLoaderDynamic& dldi, vk::Instance instance); | ||
| 26 | |||
| 27 | /** | ||
| 28 | * Returns a format supported by the device for the passed requeriments. | ||
| 29 | * @param wanted_format The ideal format to be returned. It may not be the returned format. | ||
| 30 | * @param wanted_usage The usage that must be fulfilled even if the format is not supported. | ||
| 31 | * @param format_type Format type usage. | ||
| 32 | * @returns A format supported by the device. | ||
| 33 | */ | ||
| 34 | vk::Format GetSupportedFormat(vk::Format wanted_format, vk::FormatFeatureFlags wanted_usage, | ||
| 35 | FormatType format_type) const; | ||
| 36 | |||
| 37 | /// Returns the dispatch loader with direct function pointers of the device | ||
| 38 | const vk::DispatchLoaderDynamic& GetDispatchLoader() const { | ||
| 39 | return dld; | ||
| 40 | } | ||
| 41 | |||
| 42 | /// Returns the logical device | ||
| 43 | vk::Device GetLogical() const { | ||
| 44 | return logical.get(); | ||
| 45 | } | ||
| 46 | |||
| 47 | /// Returns the physical device. | ||
| 48 | vk::PhysicalDevice GetPhysical() const { | ||
| 49 | return physical; | ||
| 50 | } | ||
| 51 | |||
| 52 | /// Returns the main graphics queue. | ||
| 53 | vk::Queue GetGraphicsQueue() const { | ||
| 54 | return graphics_queue; | ||
| 55 | } | ||
| 56 | |||
| 57 | /// Returns the main present queue. | ||
| 58 | vk::Queue GetPresentQueue() const { | ||
| 59 | return present_queue; | ||
| 60 | } | ||
| 61 | |||
| 62 | /// Returns main graphics queue family index. | ||
| 63 | u32 GetGraphicsFamily() const { | ||
| 64 | return graphics_family; | ||
| 65 | } | ||
| 66 | |||
| 67 | /// Returns main present queue family index. | ||
| 68 | u32 GetPresentFamily() const { | ||
| 69 | return present_family; | ||
| 70 | } | ||
| 71 | |||
| 72 | /// Returns if the device is integrated with the host CPU | ||
| 73 | bool IsIntegrated() const { | ||
| 74 | return device_type == vk::PhysicalDeviceType::eIntegratedGpu; | ||
| 75 | } | ||
| 76 | |||
| 77 | /// Returns uniform buffer alignment requeriment | ||
| 78 | u64 GetUniformBufferAlignment() const { | ||
| 79 | return uniform_buffer_alignment; | ||
| 80 | } | ||
| 81 | |||
| 82 | /// Checks if the physical device is suitable. | ||
| 83 | static bool IsSuitable(const vk::DispatchLoaderDynamic& dldi, vk::PhysicalDevice physical, | ||
| 84 | vk::SurfaceKHR surface); | ||
| 85 | |||
| 86 | private: | ||
| 87 | /// Sets up queue families. | ||
| 88 | void SetupFamilies(const vk::DispatchLoaderDynamic& dldi, vk::SurfaceKHR surface); | ||
| 89 | |||
| 90 | /// Sets up device properties. | ||
| 91 | void SetupProperties(const vk::DispatchLoaderDynamic& dldi); | ||
| 92 | |||
| 93 | /// Returns a list of queue initialization descriptors. | ||
| 94 | std::vector<vk::DeviceQueueCreateInfo> GetDeviceQueueCreateInfos() const; | ||
| 95 | |||
| 96 | /// Returns true if a format is supported. | ||
| 97 | bool IsFormatSupported(vk::Format wanted_format, vk::FormatFeatureFlags wanted_usage, | ||
| 98 | FormatType format_type) const; | ||
| 99 | |||
| 100 | /// Returns the device properties for Vulkan formats. | ||
| 101 | static std::map<vk::Format, vk::FormatProperties> GetFormatProperties( | ||
| 102 | const vk::DispatchLoaderDynamic& dldi, vk::PhysicalDevice physical); | ||
| 103 | |||
| 104 | const vk::PhysicalDevice physical; ///< Physical device | ||
| 105 | vk::DispatchLoaderDynamic dld; ///< Device function pointers | ||
| 106 | UniqueDevice logical; ///< Logical device | ||
| 107 | vk::Queue graphics_queue; ///< Main graphics queue | ||
| 108 | vk::Queue present_queue; ///< Main present queue | ||
| 109 | u32 graphics_family{}; ///< Main graphics queue family index | ||
| 110 | u32 present_family{}; ///< Main present queue family index | ||
| 111 | vk::PhysicalDeviceType device_type; ///< Physical device type | ||
| 112 | u64 uniform_buffer_alignment{}; ///< Uniform buffer alignment requeriment | ||
| 113 | std::map<vk::Format, vk::FormatProperties> format_properties; ///< Format properties dictionary | ||
| 114 | }; | ||
| 115 | |||
| 116 | } // namespace Vulkan | ||
diff --git a/src/video_core/shader/decode/arithmetic_integer.cpp b/src/video_core/shader/decode/arithmetic_integer.cpp index 38bb692d6..9fd4b273e 100644 --- a/src/video_core/shader/decode/arithmetic_integer.cpp +++ b/src/video_core/shader/decode/arithmetic_integer.cpp | |||
| @@ -41,7 +41,7 @@ u32 ShaderIR::DecodeArithmeticInteger(NodeBlock& bb, u32 pc) { | |||
| 41 | 41 | ||
| 42 | const Node value = Operation(OperationCode::IAdd, PRECISE, op_a, op_b); | 42 | const Node value = Operation(OperationCode::IAdd, PRECISE, op_a, op_b); |
| 43 | 43 | ||
| 44 | SetInternalFlagsFromInteger(bb, value, instr.op_32.generates_cc); | 44 | SetInternalFlagsFromInteger(bb, value, instr.generates_cc); |
| 45 | SetRegister(bb, instr.gpr0, value); | 45 | SetRegister(bb, instr.gpr0, value); |
| 46 | break; | 46 | break; |
| 47 | } | 47 | } |
| @@ -284,4 +284,4 @@ void ShaderIR::WriteLop3Instruction(NodeBlock& bb, Register dest, Node op_a, Nod | |||
| 284 | SetRegister(bb, dest, value); | 284 | SetRegister(bb, dest, value); |
| 285 | } | 285 | } |
| 286 | 286 | ||
| 287 | } // namespace VideoCommon::Shader \ No newline at end of file | 287 | } // namespace VideoCommon::Shader |
diff --git a/src/video_core/shader/decode/conversion.cpp b/src/video_core/shader/decode/conversion.cpp index a992f73f8..55a6fbbf2 100644 --- a/src/video_core/shader/decode/conversion.cpp +++ b/src/video_core/shader/decode/conversion.cpp | |||
| @@ -118,8 +118,8 @@ u32 ShaderIR::DecodeConversion(NodeBlock& bb, u32 pc) { | |||
| 118 | 118 | ||
| 119 | value = [&]() { | 119 | value = [&]() { |
| 120 | switch (instr.conversion.f2i.rounding) { | 120 | switch (instr.conversion.f2i.rounding) { |
| 121 | case Tegra::Shader::F2iRoundingOp::None: | 121 | case Tegra::Shader::F2iRoundingOp::RoundEven: |
| 122 | return value; | 122 | return Operation(OperationCode::FRoundEven, PRECISE, value); |
| 123 | case Tegra::Shader::F2iRoundingOp::Floor: | 123 | case Tegra::Shader::F2iRoundingOp::Floor: |
| 124 | return Operation(OperationCode::FFloor, PRECISE, value); | 124 | return Operation(OperationCode::FFloor, PRECISE, value); |
| 125 | case Tegra::Shader::F2iRoundingOp::Ceil: | 125 | case Tegra::Shader::F2iRoundingOp::Ceil: |
| @@ -146,4 +146,4 @@ u32 ShaderIR::DecodeConversion(NodeBlock& bb, u32 pc) { | |||
| 146 | return pc; | 146 | return pc; |
| 147 | } | 147 | } |
| 148 | 148 | ||
| 149 | } // namespace VideoCommon::Shader \ No newline at end of file | 149 | } // namespace VideoCommon::Shader |
diff --git a/src/video_core/shader/decode/memory.cpp b/src/video_core/shader/decode/memory.cpp index e006f8138..55ec601ff 100644 --- a/src/video_core/shader/decode/memory.cpp +++ b/src/video_core/shader/decode/memory.cpp | |||
| @@ -306,7 +306,6 @@ u32 ShaderIR::DecodeMemory(NodeBlock& bb, u32 pc) { | |||
| 306 | case OpCode::Id::TLD4S: { | 306 | case OpCode::Id::TLD4S: { |
| 307 | UNIMPLEMENTED_IF_MSG(instr.tld4s.UsesMiscMode(TextureMiscMode::AOFFI), | 307 | UNIMPLEMENTED_IF_MSG(instr.tld4s.UsesMiscMode(TextureMiscMode::AOFFI), |
| 308 | "AOFFI is not implemented"); | 308 | "AOFFI is not implemented"); |
| 309 | |||
| 310 | if (instr.tld4s.UsesMiscMode(TextureMiscMode::NODEP)) { | 309 | if (instr.tld4s.UsesMiscMode(TextureMiscMode::NODEP)) { |
| 311 | LOG_WARNING(HW_GPU, "TLD4S.NODEP implementation is incomplete"); | 310 | LOG_WARNING(HW_GPU, "TLD4S.NODEP implementation is incomplete"); |
| 312 | } | 311 | } |
| @@ -315,9 +314,8 @@ u32 ShaderIR::DecodeMemory(NodeBlock& bb, u32 pc) { | |||
| 315 | const Node op_a = GetRegister(instr.gpr8); | 314 | const Node op_a = GetRegister(instr.gpr8); |
| 316 | const Node op_b = GetRegister(instr.gpr20); | 315 | const Node op_b = GetRegister(instr.gpr20); |
| 317 | 316 | ||
| 318 | std::vector<Node> coords; | ||
| 319 | |||
| 320 | // TODO(Subv): Figure out how the sampler type is encoded in the TLD4S instruction. | 317 | // TODO(Subv): Figure out how the sampler type is encoded in the TLD4S instruction. |
| 318 | std::vector<Node> coords; | ||
| 321 | if (depth_compare) { | 319 | if (depth_compare) { |
| 322 | // Note: TLD4S coordinate encoding works just like TEXS's | 320 | // Note: TLD4S coordinate encoding works just like TEXS's |
| 323 | const Node op_y = GetRegister(instr.gpr8.Value() + 1); | 321 | const Node op_y = GetRegister(instr.gpr8.Value() + 1); |
| @@ -328,18 +326,17 @@ u32 ShaderIR::DecodeMemory(NodeBlock& bb, u32 pc) { | |||
| 328 | coords.push_back(op_a); | 326 | coords.push_back(op_a); |
| 329 | coords.push_back(op_b); | 327 | coords.push_back(op_b); |
| 330 | } | 328 | } |
| 331 | const auto num_coords = static_cast<u32>(coords.size()); | 329 | std::vector<Node> extras; |
| 332 | coords.push_back(Immediate(static_cast<u32>(instr.tld4s.component))); | 330 | extras.push_back(Immediate(static_cast<u32>(instr.tld4s.component))); |
| 333 | 331 | ||
| 334 | const auto& sampler = | 332 | const auto& sampler = |
| 335 | GetSampler(instr.sampler, TextureType::Texture2D, false, depth_compare); | 333 | GetSampler(instr.sampler, TextureType::Texture2D, false, depth_compare); |
| 336 | 334 | ||
| 337 | Node4 values; | 335 | Node4 values; |
| 338 | for (u32 element = 0; element < values.size(); ++element) { | 336 | for (u32 element = 0; element < values.size(); ++element) { |
| 339 | auto params = coords; | 337 | auto coords_copy = coords; |
| 340 | MetaTexture meta{sampler, element, num_coords}; | 338 | MetaTexture meta{sampler, {}, {}, extras, element}; |
| 341 | values[element] = | 339 | values[element] = Operation(OperationCode::TextureGather, meta, std::move(coords_copy)); |
| 342 | Operation(OperationCode::F4TextureGather, std::move(meta), std::move(params)); | ||
| 343 | } | 340 | } |
| 344 | 341 | ||
| 345 | WriteTexsInstructionFloat(bb, instr, values); | 342 | WriteTexsInstructionFloat(bb, instr, values); |
| @@ -360,12 +357,13 @@ u32 ShaderIR::DecodeMemory(NodeBlock& bb, u32 pc) { | |||
| 360 | switch (instr.txq.query_type) { | 357 | switch (instr.txq.query_type) { |
| 361 | case Tegra::Shader::TextureQueryType::Dimension: { | 358 | case Tegra::Shader::TextureQueryType::Dimension: { |
| 362 | for (u32 element = 0; element < 4; ++element) { | 359 | for (u32 element = 0; element < 4; ++element) { |
| 363 | if (instr.txq.IsComponentEnabled(element)) { | 360 | if (!instr.txq.IsComponentEnabled(element)) { |
| 364 | MetaTexture meta{sampler, element}; | 361 | continue; |
| 365 | const Node value = Operation(OperationCode::F4TextureQueryDimensions, | ||
| 366 | std::move(meta), GetRegister(instr.gpr8)); | ||
| 367 | SetTemporal(bb, indexer++, value); | ||
| 368 | } | 362 | } |
| 363 | MetaTexture meta{sampler, {}, {}, {}, element}; | ||
| 364 | const Node value = | ||
| 365 | Operation(OperationCode::TextureQueryDimensions, meta, GetRegister(instr.gpr8)); | ||
| 366 | SetTemporal(bb, indexer++, value); | ||
| 369 | } | 367 | } |
| 370 | for (u32 i = 0; i < indexer; ++i) { | 368 | for (u32 i = 0; i < indexer; ++i) { |
| 371 | SetRegister(bb, instr.gpr0.Value() + i, GetTemporal(i)); | 369 | SetRegister(bb, instr.gpr0.Value() + i, GetTemporal(i)); |
| @@ -412,9 +410,8 @@ u32 ShaderIR::DecodeMemory(NodeBlock& bb, u32 pc) { | |||
| 412 | 410 | ||
| 413 | for (u32 element = 0; element < 2; ++element) { | 411 | for (u32 element = 0; element < 2; ++element) { |
| 414 | auto params = coords; | 412 | auto params = coords; |
| 415 | MetaTexture meta_texture{sampler, element, static_cast<u32>(coords.size())}; | 413 | MetaTexture meta{sampler, {}, {}, {}, element}; |
| 416 | const Node value = | 414 | const Node value = Operation(OperationCode::TextureQueryLod, meta, std::move(params)); |
| 417 | Operation(OperationCode::F4TextureQueryLod, meta_texture, std::move(params)); | ||
| 418 | SetTemporal(bb, element, value); | 415 | SetTemporal(bb, element, value); |
| 419 | } | 416 | } |
| 420 | for (u32 element = 0; element < 2; ++element) { | 417 | for (u32 element = 0; element < 2; ++element) { |
| @@ -432,7 +429,7 @@ u32 ShaderIR::DecodeMemory(NodeBlock& bb, u32 pc) { | |||
| 432 | UNIMPLEMENTED_IF_MSG(instr.tlds.UsesMiscMode(TextureMiscMode::MZ), "MZ is not implemented"); | 429 | UNIMPLEMENTED_IF_MSG(instr.tlds.UsesMiscMode(TextureMiscMode::MZ), "MZ is not implemented"); |
| 433 | 430 | ||
| 434 | if (instr.tlds.UsesMiscMode(TextureMiscMode::NODEP)) { | 431 | if (instr.tlds.UsesMiscMode(TextureMiscMode::NODEP)) { |
| 435 | LOG_WARNING(HW_GPU, "TMML.NODEP implementation is incomplete"); | 432 | LOG_WARNING(HW_GPU, "TLDS.NODEP implementation is incomplete"); |
| 436 | } | 433 | } |
| 437 | 434 | ||
| 438 | WriteTexsInstructionFloat(bb, instr, GetTldsCode(instr, texture_type, is_array)); | 435 | WriteTexsInstructionFloat(bb, instr, GetTldsCode(instr, texture_type, is_array)); |
| @@ -535,15 +532,16 @@ void ShaderIR::WriteTexsInstructionHalfFloat(NodeBlock& bb, Instruction instr, | |||
| 535 | } | 532 | } |
| 536 | 533 | ||
| 537 | Node4 ShaderIR::GetTextureCode(Instruction instr, TextureType texture_type, | 534 | Node4 ShaderIR::GetTextureCode(Instruction instr, TextureType texture_type, |
| 538 | TextureProcessMode process_mode, bool depth_compare, bool is_array, | 535 | TextureProcessMode process_mode, std::vector<Node> coords, |
| 539 | std::size_t array_offset, std::size_t bias_offset, | 536 | Node array, Node depth_compare, u32 bias_offset) { |
| 540 | std::vector<Node>&& coords) { | 537 | const bool is_array = array; |
| 541 | UNIMPLEMENTED_IF_MSG( | 538 | const bool is_shadow = depth_compare; |
| 542 | (texture_type == TextureType::Texture3D && (is_array || depth_compare)) || | ||
| 543 | (texture_type == TextureType::TextureCube && is_array && depth_compare), | ||
| 544 | "This method is not supported."); | ||
| 545 | 539 | ||
| 546 | const auto& sampler = GetSampler(instr.sampler, texture_type, is_array, depth_compare); | 540 | UNIMPLEMENTED_IF_MSG((texture_type == TextureType::Texture3D && (is_array || is_shadow)) || |
| 541 | (texture_type == TextureType::TextureCube && is_array && is_shadow), | ||
| 542 | "This method is not supported."); | ||
| 543 | |||
| 544 | const auto& sampler = GetSampler(instr.sampler, texture_type, is_array, is_shadow); | ||
| 547 | 545 | ||
| 548 | const bool lod_needed = process_mode == TextureProcessMode::LZ || | 546 | const bool lod_needed = process_mode == TextureProcessMode::LZ || |
| 549 | process_mode == TextureProcessMode::LL || | 547 | process_mode == TextureProcessMode::LL || |
| @@ -552,35 +550,30 @@ Node4 ShaderIR::GetTextureCode(Instruction instr, TextureType texture_type, | |||
| 552 | // LOD selection (either via bias or explicit textureLod) not supported in GL for | 550 | // LOD selection (either via bias or explicit textureLod) not supported in GL for |
| 553 | // sampler2DArrayShadow and samplerCubeArrayShadow. | 551 | // sampler2DArrayShadow and samplerCubeArrayShadow. |
| 554 | const bool gl_lod_supported = | 552 | const bool gl_lod_supported = |
| 555 | !((texture_type == Tegra::Shader::TextureType::Texture2D && is_array && depth_compare) || | 553 | !((texture_type == Tegra::Shader::TextureType::Texture2D && is_array && is_shadow) || |
| 556 | (texture_type == Tegra::Shader::TextureType::TextureCube && is_array && depth_compare)); | 554 | (texture_type == Tegra::Shader::TextureType::TextureCube && is_array && is_shadow)); |
| 557 | 555 | ||
| 558 | const OperationCode read_method = | 556 | const OperationCode read_method = |
| 559 | lod_needed && gl_lod_supported ? OperationCode::F4TextureLod : OperationCode::F4Texture; | 557 | lod_needed && gl_lod_supported ? OperationCode::TextureLod : OperationCode::Texture; |
| 560 | 558 | ||
| 561 | UNIMPLEMENTED_IF(process_mode != TextureProcessMode::None && !gl_lod_supported); | 559 | UNIMPLEMENTED_IF(process_mode != TextureProcessMode::None && !gl_lod_supported); |
| 562 | 560 | ||
| 563 | std::optional<u32> array_offset_value; | 561 | std::vector<Node> extras; |
| 564 | if (is_array) | ||
| 565 | array_offset_value = static_cast<u32>(array_offset); | ||
| 566 | |||
| 567 | const auto coords_count = static_cast<u32>(coords.size()); | ||
| 568 | |||
| 569 | if (process_mode != TextureProcessMode::None && gl_lod_supported) { | 562 | if (process_mode != TextureProcessMode::None && gl_lod_supported) { |
| 570 | if (process_mode == TextureProcessMode::LZ) { | 563 | if (process_mode == TextureProcessMode::LZ) { |
| 571 | coords.push_back(Immediate(0.0f)); | 564 | extras.push_back(Immediate(0.0f)); |
| 572 | } else { | 565 | } else { |
| 573 | // If present, lod or bias are always stored in the register indexed by the gpr20 | 566 | // If present, lod or bias are always stored in the register indexed by the gpr20 |
| 574 | // field with an offset depending on the usage of the other registers | 567 | // field with an offset depending on the usage of the other registers |
| 575 | coords.push_back(GetRegister(instr.gpr20.Value() + bias_offset)); | 568 | extras.push_back(GetRegister(instr.gpr20.Value() + bias_offset)); |
| 576 | } | 569 | } |
| 577 | } | 570 | } |
| 578 | 571 | ||
| 579 | Node4 values; | 572 | Node4 values; |
| 580 | for (u32 element = 0; element < values.size(); ++element) { | 573 | for (u32 element = 0; element < values.size(); ++element) { |
| 581 | auto params = coords; | 574 | auto copy_coords = coords; |
| 582 | MetaTexture meta{sampler, element, coords_count, array_offset_value}; | 575 | MetaTexture meta{sampler, array, depth_compare, extras, element}; |
| 583 | values[element] = Operation(read_method, std::move(meta), std::move(params)); | 576 | values[element] = Operation(read_method, meta, std::move(copy_coords)); |
| 584 | } | 577 | } |
| 585 | 578 | ||
| 586 | return values; | 579 | return values; |
| @@ -602,28 +595,22 @@ Node4 ShaderIR::GetTexCode(Instruction instr, TextureType texture_type, | |||
| 602 | for (std::size_t i = 0; i < coord_count; ++i) { | 595 | for (std::size_t i = 0; i < coord_count; ++i) { |
| 603 | coords.push_back(GetRegister(coord_register + i)); | 596 | coords.push_back(GetRegister(coord_register + i)); |
| 604 | } | 597 | } |
| 605 | // 1D.DC in opengl the 2nd component is ignored. | 598 | // 1D.DC in OpenGL the 2nd component is ignored. |
| 606 | if (depth_compare && !is_array && texture_type == TextureType::Texture1D) { | 599 | if (depth_compare && !is_array && texture_type == TextureType::Texture1D) { |
| 607 | coords.push_back(Immediate(0.0f)); | 600 | coords.push_back(Immediate(0.0f)); |
| 608 | } | 601 | } |
| 609 | std::size_t array_offset{}; | 602 | |
| 610 | if (is_array) { | 603 | const Node array = is_array ? GetRegister(array_register) : nullptr; |
| 611 | array_offset = coords.size(); | 604 | |
| 612 | coords.push_back(GetRegister(array_register)); | 605 | Node dc{}; |
| 613 | } | ||
| 614 | if (depth_compare) { | 606 | if (depth_compare) { |
| 615 | // Depth is always stored in the register signaled by gpr20 | 607 | // Depth is always stored in the register signaled by gpr20 or in the next register if lod |
| 616 | // or in the next register if lod or bias are used | 608 | // or bias are used |
| 617 | const u64 depth_register = instr.gpr20.Value() + (lod_bias_enabled ? 1 : 0); | 609 | const u64 depth_register = instr.gpr20.Value() + (lod_bias_enabled ? 1 : 0); |
| 618 | coords.push_back(GetRegister(depth_register)); | 610 | dc = GetRegister(depth_register); |
| 619 | } | ||
| 620 | // Fill ignored coordinates | ||
| 621 | while (coords.size() < total_coord_count) { | ||
| 622 | coords.push_back(Immediate(0)); | ||
| 623 | } | 611 | } |
| 624 | 612 | ||
| 625 | return GetTextureCode(instr, texture_type, process_mode, depth_compare, is_array, array_offset, | 613 | return GetTextureCode(instr, texture_type, process_mode, coords, array, dc, 0); |
| 626 | 0, std::move(coords)); | ||
| 627 | } | 614 | } |
| 628 | 615 | ||
| 629 | Node4 ShaderIR::GetTexsCode(Instruction instr, TextureType texture_type, | 616 | Node4 ShaderIR::GetTexsCode(Instruction instr, TextureType texture_type, |
| @@ -641,6 +628,7 @@ Node4 ShaderIR::GetTexsCode(Instruction instr, TextureType texture_type, | |||
| 641 | (is_array || !(lod_bias_enabled || depth_compare) || (coord_count > 2)) | 628 | (is_array || !(lod_bias_enabled || depth_compare) || (coord_count > 2)) |
| 642 | ? static_cast<u64>(instr.gpr20.Value()) | 629 | ? static_cast<u64>(instr.gpr20.Value()) |
| 643 | : coord_register + 1; | 630 | : coord_register + 1; |
| 631 | const u32 bias_offset = coord_count > 2 ? 1 : 0; | ||
| 644 | 632 | ||
| 645 | std::vector<Node> coords; | 633 | std::vector<Node> coords; |
| 646 | for (std::size_t i = 0; i < coord_count; ++i) { | 634 | for (std::size_t i = 0; i < coord_count; ++i) { |
| @@ -648,24 +636,17 @@ Node4 ShaderIR::GetTexsCode(Instruction instr, TextureType texture_type, | |||
| 648 | coords.push_back(GetRegister(last ? last_coord_register : coord_register + i)); | 636 | coords.push_back(GetRegister(last ? last_coord_register : coord_register + i)); |
| 649 | } | 637 | } |
| 650 | 638 | ||
| 651 | std::size_t array_offset{}; | 639 | const Node array = is_array ? GetRegister(array_register) : nullptr; |
| 652 | if (is_array) { | 640 | |
| 653 | array_offset = coords.size(); | 641 | Node dc{}; |
| 654 | coords.push_back(GetRegister(array_register)); | ||
| 655 | } | ||
| 656 | if (depth_compare) { | 642 | if (depth_compare) { |
| 657 | // Depth is always stored in the register signaled by gpr20 | 643 | // Depth is always stored in the register signaled by gpr20 or in the next register if lod |
| 658 | // or in the next register if lod or bias are used | 644 | // or bias are used |
| 659 | const u64 depth_register = instr.gpr20.Value() + (lod_bias_enabled ? 1 : 0); | 645 | const u64 depth_register = instr.gpr20.Value() + (lod_bias_enabled ? 1 : 0); |
| 660 | coords.push_back(GetRegister(depth_register)); | 646 | dc = GetRegister(depth_register); |
| 661 | } | ||
| 662 | // Fill ignored coordinates | ||
| 663 | while (coords.size() < total_coord_count) { | ||
| 664 | coords.push_back(Immediate(0)); | ||
| 665 | } | 647 | } |
| 666 | 648 | ||
| 667 | return GetTextureCode(instr, texture_type, process_mode, depth_compare, is_array, array_offset, | 649 | return GetTextureCode(instr, texture_type, process_mode, coords, array, dc, bias_offset); |
| 668 | (coord_count > 2 ? 1 : 0), std::move(coords)); | ||
| 669 | } | 650 | } |
| 670 | 651 | ||
| 671 | Node4 ShaderIR::GetTld4Code(Instruction instr, TextureType texture_type, bool depth_compare, | 652 | Node4 ShaderIR::GetTld4Code(Instruction instr, TextureType texture_type, bool depth_compare, |
| @@ -680,24 +661,16 @@ Node4 ShaderIR::GetTld4Code(Instruction instr, TextureType texture_type, bool de | |||
| 680 | const u64 coord_register = array_register + (is_array ? 1 : 0); | 661 | const u64 coord_register = array_register + (is_array ? 1 : 0); |
| 681 | 662 | ||
| 682 | std::vector<Node> coords; | 663 | std::vector<Node> coords; |
| 683 | 664 | for (size_t i = 0; i < coord_count; ++i) | |
| 684 | for (size_t i = 0; i < coord_count; ++i) { | ||
| 685 | coords.push_back(GetRegister(coord_register + i)); | 665 | coords.push_back(GetRegister(coord_register + i)); |
| 686 | } | ||
| 687 | std::optional<u32> array_offset; | ||
| 688 | if (is_array) { | ||
| 689 | array_offset = static_cast<u32>(coords.size()); | ||
| 690 | coords.push_back(GetRegister(array_register)); | ||
| 691 | } | ||
| 692 | 666 | ||
| 693 | const auto& sampler = GetSampler(instr.sampler, texture_type, is_array, depth_compare); | 667 | const auto& sampler = GetSampler(instr.sampler, texture_type, is_array, depth_compare); |
| 694 | 668 | ||
| 695 | Node4 values; | 669 | Node4 values; |
| 696 | for (u32 element = 0; element < values.size(); ++element) { | 670 | for (u32 element = 0; element < values.size(); ++element) { |
| 697 | auto params = coords; | 671 | auto coords_copy = coords; |
| 698 | MetaTexture meta{sampler, element, static_cast<u32>(coords.size()), array_offset}; | 672 | MetaTexture meta{sampler, GetRegister(array_register), {}, {}, element}; |
| 699 | values[element] = | 673 | values[element] = Operation(OperationCode::TextureGather, meta, std::move(coords_copy)); |
| 700 | Operation(OperationCode::F4TextureGather, std::move(meta), std::move(params)); | ||
| 701 | } | 674 | } |
| 702 | 675 | ||
| 703 | return values; | 676 | return values; |
| @@ -705,7 +678,6 @@ Node4 ShaderIR::GetTld4Code(Instruction instr, TextureType texture_type, bool de | |||
| 705 | 678 | ||
| 706 | Node4 ShaderIR::GetTldsCode(Instruction instr, TextureType texture_type, bool is_array) { | 679 | Node4 ShaderIR::GetTldsCode(Instruction instr, TextureType texture_type, bool is_array) { |
| 707 | const std::size_t type_coord_count = GetCoordCount(texture_type); | 680 | const std::size_t type_coord_count = GetCoordCount(texture_type); |
| 708 | const std::size_t total_coord_count = type_coord_count + (is_array ? 1 : 0); | ||
| 709 | const bool lod_enabled = instr.tlds.GetTextureProcessMode() == TextureProcessMode::LL; | 681 | const bool lod_enabled = instr.tlds.GetTextureProcessMode() == TextureProcessMode::LL; |
| 710 | 682 | ||
| 711 | // If enabled arrays index is always stored in the gpr8 field | 683 | // If enabled arrays index is always stored in the gpr8 field |
| @@ -719,33 +691,22 @@ Node4 ShaderIR::GetTldsCode(Instruction instr, TextureType texture_type, bool is | |||
| 719 | : coord_register + 1; | 691 | : coord_register + 1; |
| 720 | 692 | ||
| 721 | std::vector<Node> coords; | 693 | std::vector<Node> coords; |
| 722 | |||
| 723 | for (std::size_t i = 0; i < type_coord_count; ++i) { | 694 | for (std::size_t i = 0; i < type_coord_count; ++i) { |
| 724 | const bool last = (i == (type_coord_count - 1)) && (type_coord_count > 1); | 695 | const bool last = (i == (type_coord_count - 1)) && (type_coord_count > 1); |
| 725 | coords.push_back(GetRegister(last ? last_coord_register : coord_register + i)); | 696 | coords.push_back(GetRegister(last ? last_coord_register : coord_register + i)); |
| 726 | } | 697 | } |
| 727 | std::optional<u32> array_offset; | ||
| 728 | if (is_array) { | ||
| 729 | array_offset = static_cast<u32>(coords.size()); | ||
| 730 | coords.push_back(GetRegister(array_register)); | ||
| 731 | } | ||
| 732 | const auto coords_count = static_cast<u32>(coords.size()); | ||
| 733 | 698 | ||
| 734 | if (lod_enabled) { | 699 | const Node array = is_array ? GetRegister(array_register) : nullptr; |
| 735 | // When lod is used always is in grp20 | 700 | // When lod is used always is in gpr20 |
| 736 | coords.push_back(GetRegister(instr.gpr20)); | 701 | const Node lod = lod_enabled ? GetRegister(instr.gpr20) : Immediate(0); |
| 737 | } else { | ||
| 738 | coords.push_back(Immediate(0)); | ||
| 739 | } | ||
| 740 | 702 | ||
| 741 | const auto& sampler = GetSampler(instr.sampler, texture_type, is_array, false); | 703 | const auto& sampler = GetSampler(instr.sampler, texture_type, is_array, false); |
| 742 | 704 | ||
| 743 | Node4 values; | 705 | Node4 values; |
| 744 | for (u32 element = 0; element < values.size(); ++element) { | 706 | for (u32 element = 0; element < values.size(); ++element) { |
| 745 | auto params = coords; | 707 | auto coords_copy = coords; |
| 746 | MetaTexture meta{sampler, element, coords_count, array_offset}; | 708 | MetaTexture meta{sampler, array, {}, {lod}, element}; |
| 747 | values[element] = | 709 | values[element] = Operation(OperationCode::TexelFetch, meta, std::move(coords_copy)); |
| 748 | Operation(OperationCode::F4TexelFetch, std::move(meta), std::move(params)); | ||
| 749 | } | 710 | } |
| 750 | return values; | 711 | return values; |
| 751 | } | 712 | } |
diff --git a/src/video_core/shader/shader_ir.h b/src/video_core/shader/shader_ir.h index 1d4fbef53..52c7f2c4e 100644 --- a/src/video_core/shader/shader_ir.h +++ b/src/video_core/shader/shader_ir.h | |||
| @@ -156,12 +156,12 @@ enum class OperationCode { | |||
| 156 | Logical2HNotEqual, /// (MetaHalfArithmetic, f16vec2 a, f16vec2) -> bool2 | 156 | Logical2HNotEqual, /// (MetaHalfArithmetic, f16vec2 a, f16vec2) -> bool2 |
| 157 | Logical2HGreaterEqual, /// (MetaHalfArithmetic, f16vec2 a, f16vec2) -> bool2 | 157 | Logical2HGreaterEqual, /// (MetaHalfArithmetic, f16vec2 a, f16vec2) -> bool2 |
| 158 | 158 | ||
| 159 | F4Texture, /// (MetaTexture, float[N] coords, float[M] params) -> float4 | 159 | Texture, /// (MetaTexture, float[N] coords) -> float4 |
| 160 | F4TextureLod, /// (MetaTexture, float[N] coords, float[M] params) -> float4 | 160 | TextureLod, /// (MetaTexture, float[N] coords) -> float4 |
| 161 | F4TextureGather, /// (MetaTexture, float[N] coords, float[M] params) -> float4 | 161 | TextureGather, /// (MetaTexture, float[N] coords) -> float4 |
| 162 | F4TextureQueryDimensions, /// (MetaTexture, float a) -> float4 | 162 | TextureQueryDimensions, /// (MetaTexture, float a) -> float4 |
| 163 | F4TextureQueryLod, /// (MetaTexture, float[N] coords) -> float4 | 163 | TextureQueryLod, /// (MetaTexture, float[N] coords) -> float4 |
| 164 | F4TexelFetch, /// (MetaTexture, int[N], int) -> float4 | 164 | TexelFetch, /// (MetaTexture, int[N], int) -> float4 |
| 165 | 165 | ||
| 166 | Branch, /// (uint branch_target) -> void | 166 | Branch, /// (uint branch_target) -> void |
| 167 | PushFlowStack, /// (uint branch_target) -> void | 167 | PushFlowStack, /// (uint branch_target) -> void |
| @@ -288,9 +288,10 @@ struct MetaHalfArithmetic { | |||
| 288 | 288 | ||
| 289 | struct MetaTexture { | 289 | struct MetaTexture { |
| 290 | const Sampler& sampler; | 290 | const Sampler& sampler; |
| 291 | Node array{}; | ||
| 292 | Node depth_compare{}; | ||
| 293 | std::vector<Node> extras; | ||
| 291 | u32 element{}; | 294 | u32 element{}; |
| 292 | u32 coords_count{}; | ||
| 293 | std::optional<u32> array_index; | ||
| 294 | }; | 295 | }; |
| 295 | 296 | ||
| 296 | constexpr MetaArithmetic PRECISE = {true}; | 297 | constexpr MetaArithmetic PRECISE = {true}; |
| @@ -754,9 +755,8 @@ private: | |||
| 754 | bool lod_bias_enabled, std::size_t max_coords, std::size_t max_inputs); | 755 | bool lod_bias_enabled, std::size_t max_coords, std::size_t max_inputs); |
| 755 | 756 | ||
| 756 | Node4 GetTextureCode(Tegra::Shader::Instruction instr, Tegra::Shader::TextureType texture_type, | 757 | Node4 GetTextureCode(Tegra::Shader::Instruction instr, Tegra::Shader::TextureType texture_type, |
| 757 | Tegra::Shader::TextureProcessMode process_mode, bool depth_compare, | 758 | Tegra::Shader::TextureProcessMode process_mode, std::vector<Node> coords, |
| 758 | bool is_array, std::size_t array_offset, std::size_t bias_offset, | 759 | Node array, Node depth_compare, u32 bias_offset); |
| 759 | std::vector<Node>&& coords); | ||
| 760 | 760 | ||
| 761 | Node GetVideoOperand(Node op, bool is_chunk, bool is_signed, Tegra::Shader::VideoType type, | 761 | Node GetVideoOperand(Node op, bool is_chunk, bool is_signed, Tegra::Shader::VideoType type, |
| 762 | u64 byte_height); | 762 | u64 byte_height); |
diff --git a/src/video_core/surface.cpp b/src/video_core/surface.cpp index 2f6612a35..044ba116a 100644 --- a/src/video_core/surface.cpp +++ b/src/video_core/surface.cpp | |||
| @@ -426,6 +426,8 @@ PixelFormat PixelFormatFromGPUPixelFormat(Tegra::FramebufferConfig::PixelFormat | |||
| 426 | switch (format) { | 426 | switch (format) { |
| 427 | case Tegra::FramebufferConfig::PixelFormat::ABGR8: | 427 | case Tegra::FramebufferConfig::PixelFormat::ABGR8: |
| 428 | return PixelFormat::ABGR8U; | 428 | return PixelFormat::ABGR8U; |
| 429 | case Tegra::FramebufferConfig::PixelFormat::BGRA8: | ||
| 430 | return PixelFormat::BGRA8; | ||
| 429 | default: | 431 | default: |
| 430 | LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format)); | 432 | LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format)); |
| 431 | UNREACHABLE(); | 433 | UNREACHABLE(); |