aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpineappleEA <pineaea@gmail.com>2024-02-21 02:52:05 +0100
committerpineappleEA <pineaea@gmail.com>2024-02-21 02:52:05 +0100
commitb86c4f1e6680f971f0979c0544e7e20fa1145fa3 (patch)
tree057642926928c7b14c95082e56b8734318a79bb6
parent64bd48fad59e60a5fa48c8ce512fbe80ff532e90 (diff)
early-access version 4155EA-4155
-rwxr-xr-xREADME.md2
-rwxr-xr-xsrc/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/StringSetting.kt3
-rwxr-xr-xsrc/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt3
-rwxr-xr-xsrc/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/StringInputSetting.kt22
-rwxr-xr-xsrc/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsAdapter.kt13
-rwxr-xr-xsrc/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsDialogFragment.kt23
-rwxr-xr-xsrc/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt2
-rwxr-xr-xsrc/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/StringInputViewHolder.kt45
-rwxr-xr-xsrc/android/app/src/main/res/values/strings.xml1
-rwxr-xr-xsrc/core/hle/service/nvdrv/devices/nvhost_gpu.cpp7
-rwxr-xr-xsrc/core/hle/service/vi/shared_buffer_manager.cpp2
-rwxr-xr-xsrc/shader_recompiler/backend/spirv/emit_spirv.cpp4
-rwxr-xr-xsrc/shader_recompiler/backend/spirv/emit_spirv_special.cpp8
-rwxr-xr-xsrc/shader_recompiler/profile.h1
-rwxr-xr-xsrc/video_core/control/channel_state.h6
-rwxr-xr-xsrc/video_core/control/scheduler.cpp235
-rwxr-xr-xsrc/video_core/control/scheduler.h23
-rwxr-xr-xsrc/video_core/engines/puller.cpp12
-rwxr-xr-xsrc/video_core/gpu.cpp8
-rwxr-xr-xsrc/video_core/gpu.h9
-rwxr-xr-xsrc/video_core/gpu_thread.cpp14
-rwxr-xr-xsrc/video_core/gpu_thread.h9
-rwxr-xr-xsrc/video_core/renderer_vulkan/vk_pipeline_cache.cpp1
-rwxr-xr-xsrc/video_core/vulkan_common/vulkan_device.h5
24 files changed, 160 insertions, 298 deletions
diff --git a/README.md b/README.md
index cb98f7715..9370bfe1e 100755
--- a/README.md
+++ b/README.md
@@ -1,7 +1,7 @@
1yuzu emulator early access 1yuzu emulator early access
2============= 2=============
3 3
4This is the source code for early-access 4154. 4This is the source code for early-access 4155.
5 5
6## Legal Notice 6## Legal Notice
7 7
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/StringSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/StringSetting.kt
index a0d8cfede..6f16cf5b1 100755
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/StringSetting.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/StringSetting.kt
@@ -6,7 +6,8 @@ package org.yuzu.yuzu_emu.features.settings.model
6import org.yuzu.yuzu_emu.utils.NativeConfig 6import org.yuzu.yuzu_emu.utils.NativeConfig
7 7
8enum class StringSetting(override val key: String) : AbstractStringSetting { 8enum class StringSetting(override val key: String) : AbstractStringSetting {
9 DRIVER_PATH("driver_path"); 9 DRIVER_PATH("driver_path"),
10 DEVICE_NAME("device_name");
10 11
11 override fun getString(needsGlobal: Boolean): String = NativeConfig.getString(key, needsGlobal) 12 override fun getString(needsGlobal: Boolean): String = NativeConfig.getString(key, needsGlobal)
12 13
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt
index 03d81ceb3..5fdf98318 100755
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt
@@ -16,6 +16,7 @@ import org.yuzu.yuzu_emu.features.settings.model.ByteSetting
16import org.yuzu.yuzu_emu.features.settings.model.IntSetting 16import org.yuzu.yuzu_emu.features.settings.model.IntSetting
17import org.yuzu.yuzu_emu.features.settings.model.LongSetting 17import org.yuzu.yuzu_emu.features.settings.model.LongSetting
18import org.yuzu.yuzu_emu.features.settings.model.ShortSetting 18import org.yuzu.yuzu_emu.features.settings.model.ShortSetting
19import org.yuzu.yuzu_emu.features.settings.model.StringSetting
19import org.yuzu.yuzu_emu.utils.NativeConfig 20import org.yuzu.yuzu_emu.utils.NativeConfig
20 21
21/** 22/**
@@ -90,6 +91,7 @@ abstract class SettingsItem(
90 const val TYPE_INPUT = 8 91 const val TYPE_INPUT = 8
91 const val TYPE_INT_SINGLE_CHOICE = 9 92 const val TYPE_INT_SINGLE_CHOICE = 9
92 const val TYPE_INPUT_PROFILE = 10 93 const val TYPE_INPUT_PROFILE = 10
94 const val TYPE_STRING_INPUT = 11
93 95
94 const val FASTMEM_COMBINED = "fastmem_combined" 96 const val FASTMEM_COMBINED = "fastmem_combined"
95 97
@@ -108,6 +110,7 @@ abstract class SettingsItem(
108 110
109 // List of all general 111 // List of all general
110 val settingsItems = HashMap<String, SettingsItem>().apply { 112 val settingsItems = HashMap<String, SettingsItem>().apply {
113 put(StringInputSetting(StringSetting.DEVICE_NAME, titleId = R.string.device_name))
111 put( 114 put(
112 SwitchSetting( 115 SwitchSetting(
113 BooleanSetting.RENDERER_USE_SPEED_LIMIT, 116 BooleanSetting.RENDERER_USE_SPEED_LIMIT,
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/StringInputSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/StringInputSetting.kt
new file mode 100755
index 000000000..1eb999416
--- /dev/null
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/StringInputSetting.kt
@@ -0,0 +1,22 @@
1// SPDX-FileCopyrightText: 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4package org.yuzu.yuzu_emu.features.settings.model.view
5
6import androidx.annotation.StringRes
7import org.yuzu.yuzu_emu.features.settings.model.AbstractStringSetting
8
9class StringInputSetting(
10 setting: AbstractStringSetting,
11 @StringRes titleId: Int = 0,
12 titleString: String = "",
13 @StringRes descriptionId: Int = 0,
14 descriptionString: String = ""
15) : SettingsItem(setting, titleId, titleString, descriptionId, descriptionString) {
16 override val type = TYPE_STRING_INPUT
17
18 fun getSelectedValue(needsGlobal: Boolean = false) = setting.getValueAsString(needsGlobal)
19
20 fun setSelectedValue(selection: String) =
21 (setting as AbstractStringSetting).setString(selection)
22}
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsAdapter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsAdapter.kt
index 45c8faa10..500ac6e66 100755
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsAdapter.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsAdapter.kt
@@ -85,6 +85,10 @@ class SettingsAdapter(
85 InputProfileViewHolder(ListItemSettingBinding.inflate(inflater), this) 85 InputProfileViewHolder(ListItemSettingBinding.inflate(inflater), this)
86 } 86 }
87 87
88 SettingsItem.TYPE_STRING_INPUT -> {
89 StringInputViewHolder(ListItemSettingBinding.inflate(inflater), this)
90 }
91
88 else -> { 92 else -> {
89 HeaderViewHolder(ListItemSettingsHeaderBinding.inflate(inflater), this) 93 HeaderViewHolder(ListItemSettingsHeaderBinding.inflate(inflater), this)
90 } 94 }
@@ -392,6 +396,15 @@ class SettingsAdapter(
392 popup.show() 396 popup.show()
393 } 397 }
394 398
399 fun onStringInputClick(item: StringInputSetting, position: Int) {
400 SettingsDialogFragment.newInstance(
401 settingsViewModel,
402 item,
403 SettingsItem.TYPE_STRING_INPUT,
404 position
405 ).show(fragment.childFragmentManager, SettingsDialogFragment.TAG)
406 }
407
395 fun onLongClick(item: SettingsItem, position: Int): Boolean { 408 fun onLongClick(item: SettingsItem, position: Int): Boolean {
396 SettingsDialogFragment.newInstance( 409 SettingsDialogFragment.newInstance(
397 settingsViewModel, 410 settingsViewModel,
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsDialogFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsDialogFragment.kt
index a81ff6b1a..7f562a1f4 100755
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsDialogFragment.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsDialogFragment.kt
@@ -14,6 +14,7 @@ import androidx.fragment.app.activityViewModels
14import com.google.android.material.dialog.MaterialAlertDialogBuilder 14import com.google.android.material.dialog.MaterialAlertDialogBuilder
15import com.google.android.material.slider.Slider 15import com.google.android.material.slider.Slider
16import org.yuzu.yuzu_emu.R 16import org.yuzu.yuzu_emu.R
17import org.yuzu.yuzu_emu.databinding.DialogEditTextBinding
17import org.yuzu.yuzu_emu.databinding.DialogSliderBinding 18import org.yuzu.yuzu_emu.databinding.DialogSliderBinding
18import org.yuzu.yuzu_emu.features.input.NativeInput 19import org.yuzu.yuzu_emu.features.input.NativeInput
19import org.yuzu.yuzu_emu.features.input.model.AnalogDirection 20import org.yuzu.yuzu_emu.features.input.model.AnalogDirection
@@ -23,6 +24,7 @@ import org.yuzu.yuzu_emu.features.settings.model.view.IntSingleChoiceSetting
23import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem 24import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem
24import org.yuzu.yuzu_emu.features.settings.model.view.SingleChoiceSetting 25import org.yuzu.yuzu_emu.features.settings.model.view.SingleChoiceSetting
25import org.yuzu.yuzu_emu.features.settings.model.view.SliderSetting 26import org.yuzu.yuzu_emu.features.settings.model.view.SliderSetting
27import org.yuzu.yuzu_emu.features.settings.model.view.StringInputSetting
26import org.yuzu.yuzu_emu.features.settings.model.view.StringSingleChoiceSetting 28import org.yuzu.yuzu_emu.features.settings.model.view.StringSingleChoiceSetting
27import org.yuzu.yuzu_emu.utils.ParamPackage 29import org.yuzu.yuzu_emu.utils.ParamPackage
28import org.yuzu.yuzu_emu.utils.collect 30import org.yuzu.yuzu_emu.utils.collect
@@ -37,6 +39,7 @@ class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener
37 private val settingsViewModel: SettingsViewModel by activityViewModels() 39 private val settingsViewModel: SettingsViewModel by activityViewModels()
38 40
39 private lateinit var sliderBinding: DialogSliderBinding 41 private lateinit var sliderBinding: DialogSliderBinding
42 private lateinit var stringInputBinding: DialogEditTextBinding
40 43
41 override fun onCreate(savedInstanceState: Bundle?) { 44 override fun onCreate(savedInstanceState: Bundle?) {
42 super.onCreate(savedInstanceState) 45 super.onCreate(savedInstanceState)
@@ -131,6 +134,18 @@ class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener
131 .create() 134 .create()
132 } 135 }
133 136
137 SettingsItem.TYPE_STRING_INPUT -> {
138 stringInputBinding = DialogEditTextBinding.inflate(layoutInflater)
139 val item = settingsViewModel.clickedItem as StringInputSetting
140 stringInputBinding.editText.setText(item.getSelectedValue())
141 MaterialAlertDialogBuilder(requireContext())
142 .setTitle(item.title)
143 .setView(stringInputBinding.root)
144 .setPositiveButton(android.R.string.ok, this)
145 .setNegativeButton(android.R.string.cancel, defaultCancelListener)
146 .create()
147 }
148
134 SettingsItem.TYPE_STRING_SINGLE_CHOICE -> { 149 SettingsItem.TYPE_STRING_SINGLE_CHOICE -> {
135 val item = settingsViewModel.clickedItem as StringSingleChoiceSetting 150 val item = settingsViewModel.clickedItem as StringSingleChoiceSetting
136 MaterialAlertDialogBuilder(requireContext()) 151 MaterialAlertDialogBuilder(requireContext())
@@ -158,6 +173,7 @@ class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener
158 ): View? { 173 ): View? {
159 return when (type) { 174 return when (type) {
160 SettingsItem.TYPE_SLIDER -> sliderBinding.root 175 SettingsItem.TYPE_SLIDER -> sliderBinding.root
176 SettingsItem.TYPE_STRING_INPUT -> stringInputBinding.root
161 else -> super.onCreateView(inflater, container, savedInstanceState) 177 else -> super.onCreateView(inflater, container, savedInstanceState)
162 } 178 }
163 } 179 }
@@ -200,6 +216,13 @@ class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener
200 val sliderSetting = settingsViewModel.clickedItem as SliderSetting 216 val sliderSetting = settingsViewModel.clickedItem as SliderSetting
201 sliderSetting.setSelectedValue(settingsViewModel.sliderProgress.value) 217 sliderSetting.setSelectedValue(settingsViewModel.sliderProgress.value)
202 } 218 }
219
220 is StringInputSetting -> {
221 val stringInputSetting = settingsViewModel.clickedItem as StringInputSetting
222 stringInputSetting.setSelectedValue(
223 (stringInputBinding.editText.text ?: "").toString()
224 )
225 }
203 } 226 }
204 closeDialog() 227 closeDialog()
205 } 228 }
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt
index e491c29a2..6907bec02 100755
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt
@@ -23,6 +23,7 @@ import org.yuzu.yuzu_emu.features.settings.model.LongSetting
23import org.yuzu.yuzu_emu.features.settings.model.Settings 23import org.yuzu.yuzu_emu.features.settings.model.Settings
24import org.yuzu.yuzu_emu.features.settings.model.Settings.MenuTag 24import org.yuzu.yuzu_emu.features.settings.model.Settings.MenuTag
25import org.yuzu.yuzu_emu.features.settings.model.ShortSetting 25import org.yuzu.yuzu_emu.features.settings.model.ShortSetting
26import org.yuzu.yuzu_emu.features.settings.model.StringSetting
26import org.yuzu.yuzu_emu.features.settings.model.view.* 27import org.yuzu.yuzu_emu.features.settings.model.view.*
27import org.yuzu.yuzu_emu.utils.InputHandler 28import org.yuzu.yuzu_emu.utils.InputHandler
28import org.yuzu.yuzu_emu.utils.NativeConfig 29import org.yuzu.yuzu_emu.utils.NativeConfig
@@ -153,6 +154,7 @@ class SettingsFragmentPresenter(
153 154
154 private fun addSystemSettings(sl: ArrayList<SettingsItem>) { 155 private fun addSystemSettings(sl: ArrayList<SettingsItem>) {
155 sl.apply { 156 sl.apply {
157 add(StringSetting.DEVICE_NAME.key)
156 add(BooleanSetting.RENDERER_USE_SPEED_LIMIT.key) 158 add(BooleanSetting.RENDERER_USE_SPEED_LIMIT.key)
157 add(ShortSetting.RENDERER_SPEED_LIMIT.key) 159 add(ShortSetting.RENDERER_SPEED_LIMIT.key)
158 add(BooleanSetting.USE_DOCKED_MODE.key) 160 add(BooleanSetting.USE_DOCKED_MODE.key)
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/StringInputViewHolder.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/StringInputViewHolder.kt
new file mode 100755
index 000000000..a4fd36f62
--- /dev/null
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/StringInputViewHolder.kt
@@ -0,0 +1,45 @@
1// SPDX-FileCopyrightText: 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4package org.yuzu.yuzu_emu.features.settings.ui.viewholder
5
6import android.view.View
7import org.yuzu.yuzu_emu.databinding.ListItemSettingBinding
8import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem
9import org.yuzu.yuzu_emu.features.settings.model.view.StringInputSetting
10import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter
11import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
12
13class StringInputViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAdapter) :
14 SettingViewHolder(binding.root, adapter) {
15 private lateinit var setting: StringInputSetting
16
17 override fun bind(item: SettingsItem) {
18 setting = item as StringInputSetting
19 binding.textSettingName.text = setting.title
20 binding.textSettingDescription.setVisible(setting.description.isNotEmpty())
21 binding.textSettingDescription.text = setting.description
22 binding.textSettingValue.setVisible(true)
23 binding.textSettingValue.text = setting.getSelectedValue()
24
25 binding.buttonClear.setVisible(setting.clearable)
26 binding.buttonClear.setOnClickListener {
27 adapter.onClearClick(setting, bindingAdapterPosition)
28 }
29
30 setStyle(setting.isEditable, binding)
31 }
32
33 override fun onClick(clicked: View) {
34 if (setting.isEditable) {
35 adapter.onStringInputClick(setting, bindingAdapterPosition)
36 }
37 }
38
39 override fun onLongClick(clicked: View): Boolean {
40 if (setting.isEditable) {
41 return adapter.onLongClick(setting, bindingAdapterPosition)
42 }
43 return false
44 }
45}
diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml
index 6a631f664..f7f19cdad 100755
--- a/src/android/app/src/main/res/values/strings.xml
+++ b/src/android/app/src/main/res/values/strings.xml
@@ -209,6 +209,7 @@
209 <string name="value_with_units">%1$s%2$s</string> 209 <string name="value_with_units">%1$s%2$s</string>
210 210
211 <!-- System settings strings --> 211 <!-- System settings strings -->
212 <string name="device_name">Device name</string>
212 <string name="use_docked_mode">Docked Mode</string> 213 <string name="use_docked_mode">Docked Mode</string>
213 <string name="use_docked_mode_description">Increases resolution, decreasing performance. Handheld Mode is used when disabled, lowering resolution and increasing performance.</string> 214 <string name="use_docked_mode_description">Increases resolution, decreasing performance. Handheld Mode is used when disabled, lowering resolution and increasing performance.</string>
214 <string name="emulated_region">Emulated region</string> 215 <string name="emulated_region">Emulated region</string>
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
index f537fb203..e71c58aa9 100755
--- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
@@ -13,7 +13,6 @@
13#include "core/hle/service/nvdrv/nvdrv.h" 13#include "core/hle/service/nvdrv/nvdrv.h"
14#include "core/memory.h" 14#include "core/memory.h"
15#include "video_core/control/channel_state.h" 15#include "video_core/control/channel_state.h"
16#include "video_core/control/scheduler.h"
17#include "video_core/engines/puller.h" 16#include "video_core/engines/puller.h"
18#include "video_core/gpu.h" 17#include "video_core/gpu.h"
19#include "video_core/host1x/host1x.h" 18#include "video_core/host1x/host1x.h"
@@ -34,7 +33,6 @@ nvhost_gpu::nvhost_gpu(Core::System& system_, EventInterface& events_interface_,
34 syncpoint_manager{core_.GetSyncpointManager()}, nvmap{core.GetNvMapFile()}, 33 syncpoint_manager{core_.GetSyncpointManager()}, nvmap{core.GetNvMapFile()},
35 channel_state{system.GPU().AllocateChannel()} { 34 channel_state{system.GPU().AllocateChannel()} {
36 channel_syncpoint = syncpoint_manager.AllocateSyncpoint(false); 35 channel_syncpoint = syncpoint_manager.AllocateSyncpoint(false);
37 channel_state->syncpoint_id = channel_syncpoint;
38 sm_exception_breakpoint_int_report_event = 36 sm_exception_breakpoint_int_report_event =
39 events_interface.CreateEvent("GpuChannelSMExceptionBreakpointInt"); 37 events_interface.CreateEvent("GpuChannelSMExceptionBreakpointInt");
40 sm_exception_breakpoint_pause_report_event = 38 sm_exception_breakpoint_pause_report_event =
@@ -159,9 +157,6 @@ NvResult nvhost_gpu::SetErrorNotifier(IoctlSetErrorNotifier& params) {
159 157
160NvResult nvhost_gpu::SetChannelPriority(IoctlChannelSetPriority& params) { 158NvResult nvhost_gpu::SetChannelPriority(IoctlChannelSetPriority& params) {
161 channel_priority = params.priority; 159 channel_priority = params.priority;
162 if (channel_state->initialized) {
163 system.GPU().Scheduler().ChangePriority(channel_state->bind_id, channel_priority);
164 }
165 LOG_DEBUG(Service_NVDRV, "(STUBBED) called, priority={:X}", channel_priority); 160 LOG_DEBUG(Service_NVDRV, "(STUBBED) called, priority={:X}", channel_priority);
166 return NvResult::Success; 161 return NvResult::Success;
167} 162}
@@ -319,7 +314,6 @@ NvResult nvhost_gpu::GetWaitbase(IoctlGetWaitbase& params) {
319NvResult nvhost_gpu::ChannelSetTimeout(IoctlChannelSetTimeout& params) { 314NvResult nvhost_gpu::ChannelSetTimeout(IoctlChannelSetTimeout& params) {
320 LOG_INFO(Service_NVDRV, "called, timeout=0x{:X}", params.timeout); 315 LOG_INFO(Service_NVDRV, "called, timeout=0x{:X}", params.timeout);
321 316
322 channel_state->timeout = params.timeout;
323 return NvResult::Success; 317 return NvResult::Success;
324} 318}
325 319
@@ -327,7 +321,6 @@ NvResult nvhost_gpu::ChannelSetTimeslice(IoctlSetTimeslice& params) {
327 LOG_INFO(Service_NVDRV, "called, timeslice=0x{:X}", params.timeslice); 321 LOG_INFO(Service_NVDRV, "called, timeslice=0x{:X}", params.timeslice);
328 322
329 channel_timeslice = params.timeslice; 323 channel_timeslice = params.timeslice;
330 channel_state->timeslice = params.timeslice;
331 324
332 return NvResult::Success; 325 return NvResult::Success;
333} 326}
diff --git a/src/core/hle/service/vi/shared_buffer_manager.cpp b/src/core/hle/service/vi/shared_buffer_manager.cpp
index 3c0507d30..12cba16fa 100755
--- a/src/core/hle/service/vi/shared_buffer_manager.cpp
+++ b/src/core/hle/service/vi/shared_buffer_manager.cpp
@@ -285,7 +285,7 @@ void SharedBufferManager::DestroySession(Kernel::KProcess* owner_process) {
285 auto& session = it->second; 285 auto& session = it->second;
286 286
287 // Destroy the layer. 287 // Destroy the layer.
288 R_ASSERT(m_container.DestroyStrayLayer(session.layer_id)); 288 m_container.DestroyStrayLayer(session.layer_id);
289 289
290 // Close nvmap handle. 290 // Close nvmap handle.
291 FreeHandle(session.buffer_nvmap_handle, *m_nvdrv, session.nvmap_fd); 291 FreeHandle(session.buffer_nvmap_handle, *m_nvdrv, session.nvmap_fd);
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv.cpp b/src/shader_recompiler/backend/spirv/emit_spirv.cpp
index b8ecffb8e..476418aa3 100755
--- a/src/shader_recompiler/backend/spirv/emit_spirv.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_spirv.cpp
@@ -261,7 +261,9 @@ void DefineEntryPoint(const IR::Program& program, EmitContext& ctx, Id main) {
261 case Stage::Geometry: 261 case Stage::Geometry:
262 execution_model = spv::ExecutionModel::Geometry; 262 execution_model = spv::ExecutionModel::Geometry;
263 ctx.AddCapability(spv::Capability::Geometry); 263 ctx.AddCapability(spv::Capability::Geometry);
264 ctx.AddCapability(spv::Capability::GeometryStreams); 264 if (ctx.profile.support_geometry_streams) {
265 ctx.AddCapability(spv::Capability::GeometryStreams);
266 }
265 switch (ctx.runtime_info.input_topology) { 267 switch (ctx.runtime_info.input_topology) {
266 case InputTopology::Points: 268 case InputTopology::Points:
267 ctx.AddExecutionMode(main, spv::ExecutionMode::InputPoints); 269 ctx.AddExecutionMode(main, spv::ExecutionMode::InputPoints);
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_special.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_special.cpp
index 67bf5dc9f..f4c1ebba6 100755
--- a/src/shader_recompiler/backend/spirv/emit_spirv_special.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_special.cpp
@@ -129,7 +129,9 @@ void EmitEmitVertex(EmitContext& ctx, const IR::Value& stream) {
129 if (ctx.runtime_info.convert_depth_mode && !ctx.profile.support_native_ndc) { 129 if (ctx.runtime_info.convert_depth_mode && !ctx.profile.support_native_ndc) {
130 ConvertDepthMode(ctx); 130 ConvertDepthMode(ctx);
131 } 131 }
132 if (stream.IsImmediate()) { 132 if (!ctx.profile.support_geometry_streams) {
133 throw NotImplementedException("Geometry streams");
134 } else if (stream.IsImmediate()) {
133 ctx.OpEmitStreamVertex(ctx.Def(stream)); 135 ctx.OpEmitStreamVertex(ctx.Def(stream));
134 } else { 136 } else {
135 LOG_WARNING(Shader_SPIRV, "Stream is not immediate"); 137 LOG_WARNING(Shader_SPIRV, "Stream is not immediate");
@@ -140,7 +142,9 @@ void EmitEmitVertex(EmitContext& ctx, const IR::Value& stream) {
140} 142}
141 143
142void EmitEndPrimitive(EmitContext& ctx, const IR::Value& stream) { 144void EmitEndPrimitive(EmitContext& ctx, const IR::Value& stream) {
143 if (stream.IsImmediate()) { 145 if (!ctx.profile.support_geometry_streams) {
146 throw NotImplementedException("Geometry streams");
147 } else if (stream.IsImmediate()) {
144 ctx.OpEndStreamPrimitive(ctx.Def(stream)); 148 ctx.OpEndStreamPrimitive(ctx.Def(stream));
145 } else { 149 } else {
146 LOG_WARNING(Shader_SPIRV, "Stream is not immediate"); 150 LOG_WARNING(Shader_SPIRV, "Stream is not immediate");
diff --git a/src/shader_recompiler/profile.h b/src/shader_recompiler/profile.h
index 70ea46bb2..19089775d 100755
--- a/src/shader_recompiler/profile.h
+++ b/src/shader_recompiler/profile.h
@@ -44,6 +44,7 @@ struct Profile {
44 bool support_gl_derivative_control{}; 44 bool support_gl_derivative_control{};
45 bool support_scaled_attributes{}; 45 bool support_scaled_attributes{};
46 bool support_multi_viewport{}; 46 bool support_multi_viewport{};
47 bool support_geometry_streams{};
47 48
48 bool warp_size_potentially_larger_than_guest{}; 49 bool warp_size_potentially_larger_than_guest{};
49 50
diff --git a/src/video_core/control/channel_state.h b/src/video_core/control/channel_state.h
index 9f9b4ff75..ceaa92647 100755
--- a/src/video_core/control/channel_state.h
+++ b/src/video_core/control/channel_state.h
@@ -45,12 +45,6 @@ struct ChannelState {
45 void BindRasterizer(VideoCore::RasterizerInterface* rasterizer); 45 void BindRasterizer(VideoCore::RasterizerInterface* rasterizer);
46 46
47 s32 bind_id = -1; 47 s32 bind_id = -1;
48 /// Scheduling info
49 u32 syncpoint_id = 0xFFFF;
50 u32 priority = 0;
51 u32 timeslice = 0;
52 u32 timeout = 0;
53
54 /// 3D engine 48 /// 3D engine
55 std::unique_ptr<Engines::Maxwell3D> maxwell_3d; 49 std::unique_ptr<Engines::Maxwell3D> maxwell_3d;
56 /// 2D engine 50 /// 2D engine
diff --git a/src/video_core/control/scheduler.cpp b/src/video_core/control/scheduler.cpp
index f57efd189..31e3b1235 100755
--- a/src/video_core/control/scheduler.cpp
+++ b/src/video_core/control/scheduler.cpp
@@ -1,245 +1,32 @@
1// SPDX-FileCopyrightText: 2021 yuzu Emulator Project 1// SPDX-FileCopyrightText: 2021 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later 2// SPDX-License-Identifier: GPL-3.0-or-later
3 3
4#include <atomic>
5#include <deque>
6#include <map>
7#include <memory> 4#include <memory>
8#include <mutex>
9#include <unordered_map>
10#include <utility>
11 5
12#include "common/assert.h" 6#include "common/assert.h"
13#include "common/fiber.h" 7#include "video_core/control/channel_state.h"
14#include "video_core/control/scheduler.h" 8#include "video_core/control/scheduler.h"
15#include "video_core/dma_pusher.h"
16#include "video_core/gpu.h" 9#include "video_core/gpu.h"
17 10
18namespace Tegra::Control { 11namespace Tegra::Control {
19 12Scheduler::Scheduler(GPU& gpu_) : gpu{gpu_} {}
20struct GPFifoContext {
21 bool is_active;
22 bool is_running;
23 std::shared_ptr<Common::Fiber> context;
24 std::deque<CommandList> pending_work;
25 std::mutex guard;
26 s32 bind_id;
27 std::shared_ptr<ChannelState> info;
28 size_t yield_count;
29 size_t scheduled_count;
30};
31
32struct Scheduler::SchedulerImpl {
33 // Fifos
34 std::map<u32, std::list<size_t>, std::greater<u32>> schedule_priority_queue;
35 std::unordered_map<s32, size_t> channel_gpfifo_ids;
36 std::deque<GPFifoContext> gpfifos;
37 std::deque<size_t> free_fifos;
38
39 // Scheduling
40 std::mutex scheduling_guard;
41 std::shared_ptr<Common::Fiber> master_control;
42 bool must_reschedule{};
43 GPFifoContext* current_fifo{};
44};
45
46Scheduler::Scheduler(GPU& gpu_) : gpu{gpu_} {
47 impl = std::make_unique<SchedulerImpl>();
48}
49 13
50Scheduler::~Scheduler() = default; 14Scheduler::~Scheduler() = default;
51 15
52void Scheduler::Init() {
53 impl->master_control = Common::Fiber::ThreadToFiber();
54}
55
56void Scheduler::Resume() {
57 while (UpdateHighestPriorityChannel()) {
58 impl->current_fifo->scheduled_count++;
59 Common::Fiber::YieldTo(impl->master_control, *impl->current_fifo->context);
60 }
61}
62
63bool Scheduler::UpdateHighestPriorityChannel() {
64 std::scoped_lock lk(impl->scheduling_guard);
65
66 // Clear needs to schedule state.
67 impl->must_reschedule = false;
68
69 // By default, we don't have a channel to schedule.
70 impl->current_fifo = nullptr;
71
72 // Check each level to see if we can schedule.
73 for (auto& level : impl->schedule_priority_queue) {
74 if (ScheduleLevel(level.second)) {
75 return true;
76 }
77 }
78
79 // Nothing to schedule.
80 return false;
81}
82
83bool Scheduler::ScheduleLevel(std::list<size_t>& queue) {
84 bool found_anything = false;
85 size_t min_schedule_count = std::numeric_limits<size_t>::max();
86 for (auto id : queue) {
87 auto& fifo = impl->gpfifos[id];
88 std::scoped_lock lk(fifo.guard);
89
90 // With no pending work and nothing running, this channel can't be scheduled.
91 if (fifo.pending_work.empty() && !fifo.is_running) {
92 continue;
93 }
94 // Prioritize channels at current priority which have been run the least.
95 if (fifo.scheduled_count > min_schedule_count) {
96 continue;
97 }
98
99 // Try not to select the same channel we just yielded from.
100 if (fifo.scheduled_count < fifo.yield_count) {
101 fifo.scheduled_count++;
102 continue;
103 }
104
105 // Update best selection.
106 min_schedule_count = fifo.scheduled_count;
107 impl->current_fifo = &fifo;
108 found_anything = true;
109 }
110 return found_anything;
111}
112
113void Scheduler::ChangePriority(s32 channel_id, u32 new_priority) {
114 std::scoped_lock lk(impl->scheduling_guard);
115 // Ensure we are tracking this channel.
116 auto fifo_it = impl->channel_gpfifo_ids.find(channel_id);
117 if (fifo_it == impl->channel_gpfifo_ids.end()) {
118 return;
119 }
120
121 // Get the fifo and update its priority.
122 const size_t fifo_id = fifo_it->second;
123 auto& fifo = impl->gpfifos[fifo_id];
124 const auto old_priority = std::exchange(fifo.info->priority, new_priority);
125
126 // Create the new level if needed.
127 impl->schedule_priority_queue.try_emplace(new_priority);
128
129 // Remove the old level and add to the new level.
130 impl->schedule_priority_queue[new_priority].push_back(fifo_id);
131 impl->schedule_priority_queue[old_priority].remove_if(
132 [fifo_id](size_t id) { return id == fifo_id; });
133}
134
135void Scheduler::Yield() {
136 ASSERT(impl->current_fifo != nullptr);
137
138 // Set yield count higher
139 impl->current_fifo->yield_count = impl->current_fifo->scheduled_count + 1;
140 Common::Fiber::YieldTo(impl->current_fifo->context, *impl->master_control);
141 gpu.BindChannel(impl->current_fifo->bind_id);
142}
143
144void Scheduler::CheckStatus() {
145 {
146 std::unique_lock lk(impl->scheduling_guard);
147 // If no reschedule is needed, don't transfer control
148 if (!impl->must_reschedule) {
149 return;
150 }
151 }
152 // Transfer control to the scheduler
153 Common::Fiber::YieldTo(impl->current_fifo->context, *impl->master_control);
154 gpu.BindChannel(impl->current_fifo->bind_id);
155}
156
157void Scheduler::Push(s32 channel, CommandList&& entries) { 16void Scheduler::Push(s32 channel, CommandList&& entries) {
158 std::scoped_lock lk(impl->scheduling_guard); 17 std::unique_lock lk(scheduling_guard);
159 // Get and ensure we have this channel. 18 auto it = channels.find(channel);
160 auto it = impl->channel_gpfifo_ids.find(channel); 19 ASSERT(it != channels.end());
161 ASSERT(it != impl->channel_gpfifo_ids.end()); 20 auto channel_state = it->second;
162 auto gpfifo_id = it->second; 21 gpu.BindChannel(channel_state->bind_id);
163 auto& fifo = impl->gpfifos[gpfifo_id]; 22 channel_state->dma_pusher->Push(std::move(entries));
164 // Add the new new work to the channel. 23 channel_state->dma_pusher->DispatchCalls();
165 {
166 std::scoped_lock lk2(fifo.guard);
167 fifo.pending_work.emplace_back(std::move(entries));
168 }
169
170 // If the current running FIFO is null or the one being pushed to then
171 // just return
172 if (impl->current_fifo == nullptr || impl->current_fifo == &fifo) {
173 return;
174 }
175
176 // If the current fifo has higher or equal priority to the current fifo then return
177 if (impl->current_fifo->info->priority >= fifo.info->priority) {
178 return;
179 }
180 // Mark scheduler update as required.
181 impl->must_reschedule = true;
182}
183
184void Scheduler::ChannelLoop(size_t gpfifo_id, s32 channel_id) {
185 auto& fifo = impl->gpfifos[gpfifo_id];
186 auto* channel_state = fifo.info.get();
187 const auto SendToPuller = [&] {
188 std::scoped_lock lk(fifo.guard);
189 if (fifo.pending_work.empty()) {
190 // Stop if no work available.
191 fifo.is_running = false;
192 return false;
193 }
194 // Otherwise, send work to puller and mark as running.
195 CommandList&& entries = std::move(fifo.pending_work.front());
196 channel_state->dma_pusher->Push(std::move(entries));
197 fifo.pending_work.pop_front();
198 fifo.is_running = true;
199 // Succeed.
200 return true;
201 };
202 // Inform the GPU about the current channel.
203 gpu.BindChannel(channel_id);
204 while (true) {
205 while (SendToPuller()) {
206 // Execute.
207 channel_state->dma_pusher->DispatchCalls();
208 // Reschedule.
209 CheckStatus();
210 }
211 // Return to host execution when all work is completed.
212 Common::Fiber::YieldTo(fifo.context, *impl->master_control);
213 // Inform the GPU about the current channel.
214 gpu.BindChannel(channel_id);
215 }
216} 24}
217 25
218void Scheduler::DeclareChannel(std::shared_ptr<ChannelState> new_channel) { 26void Scheduler::DeclareChannel(std::shared_ptr<ChannelState> new_channel) {
219 s32 channel = new_channel->bind_id; 27 s32 channel = new_channel->bind_id;
220 std::unique_lock lk(impl->scheduling_guard); 28 std::unique_lock lk(scheduling_guard);
221 29 channels.emplace(channel, new_channel);
222 size_t new_fifo_id;
223 if (!impl->free_fifos.empty()) {
224 new_fifo_id = impl->free_fifos.front();
225 impl->free_fifos.pop_front();
226 } else {
227 new_fifo_id = impl->gpfifos.size();
228 impl->gpfifos.emplace_back();
229 }
230 auto& new_fifo = impl->gpfifos[new_fifo_id];
231 impl->channel_gpfifo_ids[channel] = new_fifo_id;
232 new_fifo.is_active = true;
233 new_fifo.bind_id = channel;
234 new_fifo.pending_work.clear();
235 new_fifo.info = new_channel;
236 new_fifo.scheduled_count = 0;
237 new_fifo.yield_count = 0;
238 new_fifo.is_running = false;
239 impl->schedule_priority_queue.try_emplace(new_channel->priority);
240 impl->schedule_priority_queue[new_channel->priority].push_back(new_fifo_id);
241 std::function<void()> callback = std::bind(&Scheduler::ChannelLoop, this, new_fifo_id, channel);
242 new_fifo.context = std::make_shared<Common::Fiber>(std::move(callback));
243} 30}
244 31
245} // namespace Tegra::Control 32} // namespace Tegra::Control
diff --git a/src/video_core/control/scheduler.h b/src/video_core/control/scheduler.h
index 9b5620499..eab52e536 100755
--- a/src/video_core/control/scheduler.h
+++ b/src/video_core/control/scheduler.h
@@ -3,11 +3,10 @@
3 3
4#pragma once 4#pragma once
5 5
6#include <list>
7#include <memory> 6#include <memory>
7#include <mutex>
8#include <unordered_map>
8 9
9#include "common/common_types.h"
10#include "video_core/control/channel_state.h"
11#include "video_core/dma_pusher.h" 10#include "video_core/dma_pusher.h"
12 11
13namespace Tegra { 12namespace Tegra {
@@ -23,27 +22,13 @@ public:
23 explicit Scheduler(GPU& gpu_); 22 explicit Scheduler(GPU& gpu_);
24 ~Scheduler(); 23 ~Scheduler();
25 24
26 void Init();
27
28 void Resume();
29
30 void Yield();
31
32 void Push(s32 channel, CommandList&& entries); 25 void Push(s32 channel, CommandList&& entries);
33 26
34 void DeclareChannel(std::shared_ptr<ChannelState> new_channel); 27 void DeclareChannel(std::shared_ptr<ChannelState> new_channel);
35 28
36 void ChangePriority(s32 channel_id, u32 new_priority);
37
38private: 29private:
39 void ChannelLoop(size_t gpfifo_id, s32 channel_id); 30 std::unordered_map<s32, std::shared_ptr<ChannelState>> channels;
40 bool ScheduleLevel(std::list<size_t>& queue); 31 std::mutex scheduling_guard;
41 void CheckStatus();
42 bool UpdateHighestPriorityChannel();
43
44 struct SchedulerImpl;
45 std::unique_ptr<SchedulerImpl> impl;
46
47 GPU& gpu; 32 GPU& gpu;
48}; 33};
49 34
diff --git a/src/video_core/engines/puller.cpp b/src/video_core/engines/puller.cpp
index c39cada43..79d84d662 100755
--- a/src/video_core/engines/puller.cpp
+++ b/src/video_core/engines/puller.cpp
@@ -6,7 +6,6 @@
6#include "common/settings.h" 6#include "common/settings.h"
7#include "core/core.h" 7#include "core/core.h"
8#include "video_core/control/channel_state.h" 8#include "video_core/control/channel_state.h"
9#include "video_core/control/scheduler.h"
10#include "video_core/dma_pusher.h" 9#include "video_core/dma_pusher.h"
11#include "video_core/engines/fermi_2d.h" 10#include "video_core/engines/fermi_2d.h"
12#include "video_core/engines/kepler_compute.h" 11#include "video_core/engines/kepler_compute.h"
@@ -15,8 +14,6 @@
15#include "video_core/engines/maxwell_dma.h" 14#include "video_core/engines/maxwell_dma.h"
16#include "video_core/engines/puller.h" 15#include "video_core/engines/puller.h"
17#include "video_core/gpu.h" 16#include "video_core/gpu.h"
18#include "video_core/host1x/host1x.h"
19#include "video_core/host1x/syncpoint_manager.h"
20#include "video_core/memory_manager.h" 17#include "video_core/memory_manager.h"
21#include "video_core/rasterizer_interface.h" 18#include "video_core/rasterizer_interface.h"
22 19
@@ -63,14 +60,11 @@ void Puller::ProcessBindMethod(const MethodCall& method_call) {
63} 60}
64 61
65void Puller::ProcessFenceActionMethod() { 62void Puller::ProcessFenceActionMethod() {
66 auto& syncpoint_manager = gpu.Host1x().GetSyncpointManager();
67 switch (regs.fence_action.op) { 63 switch (regs.fence_action.op) {
68 case Puller::FenceOperation::Acquire: 64 case Puller::FenceOperation::Acquire:
69 while (regs.fence_value > 65 // UNIMPLEMENTED_MSG("Channel Scheduling pending.");
70 syncpoint_manager.GetGuestSyncpointValue(regs.fence_action.syncpoint_id)) { 66 // WaitFence(regs.fence_action.syncpoint_id, regs.fence_value);
71 rasterizer->ReleaseFences(); 67 rasterizer->ReleaseFences();
72 gpu.Scheduler().Yield();
73 }
74 break; 68 break;
75 case Puller::FenceOperation::Increment: 69 case Puller::FenceOperation::Increment:
76 rasterizer->SignalSyncPoint(regs.fence_action.syncpoint_id); 70 rasterizer->SignalSyncPoint(regs.fence_action.syncpoint_id);
diff --git a/src/video_core/gpu.cpp b/src/video_core/gpu.cpp
index f45f797b3..59356015b 100755
--- a/src/video_core/gpu.cpp
+++ b/src/video_core/gpu.cpp
@@ -387,14 +387,6 @@ std::shared_ptr<Control::ChannelState> GPU::AllocateChannel() {
387 return impl->AllocateChannel(); 387 return impl->AllocateChannel();
388} 388}
389 389
390Tegra::Control::Scheduler& GPU::Scheduler() {
391 return *impl->scheduler;
392}
393
394const Tegra::Control::Scheduler& GPU::Scheduler() const {
395 return *impl->scheduler;
396}
397
398void GPU::InitChannel(Control::ChannelState& to_init) { 390void GPU::InitChannel(Control::ChannelState& to_init) {
399 impl->InitChannel(to_init); 391 impl->InitChannel(to_init);
400} 392}
diff --git a/src/video_core/gpu.h b/src/video_core/gpu.h
index 154466f23..25c75a109 100755
--- a/src/video_core/gpu.h
+++ b/src/video_core/gpu.h
@@ -124,8 +124,7 @@ class KeplerCompute;
124 124
125namespace Control { 125namespace Control {
126struct ChannelState; 126struct ChannelState;
127class Scheduler; 127}
128} // namespace Control
129 128
130namespace Host1x { 129namespace Host1x {
131class Host1x; 130class Host1x;
@@ -205,12 +204,6 @@ public:
205 /// Returns a const reference to the shader notifier. 204 /// Returns a const reference to the shader notifier.
206 [[nodiscard]] const VideoCore::ShaderNotify& ShaderNotify() const; 205 [[nodiscard]] const VideoCore::ShaderNotify& ShaderNotify() const;
207 206
208 /// Returns GPU Channel Scheduler.
209 [[nodiscard]] Tegra::Control::Scheduler& Scheduler();
210
211 /// Returns GPU Channel Scheduler.
212 [[nodiscard]] const Tegra::Control::Scheduler& Scheduler() const;
213
214 [[nodiscard]] u64 GetTicks() const; 207 [[nodiscard]] u64 GetTicks() const;
215 208
216 [[nodiscard]] bool IsAsync() const; 209 [[nodiscard]] bool IsAsync() const;
diff --git a/src/video_core/gpu_thread.cpp b/src/video_core/gpu_thread.cpp
index 7decd2826..1b1b27768 100755
--- a/src/video_core/gpu_thread.cpp
+++ b/src/video_core/gpu_thread.cpp
@@ -36,15 +36,13 @@ static void RunThread(std::stop_token stop_token, Core::System& system,
36 36
37 CommandDataContainer next; 37 CommandDataContainer next;
38 38
39 scheduler.Init();
40
41 while (!stop_token.stop_requested()) { 39 while (!stop_token.stop_requested()) {
42 state.queue.PopWait(next, stop_token); 40 state.queue.PopWait(next, stop_token);
43 if (stop_token.stop_requested()) { 41 if (stop_token.stop_requested()) {
44 break; 42 break;
45 } 43 }
46 if (std::holds_alternative<SubmitListCommand>(next.data)) { 44 if (auto* submit_list = std::get_if<SubmitListCommand>(&next.data)) {
47 scheduler.Resume(); 45 scheduler.Push(submit_list->channel, std::move(submit_list->entries));
48 } else if (std::holds_alternative<GPUTickCommand>(next.data)) { 46 } else if (std::holds_alternative<GPUTickCommand>(next.data)) {
49 system.GPU().TickWork(); 47 system.GPU().TickWork();
50 } else if (const auto* flush = std::get_if<FlushRegionCommand>(&next.data)) { 48 } else if (const auto* flush = std::get_if<FlushRegionCommand>(&next.data)) {
@@ -71,16 +69,14 @@ ThreadManager::~ThreadManager() = default;
71 69
72void ThreadManager::StartThread(VideoCore::RendererBase& renderer, 70void ThreadManager::StartThread(VideoCore::RendererBase& renderer,
73 Core::Frontend::GraphicsContext& context, 71 Core::Frontend::GraphicsContext& context,
74 Tegra::Control::Scheduler& scheduler_) { 72 Tegra::Control::Scheduler& scheduler) {
75 rasterizer = renderer.ReadRasterizer(); 73 rasterizer = renderer.ReadRasterizer();
76 scheduler = &scheduler_;
77 thread = std::jthread(RunThread, std::ref(system), std::ref(renderer), std::ref(context), 74 thread = std::jthread(RunThread, std::ref(system), std::ref(renderer), std::ref(context),
78 std::ref(scheduler_), std::ref(state)); 75 std::ref(scheduler), std::ref(state));
79} 76}
80 77
81void ThreadManager::SubmitList(s32 channel, Tegra::CommandList&& entries) { 78void ThreadManager::SubmitList(s32 channel, Tegra::CommandList&& entries) {
82 scheduler->Push(channel, std::move(entries)); 79 PushCommand(SubmitListCommand(channel, std::move(entries)));
83 PushCommand(SubmitListCommand());
84} 80}
85 81
86void ThreadManager::FlushRegion(DAddr addr, u64 size) { 82void ThreadManager::FlushRegion(DAddr addr, u64 size) {
diff --git a/src/video_core/gpu_thread.h b/src/video_core/gpu_thread.h
index a4b01c42a..1a0de86b5 100755
--- a/src/video_core/gpu_thread.h
+++ b/src/video_core/gpu_thread.h
@@ -36,7 +36,13 @@ class RendererBase;
36namespace VideoCommon::GPUThread { 36namespace VideoCommon::GPUThread {
37 37
38/// Command to signal to the GPU thread that a command list is ready for processing 38/// Command to signal to the GPU thread that a command list is ready for processing
39struct SubmitListCommand final {}; 39struct SubmitListCommand final {
40 explicit SubmitListCommand(s32 channel_, Tegra::CommandList&& entries_)
41 : channel{channel_}, entries{std::move(entries_)} {}
42
43 s32 channel;
44 Tegra::CommandList entries;
45};
40 46
41/// Command to signal to the GPU thread to flush a region 47/// Command to signal to the GPU thread to flush a region
42struct FlushRegionCommand final { 48struct FlushRegionCommand final {
@@ -118,7 +124,6 @@ public:
118private: 124private:
119 /// Pushes a command to be executed by the GPU thread 125 /// Pushes a command to be executed by the GPU thread
120 u64 PushCommand(CommandData&& command_data, bool block = false); 126 u64 PushCommand(CommandData&& command_data, bool block = false);
121 Tegra::Control::Scheduler* scheduler;
122 127
123 Core::System& system; 128 Core::System& system;
124 const bool is_async; 129 const bool is_async;
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
index e5e90c069..a391aaae5 100755
--- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
@@ -352,6 +352,7 @@ PipelineCache::PipelineCache(Tegra::MaxwellDeviceMemoryManager& device_memory_,
352 .support_native_ndc = device.IsExtDepthClipControlSupported(), 352 .support_native_ndc = device.IsExtDepthClipControlSupported(),
353 .support_scaled_attributes = !device.MustEmulateScaledFormats(), 353 .support_scaled_attributes = !device.MustEmulateScaledFormats(),
354 .support_multi_viewport = device.SupportsMultiViewport(), 354 .support_multi_viewport = device.SupportsMultiViewport(),
355 .support_geometry_streams = device.AreTransformFeedbackGeometryStreamsSupported(),
355 356
356 .warp_size_potentially_larger_than_guest = device.IsWarpSizePotentiallyBiggerThanGuest(), 357 .warp_size_potentially_larger_than_guest = device.IsWarpSizePotentiallyBiggerThanGuest(),
357 358
diff --git a/src/video_core/vulkan_common/vulkan_device.h b/src/video_core/vulkan_common/vulkan_device.h
index 88a653e94..f0cb2b2dc 100755
--- a/src/video_core/vulkan_common/vulkan_device.h
+++ b/src/video_core/vulkan_common/vulkan_device.h
@@ -489,6 +489,11 @@ public:
489 return extensions.transform_feedback; 489 return extensions.transform_feedback;
490 } 490 }
491 491
492 /// Returns true if the device supports VK_EXT_transform_feedback properly.
493 bool AreTransformFeedbackGeometryStreamsSupported() const {
494 return features.transform_feedback.geometryStreams;
495 }
496
492 /// Returns true if the device supports VK_EXT_custom_border_color. 497 /// Returns true if the device supports VK_EXT_custom_border_color.
493 bool IsExtCustomBorderColorSupported() const { 498 bool IsExtCustomBorderColorSupported() const {
494 return extensions.custom_border_color; 499 return extensions.custom_border_color;