summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/audio_core/renderer/command/resample/upsample.cpp97
-rw-r--r--src/common/settings.cpp12
-rw-r--r--src/common/settings.h13
-rw-r--r--src/core/core_timing.cpp42
-rw-r--r--src/core/core_timing.h9
-rw-r--r--src/core/hle/kernel/k_hardware_timer.cpp6
-rw-r--r--src/core/hle/service/nvflinger/nvflinger.cpp8
-rw-r--r--src/core/hle/service/nvflinger/nvflinger.h2
-rw-r--r--src/core/memory.cpp4
-rw-r--r--src/input_common/drivers/sdl_driver.cpp54
-rw-r--r--src/video_core/CMakeLists.txt2
-rw-r--r--src/video_core/engines/draw_manager.cpp31
-rw-r--r--src/video_core/engines/draw_manager.h20
-rw-r--r--src/video_core/engines/maxwell_3d.cpp3
-rw-r--r--src/video_core/engines/maxwell_3d.h16
-rw-r--r--src/video_core/host_shaders/CMakeLists.txt2
-rw-r--r--src/video_core/host_shaders/blit_color_float.frag (renamed from src/video_core/host_shaders/vulkan_blit_color_float.frag)0
-rw-r--r--src/video_core/host_shaders/full_screen_triangle.vert13
-rw-r--r--src/video_core/rasterizer_interface.h3
-rw-r--r--src/video_core/renderer_null/null_rasterizer.cpp1
-rw-r--r--src/video_core/renderer_null/null_rasterizer.h1
-rw-r--r--src/video_core/renderer_opengl/blit_image.cpp59
-rw-r--r--src/video_core/renderer_opengl/blit_image.h38
-rw-r--r--src/video_core/renderer_opengl/gl_device.cpp1
-rw-r--r--src/video_core/renderer_opengl/gl_device.h7
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp44
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.h4
-rw-r--r--src/video_core/renderer_opengl/gl_shader_manager.cpp121
-rw-r--r--src/video_core/renderer_opengl/gl_shader_manager.h129
-rw-r--r--src/video_core/renderer_vulkan/blit_image.cpp88
-rw-r--r--src/video_core/renderer_vulkan/blit_image.h6
-rw-r--r--src/video_core/renderer_vulkan/vk_rasterizer.cpp29
-rw-r--r--src/video_core/renderer_vulkan/vk_rasterizer.h1
-rw-r--r--src/video_core/texture_cache/texture_cache.h7
-rw-r--r--src/video_core/texture_cache/texture_cache_base.h3
-rw-r--r--src/yuzu/configuration/configure_graphics.ui15
36 files changed, 648 insertions, 243 deletions
diff --git a/src/audio_core/renderer/command/resample/upsample.cpp b/src/audio_core/renderer/command/resample/upsample.cpp
index 6c3ff31f7..5f7db12ca 100644
--- a/src/audio_core/renderer/command/resample/upsample.cpp
+++ b/src/audio_core/renderer/command/resample/upsample.cpp
@@ -20,25 +20,25 @@ static void SrcProcessFrame(std::span<s32> output, std::span<const s32> input,
20 const u32 target_sample_count, const u32 source_sample_count, 20 const u32 target_sample_count, const u32 source_sample_count,
21 UpsamplerState* state) { 21 UpsamplerState* state) {
22 constexpr u32 WindowSize = 10; 22 constexpr u32 WindowSize = 10;
23 constexpr std::array<Common::FixedPoint<24, 8>, WindowSize> SincWindow1{ 23 constexpr std::array<Common::FixedPoint<17, 15>, WindowSize> WindowedSinc1{
24 51.93359375f, -18.80078125f, 9.73046875f, -5.33203125f, 2.84375f, 24 0.95376587f, -0.12872314f, 0.060028076f, -0.032470703f, 0.017669678f,
25 -1.41015625f, 0.62109375f, -0.2265625f, 0.0625f, -0.00390625f, 25 -0.009124756f, 0.004272461f, -0.001739502f, 0.000579834f, -0.000091552734f,
26 }; 26 };
27 constexpr std::array<Common::FixedPoint<24, 8>, WindowSize> SincWindow2{ 27 constexpr std::array<Common::FixedPoint<17, 15>, WindowSize> WindowedSinc2{
28 105.35546875f, -24.52734375f, 11.9609375f, -6.515625f, 3.52734375f, 28 0.8230896f, -0.19161987f, 0.093444824f, -0.05090332f, 0.027557373f,
29 -1.796875f, 0.828125f, -0.32421875f, 0.1015625f, -0.015625f, 29 -0.014038086f, 0.0064697266f, -0.002532959f, 0.00079345703f, -0.00012207031f,
30 }; 30 };
31 constexpr std::array<Common::FixedPoint<24, 8>, WindowSize> SincWindow3{ 31 constexpr std::array<Common::FixedPoint<17, 15>, WindowSize> WindowedSinc3{
32 122.08203125f, -16.47656250f, 7.68359375f, -4.15625000f, 2.26171875f, 32 0.6298828f, -0.19274902f, 0.09725952f, -0.05319214f, 0.028625488f,
33 -1.16796875f, 0.54687500f, -0.22265625f, 0.07421875f, -0.01171875f, 33 -0.014373779f, 0.006500244f, -0.0024719238f, 0.0007324219f, -0.000091552734f,
34 }; 34 };
35 constexpr std::array<Common::FixedPoint<24, 8>, WindowSize> SincWindow4{ 35 constexpr std::array<Common::FixedPoint<17, 15>, WindowSize> WindowedSinc4{
36 23.73437500f, -9.62109375f, 5.07812500f, -2.78125000f, 1.46875000f, 36 0.4057312f, -0.1468811f, 0.07601929f, -0.041656494f, 0.022216797f,
37 -0.71484375f, 0.30859375f, -0.10546875f, 0.02734375f, 0.00000000f, 37 -0.011016846f, 0.004852295f, -0.0017700195f, 0.00048828125f, -0.000030517578f,
38 }; 38 };
39 constexpr std::array<Common::FixedPoint<24, 8>, WindowSize> SincWindow5{ 39 constexpr std::array<Common::FixedPoint<17, 15>, WindowSize> WindowedSinc5{
40 80.62500000f, -24.67187500f, 12.44921875f, -6.80859375f, 3.66406250f, 40 0.1854248f, -0.075164795f, 0.03967285f, -0.021728516f, 0.011474609f,
41 -1.83984375f, 0.83203125f, -0.31640625f, 0.09375000f, -0.01171875f, 41 -0.005584717f, 0.0024108887f, -0.0008239746f, 0.00021362305f, 0.0f,
42 }; 42 };
43 43
44 if (!state->initialized) { 44 if (!state->initialized) {
@@ -91,52 +91,31 @@ static void SrcProcessFrame(std::span<s32> output, std::span<const s32> input,
91 static_cast<u16>((state->history_output_index + 1) % UpsamplerState::HistorySize); 91 static_cast<u16>((state->history_output_index + 1) % UpsamplerState::HistorySize);
92 }; 92 };
93 93
94 auto calculate_sample = [&state](std::span<const Common::FixedPoint<24, 8>> coeffs1, 94 auto calculate_sample = [&state](std::span<const Common::FixedPoint<17, 15>> coeffs1,
95 std::span<const Common::FixedPoint<24, 8>> coeffs2) -> s32 { 95 std::span<const Common::FixedPoint<17, 15>> coeffs2) -> s32 {
96 auto output_index{state->history_output_index}; 96 auto output_index{state->history_output_index};
97 auto start_pos{output_index - state->history_start_index + 1U}; 97 u64 result{0};
98 auto end_pos{10U};
99 98
100 if (start_pos < 10) { 99 for (u32 coeff_index = 0; coeff_index < 10; coeff_index++) {
101 end_pos = start_pos; 100 result += static_cast<u64>(state->history[output_index].to_raw()) *
102 } 101 coeffs1[coeff_index].to_raw();
103
104 u64 prev_contrib{0};
105 u32 coeff_index{0};
106 for (; coeff_index < end_pos; coeff_index++, output_index--) {
107 prev_contrib += static_cast<u64>(state->history[output_index].to_raw()) *
108 coeffs1[coeff_index].to_raw();
109 }
110 102
111 auto end_index{state->history_end_index}; 103 output_index = output_index == state->history_start_index ? state->history_end_index
112 for (; start_pos < 9; start_pos++, coeff_index++, end_index--) { 104 : output_index - 1;
113 prev_contrib += static_cast<u64>(state->history[end_index].to_raw()) *
114 coeffs1[coeff_index].to_raw();
115 } 105 }
116 106
117 output_index = 107 output_index =
118 static_cast<u16>((state->history_output_index + 1) % UpsamplerState::HistorySize); 108 static_cast<u16>((state->history_output_index + 1) % UpsamplerState::HistorySize);
119 start_pos = state->history_end_index - output_index + 1U;
120 end_pos = 10U;
121 109
122 if (start_pos < 10) { 110 for (u32 coeff_index = 0; coeff_index < 10; coeff_index++) {
123 end_pos = start_pos; 111 result += static_cast<u64>(state->history[output_index].to_raw()) *
124 } 112 coeffs2[coeff_index].to_raw();
125
126 u64 next_contrib{0};
127 coeff_index = 0;
128 for (; coeff_index < end_pos; coeff_index++, output_index++) {
129 next_contrib += static_cast<u64>(state->history[output_index].to_raw()) *
130 coeffs2[coeff_index].to_raw();
131 }
132 113
133 auto start_index{state->history_start_index}; 114 output_index = output_index == state->history_end_index ? state->history_start_index
134 for (; start_pos < 9; start_pos++, start_index++, coeff_index++) { 115 : output_index + 1;
135 next_contrib += static_cast<u64>(state->history[start_index].to_raw()) *
136 coeffs2[coeff_index].to_raw();
137 } 116 }
138 117
139 return static_cast<s32>(((prev_contrib >> 15) + (next_contrib >> 15)) >> 8); 118 return static_cast<s32>(result >> (8 + 15));
140 }; 119 };
141 120
142 switch (state->ratio.to_int_floor()) { 121 switch (state->ratio.to_int_floor()) {
@@ -150,23 +129,23 @@ static void SrcProcessFrame(std::span<s32> output, std::span<const s32> input,
150 break; 129 break;
151 130
152 case 1: 131 case 1:
153 output[write_index] = calculate_sample(SincWindow3, SincWindow4); 132 output[write_index] = calculate_sample(WindowedSinc1, WindowedSinc5);
154 break; 133 break;
155 134
156 case 2: 135 case 2:
157 output[write_index] = calculate_sample(SincWindow2, SincWindow1); 136 output[write_index] = calculate_sample(WindowedSinc2, WindowedSinc4);
158 break; 137 break;
159 138
160 case 3: 139 case 3:
161 output[write_index] = calculate_sample(SincWindow5, SincWindow5); 140 output[write_index] = calculate_sample(WindowedSinc3, WindowedSinc3);
162 break; 141 break;
163 142
164 case 4: 143 case 4:
165 output[write_index] = calculate_sample(SincWindow1, SincWindow2); 144 output[write_index] = calculate_sample(WindowedSinc4, WindowedSinc2);
166 break; 145 break;
167 146
168 case 5: 147 case 5:
169 output[write_index] = calculate_sample(SincWindow4, SincWindow3); 148 output[write_index] = calculate_sample(WindowedSinc5, WindowedSinc1);
170 break; 149 break;
171 } 150 }
172 state->sample_index = static_cast<u8>((state->sample_index + 1) % 6); 151 state->sample_index = static_cast<u8>((state->sample_index + 1) % 6);
@@ -183,11 +162,11 @@ static void SrcProcessFrame(std::span<s32> output, std::span<const s32> input,
183 break; 162 break;
184 163
185 case 1: 164 case 1:
186 output[write_index] = calculate_sample(SincWindow2, SincWindow1); 165 output[write_index] = calculate_sample(WindowedSinc2, WindowedSinc4);
187 break; 166 break;
188 167
189 case 2: 168 case 2:
190 output[write_index] = calculate_sample(SincWindow1, SincWindow2); 169 output[write_index] = calculate_sample(WindowedSinc4, WindowedSinc2);
191 break; 170 break;
192 } 171 }
193 state->sample_index = static_cast<u8>((state->sample_index + 1) % 3); 172 state->sample_index = static_cast<u8>((state->sample_index + 1) % 3);
@@ -204,12 +183,12 @@ static void SrcProcessFrame(std::span<s32> output, std::span<const s32> input,
204 break; 183 break;
205 184
206 case 1: 185 case 1:
207 output[write_index] = calculate_sample(SincWindow1, SincWindow2); 186 output[write_index] = calculate_sample(WindowedSinc4, WindowedSinc2);
208 break; 187 break;
209 188
210 case 2: 189 case 2:
211 increment(); 190 increment();
212 output[write_index] = calculate_sample(SincWindow2, SincWindow1); 191 output[write_index] = calculate_sample(WindowedSinc2, WindowedSinc4);
213 break; 192 break;
214 } 193 }
215 state->sample_index = static_cast<u8>((state->sample_index + 1) % 3); 194 state->sample_index = static_cast<u8>((state->sample_index + 1) % 3);
diff --git a/src/common/settings.cpp b/src/common/settings.cpp
index 1638b79f5..b1a2aa8b2 100644
--- a/src/common/settings.cpp
+++ b/src/common/settings.cpp
@@ -129,6 +129,10 @@ void UpdateRescalingInfo() {
129 info.up_scale = 1; 129 info.up_scale = 1;
130 info.down_shift = 0; 130 info.down_shift = 0;
131 break; 131 break;
132 case ResolutionSetup::Res3_2X:
133 info.up_scale = 3;
134 info.down_shift = 1;
135 break;
132 case ResolutionSetup::Res2X: 136 case ResolutionSetup::Res2X:
133 info.up_scale = 2; 137 info.up_scale = 2;
134 info.down_shift = 0; 138 info.down_shift = 0;
@@ -149,6 +153,14 @@ void UpdateRescalingInfo() {
149 info.up_scale = 6; 153 info.up_scale = 6;
150 info.down_shift = 0; 154 info.down_shift = 0;
151 break; 155 break;
156 case ResolutionSetup::Res7X:
157 info.up_scale = 7;
158 info.down_shift = 0;
159 break;
160 case ResolutionSetup::Res8X:
161 info.up_scale = 8;
162 info.down_shift = 0;
163 break;
152 default: 164 default:
153 ASSERT(false); 165 ASSERT(false);
154 info.up_scale = 1; 166 info.up_scale = 1;
diff --git a/src/common/settings.h b/src/common/settings.h
index a457e3f23..80b2eeabc 100644
--- a/src/common/settings.h
+++ b/src/common/settings.h
@@ -56,11 +56,14 @@ enum class ResolutionSetup : u32 {
56 Res1_2X = 0, 56 Res1_2X = 0,
57 Res3_4X = 1, 57 Res3_4X = 1,
58 Res1X = 2, 58 Res1X = 2,
59 Res2X = 3, 59 Res3_2X = 3,
60 Res3X = 4, 60 Res2X = 4,
61 Res4X = 5, 61 Res3X = 5,
62 Res5X = 6, 62 Res4X = 6,
63 Res6X = 7, 63 Res5X = 7,
64 Res6X = 8,
65 Res7X = 9,
66 Res8X = 10,
64}; 67};
65 68
66enum class ScalingFilter : u32 { 69enum class ScalingFilter : u32 {
diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp
index 0e7b5f943..6bac6722f 100644
--- a/src/core/core_timing.cpp
+++ b/src/core/core_timing.cpp
@@ -142,16 +142,24 @@ void CoreTiming::ScheduleLoopingEvent(std::chrono::nanoseconds start_time,
142} 142}
143 143
144void CoreTiming::UnscheduleEvent(const std::shared_ptr<EventType>& event_type, 144void CoreTiming::UnscheduleEvent(const std::shared_ptr<EventType>& event_type,
145 std::uintptr_t user_data) { 145 std::uintptr_t user_data, bool wait) {
146 std::scoped_lock scope{basic_lock}; 146 {
147 const auto itr = std::remove_if(event_queue.begin(), event_queue.end(), [&](const Event& e) { 147 std::scoped_lock lk{basic_lock};
148 return e.type.lock().get() == event_type.get() && e.user_data == user_data; 148 const auto itr =
149 }); 149 std::remove_if(event_queue.begin(), event_queue.end(), [&](const Event& e) {
150 150 return e.type.lock().get() == event_type.get() && e.user_data == user_data;
151 // Removing random items breaks the invariant so we have to re-establish it. 151 });
152 if (itr != event_queue.end()) { 152
153 event_queue.erase(itr, event_queue.end()); 153 // Removing random items breaks the invariant so we have to re-establish it.
154 std::make_heap(event_queue.begin(), event_queue.end(), std::greater<>()); 154 if (itr != event_queue.end()) {
155 event_queue.erase(itr, event_queue.end());
156 std::make_heap(event_queue.begin(), event_queue.end(), std::greater<>());
157 }
158 }
159
160 // Force any in-progress events to finish
161 if (wait) {
162 std::scoped_lock lk{advance_lock};
155 } 163 }
156} 164}
157 165
@@ -190,20 +198,6 @@ u64 CoreTiming::GetClockTicks() const {
190 return CpuCyclesToClockCycles(ticks); 198 return CpuCyclesToClockCycles(ticks);
191} 199}
192 200
193void CoreTiming::RemoveEvent(const std::shared_ptr<EventType>& event_type) {
194 std::scoped_lock lock{basic_lock};
195
196 const auto itr = std::remove_if(event_queue.begin(), event_queue.end(), [&](const Event& e) {
197 return e.type.lock().get() == event_type.get();
198 });
199
200 // Removing random items breaks the invariant so we have to re-establish it.
201 if (itr != event_queue.end()) {
202 event_queue.erase(itr, event_queue.end());
203 std::make_heap(event_queue.begin(), event_queue.end(), std::greater<>());
204 }
205}
206
207std::optional<s64> CoreTiming::Advance() { 201std::optional<s64> CoreTiming::Advance() {
208 std::scoped_lock lock{advance_lock, basic_lock}; 202 std::scoped_lock lock{advance_lock, basic_lock};
209 global_timer = GetGlobalTimeNs().count(); 203 global_timer = GetGlobalTimeNs().count();
diff --git a/src/core/core_timing.h b/src/core/core_timing.h
index b5925193c..da366637b 100644
--- a/src/core/core_timing.h
+++ b/src/core/core_timing.h
@@ -98,10 +98,13 @@ public:
98 const std::shared_ptr<EventType>& event_type, 98 const std::shared_ptr<EventType>& event_type,
99 std::uintptr_t user_data = 0, bool absolute_time = false); 99 std::uintptr_t user_data = 0, bool absolute_time = false);
100 100
101 void UnscheduleEvent(const std::shared_ptr<EventType>& event_type, std::uintptr_t user_data); 101 void UnscheduleEvent(const std::shared_ptr<EventType>& event_type, std::uintptr_t user_data,
102 bool wait = true);
102 103
103 /// We only permit one event of each type in the queue at a time. 104 void UnscheduleEventWithoutWait(const std::shared_ptr<EventType>& event_type,
104 void RemoveEvent(const std::shared_ptr<EventType>& event_type); 105 std::uintptr_t user_data) {
106 UnscheduleEvent(event_type, user_data, false);
107 }
105 108
106 void AddTicks(u64 ticks_to_add); 109 void AddTicks(u64 ticks_to_add);
107 110
diff --git a/src/core/hle/kernel/k_hardware_timer.cpp b/src/core/hle/kernel/k_hardware_timer.cpp
index 6bba79ea0..4dcd53821 100644
--- a/src/core/hle/kernel/k_hardware_timer.cpp
+++ b/src/core/hle/kernel/k_hardware_timer.cpp
@@ -18,7 +18,8 @@ void KHardwareTimer::Initialize() {
18} 18}
19 19
20void KHardwareTimer::Finalize() { 20void KHardwareTimer::Finalize() {
21 this->DisableInterrupt(); 21 m_kernel.System().CoreTiming().UnscheduleEvent(m_event_type, reinterpret_cast<uintptr_t>(this));
22 m_wakeup_time = std::numeric_limits<s64>::max();
22 m_event_type.reset(); 23 m_event_type.reset();
23} 24}
24 25
@@ -59,7 +60,8 @@ void KHardwareTimer::EnableInterrupt(s64 wakeup_time) {
59} 60}
60 61
61void KHardwareTimer::DisableInterrupt() { 62void KHardwareTimer::DisableInterrupt() {
62 m_kernel.System().CoreTiming().UnscheduleEvent(m_event_type, reinterpret_cast<uintptr_t>(this)); 63 m_kernel.System().CoreTiming().UnscheduleEventWithoutWait(m_event_type,
64 reinterpret_cast<uintptr_t>(this));
63 m_wakeup_time = std::numeric_limits<s64>::max(); 65 m_wakeup_time = std::numeric_limits<s64>::max();
64} 66}
65 67
diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp
index d1cbadde4..f4416f5b2 100644
--- a/src/core/hle/service/nvflinger/nvflinger.cpp
+++ b/src/core/hle/service/nvflinger/nvflinger.cpp
@@ -312,8 +312,6 @@ void NVFlinger::Compose() {
312} 312}
313 313
314s64 NVFlinger::GetNextTicks() const { 314s64 NVFlinger::GetNextTicks() const {
315 static constexpr s64 max_hertz = 120LL;
316
317 const auto& settings = Settings::values; 315 const auto& settings = Settings::values;
318 auto speed_scale = 1.f; 316 auto speed_scale = 1.f;
319 if (settings.use_multi_core.GetValue()) { 317 if (settings.use_multi_core.GetValue()) {
@@ -327,9 +325,11 @@ s64 NVFlinger::GetNextTicks() const {
327 } 325 }
328 } 326 }
329 327
330 const auto next_ticks = ((1000000000 * (1LL << swap_interval)) / max_hertz); 328 // As an extension, treat nonpositive swap interval as framerate multiplier.
329 const f32 effective_fps = swap_interval <= 0 ? 120.f * static_cast<f32>(1 - swap_interval)
330 : 60.f / static_cast<f32>(swap_interval);
331 331
332 return static_cast<s64>(speed_scale * static_cast<float>(next_ticks)); 332 return static_cast<s64>(speed_scale * (1000000000.f / effective_fps));
333} 333}
334 334
335} // namespace Service::NVFlinger 335} // namespace Service::NVFlinger
diff --git a/src/core/hle/service/nvflinger/nvflinger.h b/src/core/hle/service/nvflinger/nvflinger.h
index 9b22397db..3828cf272 100644
--- a/src/core/hle/service/nvflinger/nvflinger.h
+++ b/src/core/hle/service/nvflinger/nvflinger.h
@@ -133,7 +133,7 @@ private:
133 /// layers. 133 /// layers.
134 u32 next_buffer_queue_id = 1; 134 u32 next_buffer_queue_id = 1;
135 135
136 u32 swap_interval = 1; 136 s32 swap_interval = 1;
137 137
138 /// Event that handles screen composition. 138 /// Event that handles screen composition.
139 std::shared_ptr<Core::Timing::EventType> multi_composition_event; 139 std::shared_ptr<Core::Timing::EventType> multi_composition_event;
diff --git a/src/core/memory.cpp b/src/core/memory.cpp
index a1e41faff..4e605fae4 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -383,6 +383,10 @@ struct Memory::Impl {
383 return; 383 return;
384 } 384 }
385 385
386 if (Settings::IsFastmemEnabled()) {
387 system.DeviceMemory().buffer.Protect(vaddr, size, !debug, !debug);
388 }
389
386 // Iterate over a contiguous CPU address space, marking/unmarking the region. 390 // Iterate over a contiguous CPU address space, marking/unmarking the region.
387 // The region is at a granularity of CPU pages. 391 // The region is at a granularity of CPU pages.
388 392
diff --git a/src/input_common/drivers/sdl_driver.cpp b/src/input_common/drivers/sdl_driver.cpp
index 4818bb744..9835d99d2 100644
--- a/src/input_common/drivers/sdl_driver.cpp
+++ b/src/input_common/drivers/sdl_driver.cpp
@@ -40,25 +40,26 @@ public:
40 } 40 }
41 41
42 void EnableMotion() { 42 void EnableMotion() {
43 if (sdl_controller) { 43 if (!sdl_controller) {
44 SDL_GameController* controller = sdl_controller.get(); 44 return;
45 has_accel = SDL_GameControllerHasSensor(controller, SDL_SENSOR_ACCEL) == SDL_TRUE; 45 }
46 has_gyro = SDL_GameControllerHasSensor(controller, SDL_SENSOR_GYRO) == SDL_TRUE; 46 SDL_GameController* controller = sdl_controller.get();
47 if (has_accel) { 47 if (HasMotion()) {
48 SDL_GameControllerSetSensorEnabled(controller, SDL_SENSOR_ACCEL, SDL_TRUE); 48 SDL_GameControllerSetSensorEnabled(controller, SDL_SENSOR_ACCEL, SDL_FALSE);
49 } 49 SDL_GameControllerSetSensorEnabled(controller, SDL_SENSOR_GYRO, SDL_FALSE);
50 if (has_gyro) { 50 }
51 SDL_GameControllerSetSensorEnabled(controller, SDL_SENSOR_GYRO, SDL_TRUE); 51 has_accel = SDL_GameControllerHasSensor(controller, SDL_SENSOR_ACCEL) == SDL_TRUE;
52 } 52 has_gyro = SDL_GameControllerHasSensor(controller, SDL_SENSOR_GYRO) == SDL_TRUE;
53 if (has_accel) {
54 SDL_GameControllerSetSensorEnabled(controller, SDL_SENSOR_ACCEL, SDL_TRUE);
55 }
56 if (has_gyro) {
57 SDL_GameControllerSetSensorEnabled(controller, SDL_SENSOR_GYRO, SDL_TRUE);
53 } 58 }
54 } 59 }
55 60
56 bool HasGyro() const { 61 bool HasMotion() const {
57 return has_gyro; 62 return has_gyro || has_accel;
58 }
59
60 bool HasAccel() const {
61 return has_accel;
62 } 63 }
63 64
64 bool UpdateMotion(SDL_ControllerSensorEvent event) { 65 bool UpdateMotion(SDL_ControllerSensorEvent event) {
@@ -85,6 +86,20 @@ public:
85 if (time_difference == 0) { 86 if (time_difference == 0) {
86 return false; 87 return false;
87 } 88 }
89
90 // Motion data is invalid
91 if (motion.accel_x == 0 && motion.gyro_x == 0 && motion.accel_y == 0 &&
92 motion.gyro_y == 0 && motion.accel_z == 0 && motion.gyro_z == 0) {
93 if (motion_error_count++ < 200) {
94 return false;
95 }
96 // Try restarting the sensor
97 motion_error_count = 0;
98 EnableMotion();
99 return false;
100 }
101
102 motion_error_count = 0;
88 motion.delta_timestamp = time_difference * 1000; 103 motion.delta_timestamp = time_difference * 1000;
89 return true; 104 return true;
90 } 105 }
@@ -250,6 +265,7 @@ private:
250 mutable std::mutex mutex; 265 mutable std::mutex mutex;
251 266
252 u64 last_motion_update{}; 267 u64 last_motion_update{};
268 std::size_t motion_error_count{};
253 bool has_gyro{false}; 269 bool has_gyro{false};
254 bool has_accel{false}; 270 bool has_accel{false};
255 bool has_vibration{false}; 271 bool has_vibration{false};
@@ -942,18 +958,18 @@ MotionMapping SDLDriver::GetMotionMappingForDevice(const Common::ParamPackage& p
942 MotionMapping mapping = {}; 958 MotionMapping mapping = {};
943 joystick->EnableMotion(); 959 joystick->EnableMotion();
944 960
945 if (joystick->HasGyro() || joystick->HasAccel()) { 961 if (joystick->HasMotion()) {
946 mapping.insert_or_assign(Settings::NativeMotion::MotionRight, 962 mapping.insert_or_assign(Settings::NativeMotion::MotionRight,
947 BuildMotionParam(joystick->GetPort(), joystick->GetGUID())); 963 BuildMotionParam(joystick->GetPort(), joystick->GetGUID()));
948 } 964 }
949 if (params.Has("guid2")) { 965 if (params.Has("guid2")) {
950 joystick2->EnableMotion(); 966 joystick2->EnableMotion();
951 if (joystick2->HasGyro() || joystick2->HasAccel()) { 967 if (joystick2->HasMotion()) {
952 mapping.insert_or_assign(Settings::NativeMotion::MotionLeft, 968 mapping.insert_or_assign(Settings::NativeMotion::MotionLeft,
953 BuildMotionParam(joystick2->GetPort(), joystick2->GetGUID())); 969 BuildMotionParam(joystick2->GetPort(), joystick2->GetGUID()));
954 } 970 }
955 } else { 971 } else {
956 if (joystick->HasGyro() || joystick->HasAccel()) { 972 if (joystick->HasMotion()) {
957 mapping.insert_or_assign(Settings::NativeMotion::MotionLeft, 973 mapping.insert_or_assign(Settings::NativeMotion::MotionLeft,
958 BuildMotionParam(joystick->GetPort(), joystick->GetGUID())); 974 BuildMotionParam(joystick->GetPort(), joystick->GetGUID()));
959 } 975 }
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt
index f617665de..b474eb363 100644
--- a/src/video_core/CMakeLists.txt
+++ b/src/video_core/CMakeLists.txt
@@ -100,6 +100,8 @@ add_library(video_core STATIC
100 renderer_null/null_rasterizer.h 100 renderer_null/null_rasterizer.h
101 renderer_null/renderer_null.cpp 101 renderer_null/renderer_null.cpp
102 renderer_null/renderer_null.h 102 renderer_null/renderer_null.h
103 renderer_opengl/blit_image.cpp
104 renderer_opengl/blit_image.h
103 renderer_opengl/gl_buffer_cache.cpp 105 renderer_opengl/gl_buffer_cache.cpp
104 renderer_opengl/gl_buffer_cache.h 106 renderer_opengl/gl_buffer_cache.h
105 renderer_opengl/gl_compute_pipeline.cpp 107 renderer_opengl/gl_compute_pipeline.cpp
diff --git a/src/video_core/engines/draw_manager.cpp b/src/video_core/engines/draw_manager.cpp
index 2437121ce..1d22d25f1 100644
--- a/src/video_core/engines/draw_manager.cpp
+++ b/src/video_core/engines/draw_manager.cpp
@@ -51,6 +51,10 @@ void DrawManager::ProcessMethodCall(u32 method, u32 argument) {
51 LOG_WARNING(HW_GPU, "(STUBBED) called"); 51 LOG_WARNING(HW_GPU, "(STUBBED) called");
52 break; 52 break;
53 } 53 }
54 case MAXWELL3D_REG_INDEX(draw_texture.src_y0): {
55 DrawTexture();
56 break;
57 }
54 default: 58 default:
55 break; 59 break;
56 } 60 }
@@ -179,6 +183,33 @@ void DrawManager::DrawIndexSmall(u32 argument) {
179 ProcessDraw(true, 1); 183 ProcessDraw(true, 1);
180} 184}
181 185
186void DrawManager::DrawTexture() {
187 const auto& regs{maxwell3d->regs};
188 draw_texture_state.dst_x0 = static_cast<float>(regs.draw_texture.dst_x0) / 4096.f;
189 draw_texture_state.dst_y0 = static_cast<float>(regs.draw_texture.dst_y0) / 4096.f;
190 const auto dst_width = static_cast<float>(regs.draw_texture.dst_width) / 4096.f;
191 const auto dst_height = static_cast<float>(regs.draw_texture.dst_height) / 4096.f;
192 const bool lower_left{regs.window_origin.mode !=
193 Maxwell3D::Regs::WindowOrigin::Mode::UpperLeft};
194 if (lower_left) {
195 draw_texture_state.dst_y0 -= dst_height;
196 }
197 draw_texture_state.dst_x1 = draw_texture_state.dst_x0 + dst_width;
198 draw_texture_state.dst_y1 = draw_texture_state.dst_y0 + dst_height;
199 draw_texture_state.src_x0 = static_cast<float>(regs.draw_texture.src_x0) / 4096.f;
200 draw_texture_state.src_y0 = static_cast<float>(regs.draw_texture.src_y0) / 4096.f;
201 draw_texture_state.src_x1 =
202 (static_cast<float>(regs.draw_texture.dx_du) / 4294967296.f) * dst_width +
203 draw_texture_state.src_x0;
204 draw_texture_state.src_y1 =
205 (static_cast<float>(regs.draw_texture.dy_dv) / 4294967296.f) * dst_height +
206 draw_texture_state.src_y0;
207 draw_texture_state.src_sampler = regs.draw_texture.src_sampler;
208 draw_texture_state.src_texture = regs.draw_texture.src_texture;
209
210 maxwell3d->rasterizer->DrawTexture();
211}
212
182void DrawManager::UpdateTopology() { 213void DrawManager::UpdateTopology() {
183 const auto& regs{maxwell3d->regs}; 214 const auto& regs{maxwell3d->regs};
184 switch (regs.primitive_topology_control) { 215 switch (regs.primitive_topology_control) {
diff --git a/src/video_core/engines/draw_manager.h b/src/video_core/engines/draw_manager.h
index 58d1b2d59..7c22c49f1 100644
--- a/src/video_core/engines/draw_manager.h
+++ b/src/video_core/engines/draw_manager.h
@@ -32,6 +32,19 @@ public:
32 std::vector<u8> inline_index_draw_indexes; 32 std::vector<u8> inline_index_draw_indexes;
33 }; 33 };
34 34
35 struct DrawTextureState {
36 f32 dst_x0;
37 f32 dst_y0;
38 f32 dst_x1;
39 f32 dst_y1;
40 f32 src_x0;
41 f32 src_y0;
42 f32 src_x1;
43 f32 src_y1;
44 u32 src_sampler;
45 u32 src_texture;
46 };
47
35 struct IndirectParams { 48 struct IndirectParams {
36 bool is_indexed; 49 bool is_indexed;
37 bool include_count; 50 bool include_count;
@@ -64,6 +77,10 @@ public:
64 return draw_state; 77 return draw_state;
65 } 78 }
66 79
80 const DrawTextureState& GetDrawTextureState() const {
81 return draw_texture_state;
82 }
83
67 IndirectParams& GetIndirectParams() { 84 IndirectParams& GetIndirectParams() {
68 return indirect_state; 85 return indirect_state;
69 } 86 }
@@ -81,6 +98,8 @@ private:
81 98
82 void DrawIndexSmall(u32 argument); 99 void DrawIndexSmall(u32 argument);
83 100
101 void DrawTexture();
102
84 void UpdateTopology(); 103 void UpdateTopology();
85 104
86 void ProcessDraw(bool draw_indexed, u32 instance_count); 105 void ProcessDraw(bool draw_indexed, u32 instance_count);
@@ -89,6 +108,7 @@ private:
89 108
90 Maxwell3D* maxwell3d{}; 109 Maxwell3D* maxwell3d{};
91 State draw_state{}; 110 State draw_state{};
111 DrawTextureState draw_texture_state{};
92 IndirectParams indirect_state{}; 112 IndirectParams indirect_state{};
93}; 113};
94} // namespace Tegra::Engines 114} // namespace Tegra::Engines
diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp
index 97f547789..ae9da6290 100644
--- a/src/video_core/engines/maxwell_3d.cpp
+++ b/src/video_core/engines/maxwell_3d.cpp
@@ -149,6 +149,7 @@ bool Maxwell3D::IsMethodExecutable(u32 method) {
149 case MAXWELL3D_REG_INDEX(inline_index_4x8.index0): 149 case MAXWELL3D_REG_INDEX(inline_index_4x8.index0):
150 case MAXWELL3D_REG_INDEX(vertex_array_instance_first): 150 case MAXWELL3D_REG_INDEX(vertex_array_instance_first):
151 case MAXWELL3D_REG_INDEX(vertex_array_instance_subsequent): 151 case MAXWELL3D_REG_INDEX(vertex_array_instance_subsequent):
152 case MAXWELL3D_REG_INDEX(draw_texture.src_y0):
152 case MAXWELL3D_REG_INDEX(wait_for_idle): 153 case MAXWELL3D_REG_INDEX(wait_for_idle):
153 case MAXWELL3D_REG_INDEX(shadow_ram_control): 154 case MAXWELL3D_REG_INDEX(shadow_ram_control):
154 case MAXWELL3D_REG_INDEX(load_mme.instruction_ptr): 155 case MAXWELL3D_REG_INDEX(load_mme.instruction_ptr):
@@ -467,7 +468,7 @@ void Maxwell3D::ProcessMacroBind(u32 data) {
467} 468}
468 469
469void Maxwell3D::ProcessFirmwareCall4() { 470void Maxwell3D::ProcessFirmwareCall4() {
470 LOG_WARNING(HW_GPU, "(STUBBED) called"); 471 LOG_DEBUG(HW_GPU, "(STUBBED) called");
471 472
472 // Firmware call 4 is a blob that changes some registers depending on its parameters. 473 // Firmware call 4 is a blob that changes some registers depending on its parameters.
473 // These registers don't affect emulation and so are stubbed by setting 0xd00 to 1. 474 // These registers don't affect emulation and so are stubbed by setting 0xd00 to 1.
diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h
index 0b2fd2928..c89969bb4 100644
--- a/src/video_core/engines/maxwell_3d.h
+++ b/src/video_core/engines/maxwell_3d.h
@@ -1599,6 +1599,20 @@ public:
1599 }; 1599 };
1600 static_assert(sizeof(TIRModulationCoeff) == 0x4); 1600 static_assert(sizeof(TIRModulationCoeff) == 0x4);
1601 1601
1602 struct DrawTexture {
1603 s32 dst_x0;
1604 s32 dst_y0;
1605 s32 dst_width;
1606 s32 dst_height;
1607 s64 dx_du;
1608 s64 dy_dv;
1609 u32 src_sampler;
1610 u32 src_texture;
1611 s32 src_x0;
1612 s32 src_y0;
1613 };
1614 static_assert(sizeof(DrawTexture) == 0x30);
1615
1602 struct ReduceColorThreshold { 1616 struct ReduceColorThreshold {
1603 union { 1617 union {
1604 BitField<0, 8, u32> all_hit_once; 1618 BitField<0, 8, u32> all_hit_once;
@@ -2751,7 +2765,7 @@ public:
2751 u32 reserved_sw_method2; ///< 0x102C 2765 u32 reserved_sw_method2; ///< 0x102C
2752 std::array<TIRModulationCoeff, 5> tir_modulation_coeff; ///< 0x1030 2766 std::array<TIRModulationCoeff, 5> tir_modulation_coeff; ///< 0x1030
2753 std::array<u32, 15> spare_nop; ///< 0x1044 2767 std::array<u32, 15> spare_nop; ///< 0x1044
2754 INSERT_PADDING_BYTES_NOINIT(0x30); 2768 DrawTexture draw_texture; ///< 0x1080
2755 std::array<u32, 7> reserved_sw_method3_to_7; ///< 0x10B0 2769 std::array<u32, 7> reserved_sw_method3_to_7; ///< 0x10B0
2756 ReduceColorThreshold reduce_color_thresholds_unorm8; ///< 0x10CC 2770 ReduceColorThreshold reduce_color_thresholds_unorm8; ///< 0x10CC
2757 std::array<u32, 4> reserved_sw_method10_to_13; ///< 0x10D0 2771 std::array<u32, 4> reserved_sw_method10_to_13; ///< 0x10D0
diff --git a/src/video_core/host_shaders/CMakeLists.txt b/src/video_core/host_shaders/CMakeLists.txt
index f275b2aa9..e968ae220 100644
--- a/src/video_core/host_shaders/CMakeLists.txt
+++ b/src/video_core/host_shaders/CMakeLists.txt
@@ -11,6 +11,7 @@ set(GLSL_INCLUDES
11 11
12set(SHADER_FILES 12set(SHADER_FILES
13 astc_decoder.comp 13 astc_decoder.comp
14 blit_color_float.frag
14 block_linear_unswizzle_2d.comp 15 block_linear_unswizzle_2d.comp
15 block_linear_unswizzle_3d.comp 16 block_linear_unswizzle_3d.comp
16 convert_abgr8_to_d24s8.frag 17 convert_abgr8_to_d24s8.frag
@@ -36,7 +37,6 @@ set(SHADER_FILES
36 smaa_blending_weight_calculation.frag 37 smaa_blending_weight_calculation.frag
37 smaa_neighborhood_blending.vert 38 smaa_neighborhood_blending.vert
38 smaa_neighborhood_blending.frag 39 smaa_neighborhood_blending.frag
39 vulkan_blit_color_float.frag
40 vulkan_blit_depth_stencil.frag 40 vulkan_blit_depth_stencil.frag
41 vulkan_fidelityfx_fsr_easu_fp16.comp 41 vulkan_fidelityfx_fsr_easu_fp16.comp
42 vulkan_fidelityfx_fsr_easu_fp32.comp 42 vulkan_fidelityfx_fsr_easu_fp32.comp
diff --git a/src/video_core/host_shaders/vulkan_blit_color_float.frag b/src/video_core/host_shaders/blit_color_float.frag
index c0c832296..c0c832296 100644
--- a/src/video_core/host_shaders/vulkan_blit_color_float.frag
+++ b/src/video_core/host_shaders/blit_color_float.frag
diff --git a/src/video_core/host_shaders/full_screen_triangle.vert b/src/video_core/host_shaders/full_screen_triangle.vert
index 2c976b19f..d16d98995 100644
--- a/src/video_core/host_shaders/full_screen_triangle.vert
+++ b/src/video_core/host_shaders/full_screen_triangle.vert
@@ -4,13 +4,20 @@
4#version 450 4#version 450
5 5
6#ifdef VULKAN 6#ifdef VULKAN
7#define VERTEX_ID gl_VertexIndex
7#define BEGIN_PUSH_CONSTANTS layout(push_constant) uniform PushConstants { 8#define BEGIN_PUSH_CONSTANTS layout(push_constant) uniform PushConstants {
8#define END_PUSH_CONSTANTS }; 9#define END_PUSH_CONSTANTS };
9#define UNIFORM(n) 10#define UNIFORM(n)
11#define FLIPY 1
10#else // ^^^ Vulkan ^^^ // vvv OpenGL vvv 12#else // ^^^ Vulkan ^^^ // vvv OpenGL vvv
13#define VERTEX_ID gl_VertexID
11#define BEGIN_PUSH_CONSTANTS 14#define BEGIN_PUSH_CONSTANTS
12#define END_PUSH_CONSTANTS 15#define END_PUSH_CONSTANTS
16#define FLIPY -1
13#define UNIFORM(n) layout (location = n) uniform 17#define UNIFORM(n) layout (location = n) uniform
18out gl_PerVertex {
19 vec4 gl_Position;
20};
14#endif 21#endif
15 22
16BEGIN_PUSH_CONSTANTS 23BEGIN_PUSH_CONSTANTS
@@ -21,8 +28,8 @@ END_PUSH_CONSTANTS
21layout(location = 0) out vec2 texcoord; 28layout(location = 0) out vec2 texcoord;
22 29
23void main() { 30void main() {
24 float x = float((gl_VertexIndex & 1) << 2); 31 float x = float((VERTEX_ID & 1) << 2);
25 float y = float((gl_VertexIndex & 2) << 1); 32 float y = float((VERTEX_ID & 2) << 1);
26 gl_Position = vec4(x - 1.0, y - 1.0, 0.0, 1.0); 33 gl_Position = vec4(x - 1.0, FLIPY * (y - 1.0), 0.0, 1.0);
27 texcoord = fma(vec2(x, y) / 2.0, tex_scale, tex_offset); 34 texcoord = fma(vec2(x, y) / 2.0, tex_scale, tex_offset);
28} 35}
diff --git a/src/video_core/rasterizer_interface.h b/src/video_core/rasterizer_interface.h
index 1735b6164..33e2610bc 100644
--- a/src/video_core/rasterizer_interface.h
+++ b/src/video_core/rasterizer_interface.h
@@ -47,6 +47,9 @@ public:
47 /// Dispatches an indirect draw invocation 47 /// Dispatches an indirect draw invocation
48 virtual void DrawIndirect() {} 48 virtual void DrawIndirect() {}
49 49
50 /// Dispatches an draw texture invocation
51 virtual void DrawTexture() = 0;
52
50 /// Clear the current framebuffer 53 /// Clear the current framebuffer
51 virtual void Clear(u32 layer_count) = 0; 54 virtual void Clear(u32 layer_count) = 0;
52 55
diff --git a/src/video_core/renderer_null/null_rasterizer.cpp b/src/video_core/renderer_null/null_rasterizer.cpp
index 2c11345d7..2b5c7defa 100644
--- a/src/video_core/renderer_null/null_rasterizer.cpp
+++ b/src/video_core/renderer_null/null_rasterizer.cpp
@@ -21,6 +21,7 @@ RasterizerNull::RasterizerNull(Core::Memory::Memory& cpu_memory_, Tegra::GPU& gp
21RasterizerNull::~RasterizerNull() = default; 21RasterizerNull::~RasterizerNull() = default;
22 22
23void RasterizerNull::Draw(bool is_indexed, u32 instance_count) {} 23void RasterizerNull::Draw(bool is_indexed, u32 instance_count) {}
24void RasterizerNull::DrawTexture() {}
24void RasterizerNull::Clear(u32 layer_count) {} 25void RasterizerNull::Clear(u32 layer_count) {}
25void RasterizerNull::DispatchCompute() {} 26void RasterizerNull::DispatchCompute() {}
26void RasterizerNull::ResetCounter(VideoCore::QueryType type) {} 27void RasterizerNull::ResetCounter(VideoCore::QueryType type) {}
diff --git a/src/video_core/renderer_null/null_rasterizer.h b/src/video_core/renderer_null/null_rasterizer.h
index 2112aa70e..51f896e43 100644
--- a/src/video_core/renderer_null/null_rasterizer.h
+++ b/src/video_core/renderer_null/null_rasterizer.h
@@ -31,6 +31,7 @@ public:
31 ~RasterizerNull() override; 31 ~RasterizerNull() override;
32 32
33 void Draw(bool is_indexed, u32 instance_count) override; 33 void Draw(bool is_indexed, u32 instance_count) override;
34 void DrawTexture() override;
34 void Clear(u32 layer_count) override; 35 void Clear(u32 layer_count) override;
35 void DispatchCompute() override; 36 void DispatchCompute() override;
36 void ResetCounter(VideoCore::QueryType type) override; 37 void ResetCounter(VideoCore::QueryType type) override;
diff --git a/src/video_core/renderer_opengl/blit_image.cpp b/src/video_core/renderer_opengl/blit_image.cpp
new file mode 100644
index 000000000..9a560a73b
--- /dev/null
+++ b/src/video_core/renderer_opengl/blit_image.cpp
@@ -0,0 +1,59 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include <algorithm>
5
6#include "video_core/host_shaders/blit_color_float_frag.h"
7#include "video_core/host_shaders/full_screen_triangle_vert.h"
8#include "video_core/renderer_opengl/blit_image.h"
9#include "video_core/renderer_opengl/gl_shader_manager.h"
10#include "video_core/renderer_opengl/gl_shader_util.h"
11
12namespace OpenGL {
13
14BlitImageHelper::BlitImageHelper(ProgramManager& program_manager_)
15 : program_manager(program_manager_),
16 full_screen_vert(CreateProgram(HostShaders::FULL_SCREEN_TRIANGLE_VERT, GL_VERTEX_SHADER)),
17 blit_color_to_color_frag(
18 CreateProgram(HostShaders::BLIT_COLOR_FLOAT_FRAG, GL_FRAGMENT_SHADER)) {}
19
20BlitImageHelper::~BlitImageHelper() = default;
21
22void BlitImageHelper::BlitColor(GLuint dst_framebuffer, GLuint src_image_view, GLuint src_sampler,
23 const Region2D& dst_region, const Region2D& src_region,
24 const Extent3D& src_size) {
25 glEnable(GL_CULL_FACE);
26 glDisable(GL_COLOR_LOGIC_OP);
27 glDisable(GL_DEPTH_TEST);
28 glDisable(GL_STENCIL_TEST);
29 glDisable(GL_POLYGON_OFFSET_FILL);
30 glDisable(GL_RASTERIZER_DISCARD);
31 glDisable(GL_ALPHA_TEST);
32 glDisablei(GL_BLEND, 0);
33 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
34 glCullFace(GL_BACK);
35 glFrontFace(GL_CW);
36 glColorMaski(0, GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
37 glDepthRangeIndexed(0, 0.0, 0.0);
38
39 program_manager.BindPresentPrograms(full_screen_vert.handle, blit_color_to_color_frag.handle);
40 glProgramUniform2f(full_screen_vert.handle, 0,
41 static_cast<float>(src_region.end.x - src_region.start.x) /
42 static_cast<float>(src_size.width),
43 static_cast<float>(src_region.end.y - src_region.start.y) /
44 static_cast<float>(src_size.height));
45 glProgramUniform2f(full_screen_vert.handle, 1,
46 static_cast<float>(src_region.start.x) / static_cast<float>(src_size.width),
47 static_cast<float>(src_region.start.y) /
48 static_cast<float>(src_size.height));
49 glViewport(std::min(dst_region.start.x, dst_region.end.x),
50 std::min(dst_region.start.y, dst_region.end.y),
51 std::abs(dst_region.end.x - dst_region.start.x),
52 std::abs(dst_region.end.y - dst_region.start.y));
53 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, dst_framebuffer);
54 glBindSampler(0, src_sampler);
55 glBindTextureUnit(0, src_image_view);
56 glClear(GL_COLOR_BUFFER_BIT);
57 glDrawArrays(GL_TRIANGLES, 0, 3);
58}
59} // namespace OpenGL
diff --git a/src/video_core/renderer_opengl/blit_image.h b/src/video_core/renderer_opengl/blit_image.h
new file mode 100644
index 000000000..5a2b12d16
--- /dev/null
+++ b/src/video_core/renderer_opengl/blit_image.h
@@ -0,0 +1,38 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <glad/glad.h>
7
8#include "video_core/engines/fermi_2d.h"
9#include "video_core/renderer_opengl/gl_resource_manager.h"
10#include "video_core/texture_cache/types.h"
11
12namespace OpenGL {
13
14using VideoCommon::Extent3D;
15using VideoCommon::Offset2D;
16using VideoCommon::Region2D;
17
18class ProgramManager;
19class Framebuffer;
20class ImageView;
21
22class BlitImageHelper {
23public:
24 explicit BlitImageHelper(ProgramManager& program_manager);
25 ~BlitImageHelper();
26
27 void BlitColor(GLuint dst_framebuffer, GLuint src_image_view, GLuint src_sampler,
28 const Region2D& dst_region, const Region2D& src_region,
29 const Extent3D& src_size);
30
31private:
32 ProgramManager& program_manager;
33
34 OGLProgram full_screen_vert;
35 OGLProgram blit_color_to_color_frag;
36};
37
38} // namespace OpenGL
diff --git a/src/video_core/renderer_opengl/gl_device.cpp b/src/video_core/renderer_opengl/gl_device.cpp
index cee5c3247..22ed16ebf 100644
--- a/src/video_core/renderer_opengl/gl_device.cpp
+++ b/src/video_core/renderer_opengl/gl_device.cpp
@@ -166,6 +166,7 @@ Device::Device(Core::Frontend::EmuWindow& emu_window) {
166 has_shader_int64 = HasExtension(extensions, "GL_ARB_gpu_shader_int64"); 166 has_shader_int64 = HasExtension(extensions, "GL_ARB_gpu_shader_int64");
167 has_amd_shader_half_float = GLAD_GL_AMD_gpu_shader_half_float; 167 has_amd_shader_half_float = GLAD_GL_AMD_gpu_shader_half_float;
168 has_sparse_texture_2 = GLAD_GL_ARB_sparse_texture2; 168 has_sparse_texture_2 = GLAD_GL_ARB_sparse_texture2;
169 has_draw_texture = GLAD_GL_NV_draw_texture;
169 warp_size_potentially_larger_than_guest = !is_nvidia && !is_intel; 170 warp_size_potentially_larger_than_guest = !is_nvidia && !is_intel;
170 need_fastmath_off = is_nvidia; 171 need_fastmath_off = is_nvidia;
171 can_report_memory = GLAD_GL_NVX_gpu_memory_info; 172 can_report_memory = GLAD_GL_NVX_gpu_memory_info;
diff --git a/src/video_core/renderer_opengl/gl_device.h b/src/video_core/renderer_opengl/gl_device.h
index 2a72d84be..3ff8cad83 100644
--- a/src/video_core/renderer_opengl/gl_device.h
+++ b/src/video_core/renderer_opengl/gl_device.h
@@ -4,6 +4,8 @@
4#pragma once 4#pragma once
5 5
6#include <cstddef> 6#include <cstddef>
7#include <string>
8
7#include "common/common_types.h" 9#include "common/common_types.h"
8#include "core/frontend/emu_window.h" 10#include "core/frontend/emu_window.h"
9#include "shader_recompiler/stage.h" 11#include "shader_recompiler/stage.h"
@@ -146,6 +148,10 @@ public:
146 return has_sparse_texture_2; 148 return has_sparse_texture_2;
147 } 149 }
148 150
151 bool HasDrawTexture() const {
152 return has_draw_texture;
153 }
154
149 bool IsWarpSizePotentiallyLargerThanGuest() const { 155 bool IsWarpSizePotentiallyLargerThanGuest() const {
150 return warp_size_potentially_larger_than_guest; 156 return warp_size_potentially_larger_than_guest;
151 } 157 }
@@ -216,6 +222,7 @@ private:
216 bool has_shader_int64{}; 222 bool has_shader_int64{};
217 bool has_amd_shader_half_float{}; 223 bool has_amd_shader_half_float{};
218 bool has_sparse_texture_2{}; 224 bool has_sparse_texture_2{};
225 bool has_draw_texture{};
219 bool warp_size_potentially_larger_than_guest{}; 226 bool warp_size_potentially_larger_than_guest{};
220 bool need_fastmath_off{}; 227 bool need_fastmath_off{};
221 bool has_cbuf_ftou_bug{}; 228 bool has_cbuf_ftou_bug{};
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index 181857d9c..7bced675c 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -64,7 +64,8 @@ RasterizerOpenGL::RasterizerOpenGL(Core::Frontend::EmuWindow& emu_window_, Tegra
64 shader_cache(*this, emu_window_, device, texture_cache, buffer_cache, program_manager, 64 shader_cache(*this, emu_window_, device, texture_cache, buffer_cache, program_manager,
65 state_tracker, gpu.ShaderNotify()), 65 state_tracker, gpu.ShaderNotify()),
66 query_cache(*this), accelerate_dma(buffer_cache), 66 query_cache(*this), accelerate_dma(buffer_cache),
67 fence_manager(*this, gpu, texture_cache, buffer_cache, query_cache) {} 67 fence_manager(*this, gpu, texture_cache, buffer_cache, query_cache),
68 blit_image(program_manager_) {}
68 69
69RasterizerOpenGL::~RasterizerOpenGL() = default; 70RasterizerOpenGL::~RasterizerOpenGL() = default;
70 71
@@ -320,6 +321,47 @@ void RasterizerOpenGL::DrawIndirect() {
320 buffer_cache.SetDrawIndirect(nullptr); 321 buffer_cache.SetDrawIndirect(nullptr);
321} 322}
322 323
324void RasterizerOpenGL::DrawTexture() {
325 MICROPROFILE_SCOPE(OpenGL_Drawing);
326
327 SCOPE_EXIT({ gpu.TickWork(); });
328 query_cache.UpdateCounters();
329
330 texture_cache.SynchronizeGraphicsDescriptors();
331 texture_cache.UpdateRenderTargets(false);
332
333 SyncState();
334
335 const auto& draw_texture_state = maxwell3d->draw_manager->GetDrawTextureState();
336 const auto& sampler = texture_cache.GetGraphicsSampler(draw_texture_state.src_sampler);
337 const auto& texture = texture_cache.GetImageView(draw_texture_state.src_texture);
338
339 if (device.HasDrawTexture()) {
340 state_tracker.BindFramebuffer(texture_cache.GetFramebuffer()->Handle());
341
342 glDrawTextureNV(texture.DefaultHandle(), sampler->Handle(), draw_texture_state.dst_x0,
343 draw_texture_state.dst_y0, draw_texture_state.dst_x1,
344 draw_texture_state.dst_y1, 0,
345 draw_texture_state.src_x0 / static_cast<float>(texture.size.width),
346 draw_texture_state.src_y0 / static_cast<float>(texture.size.height),
347 draw_texture_state.src_x1 / static_cast<float>(texture.size.width),
348 draw_texture_state.src_y1 / static_cast<float>(texture.size.height));
349 } else {
350 Region2D dst_region = {Offset2D{.x = static_cast<s32>(draw_texture_state.dst_x0),
351 .y = static_cast<s32>(draw_texture_state.dst_y0)},
352 Offset2D{.x = static_cast<s32>(draw_texture_state.dst_x1),
353 .y = static_cast<s32>(draw_texture_state.dst_y1)}};
354 Region2D src_region = {Offset2D{.x = static_cast<s32>(draw_texture_state.src_x0),
355 .y = static_cast<s32>(draw_texture_state.src_y0)},
356 Offset2D{.x = static_cast<s32>(draw_texture_state.src_x1),
357 .y = static_cast<s32>(draw_texture_state.src_y1)}};
358 blit_image.BlitColor(texture_cache.GetFramebuffer()->Handle(), texture.DefaultHandle(),
359 sampler->Handle(), dst_region, src_region, texture.size);
360 }
361
362 ++num_queued_commands;
363}
364
323void RasterizerOpenGL::DispatchCompute() { 365void RasterizerOpenGL::DispatchCompute() {
324 gpu_memory->FlushCaching(); 366 gpu_memory->FlushCaching();
325 ComputePipeline* const pipeline{shader_cache.CurrentComputePipeline()}; 367 ComputePipeline* const pipeline{shader_cache.CurrentComputePipeline()};
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h
index be4f76c18..0c45832ae 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer.h
@@ -16,6 +16,7 @@
16#include "video_core/engines/maxwell_dma.h" 16#include "video_core/engines/maxwell_dma.h"
17#include "video_core/rasterizer_accelerated.h" 17#include "video_core/rasterizer_accelerated.h"
18#include "video_core/rasterizer_interface.h" 18#include "video_core/rasterizer_interface.h"
19#include "video_core/renderer_opengl/blit_image.h"
19#include "video_core/renderer_opengl/gl_buffer_cache.h" 20#include "video_core/renderer_opengl/gl_buffer_cache.h"
20#include "video_core/renderer_opengl/gl_device.h" 21#include "video_core/renderer_opengl/gl_device.h"
21#include "video_core/renderer_opengl/gl_fence_manager.h" 22#include "video_core/renderer_opengl/gl_fence_manager.h"
@@ -70,6 +71,7 @@ public:
70 71
71 void Draw(bool is_indexed, u32 instance_count) override; 72 void Draw(bool is_indexed, u32 instance_count) override;
72 void DrawIndirect() override; 73 void DrawIndirect() override;
74 void DrawTexture() override;
73 void Clear(u32 layer_count) override; 75 void Clear(u32 layer_count) override;
74 void DispatchCompute() override; 76 void DispatchCompute() override;
75 void ResetCounter(VideoCore::QueryType type) override; 77 void ResetCounter(VideoCore::QueryType type) override;
@@ -224,6 +226,8 @@ private:
224 AccelerateDMA accelerate_dma; 226 AccelerateDMA accelerate_dma;
225 FenceManagerOpenGL fence_manager; 227 FenceManagerOpenGL fence_manager;
226 228
229 BlitImageHelper blit_image;
230
227 boost::container::static_vector<u32, MAX_IMAGE_VIEWS> image_view_indices; 231 boost::container::static_vector<u32, MAX_IMAGE_VIEWS> image_view_indices;
228 std::array<ImageViewId, MAX_IMAGE_VIEWS> image_view_ids; 232 std::array<ImageViewId, MAX_IMAGE_VIEWS> image_view_ids;
229 boost::container::static_vector<GLuint, MAX_TEXTURES> sampler_handles; 233 boost::container::static_vector<GLuint, MAX_TEXTURES> sampler_handles;
diff --git a/src/video_core/renderer_opengl/gl_shader_manager.cpp b/src/video_core/renderer_opengl/gl_shader_manager.cpp
index d9c29d8b7..98841ae65 100644
--- a/src/video_core/renderer_opengl/gl_shader_manager.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_manager.cpp
@@ -1,2 +1,123 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include <glad/glad.h>
5
6#include "video_core/renderer_opengl/gl_shader_manager.h"
7
8namespace OpenGL {
9
10static constexpr std::array ASSEMBLY_PROGRAM_ENUMS{
11 GL_VERTEX_PROGRAM_NV, GL_TESS_CONTROL_PROGRAM_NV, GL_TESS_EVALUATION_PROGRAM_NV,
12 GL_GEOMETRY_PROGRAM_NV, GL_FRAGMENT_PROGRAM_NV,
13};
14
15ProgramManager::ProgramManager(const Device& device) {
16 glCreateProgramPipelines(1, &pipeline.handle);
17 if (device.UseAssemblyShaders()) {
18 glEnable(GL_COMPUTE_PROGRAM_NV);
19 }
20}
21
22void ProgramManager::BindComputeProgram(GLuint program) {
23 glUseProgram(program);
24 is_compute_bound = true;
25}
26
27void ProgramManager::BindComputeAssemblyProgram(GLuint program) {
28 if (current_assembly_compute_program != program) {
29 current_assembly_compute_program = program;
30 glBindProgramARB(GL_COMPUTE_PROGRAM_NV, program);
31 }
32 UnbindPipeline();
33}
34
35void ProgramManager::BindSourcePrograms(std::span<const OGLProgram, NUM_STAGES> programs) {
36 static constexpr std::array<GLenum, 5> stage_enums{
37 GL_VERTEX_SHADER_BIT, GL_TESS_CONTROL_SHADER_BIT, GL_TESS_EVALUATION_SHADER_BIT,
38 GL_GEOMETRY_SHADER_BIT, GL_FRAGMENT_SHADER_BIT,
39 };
40 for (size_t stage = 0; stage < NUM_STAGES; ++stage) {
41 if (current_programs[stage] != programs[stage].handle) {
42 current_programs[stage] = programs[stage].handle;
43 glUseProgramStages(pipeline.handle, stage_enums[stage], programs[stage].handle);
44 }
45 }
46 BindPipeline();
47}
48
49void ProgramManager::BindPresentPrograms(GLuint vertex, GLuint fragment) {
50 if (current_programs[0] != vertex) {
51 current_programs[0] = vertex;
52 glUseProgramStages(pipeline.handle, GL_VERTEX_SHADER_BIT, vertex);
53 }
54 if (current_programs[4] != fragment) {
55 current_programs[4] = fragment;
56 glUseProgramStages(pipeline.handle, GL_FRAGMENT_SHADER_BIT, fragment);
57 }
58 glUseProgramStages(
59 pipeline.handle,
60 GL_TESS_CONTROL_SHADER_BIT | GL_TESS_EVALUATION_SHADER_BIT | GL_GEOMETRY_SHADER_BIT, 0);
61 current_programs[1] = 0;
62 current_programs[2] = 0;
63 current_programs[3] = 0;
64
65 if (current_stage_mask != 0) {
66 current_stage_mask = 0;
67 for (const GLenum program_type : ASSEMBLY_PROGRAM_ENUMS) {
68 glDisable(program_type);
69 }
70 }
71 BindPipeline();
72}
73
74void ProgramManager::BindAssemblyPrograms(std::span<const OGLAssemblyProgram, NUM_STAGES> programs,
75 u32 stage_mask) {
76 const u32 changed_mask = current_stage_mask ^ stage_mask;
77 current_stage_mask = stage_mask;
78
79 if (changed_mask != 0) {
80 for (size_t stage = 0; stage < NUM_STAGES; ++stage) {
81 if (((changed_mask >> stage) & 1) != 0) {
82 if (((stage_mask >> stage) & 1) != 0) {
83 glEnable(ASSEMBLY_PROGRAM_ENUMS[stage]);
84 } else {
85 glDisable(ASSEMBLY_PROGRAM_ENUMS[stage]);
86 }
87 }
88 }
89 }
90 for (size_t stage = 0; stage < NUM_STAGES; ++stage) {
91 if (current_programs[stage] != programs[stage].handle) {
92 current_programs[stage] = programs[stage].handle;
93 glBindProgramARB(ASSEMBLY_PROGRAM_ENUMS[stage], programs[stage].handle);
94 }
95 }
96 UnbindPipeline();
97}
98
99void ProgramManager::RestoreGuestCompute() {}
100
101void ProgramManager::BindPipeline() {
102 if (!is_pipeline_bound) {
103 is_pipeline_bound = true;
104 glBindProgramPipeline(pipeline.handle);
105 }
106 UnbindCompute();
107}
108
109void ProgramManager::UnbindPipeline() {
110 if (is_pipeline_bound) {
111 is_pipeline_bound = false;
112 glBindProgramPipeline(0);
113 }
114 UnbindCompute();
115}
116
117void ProgramManager::UnbindCompute() {
118 if (is_compute_bound) {
119 is_compute_bound = false;
120 glUseProgram(0);
121 }
122}
123} // namespace OpenGL
diff --git a/src/video_core/renderer_opengl/gl_shader_manager.h b/src/video_core/renderer_opengl/gl_shader_manager.h
index a84f5aeb3..07ffab77f 100644
--- a/src/video_core/renderer_opengl/gl_shader_manager.h
+++ b/src/video_core/renderer_opengl/gl_shader_manager.h
@@ -6,8 +6,6 @@
6#include <array> 6#include <array>
7#include <span> 7#include <span>
8 8
9#include <glad/glad.h>
10
11#include "video_core/renderer_opengl/gl_device.h" 9#include "video_core/renderer_opengl/gl_device.h"
12#include "video_core/renderer_opengl/gl_resource_manager.h" 10#include "video_core/renderer_opengl/gl_resource_manager.h"
13 11
@@ -16,121 +14,28 @@ namespace OpenGL {
16class ProgramManager { 14class ProgramManager {
17 static constexpr size_t NUM_STAGES = 5; 15 static constexpr size_t NUM_STAGES = 5;
18 16
19 static constexpr std::array ASSEMBLY_PROGRAM_ENUMS{
20 GL_VERTEX_PROGRAM_NV, GL_TESS_CONTROL_PROGRAM_NV, GL_TESS_EVALUATION_PROGRAM_NV,
21 GL_GEOMETRY_PROGRAM_NV, GL_FRAGMENT_PROGRAM_NV,
22 };
23
24public: 17public:
25 explicit ProgramManager(const Device& device) { 18 explicit ProgramManager(const Device& device);
26 glCreateProgramPipelines(1, &pipeline.handle); 19
27 if (device.UseAssemblyShaders()) { 20 void BindComputeProgram(GLuint program);
28 glEnable(GL_COMPUTE_PROGRAM_NV); 21
29 } 22 void BindComputeAssemblyProgram(GLuint program);
30 } 23
31 24 void BindSourcePrograms(std::span<const OGLProgram, NUM_STAGES> programs);
32 void BindComputeProgram(GLuint program) { 25
33 glUseProgram(program); 26 void BindPresentPrograms(GLuint vertex, GLuint fragment);
34 is_compute_bound = true;
35 }
36
37 void BindComputeAssemblyProgram(GLuint program) {
38 if (current_assembly_compute_program != program) {
39 current_assembly_compute_program = program;
40 glBindProgramARB(GL_COMPUTE_PROGRAM_NV, program);
41 }
42 UnbindPipeline();
43 }
44
45 void BindSourcePrograms(std::span<const OGLProgram, NUM_STAGES> programs) {
46 static constexpr std::array<GLenum, 5> stage_enums{
47 GL_VERTEX_SHADER_BIT, GL_TESS_CONTROL_SHADER_BIT, GL_TESS_EVALUATION_SHADER_BIT,
48 GL_GEOMETRY_SHADER_BIT, GL_FRAGMENT_SHADER_BIT,
49 };
50 for (size_t stage = 0; stage < NUM_STAGES; ++stage) {
51 if (current_programs[stage] != programs[stage].handle) {
52 current_programs[stage] = programs[stage].handle;
53 glUseProgramStages(pipeline.handle, stage_enums[stage], programs[stage].handle);
54 }
55 }
56 BindPipeline();
57 }
58
59 void BindPresentPrograms(GLuint vertex, GLuint fragment) {
60 if (current_programs[0] != vertex) {
61 current_programs[0] = vertex;
62 glUseProgramStages(pipeline.handle, GL_VERTEX_SHADER_BIT, vertex);
63 }
64 if (current_programs[4] != fragment) {
65 current_programs[4] = fragment;
66 glUseProgramStages(pipeline.handle, GL_FRAGMENT_SHADER_BIT, fragment);
67 }
68 glUseProgramStages(
69 pipeline.handle,
70 GL_TESS_CONTROL_SHADER_BIT | GL_TESS_EVALUATION_SHADER_BIT | GL_GEOMETRY_SHADER_BIT, 0);
71 current_programs[1] = 0;
72 current_programs[2] = 0;
73 current_programs[3] = 0;
74
75 if (current_stage_mask != 0) {
76 current_stage_mask = 0;
77 for (const GLenum program_type : ASSEMBLY_PROGRAM_ENUMS) {
78 glDisable(program_type);
79 }
80 }
81 BindPipeline();
82 }
83 27
84 void BindAssemblyPrograms(std::span<const OGLAssemblyProgram, NUM_STAGES> programs, 28 void BindAssemblyPrograms(std::span<const OGLAssemblyProgram, NUM_STAGES> programs,
85 u32 stage_mask) { 29 u32 stage_mask);
86 const u32 changed_mask = current_stage_mask ^ stage_mask; 30
87 current_stage_mask = stage_mask; 31 void RestoreGuestCompute();
88
89 if (changed_mask != 0) {
90 for (size_t stage = 0; stage < NUM_STAGES; ++stage) {
91 if (((changed_mask >> stage) & 1) != 0) {
92 if (((stage_mask >> stage) & 1) != 0) {
93 glEnable(ASSEMBLY_PROGRAM_ENUMS[stage]);
94 } else {
95 glDisable(ASSEMBLY_PROGRAM_ENUMS[stage]);
96 }
97 }
98 }
99 }
100 for (size_t stage = 0; stage < NUM_STAGES; ++stage) {
101 if (current_programs[stage] != programs[stage].handle) {
102 current_programs[stage] = programs[stage].handle;
103 glBindProgramARB(ASSEMBLY_PROGRAM_ENUMS[stage], programs[stage].handle);
104 }
105 }
106 UnbindPipeline();
107 }
108
109 void RestoreGuestCompute() {}
110 32
111private: 33private:
112 void BindPipeline() { 34 void BindPipeline();
113 if (!is_pipeline_bound) { 35
114 is_pipeline_bound = true; 36 void UnbindPipeline();
115 glBindProgramPipeline(pipeline.handle); 37
116 } 38 void UnbindCompute();
117 UnbindCompute();
118 }
119
120 void UnbindPipeline() {
121 if (is_pipeline_bound) {
122 is_pipeline_bound = false;
123 glBindProgramPipeline(0);
124 }
125 UnbindCompute();
126 }
127
128 void UnbindCompute() {
129 if (is_compute_bound) {
130 is_compute_bound = false;
131 glUseProgram(0);
132 }
133 }
134 39
135 OGLPipeline pipeline; 40 OGLPipeline pipeline;
136 bool is_pipeline_bound{}; 41 bool is_pipeline_bound{};
diff --git a/src/video_core/renderer_vulkan/blit_image.cpp b/src/video_core/renderer_vulkan/blit_image.cpp
index 3f2b139e0..dd00d3edf 100644
--- a/src/video_core/renderer_vulkan/blit_image.cpp
+++ b/src/video_core/renderer_vulkan/blit_image.cpp
@@ -4,13 +4,13 @@
4#include <algorithm> 4#include <algorithm>
5 5
6#include "common/settings.h" 6#include "common/settings.h"
7#include "video_core/host_shaders/blit_color_float_frag_spv.h"
7#include "video_core/host_shaders/convert_abgr8_to_d24s8_frag_spv.h" 8#include "video_core/host_shaders/convert_abgr8_to_d24s8_frag_spv.h"
8#include "video_core/host_shaders/convert_d24s8_to_abgr8_frag_spv.h" 9#include "video_core/host_shaders/convert_d24s8_to_abgr8_frag_spv.h"
9#include "video_core/host_shaders/convert_depth_to_float_frag_spv.h" 10#include "video_core/host_shaders/convert_depth_to_float_frag_spv.h"
10#include "video_core/host_shaders/convert_float_to_depth_frag_spv.h" 11#include "video_core/host_shaders/convert_float_to_depth_frag_spv.h"
11#include "video_core/host_shaders/convert_s8d24_to_abgr8_frag_spv.h" 12#include "video_core/host_shaders/convert_s8d24_to_abgr8_frag_spv.h"
12#include "video_core/host_shaders/full_screen_triangle_vert_spv.h" 13#include "video_core/host_shaders/full_screen_triangle_vert_spv.h"
13#include "video_core/host_shaders/vulkan_blit_color_float_frag_spv.h"
14#include "video_core/host_shaders/vulkan_blit_depth_stencil_frag_spv.h" 14#include "video_core/host_shaders/vulkan_blit_depth_stencil_frag_spv.h"
15#include "video_core/renderer_vulkan/blit_image.h" 15#include "video_core/renderer_vulkan/blit_image.h"
16#include "video_core/renderer_vulkan/maxwell_to_vk.h" 16#include "video_core/renderer_vulkan/maxwell_to_vk.h"
@@ -303,7 +303,7 @@ void UpdateTwoTexturesDescriptorSet(const Device& device, VkDescriptorSet descri
303} 303}
304 304
305void BindBlitState(vk::CommandBuffer cmdbuf, VkPipelineLayout layout, const Region2D& dst_region, 305void BindBlitState(vk::CommandBuffer cmdbuf, VkPipelineLayout layout, const Region2D& dst_region,
306 const Region2D& src_region) { 306 const Region2D& src_region, const Extent3D& src_size = {1, 1, 1}) {
307 const VkOffset2D offset{ 307 const VkOffset2D offset{
308 .x = std::min(dst_region.start.x, dst_region.end.x), 308 .x = std::min(dst_region.start.x, dst_region.end.x),
309 .y = std::min(dst_region.start.y, dst_region.end.y), 309 .y = std::min(dst_region.start.y, dst_region.end.y),
@@ -325,12 +325,15 @@ void BindBlitState(vk::CommandBuffer cmdbuf, VkPipelineLayout layout, const Regi
325 .offset = offset, 325 .offset = offset,
326 .extent = extent, 326 .extent = extent,
327 }; 327 };
328 const float scale_x = static_cast<float>(src_region.end.x - src_region.start.x); 328 const float scale_x = static_cast<float>(src_region.end.x - src_region.start.x) /
329 const float scale_y = static_cast<float>(src_region.end.y - src_region.start.y); 329 static_cast<float>(src_size.width);
330 const float scale_y = static_cast<float>(src_region.end.y - src_region.start.y) /
331 static_cast<float>(src_size.height);
330 const PushConstants push_constants{ 332 const PushConstants push_constants{
331 .tex_scale = {scale_x, scale_y}, 333 .tex_scale = {scale_x, scale_y},
332 .tex_offset = {static_cast<float>(src_region.start.x), 334 .tex_offset = {static_cast<float>(src_region.start.x) / static_cast<float>(src_size.width),
333 static_cast<float>(src_region.start.y)}, 335 static_cast<float>(src_region.start.y) /
336 static_cast<float>(src_size.height)},
334 }; 337 };
335 cmdbuf.SetViewport(0, viewport); 338 cmdbuf.SetViewport(0, viewport);
336 cmdbuf.SetScissor(0, scissor); 339 cmdbuf.SetScissor(0, scissor);
@@ -347,6 +350,51 @@ VkExtent2D GetConversionExtent(const ImageView& src_image_view) {
347 .height = is_rescaled ? resolution.ScaleUp(height) : height, 350 .height = is_rescaled ? resolution.ScaleUp(height) : height,
348 }; 351 };
349} 352}
353
354void TransitionImageLayout(vk::CommandBuffer& cmdbuf, VkImage image, VkImageLayout target_layout,
355 VkImageLayout source_layout = VK_IMAGE_LAYOUT_GENERAL) {
356 constexpr VkFlags flags{VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
357 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT};
358 const VkImageMemoryBarrier barrier{
359 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
360 .pNext = nullptr,
361 .srcAccessMask = flags,
362 .dstAccessMask = flags,
363 .oldLayout = source_layout,
364 .newLayout = target_layout,
365 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
366 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
367 .image = image,
368 .subresourceRange{
369 .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
370 .baseMipLevel = 0,
371 .levelCount = 1,
372 .baseArrayLayer = 0,
373 .layerCount = 1,
374 },
375 };
376 cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
377 0, barrier);
378}
379
380void BeginRenderPass(vk::CommandBuffer& cmdbuf, const Framebuffer* framebuffer) {
381 const VkRenderPass render_pass = framebuffer->RenderPass();
382 const VkFramebuffer framebuffer_handle = framebuffer->Handle();
383 const VkExtent2D render_area = framebuffer->RenderArea();
384 const VkRenderPassBeginInfo renderpass_bi{
385 .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
386 .pNext = nullptr,
387 .renderPass = render_pass,
388 .framebuffer = framebuffer_handle,
389 .renderArea{
390 .offset{},
391 .extent = render_area,
392 },
393 .clearValueCount = 0,
394 .pClearValues = nullptr,
395 };
396 cmdbuf.BeginRenderPass(renderpass_bi, VK_SUBPASS_CONTENTS_INLINE);
397}
350} // Anonymous namespace 398} // Anonymous namespace
351 399
352BlitImageHelper::BlitImageHelper(const Device& device_, Scheduler& scheduler_, 400BlitImageHelper::BlitImageHelper(const Device& device_, Scheduler& scheduler_,
@@ -365,7 +413,7 @@ BlitImageHelper::BlitImageHelper(const Device& device_, Scheduler& scheduler_,
365 two_textures_pipeline_layout(device.GetLogical().CreatePipelineLayout( 413 two_textures_pipeline_layout(device.GetLogical().CreatePipelineLayout(
366 PipelineLayoutCreateInfo(two_textures_set_layout.address()))), 414 PipelineLayoutCreateInfo(two_textures_set_layout.address()))),
367 full_screen_vert(BuildShader(device, FULL_SCREEN_TRIANGLE_VERT_SPV)), 415 full_screen_vert(BuildShader(device, FULL_SCREEN_TRIANGLE_VERT_SPV)),
368 blit_color_to_color_frag(BuildShader(device, VULKAN_BLIT_COLOR_FLOAT_FRAG_SPV)), 416 blit_color_to_color_frag(BuildShader(device, BLIT_COLOR_FLOAT_FRAG_SPV)),
369 blit_depth_stencil_frag(BuildShader(device, VULKAN_BLIT_DEPTH_STENCIL_FRAG_SPV)), 417 blit_depth_stencil_frag(BuildShader(device, VULKAN_BLIT_DEPTH_STENCIL_FRAG_SPV)),
370 convert_depth_to_float_frag(BuildShader(device, CONVERT_DEPTH_TO_FLOAT_FRAG_SPV)), 418 convert_depth_to_float_frag(BuildShader(device, CONVERT_DEPTH_TO_FLOAT_FRAG_SPV)),
371 convert_float_to_depth_frag(BuildShader(device, CONVERT_FLOAT_TO_DEPTH_FRAG_SPV)), 419 convert_float_to_depth_frag(BuildShader(device, CONVERT_FLOAT_TO_DEPTH_FRAG_SPV)),
@@ -404,6 +452,32 @@ void BlitImageHelper::BlitColor(const Framebuffer* dst_framebuffer, VkImageView
404 scheduler.InvalidateState(); 452 scheduler.InvalidateState();
405} 453}
406 454
455void BlitImageHelper::BlitColor(const Framebuffer* dst_framebuffer, VkImageView src_image_view,
456 VkImage src_image, VkSampler src_sampler,
457 const Region2D& dst_region, const Region2D& src_region,
458 const Extent3D& src_size) {
459 const BlitImagePipelineKey key{
460 .renderpass = dst_framebuffer->RenderPass(),
461 .operation = Tegra::Engines::Fermi2D::Operation::SrcCopy,
462 };
463 const VkPipelineLayout layout = *one_texture_pipeline_layout;
464 const VkPipeline pipeline = FindOrEmplaceColorPipeline(key);
465 scheduler.RequestOutsideRenderPassOperationContext();
466 scheduler.Record([this, dst_framebuffer, src_image_view, src_image, src_sampler, dst_region,
467 src_region, src_size, pipeline, layout](vk::CommandBuffer cmdbuf) {
468 TransitionImageLayout(cmdbuf, src_image, VK_IMAGE_LAYOUT_READ_ONLY_OPTIMAL);
469 BeginRenderPass(cmdbuf, dst_framebuffer);
470 const VkDescriptorSet descriptor_set = one_texture_descriptor_allocator.Commit();
471 UpdateOneTextureDescriptorSet(device, descriptor_set, src_sampler, src_image_view);
472 cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
473 cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, descriptor_set,
474 nullptr);
475 BindBlitState(cmdbuf, layout, dst_region, src_region, src_size);
476 cmdbuf.Draw(3, 1, 0, 0);
477 cmdbuf.EndRenderPass();
478 });
479}
480
407void BlitImageHelper::BlitDepthStencil(const Framebuffer* dst_framebuffer, 481void BlitImageHelper::BlitDepthStencil(const Framebuffer* dst_framebuffer,
408 VkImageView src_depth_view, VkImageView src_stencil_view, 482 VkImageView src_depth_view, VkImageView src_stencil_view,
409 const Region2D& dst_region, const Region2D& src_region, 483 const Region2D& dst_region, const Region2D& src_region,
diff --git a/src/video_core/renderer_vulkan/blit_image.h b/src/video_core/renderer_vulkan/blit_image.h
index 5df679fb4..be8a9a2f6 100644
--- a/src/video_core/renderer_vulkan/blit_image.h
+++ b/src/video_core/renderer_vulkan/blit_image.h
@@ -10,6 +10,8 @@
10 10
11namespace Vulkan { 11namespace Vulkan {
12 12
13using VideoCommon::Extent3D;
14using VideoCommon::Offset2D;
13using VideoCommon::Region2D; 15using VideoCommon::Region2D;
14 16
15class Device; 17class Device;
@@ -36,6 +38,10 @@ public:
36 Tegra::Engines::Fermi2D::Filter filter, 38 Tegra::Engines::Fermi2D::Filter filter,
37 Tegra::Engines::Fermi2D::Operation operation); 39 Tegra::Engines::Fermi2D::Operation operation);
38 40
41 void BlitColor(const Framebuffer* dst_framebuffer, VkImageView src_image_view,
42 VkImage src_image, VkSampler src_sampler, const Region2D& dst_region,
43 const Region2D& src_region, const Extent3D& src_size);
44
39 void BlitDepthStencil(const Framebuffer* dst_framebuffer, VkImageView src_depth_view, 45 void BlitDepthStencil(const Framebuffer* dst_framebuffer, VkImageView src_depth_view,
40 VkImageView src_stencil_view, const Region2D& dst_region, 46 VkImageView src_stencil_view, const Region2D& dst_region,
41 const Region2D& src_region, Tegra::Engines::Fermi2D::Filter filter, 47 const Region2D& src_region, Tegra::Engines::Fermi2D::Filter filter,
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
index b75b8eec6..86ef0daeb 100644
--- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp
+++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
@@ -266,6 +266,35 @@ void RasterizerVulkan::DrawIndirect() {
266 buffer_cache.SetDrawIndirect(nullptr); 266 buffer_cache.SetDrawIndirect(nullptr);
267} 267}
268 268
269void RasterizerVulkan::DrawTexture() {
270 MICROPROFILE_SCOPE(Vulkan_Drawing);
271
272 SCOPE_EXIT({ gpu.TickWork(); });
273 FlushWork();
274
275 query_cache.UpdateCounters();
276
277 texture_cache.SynchronizeGraphicsDescriptors();
278 texture_cache.UpdateRenderTargets(false);
279
280 UpdateDynamicStates();
281
282 const auto& draw_texture_state = maxwell3d->draw_manager->GetDrawTextureState();
283 const auto& sampler = texture_cache.GetGraphicsSampler(draw_texture_state.src_sampler);
284 const auto& texture = texture_cache.GetImageView(draw_texture_state.src_texture);
285 Region2D dst_region = {Offset2D{.x = static_cast<s32>(draw_texture_state.dst_x0),
286 .y = static_cast<s32>(draw_texture_state.dst_y0)},
287 Offset2D{.x = static_cast<s32>(draw_texture_state.dst_x1),
288 .y = static_cast<s32>(draw_texture_state.dst_y1)}};
289 Region2D src_region = {Offset2D{.x = static_cast<s32>(draw_texture_state.src_x0),
290 .y = static_cast<s32>(draw_texture_state.src_y0)},
291 Offset2D{.x = static_cast<s32>(draw_texture_state.src_x1),
292 .y = static_cast<s32>(draw_texture_state.src_y1)}};
293 blit_image.BlitColor(texture_cache.GetFramebuffer(), texture.RenderTarget(),
294 texture.ImageHandle(), sampler->Handle(), dst_region, src_region,
295 texture.size);
296}
297
269void RasterizerVulkan::Clear(u32 layer_count) { 298void RasterizerVulkan::Clear(u32 layer_count) {
270 MICROPROFILE_SCOPE(Vulkan_Clearing); 299 MICROPROFILE_SCOPE(Vulkan_Clearing);
271 300
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.h b/src/video_core/renderer_vulkan/vk_rasterizer.h
index 472cc64d9..a0508b57c 100644
--- a/src/video_core/renderer_vulkan/vk_rasterizer.h
+++ b/src/video_core/renderer_vulkan/vk_rasterizer.h
@@ -66,6 +66,7 @@ public:
66 66
67 void Draw(bool is_indexed, u32 instance_count) override; 67 void Draw(bool is_indexed, u32 instance_count) override;
68 void DrawIndirect() override; 68 void DrawIndirect() override;
69 void DrawTexture() override;
69 void Clear(u32 layer_count) override; 70 void Clear(u32 layer_count) override;
70 void DispatchCompute() override; 71 void DispatchCompute() override;
71 void ResetCounter(VideoCore::QueryType type) override; 72 void ResetCounter(VideoCore::QueryType type) override;
diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h
index 87152c8e9..1b01990a4 100644
--- a/src/video_core/texture_cache/texture_cache.h
+++ b/src/video_core/texture_cache/texture_cache.h
@@ -149,6 +149,13 @@ typename P::ImageView& TextureCache<P>::GetImageView(ImageViewId id) noexcept {
149} 149}
150 150
151template <class P> 151template <class P>
152typename P::ImageView& TextureCache<P>::GetImageView(u32 index) noexcept {
153 const auto image_view_id = VisitImageView(channel_state->graphics_image_table,
154 channel_state->graphics_image_view_ids, index);
155 return slot_image_views[image_view_id];
156}
157
158template <class P>
152void TextureCache<P>::MarkModification(ImageId id) noexcept { 159void TextureCache<P>::MarkModification(ImageId id) noexcept {
153 MarkModification(slot_images[id]); 160 MarkModification(slot_images[id]);
154} 161}
diff --git a/src/video_core/texture_cache/texture_cache_base.h b/src/video_core/texture_cache/texture_cache_base.h
index 4eea1f609..485eaabaa 100644
--- a/src/video_core/texture_cache/texture_cache_base.h
+++ b/src/video_core/texture_cache/texture_cache_base.h
@@ -129,6 +129,9 @@ public:
129 /// Return a reference to the given image view id 129 /// Return a reference to the given image view id
130 [[nodiscard]] ImageView& GetImageView(ImageViewId id) noexcept; 130 [[nodiscard]] ImageView& GetImageView(ImageViewId id) noexcept;
131 131
132 /// Get the imageview from the graphics descriptor table in the specified index
133 [[nodiscard]] ImageView& GetImageView(u32 index) noexcept;
134
132 /// Mark an image as modified from the GPU 135 /// Mark an image as modified from the GPU
133 void MarkModification(ImageId id) noexcept; 136 void MarkModification(ImageId id) noexcept;
134 137
diff --git a/src/yuzu/configuration/configure_graphics.ui b/src/yuzu/configuration/configure_graphics.ui
index aa02cc63c..bb9910a53 100644
--- a/src/yuzu/configuration/configure_graphics.ui
+++ b/src/yuzu/configuration/configure_graphics.ui
@@ -366,6 +366,11 @@
366 </item> 366 </item>
367 <item> 367 <item>
368 <property name="text"> 368 <property name="text">
369 <string>1.5X (1080p/1620p) [EXPERIMENTAL]</string>
370 </property>
371 </item>
372 <item>
373 <property name="text">
369 <string>2X (1440p/2160p)</string> 374 <string>2X (1440p/2160p)</string>
370 </property> 375 </property>
371 </item> 376 </item>
@@ -389,6 +394,16 @@
389 <string>6X (4320p/6480p)</string> 394 <string>6X (4320p/6480p)</string>
390 </property> 395 </property>
391 </item> 396 </item>
397 <item>
398 <property name="text">
399 <string>7X (5040p/7560p)</string>
400 </property>
401 </item>
402 <item>
403 <property name="text">
404 <string>8X (5760p/8640p)</string>
405 </property>
406 </item>
392 </widget> 407 </widget>
393 </item> 408 </item>
394 </layout> 409 </layout>