From b86c4f1e6680f971f0979c0544e7e20fa1145fa3 Mon Sep 17 00:00:00 2001 From: pineappleEA Date: Wed, 21 Feb 2024 02:52:05 +0100 Subject: [PATCH] early-access version 4155 --- README.md | 2 +- .../features/settings/model/StringSetting.kt | 3 +- .../settings/model/view/SettingsItem.kt | 3 + .../settings/model/view/StringInputSetting.kt | 22 ++ .../features/settings/ui/SettingsAdapter.kt | 13 + .../settings/ui/SettingsDialogFragment.kt | 23 ++ .../settings/ui/SettingsFragmentPresenter.kt | 2 + .../ui/viewholder/StringInputViewHolder.kt | 45 ++++ .../app/src/main/res/values/strings.xml | 1 + .../hle/service/nvdrv/devices/nvhost_gpu.cpp | 7 - .../hle/service/vi/shared_buffer_manager.cpp | 2 +- .../backend/spirv/emit_spirv.cpp | 4 +- .../backend/spirv/emit_spirv_special.cpp | 8 +- src/shader_recompiler/profile.h | 1 + src/video_core/control/channel_state.h | 6 - src/video_core/control/scheduler.cpp | 235 +----------------- src/video_core/control/scheduler.h | 23 +- src/video_core/engines/puller.cpp | 12 +- src/video_core/gpu.cpp | 8 - src/video_core/gpu.h | 9 +- src/video_core/gpu_thread.cpp | 14 +- src/video_core/gpu_thread.h | 9 +- .../renderer_vulkan/vk_pipeline_cache.cpp | 1 + src/video_core/vulkan_common/vulkan_device.h | 5 + 24 files changed, 160 insertions(+), 298 deletions(-) create mode 100755 src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/StringInputSetting.kt create mode 100755 src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/StringInputViewHolder.kt diff --git a/README.md b/README.md index cb98f7715..9370bfe1e 100755 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ yuzu emulator early access ============= -This is the source code for early-access 4154. +This is the source code for early-access 4155. ## Legal Notice 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 import org.yuzu.yuzu_emu.utils.NativeConfig enum class StringSetting(override val key: String) : AbstractStringSetting { - DRIVER_PATH("driver_path"); + DRIVER_PATH("driver_path"), + DEVICE_NAME("device_name"); override fun getString(needsGlobal: Boolean): String = NativeConfig.getString(key, needsGlobal) 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 import org.yuzu.yuzu_emu.features.settings.model.IntSetting import org.yuzu.yuzu_emu.features.settings.model.LongSetting import org.yuzu.yuzu_emu.features.settings.model.ShortSetting +import org.yuzu.yuzu_emu.features.settings.model.StringSetting import org.yuzu.yuzu_emu.utils.NativeConfig /** @@ -90,6 +91,7 @@ abstract class SettingsItem( const val TYPE_INPUT = 8 const val TYPE_INT_SINGLE_CHOICE = 9 const val TYPE_INPUT_PROFILE = 10 + const val TYPE_STRING_INPUT = 11 const val FASTMEM_COMBINED = "fastmem_combined" @@ -108,6 +110,7 @@ abstract class SettingsItem( // List of all general val settingsItems = HashMap().apply { + put(StringInputSetting(StringSetting.DEVICE_NAME, titleId = R.string.device_name)) put( SwitchSetting( 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 @@ +// SPDX-FileCopyrightText: 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +package org.yuzu.yuzu_emu.features.settings.model.view + +import androidx.annotation.StringRes +import org.yuzu.yuzu_emu.features.settings.model.AbstractStringSetting + +class StringInputSetting( + setting: AbstractStringSetting, + @StringRes titleId: Int = 0, + titleString: String = "", + @StringRes descriptionId: Int = 0, + descriptionString: String = "" +) : SettingsItem(setting, titleId, titleString, descriptionId, descriptionString) { + override val type = TYPE_STRING_INPUT + + fun getSelectedValue(needsGlobal: Boolean = false) = setting.getValueAsString(needsGlobal) + + fun setSelectedValue(selection: String) = + (setting as AbstractStringSetting).setString(selection) +} 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( InputProfileViewHolder(ListItemSettingBinding.inflate(inflater), this) } + SettingsItem.TYPE_STRING_INPUT -> { + StringInputViewHolder(ListItemSettingBinding.inflate(inflater), this) + } + else -> { HeaderViewHolder(ListItemSettingsHeaderBinding.inflate(inflater), this) } @@ -392,6 +396,15 @@ class SettingsAdapter( popup.show() } + fun onStringInputClick(item: StringInputSetting, position: Int) { + SettingsDialogFragment.newInstance( + settingsViewModel, + item, + SettingsItem.TYPE_STRING_INPUT, + position + ).show(fragment.childFragmentManager, SettingsDialogFragment.TAG) + } + fun onLongClick(item: SettingsItem, position: Int): Boolean { SettingsDialogFragment.newInstance( 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 import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.slider.Slider import org.yuzu.yuzu_emu.R +import org.yuzu.yuzu_emu.databinding.DialogEditTextBinding import org.yuzu.yuzu_emu.databinding.DialogSliderBinding import org.yuzu.yuzu_emu.features.input.NativeInput import org.yuzu.yuzu_emu.features.input.model.AnalogDirection @@ -23,6 +24,7 @@ import org.yuzu.yuzu_emu.features.settings.model.view.IntSingleChoiceSetting import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem import org.yuzu.yuzu_emu.features.settings.model.view.SingleChoiceSetting import org.yuzu.yuzu_emu.features.settings.model.view.SliderSetting +import org.yuzu.yuzu_emu.features.settings.model.view.StringInputSetting import org.yuzu.yuzu_emu.features.settings.model.view.StringSingleChoiceSetting import org.yuzu.yuzu_emu.utils.ParamPackage import org.yuzu.yuzu_emu.utils.collect @@ -37,6 +39,7 @@ class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener private val settingsViewModel: SettingsViewModel by activityViewModels() private lateinit var sliderBinding: DialogSliderBinding + private lateinit var stringInputBinding: DialogEditTextBinding override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -131,6 +134,18 @@ class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener .create() } + SettingsItem.TYPE_STRING_INPUT -> { + stringInputBinding = DialogEditTextBinding.inflate(layoutInflater) + val item = settingsViewModel.clickedItem as StringInputSetting + stringInputBinding.editText.setText(item.getSelectedValue()) + MaterialAlertDialogBuilder(requireContext()) + .setTitle(item.title) + .setView(stringInputBinding.root) + .setPositiveButton(android.R.string.ok, this) + .setNegativeButton(android.R.string.cancel, defaultCancelListener) + .create() + } + SettingsItem.TYPE_STRING_SINGLE_CHOICE -> { val item = settingsViewModel.clickedItem as StringSingleChoiceSetting MaterialAlertDialogBuilder(requireContext()) @@ -158,6 +173,7 @@ class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener ): View? { return when (type) { SettingsItem.TYPE_SLIDER -> sliderBinding.root + SettingsItem.TYPE_STRING_INPUT -> stringInputBinding.root else -> super.onCreateView(inflater, container, savedInstanceState) } } @@ -200,6 +216,13 @@ class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener val sliderSetting = settingsViewModel.clickedItem as SliderSetting sliderSetting.setSelectedValue(settingsViewModel.sliderProgress.value) } + + is StringInputSetting -> { + val stringInputSetting = settingsViewModel.clickedItem as StringInputSetting + stringInputSetting.setSelectedValue( + (stringInputBinding.editText.text ?: "").toString() + ) + } } closeDialog() } 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 import org.yuzu.yuzu_emu.features.settings.model.Settings import org.yuzu.yuzu_emu.features.settings.model.Settings.MenuTag import org.yuzu.yuzu_emu.features.settings.model.ShortSetting +import org.yuzu.yuzu_emu.features.settings.model.StringSetting import org.yuzu.yuzu_emu.features.settings.model.view.* import org.yuzu.yuzu_emu.utils.InputHandler import org.yuzu.yuzu_emu.utils.NativeConfig @@ -153,6 +154,7 @@ class SettingsFragmentPresenter( private fun addSystemSettings(sl: ArrayList) { sl.apply { + add(StringSetting.DEVICE_NAME.key) add(BooleanSetting.RENDERER_USE_SPEED_LIMIT.key) add(ShortSetting.RENDERER_SPEED_LIMIT.key) 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 @@ +// SPDX-FileCopyrightText: 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +package org.yuzu.yuzu_emu.features.settings.ui.viewholder + +import android.view.View +import org.yuzu.yuzu_emu.databinding.ListItemSettingBinding +import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem +import org.yuzu.yuzu_emu.features.settings.model.view.StringInputSetting +import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter +import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible + +class StringInputViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAdapter) : + SettingViewHolder(binding.root, adapter) { + private lateinit var setting: StringInputSetting + + override fun bind(item: SettingsItem) { + setting = item as StringInputSetting + binding.textSettingName.text = setting.title + binding.textSettingDescription.setVisible(setting.description.isNotEmpty()) + binding.textSettingDescription.text = setting.description + binding.textSettingValue.setVisible(true) + binding.textSettingValue.text = setting.getSelectedValue() + + binding.buttonClear.setVisible(setting.clearable) + binding.buttonClear.setOnClickListener { + adapter.onClearClick(setting, bindingAdapterPosition) + } + + setStyle(setting.isEditable, binding) + } + + override fun onClick(clicked: View) { + if (setting.isEditable) { + adapter.onStringInputClick(setting, bindingAdapterPosition) + } + } + + override fun onLongClick(clicked: View): Boolean { + if (setting.isEditable) { + return adapter.onLongClick(setting, bindingAdapterPosition) + } + return false + } +} 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 @@ %1$s%2$s + Device name Docked Mode Increases resolution, decreasing performance. Handheld Mode is used when disabled, lowering resolution and increasing performance. Emulated region 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 @@ #include "core/hle/service/nvdrv/nvdrv.h" #include "core/memory.h" #include "video_core/control/channel_state.h" -#include "video_core/control/scheduler.h" #include "video_core/engines/puller.h" #include "video_core/gpu.h" #include "video_core/host1x/host1x.h" @@ -34,7 +33,6 @@ nvhost_gpu::nvhost_gpu(Core::System& system_, EventInterface& events_interface_, syncpoint_manager{core_.GetSyncpointManager()}, nvmap{core.GetNvMapFile()}, channel_state{system.GPU().AllocateChannel()} { channel_syncpoint = syncpoint_manager.AllocateSyncpoint(false); - channel_state->syncpoint_id = channel_syncpoint; sm_exception_breakpoint_int_report_event = events_interface.CreateEvent("GpuChannelSMExceptionBreakpointInt"); sm_exception_breakpoint_pause_report_event = @@ -159,9 +157,6 @@ NvResult nvhost_gpu::SetErrorNotifier(IoctlSetErrorNotifier& params) { NvResult nvhost_gpu::SetChannelPriority(IoctlChannelSetPriority& params) { channel_priority = params.priority; - if (channel_state->initialized) { - system.GPU().Scheduler().ChangePriority(channel_state->bind_id, channel_priority); - } LOG_DEBUG(Service_NVDRV, "(STUBBED) called, priority={:X}", channel_priority); return NvResult::Success; } @@ -319,7 +314,6 @@ NvResult nvhost_gpu::GetWaitbase(IoctlGetWaitbase& params) { NvResult nvhost_gpu::ChannelSetTimeout(IoctlChannelSetTimeout& params) { LOG_INFO(Service_NVDRV, "called, timeout=0x{:X}", params.timeout); - channel_state->timeout = params.timeout; return NvResult::Success; } @@ -327,7 +321,6 @@ NvResult nvhost_gpu::ChannelSetTimeslice(IoctlSetTimeslice& params) { LOG_INFO(Service_NVDRV, "called, timeslice=0x{:X}", params.timeslice); channel_timeslice = params.timeslice; - channel_state->timeslice = params.timeslice; return NvResult::Success; } 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) { auto& session = it->second; // Destroy the layer. - R_ASSERT(m_container.DestroyStrayLayer(session.layer_id)); + m_container.DestroyStrayLayer(session.layer_id); // Close nvmap handle. 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) { case Stage::Geometry: execution_model = spv::ExecutionModel::Geometry; ctx.AddCapability(spv::Capability::Geometry); - ctx.AddCapability(spv::Capability::GeometryStreams); + if (ctx.profile.support_geometry_streams) { + ctx.AddCapability(spv::Capability::GeometryStreams); + } switch (ctx.runtime_info.input_topology) { case InputTopology::Points: 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) { if (ctx.runtime_info.convert_depth_mode && !ctx.profile.support_native_ndc) { ConvertDepthMode(ctx); } - if (stream.IsImmediate()) { + if (!ctx.profile.support_geometry_streams) { + throw NotImplementedException("Geometry streams"); + } else if (stream.IsImmediate()) { ctx.OpEmitStreamVertex(ctx.Def(stream)); } else { LOG_WARNING(Shader_SPIRV, "Stream is not immediate"); @@ -140,7 +142,9 @@ void EmitEmitVertex(EmitContext& ctx, const IR::Value& stream) { } void EmitEndPrimitive(EmitContext& ctx, const IR::Value& stream) { - if (stream.IsImmediate()) { + if (!ctx.profile.support_geometry_streams) { + throw NotImplementedException("Geometry streams"); + } else if (stream.IsImmediate()) { ctx.OpEndStreamPrimitive(ctx.Def(stream)); } else { 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 { bool support_gl_derivative_control{}; bool support_scaled_attributes{}; bool support_multi_viewport{}; + bool support_geometry_streams{}; bool warp_size_potentially_larger_than_guest{}; 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 { void BindRasterizer(VideoCore::RasterizerInterface* rasterizer); s32 bind_id = -1; - /// Scheduling info - u32 syncpoint_id = 0xFFFF; - u32 priority = 0; - u32 timeslice = 0; - u32 timeout = 0; - /// 3D engine std::unique_ptr maxwell_3d; /// 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 @@ // SPDX-FileCopyrightText: 2021 yuzu Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later -#include -#include -#include #include -#include -#include -#include #include "common/assert.h" -#include "common/fiber.h" +#include "video_core/control/channel_state.h" #include "video_core/control/scheduler.h" -#include "video_core/dma_pusher.h" #include "video_core/gpu.h" namespace Tegra::Control { - -struct GPFifoContext { - bool is_active; - bool is_running; - std::shared_ptr context; - std::deque pending_work; - std::mutex guard; - s32 bind_id; - std::shared_ptr info; - size_t yield_count; - size_t scheduled_count; -}; - -struct Scheduler::SchedulerImpl { - // Fifos - std::map, std::greater> schedule_priority_queue; - std::unordered_map channel_gpfifo_ids; - std::deque gpfifos; - std::deque free_fifos; - - // Scheduling - std::mutex scheduling_guard; - std::shared_ptr master_control; - bool must_reschedule{}; - GPFifoContext* current_fifo{}; -}; - -Scheduler::Scheduler(GPU& gpu_) : gpu{gpu_} { - impl = std::make_unique(); -} +Scheduler::Scheduler(GPU& gpu_) : gpu{gpu_} {} Scheduler::~Scheduler() = default; -void Scheduler::Init() { - impl->master_control = Common::Fiber::ThreadToFiber(); -} - -void Scheduler::Resume() { - while (UpdateHighestPriorityChannel()) { - impl->current_fifo->scheduled_count++; - Common::Fiber::YieldTo(impl->master_control, *impl->current_fifo->context); - } -} - -bool Scheduler::UpdateHighestPriorityChannel() { - std::scoped_lock lk(impl->scheduling_guard); - - // Clear needs to schedule state. - impl->must_reschedule = false; - - // By default, we don't have a channel to schedule. - impl->current_fifo = nullptr; - - // Check each level to see if we can schedule. - for (auto& level : impl->schedule_priority_queue) { - if (ScheduleLevel(level.second)) { - return true; - } - } - - // Nothing to schedule. - return false; -} - -bool Scheduler::ScheduleLevel(std::list& queue) { - bool found_anything = false; - size_t min_schedule_count = std::numeric_limits::max(); - for (auto id : queue) { - auto& fifo = impl->gpfifos[id]; - std::scoped_lock lk(fifo.guard); - - // With no pending work and nothing running, this channel can't be scheduled. - if (fifo.pending_work.empty() && !fifo.is_running) { - continue; - } - // Prioritize channels at current priority which have been run the least. - if (fifo.scheduled_count > min_schedule_count) { - continue; - } - - // Try not to select the same channel we just yielded from. - if (fifo.scheduled_count < fifo.yield_count) { - fifo.scheduled_count++; - continue; - } - - // Update best selection. - min_schedule_count = fifo.scheduled_count; - impl->current_fifo = &fifo; - found_anything = true; - } - return found_anything; -} - -void Scheduler::ChangePriority(s32 channel_id, u32 new_priority) { - std::scoped_lock lk(impl->scheduling_guard); - // Ensure we are tracking this channel. - auto fifo_it = impl->channel_gpfifo_ids.find(channel_id); - if (fifo_it == impl->channel_gpfifo_ids.end()) { - return; - } - - // Get the fifo and update its priority. - const size_t fifo_id = fifo_it->second; - auto& fifo = impl->gpfifos[fifo_id]; - const auto old_priority = std::exchange(fifo.info->priority, new_priority); - - // Create the new level if needed. - impl->schedule_priority_queue.try_emplace(new_priority); - - // Remove the old level and add to the new level. - impl->schedule_priority_queue[new_priority].push_back(fifo_id); - impl->schedule_priority_queue[old_priority].remove_if( - [fifo_id](size_t id) { return id == fifo_id; }); -} - -void Scheduler::Yield() { - ASSERT(impl->current_fifo != nullptr); - - // Set yield count higher - impl->current_fifo->yield_count = impl->current_fifo->scheduled_count + 1; - Common::Fiber::YieldTo(impl->current_fifo->context, *impl->master_control); - gpu.BindChannel(impl->current_fifo->bind_id); -} - -void Scheduler::CheckStatus() { - { - std::unique_lock lk(impl->scheduling_guard); - // If no reschedule is needed, don't transfer control - if (!impl->must_reschedule) { - return; - } - } - // Transfer control to the scheduler - Common::Fiber::YieldTo(impl->current_fifo->context, *impl->master_control); - gpu.BindChannel(impl->current_fifo->bind_id); -} - void Scheduler::Push(s32 channel, CommandList&& entries) { - std::scoped_lock lk(impl->scheduling_guard); - // Get and ensure we have this channel. - auto it = impl->channel_gpfifo_ids.find(channel); - ASSERT(it != impl->channel_gpfifo_ids.end()); - auto gpfifo_id = it->second; - auto& fifo = impl->gpfifos[gpfifo_id]; - // Add the new new work to the channel. - { - std::scoped_lock lk2(fifo.guard); - fifo.pending_work.emplace_back(std::move(entries)); - } - - // If the current running FIFO is null or the one being pushed to then - // just return - if (impl->current_fifo == nullptr || impl->current_fifo == &fifo) { - return; - } - - // If the current fifo has higher or equal priority to the current fifo then return - if (impl->current_fifo->info->priority >= fifo.info->priority) { - return; - } - // Mark scheduler update as required. - impl->must_reschedule = true; -} - -void Scheduler::ChannelLoop(size_t gpfifo_id, s32 channel_id) { - auto& fifo = impl->gpfifos[gpfifo_id]; - auto* channel_state = fifo.info.get(); - const auto SendToPuller = [&] { - std::scoped_lock lk(fifo.guard); - if (fifo.pending_work.empty()) { - // Stop if no work available. - fifo.is_running = false; - return false; - } - // Otherwise, send work to puller and mark as running. - CommandList&& entries = std::move(fifo.pending_work.front()); - channel_state->dma_pusher->Push(std::move(entries)); - fifo.pending_work.pop_front(); - fifo.is_running = true; - // Succeed. - return true; - }; - // Inform the GPU about the current channel. - gpu.BindChannel(channel_id); - while (true) { - while (SendToPuller()) { - // Execute. - channel_state->dma_pusher->DispatchCalls(); - // Reschedule. - CheckStatus(); - } - // Return to host execution when all work is completed. - Common::Fiber::YieldTo(fifo.context, *impl->master_control); - // Inform the GPU about the current channel. - gpu.BindChannel(channel_id); - } + std::unique_lock lk(scheduling_guard); + auto it = channels.find(channel); + ASSERT(it != channels.end()); + auto channel_state = it->second; + gpu.BindChannel(channel_state->bind_id); + channel_state->dma_pusher->Push(std::move(entries)); + channel_state->dma_pusher->DispatchCalls(); } void Scheduler::DeclareChannel(std::shared_ptr new_channel) { s32 channel = new_channel->bind_id; - std::unique_lock lk(impl->scheduling_guard); - - size_t new_fifo_id; - if (!impl->free_fifos.empty()) { - new_fifo_id = impl->free_fifos.front(); - impl->free_fifos.pop_front(); - } else { - new_fifo_id = impl->gpfifos.size(); - impl->gpfifos.emplace_back(); - } - auto& new_fifo = impl->gpfifos[new_fifo_id]; - impl->channel_gpfifo_ids[channel] = new_fifo_id; - new_fifo.is_active = true; - new_fifo.bind_id = channel; - new_fifo.pending_work.clear(); - new_fifo.info = new_channel; - new_fifo.scheduled_count = 0; - new_fifo.yield_count = 0; - new_fifo.is_running = false; - impl->schedule_priority_queue.try_emplace(new_channel->priority); - impl->schedule_priority_queue[new_channel->priority].push_back(new_fifo_id); - std::function callback = std::bind(&Scheduler::ChannelLoop, this, new_fifo_id, channel); - new_fifo.context = std::make_shared(std::move(callback)); + std::unique_lock lk(scheduling_guard); + channels.emplace(channel, new_channel); } } // 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 @@ #pragma once -#include #include +#include +#include -#include "common/common_types.h" -#include "video_core/control/channel_state.h" #include "video_core/dma_pusher.h" namespace Tegra { @@ -23,27 +22,13 @@ public: explicit Scheduler(GPU& gpu_); ~Scheduler(); - void Init(); - - void Resume(); - - void Yield(); - void Push(s32 channel, CommandList&& entries); void DeclareChannel(std::shared_ptr new_channel); - void ChangePriority(s32 channel_id, u32 new_priority); - private: - void ChannelLoop(size_t gpfifo_id, s32 channel_id); - bool ScheduleLevel(std::list& queue); - void CheckStatus(); - bool UpdateHighestPriorityChannel(); - - struct SchedulerImpl; - std::unique_ptr impl; - + std::unordered_map> channels; + std::mutex scheduling_guard; GPU& gpu; }; 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 @@ #include "common/settings.h" #include "core/core.h" #include "video_core/control/channel_state.h" -#include "video_core/control/scheduler.h" #include "video_core/dma_pusher.h" #include "video_core/engines/fermi_2d.h" #include "video_core/engines/kepler_compute.h" @@ -15,8 +14,6 @@ #include "video_core/engines/maxwell_dma.h" #include "video_core/engines/puller.h" #include "video_core/gpu.h" -#include "video_core/host1x/host1x.h" -#include "video_core/host1x/syncpoint_manager.h" #include "video_core/memory_manager.h" #include "video_core/rasterizer_interface.h" @@ -63,14 +60,11 @@ void Puller::ProcessBindMethod(const MethodCall& method_call) { } void Puller::ProcessFenceActionMethod() { - auto& syncpoint_manager = gpu.Host1x().GetSyncpointManager(); switch (regs.fence_action.op) { case Puller::FenceOperation::Acquire: - while (regs.fence_value > - syncpoint_manager.GetGuestSyncpointValue(regs.fence_action.syncpoint_id)) { - rasterizer->ReleaseFences(); - gpu.Scheduler().Yield(); - } + // UNIMPLEMENTED_MSG("Channel Scheduling pending."); + // WaitFence(regs.fence_action.syncpoint_id, regs.fence_value); + rasterizer->ReleaseFences(); break; case Puller::FenceOperation::Increment: 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 GPU::AllocateChannel() { return impl->AllocateChannel(); } -Tegra::Control::Scheduler& GPU::Scheduler() { - return *impl->scheduler; -} - -const Tegra::Control::Scheduler& GPU::Scheduler() const { - return *impl->scheduler; -} - void GPU::InitChannel(Control::ChannelState& to_init) { impl->InitChannel(to_init); } 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; namespace Control { struct ChannelState; -class Scheduler; -} // namespace Control +} namespace Host1x { class Host1x; @@ -205,12 +204,6 @@ public: /// Returns a const reference to the shader notifier. [[nodiscard]] const VideoCore::ShaderNotify& ShaderNotify() const; - /// Returns GPU Channel Scheduler. - [[nodiscard]] Tegra::Control::Scheduler& Scheduler(); - - /// Returns GPU Channel Scheduler. - [[nodiscard]] const Tegra::Control::Scheduler& Scheduler() const; - [[nodiscard]] u64 GetTicks() const; [[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, CommandDataContainer next; - scheduler.Init(); - while (!stop_token.stop_requested()) { state.queue.PopWait(next, stop_token); if (stop_token.stop_requested()) { break; } - if (std::holds_alternative(next.data)) { - scheduler.Resume(); + if (auto* submit_list = std::get_if(&next.data)) { + scheduler.Push(submit_list->channel, std::move(submit_list->entries)); } else if (std::holds_alternative(next.data)) { system.GPU().TickWork(); } else if (const auto* flush = std::get_if(&next.data)) { @@ -71,16 +69,14 @@ ThreadManager::~ThreadManager() = default; void ThreadManager::StartThread(VideoCore::RendererBase& renderer, Core::Frontend::GraphicsContext& context, - Tegra::Control::Scheduler& scheduler_) { + Tegra::Control::Scheduler& scheduler) { rasterizer = renderer.ReadRasterizer(); - scheduler = &scheduler_; thread = std::jthread(RunThread, std::ref(system), std::ref(renderer), std::ref(context), - std::ref(scheduler_), std::ref(state)); + std::ref(scheduler), std::ref(state)); } void ThreadManager::SubmitList(s32 channel, Tegra::CommandList&& entries) { - scheduler->Push(channel, std::move(entries)); - PushCommand(SubmitListCommand()); + PushCommand(SubmitListCommand(channel, std::move(entries))); } void 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; namespace VideoCommon::GPUThread { /// Command to signal to the GPU thread that a command list is ready for processing -struct SubmitListCommand final {}; +struct SubmitListCommand final { + explicit SubmitListCommand(s32 channel_, Tegra::CommandList&& entries_) + : channel{channel_}, entries{std::move(entries_)} {} + + s32 channel; + Tegra::CommandList entries; +}; /// Command to signal to the GPU thread to flush a region struct FlushRegionCommand final { @@ -118,7 +124,6 @@ public: private: /// Pushes a command to be executed by the GPU thread u64 PushCommand(CommandData&& command_data, bool block = false); - Tegra::Control::Scheduler* scheduler; Core::System& system; 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_, .support_native_ndc = device.IsExtDepthClipControlSupported(), .support_scaled_attributes = !device.MustEmulateScaledFormats(), .support_multi_viewport = device.SupportsMultiViewport(), + .support_geometry_streams = device.AreTransformFeedbackGeometryStreamsSupported(), .warp_size_potentially_larger_than_guest = device.IsWarpSizePotentiallyBiggerThanGuest(), 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: return extensions.transform_feedback; } + /// Returns true if the device supports VK_EXT_transform_feedback properly. + bool AreTransformFeedbackGeometryStreamsSupported() const { + return features.transform_feedback.geometryStreams; + } + /// Returns true if the device supports VK_EXT_custom_border_color. bool IsExtCustomBorderColorSupported() const { return extensions.custom_border_color;