Compare commits
103 Commits
__refs_pul
...
__refs_pul
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
453fd47030 | ||
|
|
91c12db070 | ||
|
|
b088a448cd | ||
|
|
c4f6c3b00b | ||
|
|
cddb28cf26 | ||
|
|
538e137bca | ||
|
|
e69118042f | ||
|
|
a6b8d85b34 | ||
|
|
8da5bd27e9 | ||
|
|
0216aa55b4 | ||
|
|
0298c2cc5d | ||
|
|
00dcf69ce8 | ||
|
|
1ea0890a36 | ||
|
|
a77feca086 | ||
|
|
99a8f7fb72 | ||
|
|
8ae26df15c | ||
|
|
82a4a67f6b | ||
|
|
8e93a9a9ef | ||
|
|
23c1f7c72f | ||
|
|
d3ed771f39 | ||
|
|
12fba361bd | ||
|
|
6bcde572dd | ||
|
|
cb004d1ba1 | ||
|
|
20a17607ae | ||
|
|
473caaff5b | ||
|
|
787552f832 | ||
|
|
5f945e2fcd | ||
|
|
c08da2d6ad | ||
|
|
4458920799 | ||
|
|
61fed8a3a6 | ||
|
|
efb3165e3d | ||
|
|
a493ba76b4 | ||
|
|
ae60a5657e | ||
|
|
feb60de5c3 | ||
|
|
c67644f1da | ||
|
|
9343b81afd | ||
|
|
71f53b4218 | ||
|
|
f131b0faeb | ||
|
|
6c64d5aff2 | ||
|
|
de594995da | ||
|
|
4c16a1a26f | ||
|
|
862e66202c | ||
|
|
4055a476aa | ||
|
|
2136a46ab7 | ||
|
|
b9c7e5c2c8 | ||
|
|
d86e88a622 | ||
|
|
7eac28e410 | ||
|
|
ea4c92f734 | ||
|
|
c9cd938dfd | ||
|
|
4c5e3d5f7a | ||
|
|
e2be180136 | ||
|
|
c9437e5244 | ||
|
|
24548b1f5c | ||
|
|
be0ecae108 | ||
|
|
fcd54c6479 | ||
|
|
08296f151e | ||
|
|
a134e924ff | ||
|
|
31ed6bae11 | ||
|
|
9a5ef835cc | ||
|
|
df0d3698ae | ||
|
|
51fc608f68 | ||
|
|
b30e19ba24 | ||
|
|
ec6b67d862 | ||
|
|
e3b510a4b4 | ||
|
|
ecaa038b4d | ||
|
|
f1806d237f | ||
|
|
ae57a99d7d | ||
|
|
1d03a0fa75 | ||
|
|
c9038af29e | ||
|
|
f3053920bf | ||
|
|
c7b31d24b9 | ||
|
|
cb3559539a | ||
|
|
71cdfa6ad5 | ||
|
|
8d0d0e1c7a | ||
|
|
4b8b223db2 | ||
|
|
728aca7703 | ||
|
|
a872030a35 | ||
|
|
79e7d7f4ba | ||
|
|
7f62a48ab5 | ||
|
|
b5415b6872 | ||
|
|
b76a1d987f | ||
|
|
ae2130470e | ||
|
|
ac6290bea7 | ||
|
|
4051bbbed7 | ||
|
|
2a7edda70a | ||
|
|
59b6ada7b7 | ||
|
|
9908434c14 | ||
|
|
668a10f9b9 | ||
|
|
fc4b45ebd3 | ||
|
|
1afe6d51ee | ||
|
|
1ae0f0f3f6 | ||
|
|
de0b35b974 | ||
|
|
ae88d01d8d | ||
|
|
d759de9f96 | ||
|
|
89d3e81be8 | ||
|
|
71f264c498 | ||
|
|
26417da5d3 | ||
|
|
b3b458edf9 | ||
|
|
74961d4dfb | ||
|
|
9ffa1801c7 | ||
|
|
4d4fe69223 | ||
|
|
0a75519ab5 | ||
|
|
3062a35eb1 |
5
dist/languages/.tx/config
vendored
5
dist/languages/.tx/config
vendored
@@ -6,3 +6,8 @@ file_filter = <lang>.ts
|
||||
source_file = en.ts
|
||||
source_lang = en
|
||||
type = QT
|
||||
|
||||
[o:yuzu-emulator:p:yuzu:r:yuzu-android]
|
||||
file_filter = ../../src/android/app/src/main/res/values-<lang>/strings.xml
|
||||
source_file = ../../src/android/app/src/main/res/values/strings.xml
|
||||
type = ANDROID
|
||||
|
||||
@@ -373,8 +373,10 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
|
||||
val pictureInPictureParamsBuilder = PictureInPictureParams.Builder()
|
||||
.getPictureInPictureActionsBuilder().getPictureInPictureAspectBuilder()
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||
val isEmulationActive = emulationViewModel.emulationStarted.value &&
|
||||
!emulationViewModel.isEmulationStopping.value
|
||||
pictureInPictureParamsBuilder.setAutoEnterEnabled(
|
||||
BooleanSetting.PICTURE_IN_PICTURE.boolean
|
||||
BooleanSetting.PICTURE_IN_PICTURE.boolean && isEmulationActive
|
||||
)
|
||||
}
|
||||
setPictureInPictureParams(pictureInPictureParamsBuilder.build())
|
||||
|
||||
@@ -73,7 +73,7 @@ abstract class SettingsItem(
|
||||
R.string.frame_limit_slider,
|
||||
R.string.frame_limit_slider_description,
|
||||
1,
|
||||
200,
|
||||
400,
|
||||
"%"
|
||||
)
|
||||
)
|
||||
|
||||
@@ -21,6 +21,8 @@ import org.yuzu.yuzu_emu.databinding.FragmentInstallablesBinding
|
||||
import org.yuzu.yuzu_emu.model.HomeViewModel
|
||||
import org.yuzu.yuzu_emu.model.Installable
|
||||
import org.yuzu.yuzu_emu.ui.main.MainActivity
|
||||
import java.time.LocalDateTime
|
||||
import java.time.format.DateTimeFormatter
|
||||
|
||||
class InstallableFragment : Fragment() {
|
||||
private var _binding: FragmentInstallablesBinding? = null
|
||||
@@ -78,7 +80,15 @@ class InstallableFragment : Fragment() {
|
||||
R.string.manage_save_data,
|
||||
R.string.import_export_saves_description,
|
||||
install = { mainActivity.importSaves.launch(arrayOf("application/zip")) },
|
||||
export = { mainActivity.exportSave() }
|
||||
export = {
|
||||
mainActivity.exportSaves.launch(
|
||||
"yuzu saves - ${
|
||||
LocalDateTime.now().format(
|
||||
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm")
|
||||
)
|
||||
}.zip"
|
||||
)
|
||||
}
|
||||
)
|
||||
} else {
|
||||
Installable(
|
||||
|
||||
@@ -18,8 +18,8 @@ class Game(
|
||||
val version: String = "",
|
||||
val isHomebrew: Boolean = false
|
||||
) : Parcelable {
|
||||
val keyAddedToLibraryTime get() = "${programId}_AddedToLibraryTime"
|
||||
val keyLastPlayedTime get() = "${programId}_LastPlayed"
|
||||
val keyAddedToLibraryTime get() = "${path}_AddedToLibraryTime"
|
||||
val keyLastPlayedTime get() = "${path}_LastPlayed"
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (other !is Game) {
|
||||
|
||||
@@ -6,7 +6,6 @@ package org.yuzu.yuzu_emu.ui.main
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.provider.DocumentsContract
|
||||
import android.view.View
|
||||
import android.view.ViewGroup.MarginLayoutParams
|
||||
import android.view.WindowManager
|
||||
@@ -20,7 +19,6 @@ import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.core.view.WindowCompat
|
||||
import androidx.core.view.WindowInsetsCompat
|
||||
import androidx.documentfile.provider.DocumentFile
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.lifecycle.repeatOnLifecycle
|
||||
@@ -41,7 +39,6 @@ import org.yuzu.yuzu_emu.NativeLibrary
|
||||
import org.yuzu.yuzu_emu.R
|
||||
import org.yuzu.yuzu_emu.activities.EmulationActivity
|
||||
import org.yuzu.yuzu_emu.databinding.ActivityMainBinding
|
||||
import org.yuzu.yuzu_emu.features.DocumentProvider
|
||||
import org.yuzu.yuzu_emu.features.settings.model.Settings
|
||||
import org.yuzu.yuzu_emu.fragments.IndeterminateProgressDialogFragment
|
||||
import org.yuzu.yuzu_emu.fragments.MessageDialogFragment
|
||||
@@ -53,9 +50,6 @@ import org.yuzu.yuzu_emu.model.TaskViewModel
|
||||
import org.yuzu.yuzu_emu.utils.*
|
||||
import java.io.BufferedInputStream
|
||||
import java.io.BufferedOutputStream
|
||||
import java.io.FileOutputStream
|
||||
import java.time.LocalDateTime
|
||||
import java.time.format.DateTimeFormatter
|
||||
import java.util.zip.ZipEntry
|
||||
import java.util.zip.ZipInputStream
|
||||
|
||||
@@ -73,7 +67,6 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
|
||||
|
||||
// Get first subfolder in saves folder (should be the user folder)
|
||||
val savesFolderRoot get() = File(savesFolder).listFiles()?.firstOrNull()?.canonicalPath ?: ""
|
||||
private var lastZipCreated: File? = null
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
val splashScreen = installSplashScreen()
|
||||
@@ -656,75 +649,31 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
|
||||
}.show(supportFragmentManager, IndeterminateProgressDialogFragment.TAG)
|
||||
}
|
||||
|
||||
/**
|
||||
* Zips the save files located in the given folder path and creates a new zip file with the current date and time.
|
||||
* @return true if the zip file is successfully created, false otherwise.
|
||||
*/
|
||||
private fun zipSave(): Boolean {
|
||||
try {
|
||||
val tempFolder = File(getPublicFilesDir().canonicalPath, "temp")
|
||||
tempFolder.mkdirs()
|
||||
val saveFolder = File(savesFolderRoot)
|
||||
val outputZipFile = File(
|
||||
tempFolder,
|
||||
"yuzu saves - ${
|
||||
LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"))
|
||||
}.zip"
|
||||
)
|
||||
outputZipFile.createNewFile()
|
||||
val result = FileUtil.zipFromInternalStorage(
|
||||
saveFolder,
|
||||
savesFolderRoot,
|
||||
BufferedOutputStream(FileOutputStream(outputZipFile))
|
||||
)
|
||||
if (result == TaskState.Failed) {
|
||||
return false
|
||||
}
|
||||
lastZipCreated = outputZipFile
|
||||
} catch (e: Exception) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* Exports the save file located in the given folder path by creating a zip file and sharing it via intent.
|
||||
*/
|
||||
fun exportSave() {
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
val wasZipCreated = zipSave()
|
||||
val lastZipFile = lastZipCreated
|
||||
if (!wasZipCreated || lastZipFile == null) {
|
||||
withContext(Dispatchers.Main) {
|
||||
Toast.makeText(
|
||||
this@MainActivity,
|
||||
getString(R.string.export_save_failed),
|
||||
Toast.LENGTH_LONG
|
||||
).show()
|
||||
}
|
||||
return@launch
|
||||
}
|
||||
|
||||
withContext(Dispatchers.Main) {
|
||||
val file = DocumentFile.fromSingleUri(
|
||||
this@MainActivity,
|
||||
DocumentsContract.buildDocumentUri(
|
||||
DocumentProvider.AUTHORITY,
|
||||
"${DocumentProvider.ROOT_ID}/temp/${lastZipFile.name}"
|
||||
)
|
||||
)!!
|
||||
val intent = Intent(Intent.ACTION_SEND)
|
||||
.setDataAndType(file.uri, "application/zip")
|
||||
.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||
.putExtra(Intent.EXTRA_STREAM, file.uri)
|
||||
startForResultExportSave.launch(
|
||||
Intent.createChooser(
|
||||
intent,
|
||||
getString(R.string.share_save_file)
|
||||
)
|
||||
)
|
||||
}
|
||||
val exportSaves = registerForActivityResult(
|
||||
ActivityResultContracts.CreateDocument("application/zip")
|
||||
) { result ->
|
||||
if (result == null) {
|
||||
return@registerForActivityResult
|
||||
}
|
||||
|
||||
IndeterminateProgressDialogFragment.newInstance(
|
||||
this,
|
||||
R.string.save_files_exporting,
|
||||
false
|
||||
) {
|
||||
val zipResult = FileUtil.zipFromInternalStorage(
|
||||
File(savesFolderRoot),
|
||||
savesFolderRoot,
|
||||
BufferedOutputStream(contentResolver.openOutputStream(result))
|
||||
)
|
||||
return@newInstance when (zipResult) {
|
||||
TaskState.Completed -> getString(R.string.export_success)
|
||||
TaskState.Cancelled, TaskState.Failed -> getString(R.string.export_failed)
|
||||
}
|
||||
}.show(supportFragmentManager, IndeterminateProgressDialogFragment.TAG)
|
||||
}
|
||||
|
||||
private val startForResultExportSave =
|
||||
|
||||
@@ -13,7 +13,7 @@ struct Values {
|
||||
Settings::Linkage linkage;
|
||||
|
||||
// Android
|
||||
Settings::Setting<bool> picture_in_picture{linkage, true, "picture_in_picture",
|
||||
Settings::Setting<bool> picture_in_picture{linkage, false, "picture_in_picture",
|
||||
Settings::Category::Android};
|
||||
Settings::Setting<s32> screen_layout{linkage,
|
||||
5,
|
||||
|
||||
@@ -139,7 +139,7 @@
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/show_fps_text"
|
||||
style="@style/TextAppearance.Material3.BodyMedium"
|
||||
style="@style/TextAppearance.Material3.BodySmall"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="left"
|
||||
@@ -147,7 +147,8 @@
|
||||
android:focusable="false"
|
||||
android:paddingHorizontal="20dp"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="12sp"
|
||||
android:shadowColor="@android:color/black"
|
||||
android:shadowRadius="3"
|
||||
tools:ignore="RtlHardcoded" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
@@ -127,6 +127,7 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:clipToPadding="false"
|
||||
android:paddingVertical="4dp"
|
||||
app:checkedChip="@id/chip_recently_played"
|
||||
app:chipSpacingHorizontal="12dp"
|
||||
app:singleLine="true"
|
||||
app:singleSelection="true">
|
||||
|
||||
@@ -91,6 +91,7 @@
|
||||
<string name="manage_save_data">Manage save data</string>
|
||||
<string name="manage_save_data_description">Save data found. Please select an option below.</string>
|
||||
<string name="import_export_saves_description">Import or export save files</string>
|
||||
<string name="save_files_exporting">Exporting save files…</string>
|
||||
<string name="save_file_imported_success">Imported successfully</string>
|
||||
<string name="save_file_invalid_zip_structure">Invalid save directory structure</string>
|
||||
<string name="save_file_invalid_zip_structure_description">The first subfolder name must be the title ID of the game.</string>
|
||||
@@ -256,6 +257,7 @@
|
||||
<string name="cancelling">Cancelling</string>
|
||||
<string name="install">Install</string>
|
||||
<string name="delete">Delete</string>
|
||||
<string name="export_success">Exported successfully</string>
|
||||
|
||||
<!-- GPU driver installation -->
|
||||
<string name="select_gpu_driver">Select GPU driver</string>
|
||||
|
||||
@@ -12,7 +12,7 @@ bool IsValidChannelCount(u32 channel_count) {
|
||||
}
|
||||
|
||||
bool IsValidStreamCounts(u32 total_stream_count, u32 stereo_stream_count) {
|
||||
return total_stream_count > 0 && stereo_stream_count > 0 &&
|
||||
return total_stream_count > 0 && static_cast<s32>(stereo_stream_count) >= 0 &&
|
||||
stereo_stream_count <= total_stream_count && IsValidChannelCount(total_stream_count);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
@@ -148,7 +148,7 @@ Result OpusDecoder::DecodeInterleavedForMultiStream(u32* out_data_size, u64* out
|
||||
auto* header_p{reinterpret_cast<const OpusPacketHeader*>(input_data.data())};
|
||||
OpusPacketHeader header{ReverseHeader(*header_p)};
|
||||
|
||||
LOG_ERROR(Service_Audio, "header size 0x{:X} input data size 0x{:X} in_data size 0x{:X}",
|
||||
LOG_TRACE(Service_Audio, "header size 0x{:X} input data size 0x{:X} in_data size 0x{:X}",
|
||||
header.size, input_data.size_bytes(), in_data.size_bytes());
|
||||
|
||||
R_UNLESS(in_data.size_bytes() >= header.size &&
|
||||
|
||||
@@ -146,7 +146,7 @@ public:
|
||||
return;
|
||||
}
|
||||
|
||||
paused = true;
|
||||
SignalPause();
|
||||
if (cubeb_stream_stop(stream_backend) != CUBEB_OK) {
|
||||
LOG_CRITICAL(Audio_Sink, "Error stopping cubeb stream");
|
||||
}
|
||||
|
||||
@@ -111,7 +111,7 @@ public:
|
||||
if (device == 0 || paused) {
|
||||
return;
|
||||
}
|
||||
paused = true;
|
||||
SignalPause();
|
||||
SDL_PauseAudioDevice(device, 1);
|
||||
}
|
||||
|
||||
|
||||
@@ -282,11 +282,19 @@ u64 SinkStream::GetExpectedPlayedSampleCount() {
|
||||
void SinkStream::WaitFreeSpace(std::stop_token stop_token) {
|
||||
std::unique_lock lk{release_mutex};
|
||||
release_cv.wait_for(lk, std::chrono::milliseconds(5),
|
||||
[this]() { return queued_buffers < max_queue_size; });
|
||||
[this]() { return paused || queued_buffers < max_queue_size; });
|
||||
if (queued_buffers > max_queue_size + 3) {
|
||||
Common::CondvarWait(release_cv, lk, stop_token,
|
||||
[this] { return queued_buffers < max_queue_size; });
|
||||
[this] { return paused || queued_buffers < max_queue_size; });
|
||||
}
|
||||
}
|
||||
|
||||
void SinkStream::SignalPause() {
|
||||
{
|
||||
std::scoped_lock lk{release_mutex};
|
||||
paused = true;
|
||||
}
|
||||
release_cv.notify_one();
|
||||
}
|
||||
|
||||
} // namespace AudioCore::Sink
|
||||
|
||||
@@ -213,6 +213,12 @@ public:
|
||||
*/
|
||||
void WaitFreeSpace(std::stop_token stop_token);
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Unblocks the ADSP if the stream is paused.
|
||||
*/
|
||||
void SignalPause();
|
||||
|
||||
protected:
|
||||
/// Core system
|
||||
Core::System& system;
|
||||
|
||||
@@ -6,10 +6,11 @@
|
||||
namespace Settings {
|
||||
namespace NativeButton {
|
||||
const std::array<const char*, NumButtons> mapping = {{
|
||||
"button_a", "button_b", "button_x", "button_y", "button_lstick",
|
||||
"button_rstick", "button_l", "button_r", "button_zl", "button_zr",
|
||||
"button_plus", "button_minus", "button_dleft", "button_dup", "button_dright",
|
||||
"button_ddown", "button_sl", "button_sr", "button_home", "button_screenshot",
|
||||
"button_a", "button_b", "button_x", "button_y", "button_lstick",
|
||||
"button_rstick", "button_l", "button_r", "button_zl", "button_zr",
|
||||
"button_plus", "button_minus", "button_dleft", "button_dup", "button_dright",
|
||||
"button_ddown", "button_slleft", "button_srleft", "button_home", "button_screenshot",
|
||||
"button_slright", "button_srright",
|
||||
}};
|
||||
}
|
||||
|
||||
|
||||
@@ -29,12 +29,15 @@ enum Values : int {
|
||||
DRight,
|
||||
DDown,
|
||||
|
||||
SL,
|
||||
SR,
|
||||
SLLeft,
|
||||
SRLeft,
|
||||
|
||||
Home,
|
||||
Screenshot,
|
||||
|
||||
SLRight,
|
||||
SRRight,
|
||||
|
||||
NumButtons,
|
||||
};
|
||||
|
||||
|
||||
@@ -521,11 +521,21 @@ add_library(core STATIC
|
||||
hle/service/grc/grc.h
|
||||
hle/service/hid/hid.cpp
|
||||
hle/service/hid/hid.h
|
||||
hle/service/hid/hid_debug_server.cpp
|
||||
hle/service/hid/hid_debug_server.h
|
||||
hle/service/hid/hid_firmware_settings.cpp
|
||||
hle/service/hid/hid_firmware_settings.h
|
||||
hle/service/hid/hid_server.cpp
|
||||
hle/service/hid/hid_server.h
|
||||
hle/service/hid/hid_system_server.cpp
|
||||
hle/service/hid/hid_system_server.h
|
||||
hle/service/hid/hidbus.cpp
|
||||
hle/service/hid/hidbus.h
|
||||
hle/service/hid/irs.cpp
|
||||
hle/service/hid/irs.h
|
||||
hle/service/hid/irs_ring_lifo.h
|
||||
hle/service/hid/resource_manager.cpp
|
||||
hle/service/hid/resource_manager.h
|
||||
hle/service/hid/ring_lifo.h
|
||||
hle/service/hid/xcd.cpp
|
||||
hle/service/hid/xcd.h
|
||||
@@ -715,6 +725,7 @@ add_library(core STATIC
|
||||
hle/service/nvnflinger/producer_listener.h
|
||||
hle/service/nvnflinger/status.h
|
||||
hle/service/nvnflinger/ui/fence.h
|
||||
hle/service/nvnflinger/ui/graphic_buffer.cpp
|
||||
hle/service/nvnflinger/ui/graphic_buffer.h
|
||||
hle/service/nvnflinger/window.h
|
||||
hle/service/olsc/olsc.cpp
|
||||
|
||||
@@ -153,6 +153,14 @@ void ARM_Interface::Run() {
|
||||
Kernel::KThread* current_thread{Kernel::GetCurrentThreadPointer(system.Kernel())};
|
||||
HaltReason hr{};
|
||||
|
||||
// If the thread is scheduled for termination, exit the thread.
|
||||
if (current_thread->HasDpc()) {
|
||||
if (current_thread->IsTerminationRequested()) {
|
||||
current_thread->Exit();
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
// Notify the debugger and go to sleep if a step was performed
|
||||
// and this thread has been scheduled again.
|
||||
if (current_thread->GetStepState() == StepState::StepPerformed) {
|
||||
@@ -174,14 +182,6 @@ void ARM_Interface::Run() {
|
||||
}
|
||||
system.ExitCPUProfile();
|
||||
|
||||
// If the thread is scheduled for termination, exit the thread.
|
||||
if (current_thread->HasDpc()) {
|
||||
if (current_thread->IsTerminationRequested()) {
|
||||
current_thread->Exit();
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
// Notify the debugger and go to sleep if a breakpoint was hit,
|
||||
// or if the thread is unable to continue for any reason.
|
||||
if (True(hr & HaltReason::InstructionBreakpoint) || True(hr & HaltReason::PrefetchAbort)) {
|
||||
|
||||
@@ -76,6 +76,7 @@ void CoreTiming::Initialize(std::function<void()>&& on_thread_init_) {
|
||||
}
|
||||
|
||||
void CoreTiming::ClearPendingEvents() {
|
||||
std::scoped_lock lock{basic_lock};
|
||||
event_queue.clear();
|
||||
}
|
||||
|
||||
@@ -113,6 +114,7 @@ bool CoreTiming::IsRunning() const {
|
||||
}
|
||||
|
||||
bool CoreTiming::HasPendingEvents() const {
|
||||
std::scoped_lock lock{basic_lock};
|
||||
return !(wait_set && event_queue.empty());
|
||||
}
|
||||
|
||||
|
||||
@@ -161,7 +161,7 @@ private:
|
||||
std::shared_ptr<EventType> ev_lost;
|
||||
Common::Event event{};
|
||||
Common::Event pause_event{};
|
||||
std::mutex basic_lock;
|
||||
mutable std::mutex basic_lock;
|
||||
std::mutex advance_lock;
|
||||
std::unique_ptr<std::jthread> timer_thread;
|
||||
std::atomic<bool> paused{};
|
||||
|
||||
@@ -38,14 +38,6 @@ using TouchParams = std::array<Common::ParamPackage, MaxTouchDevices>;
|
||||
using ConsoleMotionValues = ConsoleMotionInfo;
|
||||
using TouchValues = std::array<Common::Input::TouchStatus, MaxTouchDevices>;
|
||||
|
||||
struct TouchFinger {
|
||||
u64 last_touch{};
|
||||
Common::Point<float> position{};
|
||||
u32 id{};
|
||||
TouchAttribute attribute{};
|
||||
bool pressed{};
|
||||
};
|
||||
|
||||
// Contains all motion related data that is used on the services
|
||||
struct ConsoleMotion {
|
||||
Common::Vec3f accel{};
|
||||
|
||||
@@ -243,10 +243,12 @@ void EmulatedController::LoadTASParams() {
|
||||
tas_button_params[Settings::NativeButton::DUp].Set("button", 13);
|
||||
tas_button_params[Settings::NativeButton::DRight].Set("button", 14);
|
||||
tas_button_params[Settings::NativeButton::DDown].Set("button", 15);
|
||||
tas_button_params[Settings::NativeButton::SL].Set("button", 16);
|
||||
tas_button_params[Settings::NativeButton::SR].Set("button", 17);
|
||||
tas_button_params[Settings::NativeButton::SLLeft].Set("button", 16);
|
||||
tas_button_params[Settings::NativeButton::SRLeft].Set("button", 17);
|
||||
tas_button_params[Settings::NativeButton::Home].Set("button", 18);
|
||||
tas_button_params[Settings::NativeButton::Screenshot].Set("button", 19);
|
||||
tas_button_params[Settings::NativeButton::SLRight].Set("button", 20);
|
||||
tas_button_params[Settings::NativeButton::SRRight].Set("button", 21);
|
||||
|
||||
tas_stick_params[Settings::NativeAnalog::LStick].Set("axis_x", 0);
|
||||
tas_stick_params[Settings::NativeAnalog::LStick].Set("axis_y", 1);
|
||||
@@ -296,10 +298,12 @@ void EmulatedController::LoadVirtualGamepadParams() {
|
||||
virtual_button_params[Settings::NativeButton::DUp].Set("button", 13);
|
||||
virtual_button_params[Settings::NativeButton::DRight].Set("button", 14);
|
||||
virtual_button_params[Settings::NativeButton::DDown].Set("button", 15);
|
||||
virtual_button_params[Settings::NativeButton::SL].Set("button", 16);
|
||||
virtual_button_params[Settings::NativeButton::SR].Set("button", 17);
|
||||
virtual_button_params[Settings::NativeButton::SLLeft].Set("button", 16);
|
||||
virtual_button_params[Settings::NativeButton::SRLeft].Set("button", 17);
|
||||
virtual_button_params[Settings::NativeButton::Home].Set("button", 18);
|
||||
virtual_button_params[Settings::NativeButton::Screenshot].Set("button", 19);
|
||||
virtual_button_params[Settings::NativeButton::SLRight].Set("button", 20);
|
||||
virtual_button_params[Settings::NativeButton::SRRight].Set("button", 21);
|
||||
|
||||
virtual_stick_params[Settings::NativeAnalog::LStick].Set("axis_x", 0);
|
||||
virtual_stick_params[Settings::NativeAnalog::LStick].Set("axis_y", 1);
|
||||
@@ -867,12 +871,16 @@ void EmulatedController::SetButton(const Common::Input::CallbackStatus& callback
|
||||
controller.npad_button_state.down.Assign(current_status.value);
|
||||
controller.debug_pad_button_state.d_down.Assign(current_status.value);
|
||||
break;
|
||||
case Settings::NativeButton::SL:
|
||||
case Settings::NativeButton::SLLeft:
|
||||
controller.npad_button_state.left_sl.Assign(current_status.value);
|
||||
break;
|
||||
case Settings::NativeButton::SLRight:
|
||||
controller.npad_button_state.right_sl.Assign(current_status.value);
|
||||
break;
|
||||
case Settings::NativeButton::SR:
|
||||
case Settings::NativeButton::SRLeft:
|
||||
controller.npad_button_state.left_sr.Assign(current_status.value);
|
||||
break;
|
||||
case Settings::NativeButton::SRRight:
|
||||
controller.npad_button_state.right_sr.Assign(current_status.value);
|
||||
break;
|
||||
case Settings::NativeButton::Home:
|
||||
@@ -1890,12 +1898,16 @@ NpadButton EmulatedController::GetTurboButtonMask() const {
|
||||
case Settings::NativeButton::DDown:
|
||||
button_mask.down.Assign(1);
|
||||
break;
|
||||
case Settings::NativeButton::SL:
|
||||
case Settings::NativeButton::SLLeft:
|
||||
button_mask.left_sl.Assign(1);
|
||||
break;
|
||||
case Settings::NativeButton::SLRight:
|
||||
button_mask.right_sl.Assign(1);
|
||||
break;
|
||||
case Settings::NativeButton::SR:
|
||||
case Settings::NativeButton::SRLeft:
|
||||
button_mask.left_sr.Assign(1);
|
||||
break;
|
||||
case Settings::NativeButton::SRRight:
|
||||
button_mask.right_sr.Assign(1);
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -218,6 +218,13 @@ enum class NpadIdType : u32 {
|
||||
Invalid = 0xFFFFFFFF,
|
||||
};
|
||||
|
||||
enum class NpadInterfaceType : u8 {
|
||||
Bluetooth = 1,
|
||||
Rail = 2,
|
||||
Usb = 3,
|
||||
Embedded = 4,
|
||||
};
|
||||
|
||||
// This is nn::hid::NpadStyleIndex
|
||||
enum class NpadStyleIndex : u8 {
|
||||
None = 0,
|
||||
@@ -356,6 +363,14 @@ struct TouchState {
|
||||
};
|
||||
static_assert(sizeof(TouchState) == 0x28, "Touchstate is an invalid size");
|
||||
|
||||
struct TouchFinger {
|
||||
u64 last_touch{};
|
||||
Common::Point<float> position{};
|
||||
u32 id{};
|
||||
TouchAttribute attribute{};
|
||||
bool pressed{};
|
||||
};
|
||||
|
||||
// This is nn::hid::TouchScreenConfigurationForNx
|
||||
struct TouchScreenConfigurationForNx {
|
||||
TouchScreenModeForNx mode{TouchScreenModeForNx::UseSystemSetting};
|
||||
|
||||
@@ -5,13 +5,14 @@
|
||||
#include "core/hid/hid_types.h"
|
||||
#include "core/hid/input_interpreter.h"
|
||||
#include "core/hle/service/hid/controllers/npad.h"
|
||||
#include "core/hle/service/hid/hid.h"
|
||||
#include "core/hle/service/hid/hid_server.h"
|
||||
#include "core/hle/service/hid/resource_manager.h"
|
||||
#include "core/hle/service/sm/sm.h"
|
||||
|
||||
InputInterpreter::InputInterpreter(Core::System& system)
|
||||
: npad{system.ServiceManager()
|
||||
.GetService<Service::HID::Hid>("hid")
|
||||
->GetAppletResource()
|
||||
.GetService<Service::HID::IHidServer>("hid")
|
||||
->GetResourceManager()
|
||||
->GetController<Service::HID::Controller_NPad>(Service::HID::HidController::NPad)} {
|
||||
ResetButtonStates();
|
||||
}
|
||||
|
||||
@@ -1617,9 +1617,9 @@ void KPageTableBase::RemapPageGroup(PageLinkedList* page_list, KProcessAddress a
|
||||
const KMemoryInfo info = it->GetMemoryInfo();
|
||||
|
||||
// Determine the range to map.
|
||||
KProcessAddress map_address = std::max(info.GetAddress(), GetInteger(start_address));
|
||||
KProcessAddress map_address = std::max<u64>(info.GetAddress(), GetInteger(start_address));
|
||||
const KProcessAddress map_end_address =
|
||||
std::min(info.GetEndAddress(), GetInteger(end_address));
|
||||
std::min<u64>(info.GetEndAddress(), GetInteger(end_address));
|
||||
ASSERT(map_end_address != map_address);
|
||||
|
||||
// Determine if we should disable head merge.
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "core/file_sys/patch_manager.h"
|
||||
#include "core/file_sys/registered_cache.h"
|
||||
#include "core/file_sys/savedata_factory.h"
|
||||
#include "core/hid/hid_types.h"
|
||||
#include "core/hle/kernel/k_event.h"
|
||||
#include "core/hle/kernel/k_transfer_memory.h"
|
||||
#include "core/hle/result.h"
|
||||
@@ -21,6 +22,7 @@
|
||||
#include "core/hle/service/am/applet_ae.h"
|
||||
#include "core/hle/service/am/applet_oe.h"
|
||||
#include "core/hle/service/am/applets/applet_cabinet.h"
|
||||
#include "core/hle/service/am/applets/applet_controller.h"
|
||||
#include "core/hle/service/am/applets/applet_mii_edit_types.h"
|
||||
#include "core/hle/service/am/applets/applet_profile_select.h"
|
||||
#include "core/hle/service/am/applets/applet_software_keyboard_types.h"
|
||||
@@ -35,6 +37,7 @@
|
||||
#include "core/hle/service/caps/caps_su.h"
|
||||
#include "core/hle/service/caps/caps_types.h"
|
||||
#include "core/hle/service/filesystem/filesystem.h"
|
||||
#include "core/hle/service/hid/controllers/npad.h"
|
||||
#include "core/hle/service/ipc_helpers.h"
|
||||
#include "core/hle/service/ns/ns.h"
|
||||
#include "core/hle/service/nvnflinger/fb_share_buffer_manager.h"
|
||||
@@ -73,7 +76,7 @@ IWindowController::IWindowController(Core::System& system_)
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, nullptr, "CreateWindow"},
|
||||
{1, &IWindowController::GetAppletResourceUserId, "GetAppletResourceUserId"},
|
||||
{2, nullptr, "GetAppletResourceUserIdOfCallerApplet"},
|
||||
{2, &IWindowController::GetAppletResourceUserIdOfCallerApplet, "GetAppletResourceUserIdOfCallerApplet"},
|
||||
{10, &IWindowController::AcquireForegroundRights, "AcquireForegroundRights"},
|
||||
{11, nullptr, "ReleaseForegroundRights"},
|
||||
{12, nullptr, "RejectToChangeIntoBackground"},
|
||||
@@ -97,6 +100,16 @@ void IWindowController::GetAppletResourceUserId(HLERequestContext& ctx) {
|
||||
rb.Push<u64>(process_id);
|
||||
}
|
||||
|
||||
void IWindowController::GetAppletResourceUserIdOfCallerApplet(HLERequestContext& ctx) {
|
||||
const u64 process_id = 0;
|
||||
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push<u64>(process_id);
|
||||
}
|
||||
|
||||
void IWindowController::AcquireForegroundRights(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
@@ -1565,7 +1578,7 @@ ILibraryAppletSelfAccessor::ILibraryAppletSelfAccessor(Core::System& system_)
|
||||
{6, nullptr, "GetPopInteractiveInDataEvent"},
|
||||
{10, &ILibraryAppletSelfAccessor::ExitProcessAndReturn, "ExitProcessAndReturn"},
|
||||
{11, &ILibraryAppletSelfAccessor::GetLibraryAppletInfo, "GetLibraryAppletInfo"},
|
||||
{12, nullptr, "GetMainAppletIdentityInfo"},
|
||||
{12, &ILibraryAppletSelfAccessor::GetMainAppletIdentityInfo, "GetMainAppletIdentityInfo"},
|
||||
{13, nullptr, "CanUseApplicationCore"},
|
||||
{14, &ILibraryAppletSelfAccessor::GetCallerAppletIdentityInfo, "GetCallerAppletIdentityInfo"},
|
||||
{15, nullptr, "GetMainAppletApplicationControlProperty"},
|
||||
@@ -1609,6 +1622,9 @@ ILibraryAppletSelfAccessor::ILibraryAppletSelfAccessor(Core::System& system_)
|
||||
case Applets::AppletId::SoftwareKeyboard:
|
||||
PushInShowSoftwareKeyboard();
|
||||
break;
|
||||
case Applets::AppletId::Controller:
|
||||
PushInShowController();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -1666,13 +1682,33 @@ void ILibraryAppletSelfAccessor::GetLibraryAppletInfo(HLERequestContext& ctx) {
|
||||
rb.PushRaw(applet_info);
|
||||
}
|
||||
|
||||
void ILibraryAppletSelfAccessor::GetMainAppletIdentityInfo(HLERequestContext& ctx) {
|
||||
struct AppletIdentityInfo {
|
||||
Applets::AppletId applet_id;
|
||||
INSERT_PADDING_BYTES(0x4);
|
||||
u64 application_id;
|
||||
};
|
||||
static_assert(sizeof(AppletIdentityInfo) == 0x10, "AppletIdentityInfo has incorrect size.");
|
||||
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
const AppletIdentityInfo applet_info{
|
||||
.applet_id = Applets::AppletId::QLaunch,
|
||||
.application_id = 0x0100000000001000ull,
|
||||
};
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 6};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushRaw(applet_info);
|
||||
}
|
||||
|
||||
void ILibraryAppletSelfAccessor::GetCallerAppletIdentityInfo(HLERequestContext& ctx) {
|
||||
struct AppletIdentityInfo {
|
||||
Applets::AppletId applet_id;
|
||||
INSERT_PADDING_BYTES(0x4);
|
||||
u64 application_id;
|
||||
};
|
||||
|
||||
static_assert(sizeof(AppletIdentityInfo) == 0x10, "AppletIdentityInfo has incorrect size.");
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
const AppletIdentityInfo applet_info{
|
||||
@@ -1737,6 +1773,55 @@ void ILibraryAppletSelfAccessor::PushInShowAlbum() {
|
||||
queue_data.emplace_back(std::move(settings_data));
|
||||
}
|
||||
|
||||
void ILibraryAppletSelfAccessor::PushInShowController() {
|
||||
const Applets::CommonArguments common_args = {
|
||||
.arguments_version = Applets::CommonArgumentVersion::Version3,
|
||||
.size = Applets::CommonArgumentSize::Version3,
|
||||
.library_version = static_cast<u32>(Applets::ControllerAppletVersion::Version8),
|
||||
.theme_color = Applets::ThemeColor::BasicBlack,
|
||||
.play_startup_sound = true,
|
||||
.system_tick = system.CoreTiming().GetClockTicks(),
|
||||
};
|
||||
|
||||
Applets::ControllerSupportArgNew user_args = {
|
||||
.header = {.player_count_min = 1,
|
||||
.player_count_max = 4,
|
||||
.enable_take_over_connection = true,
|
||||
.enable_left_justify = false,
|
||||
.enable_permit_joy_dual = true,
|
||||
.enable_single_mode = false,
|
||||
.enable_identification_color = false},
|
||||
.identification_colors = {},
|
||||
.enable_explain_text = false,
|
||||
.explain_text = {},
|
||||
};
|
||||
|
||||
Applets::ControllerSupportArgPrivate private_args = {
|
||||
.arg_private_size = sizeof(Applets::ControllerSupportArgPrivate),
|
||||
.arg_size = sizeof(Applets::ControllerSupportArgNew),
|
||||
.is_home_menu = true,
|
||||
.flag_1 = true,
|
||||
.mode = Applets::ControllerSupportMode::ShowControllerSupport,
|
||||
.caller = Applets::ControllerSupportCaller::
|
||||
Application, // switchbrew: Always zero except with
|
||||
// ShowControllerFirmwareUpdateForSystem/ShowControllerKeyRemappingForSystem,
|
||||
// which sets this to the input param
|
||||
.style_set = Core::HID::NpadStyleSet::None,
|
||||
.joy_hold_type = 0,
|
||||
};
|
||||
std::vector<u8> common_args_data(sizeof(common_args));
|
||||
std::vector<u8> private_args_data(sizeof(private_args));
|
||||
std::vector<u8> user_args_data(sizeof(user_args));
|
||||
|
||||
std::memcpy(common_args_data.data(), &common_args, sizeof(common_args));
|
||||
std::memcpy(private_args_data.data(), &private_args, sizeof(private_args));
|
||||
std::memcpy(user_args_data.data(), &user_args, sizeof(user_args));
|
||||
|
||||
queue_data.emplace_back(std::move(common_args_data));
|
||||
queue_data.emplace_back(std::move(private_args_data));
|
||||
queue_data.emplace_back(std::move(user_args_data));
|
||||
}
|
||||
|
||||
void ILibraryAppletSelfAccessor::PushInShowCabinetData() {
|
||||
const Applets::CommonArguments arguments{
|
||||
.arguments_version = Applets::CommonArgumentVersion::Version3,
|
||||
|
||||
@@ -87,6 +87,7 @@ public:
|
||||
|
||||
private:
|
||||
void GetAppletResourceUserId(HLERequestContext& ctx);
|
||||
void GetAppletResourceUserIdOfCallerApplet(HLERequestContext& ctx);
|
||||
void AcquireForegroundRights(HLERequestContext& ctx);
|
||||
};
|
||||
|
||||
@@ -345,6 +346,7 @@ private:
|
||||
void PopInData(HLERequestContext& ctx);
|
||||
void PushOutData(HLERequestContext& ctx);
|
||||
void GetLibraryAppletInfo(HLERequestContext& ctx);
|
||||
void GetMainAppletIdentityInfo(HLERequestContext& ctx);
|
||||
void ExitProcessAndReturn(HLERequestContext& ctx);
|
||||
void GetCallerAppletIdentityInfo(HLERequestContext& ctx);
|
||||
void GetDesirableKeyboardLayout(HLERequestContext& ctx);
|
||||
@@ -355,6 +357,7 @@ private:
|
||||
void PushInShowCabinetData();
|
||||
void PushInShowMiiEditData();
|
||||
void PushInShowSoftwareKeyboard();
|
||||
void PushInShowController();
|
||||
|
||||
std::deque<std::vector<u8>> queue_data;
|
||||
};
|
||||
|
||||
@@ -56,7 +56,7 @@ enum class ControllerSupportResult : u32 {
|
||||
struct ControllerSupportArgPrivate {
|
||||
u32 arg_private_size{};
|
||||
u32 arg_size{};
|
||||
bool flag_0{};
|
||||
bool is_home_menu{};
|
||||
bool flag_1{};
|
||||
ControllerSupportMode mode{};
|
||||
ControllerSupportCaller caller{};
|
||||
|
||||
@@ -127,7 +127,7 @@ public:
|
||||
|
||||
private:
|
||||
void GetCore(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_BTM, "called");
|
||||
LOG_WARNING(Service_BTM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
@@ -263,13 +263,13 @@ public:
|
||||
explicit IBtmSystemCore(Core::System& system_) : ServiceFramework{system_, "IBtmSystemCore"} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, nullptr, "StartGamepadPairing"},
|
||||
{1, nullptr, "CancelGamepadPairing"},
|
||||
{0, &IBtmSystemCore::StartGamepadPairing, "StartGamepadPairing"},
|
||||
{1, &IBtmSystemCore::CancelGamepadPairing, "CancelGamepadPairing"},
|
||||
{2, nullptr, "ClearGamepadPairingDatabase"},
|
||||
{3, nullptr, "GetPairedGamepadCount"},
|
||||
{4, nullptr, "EnableRadio"},
|
||||
{5, nullptr, "DisableRadio"},
|
||||
{6, nullptr, "GetRadioOnOff"},
|
||||
{6, &IBtmSystemCore::IsRadioEnabled, "IsRadioEnabled"},
|
||||
{7, nullptr, "AcquireRadioEvent"},
|
||||
{8, nullptr, "AcquireGamepadPairingEvent"},
|
||||
{9, nullptr, "IsGamepadPairingStarted"},
|
||||
@@ -280,18 +280,58 @@ public:
|
||||
{14, nullptr, "AcquireAudioDeviceConnectionEvent"},
|
||||
{15, nullptr, "ConnectAudioDevice"},
|
||||
{16, nullptr, "IsConnectingAudioDevice"},
|
||||
{17, nullptr, "GetConnectedAudioDevices"},
|
||||
{17, &IBtmSystemCore::GetConnectedAudioDevices, "GetConnectedAudioDevices"},
|
||||
{18, nullptr, "DisconnectAudioDevice"},
|
||||
{19, nullptr, "AcquirePairedAudioDeviceInfoChangedEvent"},
|
||||
{20, nullptr, "GetPairedAudioDevices"},
|
||||
{21, nullptr, "RemoveAudioDevicePairing"},
|
||||
{22, nullptr, "RequestAudioDeviceConnectionRejection"},
|
||||
{23, nullptr, "CancelAudioDeviceConnectionRejection"}
|
||||
{22, &IBtmSystemCore::RequestAudioDeviceConnectionRejection, "RequestAudioDeviceConnectionRejection"},
|
||||
{23, &IBtmSystemCore::CancelAudioDeviceConnectionRejection, "CancelAudioDeviceConnectionRejection"}
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
private:
|
||||
void IsRadioEnabled(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_BTM, "(STUBBED) called"); // Spams a lot when controller applet is running
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push(true);
|
||||
}
|
||||
|
||||
void StartGamepadPairing(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_BTM, "(STUBBED) called");
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void CancelGamepadPairing(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_BTM, "(STUBBED) called");
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void CancelAudioDeviceConnectionRejection(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_BTM, "(STUBBED) called");
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void GetConnectedAudioDevices(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_BTM, "(STUBBED) called");
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push<u32>(0);
|
||||
}
|
||||
|
||||
void RequestAudioDeviceConnectionRejection(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_BTM, "(STUBBED) called");
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
};
|
||||
|
||||
class BTM_SYS final : public ServiceFramework<BTM_SYS> {
|
||||
@@ -308,7 +348,7 @@ public:
|
||||
|
||||
private:
|
||||
void GetCore(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_BTM, "called");
|
||||
LOG_WARNING(Service_BTM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
|
||||
@@ -32,7 +32,7 @@ public:
|
||||
{10200, nullptr, "SendFriendRequestForApplication"},
|
||||
{10211, nullptr, "AddFacedFriendRequestForApplication"},
|
||||
{10400, &IFriendService::GetBlockedUserListIds, "GetBlockedUserListIds"},
|
||||
{10420, nullptr, "IsBlockedUserListCacheAvailable"},
|
||||
{10420, &IFriendService::CheckBlockedUserListAvailability, "CheckBlockedUserListAvailability"},
|
||||
{10421, nullptr, "EnsureBlockedUserListAvailable"},
|
||||
{10500, nullptr, "GetProfileList"},
|
||||
{10600, nullptr, "DeclareOpenOnlinePlaySession"},
|
||||
@@ -206,6 +206,17 @@ private:
|
||||
rb.Push(true);
|
||||
}
|
||||
|
||||
void CheckBlockedUserListAvailability(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto uuid{rp.PopRaw<Common::UUID>()};
|
||||
|
||||
LOG_WARNING(Service_Friend, "(STUBBED) called, uuid=0x{}", uuid.RawString());
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push(true);
|
||||
}
|
||||
|
||||
KernelHelpers::ServiceContext service_context;
|
||||
|
||||
Kernel::KEvent* completion_event;
|
||||
|
||||
@@ -8,12 +8,17 @@ namespace Service::HID {
|
||||
ControllerBase::ControllerBase(Core::HID::HIDCore& hid_core_) : hid_core(hid_core_) {}
|
||||
ControllerBase::~ControllerBase() = default;
|
||||
|
||||
void ControllerBase::ActivateController() {
|
||||
Result ControllerBase::Activate() {
|
||||
if (is_activated) {
|
||||
return;
|
||||
return ResultSuccess;
|
||||
}
|
||||
is_activated = true;
|
||||
OnInit();
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result ControllerBase::Activate(u64 aruid) {
|
||||
return Activate();
|
||||
}
|
||||
|
||||
void ControllerBase::DeactivateController() {
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "core/hle/result.h"
|
||||
|
||||
namespace Core::Timing {
|
||||
class CoreTiming;
|
||||
@@ -31,7 +32,8 @@ public:
|
||||
// When the controller is requesting a motion update for the shared memory
|
||||
virtual void OnMotionUpdate(const Core::Timing::CoreTiming& core_timing) {}
|
||||
|
||||
void ActivateController();
|
||||
Result Activate();
|
||||
Result Activate(u64 aruid);
|
||||
|
||||
void DeactivateController();
|
||||
|
||||
|
||||
@@ -344,6 +344,7 @@ void Controller_NPad::InitNewlyAddedController(Core::HID::NpadIdType npad_id) {
|
||||
controller.device->SetPollingMode(Core::HID::EmulatedDeviceIndex::AllDevices,
|
||||
Common::Input::PollingMode::Active);
|
||||
}
|
||||
|
||||
SignalStyleSetChangedEvent(npad_id);
|
||||
WriteEmptyEntry(controller.shared_memory);
|
||||
hid_core.SetLastActiveController(npad_id);
|
||||
@@ -457,12 +458,14 @@ void Controller_NPad::RequestPadStateUpdate(Core::HID::NpadIdType npad_id) {
|
||||
pad_entry.l_stick = stick_state.left;
|
||||
}
|
||||
|
||||
if (controller_type == Core::HID::NpadStyleIndex::JoyconLeft) {
|
||||
if (controller_type == Core::HID::NpadStyleIndex::JoyconLeft ||
|
||||
controller_type == Core::HID::NpadStyleIndex::JoyconDual) {
|
||||
pad_entry.npad_buttons.left_sl.Assign(button_state.left_sl);
|
||||
pad_entry.npad_buttons.left_sr.Assign(button_state.left_sr);
|
||||
}
|
||||
|
||||
if (controller_type == Core::HID::NpadStyleIndex::JoyconRight) {
|
||||
if (controller_type == Core::HID::NpadStyleIndex::JoyconRight ||
|
||||
controller_type == Core::HID::NpadStyleIndex::JoyconDual) {
|
||||
pad_entry.npad_buttons.right_sl.Assign(button_state.right_sl);
|
||||
pad_entry.npad_buttons.right_sr.Assign(button_state.right_sr);
|
||||
}
|
||||
@@ -1724,4 +1727,19 @@ const Controller_NPad::SixaxisParameters& Controller_NPad::GetSixaxisState(
|
||||
}
|
||||
}
|
||||
|
||||
Controller_NPad::AppletDetailedUiType Controller_NPad::GetAppletDetailedUiType(
|
||||
Core::HID::NpadIdType npad_id) {
|
||||
|
||||
auto controller = GetControllerFromNpadIdType(npad_id);
|
||||
auto shared_memory = controller.shared_memory;
|
||||
Service::HID::Controller_NPad::AppletFooterUiType applet_footer_type =
|
||||
shared_memory->applet_footer_type;
|
||||
|
||||
Controller_NPad::AppletDetailedUiType detailed_ui_type{
|
||||
.ui_variant = 0,
|
||||
.footer = applet_footer_type,
|
||||
};
|
||||
return detailed_ui_type;
|
||||
}
|
||||
|
||||
} // namespace Service::HID
|
||||
|
||||
@@ -78,6 +78,46 @@ public:
|
||||
MaxActivationMode = 3,
|
||||
};
|
||||
|
||||
// This is nn::hid::system::AppletFooterUiAttributesSet
|
||||
struct AppletFooterUiAttributes {
|
||||
INSERT_PADDING_BYTES(0x4);
|
||||
};
|
||||
|
||||
// This is nn::hid::system::AppletFooterUiType
|
||||
enum class AppletFooterUiType : u8 {
|
||||
None = 0,
|
||||
HandheldNone = 1,
|
||||
HandheldJoyConLeftOnly = 2,
|
||||
HandheldJoyConRightOnly = 3,
|
||||
HandheldJoyConLeftJoyConRight = 4,
|
||||
JoyDual = 5,
|
||||
JoyDualLeftOnly = 6,
|
||||
JoyDualRightOnly = 7,
|
||||
JoyLeftHorizontal = 8,
|
||||
JoyLeftVertical = 9,
|
||||
JoyRightHorizontal = 10,
|
||||
JoyRightVertical = 11,
|
||||
SwitchProController = 12,
|
||||
CompatibleProController = 13,
|
||||
CompatibleJoyCon = 14,
|
||||
LarkHvc1 = 15,
|
||||
LarkHvc2 = 16,
|
||||
LarkNesLeft = 17,
|
||||
LarkNesRight = 18,
|
||||
Lucia = 19,
|
||||
Verification = 20,
|
||||
Lagon = 21,
|
||||
};
|
||||
|
||||
using AppletFooterUiVariant = u8;
|
||||
|
||||
// This is "nn::hid::system::AppletDetailedUiType".
|
||||
struct AppletDetailedUiType {
|
||||
AppletFooterUiVariant ui_variant;
|
||||
INSERT_PADDING_BYTES(0x2);
|
||||
AppletFooterUiType footer;
|
||||
};
|
||||
static_assert(sizeof(AppletDetailedUiType) == 0x4, "AppletDetailedUiType is an invalid size");
|
||||
// This is nn::hid::NpadCommunicationMode
|
||||
enum class NpadCommunicationMode : u64 {
|
||||
Mode_5ms = 0,
|
||||
@@ -86,6 +126,13 @@ public:
|
||||
Default = 3,
|
||||
};
|
||||
|
||||
enum class NpadRevision : u32 {
|
||||
Revision0 = 0,
|
||||
Revision1 = 1,
|
||||
Revision2 = 2,
|
||||
Revision3 = 3,
|
||||
};
|
||||
|
||||
void SetSupportedStyleSet(Core::HID::NpadStyleTag style_set);
|
||||
Core::HID::NpadStyleTag GetSupportedStyleSet() const;
|
||||
|
||||
@@ -196,6 +243,7 @@ public:
|
||||
static Result IsDeviceHandleValid(const Core::HID::VibrationDeviceHandle& device_handle);
|
||||
static Result VerifyValidSixAxisSensorHandle(
|
||||
const Core::HID::SixAxisSensorHandle& device_handle);
|
||||
AppletDetailedUiType GetAppletDetailedUiType(Core::HID::NpadIdType npad_id);
|
||||
|
||||
private:
|
||||
static constexpr std::size_t NPAD_COUNT = 10;
|
||||
@@ -353,37 +401,6 @@ private:
|
||||
static_assert(sizeof(NfcXcdDeviceHandleStateImpl) == 0x18,
|
||||
"NfcXcdDeviceHandleStateImpl is an invalid size");
|
||||
|
||||
// This is nn::hid::system::AppletFooterUiAttributesSet
|
||||
struct AppletFooterUiAttributes {
|
||||
INSERT_PADDING_BYTES(0x4);
|
||||
};
|
||||
|
||||
// This is nn::hid::system::AppletFooterUiType
|
||||
enum class AppletFooterUiType : u8 {
|
||||
None = 0,
|
||||
HandheldNone = 1,
|
||||
HandheldJoyConLeftOnly = 2,
|
||||
HandheldJoyConRightOnly = 3,
|
||||
HandheldJoyConLeftJoyConRight = 4,
|
||||
JoyDual = 5,
|
||||
JoyDualLeftOnly = 6,
|
||||
JoyDualRightOnly = 7,
|
||||
JoyLeftHorizontal = 8,
|
||||
JoyLeftVertical = 9,
|
||||
JoyRightHorizontal = 10,
|
||||
JoyRightVertical = 11,
|
||||
SwitchProController = 12,
|
||||
CompatibleProController = 13,
|
||||
CompatibleJoyCon = 14,
|
||||
LarkHvc1 = 15,
|
||||
LarkHvc2 = 16,
|
||||
LarkNesLeft = 17,
|
||||
LarkNesRight = 18,
|
||||
Lucia = 19,
|
||||
Verification = 20,
|
||||
Lagon = 21,
|
||||
};
|
||||
|
||||
// This is nn::hid::NpadLarkType
|
||||
enum class NpadLarkType : u32 {
|
||||
Invalid,
|
||||
|
||||
@@ -44,7 +44,7 @@ Result Controller_Palma::InitializePalma(const PalmaConnectionHandle& handle) {
|
||||
if (handle.npad_id != active_handle.npad_id) {
|
||||
return InvalidPalmaHandle;
|
||||
}
|
||||
ActivateController();
|
||||
Activate();
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -3,220 +3,12 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <chrono>
|
||||
|
||||
#include "core/hle/service/hid/controllers/controller_base.h"
|
||||
#include "core/hle/service/kernel_helpers.h"
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Core::Timing {
|
||||
struct EventType;
|
||||
}
|
||||
|
||||
namespace Service::SM {
|
||||
class ServiceManager;
|
||||
namespace Core {
|
||||
class System;
|
||||
}
|
||||
|
||||
namespace Service::HID {
|
||||
|
||||
enum class HidController : std::size_t {
|
||||
DebugPad,
|
||||
Touchscreen,
|
||||
Mouse,
|
||||
Keyboard,
|
||||
XPad,
|
||||
HomeButton,
|
||||
SleepButton,
|
||||
CaptureButton,
|
||||
InputDetector,
|
||||
UniquePad,
|
||||
NPad,
|
||||
Gesture,
|
||||
ConsoleSixAxisSensor,
|
||||
DebugMouse,
|
||||
Palma,
|
||||
|
||||
MaxControllers,
|
||||
};
|
||||
|
||||
class IAppletResource final : public ServiceFramework<IAppletResource> {
|
||||
public:
|
||||
explicit IAppletResource(Core::System& system_,
|
||||
KernelHelpers::ServiceContext& service_context_);
|
||||
~IAppletResource() override;
|
||||
|
||||
void ActivateController(HidController controller);
|
||||
void DeactivateController(HidController controller);
|
||||
|
||||
template <typename T>
|
||||
T& GetController(HidController controller) {
|
||||
return static_cast<T&>(*controllers[static_cast<size_t>(controller)]);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
const T& GetController(HidController controller) const {
|
||||
return static_cast<T&>(*controllers[static_cast<size_t>(controller)]);
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename T>
|
||||
void MakeController(HidController controller, u8* shared_memory) {
|
||||
if constexpr (std::is_constructible_v<T, Core::System&, u8*>) {
|
||||
controllers[static_cast<std::size_t>(controller)] =
|
||||
std::make_unique<T>(system, shared_memory);
|
||||
} else {
|
||||
controllers[static_cast<std::size_t>(controller)] =
|
||||
std::make_unique<T>(system.HIDCore(), shared_memory);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void MakeControllerWithServiceContext(HidController controller, u8* shared_memory) {
|
||||
controllers[static_cast<std::size_t>(controller)] =
|
||||
std::make_unique<T>(system.HIDCore(), shared_memory, service_context);
|
||||
}
|
||||
|
||||
void GetSharedMemoryHandle(HLERequestContext& ctx);
|
||||
void UpdateControllers(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
|
||||
void UpdateNpad(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
|
||||
void UpdateMouseKeyboard(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
|
||||
void UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
|
||||
|
||||
KernelHelpers::ServiceContext& service_context;
|
||||
|
||||
std::shared_ptr<Core::Timing::EventType> npad_update_event;
|
||||
std::shared_ptr<Core::Timing::EventType> default_update_event;
|
||||
std::shared_ptr<Core::Timing::EventType> mouse_keyboard_update_event;
|
||||
std::shared_ptr<Core::Timing::EventType> motion_update_event;
|
||||
|
||||
std::array<std::unique_ptr<ControllerBase>, static_cast<size_t>(HidController::MaxControllers)>
|
||||
controllers{};
|
||||
};
|
||||
|
||||
class Hid final : public ServiceFramework<Hid> {
|
||||
public:
|
||||
explicit Hid(Core::System& system_, std::shared_ptr<IAppletResource> applet_resource_);
|
||||
~Hid() override;
|
||||
|
||||
std::shared_ptr<IAppletResource> GetAppletResource();
|
||||
|
||||
private:
|
||||
void CreateAppletResource(HLERequestContext& ctx);
|
||||
void ActivateDebugPad(HLERequestContext& ctx);
|
||||
void ActivateTouchScreen(HLERequestContext& ctx);
|
||||
void ActivateMouse(HLERequestContext& ctx);
|
||||
void ActivateKeyboard(HLERequestContext& ctx);
|
||||
void SendKeyboardLockKeyEvent(HLERequestContext& ctx);
|
||||
void ActivateXpad(HLERequestContext& ctx);
|
||||
void GetXpadIDs(HLERequestContext& ctx);
|
||||
void ActivateSixAxisSensor(HLERequestContext& ctx);
|
||||
void DeactivateSixAxisSensor(HLERequestContext& ctx);
|
||||
void StartSixAxisSensor(HLERequestContext& ctx);
|
||||
void StopSixAxisSensor(HLERequestContext& ctx);
|
||||
void IsSixAxisSensorFusionEnabled(HLERequestContext& ctx);
|
||||
void EnableSixAxisSensorFusion(HLERequestContext& ctx);
|
||||
void SetSixAxisSensorFusionParameters(HLERequestContext& ctx);
|
||||
void GetSixAxisSensorFusionParameters(HLERequestContext& ctx);
|
||||
void ResetSixAxisSensorFusionParameters(HLERequestContext& ctx);
|
||||
void SetGyroscopeZeroDriftMode(HLERequestContext& ctx);
|
||||
void GetGyroscopeZeroDriftMode(HLERequestContext& ctx);
|
||||
void ResetGyroscopeZeroDriftMode(HLERequestContext& ctx);
|
||||
void IsSixAxisSensorAtRest(HLERequestContext& ctx);
|
||||
void IsFirmwareUpdateAvailableForSixAxisSensor(HLERequestContext& ctx);
|
||||
void EnableSixAxisSensorUnalteredPassthrough(HLERequestContext& ctx);
|
||||
void IsSixAxisSensorUnalteredPassthroughEnabled(HLERequestContext& ctx);
|
||||
void LoadSixAxisSensorCalibrationParameter(HLERequestContext& ctx);
|
||||
void GetSixAxisSensorIcInformation(HLERequestContext& ctx);
|
||||
void ResetIsSixAxisSensorDeviceNewlyAssigned(HLERequestContext& ctx);
|
||||
void ActivateGesture(HLERequestContext& ctx);
|
||||
void SetSupportedNpadStyleSet(HLERequestContext& ctx);
|
||||
void GetSupportedNpadStyleSet(HLERequestContext& ctx);
|
||||
void SetSupportedNpadIdType(HLERequestContext& ctx);
|
||||
void ActivateNpad(HLERequestContext& ctx);
|
||||
void DeactivateNpad(HLERequestContext& ctx);
|
||||
void AcquireNpadStyleSetUpdateEventHandle(HLERequestContext& ctx);
|
||||
void DisconnectNpad(HLERequestContext& ctx);
|
||||
void GetPlayerLedPattern(HLERequestContext& ctx);
|
||||
void ActivateNpadWithRevision(HLERequestContext& ctx);
|
||||
void SetNpadJoyHoldType(HLERequestContext& ctx);
|
||||
void GetNpadJoyHoldType(HLERequestContext& ctx);
|
||||
void SetNpadJoyAssignmentModeSingleByDefault(HLERequestContext& ctx);
|
||||
void SetNpadJoyAssignmentModeSingle(HLERequestContext& ctx);
|
||||
void SetNpadJoyAssignmentModeDual(HLERequestContext& ctx);
|
||||
void MergeSingleJoyAsDualJoy(HLERequestContext& ctx);
|
||||
void StartLrAssignmentMode(HLERequestContext& ctx);
|
||||
void StopLrAssignmentMode(HLERequestContext& ctx);
|
||||
void SetNpadHandheldActivationMode(HLERequestContext& ctx);
|
||||
void GetNpadHandheldActivationMode(HLERequestContext& ctx);
|
||||
void SwapNpadAssignment(HLERequestContext& ctx);
|
||||
void IsUnintendedHomeButtonInputProtectionEnabled(HLERequestContext& ctx);
|
||||
void EnableUnintendedHomeButtonInputProtection(HLERequestContext& ctx);
|
||||
void SetNpadJoyAssignmentModeSingleWithDestination(HLERequestContext& ctx);
|
||||
void SetNpadAnalogStickUseCenterClamp(HLERequestContext& ctx);
|
||||
void SetNpadCaptureButtonAssignment(HLERequestContext& ctx);
|
||||
void ClearNpadCaptureButtonAssignment(HLERequestContext& ctx);
|
||||
void GetVibrationDeviceInfo(HLERequestContext& ctx);
|
||||
void SendVibrationValue(HLERequestContext& ctx);
|
||||
void GetActualVibrationValue(HLERequestContext& ctx);
|
||||
void CreateActiveVibrationDeviceList(HLERequestContext& ctx);
|
||||
void PermitVibration(HLERequestContext& ctx);
|
||||
void IsVibrationPermitted(HLERequestContext& ctx);
|
||||
void SendVibrationValues(HLERequestContext& ctx);
|
||||
void SendVibrationGcErmCommand(HLERequestContext& ctx);
|
||||
void GetActualVibrationGcErmCommand(HLERequestContext& ctx);
|
||||
void BeginPermitVibrationSession(HLERequestContext& ctx);
|
||||
void EndPermitVibrationSession(HLERequestContext& ctx);
|
||||
void IsVibrationDeviceMounted(HLERequestContext& ctx);
|
||||
void ActivateConsoleSixAxisSensor(HLERequestContext& ctx);
|
||||
void StartConsoleSixAxisSensor(HLERequestContext& ctx);
|
||||
void StopConsoleSixAxisSensor(HLERequestContext& ctx);
|
||||
void ActivateSevenSixAxisSensor(HLERequestContext& ctx);
|
||||
void StartSevenSixAxisSensor(HLERequestContext& ctx);
|
||||
void StopSevenSixAxisSensor(HLERequestContext& ctx);
|
||||
void InitializeSevenSixAxisSensor(HLERequestContext& ctx);
|
||||
void FinalizeSevenSixAxisSensor(HLERequestContext& ctx);
|
||||
void ResetSevenSixAxisSensorTimestamp(HLERequestContext& ctx);
|
||||
void IsUsbFullKeyControllerEnabled(HLERequestContext& ctx);
|
||||
void GetPalmaConnectionHandle(HLERequestContext& ctx);
|
||||
void InitializePalma(HLERequestContext& ctx);
|
||||
void AcquirePalmaOperationCompleteEvent(HLERequestContext& ctx);
|
||||
void GetPalmaOperationInfo(HLERequestContext& ctx);
|
||||
void PlayPalmaActivity(HLERequestContext& ctx);
|
||||
void SetPalmaFrModeType(HLERequestContext& ctx);
|
||||
void ReadPalmaStep(HLERequestContext& ctx);
|
||||
void EnablePalmaStep(HLERequestContext& ctx);
|
||||
void ResetPalmaStep(HLERequestContext& ctx);
|
||||
void ReadPalmaApplicationSection(HLERequestContext& ctx);
|
||||
void WritePalmaApplicationSection(HLERequestContext& ctx);
|
||||
void ReadPalmaUniqueCode(HLERequestContext& ctx);
|
||||
void SetPalmaUniqueCodeInvalid(HLERequestContext& ctx);
|
||||
void WritePalmaActivityEntry(HLERequestContext& ctx);
|
||||
void WritePalmaRgbLedPatternEntry(HLERequestContext& ctx);
|
||||
void WritePalmaWaveEntry(HLERequestContext& ctx);
|
||||
void SetPalmaDataBaseIdentificationVersion(HLERequestContext& ctx);
|
||||
void GetPalmaDataBaseIdentificationVersion(HLERequestContext& ctx);
|
||||
void SuspendPalmaFeature(HLERequestContext& ctx);
|
||||
void GetPalmaOperationResult(HLERequestContext& ctx);
|
||||
void ReadPalmaPlayLog(HLERequestContext& ctx);
|
||||
void ResetPalmaPlayLog(HLERequestContext& ctx);
|
||||
void SetIsPalmaAllConnectable(HLERequestContext& ctx);
|
||||
void SetIsPalmaPairedConnectable(HLERequestContext& ctx);
|
||||
void PairPalma(HLERequestContext& ctx);
|
||||
void SetPalmaBoostMode(HLERequestContext& ctx);
|
||||
void CancelWritePalmaWaveEntry(HLERequestContext& ctx);
|
||||
void EnablePalmaBoostMode(HLERequestContext& ctx);
|
||||
void GetPalmaBluetoothAddress(HLERequestContext& ctx);
|
||||
void SetDisallowedPalmaConnection(HLERequestContext& ctx);
|
||||
void SetNpadCommunicationMode(HLERequestContext& ctx);
|
||||
void GetNpadCommunicationMode(HLERequestContext& ctx);
|
||||
void SetTouchScreenConfiguration(HLERequestContext& ctx);
|
||||
void IsFirmwareUpdateNeededForNotification(HLERequestContext& ctx);
|
||||
|
||||
std::shared_ptr<IAppletResource> applet_resource;
|
||||
|
||||
KernelHelpers::ServiceContext service_context;
|
||||
};
|
||||
|
||||
void LoopProcess(Core::System& system);
|
||||
|
||||
} // namespace Service::HID
|
||||
|
||||
159
src/core/hle/service/hid/hid_debug_server.cpp
Normal file
159
src/core/hle/service/hid/hid_debug_server.cpp
Normal file
@@ -0,0 +1,159 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include "core/hle/service/hid/hid_debug_server.h"
|
||||
#include "core/hle/service/hid/resource_manager.h"
|
||||
#include "core/hle/service/ipc_helpers.h"
|
||||
|
||||
namespace Service::HID {
|
||||
|
||||
IHidDebugServer::IHidDebugServer(Core::System& system_, std::shared_ptr<ResourceManager> resource)
|
||||
: ServiceFramework{system_, "hid:dbg"}, resource_manager{resource} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, nullptr, "DeactivateDebugPad"},
|
||||
{1, nullptr, "SetDebugPadAutoPilotState"},
|
||||
{2, nullptr, "UnsetDebugPadAutoPilotState"},
|
||||
{10, nullptr, "DeactivateTouchScreen"},
|
||||
{11, nullptr, "SetTouchScreenAutoPilotState"},
|
||||
{12, nullptr, "UnsetTouchScreenAutoPilotState"},
|
||||
{13, nullptr, "GetTouchScreenConfiguration"},
|
||||
{14, nullptr, "ProcessTouchScreenAutoTune"},
|
||||
{15, nullptr, "ForceStopTouchScreenManagement"},
|
||||
{16, nullptr, "ForceRestartTouchScreenManagement"},
|
||||
{17, nullptr, "IsTouchScreenManaged"},
|
||||
{20, nullptr, "DeactivateMouse"},
|
||||
{21, nullptr, "SetMouseAutoPilotState"},
|
||||
{22, nullptr, "UnsetMouseAutoPilotState"},
|
||||
{25, nullptr, "SetDebugMouseAutoPilotState"},
|
||||
{26, nullptr, "UnsetDebugMouseAutoPilotState"},
|
||||
{30, nullptr, "DeactivateKeyboard"},
|
||||
{31, nullptr, "SetKeyboardAutoPilotState"},
|
||||
{32, nullptr, "UnsetKeyboardAutoPilotState"},
|
||||
{50, nullptr, "DeactivateXpad"},
|
||||
{51, nullptr, "SetXpadAutoPilotState"},
|
||||
{52, nullptr, "UnsetXpadAutoPilotState"},
|
||||
{53, nullptr, "DeactivateJoyXpad"},
|
||||
{60, nullptr, "ClearNpadSystemCommonPolicy"},
|
||||
{61, nullptr, "DeactivateNpad"},
|
||||
{62, nullptr, "ForceDisconnectNpad"},
|
||||
{91, nullptr, "DeactivateGesture"},
|
||||
{110, nullptr, "DeactivateHomeButton"},
|
||||
{111, nullptr, "SetHomeButtonAutoPilotState"},
|
||||
{112, nullptr, "UnsetHomeButtonAutoPilotState"},
|
||||
{120, nullptr, "DeactivateSleepButton"},
|
||||
{121, nullptr, "SetSleepButtonAutoPilotState"},
|
||||
{122, nullptr, "UnsetSleepButtonAutoPilotState"},
|
||||
{123, nullptr, "DeactivateInputDetector"},
|
||||
{130, nullptr, "DeactivateCaptureButton"},
|
||||
{131, nullptr, "SetCaptureButtonAutoPilotState"},
|
||||
{132, nullptr, "UnsetCaptureButtonAutoPilotState"},
|
||||
{133, nullptr, "SetShiftAccelerometerCalibrationValue"},
|
||||
{134, nullptr, "GetShiftAccelerometerCalibrationValue"},
|
||||
{135, nullptr, "SetShiftGyroscopeCalibrationValue"},
|
||||
{136, nullptr, "GetShiftGyroscopeCalibrationValue"},
|
||||
{140, nullptr, "DeactivateConsoleSixAxisSensor"},
|
||||
{141, nullptr, "GetConsoleSixAxisSensorSamplingFrequency"},
|
||||
{142, nullptr, "DeactivateSevenSixAxisSensor"},
|
||||
{143, nullptr, "GetConsoleSixAxisSensorCountStates"},
|
||||
{144, nullptr, "GetAccelerometerFsr"},
|
||||
{145, nullptr, "SetAccelerometerFsr"},
|
||||
{146, nullptr, "GetAccelerometerOdr"},
|
||||
{147, nullptr, "SetAccelerometerOdr"},
|
||||
{148, nullptr, "GetGyroscopeFsr"},
|
||||
{149, nullptr, "SetGyroscopeFsr"},
|
||||
{150, nullptr, "GetGyroscopeOdr"},
|
||||
{151, nullptr, "SetGyroscopeOdr"},
|
||||
{152, nullptr, "GetWhoAmI"},
|
||||
{201, nullptr, "ActivateFirmwareUpdate"},
|
||||
{202, nullptr, "DeactivateFirmwareUpdate"},
|
||||
{203, nullptr, "StartFirmwareUpdate"},
|
||||
{204, nullptr, "GetFirmwareUpdateStage"},
|
||||
{205, nullptr, "GetFirmwareVersion"},
|
||||
{206, nullptr, "GetDestinationFirmwareVersion"},
|
||||
{207, nullptr, "DiscardFirmwareInfoCacheForRevert"},
|
||||
{208, nullptr, "StartFirmwareUpdateForRevert"},
|
||||
{209, nullptr, "GetAvailableFirmwareVersionForRevert"},
|
||||
{210, nullptr, "IsFirmwareUpdatingDevice"},
|
||||
{211, nullptr, "StartFirmwareUpdateIndividual"},
|
||||
{215, nullptr, "SetUsbFirmwareForceUpdateEnabled"},
|
||||
{216, nullptr, "SetAllKuinaDevicesToFirmwareUpdateMode"},
|
||||
{221, nullptr, "UpdateControllerColor"},
|
||||
{222, nullptr, "ConnectUsbPadsAsync"},
|
||||
{223, nullptr, "DisconnectUsbPadsAsync"},
|
||||
{224, nullptr, "UpdateDesignInfo"},
|
||||
{225, nullptr, "GetUniquePadDriverState"},
|
||||
{226, nullptr, "GetSixAxisSensorDriverStates"},
|
||||
{227, nullptr, "GetRxPacketHistory"},
|
||||
{228, nullptr, "AcquireOperationEventHandle"},
|
||||
{229, nullptr, "ReadSerialFlash"},
|
||||
{230, nullptr, "WriteSerialFlash"},
|
||||
{231, nullptr, "GetOperationResult"},
|
||||
{232, nullptr, "EnableShipmentMode"},
|
||||
{233, nullptr, "ClearPairingInfo"},
|
||||
{234, nullptr, "GetUniquePadDeviceTypeSetInternal"},
|
||||
{235, nullptr, "EnableAnalogStickPower"},
|
||||
{236, nullptr, "RequestKuinaUartClockCal"},
|
||||
{237, nullptr, "GetKuinaUartClockCal"},
|
||||
{238, nullptr, "SetKuinaUartClockTrim"},
|
||||
{239, nullptr, "KuinaLoopbackTest"},
|
||||
{240, nullptr, "RequestBatteryVoltage"},
|
||||
{241, nullptr, "GetBatteryVoltage"},
|
||||
{242, nullptr, "GetUniquePadPowerInfo"},
|
||||
{243, nullptr, "RebootUniquePad"},
|
||||
{244, nullptr, "RequestKuinaFirmwareVersion"},
|
||||
{245, nullptr, "GetKuinaFirmwareVersion"},
|
||||
{246, nullptr, "GetVidPid"},
|
||||
{247, nullptr, "GetAnalogStickCalibrationValue"},
|
||||
{248, nullptr, "GetUniquePadIdsFull"},
|
||||
{249, nullptr, "ConnectUniquePad"},
|
||||
{250, nullptr, "IsVirtual"},
|
||||
{251, nullptr, "GetAnalogStickModuleParam"},
|
||||
{301, nullptr, "GetAbstractedPadHandles"},
|
||||
{302, nullptr, "GetAbstractedPadState"},
|
||||
{303, nullptr, "GetAbstractedPadsState"},
|
||||
{321, nullptr, "SetAutoPilotVirtualPadState"},
|
||||
{322, nullptr, "UnsetAutoPilotVirtualPadState"},
|
||||
{323, nullptr, "UnsetAllAutoPilotVirtualPadState"},
|
||||
{324, nullptr, "AttachHdlsWorkBuffer"},
|
||||
{325, nullptr, "ReleaseHdlsWorkBuffer"},
|
||||
{326, nullptr, "DumpHdlsNpadAssignmentState"},
|
||||
{327, nullptr, "DumpHdlsStates"},
|
||||
{328, nullptr, "ApplyHdlsNpadAssignmentState"},
|
||||
{329, nullptr, "ApplyHdlsStateList"},
|
||||
{330, nullptr, "AttachHdlsVirtualDevice"},
|
||||
{331, nullptr, "DetachHdlsVirtualDevice"},
|
||||
{332, nullptr, "SetHdlsState"},
|
||||
{350, nullptr, "AddRegisteredDevice"},
|
||||
{400, nullptr, "DisableExternalMcuOnNxDevice"},
|
||||
{401, nullptr, "DisableRailDeviceFiltering"},
|
||||
{402, nullptr, "EnableWiredPairing"},
|
||||
{403, nullptr, "EnableShipmentModeAutoClear"},
|
||||
{404, nullptr, "SetRailEnabled"},
|
||||
{500, nullptr, "SetFactoryInt"},
|
||||
{501, nullptr, "IsFactoryBootEnabled"},
|
||||
{550, nullptr, "SetAnalogStickModelDataTemporarily"},
|
||||
{551, nullptr, "GetAnalogStickModelData"},
|
||||
{552, nullptr, "ResetAnalogStickModelData"},
|
||||
{600, nullptr, "ConvertPadState"},
|
||||
{650, nullptr, "AddButtonPlayData"},
|
||||
{651, nullptr, "StartButtonPlayData"},
|
||||
{652, nullptr, "StopButtonPlayData"},
|
||||
{2000, nullptr, "DeactivateDigitizer"},
|
||||
{2001, nullptr, "SetDigitizerAutoPilotState"},
|
||||
{2002, nullptr, "UnsetDigitizerAutoPilotState"},
|
||||
{2002, nullptr, "ReloadFirmwareDebugSettings"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
IHidDebugServer::~IHidDebugServer() = default;
|
||||
|
||||
std::shared_ptr<ResourceManager> IHidDebugServer::GetResourceManager() {
|
||||
resource_manager->Initialize();
|
||||
return resource_manager;
|
||||
}
|
||||
|
||||
} // namespace Service::HID
|
||||
26
src/core/hle/service/hid/hid_debug_server.h
Normal file
26
src/core/hle/service/hid/hid_debug_server.h
Normal file
@@ -0,0 +1,26 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
}
|
||||
|
||||
namespace Service::HID {
|
||||
class ResourceManager;
|
||||
|
||||
class IHidDebugServer final : public ServiceFramework<IHidDebugServer> {
|
||||
public:
|
||||
explicit IHidDebugServer(Core::System& system_, std::shared_ptr<ResourceManager> resource);
|
||||
~IHidDebugServer() override;
|
||||
|
||||
private:
|
||||
std::shared_ptr<ResourceManager> GetResourceManager();
|
||||
|
||||
std::shared_ptr<ResourceManager> resource_manager;
|
||||
};
|
||||
|
||||
} // namespace Service::HID
|
||||
99
src/core/hle/service/hid/hid_firmware_settings.cpp
Normal file
99
src/core/hle/service/hid/hid_firmware_settings.cpp
Normal file
@@ -0,0 +1,99 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include "core/hle/service/hid/hid_firmware_settings.h"
|
||||
|
||||
namespace Service::HID {
|
||||
|
||||
HidFirmwareSettings::HidFirmwareSettings() {
|
||||
LoadSettings(true);
|
||||
}
|
||||
|
||||
void HidFirmwareSettings::Reload() {
|
||||
LoadSettings(true);
|
||||
}
|
||||
|
||||
void HidFirmwareSettings::LoadSettings(bool reload_config) {
|
||||
if (is_initalized && !reload_config) {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: Use nn::settings::fwdbg::GetSettingsItemValue to load config values
|
||||
|
||||
is_debug_pad_enabled = true;
|
||||
is_device_managed = true;
|
||||
is_touch_i2c_managed = is_device_managed;
|
||||
is_future_devices_emulated = false;
|
||||
is_mcu_hardware_error_emulated = false;
|
||||
is_rail_enabled = true;
|
||||
is_firmware_update_failure_emulated = false;
|
||||
is_firmware_update_failure = {};
|
||||
is_ble_disabled = false;
|
||||
is_dscale_disabled = false;
|
||||
is_handheld_forced = true;
|
||||
features_per_id_disabled = {};
|
||||
is_touch_firmware_auto_update_disabled = false;
|
||||
is_initalized = true;
|
||||
}
|
||||
|
||||
bool HidFirmwareSettings::IsDebugPadEnabled() {
|
||||
LoadSettings(false);
|
||||
return is_debug_pad_enabled;
|
||||
}
|
||||
|
||||
bool HidFirmwareSettings::IsDeviceManaged() {
|
||||
LoadSettings(false);
|
||||
return is_device_managed;
|
||||
}
|
||||
|
||||
bool HidFirmwareSettings::IsEmulateFutureDevice() {
|
||||
LoadSettings(false);
|
||||
return is_future_devices_emulated;
|
||||
}
|
||||
|
||||
bool HidFirmwareSettings::IsTouchI2cManaged() {
|
||||
LoadSettings(false);
|
||||
return is_touch_i2c_managed;
|
||||
}
|
||||
|
||||
bool HidFirmwareSettings::IsHandheldForced() {
|
||||
LoadSettings(false);
|
||||
return is_handheld_forced;
|
||||
}
|
||||
|
||||
bool HidFirmwareSettings::IsRailEnabled() {
|
||||
LoadSettings(false);
|
||||
return is_rail_enabled;
|
||||
}
|
||||
|
||||
bool HidFirmwareSettings::IsHardwareErrorEmulated() {
|
||||
LoadSettings(false);
|
||||
return is_mcu_hardware_error_emulated;
|
||||
}
|
||||
|
||||
bool HidFirmwareSettings::IsBleDisabled() {
|
||||
LoadSettings(false);
|
||||
return is_ble_disabled;
|
||||
}
|
||||
|
||||
bool HidFirmwareSettings::IsDscaleDisabled() {
|
||||
LoadSettings(false);
|
||||
return is_dscale_disabled;
|
||||
}
|
||||
|
||||
bool HidFirmwareSettings::IsTouchAutoUpdateDisabled() {
|
||||
LoadSettings(false);
|
||||
return is_touch_firmware_auto_update_disabled;
|
||||
}
|
||||
|
||||
HidFirmwareSettings::FirmwareSetting HidFirmwareSettings::GetFirmwareUpdateFailure() {
|
||||
LoadSettings(false);
|
||||
return is_firmware_update_failure;
|
||||
}
|
||||
|
||||
HidFirmwareSettings::FeaturesPerId HidFirmwareSettings::FeaturesDisabledPerId() {
|
||||
LoadSettings(false);
|
||||
return features_per_id_disabled;
|
||||
}
|
||||
|
||||
} // namespace Service::HID
|
||||
54
src/core/hle/service/hid/hid_firmware_settings.h
Normal file
54
src/core/hle/service/hid/hid_firmware_settings.h
Normal file
@@ -0,0 +1,54 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace Service::HID {
|
||||
|
||||
/// Loads firmware config from nn::settings::fwdbg
|
||||
class HidFirmwareSettings {
|
||||
public:
|
||||
using FirmwareSetting = std::array<u8, 4>;
|
||||
using FeaturesPerId = std::array<bool, 0xA8>;
|
||||
|
||||
HidFirmwareSettings();
|
||||
|
||||
void Reload();
|
||||
void LoadSettings(bool reload_config);
|
||||
|
||||
bool IsDebugPadEnabled();
|
||||
bool IsDeviceManaged();
|
||||
bool IsEmulateFutureDevice();
|
||||
bool IsTouchI2cManaged();
|
||||
bool IsHandheldForced();
|
||||
bool IsRailEnabled();
|
||||
bool IsHardwareErrorEmulated();
|
||||
bool IsBleDisabled();
|
||||
bool IsDscaleDisabled();
|
||||
bool IsTouchAutoUpdateDisabled();
|
||||
|
||||
FirmwareSetting GetFirmwareUpdateFailure();
|
||||
FeaturesPerId FeaturesDisabledPerId();
|
||||
|
||||
private:
|
||||
bool is_initalized{};
|
||||
|
||||
// Debug settings
|
||||
bool is_debug_pad_enabled{};
|
||||
bool is_device_managed{};
|
||||
bool is_touch_i2c_managed{};
|
||||
bool is_future_devices_emulated{};
|
||||
bool is_mcu_hardware_error_emulated{};
|
||||
bool is_rail_enabled{};
|
||||
bool is_firmware_update_failure_emulated{};
|
||||
bool is_ble_disabled{};
|
||||
bool is_dscale_disabled{};
|
||||
bool is_handheld_forced{};
|
||||
bool is_touch_firmware_auto_update_disabled{};
|
||||
FirmwareSetting is_firmware_update_failure{};
|
||||
FeaturesPerId features_per_id_disabled{};
|
||||
};
|
||||
|
||||
} // namespace Service::HID
|
||||
2440
src/core/hle/service/hid/hid_server.cpp
Normal file
2440
src/core/hle/service/hid/hid_server.cpp
Normal file
File diff suppressed because it is too large
Load Diff
149
src/core/hle/service/hid/hid_server.h
Normal file
149
src/core/hle/service/hid/hid_server.h
Normal file
@@ -0,0 +1,149 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
}
|
||||
|
||||
namespace Service::HID {
|
||||
class ResourceManager;
|
||||
class HidFirmwareSettings;
|
||||
|
||||
class IHidServer final : public ServiceFramework<IHidServer> {
|
||||
public:
|
||||
explicit IHidServer(Core::System& system_, std::shared_ptr<ResourceManager> resource,
|
||||
std::shared_ptr<HidFirmwareSettings> settings);
|
||||
~IHidServer() override;
|
||||
|
||||
std::shared_ptr<ResourceManager> GetResourceManager();
|
||||
|
||||
private:
|
||||
void CreateAppletResource(HLERequestContext& ctx);
|
||||
void ActivateDebugPad(HLERequestContext& ctx);
|
||||
void ActivateTouchScreen(HLERequestContext& ctx);
|
||||
void ActivateMouse(HLERequestContext& ctx);
|
||||
void ActivateKeyboard(HLERequestContext& ctx);
|
||||
void SendKeyboardLockKeyEvent(HLERequestContext& ctx);
|
||||
void AcquireXpadIdEventHandle(HLERequestContext& ctx);
|
||||
void ReleaseXpadIdEventHandle(HLERequestContext& ctx);
|
||||
void ActivateXpad(HLERequestContext& ctx);
|
||||
void GetXpadIds(HLERequestContext& ctx);
|
||||
void ActivateJoyXpad(HLERequestContext& ctx);
|
||||
void GetJoyXpadLifoHandle(HLERequestContext& ctx);
|
||||
void GetJoyXpadIds(HLERequestContext& ctx);
|
||||
void ActivateSixAxisSensor(HLERequestContext& ctx);
|
||||
void DeactivateSixAxisSensor(HLERequestContext& ctx);
|
||||
void GetSixAxisSensorLifoHandle(HLERequestContext& ctx);
|
||||
void ActivateJoySixAxisSensor(HLERequestContext& ctx);
|
||||
void DeactivateJoySixAxisSensor(HLERequestContext& ctx);
|
||||
void GetJoySixAxisSensorLifoHandle(HLERequestContext& ctx);
|
||||
void StartSixAxisSensor(HLERequestContext& ctx);
|
||||
void StopSixAxisSensor(HLERequestContext& ctx);
|
||||
void IsSixAxisSensorFusionEnabled(HLERequestContext& ctx);
|
||||
void EnableSixAxisSensorFusion(HLERequestContext& ctx);
|
||||
void SetSixAxisSensorFusionParameters(HLERequestContext& ctx);
|
||||
void GetSixAxisSensorFusionParameters(HLERequestContext& ctx);
|
||||
void ResetSixAxisSensorFusionParameters(HLERequestContext& ctx);
|
||||
void SetGyroscopeZeroDriftMode(HLERequestContext& ctx);
|
||||
void GetGyroscopeZeroDriftMode(HLERequestContext& ctx);
|
||||
void ResetGyroscopeZeroDriftMode(HLERequestContext& ctx);
|
||||
void IsSixAxisSensorAtRest(HLERequestContext& ctx);
|
||||
void IsFirmwareUpdateAvailableForSixAxisSensor(HLERequestContext& ctx);
|
||||
void EnableSixAxisSensorUnalteredPassthrough(HLERequestContext& ctx);
|
||||
void IsSixAxisSensorUnalteredPassthroughEnabled(HLERequestContext& ctx);
|
||||
void LoadSixAxisSensorCalibrationParameter(HLERequestContext& ctx);
|
||||
void GetSixAxisSensorIcInformation(HLERequestContext& ctx);
|
||||
void ResetIsSixAxisSensorDeviceNewlyAssigned(HLERequestContext& ctx);
|
||||
void ActivateGesture(HLERequestContext& ctx);
|
||||
void SetSupportedNpadStyleSet(HLERequestContext& ctx);
|
||||
void GetSupportedNpadStyleSet(HLERequestContext& ctx);
|
||||
void SetSupportedNpadIdType(HLERequestContext& ctx);
|
||||
void ActivateNpad(HLERequestContext& ctx);
|
||||
void DeactivateNpad(HLERequestContext& ctx);
|
||||
void AcquireNpadStyleSetUpdateEventHandle(HLERequestContext& ctx);
|
||||
void DisconnectNpad(HLERequestContext& ctx);
|
||||
void GetPlayerLedPattern(HLERequestContext& ctx);
|
||||
void ActivateNpadWithRevision(HLERequestContext& ctx);
|
||||
void SetNpadJoyHoldType(HLERequestContext& ctx);
|
||||
void GetNpadJoyHoldType(HLERequestContext& ctx);
|
||||
void SetNpadJoyAssignmentModeSingleByDefault(HLERequestContext& ctx);
|
||||
void SetNpadJoyAssignmentModeSingle(HLERequestContext& ctx);
|
||||
void SetNpadJoyAssignmentModeDual(HLERequestContext& ctx);
|
||||
void MergeSingleJoyAsDualJoy(HLERequestContext& ctx);
|
||||
void StartLrAssignmentMode(HLERequestContext& ctx);
|
||||
void StopLrAssignmentMode(HLERequestContext& ctx);
|
||||
void SetNpadHandheldActivationMode(HLERequestContext& ctx);
|
||||
void GetNpadHandheldActivationMode(HLERequestContext& ctx);
|
||||
void SwapNpadAssignment(HLERequestContext& ctx);
|
||||
void IsUnintendedHomeButtonInputProtectionEnabled(HLERequestContext& ctx);
|
||||
void EnableUnintendedHomeButtonInputProtection(HLERequestContext& ctx);
|
||||
void SetNpadJoyAssignmentModeSingleWithDestination(HLERequestContext& ctx);
|
||||
void SetNpadAnalogStickUseCenterClamp(HLERequestContext& ctx);
|
||||
void SetNpadCaptureButtonAssignment(HLERequestContext& ctx);
|
||||
void ClearNpadCaptureButtonAssignment(HLERequestContext& ctx);
|
||||
void GetVibrationDeviceInfo(HLERequestContext& ctx);
|
||||
void SendVibrationValue(HLERequestContext& ctx);
|
||||
void GetActualVibrationValue(HLERequestContext& ctx);
|
||||
void CreateActiveVibrationDeviceList(HLERequestContext& ctx);
|
||||
void PermitVibration(HLERequestContext& ctx);
|
||||
void IsVibrationPermitted(HLERequestContext& ctx);
|
||||
void SendVibrationValues(HLERequestContext& ctx);
|
||||
void SendVibrationGcErmCommand(HLERequestContext& ctx);
|
||||
void GetActualVibrationGcErmCommand(HLERequestContext& ctx);
|
||||
void BeginPermitVibrationSession(HLERequestContext& ctx);
|
||||
void EndPermitVibrationSession(HLERequestContext& ctx);
|
||||
void IsVibrationDeviceMounted(HLERequestContext& ctx);
|
||||
void ActivateConsoleSixAxisSensor(HLERequestContext& ctx);
|
||||
void StartConsoleSixAxisSensor(HLERequestContext& ctx);
|
||||
void StopConsoleSixAxisSensor(HLERequestContext& ctx);
|
||||
void ActivateSevenSixAxisSensor(HLERequestContext& ctx);
|
||||
void StartSevenSixAxisSensor(HLERequestContext& ctx);
|
||||
void StopSevenSixAxisSensor(HLERequestContext& ctx);
|
||||
void InitializeSevenSixAxisSensor(HLERequestContext& ctx);
|
||||
void FinalizeSevenSixAxisSensor(HLERequestContext& ctx);
|
||||
void ResetSevenSixAxisSensorTimestamp(HLERequestContext& ctx);
|
||||
void IsUsbFullKeyControllerEnabled(HLERequestContext& ctx);
|
||||
void GetPalmaConnectionHandle(HLERequestContext& ctx);
|
||||
void InitializePalma(HLERequestContext& ctx);
|
||||
void AcquirePalmaOperationCompleteEvent(HLERequestContext& ctx);
|
||||
void GetPalmaOperationInfo(HLERequestContext& ctx);
|
||||
void PlayPalmaActivity(HLERequestContext& ctx);
|
||||
void SetPalmaFrModeType(HLERequestContext& ctx);
|
||||
void ReadPalmaStep(HLERequestContext& ctx);
|
||||
void EnablePalmaStep(HLERequestContext& ctx);
|
||||
void ResetPalmaStep(HLERequestContext& ctx);
|
||||
void ReadPalmaApplicationSection(HLERequestContext& ctx);
|
||||
void WritePalmaApplicationSection(HLERequestContext& ctx);
|
||||
void ReadPalmaUniqueCode(HLERequestContext& ctx);
|
||||
void SetPalmaUniqueCodeInvalid(HLERequestContext& ctx);
|
||||
void WritePalmaActivityEntry(HLERequestContext& ctx);
|
||||
void WritePalmaRgbLedPatternEntry(HLERequestContext& ctx);
|
||||
void WritePalmaWaveEntry(HLERequestContext& ctx);
|
||||
void SetPalmaDataBaseIdentificationVersion(HLERequestContext& ctx);
|
||||
void GetPalmaDataBaseIdentificationVersion(HLERequestContext& ctx);
|
||||
void SuspendPalmaFeature(HLERequestContext& ctx);
|
||||
void GetPalmaOperationResult(HLERequestContext& ctx);
|
||||
void ReadPalmaPlayLog(HLERequestContext& ctx);
|
||||
void ResetPalmaPlayLog(HLERequestContext& ctx);
|
||||
void SetIsPalmaAllConnectable(HLERequestContext& ctx);
|
||||
void SetIsPalmaPairedConnectable(HLERequestContext& ctx);
|
||||
void PairPalma(HLERequestContext& ctx);
|
||||
void SetPalmaBoostMode(HLERequestContext& ctx);
|
||||
void CancelWritePalmaWaveEntry(HLERequestContext& ctx);
|
||||
void EnablePalmaBoostMode(HLERequestContext& ctx);
|
||||
void GetPalmaBluetoothAddress(HLERequestContext& ctx);
|
||||
void SetDisallowedPalmaConnection(HLERequestContext& ctx);
|
||||
void SetNpadCommunicationMode(HLERequestContext& ctx);
|
||||
void GetNpadCommunicationMode(HLERequestContext& ctx);
|
||||
void SetTouchScreenConfiguration(HLERequestContext& ctx);
|
||||
void IsFirmwareUpdateNeededForNotification(HLERequestContext& ctx);
|
||||
|
||||
std::shared_ptr<ResourceManager> resource_manager;
|
||||
std::shared_ptr<HidFirmwareSettings> firmware_settings;
|
||||
};
|
||||
|
||||
} // namespace Service::HID
|
||||
551
src/core/hle/service/hid/hid_system_server.cpp
Normal file
551
src/core/hle/service/hid/hid_system_server.cpp
Normal file
@@ -0,0 +1,551 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include "core/hid/hid_core.h"
|
||||
#include "core/hle/service/hid/controllers/npad.h"
|
||||
#include "core/hle/service/hid/controllers/touchscreen.h"
|
||||
#include "core/hle/service/hid/errors.h"
|
||||
#include "core/hle/service/hid/hid_system_server.h"
|
||||
#include "core/hle/service/hid/resource_manager.h"
|
||||
#include "core/hle/service/ipc_helpers.h"
|
||||
|
||||
namespace Service::HID {
|
||||
|
||||
IHidSystemServer::IHidSystemServer(Core::System& system_, std::shared_ptr<ResourceManager> resource)
|
||||
: ServiceFramework{system_, "hid:sys"}, service_context{system_, service_name},
|
||||
resource_manager{resource} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{31, nullptr, "SendKeyboardLockKeyEvent"},
|
||||
{101, nullptr, "AcquireHomeButtonEventHandle"},
|
||||
{111, nullptr, "ActivateHomeButton"},
|
||||
{121, nullptr, "AcquireSleepButtonEventHandle"},
|
||||
{131, nullptr, "ActivateSleepButton"},
|
||||
{141, nullptr, "AcquireCaptureButtonEventHandle"},
|
||||
{151, nullptr, "ActivateCaptureButton"},
|
||||
{161, nullptr, "GetPlatformConfig"},
|
||||
{210, nullptr, "AcquireNfcDeviceUpdateEventHandle"},
|
||||
{211, nullptr, "GetNpadsWithNfc"},
|
||||
{212, nullptr, "AcquireNfcActivateEventHandle"},
|
||||
{213, nullptr, "ActivateNfc"},
|
||||
{214, nullptr, "GetXcdHandleForNpadWithNfc"},
|
||||
{215, nullptr, "IsNfcActivated"},
|
||||
{230, nullptr, "AcquireIrSensorEventHandle"},
|
||||
{231, nullptr, "ActivateIrSensor"},
|
||||
{232, nullptr, "GetIrSensorState"},
|
||||
{233, nullptr, "GetXcdHandleForNpadWithIrSensor"},
|
||||
{301, nullptr, "ActivateNpadSystem"},
|
||||
{303, &IHidSystemServer::ApplyNpadSystemCommonPolicy, "ApplyNpadSystemCommonPolicy"},
|
||||
{304, &IHidSystemServer::EnableAssigningSingleOnSlSrPress, "EnableAssigningSingleOnSlSrPress"},
|
||||
{305, &IHidSystemServer::DisableAssigningSingleOnSlSrPress, "DisableAssigningSingleOnSlSrPress"},
|
||||
{306, &IHidSystemServer::GetLastActiveNpad, "GetLastActiveNpad"},
|
||||
{307, nullptr, "GetNpadSystemExtStyle"},
|
||||
{308, &IHidSystemServer::ApplyNpadSystemCommonPolicyFull, "ApplyNpadSystemCommonPolicyFull"},
|
||||
{309, &IHidSystemServer::GetNpadFullKeyGripColor, "GetNpadFullKeyGripColor"},
|
||||
{310, &IHidSystemServer::GetMaskedSupportedNpadStyleSet, "GetMaskedSupportedNpadStyleSet"},
|
||||
{311, nullptr, "SetNpadPlayerLedBlinkingDevice"},
|
||||
{312, &IHidSystemServer::SetSupportedNpadStyleSetAll, "SetSupportedNpadStyleSetAll"},
|
||||
{313, nullptr, "GetNpadCaptureButtonAssignment"},
|
||||
{314, nullptr, "GetAppletFooterUiType"},
|
||||
{315, &IHidSystemServer::GetAppletDetailedUiType, "GetAppletDetailedUiType"},
|
||||
{316, &IHidSystemServer::GetNpadInterfaceType, "GetNpadInterfaceType"},
|
||||
{317, &IHidSystemServer::GetNpadLeftRightInterfaceType, "GetNpadLeftRightInterfaceType"},
|
||||
{318, &IHidSystemServer::HasBattery, "HasBattery"},
|
||||
{319, &IHidSystemServer::HasLeftRightBattery, "HasLeftRightBattery"},
|
||||
{321, &IHidSystemServer::GetUniquePadsFromNpad, "GetUniquePadsFromNpad"},
|
||||
{322, &IHidSystemServer::GetIrSensorState, "GetIrSensorState"},
|
||||
{323, nullptr, "GetXcdHandleForNpadWithIrSensor"},
|
||||
{324, nullptr, "GetUniquePadButtonSet"},
|
||||
{325, nullptr, "GetUniquePadColor"},
|
||||
{326, nullptr, "GetUniquePadAppletDetailedUiType"},
|
||||
{327, nullptr, "GetAbstractedPadIdDataFromNpad"},
|
||||
{328, nullptr, "AttachAbstractedPadToNpad"},
|
||||
{329, nullptr, "DetachAbstractedPadAll"},
|
||||
{330, nullptr, "CheckAbstractedPadConnection"},
|
||||
{500, nullptr, "SetAppletResourceUserId"},
|
||||
{501, nullptr, "RegisterAppletResourceUserId"},
|
||||
{502, nullptr, "UnregisterAppletResourceUserId"},
|
||||
{503, nullptr, "EnableAppletToGetInput"},
|
||||
{504, nullptr, "SetAruidValidForVibration"},
|
||||
{505, nullptr, "EnableAppletToGetSixAxisSensor"},
|
||||
{506, nullptr, "EnableAppletToGetPadInput"},
|
||||
{507, nullptr, "EnableAppletToGetTouchScreen"},
|
||||
{510, nullptr, "SetVibrationMasterVolume"},
|
||||
{511, nullptr, "GetVibrationMasterVolume"},
|
||||
{512, nullptr, "BeginPermitVibrationSession"},
|
||||
{513, nullptr, "EndPermitVibrationSession"},
|
||||
{514, nullptr, "Unknown514"},
|
||||
{520, nullptr, "EnableHandheldHids"},
|
||||
{521, nullptr, "DisableHandheldHids"},
|
||||
{522, nullptr, "SetJoyConRailEnabled"},
|
||||
{523, nullptr, "IsJoyConRailEnabled"},
|
||||
{524, nullptr, "IsHandheldHidsEnabled"},
|
||||
{525, nullptr, "IsJoyConAttachedOnAllRail"},
|
||||
{540, nullptr, "AcquirePlayReportControllerUsageUpdateEvent"},
|
||||
{541, nullptr, "GetPlayReportControllerUsages"},
|
||||
{542, nullptr, "AcquirePlayReportRegisteredDeviceUpdateEvent"},
|
||||
{543, nullptr, "GetRegisteredDevicesOld"},
|
||||
{544, &IHidSystemServer::AcquireConnectionTriggerTimeoutEvent, "AcquireConnectionTriggerTimeoutEvent"},
|
||||
{545, nullptr, "SendConnectionTrigger"},
|
||||
{546, &IHidSystemServer::AcquireDeviceRegisteredEventForControllerSupport, "AcquireDeviceRegisteredEventForControllerSupport"},
|
||||
{547, nullptr, "GetAllowedBluetoothLinksCount"},
|
||||
{548, &IHidSystemServer::GetRegisteredDevices, "GetRegisteredDevices"},
|
||||
{549, nullptr, "GetConnectableRegisteredDevices"},
|
||||
{700, nullptr, "ActivateUniquePad"},
|
||||
{702, &IHidSystemServer::AcquireUniquePadConnectionEventHandle, "AcquireUniquePadConnectionEventHandle"},
|
||||
{703, &IHidSystemServer::GetUniquePadIds, "GetUniquePadIds"},
|
||||
{751, &IHidSystemServer::AcquireJoyDetachOnBluetoothOffEventHandle, "AcquireJoyDetachOnBluetoothOffEventHandle"},
|
||||
{800, nullptr, "ListSixAxisSensorHandles"},
|
||||
{801, nullptr, "IsSixAxisSensorUserCalibrationSupported"},
|
||||
{802, nullptr, "ResetSixAxisSensorCalibrationValues"},
|
||||
{803, nullptr, "StartSixAxisSensorUserCalibration"},
|
||||
{804, nullptr, "CancelSixAxisSensorUserCalibration"},
|
||||
{805, nullptr, "GetUniquePadBluetoothAddress"},
|
||||
{806, nullptr, "DisconnectUniquePad"},
|
||||
{807, nullptr, "GetUniquePadType"},
|
||||
{808, nullptr, "GetUniquePadInterface"},
|
||||
{809, nullptr, "GetUniquePadSerialNumber"},
|
||||
{810, nullptr, "GetUniquePadControllerNumber"},
|
||||
{811, nullptr, "GetSixAxisSensorUserCalibrationStage"},
|
||||
{812, nullptr, "GetConsoleUniqueSixAxisSensorHandle"},
|
||||
{821, nullptr, "StartAnalogStickManualCalibration"},
|
||||
{822, nullptr, "RetryCurrentAnalogStickManualCalibrationStage"},
|
||||
{823, nullptr, "CancelAnalogStickManualCalibration"},
|
||||
{824, nullptr, "ResetAnalogStickManualCalibration"},
|
||||
{825, nullptr, "GetAnalogStickState"},
|
||||
{826, nullptr, "GetAnalogStickManualCalibrationStage"},
|
||||
{827, nullptr, "IsAnalogStickButtonPressed"},
|
||||
{828, nullptr, "IsAnalogStickInReleasePosition"},
|
||||
{829, nullptr, "IsAnalogStickInCircumference"},
|
||||
{830, nullptr, "SetNotificationLedPattern"},
|
||||
{831, nullptr, "SetNotificationLedPatternWithTimeout"},
|
||||
{832, nullptr, "PrepareHidsForNotificationWake"},
|
||||
{850, &IHidSystemServer::IsUsbFullKeyControllerEnabled, "IsUsbFullKeyControllerEnabled"},
|
||||
{851, nullptr, "EnableUsbFullKeyController"},
|
||||
{852, nullptr, "IsUsbConnected"},
|
||||
{870, &IHidSystemServer::IsHandheldButtonPressedOnConsoleMode, "IsHandheldButtonPressedOnConsoleMode"},
|
||||
{900, nullptr, "ActivateInputDetector"},
|
||||
{901, nullptr, "NotifyInputDetector"},
|
||||
{1000, &IHidSystemServer::InitializeFirmwareUpdate, "InitializeFirmwareUpdate"},
|
||||
{1001, nullptr, "GetFirmwareVersion"},
|
||||
{1002, nullptr, "GetAvailableFirmwareVersion"},
|
||||
{1003, nullptr, "IsFirmwareUpdateAvailable"},
|
||||
{1004, nullptr, "CheckFirmwareUpdateRequired"},
|
||||
{1005, nullptr, "StartFirmwareUpdate"},
|
||||
{1006, nullptr, "AbortFirmwareUpdate"},
|
||||
{1007, nullptr, "GetFirmwareUpdateState"},
|
||||
{1008, nullptr, "ActivateAudioControl"},
|
||||
{1009, nullptr, "AcquireAudioControlEventHandle"},
|
||||
{1010, nullptr, "GetAudioControlStates"},
|
||||
{1011, nullptr, "DeactivateAudioControl"},
|
||||
{1050, nullptr, "IsSixAxisSensorAccurateUserCalibrationSupported"},
|
||||
{1051, nullptr, "StartSixAxisSensorAccurateUserCalibration"},
|
||||
{1052, nullptr, "CancelSixAxisSensorAccurateUserCalibration"},
|
||||
{1053, nullptr, "GetSixAxisSensorAccurateUserCalibrationState"},
|
||||
{1100, nullptr, "GetHidbusSystemServiceObject"},
|
||||
{1120, nullptr, "SetFirmwareHotfixUpdateSkipEnabled"},
|
||||
{1130, nullptr, "InitializeUsbFirmwareUpdate"},
|
||||
{1131, nullptr, "FinalizeUsbFirmwareUpdate"},
|
||||
{1132, nullptr, "CheckUsbFirmwareUpdateRequired"},
|
||||
{1133, nullptr, "StartUsbFirmwareUpdate"},
|
||||
{1134, nullptr, "GetUsbFirmwareUpdateState"},
|
||||
{1135, &IHidSystemServer::InitializeUsbFirmwareUpdateWithoutMemory, "InitializeUsbFirmwareUpdateWithoutMemory"},
|
||||
{1150, nullptr, "SetTouchScreenMagnification"},
|
||||
{1151, nullptr, "GetTouchScreenFirmwareVersion"},
|
||||
{1152, nullptr, "SetTouchScreenDefaultConfiguration"},
|
||||
{1153, &IHidSystemServer::GetTouchScreenDefaultConfiguration, "GetTouchScreenDefaultConfiguration"},
|
||||
{1154, nullptr, "IsFirmwareAvailableForNotification"},
|
||||
{1155, nullptr, "SetForceHandheldStyleVibration"},
|
||||
{1156, nullptr, "SendConnectionTriggerWithoutTimeoutEvent"},
|
||||
{1157, nullptr, "CancelConnectionTrigger"},
|
||||
{1200, nullptr, "IsButtonConfigSupported"},
|
||||
{1201, nullptr, "IsButtonConfigEmbeddedSupported"},
|
||||
{1202, nullptr, "DeleteButtonConfig"},
|
||||
{1203, nullptr, "DeleteButtonConfigEmbedded"},
|
||||
{1204, nullptr, "SetButtonConfigEnabled"},
|
||||
{1205, nullptr, "SetButtonConfigEmbeddedEnabled"},
|
||||
{1206, nullptr, "IsButtonConfigEnabled"},
|
||||
{1207, nullptr, "IsButtonConfigEmbeddedEnabled"},
|
||||
{1208, nullptr, "SetButtonConfigEmbedded"},
|
||||
{1209, nullptr, "SetButtonConfigFull"},
|
||||
{1210, nullptr, "SetButtonConfigLeft"},
|
||||
{1211, nullptr, "SetButtonConfigRight"},
|
||||
{1212, nullptr, "GetButtonConfigEmbedded"},
|
||||
{1213, nullptr, "GetButtonConfigFull"},
|
||||
{1214, nullptr, "GetButtonConfigLeft"},
|
||||
{1215, nullptr, "GetButtonConfigRight"},
|
||||
{1250, nullptr, "IsCustomButtonConfigSupported"},
|
||||
{1251, nullptr, "IsDefaultButtonConfigEmbedded"},
|
||||
{1252, nullptr, "IsDefaultButtonConfigFull"},
|
||||
{1253, nullptr, "IsDefaultButtonConfigLeft"},
|
||||
{1254, nullptr, "IsDefaultButtonConfigRight"},
|
||||
{1255, nullptr, "IsButtonConfigStorageEmbeddedEmpty"},
|
||||
{1256, nullptr, "IsButtonConfigStorageFullEmpty"},
|
||||
{1257, nullptr, "IsButtonConfigStorageLeftEmpty"},
|
||||
{1258, nullptr, "IsButtonConfigStorageRightEmpty"},
|
||||
{1259, nullptr, "GetButtonConfigStorageEmbeddedDeprecated"},
|
||||
{1260, nullptr, "GetButtonConfigStorageFullDeprecated"},
|
||||
{1261, nullptr, "GetButtonConfigStorageLeftDeprecated"},
|
||||
{1262, nullptr, "GetButtonConfigStorageRightDeprecated"},
|
||||
{1263, nullptr, "SetButtonConfigStorageEmbeddedDeprecated"},
|
||||
{1264, nullptr, "SetButtonConfigStorageFullDeprecated"},
|
||||
{1265, nullptr, "SetButtonConfigStorageLeftDeprecated"},
|
||||
{1266, nullptr, "SetButtonConfigStorageRightDeprecated"},
|
||||
{1267, nullptr, "DeleteButtonConfigStorageEmbedded"},
|
||||
{1268, nullptr, "DeleteButtonConfigStorageFull"},
|
||||
{1269, nullptr, "DeleteButtonConfigStorageLeft"},
|
||||
{1270, nullptr, "DeleteButtonConfigStorageRight"},
|
||||
{1271, nullptr, "IsUsingCustomButtonConfig"},
|
||||
{1272, nullptr, "IsAnyCustomButtonConfigEnabled"},
|
||||
{1273, nullptr, "SetAllCustomButtonConfigEnabled"},
|
||||
{1274, nullptr, "SetDefaultButtonConfig"},
|
||||
{1275, nullptr, "SetAllDefaultButtonConfig"},
|
||||
{1276, nullptr, "SetHidButtonConfigEmbedded"},
|
||||
{1277, nullptr, "SetHidButtonConfigFull"},
|
||||
{1278, nullptr, "SetHidButtonConfigLeft"},
|
||||
{1279, nullptr, "SetHidButtonConfigRight"},
|
||||
{1280, nullptr, "GetHidButtonConfigEmbedded"},
|
||||
{1281, nullptr, "GetHidButtonConfigFull"},
|
||||
{1282, nullptr, "GetHidButtonConfigLeft"},
|
||||
{1283, nullptr, "GetHidButtonConfigRight"},
|
||||
{1284, nullptr, "GetButtonConfigStorageEmbedded"},
|
||||
{1285, nullptr, "GetButtonConfigStorageFull"},
|
||||
{1286, nullptr, "GetButtonConfigStorageLeft"},
|
||||
{1287, nullptr, "GetButtonConfigStorageRight"},
|
||||
{1288, nullptr, "SetButtonConfigStorageEmbedded"},
|
||||
{1289, nullptr, "SetButtonConfigStorageFull"},
|
||||
{1290, nullptr, "DeleteButtonConfigStorageRight"},
|
||||
{1291, nullptr, "DeleteButtonConfigStorageRight"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
|
||||
joy_detach_event = service_context.CreateEvent("IHidSystemServer::JoyDetachEvent");
|
||||
acquire_device_registered_event =
|
||||
service_context.CreateEvent("IHidSystemServer::AcquireDeviceRegisteredEvent");
|
||||
acquire_connection_trigger_timeout_event =
|
||||
service_context.CreateEvent("IHidSystemServer::AcquireConnectionTriggerTimeoutEvent");
|
||||
unique_pad_connection_event =
|
||||
service_context.CreateEvent("IHidSystemServer::AcquireUniquePadConnectionEventHandle");
|
||||
}
|
||||
|
||||
IHidSystemServer::~IHidSystemServer() {
|
||||
service_context.CloseEvent(joy_detach_event);
|
||||
service_context.CloseEvent(acquire_device_registered_event);
|
||||
service_context.CloseEvent(acquire_connection_trigger_timeout_event);
|
||||
service_context.CloseEvent(unique_pad_connection_event);
|
||||
};
|
||||
|
||||
void IHidSystemServer::ApplyNpadSystemCommonPolicy(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_HID, "called");
|
||||
|
||||
GetResourceManager()
|
||||
->GetController<Controller_NPad>(HidController::NPad)
|
||||
.ApplyNpadSystemCommonPolicy();
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void IHidSystemServer::EnableAssigningSingleOnSlSrPress(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void IHidSystemServer::DisableAssigningSingleOnSlSrPress(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void IHidSystemServer::GetLastActiveNpad(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_HID, "(STUBBED) called"); // Spams a lot when controller applet is running
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushEnum(system.HIDCore().GetLastActiveController());
|
||||
}
|
||||
|
||||
void IHidSystemServer::ApplyNpadSystemCommonPolicyFull(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_HID, "called");
|
||||
|
||||
GetResourceManager()
|
||||
->GetController<Controller_NPad>(HidController::NPad)
|
||||
.ApplyNpadSystemCommonPolicy();
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void IHidSystemServer::GetNpadFullKeyGripColor(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto npad_id_type{rp.PopEnum<Core::HID::NpadIdType>()};
|
||||
|
||||
LOG_DEBUG(Service_HID, "(STUBBED) called, npad_id_type={}",
|
||||
npad_id_type); // Spams a lot when controller applet is running
|
||||
|
||||
Core::HID::NpadColor left_color{};
|
||||
Core::HID::NpadColor right_color{};
|
||||
// TODO: Get colors from Npad
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushRaw(left_color);
|
||||
rb.PushRaw(right_color);
|
||||
}
|
||||
|
||||
void IHidSystemServer::GetMaskedSupportedNpadStyleSet(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
|
||||
LOG_INFO(Service_HID, "(STUBBED) called");
|
||||
|
||||
Core::HID::NpadStyleSet supported_styleset =
|
||||
GetResourceManager()
|
||||
->GetController<Controller_NPad>(HidController::NPad)
|
||||
.GetSupportedStyleSet()
|
||||
.raw;
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushEnum(supported_styleset);
|
||||
}
|
||||
|
||||
void IHidSystemServer::SetSupportedNpadStyleSetAll(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
|
||||
LOG_INFO(Service_HID, "(STUBBED) called");
|
||||
|
||||
Core::HID::NpadStyleSet supported_styleset =
|
||||
GetResourceManager()
|
||||
->GetController<Controller_NPad>(HidController::NPad)
|
||||
.GetSupportedStyleSet()
|
||||
.raw;
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushEnum(supported_styleset);
|
||||
}
|
||||
|
||||
void IHidSystemServer::GetAppletDetailedUiType(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto npad_id_type{rp.PopEnum<Core::HID::NpadIdType>()};
|
||||
|
||||
LOG_DEBUG(Service_HID, "called, npad_id_type={}",
|
||||
npad_id_type); // Spams a lot when controller applet is running
|
||||
|
||||
const Service::HID::Controller_NPad::AppletDetailedUiType detailed_ui_type =
|
||||
GetResourceManager()
|
||||
->GetController<Controller_NPad>(HidController::NPad)
|
||||
.GetAppletDetailedUiType(npad_id_type);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushRaw(detailed_ui_type);
|
||||
}
|
||||
|
||||
void IHidSystemServer::GetNpadInterfaceType(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto npad_id_type{rp.PopEnum<Core::HID::NpadIdType>()};
|
||||
|
||||
LOG_DEBUG(Service_HID, "(STUBBED) called, npad_id_type={}",
|
||||
npad_id_type); // Spams a lot when controller applet is running
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushEnum(Core::HID::NpadInterfaceType::Bluetooth);
|
||||
}
|
||||
|
||||
void IHidSystemServer::GetNpadLeftRightInterfaceType(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto npad_id_type{rp.PopEnum<Core::HID::NpadIdType>()};
|
||||
|
||||
LOG_DEBUG(Service_HID, "(STUBBED) called, npad_id_type={}",
|
||||
npad_id_type); // Spams a lot when controller applet is running
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushEnum(Core::HID::NpadInterfaceType::Bluetooth);
|
||||
rb.PushEnum(Core::HID::NpadInterfaceType::Bluetooth);
|
||||
}
|
||||
|
||||
void IHidSystemServer::HasBattery(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto npad_id_type{rp.PopEnum<Core::HID::NpadIdType>()};
|
||||
|
||||
LOG_DEBUG(Service_HID, "(STUBBED) called, npad_id_type={}",
|
||||
npad_id_type); // Spams a lot when controller applet is running
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push(false);
|
||||
}
|
||||
|
||||
void IHidSystemServer::HasLeftRightBattery(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto npad_id_type{rp.PopEnum<Core::HID::NpadIdType>()};
|
||||
|
||||
LOG_DEBUG(Service_HID, "(STUBBED) called, npad_id_type={}",
|
||||
npad_id_type); // Spams a lot when controller applet is running
|
||||
|
||||
struct LeftRightBattery {
|
||||
bool left;
|
||||
bool right;
|
||||
};
|
||||
|
||||
LeftRightBattery left_right_battery{
|
||||
.left = false,
|
||||
.right = false,
|
||||
};
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushRaw(left_right_battery);
|
||||
}
|
||||
|
||||
void IHidSystemServer::GetUniquePadsFromNpad(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto npad_id_type{rp.PopEnum<Core::HID::NpadIdType>()};
|
||||
|
||||
LOG_DEBUG(Service_HID, "(STUBBED) called, npad_id_type={}",
|
||||
npad_id_type); // Spams a lot when controller applet is running
|
||||
|
||||
const std::vector<Core::HID::UniquePadId> unique_pads{};
|
||||
|
||||
if (!unique_pads.empty()) {
|
||||
ctx.WriteBuffer(unique_pads);
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push(static_cast<u32>(unique_pads.size()));
|
||||
}
|
||||
|
||||
void IHidSystemServer::GetIrSensorState(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void IHidSystemServer::AcquireConnectionTriggerTimeoutEvent(HLERequestContext& ctx) {
|
||||
LOG_INFO(Service_AM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushCopyObjects(acquire_device_registered_event->GetReadableEvent());
|
||||
}
|
||||
|
||||
void IHidSystemServer::AcquireDeviceRegisteredEventForControllerSupport(HLERequestContext& ctx) {
|
||||
LOG_INFO(Service_HID, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushCopyObjects(acquire_device_registered_event->GetReadableEvent());
|
||||
}
|
||||
|
||||
void IHidSystemServer::GetRegisteredDevices(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called");
|
||||
|
||||
struct RegisterData {
|
||||
std::array<u8, 0x68> data;
|
||||
};
|
||||
static_assert(sizeof(RegisterData) == 0x68, "RegisterData is an invalid size");
|
||||
std::vector<RegisterData> registered_devices{};
|
||||
|
||||
if (!registered_devices.empty()) {
|
||||
ctx.WriteBuffer(registered_devices);
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push<u64>(registered_devices.size());
|
||||
}
|
||||
|
||||
void IHidSystemServer::AcquireUniquePadConnectionEventHandle(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.PushCopyObjects(unique_pad_connection_event->GetReadableEvent());
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void IHidSystemServer::GetUniquePadIds(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push<u64>(0);
|
||||
}
|
||||
|
||||
void IHidSystemServer::AcquireJoyDetachOnBluetoothOffEventHandle(HLERequestContext& ctx) {
|
||||
LOG_INFO(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushCopyObjects(joy_detach_event->GetReadableEvent());
|
||||
}
|
||||
|
||||
void IHidSystemServer::IsUsbFullKeyControllerEnabled(HLERequestContext& ctx) {
|
||||
const bool is_enabled = false;
|
||||
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called, is_enabled={}", is_enabled);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push(is_enabled);
|
||||
}
|
||||
|
||||
void IHidSystemServer::IsHandheldButtonPressedOnConsoleMode(HLERequestContext& ctx) {
|
||||
const bool button_pressed = false;
|
||||
|
||||
LOG_DEBUG(Service_HID, "(STUBBED) called, is_enabled={}",
|
||||
button_pressed); // Spams a lot when controller applet is open
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push(button_pressed);
|
||||
}
|
||||
|
||||
void IHidSystemServer::InitializeFirmwareUpdate(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void IHidSystemServer::InitializeUsbFirmwareUpdateWithoutMemory(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void IHidSystemServer::GetTouchScreenDefaultConfiguration(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called");
|
||||
|
||||
Core::HID::TouchScreenConfigurationForNx touchscreen_config{
|
||||
.mode = Core::HID::TouchScreenModeForNx::Finger,
|
||||
};
|
||||
|
||||
if (touchscreen_config.mode != Core::HID::TouchScreenModeForNx::Heat2 &&
|
||||
touchscreen_config.mode != Core::HID::TouchScreenModeForNx::Finger) {
|
||||
touchscreen_config.mode = Core::HID::TouchScreenModeForNx::UseSystemSetting;
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 6};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushRaw(touchscreen_config);
|
||||
}
|
||||
|
||||
std::shared_ptr<ResourceManager> IHidSystemServer::GetResourceManager() {
|
||||
resource_manager->Initialize();
|
||||
return resource_manager;
|
||||
}
|
||||
|
||||
} // namespace Service::HID
|
||||
63
src/core/hle/service/hid/hid_system_server.h
Normal file
63
src/core/hle/service/hid/hid_system_server.h
Normal file
@@ -0,0 +1,63 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/service/kernel_helpers.h"
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
}
|
||||
|
||||
namespace Kernel {
|
||||
class KEvent;
|
||||
}
|
||||
|
||||
namespace Service::HID {
|
||||
class ResourceManager;
|
||||
|
||||
class IHidSystemServer final : public ServiceFramework<IHidSystemServer> {
|
||||
public:
|
||||
explicit IHidSystemServer(Core::System& system_, std::shared_ptr<ResourceManager> resource);
|
||||
~IHidSystemServer() override;
|
||||
|
||||
private:
|
||||
void ApplyNpadSystemCommonPolicy(HLERequestContext& ctx);
|
||||
void EnableAssigningSingleOnSlSrPress(HLERequestContext& ctx);
|
||||
void DisableAssigningSingleOnSlSrPress(HLERequestContext& ctx);
|
||||
void GetLastActiveNpad(HLERequestContext& ctx);
|
||||
void ApplyNpadSystemCommonPolicyFull(HLERequestContext& ctx);
|
||||
void GetNpadFullKeyGripColor(HLERequestContext& ctx);
|
||||
void GetMaskedSupportedNpadStyleSet(HLERequestContext& ctx);
|
||||
void SetSupportedNpadStyleSetAll(HLERequestContext& ctx);
|
||||
void GetAppletDetailedUiType(HLERequestContext& ctx);
|
||||
void GetNpadInterfaceType(HLERequestContext& ctx);
|
||||
void GetNpadLeftRightInterfaceType(HLERequestContext& ctx);
|
||||
void HasBattery(HLERequestContext& ctx);
|
||||
void HasLeftRightBattery(HLERequestContext& ctx);
|
||||
void GetUniquePadsFromNpad(HLERequestContext& ctx);
|
||||
void GetIrSensorState(HLERequestContext& ctx);
|
||||
void AcquireConnectionTriggerTimeoutEvent(HLERequestContext& ctx);
|
||||
void AcquireDeviceRegisteredEventForControllerSupport(HLERequestContext& ctx);
|
||||
void GetRegisteredDevices(HLERequestContext& ctx);
|
||||
void AcquireUniquePadConnectionEventHandle(HLERequestContext& ctx);
|
||||
void GetUniquePadIds(HLERequestContext& ctx);
|
||||
void AcquireJoyDetachOnBluetoothOffEventHandle(HLERequestContext& ctx);
|
||||
void IsUsbFullKeyControllerEnabled(HLERequestContext& ctx);
|
||||
void IsHandheldButtonPressedOnConsoleMode(HLERequestContext& ctx);
|
||||
void InitializeFirmwareUpdate(HLERequestContext& ctx);
|
||||
void InitializeUsbFirmwareUpdateWithoutMemory(HLERequestContext& ctx);
|
||||
void GetTouchScreenDefaultConfiguration(HLERequestContext& ctx);
|
||||
|
||||
std::shared_ptr<ResourceManager> GetResourceManager();
|
||||
|
||||
Kernel::KEvent* acquire_connection_trigger_timeout_event;
|
||||
Kernel::KEvent* acquire_device_registered_event;
|
||||
Kernel::KEvent* joy_detach_event;
|
||||
Kernel::KEvent* unique_pad_connection_event;
|
||||
KernelHelpers::ServiceContext service_context;
|
||||
std::shared_ptr<ResourceManager> resource_manager;
|
||||
};
|
||||
|
||||
} // namespace Service::HID
|
||||
@@ -3,15 +3,12 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/core.h"
|
||||
#include "core/hid/hid_types.h"
|
||||
#include "core/hid/irs_types.h"
|
||||
#include "core/hle/service/hid/irsensor/processor_base.h"
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
}
|
||||
|
||||
namespace Core::HID {
|
||||
class EmulatedController;
|
||||
} // namespace Core::HID
|
||||
|
||||
184
src/core/hle/service/hid/resource_manager.cpp
Normal file
184
src/core/hle/service/hid/resource_manager.cpp
Normal file
@@ -0,0 +1,184 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include "common/logging/log.h"
|
||||
#include "core/core.h"
|
||||
#include "core/core_timing.h"
|
||||
#include "core/hid/hid_core.h"
|
||||
#include "core/hle/kernel/k_shared_memory.h"
|
||||
#include "core/hle/service/hid/resource_manager.h"
|
||||
#include "core/hle/service/ipc_helpers.h"
|
||||
|
||||
#include "core/hle/service/hid/controllers/console_sixaxis.h"
|
||||
#include "core/hle/service/hid/controllers/controller_base.h"
|
||||
#include "core/hle/service/hid/controllers/debug_pad.h"
|
||||
#include "core/hle/service/hid/controllers/gesture.h"
|
||||
#include "core/hle/service/hid/controllers/keyboard.h"
|
||||
#include "core/hle/service/hid/controllers/mouse.h"
|
||||
#include "core/hle/service/hid/controllers/npad.h"
|
||||
#include "core/hle/service/hid/controllers/palma.h"
|
||||
#include "core/hle/service/hid/controllers/stubbed.h"
|
||||
#include "core/hle/service/hid/controllers/touchscreen.h"
|
||||
#include "core/hle/service/hid/controllers/xpad.h"
|
||||
|
||||
namespace Service::HID {
|
||||
|
||||
// Updating period for each HID device.
|
||||
// Period time is obtained by measuring the number of samples in a second on HW using a homebrew
|
||||
// Correct npad_update_ns is 4ms this is overclocked to lower input lag
|
||||
constexpr auto npad_update_ns = std::chrono::nanoseconds{1 * 1000 * 1000}; // (1ms, 1000Hz)
|
||||
constexpr auto default_update_ns = std::chrono::nanoseconds{4 * 1000 * 1000}; // (4ms, 1000Hz)
|
||||
constexpr auto mouse_keyboard_update_ns = std::chrono::nanoseconds{8 * 1000 * 1000}; // (8ms, 125Hz)
|
||||
constexpr auto motion_update_ns = std::chrono::nanoseconds{5 * 1000 * 1000}; // (5ms, 200Hz)
|
||||
|
||||
ResourceManager::ResourceManager(Core::System& system_)
|
||||
: system{system_}, service_context{system_, "hid"} {}
|
||||
|
||||
ResourceManager::~ResourceManager() = default;
|
||||
|
||||
void ResourceManager::Initialize() {
|
||||
if (is_initialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
u8* shared_memory = system.Kernel().GetHidSharedMem().GetPointer();
|
||||
MakeController<Controller_DebugPad>(HidController::DebugPad, shared_memory);
|
||||
MakeController<Controller_Touchscreen>(HidController::Touchscreen, shared_memory);
|
||||
MakeController<Controller_Mouse>(HidController::Mouse, shared_memory);
|
||||
MakeController<Controller_Keyboard>(HidController::Keyboard, shared_memory);
|
||||
MakeController<Controller_XPad>(HidController::XPad, shared_memory);
|
||||
MakeController<Controller_Stubbed>(HidController::HomeButton, shared_memory);
|
||||
MakeController<Controller_Stubbed>(HidController::SleepButton, shared_memory);
|
||||
MakeController<Controller_Stubbed>(HidController::CaptureButton, shared_memory);
|
||||
MakeController<Controller_Stubbed>(HidController::InputDetector, shared_memory);
|
||||
MakeController<Controller_Stubbed>(HidController::UniquePad, shared_memory);
|
||||
MakeControllerWithServiceContext<Controller_NPad>(HidController::NPad, shared_memory);
|
||||
MakeController<Controller_Gesture>(HidController::Gesture, shared_memory);
|
||||
MakeController<Controller_ConsoleSixAxis>(HidController::ConsoleSixAxisSensor, shared_memory);
|
||||
MakeController<Controller_Stubbed>(HidController::DebugMouse, shared_memory);
|
||||
MakeControllerWithServiceContext<Controller_Palma>(HidController::Palma, shared_memory);
|
||||
|
||||
// Homebrew doesn't try to activate some controllers, so we activate them by default
|
||||
GetController<Controller_NPad>(HidController::NPad).Activate();
|
||||
GetController<Controller_Touchscreen>(HidController::Touchscreen).Activate();
|
||||
|
||||
GetController<Controller_Stubbed>(HidController::HomeButton).SetCommonHeaderOffset(0x4C00);
|
||||
GetController<Controller_Stubbed>(HidController::SleepButton).SetCommonHeaderOffset(0x4E00);
|
||||
GetController<Controller_Stubbed>(HidController::CaptureButton).SetCommonHeaderOffset(0x5000);
|
||||
GetController<Controller_Stubbed>(HidController::InputDetector).SetCommonHeaderOffset(0x5200);
|
||||
GetController<Controller_Stubbed>(HidController::UniquePad).SetCommonHeaderOffset(0x5A00);
|
||||
GetController<Controller_Stubbed>(HidController::DebugMouse).SetCommonHeaderOffset(0x3DC00);
|
||||
|
||||
system.HIDCore().ReloadInputDevices();
|
||||
is_initialized = true;
|
||||
}
|
||||
|
||||
void ResourceManager::UpdateControllers(std::uintptr_t user_data,
|
||||
std::chrono::nanoseconds ns_late) {
|
||||
auto& core_timing = system.CoreTiming();
|
||||
|
||||
for (const auto& controller : controllers) {
|
||||
// Keyboard has it's own update event
|
||||
if (controller == controllers[static_cast<size_t>(HidController::Keyboard)]) {
|
||||
continue;
|
||||
}
|
||||
// Mouse has it's own update event
|
||||
if (controller == controllers[static_cast<size_t>(HidController::Mouse)]) {
|
||||
continue;
|
||||
}
|
||||
// Npad has it's own update event
|
||||
if (controller == controllers[static_cast<size_t>(HidController::NPad)]) {
|
||||
continue;
|
||||
}
|
||||
controller->OnUpdate(core_timing);
|
||||
}
|
||||
}
|
||||
|
||||
void ResourceManager::UpdateNpad(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
|
||||
auto& core_timing = system.CoreTiming();
|
||||
|
||||
controllers[static_cast<size_t>(HidController::NPad)]->OnUpdate(core_timing);
|
||||
}
|
||||
|
||||
void ResourceManager::UpdateMouseKeyboard(std::uintptr_t user_data,
|
||||
std::chrono::nanoseconds ns_late) {
|
||||
auto& core_timing = system.CoreTiming();
|
||||
|
||||
controllers[static_cast<size_t>(HidController::Mouse)]->OnUpdate(core_timing);
|
||||
controllers[static_cast<size_t>(HidController::Keyboard)]->OnUpdate(core_timing);
|
||||
}
|
||||
|
||||
void ResourceManager::UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
|
||||
auto& core_timing = system.CoreTiming();
|
||||
|
||||
controllers[static_cast<size_t>(HidController::NPad)]->OnMotionUpdate(core_timing);
|
||||
}
|
||||
|
||||
IAppletResource::IAppletResource(Core::System& system_, std::shared_ptr<ResourceManager> resource)
|
||||
: ServiceFramework{system_, "IAppletResource"} {
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &IAppletResource::GetSharedMemoryHandle, "GetSharedMemoryHandle"},
|
||||
};
|
||||
RegisterHandlers(functions);
|
||||
|
||||
resource->Initialize();
|
||||
|
||||
// Register update callbacks
|
||||
npad_update_event = Core::Timing::CreateEvent(
|
||||
"HID::UpdatePadCallback",
|
||||
[this, resource](std::uintptr_t user_data, s64 time, std::chrono::nanoseconds ns_late)
|
||||
-> std::optional<std::chrono::nanoseconds> {
|
||||
const auto guard = LockService();
|
||||
resource->UpdateNpad(user_data, ns_late);
|
||||
return std::nullopt;
|
||||
});
|
||||
default_update_event = Core::Timing::CreateEvent(
|
||||
"HID::UpdateDefaultCallback",
|
||||
[this, resource](std::uintptr_t user_data, s64 time, std::chrono::nanoseconds ns_late)
|
||||
-> std::optional<std::chrono::nanoseconds> {
|
||||
const auto guard = LockService();
|
||||
resource->UpdateControllers(user_data, ns_late);
|
||||
return std::nullopt;
|
||||
});
|
||||
mouse_keyboard_update_event = Core::Timing::CreateEvent(
|
||||
"HID::UpdateMouseKeyboardCallback",
|
||||
[this, resource](std::uintptr_t user_data, s64 time, std::chrono::nanoseconds ns_late)
|
||||
-> std::optional<std::chrono::nanoseconds> {
|
||||
const auto guard = LockService();
|
||||
resource->UpdateMouseKeyboard(user_data, ns_late);
|
||||
return std::nullopt;
|
||||
});
|
||||
motion_update_event = Core::Timing::CreateEvent(
|
||||
"HID::UpdateMotionCallback",
|
||||
[this, resource](std::uintptr_t user_data, s64 time, std::chrono::nanoseconds ns_late)
|
||||
-> std::optional<std::chrono::nanoseconds> {
|
||||
const auto guard = LockService();
|
||||
resource->UpdateMotion(user_data, ns_late);
|
||||
return std::nullopt;
|
||||
});
|
||||
|
||||
system.CoreTiming().ScheduleLoopingEvent(npad_update_ns, npad_update_ns, npad_update_event);
|
||||
system.CoreTiming().ScheduleLoopingEvent(default_update_ns, default_update_ns,
|
||||
default_update_event);
|
||||
system.CoreTiming().ScheduleLoopingEvent(mouse_keyboard_update_ns, mouse_keyboard_update_ns,
|
||||
mouse_keyboard_update_event);
|
||||
system.CoreTiming().ScheduleLoopingEvent(motion_update_ns, motion_update_ns,
|
||||
motion_update_event);
|
||||
}
|
||||
|
||||
IAppletResource::~IAppletResource() {
|
||||
system.CoreTiming().UnscheduleEvent(npad_update_event, 0);
|
||||
system.CoreTiming().UnscheduleEvent(default_update_event, 0);
|
||||
system.CoreTiming().UnscheduleEvent(mouse_keyboard_update_event, 0);
|
||||
system.CoreTiming().UnscheduleEvent(motion_update_event, 0);
|
||||
}
|
||||
|
||||
void IAppletResource::GetSharedMemoryHandle(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_HID, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushCopyObjects(&system.Kernel().GetHidSharedMem());
|
||||
}
|
||||
|
||||
} // namespace Service::HID
|
||||
104
src/core/hle/service/hid/resource_manager.h
Normal file
104
src/core/hle/service/hid/resource_manager.h
Normal file
@@ -0,0 +1,104 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <chrono>
|
||||
|
||||
#include "core/core.h"
|
||||
#include "core/hle/service/hid/controllers/controller_base.h"
|
||||
#include "core/hle/service/kernel_helpers.h"
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Core::Timing {
|
||||
struct EventType;
|
||||
}
|
||||
|
||||
namespace Core::HID {
|
||||
class HIDCore;
|
||||
}
|
||||
|
||||
namespace Service::HID {
|
||||
|
||||
enum class HidController : std::size_t {
|
||||
DebugPad,
|
||||
Touchscreen,
|
||||
Mouse,
|
||||
Keyboard,
|
||||
XPad,
|
||||
HomeButton,
|
||||
SleepButton,
|
||||
CaptureButton,
|
||||
InputDetector,
|
||||
UniquePad,
|
||||
NPad,
|
||||
Gesture,
|
||||
ConsoleSixAxisSensor,
|
||||
DebugMouse,
|
||||
Palma,
|
||||
|
||||
MaxControllers,
|
||||
};
|
||||
class ResourceManager {
|
||||
public:
|
||||
explicit ResourceManager(Core::System& system_);
|
||||
~ResourceManager();
|
||||
|
||||
template <typename T>
|
||||
T& GetController(HidController controller) {
|
||||
return static_cast<T&>(*controllers[static_cast<size_t>(controller)]);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
const T& GetController(HidController controller) const {
|
||||
return static_cast<T&>(*controllers[static_cast<size_t>(controller)]);
|
||||
}
|
||||
|
||||
void Initialize();
|
||||
|
||||
void UpdateControllers(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
|
||||
void UpdateNpad(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
|
||||
void UpdateMouseKeyboard(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
|
||||
void UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
|
||||
|
||||
private:
|
||||
template <typename T>
|
||||
void MakeController(HidController controller, u8* shared_memory) {
|
||||
if constexpr (std::is_constructible_v<T, Core::System&, u8*>) {
|
||||
controllers[static_cast<std::size_t>(controller)] =
|
||||
std::make_unique<T>(system, shared_memory);
|
||||
} else {
|
||||
controllers[static_cast<std::size_t>(controller)] =
|
||||
std::make_unique<T>(system.HIDCore(), shared_memory);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void MakeControllerWithServiceContext(HidController controller, u8* shared_memory) {
|
||||
controllers[static_cast<std::size_t>(controller)] =
|
||||
std::make_unique<T>(system.HIDCore(), shared_memory, service_context);
|
||||
}
|
||||
|
||||
bool is_initialized{false};
|
||||
std::array<std::unique_ptr<ControllerBase>, static_cast<size_t>(HidController::MaxControllers)>
|
||||
controllers{};
|
||||
|
||||
Core::System& system;
|
||||
KernelHelpers::ServiceContext service_context;
|
||||
};
|
||||
|
||||
class IAppletResource final : public ServiceFramework<IAppletResource> {
|
||||
public:
|
||||
explicit IAppletResource(Core::System& system_, std::shared_ptr<ResourceManager> resource);
|
||||
~IAppletResource() override;
|
||||
|
||||
private:
|
||||
void GetSharedMemoryHandle(HLERequestContext& ctx);
|
||||
|
||||
std::shared_ptr<Core::Timing::EventType> npad_update_event;
|
||||
std::shared_ptr<Core::Timing::EventType> default_update_event;
|
||||
std::shared_ptr<Core::Timing::EventType> mouse_keyboard_update_event;
|
||||
std::shared_ptr<Core::Timing::EventType> motion_update_event;
|
||||
};
|
||||
|
||||
} // namespace Service::HID
|
||||
@@ -115,12 +115,20 @@ public:
|
||||
{400, nullptr, "InitializeSystem"},
|
||||
{401, nullptr, "FinalizeSystem"},
|
||||
{402, nullptr, "SetOperationMode"},
|
||||
{403, nullptr, "InitializeSystem2"},
|
||||
{403, &ISystemLocalCommunicationService::InitializeSystem2, "InitializeSystem2"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
private:
|
||||
void InitializeSystem2(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_LDN, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
};
|
||||
|
||||
class IUserLocalCommunicationService final
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
|
||||
namespace Service::android {
|
||||
|
||||
struct GraphicBuffer;
|
||||
class GraphicBuffer;
|
||||
|
||||
class BufferItem final {
|
||||
public:
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
// https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/libs/gui/BufferQueueConsumer.cpp
|
||||
|
||||
#include "common/logging/log.h"
|
||||
#include "core/hle/service/nvdrv/core/nvmap.h"
|
||||
#include "core/hle/service/nvnflinger/buffer_item.h"
|
||||
#include "core/hle/service/nvnflinger/buffer_queue_consumer.h"
|
||||
#include "core/hle/service/nvnflinger/buffer_queue_core.h"
|
||||
@@ -14,9 +13,8 @@
|
||||
|
||||
namespace Service::android {
|
||||
|
||||
BufferQueueConsumer::BufferQueueConsumer(std::shared_ptr<BufferQueueCore> core_,
|
||||
Service::Nvidia::NvCore::NvMap& nvmap_)
|
||||
: core{std::move(core_)}, slots{core->slots}, nvmap(nvmap_) {}
|
||||
BufferQueueConsumer::BufferQueueConsumer(std::shared_ptr<BufferQueueCore> core_)
|
||||
: core{std::move(core_)}, slots{core->slots} {}
|
||||
|
||||
BufferQueueConsumer::~BufferQueueConsumer() = default;
|
||||
|
||||
@@ -136,8 +134,6 @@ Status BufferQueueConsumer::ReleaseBuffer(s32 slot, u64 frame_number, const Fenc
|
||||
|
||||
slots[slot].buffer_state = BufferState::Free;
|
||||
|
||||
nvmap.FreeHandle(slots[slot].graphic_buffer->BufferId(), true);
|
||||
|
||||
listener = core->connected_producer_listener;
|
||||
|
||||
LOG_DEBUG(Service_Nvnflinger, "releasing slot {}", slot);
|
||||
@@ -175,6 +171,25 @@ Status BufferQueueConsumer::Connect(std::shared_ptr<IConsumerListener> consumer_
|
||||
return Status::NoError;
|
||||
}
|
||||
|
||||
Status BufferQueueConsumer::Disconnect() {
|
||||
LOG_DEBUG(Service_Nvnflinger, "called");
|
||||
|
||||
std::scoped_lock lock{core->mutex};
|
||||
|
||||
if (core->consumer_listener == nullptr) {
|
||||
LOG_ERROR(Service_Nvnflinger, "no consumer is connected");
|
||||
return Status::BadValue;
|
||||
}
|
||||
|
||||
core->is_abandoned = true;
|
||||
core->consumer_listener = nullptr;
|
||||
core->queue.clear();
|
||||
core->FreeAllBuffersLocked();
|
||||
core->SignalDequeueCondition();
|
||||
|
||||
return Status::NoError;
|
||||
}
|
||||
|
||||
Status BufferQueueConsumer::GetReleasedBuffers(u64* out_slot_mask) {
|
||||
if (out_slot_mask == nullptr) {
|
||||
LOG_ERROR(Service_Nvnflinger, "out_slot_mask may not be nullptr");
|
||||
|
||||
@@ -13,10 +13,6 @@
|
||||
#include "core/hle/service/nvnflinger/buffer_queue_defs.h"
|
||||
#include "core/hle/service/nvnflinger/status.h"
|
||||
|
||||
namespace Service::Nvidia::NvCore {
|
||||
class NvMap;
|
||||
} // namespace Service::Nvidia::NvCore
|
||||
|
||||
namespace Service::android {
|
||||
|
||||
class BufferItem;
|
||||
@@ -25,19 +21,18 @@ class IConsumerListener;
|
||||
|
||||
class BufferQueueConsumer final {
|
||||
public:
|
||||
explicit BufferQueueConsumer(std::shared_ptr<BufferQueueCore> core_,
|
||||
Service::Nvidia::NvCore::NvMap& nvmap_);
|
||||
explicit BufferQueueConsumer(std::shared_ptr<BufferQueueCore> core_);
|
||||
~BufferQueueConsumer();
|
||||
|
||||
Status AcquireBuffer(BufferItem* out_buffer, std::chrono::nanoseconds expected_present);
|
||||
Status ReleaseBuffer(s32 slot, u64 frame_number, const Fence& release_fence);
|
||||
Status Connect(std::shared_ptr<IConsumerListener> consumer_listener, bool controlled_by_app);
|
||||
Status Disconnect();
|
||||
Status GetReleasedBuffers(u64* out_slot_mask);
|
||||
|
||||
private:
|
||||
std::shared_ptr<BufferQueueCore> core;
|
||||
BufferQueueDefs::SlotsType& slots;
|
||||
Service::Nvidia::NvCore::NvMap& nvmap;
|
||||
};
|
||||
|
||||
} // namespace Service::android
|
||||
|
||||
@@ -14,24 +14,12 @@ BufferQueueCore::BufferQueueCore() = default;
|
||||
|
||||
BufferQueueCore::~BufferQueueCore() = default;
|
||||
|
||||
void BufferQueueCore::NotifyShutdown() {
|
||||
std::scoped_lock lock{mutex};
|
||||
|
||||
is_shutting_down = true;
|
||||
|
||||
SignalDequeueCondition();
|
||||
}
|
||||
|
||||
void BufferQueueCore::SignalDequeueCondition() {
|
||||
dequeue_possible.store(true);
|
||||
dequeue_condition.notify_all();
|
||||
}
|
||||
|
||||
bool BufferQueueCore::WaitForDequeueCondition(std::unique_lock<std::mutex>& lk) {
|
||||
if (is_shutting_down) {
|
||||
return false;
|
||||
}
|
||||
|
||||
dequeue_condition.wait(lk, [&] { return dequeue_possible.load(); });
|
||||
dequeue_possible.store(false);
|
||||
|
||||
|
||||
@@ -34,8 +34,6 @@ public:
|
||||
BufferQueueCore();
|
||||
~BufferQueueCore();
|
||||
|
||||
void NotifyShutdown();
|
||||
|
||||
private:
|
||||
void SignalDequeueCondition();
|
||||
bool WaitForDequeueCondition(std::unique_lock<std::mutex>& lk);
|
||||
@@ -74,7 +72,6 @@ private:
|
||||
u32 transform_hint{};
|
||||
bool is_allocating{};
|
||||
mutable std::condition_variable_any is_allocating_condition;
|
||||
bool is_shutting_down{};
|
||||
};
|
||||
|
||||
} // namespace Service::android
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
#include "core/hle/service/hle_ipc.h"
|
||||
#include "core/hle/service/kernel_helpers.h"
|
||||
#include "core/hle/service/nvdrv/core/nvmap.h"
|
||||
#include "core/hle/service/nvnflinger/buffer_queue_core.h"
|
||||
#include "core/hle/service/nvnflinger/buffer_queue_producer.h"
|
||||
#include "core/hle/service/nvnflinger/consumer_listener.h"
|
||||
@@ -533,8 +532,6 @@ Status BufferQueueProducer::QueueBuffer(s32 slot, const QueueBufferInput& input,
|
||||
item.is_droppable = core->dequeue_buffer_cannot_block || async;
|
||||
item.swap_interval = swap_interval;
|
||||
|
||||
nvmap.DuplicateHandle(item.graphic_buffer->BufferId(), true);
|
||||
|
||||
sticky_transform = sticky_transform_;
|
||||
|
||||
if (core->queue.empty()) {
|
||||
@@ -744,19 +741,13 @@ Status BufferQueueProducer::Disconnect(NativeWindowApi api) {
|
||||
return Status::NoError;
|
||||
}
|
||||
|
||||
// HACK: We are not Android. Remove handle for items in queue, and clear queue.
|
||||
// Allows synchronous destruction of nvmap handles.
|
||||
for (auto& item : core->queue) {
|
||||
nvmap.FreeHandle(item.graphic_buffer->BufferId(), true);
|
||||
}
|
||||
core->queue.clear();
|
||||
|
||||
switch (api) {
|
||||
case NativeWindowApi::Egl:
|
||||
case NativeWindowApi::Cpu:
|
||||
case NativeWindowApi::Media:
|
||||
case NativeWindowApi::Camera:
|
||||
if (core->connected_api == api) {
|
||||
core->queue.clear();
|
||||
core->FreeAllBuffersLocked();
|
||||
core->connected_producer_listener = nullptr;
|
||||
core->connected_api = NativeWindowApi::NoConnectedApi;
|
||||
@@ -785,7 +776,7 @@ Status BufferQueueProducer::Disconnect(NativeWindowApi api) {
|
||||
}
|
||||
|
||||
Status BufferQueueProducer::SetPreallocatedBuffer(s32 slot,
|
||||
const std::shared_ptr<GraphicBuffer>& buffer) {
|
||||
const std::shared_ptr<NvGraphicBuffer>& buffer) {
|
||||
LOG_DEBUG(Service_Nvnflinger, "slot {}", slot);
|
||||
|
||||
if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) {
|
||||
@@ -796,7 +787,7 @@ Status BufferQueueProducer::SetPreallocatedBuffer(s32 slot,
|
||||
|
||||
slots[slot] = {};
|
||||
slots[slot].fence = Fence::NoFence();
|
||||
slots[slot].graphic_buffer = buffer;
|
||||
slots[slot].graphic_buffer = std::make_shared<GraphicBuffer>(nvmap, buffer);
|
||||
slots[slot].frame_number = 0;
|
||||
|
||||
// Most games preallocate a buffer and pass a valid buffer here. However, it is possible for
|
||||
@@ -839,7 +830,7 @@ void BufferQueueProducer::Transact(HLERequestContext& ctx, TransactionId code, u
|
||||
}
|
||||
case TransactionId::SetPreallocatedBuffer: {
|
||||
const auto slot = parcel_in.Read<s32>();
|
||||
const auto buffer = parcel_in.ReadObject<GraphicBuffer>();
|
||||
const auto buffer = parcel_in.ReadObject<NvGraphicBuffer>();
|
||||
|
||||
status = SetPreallocatedBuffer(slot, buffer);
|
||||
break;
|
||||
@@ -867,7 +858,7 @@ void BufferQueueProducer::Transact(HLERequestContext& ctx, TransactionId code, u
|
||||
|
||||
status = RequestBuffer(slot, &buf);
|
||||
|
||||
parcel_out.WriteFlattenedObject(buf);
|
||||
parcel_out.WriteFlattenedObject<NvGraphicBuffer>(buf.get());
|
||||
break;
|
||||
}
|
||||
case TransactionId::QueueBuffer: {
|
||||
|
||||
@@ -38,6 +38,7 @@ namespace Service::android {
|
||||
|
||||
class BufferQueueCore;
|
||||
class IProducerListener;
|
||||
struct NvGraphicBuffer;
|
||||
|
||||
class BufferQueueProducer final : public IBinder {
|
||||
public:
|
||||
@@ -65,7 +66,7 @@ public:
|
||||
bool producer_controlled_by_app, QueueBufferOutput* output);
|
||||
|
||||
Status Disconnect(NativeWindowApi api);
|
||||
Status SetPreallocatedBuffer(s32 slot, const std::shared_ptr<GraphicBuffer>& buffer);
|
||||
Status SetPreallocatedBuffer(s32 slot, const std::shared_ptr<NvGraphicBuffer>& buffer);
|
||||
|
||||
private:
|
||||
BufferQueueProducer(const BufferQueueProducer&) = delete;
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
|
||||
namespace Service::android {
|
||||
|
||||
struct GraphicBuffer;
|
||||
class GraphicBuffer;
|
||||
|
||||
enum class BufferState : u32 {
|
||||
Free = 0,
|
||||
|
||||
@@ -27,6 +27,26 @@ void ConsumerBase::Connect(bool controlled_by_app) {
|
||||
consumer->Connect(shared_from_this(), controlled_by_app);
|
||||
}
|
||||
|
||||
void ConsumerBase::Abandon() {
|
||||
LOG_DEBUG(Service_Nvnflinger, "called");
|
||||
|
||||
std::scoped_lock lock{mutex};
|
||||
|
||||
if (!is_abandoned) {
|
||||
this->AbandonLocked();
|
||||
is_abandoned = true;
|
||||
}
|
||||
}
|
||||
|
||||
void ConsumerBase::AbandonLocked() {
|
||||
for (int i = 0; i < BufferQueueDefs::NUM_BUFFER_SLOTS; i++) {
|
||||
this->FreeBufferLocked(i);
|
||||
}
|
||||
// disconnect from the BufferQueue
|
||||
consumer->Disconnect();
|
||||
consumer = nullptr;
|
||||
}
|
||||
|
||||
void ConsumerBase::FreeBufferLocked(s32 slot_index) {
|
||||
LOG_DEBUG(Service_Nvnflinger, "slot_index={}", slot_index);
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ class BufferQueueConsumer;
|
||||
class ConsumerBase : public IConsumerListener, public std::enable_shared_from_this<ConsumerBase> {
|
||||
public:
|
||||
void Connect(bool controlled_by_app);
|
||||
void Abandon();
|
||||
|
||||
protected:
|
||||
explicit ConsumerBase(std::unique_ptr<BufferQueueConsumer> consumer_);
|
||||
@@ -34,6 +35,7 @@ protected:
|
||||
void OnBuffersReleased() override;
|
||||
void OnSidebandStreamChanged() override;
|
||||
|
||||
void AbandonLocked();
|
||||
void FreeBufferLocked(s32 slot_index);
|
||||
Status AcquireBufferLocked(BufferItem* item, std::chrono::nanoseconds present_when);
|
||||
Status ReleaseBufferLocked(s32 slot, const std::shared_ptr<GraphicBuffer>& graphic_buffer);
|
||||
|
||||
@@ -166,7 +166,7 @@ constexpr SharedMemoryPoolLayout SharedBufferPoolLayout = [] {
|
||||
}();
|
||||
|
||||
void MakeGraphicBuffer(android::BufferQueueProducer& producer, u32 slot, u32 handle) {
|
||||
auto buffer = std::make_shared<android::GraphicBuffer>();
|
||||
auto buffer = std::make_shared<android::NvGraphicBuffer>();
|
||||
buffer->width = SharedBufferWidth;
|
||||
buffer->height = SharedBufferHeight;
|
||||
buffer->stride = SharedBufferBlockLinearStride;
|
||||
|
||||
@@ -47,7 +47,10 @@ void Nvnflinger::SplitVSync(std::stop_token stop_token) {
|
||||
vsync_signal.Wait();
|
||||
|
||||
const auto lock_guard = Lock();
|
||||
Compose();
|
||||
|
||||
if (!is_abandoned) {
|
||||
Compose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,7 +101,6 @@ Nvnflinger::~Nvnflinger() {
|
||||
}
|
||||
|
||||
ShutdownLayers();
|
||||
vsync_thread = {};
|
||||
|
||||
if (nvdrv) {
|
||||
nvdrv->Close(disp_fd);
|
||||
@@ -106,12 +108,20 @@ Nvnflinger::~Nvnflinger() {
|
||||
}
|
||||
|
||||
void Nvnflinger::ShutdownLayers() {
|
||||
const auto lock_guard = Lock();
|
||||
for (auto& display : displays) {
|
||||
for (size_t layer = 0; layer < display.GetNumLayers(); ++layer) {
|
||||
display.GetLayer(layer).Core().NotifyShutdown();
|
||||
// Abandon consumers.
|
||||
{
|
||||
const auto lock_guard = Lock();
|
||||
for (auto& display : displays) {
|
||||
for (size_t layer = 0; layer < display.GetNumLayers(); ++layer) {
|
||||
display.GetLayer(layer).GetConsumer().Abandon();
|
||||
}
|
||||
}
|
||||
|
||||
is_abandoned = true;
|
||||
}
|
||||
|
||||
// Join the vsync thread, if it exists.
|
||||
vsync_thread = {};
|
||||
}
|
||||
|
||||
void Nvnflinger::SetNVDrvInstance(std::shared_ptr<Nvidia::Module> instance) {
|
||||
|
||||
@@ -140,6 +140,8 @@ private:
|
||||
|
||||
s32 swap_interval = 1;
|
||||
|
||||
bool is_abandoned = false;
|
||||
|
||||
/// Event that handles screen composition.
|
||||
std::shared_ptr<Core::Timing::EventType> multi_composition_event;
|
||||
std::shared_ptr<Core::Timing::EventType> single_composition_event;
|
||||
|
||||
@@ -19,7 +19,7 @@ enum class Status : s32 {
|
||||
Busy = -16,
|
||||
NoInit = -19,
|
||||
BadValue = -22,
|
||||
InvalidOperation = -37,
|
||||
InvalidOperation = -38,
|
||||
BufferNeedsReallocation = 1,
|
||||
ReleaseAllBuffers = 2,
|
||||
};
|
||||
|
||||
34
src/core/hle/service/nvnflinger/ui/graphic_buffer.cpp
Normal file
34
src/core/hle/service/nvnflinger/ui/graphic_buffer.cpp
Normal file
@@ -0,0 +1,34 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include "core/hle/service/nvdrv/core/nvmap.h"
|
||||
#include "core/hle/service/nvnflinger/ui/graphic_buffer.h"
|
||||
|
||||
namespace Service::android {
|
||||
|
||||
static NvGraphicBuffer GetBuffer(std::shared_ptr<NvGraphicBuffer>& buffer) {
|
||||
if (buffer) {
|
||||
return *buffer;
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
GraphicBuffer::GraphicBuffer(u32 width_, u32 height_, PixelFormat format_, u32 usage_)
|
||||
: NvGraphicBuffer(width_, height_, format_, usage_), m_nvmap(nullptr) {}
|
||||
|
||||
GraphicBuffer::GraphicBuffer(Service::Nvidia::NvCore::NvMap& nvmap,
|
||||
std::shared_ptr<NvGraphicBuffer> buffer)
|
||||
: NvGraphicBuffer(GetBuffer(buffer)), m_nvmap(std::addressof(nvmap)) {
|
||||
if (this->BufferId() > 0) {
|
||||
m_nvmap->DuplicateHandle(this->BufferId(), true);
|
||||
}
|
||||
}
|
||||
|
||||
GraphicBuffer::~GraphicBuffer() {
|
||||
if (m_nvmap != nullptr && this->BufferId() > 0) {
|
||||
m_nvmap->FreeHandle(this->BufferId(), true);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Service::android
|
||||
@@ -6,16 +6,22 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/common_types.h"
|
||||
#include "core/hle/service/nvnflinger/pixel_format.h"
|
||||
|
||||
namespace Service::Nvidia::NvCore {
|
||||
class NvMap;
|
||||
} // namespace Service::Nvidia::NvCore
|
||||
|
||||
namespace Service::android {
|
||||
|
||||
struct GraphicBuffer final {
|
||||
constexpr GraphicBuffer() = default;
|
||||
struct NvGraphicBuffer {
|
||||
constexpr NvGraphicBuffer() = default;
|
||||
|
||||
constexpr GraphicBuffer(u32 width_, u32 height_, PixelFormat format_, u32 usage_)
|
||||
constexpr NvGraphicBuffer(u32 width_, u32 height_, PixelFormat format_, u32 usage_)
|
||||
: width{static_cast<s32>(width_)}, height{static_cast<s32>(height_)}, format{format_},
|
||||
usage{static_cast<s32>(usage_)} {}
|
||||
|
||||
@@ -93,6 +99,17 @@ struct GraphicBuffer final {
|
||||
u32 offset{};
|
||||
INSERT_PADDING_WORDS(60);
|
||||
};
|
||||
static_assert(sizeof(GraphicBuffer) == 0x16C, "GraphicBuffer has wrong size");
|
||||
static_assert(sizeof(NvGraphicBuffer) == 0x16C, "NvGraphicBuffer has wrong size");
|
||||
|
||||
class GraphicBuffer final : public NvGraphicBuffer {
|
||||
public:
|
||||
explicit GraphicBuffer(u32 width, u32 height, PixelFormat format, u32 usage);
|
||||
explicit GraphicBuffer(Service::Nvidia::NvCore::NvMap& nvmap,
|
||||
std::shared_ptr<NvGraphicBuffer> buffer);
|
||||
~GraphicBuffer();
|
||||
|
||||
private:
|
||||
Service::Nvidia::NvCore::NvMap* m_nvmap{};
|
||||
};
|
||||
|
||||
} // namespace Service::android
|
||||
|
||||
@@ -431,8 +431,7 @@ void SET_SYS::GetAutoUpdateEnableFlag(HLERequestContext& ctx) {
|
||||
void SET_SYS::GetBatteryPercentageFlag(HLERequestContext& ctx) {
|
||||
u8 battery_percentage_flag{1};
|
||||
|
||||
LOG_WARNING(Service_SET, "(STUBBED) called, battery_percentage_flag={}",
|
||||
battery_percentage_flag);
|
||||
LOG_DEBUG(Service_SET, "(STUBBED) called, battery_percentage_flag={}", battery_percentage_flag);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
@@ -492,6 +491,29 @@ void SET_SYS::GetChineseTraditionalInputMethod(HLERequestContext& ctx) {
|
||||
rb.PushEnum(ChineseTraditionalInputMethod::Unknown0);
|
||||
}
|
||||
|
||||
void SET_SYS::GetHomeMenuScheme(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_SET, "(STUBBED) called");
|
||||
|
||||
const HomeMenuScheme default_color = {
|
||||
.main = 0xFF323232,
|
||||
.back = 0xFF323232,
|
||||
.sub = 0xFFFFFFFF,
|
||||
.bezel = 0xFFFFFFFF,
|
||||
.extra = 0xFF000000,
|
||||
};
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 7};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushRaw(default_color);
|
||||
}
|
||||
|
||||
void SET_SYS::GetHomeMenuSchemeModel(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_SET, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push(0);
|
||||
}
|
||||
void SET_SYS::GetFieldTestingFlag(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_SET, "(STUBBED) called");
|
||||
|
||||
@@ -674,7 +696,7 @@ SET_SYS::SET_SYS(Core::System& system_) : ServiceFramework{system_, "set:sys"} {
|
||||
{171, nullptr, "SetChineseTraditionalInputMethod"},
|
||||
{172, nullptr, "GetPtmCycleCountReliability"},
|
||||
{173, nullptr, "SetPtmCycleCountReliability"},
|
||||
{174, nullptr, "GetHomeMenuScheme"},
|
||||
{174, &SET_SYS::GetHomeMenuScheme, "GetHomeMenuScheme"},
|
||||
{175, nullptr, "GetThemeSettings"},
|
||||
{176, nullptr, "SetThemeSettings"},
|
||||
{177, nullptr, "GetThemeKey"},
|
||||
@@ -685,7 +707,7 @@ SET_SYS::SET_SYS(Core::System& system_) : ServiceFramework{system_, "set:sys"} {
|
||||
{182, nullptr, "SetT"},
|
||||
{183, nullptr, "GetPlatformRegion"},
|
||||
{184, nullptr, "SetPlatformRegion"},
|
||||
{185, nullptr, "GetHomeMenuSchemeModel"},
|
||||
{185, &SET_SYS::GetHomeMenuSchemeModel, "GetHomeMenuSchemeModel"},
|
||||
{186, nullptr, "GetMemoryUsageRateFlag"},
|
||||
{187, nullptr, "GetTouchScreenMode"},
|
||||
{188, nullptr, "SetTouchScreenMode"},
|
||||
|
||||
@@ -269,6 +269,16 @@ private:
|
||||
};
|
||||
static_assert(sizeof(EulaVersion) == 0x30, "EulaVersion is incorrect size");
|
||||
|
||||
/// This is nn::settings::system::HomeMenuScheme
|
||||
struct HomeMenuScheme {
|
||||
u32 main;
|
||||
u32 back;
|
||||
u32 sub;
|
||||
u32 bezel;
|
||||
u32 extra;
|
||||
};
|
||||
static_assert(sizeof(HomeMenuScheme) == 0x14, "HomeMenuScheme is incorrect size");
|
||||
|
||||
void SetLanguageCode(HLERequestContext& ctx);
|
||||
void GetFirmwareVersion(HLERequestContext& ctx);
|
||||
void GetFirmwareVersion2(HLERequestContext& ctx);
|
||||
@@ -305,6 +315,8 @@ private:
|
||||
void GetKeyboardLayout(HLERequestContext& ctx);
|
||||
void GetChineseTraditionalInputMethod(HLERequestContext& ctx);
|
||||
void GetFieldTestingFlag(HLERequestContext& ctx);
|
||||
void GetHomeMenuScheme(HLERequestContext& ctx);
|
||||
void GetHomeMenuSchemeModel(HLERequestContext& ctx);
|
||||
|
||||
AccountSettings account_settings{
|
||||
.flags = {},
|
||||
|
||||
@@ -35,7 +35,7 @@ static BufferQueue CreateBufferQueue(KernelHelpers::ServiceContext& service_cont
|
||||
return {
|
||||
buffer_queue_core,
|
||||
std::make_unique<android::BufferQueueProducer>(service_context, buffer_queue_core, nvmap),
|
||||
std::make_unique<android::BufferQueueConsumer>(buffer_queue_core, nvmap)};
|
||||
std::make_unique<android::BufferQueueConsumer>(buffer_queue_core)};
|
||||
}
|
||||
|
||||
Display::Display(u64 id, std::string name_,
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
// SPDX-FileCopyrightText: 2015 Citra Emulator Project
|
||||
// SPDX-FileCopyrightText: 2018 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <mutex>
|
||||
#include <span>
|
||||
|
||||
#include "common/assert.h"
|
||||
@@ -10,6 +12,7 @@
|
||||
#include "common/common_types.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/page_table.h"
|
||||
#include "common/scope_exit.h"
|
||||
#include "common/settings.h"
|
||||
#include "common/swap.h"
|
||||
#include "core/core.h"
|
||||
@@ -318,7 +321,7 @@ struct Memory::Impl {
|
||||
[&](const Common::ProcessAddress current_vaddr, const std::size_t copy_amount,
|
||||
u8* const host_ptr) {
|
||||
if constexpr (!UNSAFE) {
|
||||
system.GPU().InvalidateRegion(GetInteger(current_vaddr), copy_amount);
|
||||
HandleRasterizerWrite(GetInteger(current_vaddr), copy_amount);
|
||||
}
|
||||
std::memcpy(host_ptr, src_buffer, copy_amount);
|
||||
},
|
||||
@@ -351,7 +354,7 @@ struct Memory::Impl {
|
||||
},
|
||||
[&](const Common::ProcessAddress current_vaddr, const std::size_t copy_amount,
|
||||
u8* const host_ptr) {
|
||||
system.GPU().InvalidateRegion(GetInteger(current_vaddr), copy_amount);
|
||||
HandleRasterizerWrite(GetInteger(current_vaddr), copy_amount);
|
||||
std::memset(host_ptr, 0, copy_amount);
|
||||
},
|
||||
[](const std::size_t copy_amount) {});
|
||||
@@ -420,7 +423,7 @@ struct Memory::Impl {
|
||||
const std::size_t block_size) {
|
||||
// dc cvac: Store to point of coherency
|
||||
// CPU flush -> GPU invalidate
|
||||
system.GPU().InvalidateRegion(GetInteger(current_vaddr), block_size);
|
||||
HandleRasterizerWrite(GetInteger(current_vaddr), block_size);
|
||||
};
|
||||
return PerformCacheOperation(dest_addr, size, on_rasterizer);
|
||||
}
|
||||
@@ -430,7 +433,7 @@ struct Memory::Impl {
|
||||
const std::size_t block_size) {
|
||||
// dc civac: Store to point of coherency, and invalidate from cache
|
||||
// CPU flush -> GPU invalidate
|
||||
system.GPU().InvalidateRegion(GetInteger(current_vaddr), block_size);
|
||||
HandleRasterizerWrite(GetInteger(current_vaddr), block_size);
|
||||
};
|
||||
return PerformCacheOperation(dest_addr, size, on_rasterizer);
|
||||
}
|
||||
@@ -767,7 +770,18 @@ struct Memory::Impl {
|
||||
}
|
||||
|
||||
void HandleRasterizerWrite(VAddr address, size_t size) {
|
||||
const size_t core = system.GetCurrentHostThreadID();
|
||||
constexpr size_t sys_core = Core::Hardware::NUM_CPU_CORES - 1;
|
||||
const size_t core = std::min(system.GetCurrentHostThreadID(),
|
||||
sys_core); // any other calls threads go to syscore.
|
||||
// Guard on sys_core;
|
||||
if (core == sys_core) [[unlikely]] {
|
||||
sys_core_guard.lock();
|
||||
}
|
||||
SCOPE_EXIT({
|
||||
if (core == sys_core) [[unlikely]] {
|
||||
sys_core_guard.unlock();
|
||||
}
|
||||
});
|
||||
auto& current_area = rasterizer_write_areas[core];
|
||||
VAddr subaddress = address >> YUZU_PAGEBITS;
|
||||
bool do_collection = current_area.last_address == subaddress;
|
||||
@@ -799,6 +813,7 @@ struct Memory::Impl {
|
||||
rasterizer_read_areas{};
|
||||
std::array<GPUDirtyState, Core::Hardware::NUM_CPU_CORES> rasterizer_write_areas{};
|
||||
std::span<Core::GPUDirtyMemoryManager> gpu_dirty_managers;
|
||||
std::mutex sys_core_guard;
|
||||
};
|
||||
|
||||
Memory::Memory(Core::System& system_) : system{system_} {
|
||||
|
||||
@@ -10,7 +10,8 @@
|
||||
#include "core/hle/kernel/k_page_table.h"
|
||||
#include "core/hle/kernel/k_process.h"
|
||||
#include "core/hle/service/hid/controllers/npad.h"
|
||||
#include "core/hle/service/hid/hid.h"
|
||||
#include "core/hle/service/hid/hid_server.h"
|
||||
#include "core/hle/service/hid/resource_manager.h"
|
||||
#include "core/hle/service/sm/sm.h"
|
||||
#include "core/memory.h"
|
||||
#include "core/memory/cheat_engine.h"
|
||||
@@ -54,13 +55,13 @@ void StandardVmCallbacks::MemoryWrite(VAddr address, const void* data, u64 size)
|
||||
}
|
||||
|
||||
u64 StandardVmCallbacks::HidKeysDown() {
|
||||
const auto hid = system.ServiceManager().GetService<Service::HID::Hid>("hid");
|
||||
const auto hid = system.ServiceManager().GetService<Service::HID::IHidServer>("hid");
|
||||
if (hid == nullptr) {
|
||||
LOG_WARNING(CheatEngine, "Attempted to read input state, but hid is not initialized!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
const auto applet_resource = hid->GetAppletResource();
|
||||
const auto applet_resource = hid->GetResourceManager();
|
||||
if (applet_resource == nullptr) {
|
||||
LOG_WARNING(CheatEngine,
|
||||
"Attempted to read input state, but applet resource is not initialized!");
|
||||
|
||||
@@ -415,7 +415,7 @@ ButtonMapping GCAdapter::GetButtonMappingForDevice(const Common::ParamPackage& p
|
||||
// This list is missing ZL/ZR since those are not considered buttons.
|
||||
// We will add those afterwards
|
||||
// This list also excludes any button that can't be really mapped
|
||||
static constexpr std::array<std::pair<Settings::NativeButton::Values, PadButton>, 12>
|
||||
static constexpr std::array<std::pair<Settings::NativeButton::Values, PadButton>, 14>
|
||||
switch_to_gcadapter_button = {
|
||||
std::pair{Settings::NativeButton::A, PadButton::ButtonA},
|
||||
{Settings::NativeButton::B, PadButton::ButtonB},
|
||||
@@ -426,8 +426,10 @@ ButtonMapping GCAdapter::GetButtonMappingForDevice(const Common::ParamPackage& p
|
||||
{Settings::NativeButton::DUp, PadButton::ButtonUp},
|
||||
{Settings::NativeButton::DRight, PadButton::ButtonRight},
|
||||
{Settings::NativeButton::DDown, PadButton::ButtonDown},
|
||||
{Settings::NativeButton::SL, PadButton::TriggerL},
|
||||
{Settings::NativeButton::SR, PadButton::TriggerR},
|
||||
{Settings::NativeButton::SLLeft, PadButton::TriggerL},
|
||||
{Settings::NativeButton::SRLeft, PadButton::TriggerR},
|
||||
{Settings::NativeButton::SLRight, PadButton::TriggerL},
|
||||
{Settings::NativeButton::SRRight, PadButton::TriggerR},
|
||||
{Settings::NativeButton::R, PadButton::TriggerZ},
|
||||
};
|
||||
if (!params.Has("port")) {
|
||||
|
||||
@@ -680,8 +680,8 @@ ButtonMapping Joycons::GetButtonMappingForDevice(const Common::ParamPackage& par
|
||||
Common::ParamPackage sr_button_params = button_params;
|
||||
sl_button_params.Set("button", static_cast<int>(Joycon::PadButton::LeftSL));
|
||||
sr_button_params.Set("button", static_cast<int>(Joycon::PadButton::LeftSR));
|
||||
mapping.insert_or_assign(Settings::NativeButton::SL, std::move(sl_button_params));
|
||||
mapping.insert_or_assign(Settings::NativeButton::SR, std::move(sr_button_params));
|
||||
mapping.insert_or_assign(Settings::NativeButton::SLLeft, std::move(sl_button_params));
|
||||
mapping.insert_or_assign(Settings::NativeButton::SRLeft, std::move(sr_button_params));
|
||||
}
|
||||
|
||||
// Map SL and SR buttons for right joycons
|
||||
@@ -693,8 +693,8 @@ ButtonMapping Joycons::GetButtonMappingForDevice(const Common::ParamPackage& par
|
||||
Common::ParamPackage sr_button_params = button_params;
|
||||
sl_button_params.Set("button", static_cast<int>(Joycon::PadButton::RightSL));
|
||||
sr_button_params.Set("button", static_cast<int>(Joycon::PadButton::RightSR));
|
||||
mapping.insert_or_assign(Settings::NativeButton::SL, std::move(sl_button_params));
|
||||
mapping.insert_or_assign(Settings::NativeButton::SR, std::move(sr_button_params));
|
||||
mapping.insert_or_assign(Settings::NativeButton::SLRight, std::move(sl_button_params));
|
||||
mapping.insert_or_assign(Settings::NativeButton::SRRight, std::move(sr_button_params));
|
||||
}
|
||||
|
||||
return mapping;
|
||||
|
||||
@@ -828,16 +828,18 @@ ButtonMapping SDLDriver::GetButtonMappingForDevice(const Common::ParamPackage& p
|
||||
ButtonBindings SDLDriver::GetDefaultButtonBinding(
|
||||
const std::shared_ptr<SDLJoystick>& joystick) const {
|
||||
// Default SL/SR mapping for other controllers
|
||||
auto sl_button = SDL_CONTROLLER_BUTTON_LEFTSHOULDER;
|
||||
auto sr_button = SDL_CONTROLLER_BUTTON_RIGHTSHOULDER;
|
||||
auto sll_button = SDL_CONTROLLER_BUTTON_LEFTSHOULDER;
|
||||
auto srl_button = SDL_CONTROLLER_BUTTON_RIGHTSHOULDER;
|
||||
auto slr_button = SDL_CONTROLLER_BUTTON_LEFTSHOULDER;
|
||||
auto srr_button = SDL_CONTROLLER_BUTTON_RIGHTSHOULDER;
|
||||
|
||||
if (joystick->IsJoyconLeft()) {
|
||||
sl_button = SDL_CONTROLLER_BUTTON_PADDLE2;
|
||||
sr_button = SDL_CONTROLLER_BUTTON_PADDLE4;
|
||||
sll_button = SDL_CONTROLLER_BUTTON_PADDLE2;
|
||||
srl_button = SDL_CONTROLLER_BUTTON_PADDLE4;
|
||||
}
|
||||
if (joystick->IsJoyconRight()) {
|
||||
sl_button = SDL_CONTROLLER_BUTTON_PADDLE3;
|
||||
sr_button = SDL_CONTROLLER_BUTTON_PADDLE1;
|
||||
slr_button = SDL_CONTROLLER_BUTTON_PADDLE3;
|
||||
srr_button = SDL_CONTROLLER_BUTTON_PADDLE1;
|
||||
}
|
||||
|
||||
return {
|
||||
@@ -855,8 +857,10 @@ ButtonBindings SDLDriver::GetDefaultButtonBinding(
|
||||
{Settings::NativeButton::DUp, SDL_CONTROLLER_BUTTON_DPAD_UP},
|
||||
{Settings::NativeButton::DRight, SDL_CONTROLLER_BUTTON_DPAD_RIGHT},
|
||||
{Settings::NativeButton::DDown, SDL_CONTROLLER_BUTTON_DPAD_DOWN},
|
||||
{Settings::NativeButton::SL, sl_button},
|
||||
{Settings::NativeButton::SR, sr_button},
|
||||
{Settings::NativeButton::SLLeft, sll_button},
|
||||
{Settings::NativeButton::SRLeft, srl_button},
|
||||
{Settings::NativeButton::SLRight, slr_button},
|
||||
{Settings::NativeButton::SRRight, srr_button},
|
||||
{Settings::NativeButton::Home, SDL_CONTROLLER_BUTTON_GUIDE},
|
||||
{Settings::NativeButton::Screenshot, SDL_CONTROLLER_BUTTON_MISC1},
|
||||
};
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace InputCommon {
|
||||
class SDLJoystick;
|
||||
|
||||
using ButtonBindings =
|
||||
std::array<std::pair<Settings::NativeButton::Values, SDL_GameControllerButton>, 18>;
|
||||
std::array<std::pair<Settings::NativeButton::Values, SDL_GameControllerButton>, 20>;
|
||||
using ZButtonBindings =
|
||||
std::array<std::pair<Settings::NativeButton::Values, SDL_GameControllerAxis>, 2>;
|
||||
|
||||
|
||||
@@ -396,7 +396,7 @@ std::vector<Common::ParamPackage> UDPClient::GetInputDevices() const {
|
||||
|
||||
ButtonMapping UDPClient::GetButtonMappingForDevice(const Common::ParamPackage& params) {
|
||||
// This list excludes any button that can't be really mapped
|
||||
static constexpr std::array<std::pair<Settings::NativeButton::Values, PadButton>, 20>
|
||||
static constexpr std::array<std::pair<Settings::NativeButton::Values, PadButton>, 22>
|
||||
switch_to_dsu_button = {
|
||||
std::pair{Settings::NativeButton::A, PadButton::Circle},
|
||||
{Settings::NativeButton::B, PadButton::Cross},
|
||||
@@ -412,8 +412,10 @@ ButtonMapping UDPClient::GetButtonMappingForDevice(const Common::ParamPackage& p
|
||||
{Settings::NativeButton::R, PadButton::R1},
|
||||
{Settings::NativeButton::ZL, PadButton::L2},
|
||||
{Settings::NativeButton::ZR, PadButton::R2},
|
||||
{Settings::NativeButton::SL, PadButton::L2},
|
||||
{Settings::NativeButton::SR, PadButton::R2},
|
||||
{Settings::NativeButton::SLLeft, PadButton::L2},
|
||||
{Settings::NativeButton::SRLeft, PadButton::R2},
|
||||
{Settings::NativeButton::SLRight, PadButton::L2},
|
||||
{Settings::NativeButton::SRRight, PadButton::R2},
|
||||
{Settings::NativeButton::LStick, PadButton::L3},
|
||||
{Settings::NativeButton::RStick, PadButton::R3},
|
||||
{Settings::NativeButton::Home, PadButton::Home},
|
||||
|
||||
@@ -231,6 +231,7 @@ add_library(shader_recompiler STATIC
|
||||
ir_opt/rescaling_pass.cpp
|
||||
ir_opt/ssa_rewrite_pass.cpp
|
||||
ir_opt/texture_pass.cpp
|
||||
ir_opt/vendor_workaround_pass.cpp
|
||||
ir_opt/verification_pass.cpp
|
||||
object_pool.h
|
||||
precompiled_headers.h
|
||||
|
||||
@@ -559,12 +559,12 @@ void EmitImageGradient(EmitContext& ctx, IR::Inst& inst, const IR::Value& index,
|
||||
const IR::Value& offset, const IR::Value& lod_clamp) {
|
||||
const auto info{inst.Flags<IR::TextureInstInfo>()};
|
||||
ScopedRegister dpdx, dpdy, coords;
|
||||
const bool multi_component{info.num_derivates > 1 || info.has_lod_clamp};
|
||||
const bool multi_component{info.num_derivatives > 1 || info.has_lod_clamp};
|
||||
if (multi_component) {
|
||||
// Allocate this early to avoid aliasing other registers
|
||||
dpdx = ScopedRegister{ctx.reg_alloc};
|
||||
dpdy = ScopedRegister{ctx.reg_alloc};
|
||||
if (info.num_derivates >= 3) {
|
||||
if (info.num_derivatives >= 3) {
|
||||
coords = ScopedRegister{ctx.reg_alloc};
|
||||
}
|
||||
}
|
||||
@@ -584,7 +584,7 @@ void EmitImageGradient(EmitContext& ctx, IR::Inst& inst, const IR::Value& index,
|
||||
dpdx.reg, derivatives_vec, dpdx.reg, derivatives_vec, dpdy.reg, derivatives_vec,
|
||||
dpdy.reg, derivatives_vec);
|
||||
Register final_coord;
|
||||
if (info.num_derivates >= 3) {
|
||||
if (info.num_derivatives >= 3) {
|
||||
ctx.Add("MOV.F {}.z,{}.x;"
|
||||
"MOV.F {}.z,{}.y;",
|
||||
dpdx.reg, coord_vec, dpdy.reg, coord_vec);
|
||||
|
||||
@@ -548,15 +548,15 @@ void EmitImageGradient(EmitContext& ctx, IR::Inst& inst, const IR::Value& index,
|
||||
if (sparse_inst) {
|
||||
throw NotImplementedException("EmitImageGradient Sparse");
|
||||
}
|
||||
if (!offset.IsEmpty() && info.num_derivates <= 2) {
|
||||
if (!offset.IsEmpty() && info.num_derivatives <= 2) {
|
||||
throw NotImplementedException("EmitImageGradient offset");
|
||||
}
|
||||
const auto texture{Texture(ctx, info, index)};
|
||||
const auto texel{ctx.var_alloc.Define(inst, GlslVarType::F32x4)};
|
||||
const bool multi_component{info.num_derivates > 1 || info.has_lod_clamp};
|
||||
const bool multi_component{info.num_derivatives > 1 || info.has_lod_clamp};
|
||||
const auto derivatives_vec{ctx.var_alloc.Consume(derivatives)};
|
||||
if (multi_component) {
|
||||
if (info.num_derivates >= 3) {
|
||||
if (info.num_derivatives >= 3) {
|
||||
const auto offset_vec{ctx.var_alloc.Consume(offset)};
|
||||
ctx.Add("{}=textureGrad({},{},vec3({}.xz, {}.x),vec3({}.yw, {}.y));", texel, texture,
|
||||
coords, derivatives_vec, offset_vec, derivatives_vec, offset_vec);
|
||||
|
||||
@@ -407,7 +407,7 @@ void SetupCapabilities(const Profile& profile, const Info& info, EmitContext& ct
|
||||
}
|
||||
ctx.AddCapability(spv::Capability::DemoteToHelperInvocation);
|
||||
}
|
||||
if (info.stores[IR::Attribute::ViewportIndex]) {
|
||||
if (info.stores[IR::Attribute::ViewportIndex] && profile.support_multi_viewport) {
|
||||
ctx.AddCapability(spv::Capability::MultiViewport);
|
||||
}
|
||||
if (info.stores[IR::Attribute::ViewportMask] && profile.support_viewport_mask) {
|
||||
|
||||
@@ -84,6 +84,10 @@ std::optional<OutAttr> OutputAttrPointer(EmitContext& ctx, IR::Attribute attr) {
|
||||
}
|
||||
return std::nullopt;
|
||||
case IR::Attribute::ViewportIndex:
|
||||
if (!ctx.profile.support_multi_viewport) {
|
||||
LOG_WARNING(Shader, "Ignoring viewport index store on non-supporting driver");
|
||||
return std::nullopt;
|
||||
}
|
||||
if (ctx.profile.support_viewport_index_layer_non_geometry ||
|
||||
ctx.stage == Shader::Stage::Geometry) {
|
||||
return OutAttr{ctx.viewport_index, ctx.U32[1]};
|
||||
|
||||
@@ -67,22 +67,22 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
explicit ImageOperands(EmitContext& ctx, bool has_lod_clamp, Id derivates, u32 num_derivates,
|
||||
Id offset, Id lod_clamp) {
|
||||
if (!Sirit::ValidId(derivates)) {
|
||||
throw LogicError("Derivates must be present");
|
||||
explicit ImageOperands(EmitContext& ctx, bool has_lod_clamp, Id derivatives,
|
||||
u32 num_derivatives, Id offset, Id lod_clamp) {
|
||||
if (!Sirit::ValidId(derivatives)) {
|
||||
throw LogicError("Derivatives must be present");
|
||||
}
|
||||
boost::container::static_vector<Id, 3> deriv_x_accum;
|
||||
boost::container::static_vector<Id, 3> deriv_y_accum;
|
||||
for (u32 i = 0; i < num_derivates; ++i) {
|
||||
deriv_x_accum.push_back(ctx.OpCompositeExtract(ctx.F32[1], derivates, i * 2));
|
||||
deriv_y_accum.push_back(ctx.OpCompositeExtract(ctx.F32[1], derivates, i * 2 + 1));
|
||||
for (u32 i = 0; i < num_derivatives; ++i) {
|
||||
deriv_x_accum.push_back(ctx.OpCompositeExtract(ctx.F32[1], derivatives, i * 2));
|
||||
deriv_y_accum.push_back(ctx.OpCompositeExtract(ctx.F32[1], derivatives, i * 2 + 1));
|
||||
}
|
||||
const Id derivates_X{ctx.OpCompositeConstruct(
|
||||
ctx.F32[num_derivates], std::span{deriv_x_accum.data(), deriv_x_accum.size()})};
|
||||
const Id derivates_Y{ctx.OpCompositeConstruct(
|
||||
ctx.F32[num_derivates], std::span{deriv_y_accum.data(), deriv_y_accum.size()})};
|
||||
Add(spv::ImageOperandsMask::Grad, derivates_X, derivates_Y);
|
||||
const Id derivatives_X{ctx.OpCompositeConstruct(
|
||||
ctx.F32[num_derivatives], std::span{deriv_x_accum.data(), deriv_x_accum.size()})};
|
||||
const Id derivatives_Y{ctx.OpCompositeConstruct(
|
||||
ctx.F32[num_derivatives], std::span{deriv_y_accum.data(), deriv_y_accum.size()})};
|
||||
Add(spv::ImageOperandsMask::Grad, derivatives_X, derivatives_Y);
|
||||
if (Sirit::ValidId(offset)) {
|
||||
Add(spv::ImageOperandsMask::Offset, offset);
|
||||
}
|
||||
@@ -91,26 +91,26 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
explicit ImageOperands(EmitContext& ctx, bool has_lod_clamp, Id derivates_1, Id derivates_2,
|
||||
explicit ImageOperands(EmitContext& ctx, bool has_lod_clamp, Id derivatives_1, Id derivatives_2,
|
||||
Id offset, Id lod_clamp) {
|
||||
if (!Sirit::ValidId(derivates_1) || !Sirit::ValidId(derivates_2)) {
|
||||
throw LogicError("Derivates must be present");
|
||||
if (!Sirit::ValidId(derivatives_1) || !Sirit::ValidId(derivatives_2)) {
|
||||
throw LogicError("Derivatives must be present");
|
||||
}
|
||||
boost::container::static_vector<Id, 3> deriv_1_accum{
|
||||
ctx.OpCompositeExtract(ctx.F32[1], derivates_1, 0),
|
||||
ctx.OpCompositeExtract(ctx.F32[1], derivates_1, 2),
|
||||
ctx.OpCompositeExtract(ctx.F32[1], derivates_2, 0),
|
||||
ctx.OpCompositeExtract(ctx.F32[1], derivatives_1, 0),
|
||||
ctx.OpCompositeExtract(ctx.F32[1], derivatives_1, 2),
|
||||
ctx.OpCompositeExtract(ctx.F32[1], derivatives_2, 0),
|
||||
};
|
||||
boost::container::static_vector<Id, 3> deriv_2_accum{
|
||||
ctx.OpCompositeExtract(ctx.F32[1], derivates_1, 1),
|
||||
ctx.OpCompositeExtract(ctx.F32[1], derivates_1, 3),
|
||||
ctx.OpCompositeExtract(ctx.F32[1], derivates_2, 1),
|
||||
ctx.OpCompositeExtract(ctx.F32[1], derivatives_1, 1),
|
||||
ctx.OpCompositeExtract(ctx.F32[1], derivatives_1, 3),
|
||||
ctx.OpCompositeExtract(ctx.F32[1], derivatives_2, 1),
|
||||
};
|
||||
const Id derivates_id1{ctx.OpCompositeConstruct(
|
||||
const Id derivatives_id1{ctx.OpCompositeConstruct(
|
||||
ctx.F32[3], std::span{deriv_1_accum.data(), deriv_1_accum.size()})};
|
||||
const Id derivates_id2{ctx.OpCompositeConstruct(
|
||||
const Id derivatives_id2{ctx.OpCompositeConstruct(
|
||||
ctx.F32[3], std::span{deriv_2_accum.data(), deriv_2_accum.size()})};
|
||||
Add(spv::ImageOperandsMask::Grad, derivates_id1, derivates_id2);
|
||||
Add(spv::ImageOperandsMask::Grad, derivatives_id1, derivatives_id2);
|
||||
if (Sirit::ValidId(offset)) {
|
||||
Add(spv::ImageOperandsMask::Offset, offset);
|
||||
}
|
||||
@@ -548,12 +548,12 @@ Id EmitImageQueryLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, I
|
||||
}
|
||||
|
||||
Id EmitImageGradient(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords,
|
||||
Id derivates, Id offset, Id lod_clamp) {
|
||||
Id derivatives, Id offset, Id lod_clamp) {
|
||||
const auto info{inst->Flags<IR::TextureInstInfo>()};
|
||||
const auto operands =
|
||||
info.num_derivates == 3
|
||||
? ImageOperands(ctx, info.has_lod_clamp != 0, derivates, offset, {}, lod_clamp)
|
||||
: ImageOperands(ctx, info.has_lod_clamp != 0, derivates, info.num_derivates, offset,
|
||||
info.num_derivatives == 3
|
||||
? ImageOperands(ctx, info.has_lod_clamp != 0, derivatives, offset, {}, lod_clamp)
|
||||
: ImageOperands(ctx, info.has_lod_clamp != 0, derivatives, info.num_derivatives, offset,
|
||||
lod_clamp);
|
||||
return Emit(&EmitContext::OpImageSparseSampleExplicitLod,
|
||||
&EmitContext::OpImageSampleExplicitLod, ctx, inst, ctx.F32[4],
|
||||
|
||||
@@ -543,7 +543,7 @@ Id EmitImageQueryDimensions(EmitContext& ctx, IR::Inst* inst, const IR::Value& i
|
||||
const IR::Value& skip_mips);
|
||||
Id EmitImageQueryLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords);
|
||||
Id EmitImageGradient(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords,
|
||||
Id derivates, Id offset, Id lod_clamp);
|
||||
Id derivatives, Id offset, Id lod_clamp);
|
||||
Id EmitImageRead(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords);
|
||||
void EmitImageWrite(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, Id color);
|
||||
Id EmitIsTextureScaled(EmitContext& ctx, const IR::Value& index);
|
||||
|
||||
@@ -1864,11 +1864,11 @@ Value IREmitter::ImageQueryLod(const Value& handle, const Value& coords, Texture
|
||||
return Inst(op, Flags{info}, handle, coords);
|
||||
}
|
||||
|
||||
Value IREmitter::ImageGradient(const Value& handle, const Value& coords, const Value& derivates,
|
||||
Value IREmitter::ImageGradient(const Value& handle, const Value& coords, const Value& derivatives,
|
||||
const Value& offset, const F32& lod_clamp, TextureInstInfo info) {
|
||||
const Opcode op{handle.IsImmediate() ? Opcode::BoundImageGradient
|
||||
: Opcode::BindlessImageGradient};
|
||||
return Inst(op, Flags{info}, handle, coords, derivates, offset, lod_clamp);
|
||||
return Inst(op, Flags{info}, handle, coords, derivatives, offset, lod_clamp);
|
||||
}
|
||||
|
||||
Value IREmitter::ImageRead(const Value& handle, const Value& coords, TextureInstInfo info) {
|
||||
|
||||
@@ -335,7 +335,7 @@ public:
|
||||
[[nodiscard]] Value ImageFetch(const Value& handle, const Value& coords, const Value& offset,
|
||||
const U32& lod, const U32& multisampling, TextureInstInfo info);
|
||||
[[nodiscard]] Value ImageGradient(const Value& handle, const Value& coords,
|
||||
const Value& derivates, const Value& offset,
|
||||
const Value& derivatives, const Value& offset,
|
||||
const F32& lod_clamp, TextureInstInfo info);
|
||||
[[nodiscard]] Value ImageRead(const Value& handle, const Value& coords, TextureInstInfo info);
|
||||
void ImageWrite(const Value& handle, const Value& coords, const Value& color,
|
||||
|
||||
@@ -40,7 +40,7 @@ union TextureInstInfo {
|
||||
BitField<21, 1, u32> has_lod_clamp;
|
||||
BitField<22, 1, u32> relaxed_precision;
|
||||
BitField<23, 2, u32> gather_component;
|
||||
BitField<25, 2, u32> num_derivates;
|
||||
BitField<25, 2, u32> num_derivatives;
|
||||
BitField<27, 3, ImageFormat> image_format;
|
||||
BitField<30, 1, u32> ndv_is_active;
|
||||
};
|
||||
|
||||
@@ -59,7 +59,7 @@ void Impl(TranslatorVisitor& v, u64 insn, bool is_bindless) {
|
||||
BitField<51, 3, IR::Pred> sparse_pred;
|
||||
BitField<0, 8, IR::Reg> dest_reg;
|
||||
BitField<8, 8, IR::Reg> coord_reg;
|
||||
BitField<20, 8, IR::Reg> derivate_reg;
|
||||
BitField<20, 8, IR::Reg> derivative_reg;
|
||||
BitField<28, 3, TextureType> type;
|
||||
BitField<31, 4, u64> mask;
|
||||
BitField<36, 13, u64> cbuf_offset;
|
||||
@@ -71,7 +71,7 @@ void Impl(TranslatorVisitor& v, u64 insn, bool is_bindless) {
|
||||
}
|
||||
|
||||
IR::Value coords;
|
||||
u32 num_derivates{};
|
||||
u32 num_derivatives{};
|
||||
IR::Reg base_reg{txd.coord_reg};
|
||||
IR::Reg last_reg;
|
||||
IR::Value handle;
|
||||
@@ -90,42 +90,42 @@ void Impl(TranslatorVisitor& v, u64 insn, bool is_bindless) {
|
||||
switch (txd.type) {
|
||||
case TextureType::_1D: {
|
||||
coords = v.F(base_reg);
|
||||
num_derivates = 1;
|
||||
num_derivatives = 1;
|
||||
last_reg = base_reg + 1;
|
||||
break;
|
||||
}
|
||||
case TextureType::ARRAY_1D: {
|
||||
last_reg = base_reg + 1;
|
||||
coords = v.ir.CompositeConstruct(v.F(base_reg), read_array());
|
||||
num_derivates = 1;
|
||||
num_derivatives = 1;
|
||||
break;
|
||||
}
|
||||
case TextureType::_2D: {
|
||||
last_reg = base_reg + 2;
|
||||
coords = v.ir.CompositeConstruct(v.F(base_reg), v.F(base_reg + 1));
|
||||
num_derivates = 2;
|
||||
num_derivatives = 2;
|
||||
break;
|
||||
}
|
||||
case TextureType::ARRAY_2D: {
|
||||
last_reg = base_reg + 2;
|
||||
coords = v.ir.CompositeConstruct(v.F(base_reg), v.F(base_reg + 1), read_array());
|
||||
num_derivates = 2;
|
||||
num_derivatives = 2;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw NotImplementedException("Invalid texture type");
|
||||
}
|
||||
|
||||
const IR::Reg derivate_reg{txd.derivate_reg};
|
||||
IR::Value derivates;
|
||||
switch (num_derivates) {
|
||||
const IR::Reg derivative_reg{txd.derivative_reg};
|
||||
IR::Value derivatives;
|
||||
switch (num_derivatives) {
|
||||
case 1: {
|
||||
derivates = v.ir.CompositeConstruct(v.F(derivate_reg), v.F(derivate_reg + 1));
|
||||
derivatives = v.ir.CompositeConstruct(v.F(derivative_reg), v.F(derivative_reg + 1));
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
derivates = v.ir.CompositeConstruct(v.F(derivate_reg), v.F(derivate_reg + 1),
|
||||
v.F(derivate_reg + 2), v.F(derivate_reg + 3));
|
||||
derivatives = v.ir.CompositeConstruct(v.F(derivative_reg), v.F(derivative_reg + 1),
|
||||
v.F(derivative_reg + 2), v.F(derivative_reg + 3));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@@ -150,9 +150,10 @@ void Impl(TranslatorVisitor& v, u64 insn, bool is_bindless) {
|
||||
|
||||
IR::TextureInstInfo info{};
|
||||
info.type.Assign(GetType(txd.type));
|
||||
info.num_derivates.Assign(num_derivates);
|
||||
info.num_derivatives.Assign(num_derivatives);
|
||||
info.has_lod_clamp.Assign(has_lod_clamp ? 1 : 0);
|
||||
const IR::Value sample{v.ir.ImageGradient(handle, coords, derivates, offset, lod_clamp, info)};
|
||||
const IR::Value sample{
|
||||
v.ir.ImageGradient(handle, coords, derivatives, offset, lod_clamp, info)};
|
||||
|
||||
IR::Reg dest_reg{txd.dest_reg};
|
||||
for (size_t element = 0; element < 4; ++element) {
|
||||
|
||||
@@ -310,6 +310,7 @@ IR::Program TranslateProgram(ObjectPool<IR::Inst>& inst_pool, ObjectPool<IR::Blo
|
||||
}
|
||||
Optimization::CollectShaderInfoPass(env, program);
|
||||
Optimization::LayerPass(program, host_info);
|
||||
Optimization::VendorWorkaroundPass(program);
|
||||
|
||||
CollectInterpolationInfo(env, program);
|
||||
AddNVNStorageBuffers(program);
|
||||
|
||||
@@ -428,7 +428,7 @@ void FoldFPAdd32(IR::Inst& inst) {
|
||||
}
|
||||
}
|
||||
|
||||
bool FoldDerivateYFromCorrection(IR::Inst& inst) {
|
||||
bool FoldDerivativeYFromCorrection(IR::Inst& inst) {
|
||||
const IR::Value lhs_value{inst.Arg(0)};
|
||||
const IR::Value rhs_value{inst.Arg(1)};
|
||||
IR::Inst* const lhs_op{lhs_value.InstRecursive()};
|
||||
@@ -464,7 +464,7 @@ void FoldFPMul32(IR::Inst& inst) {
|
||||
if (lhs_value.IsImmediate() || rhs_value.IsImmediate()) {
|
||||
return;
|
||||
}
|
||||
if (FoldDerivateYFromCorrection(inst)) {
|
||||
if (FoldDerivativeYFromCorrection(inst)) {
|
||||
return;
|
||||
}
|
||||
IR::Inst* const lhs_op{lhs_value.InstRecursive()};
|
||||
@@ -699,7 +699,7 @@ void FoldFSwizzleAdd(IR::Block& block, IR::Inst& inst) {
|
||||
}
|
||||
}
|
||||
|
||||
bool FindGradient3DDerivates(std::array<IR::Value, 3>& results, IR::Value coord) {
|
||||
bool FindGradient3DDerivatives(std::array<IR::Value, 3>& results, IR::Value coord) {
|
||||
if (coord.IsImmediate()) {
|
||||
return false;
|
||||
}
|
||||
@@ -834,7 +834,7 @@ void FoldImageSampleImplicitLod(IR::Block& block, IR::Inst& inst) {
|
||||
IR::Inst* const inst2 = coords.InstRecursive();
|
||||
std::array<std::array<IR::Value, 3>, 3> results_matrix;
|
||||
for (size_t i = 0; i < 3; i++) {
|
||||
if (!FindGradient3DDerivates(results_matrix[i], inst2->Arg(i).Resolve())) {
|
||||
if (!FindGradient3DDerivatives(results_matrix[i], inst2->Arg(i).Resolve())) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -852,7 +852,7 @@ void FoldImageSampleImplicitLod(IR::Block& block, IR::Inst& inst) {
|
||||
IR::Value derivatives_1 = ir.CompositeConstruct(results_matrix[0][1], results_matrix[0][2],
|
||||
results_matrix[1][1], results_matrix[1][2]);
|
||||
IR::Value derivatives_2 = ir.CompositeConstruct(results_matrix[2][1], results_matrix[2][2]);
|
||||
info.num_derivates.Assign(3);
|
||||
info.num_derivatives.Assign(3);
|
||||
IR::Value new_gradient_instruction =
|
||||
ir.ImageGradient(handle, new_coords, derivatives_1, derivatives_2, lod_clamp, info);
|
||||
IR::Inst* const new_inst = new_gradient_instruction.InstRecursive();
|
||||
|
||||
@@ -26,6 +26,7 @@ void SsaRewritePass(IR::Program& program);
|
||||
void PositionPass(Environment& env, IR::Program& program);
|
||||
void TexturePass(Environment& env, IR::Program& program, const HostTranslateInfo& host_info);
|
||||
void LayerPass(IR::Program& program, const HostTranslateInfo& host_info);
|
||||
void VendorWorkaroundPass(IR::Program& program);
|
||||
void VerificationPass(const IR::Program& program);
|
||||
|
||||
// Dual Vertex
|
||||
|
||||
79
src/shader_recompiler/ir_opt/vendor_workaround_pass.cpp
Normal file
79
src/shader_recompiler/ir_opt/vendor_workaround_pass.cpp
Normal file
@@ -0,0 +1,79 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "shader_recompiler/frontend/ir/basic_block.h"
|
||||
#include "shader_recompiler/frontend/ir/ir_emitter.h"
|
||||
#include "shader_recompiler/frontend/ir/value.h"
|
||||
#include "shader_recompiler/ir_opt/passes.h"
|
||||
|
||||
namespace Shader::Optimization {
|
||||
|
||||
namespace {
|
||||
void AddingByteSwapsWorkaround(IR::Block& block, IR::Inst& inst) {
|
||||
/*
|
||||
* Workaround for an NVIDIA bug seen in Super Mario RPG
|
||||
*
|
||||
* We are looking for this pattern:
|
||||
* %lhs_bfe = BitFieldUExtract %factor_a, #0, #16
|
||||
* %lhs_mul = IMul32 %lhs_bfe, %factor_b // potentially optional?
|
||||
* %lhs_shl = ShiftLeftLogical32 %lhs_mul, #16
|
||||
* %rhs_bfe = BitFieldUExtract %factor_a, #16, #16
|
||||
* %result = IAdd32 %lhs_shl, %rhs_bfe
|
||||
*
|
||||
* And replacing the IAdd32 with a BitwiseOr32
|
||||
* %result = BitwiseOr32 %lhs_shl, %rhs_bfe
|
||||
*
|
||||
*/
|
||||
IR::Inst* const lhs_shl{inst.Arg(0).TryInstRecursive()};
|
||||
IR::Inst* const rhs_bfe{inst.Arg(1).TryInstRecursive()};
|
||||
if (!lhs_shl || !rhs_bfe) {
|
||||
return;
|
||||
}
|
||||
if (lhs_shl->GetOpcode() != IR::Opcode::ShiftLeftLogical32 ||
|
||||
lhs_shl->Arg(1) != IR::Value{16U}) {
|
||||
return;
|
||||
}
|
||||
if (rhs_bfe->GetOpcode() != IR::Opcode::BitFieldUExtract || rhs_bfe->Arg(1) != IR::Value{16U} ||
|
||||
rhs_bfe->Arg(2) != IR::Value{16U}) {
|
||||
return;
|
||||
}
|
||||
IR::Inst* const lhs_mul{lhs_shl->Arg(0).TryInstRecursive()};
|
||||
if (!lhs_mul) {
|
||||
return;
|
||||
}
|
||||
const bool lhs_mul_optional{lhs_mul->GetOpcode() == IR::Opcode::BitFieldUExtract};
|
||||
if (lhs_mul->GetOpcode() != IR::Opcode::IMul32 &&
|
||||
lhs_mul->GetOpcode() != IR::Opcode::BitFieldUExtract) {
|
||||
return;
|
||||
}
|
||||
IR::Inst* const lhs_bfe{lhs_mul_optional ? lhs_mul : lhs_mul->Arg(0).TryInstRecursive()};
|
||||
if (!lhs_bfe) {
|
||||
return;
|
||||
}
|
||||
if (lhs_bfe->GetOpcode() != IR::Opcode::BitFieldUExtract) {
|
||||
return;
|
||||
}
|
||||
if (lhs_bfe->Arg(1) != IR::Value{0U} || lhs_bfe->Arg(2) != IR::Value{16U}) {
|
||||
return;
|
||||
}
|
||||
IR::IREmitter ir{block, IR::Block::InstructionList::s_iterator_to(inst)};
|
||||
inst.ReplaceUsesWith(ir.BitwiseOr(IR::U32{inst.Arg(0)}, IR::U32{inst.Arg(1)}));
|
||||
}
|
||||
|
||||
} // Anonymous namespace
|
||||
|
||||
void VendorWorkaroundPass(IR::Program& program) {
|
||||
for (IR::Block* const block : program.post_order_blocks) {
|
||||
for (IR::Inst& inst : block->Instructions()) {
|
||||
switch (inst.GetOpcode()) {
|
||||
case IR::Opcode::IAdd32:
|
||||
AddingByteSwapsWorkaround(*block, inst);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Shader::Optimization
|
||||
@@ -43,6 +43,7 @@ struct Profile {
|
||||
bool support_gl_sparse_textures{};
|
||||
bool support_gl_derivative_control{};
|
||||
bool support_scaled_attributes{};
|
||||
bool support_multi_viewport{};
|
||||
|
||||
bool warp_size_potentially_larger_than_guest{};
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
add_subdirectory(host_shaders)
|
||||
|
||||
if(LIBVA_FOUND)
|
||||
set_source_files_properties(host1x/codecs/codec.cpp
|
||||
set_source_files_properties(host1x/ffmpeg/ffmpeg.cpp
|
||||
PROPERTIES COMPILE_DEFINITIONS LIBVA_FOUND=1)
|
||||
list(APPEND FFmpeg_LIBRARIES ${LIBVA_LIBRARIES})
|
||||
endif()
|
||||
@@ -66,6 +66,8 @@ add_library(video_core STATIC
|
||||
host1x/codecs/vp9.cpp
|
||||
host1x/codecs/vp9.h
|
||||
host1x/codecs/vp9_types.h
|
||||
host1x/ffmpeg/ffmpeg.cpp
|
||||
host1x/ffmpeg/ffmpeg.h
|
||||
host1x/control.cpp
|
||||
host1x/control.h
|
||||
host1x/host1x.cpp
|
||||
|
||||
@@ -1192,11 +1192,6 @@ void BufferCache<P>::UpdateDrawIndirect() {
|
||||
.size = static_cast<u32>(size),
|
||||
.buffer_id = FindBuffer(*cpu_addr, static_cast<u32>(size)),
|
||||
};
|
||||
VAddr cpu_addr_start = Common::AlignDown(*cpu_addr, 64);
|
||||
VAddr cpu_addr_end = Common::AlignUp(*cpu_addr + size, 64);
|
||||
IntervalType interval{cpu_addr_start, cpu_addr_end};
|
||||
ClearDownload(interval);
|
||||
common_ranges.subtract(interval);
|
||||
};
|
||||
if (current_draw_indirect->include_count) {
|
||||
update(current_draw_indirect->count_start_address, sizeof(u32),
|
||||
|
||||
@@ -72,7 +72,7 @@ void Fermi2D::Blit() {
|
||||
UNIMPLEMENTED_IF_MSG(regs.clip_enable != 0, "Clipped blit enabled");
|
||||
|
||||
const auto& args = regs.pixels_from_memory;
|
||||
constexpr s64 null_derivate = 1ULL << 32;
|
||||
constexpr s64 null_derivative = 1ULL << 32;
|
||||
Surface src = regs.src;
|
||||
const auto bytes_per_pixel = BytesPerBlock(PixelFormatFromRenderTargetFormat(src.format));
|
||||
const bool delegate_to_gpu = src.width > 512 && src.height > 512 && bytes_per_pixel <= 8 &&
|
||||
@@ -89,7 +89,7 @@ void Fermi2D::Blit() {
|
||||
.operation = regs.operation,
|
||||
.filter = args.sample_mode.filter,
|
||||
.must_accelerate =
|
||||
args.du_dx != null_derivate || args.dv_dy != null_derivate || delegate_to_gpu,
|
||||
args.du_dx != null_derivative || args.dv_dy != null_derivative || delegate_to_gpu,
|
||||
.dst_x0 = args.dst_x0,
|
||||
.dst_y0 = args.dst_y0,
|
||||
.dst_x1 = args.dst_x0 + args.dst_width,
|
||||
|
||||
@@ -268,7 +268,7 @@ size_t Maxwell3D::EstimateIndexBufferSize() {
|
||||
std::numeric_limits<u32>::max()};
|
||||
const size_t byte_size = regs.index_buffer.FormatSizeInBytes();
|
||||
const size_t log2_byte_size = Common::Log2Ceil64(byte_size);
|
||||
const size_t cap{GetMaxCurrentVertices() * 3 * byte_size};
|
||||
const size_t cap{GetMaxCurrentVertices() * 4 * byte_size};
|
||||
const size_t lower_cap =
|
||||
std::min<size_t>(static_cast<size_t>(end_address - start_address), cap);
|
||||
return std::min<size_t>(
|
||||
|
||||
@@ -86,10 +86,7 @@ public:
|
||||
uncommitted_operations.emplace_back(std::move(func));
|
||||
}
|
||||
pending_operations.emplace_back(std::move(uncommitted_operations));
|
||||
{
|
||||
std::scoped_lock lock{buffer_cache.mutex, texture_cache.mutex};
|
||||
QueueFence(new_fence);
|
||||
}
|
||||
QueueFence(new_fence);
|
||||
if (!delay_fence) {
|
||||
func();
|
||||
}
|
||||
|
||||
@@ -1,11 +1,7 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <algorithm>
|
||||
#include <fstream>
|
||||
#include <vector>
|
||||
#include "common/assert.h"
|
||||
#include "common/scope_exit.h"
|
||||
#include "common/settings.h"
|
||||
#include "video_core/host1x/codecs/codec.h"
|
||||
#include "video_core/host1x/codecs/h264.h"
|
||||
@@ -14,242 +10,17 @@
|
||||
#include "video_core/host1x/host1x.h"
|
||||
#include "video_core/memory_manager.h"
|
||||
|
||||
extern "C" {
|
||||
#include <libavfilter/buffersink.h>
|
||||
#include <libavfilter/buffersrc.h>
|
||||
#include <libavutil/opt.h>
|
||||
#ifdef LIBVA_FOUND
|
||||
// for querying VAAPI driver information
|
||||
#include <libavutil/hwcontext_vaapi.h>
|
||||
#endif
|
||||
}
|
||||
|
||||
namespace Tegra {
|
||||
namespace {
|
||||
constexpr AVPixelFormat PREFERRED_GPU_FMT = AV_PIX_FMT_NV12;
|
||||
constexpr AVPixelFormat PREFERRED_CPU_FMT = AV_PIX_FMT_YUV420P;
|
||||
constexpr std::array PREFERRED_GPU_DECODERS = {
|
||||
AV_HWDEVICE_TYPE_CUDA,
|
||||
#ifdef _WIN32
|
||||
AV_HWDEVICE_TYPE_D3D11VA,
|
||||
AV_HWDEVICE_TYPE_DXVA2,
|
||||
#elif defined(__unix__)
|
||||
AV_HWDEVICE_TYPE_VAAPI,
|
||||
AV_HWDEVICE_TYPE_VDPAU,
|
||||
#endif
|
||||
// last resort for Linux Flatpak (w/ NVIDIA)
|
||||
AV_HWDEVICE_TYPE_VULKAN,
|
||||
};
|
||||
|
||||
void AVPacketDeleter(AVPacket* ptr) {
|
||||
av_packet_free(&ptr);
|
||||
}
|
||||
|
||||
using AVPacketPtr = std::unique_ptr<AVPacket, decltype(&AVPacketDeleter)>;
|
||||
|
||||
AVPixelFormat GetGpuFormat(AVCodecContext* av_codec_ctx, const AVPixelFormat* pix_fmts) {
|
||||
for (const AVPixelFormat* p = pix_fmts; *p != AV_PIX_FMT_NONE; ++p) {
|
||||
if (*p == av_codec_ctx->pix_fmt) {
|
||||
return av_codec_ctx->pix_fmt;
|
||||
}
|
||||
}
|
||||
LOG_INFO(Service_NVDRV, "Could not find compatible GPU AV format, falling back to CPU");
|
||||
av_buffer_unref(&av_codec_ctx->hw_device_ctx);
|
||||
av_codec_ctx->pix_fmt = PREFERRED_CPU_FMT;
|
||||
return PREFERRED_CPU_FMT;
|
||||
}
|
||||
|
||||
// List all the currently available hwcontext in ffmpeg
|
||||
std::vector<AVHWDeviceType> ListSupportedContexts() {
|
||||
std::vector<AVHWDeviceType> contexts{};
|
||||
AVHWDeviceType current_device_type = AV_HWDEVICE_TYPE_NONE;
|
||||
do {
|
||||
current_device_type = av_hwdevice_iterate_types(current_device_type);
|
||||
contexts.push_back(current_device_type);
|
||||
} while (current_device_type != AV_HWDEVICE_TYPE_NONE);
|
||||
return contexts;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void AVFrameDeleter(AVFrame* ptr) {
|
||||
av_frame_free(&ptr);
|
||||
}
|
||||
|
||||
Codec::Codec(Host1x::Host1x& host1x_, const Host1x::NvdecCommon::NvdecRegisters& regs)
|
||||
: host1x(host1x_), state{regs}, h264_decoder(std::make_unique<Decoder::H264>(host1x)),
|
||||
vp8_decoder(std::make_unique<Decoder::VP8>(host1x)),
|
||||
vp9_decoder(std::make_unique<Decoder::VP9>(host1x)) {}
|
||||
|
||||
Codec::~Codec() {
|
||||
if (!initialized) {
|
||||
return;
|
||||
}
|
||||
// Free libav memory
|
||||
avcodec_free_context(&av_codec_ctx);
|
||||
av_buffer_unref(&av_gpu_decoder);
|
||||
|
||||
if (filters_initialized) {
|
||||
avfilter_graph_free(&av_filter_graph);
|
||||
}
|
||||
}
|
||||
|
||||
bool Codec::CreateGpuAvDevice() {
|
||||
static constexpr auto HW_CONFIG_METHOD = AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX;
|
||||
static const auto supported_contexts = ListSupportedContexts();
|
||||
for (const auto& type : PREFERRED_GPU_DECODERS) {
|
||||
if (std::none_of(supported_contexts.begin(), supported_contexts.end(),
|
||||
[&type](const auto& context) { return context == type; })) {
|
||||
LOG_DEBUG(Service_NVDRV, "{} explicitly unsupported", av_hwdevice_get_type_name(type));
|
||||
continue;
|
||||
}
|
||||
// Avoid memory leak from not cleaning up after av_hwdevice_ctx_create
|
||||
av_buffer_unref(&av_gpu_decoder);
|
||||
const int hwdevice_res = av_hwdevice_ctx_create(&av_gpu_decoder, type, nullptr, nullptr, 0);
|
||||
if (hwdevice_res < 0) {
|
||||
LOG_DEBUG(Service_NVDRV, "{} av_hwdevice_ctx_create failed {}",
|
||||
av_hwdevice_get_type_name(type), hwdevice_res);
|
||||
continue;
|
||||
}
|
||||
#ifdef LIBVA_FOUND
|
||||
if (type == AV_HWDEVICE_TYPE_VAAPI) {
|
||||
// we need to determine if this is an impersonated VAAPI driver
|
||||
AVHWDeviceContext* hwctx =
|
||||
static_cast<AVHWDeviceContext*>(static_cast<void*>(av_gpu_decoder->data));
|
||||
AVVAAPIDeviceContext* vactx = static_cast<AVVAAPIDeviceContext*>(hwctx->hwctx);
|
||||
const char* vendor_name = vaQueryVendorString(vactx->display);
|
||||
if (strstr(vendor_name, "VDPAU backend")) {
|
||||
// VDPAU impersonated VAAPI impl's are super buggy, we need to skip them
|
||||
LOG_DEBUG(Service_NVDRV, "Skipping vdapu impersonated VAAPI driver");
|
||||
continue;
|
||||
} else {
|
||||
// according to some user testing, certain vaapi driver (Intel?) could be buggy
|
||||
// so let's log the driver name which may help the developers/supporters
|
||||
LOG_DEBUG(Service_NVDRV, "Using VAAPI driver: {}", vendor_name);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
for (int i = 0;; i++) {
|
||||
const AVCodecHWConfig* config = avcodec_get_hw_config(av_codec, i);
|
||||
if (!config) {
|
||||
LOG_DEBUG(Service_NVDRV, "{} decoder does not support device type {}.",
|
||||
av_codec->name, av_hwdevice_get_type_name(type));
|
||||
break;
|
||||
}
|
||||
if ((config->methods & HW_CONFIG_METHOD) != 0 && config->device_type == type) {
|
||||
LOG_INFO(Service_NVDRV, "Using {} GPU decoder", av_hwdevice_get_type_name(type));
|
||||
av_codec_ctx->pix_fmt = config->pix_fmt;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Codec::InitializeAvCodecContext() {
|
||||
av_codec_ctx = avcodec_alloc_context3(av_codec);
|
||||
av_opt_set(av_codec_ctx->priv_data, "tune", "zerolatency", 0);
|
||||
av_codec_ctx->thread_count = 0;
|
||||
av_codec_ctx->thread_type &= ~FF_THREAD_FRAME;
|
||||
}
|
||||
|
||||
void Codec::InitializeGpuDecoder() {
|
||||
if (!CreateGpuAvDevice()) {
|
||||
av_buffer_unref(&av_gpu_decoder);
|
||||
return;
|
||||
}
|
||||
auto* hw_device_ctx = av_buffer_ref(av_gpu_decoder);
|
||||
ASSERT_MSG(hw_device_ctx, "av_buffer_ref failed");
|
||||
av_codec_ctx->hw_device_ctx = hw_device_ctx;
|
||||
av_codec_ctx->get_format = GetGpuFormat;
|
||||
}
|
||||
|
||||
void Codec::InitializeAvFilters(AVFrame* frame) {
|
||||
const AVFilter* buffer_src = avfilter_get_by_name("buffer");
|
||||
const AVFilter* buffer_sink = avfilter_get_by_name("buffersink");
|
||||
AVFilterInOut* inputs = avfilter_inout_alloc();
|
||||
AVFilterInOut* outputs = avfilter_inout_alloc();
|
||||
SCOPE_EXIT({
|
||||
avfilter_inout_free(&inputs);
|
||||
avfilter_inout_free(&outputs);
|
||||
});
|
||||
|
||||
// Don't know how to get the accurate time_base but it doesn't matter for yadif filter
|
||||
// so just use 1/1 to make buffer filter happy
|
||||
std::string args = fmt::format("video_size={}x{}:pix_fmt={}:time_base=1/1", frame->width,
|
||||
frame->height, frame->format);
|
||||
|
||||
av_filter_graph = avfilter_graph_alloc();
|
||||
int ret = avfilter_graph_create_filter(&av_filter_src_ctx, buffer_src, "in", args.c_str(),
|
||||
nullptr, av_filter_graph);
|
||||
if (ret < 0) {
|
||||
LOG_ERROR(Service_NVDRV, "avfilter_graph_create_filter source error: {}", ret);
|
||||
return;
|
||||
}
|
||||
|
||||
ret = avfilter_graph_create_filter(&av_filter_sink_ctx, buffer_sink, "out", nullptr, nullptr,
|
||||
av_filter_graph);
|
||||
if (ret < 0) {
|
||||
LOG_ERROR(Service_NVDRV, "avfilter_graph_create_filter sink error: {}", ret);
|
||||
return;
|
||||
}
|
||||
|
||||
inputs->name = av_strdup("out");
|
||||
inputs->filter_ctx = av_filter_sink_ctx;
|
||||
inputs->pad_idx = 0;
|
||||
inputs->next = nullptr;
|
||||
|
||||
outputs->name = av_strdup("in");
|
||||
outputs->filter_ctx = av_filter_src_ctx;
|
||||
outputs->pad_idx = 0;
|
||||
outputs->next = nullptr;
|
||||
|
||||
const char* description = "yadif=1:-1:0";
|
||||
ret = avfilter_graph_parse_ptr(av_filter_graph, description, &inputs, &outputs, nullptr);
|
||||
if (ret < 0) {
|
||||
LOG_ERROR(Service_NVDRV, "avfilter_graph_parse_ptr error: {}", ret);
|
||||
return;
|
||||
}
|
||||
|
||||
ret = avfilter_graph_config(av_filter_graph, nullptr);
|
||||
if (ret < 0) {
|
||||
LOG_ERROR(Service_NVDRV, "avfilter_graph_config error: {}", ret);
|
||||
return;
|
||||
}
|
||||
|
||||
filters_initialized = true;
|
||||
}
|
||||
Codec::~Codec() = default;
|
||||
|
||||
void Codec::Initialize() {
|
||||
const AVCodecID codec = [&] {
|
||||
switch (current_codec) {
|
||||
case Host1x::NvdecCommon::VideoCodec::H264:
|
||||
return AV_CODEC_ID_H264;
|
||||
case Host1x::NvdecCommon::VideoCodec::VP8:
|
||||
return AV_CODEC_ID_VP8;
|
||||
case Host1x::NvdecCommon::VideoCodec::VP9:
|
||||
return AV_CODEC_ID_VP9;
|
||||
default:
|
||||
UNIMPLEMENTED_MSG("Unknown codec {}", current_codec);
|
||||
return AV_CODEC_ID_NONE;
|
||||
}
|
||||
}();
|
||||
av_codec = avcodec_find_decoder(codec);
|
||||
|
||||
InitializeAvCodecContext();
|
||||
if (Settings::values.nvdec_emulation.GetValue() == Settings::NvdecEmulation::Gpu) {
|
||||
InitializeGpuDecoder();
|
||||
}
|
||||
if (const int res = avcodec_open2(av_codec_ctx, av_codec, nullptr); res < 0) {
|
||||
LOG_ERROR(Service_NVDRV, "avcodec_open2() Failed with result {}", res);
|
||||
avcodec_free_context(&av_codec_ctx);
|
||||
av_buffer_unref(&av_gpu_decoder);
|
||||
return;
|
||||
}
|
||||
if (!av_codec_ctx->hw_device_ctx) {
|
||||
LOG_INFO(Service_NVDRV, "Using FFmpeg software decoding");
|
||||
}
|
||||
initialized = true;
|
||||
initialized = decode_api.Initialize(current_codec);
|
||||
}
|
||||
|
||||
void Codec::SetTargetCodec(Host1x::NvdecCommon::VideoCodec codec) {
|
||||
@@ -264,14 +35,18 @@ void Codec::Decode() {
|
||||
if (is_first_frame) {
|
||||
Initialize();
|
||||
}
|
||||
|
||||
if (!initialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Assemble bitstream.
|
||||
bool vp9_hidden_frame = false;
|
||||
const auto& frame_data = [&]() {
|
||||
size_t configuration_size = 0;
|
||||
const auto packet_data = [&]() {
|
||||
switch (current_codec) {
|
||||
case Tegra::Host1x::NvdecCommon::VideoCodec::H264:
|
||||
return h264_decoder->ComposeFrame(state, is_first_frame);
|
||||
return h264_decoder->ComposeFrame(state, &configuration_size, is_first_frame);
|
||||
case Tegra::Host1x::NvdecCommon::VideoCodec::VP8:
|
||||
return vp8_decoder->ComposeFrame(state);
|
||||
case Tegra::Host1x::NvdecCommon::VideoCodec::VP9:
|
||||
@@ -283,89 +58,35 @@ void Codec::Decode() {
|
||||
return std::span<const u8>{};
|
||||
}
|
||||
}();
|
||||
AVPacketPtr packet{av_packet_alloc(), AVPacketDeleter};
|
||||
if (!packet) {
|
||||
LOG_ERROR(Service_NVDRV, "av_packet_alloc failed");
|
||||
|
||||
// Send assembled bitstream to decoder.
|
||||
if (!decode_api.SendPacket(packet_data, configuration_size)) {
|
||||
return;
|
||||
}
|
||||
packet->data = const_cast<u8*>(frame_data.data());
|
||||
packet->size = static_cast<s32>(frame_data.size());
|
||||
if (const int res = avcodec_send_packet(av_codec_ctx, packet.get()); res != 0) {
|
||||
LOG_DEBUG(Service_NVDRV, "avcodec_send_packet error {}", res);
|
||||
return;
|
||||
}
|
||||
// Only receive/store visible frames
|
||||
|
||||
// Only receive/store visible frames.
|
||||
if (vp9_hidden_frame) {
|
||||
return;
|
||||
}
|
||||
AVFramePtr initial_frame{av_frame_alloc(), AVFrameDeleter};
|
||||
AVFramePtr final_frame{nullptr, AVFrameDeleter};
|
||||
ASSERT_MSG(initial_frame, "av_frame_alloc initial_frame failed");
|
||||
if (const int ret = avcodec_receive_frame(av_codec_ctx, initial_frame.get()); ret) {
|
||||
LOG_DEBUG(Service_NVDRV, "avcodec_receive_frame error {}", ret);
|
||||
return;
|
||||
}
|
||||
if (initial_frame->width == 0 || initial_frame->height == 0) {
|
||||
LOG_WARNING(Service_NVDRV, "Zero width or height in frame");
|
||||
return;
|
||||
}
|
||||
bool is_interlaced = initial_frame->interlaced_frame != 0;
|
||||
if (av_codec_ctx->hw_device_ctx) {
|
||||
final_frame = AVFramePtr{av_frame_alloc(), AVFrameDeleter};
|
||||
ASSERT_MSG(final_frame, "av_frame_alloc final_frame failed");
|
||||
// Can't use AV_PIX_FMT_YUV420P and share code with software decoding in vic.cpp
|
||||
// because Intel drivers crash unless using AV_PIX_FMT_NV12
|
||||
final_frame->format = PREFERRED_GPU_FMT;
|
||||
const int ret = av_hwframe_transfer_data(final_frame.get(), initial_frame.get(), 0);
|
||||
ASSERT_MSG(!ret, "av_hwframe_transfer_data error {}", ret);
|
||||
} else {
|
||||
final_frame = std::move(initial_frame);
|
||||
}
|
||||
if (final_frame->format != PREFERRED_CPU_FMT && final_frame->format != PREFERRED_GPU_FMT) {
|
||||
UNIMPLEMENTED_MSG("Unexpected video format: {}", final_frame->format);
|
||||
return;
|
||||
}
|
||||
if (!is_interlaced) {
|
||||
av_frames.push(std::move(final_frame));
|
||||
} else {
|
||||
if (!filters_initialized) {
|
||||
InitializeAvFilters(final_frame.get());
|
||||
}
|
||||
if (const int ret = av_buffersrc_add_frame_flags(av_filter_src_ctx, final_frame.get(),
|
||||
AV_BUFFERSRC_FLAG_KEEP_REF);
|
||||
ret) {
|
||||
LOG_DEBUG(Service_NVDRV, "av_buffersrc_add_frame_flags error {}", ret);
|
||||
return;
|
||||
}
|
||||
while (true) {
|
||||
auto filter_frame = AVFramePtr{av_frame_alloc(), AVFrameDeleter};
|
||||
|
||||
int ret = av_buffersink_get_frame(av_filter_sink_ctx, filter_frame.get());
|
||||
// Receive output frames from decoder.
|
||||
decode_api.ReceiveFrames(frames);
|
||||
|
||||
if (ret == AVERROR(EAGAIN) || ret == AVERROR(AVERROR_EOF))
|
||||
break;
|
||||
if (ret < 0) {
|
||||
LOG_DEBUG(Service_NVDRV, "av_buffersink_get_frame error {}", ret);
|
||||
return;
|
||||
}
|
||||
|
||||
av_frames.push(std::move(filter_frame));
|
||||
}
|
||||
}
|
||||
while (av_frames.size() > 10) {
|
||||
LOG_TRACE(Service_NVDRV, "av_frames.push overflow dropped frame");
|
||||
av_frames.pop();
|
||||
while (frames.size() > 10) {
|
||||
LOG_DEBUG(HW_GPU, "ReceiveFrames overflow, dropped frame");
|
||||
frames.pop();
|
||||
}
|
||||
}
|
||||
|
||||
AVFramePtr Codec::GetCurrentFrame() {
|
||||
std::unique_ptr<FFmpeg::Frame> Codec::GetCurrentFrame() {
|
||||
// Sometimes VIC will request more frames than have been decoded.
|
||||
// in this case, return a nullptr and don't overwrite previous frame data
|
||||
if (av_frames.empty()) {
|
||||
return AVFramePtr{nullptr, AVFrameDeleter};
|
||||
// in this case, return a blank frame and don't overwrite previous data.
|
||||
if (frames.empty()) {
|
||||
return {};
|
||||
}
|
||||
AVFramePtr frame = std::move(av_frames.front());
|
||||
av_frames.pop();
|
||||
|
||||
auto frame = std::move(frames.front());
|
||||
frames.pop();
|
||||
return frame;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,28 +4,15 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string_view>
|
||||
#include <queue>
|
||||
#include "common/common_types.h"
|
||||
#include "video_core/host1x/ffmpeg/ffmpeg.h"
|
||||
#include "video_core/host1x/nvdec_common.h"
|
||||
|
||||
extern "C" {
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wconversion"
|
||||
#endif
|
||||
#include <libavcodec/avcodec.h>
|
||||
#include <libavfilter/avfilter.h>
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
}
|
||||
|
||||
namespace Tegra {
|
||||
|
||||
void AVFrameDeleter(AVFrame* ptr);
|
||||
using AVFramePtr = std::unique_ptr<AVFrame, decltype(&AVFrameDeleter)>;
|
||||
|
||||
namespace Decoder {
|
||||
class H264;
|
||||
class VP8;
|
||||
@@ -51,7 +38,7 @@ public:
|
||||
void Decode();
|
||||
|
||||
/// Returns next decoded frame
|
||||
[[nodiscard]] AVFramePtr GetCurrentFrame();
|
||||
[[nodiscard]] std::unique_ptr<FFmpeg::Frame> GetCurrentFrame();
|
||||
|
||||
/// Returns the value of current_codec
|
||||
[[nodiscard]] Host1x::NvdecCommon::VideoCodec GetCurrentCodec() const;
|
||||
@@ -60,25 +47,9 @@ public:
|
||||
[[nodiscard]] std::string_view GetCurrentCodecName() const;
|
||||
|
||||
private:
|
||||
void InitializeAvCodecContext();
|
||||
|
||||
void InitializeAvFilters(AVFrame* frame);
|
||||
|
||||
void InitializeGpuDecoder();
|
||||
|
||||
bool CreateGpuAvDevice();
|
||||
|
||||
bool initialized{};
|
||||
bool filters_initialized{};
|
||||
Host1x::NvdecCommon::VideoCodec current_codec{Host1x::NvdecCommon::VideoCodec::None};
|
||||
|
||||
const AVCodec* av_codec{nullptr};
|
||||
AVCodecContext* av_codec_ctx{nullptr};
|
||||
AVBufferRef* av_gpu_decoder{nullptr};
|
||||
|
||||
AVFilterContext* av_filter_src_ctx{nullptr};
|
||||
AVFilterContext* av_filter_sink_ctx{nullptr};
|
||||
AVFilterGraph* av_filter_graph{nullptr};
|
||||
FFmpeg::DecodeApi decode_api;
|
||||
|
||||
Host1x::Host1x& host1x;
|
||||
const Host1x::NvdecCommon::NvdecRegisters& state;
|
||||
@@ -86,7 +57,7 @@ private:
|
||||
std::unique_ptr<Decoder::VP8> vp8_decoder;
|
||||
std::unique_ptr<Decoder::VP9> vp9_decoder;
|
||||
|
||||
std::queue<AVFramePtr> av_frames{};
|
||||
std::queue<std::unique_ptr<FFmpeg::Frame>> frames{};
|
||||
};
|
||||
|
||||
} // namespace Tegra
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user