Compare commits

...

20 Commits

Author SHA1 Message Date
48d16031e9 Android #55 2023-08-30 00:57:37 +00:00
2f03fac9a0 Merge pull request #11413 from t895/intents
android: Support intents to emulation activity
2023-08-29 20:01:52 -04:00
3d5ecc1f08 Merge pull request #11406 from german77/sdl2-28-2
externals: Update SDL to 2.28.2
2023-08-29 09:27:54 -04:00
52c71e7eb6 Merge pull request #11408 from Kelebek1/fix_audio_node_id
[Audio] Fix node id index in DropVoices
2023-08-29 09:27:40 -04:00
1f04a3dd55 Merge pull request #11409 from liamwhite/splatoon-nsd-v2
sfdnsres: ensure lp1 is not resolved
2023-08-29 09:27:32 -04:00
d360abadba Merge pull request #11112 from danilaml/nvdec-deinterlace
Use initial_frame to check interlaced flag
2023-08-29 09:27:22 -04:00
2dbe067d74 android: Support intents to emulation activity 2023-08-29 02:57:20 -04:00
2f18fa5cd1 Merge pull request #11392 from t895/layout-troubles
android: Emulation activity fixes
2023-08-29 02:11:13 -04:00
1615a86375 Merge pull request #11390 from FearlessTobi/hwopus-multi
hwopus: Implement OpenHardwareOpusDecoderForMultiStreamEx and DecodeInterleavedForMultiStream
2023-08-28 19:14:44 -04:00
199de26995 Merge pull request #11399 from liamwhite/cubeb-latency
audio: allow more latency in cubeb initialization
2023-08-28 19:14:33 -04:00
6c68b07a67 sfdnsres: ensure lp1 is not resolved 2023-08-28 11:55:53 -04:00
1d201c71dc Fix node id index in DropVoices 2023-08-28 10:35:30 +01:00
4077ff6851 externals: Update SDL to 2.28.2 2023-08-27 21:08:28 -06:00
164f880f23 Use initial_frame to check interlaced flag
If final frame was transferred from GPU, it won't carry the props.

Fixes #11089
2023-08-28 00:48:53 +04:00
954144e22b audio: allow more latency in cubeb initialization 2023-08-27 12:46:01 -04:00
c2f827b85e hwopus: Implement OpenHardwareOpusDecoderForMultiStreamEx and DecodeInterleavedForMultiStream
Allows MLB The Show 22 to boot.

Fixes https://github.com/yuzu-emu/yuzu/issues/7911.
2023-08-27 18:03:10 +02:00
037f82025c android: Don't set a default emulation orientation
Could cause unnecessary configuration change when setting an orientation other than "Landscape"
2023-08-27 00:19:03 -04:00
338d6f29b1 android: Properly adjust emulation surface aspect ratio
Previously the emulation surface wouldn't respond properly to orientation changes. This would result in the screen appearing stretched when starting in one orientation and switching to another.

The code for calculating the bounds of the view have been changed to match the expected behavior now. Before the view would just match parent in height and width. Now instead of using setLeftTopRightBottom (which is intended to be used for animations) we pass newly calculated bounds for the view into super. Now the view bounds match the emulation output.

This also means that we don't need the overload for the SettingsActivity to launch it using an ActivityResultLauncher. We can just update the view in onResume.
2023-08-27 00:16:53 -04:00
ada4697300 Merge pull request #11389 from FernandoS27/discard-fix
Buffer Cache: fix discard writes.
2023-08-27 04:26:59 +02:00
acc99433c7 Buffer Cache: fix discard writes. 2023-08-27 03:45:43 +02:00
20 changed files with 177 additions and 78 deletions

View File

@ -524,7 +524,7 @@ if (ENABLE_SDL2)
if (YUZU_USE_BUNDLED_SDL2) if (YUZU_USE_BUNDLED_SDL2)
# Detect toolchain and platform # Detect toolchain and platform
if ((MSVC_VERSION GREATER_EQUAL 1920 AND MSVC_VERSION LESS 1940) AND ARCHITECTURE_x86_64) if ((MSVC_VERSION GREATER_EQUAL 1920 AND MSVC_VERSION LESS 1940) AND ARCHITECTURE_x86_64)
set(SDL2_VER "SDL2-2.28.1") set(SDL2_VER "SDL2-2.28.2")
else() else()
message(FATAL_ERROR "No bundled SDL2 binaries for your toolchain. Disable YUZU_USE_BUNDLED_SDL2 and provide your own.") message(FATAL_ERROR "No bundled SDL2 binaries for your toolchain. Disable YUZU_USE_BUNDLED_SDL2 and provide your own.")
endif() endif()

View File

@ -1,3 +1,11 @@
| Pull Request | Commit | Title | Author | Merged? |
|----|----|----|----|----|
End of merge log. You can find the original README.md below the break.
-----
<!-- <!--
SPDX-FileCopyrightText: 2018 yuzu Emulator Project SPDX-FileCopyrightText: 2018 yuzu Emulator Project
SPDX-License-Identifier: GPL-2.0-or-later SPDX-License-Identifier: GPL-2.0-or-later

2
externals/SDL vendored

View File

@ -164,7 +164,7 @@ if (NOT WIN32 AND NOT ANDROID)
--enable-decoder=h264 --enable-decoder=h264
--enable-decoder=vp8 --enable-decoder=vp8
--enable-decoder=vp9 --enable-decoder=vp9
--enable-filter=yadif --enable-filter=yadif,scale
--cc="${FFmpeg_CC}" --cc="${FFmpeg_CC}"
--cxx="${FFmpeg_CXX}" --cxx="${FFmpeg_CXX}"
${FFmpeg_HWACCEL_FLAGS} ${FFmpeg_HWACCEL_FLAGS}
@ -254,7 +254,7 @@ elseif(ANDROID)
set(FFmpeg_INCLUDE_DIR "${FFmpeg_INCLUDE_DIR}" PARENT_SCOPE) set(FFmpeg_INCLUDE_DIR "${FFmpeg_INCLUDE_DIR}" PARENT_SCOPE)
elseif(WIN32) elseif(WIN32)
# Use yuzu FFmpeg binaries # Use yuzu FFmpeg binaries
set(FFmpeg_EXT_NAME "ffmpeg-5.1.3") set(FFmpeg_EXT_NAME "ffmpeg-6.0")
set(FFmpeg_PATH "${CMAKE_BINARY_DIR}/externals/${FFmpeg_EXT_NAME}") set(FFmpeg_PATH "${CMAKE_BINARY_DIR}/externals/${FFmpeg_EXT_NAME}")
download_bundled_external("ffmpeg/" ${FFmpeg_EXT_NAME} "") download_bundled_external("ffmpeg/" ${FFmpeg_EXT_NAME} "")
set(FFmpeg_FOUND YES) set(FFmpeg_FOUND YES)

View File

@ -56,7 +56,6 @@ SPDX-License-Identifier: GPL-3.0-or-later
android:name="org.yuzu.yuzu_emu.activities.EmulationActivity" android:name="org.yuzu.yuzu_emu.activities.EmulationActivity"
android:theme="@style/Theme.Yuzu.Main" android:theme="@style/Theme.Yuzu.Main"
android:launchMode="singleTop" android:launchMode="singleTop"
android:screenOrientation="userLandscape"
android:supportsPictureInPicture="true" android:supportsPictureInPicture="true"
android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout|uiMode" android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout|uiMode"
android:exported="true"> android:exported="true">
@ -67,6 +66,14 @@ SPDX-License-Identifier: GPL-3.0-or-later
<data android:mimeType="application/octet-stream" /> <data android:mimeType="application/octet-stream" />
</intent-filter> </intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data
android:mimeType="application/octet-stream"
android:scheme="content"/>
</intent-filter>
<meta-data <meta-data
android:name="android.nfc.action.TECH_DISCOVERED" android:name="android.nfc.action.TECH_DISCOVERED"
android:resource="@xml/nfc_tech_filter" /> android:resource="@xml/nfc_tech_filter" />

View File

@ -11,7 +11,6 @@ import android.view.View
import android.view.ViewGroup.MarginLayoutParams import android.view.ViewGroup.MarginLayoutParams
import android.widget.Toast import android.widget.Toast
import androidx.activity.OnBackPressedCallback import androidx.activity.OnBackPressedCallback
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.viewModels import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat import androidx.core.view.ViewCompat
@ -246,17 +245,5 @@ class SettingsActivity : AppCompatActivity(), SettingsActivityView {
settings.putExtra(ARG_GAME_ID, gameId) settings.putExtra(ARG_GAME_ID, gameId)
context.startActivity(settings) context.startActivity(settings)
} }
fun launch(
context: Context,
launcher: ActivityResultLauncher<Intent>,
menuTag: String?,
gameId: String?
) {
val settings = Intent(context, SettingsActivity::class.java)
settings.putExtra(ARG_MENU_TAG, menuTag)
settings.putExtra(ARG_GAME_ID, gameId)
launcher.launch(settings)
}
} }
} }

View File

@ -7,11 +7,11 @@ import android.annotation.SuppressLint
import android.app.AlertDialog import android.app.AlertDialog
import android.content.Context import android.content.Context
import android.content.DialogInterface import android.content.DialogInterface
import android.content.Intent
import android.content.SharedPreferences import android.content.SharedPreferences
import android.content.pm.ActivityInfo import android.content.pm.ActivityInfo
import android.content.res.Configuration import android.content.res.Configuration
import android.graphics.Color import android.graphics.Color
import android.net.Uri
import android.os.Bundle import android.os.Bundle
import android.os.Handler import android.os.Handler
import android.os.Looper import android.os.Looper
@ -19,8 +19,6 @@ import android.util.Rational
import android.view.* import android.view.*
import android.widget.TextView import android.widget.TextView
import androidx.activity.OnBackPressedCallback import androidx.activity.OnBackPressedCallback
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.widget.PopupMenu import androidx.appcompat.widget.PopupMenu
import androidx.core.content.res.ResourcesCompat import androidx.core.content.res.ResourcesCompat
import androidx.core.graphics.Insets import androidx.core.graphics.Insets
@ -50,6 +48,7 @@ import org.yuzu.yuzu_emu.features.settings.model.IntSetting
import org.yuzu.yuzu_emu.features.settings.model.Settings import org.yuzu.yuzu_emu.features.settings.model.Settings
import org.yuzu.yuzu_emu.features.settings.ui.SettingsActivity import org.yuzu.yuzu_emu.features.settings.ui.SettingsActivity
import org.yuzu.yuzu_emu.features.settings.utils.SettingsFile import org.yuzu.yuzu_emu.features.settings.utils.SettingsFile
import org.yuzu.yuzu_emu.model.Game
import org.yuzu.yuzu_emu.overlay.InputOverlay import org.yuzu.yuzu_emu.overlay.InputOverlay
import org.yuzu.yuzu_emu.utils.* import org.yuzu.yuzu_emu.utils.*
@ -62,12 +61,12 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
private var _binding: FragmentEmulationBinding? = null private var _binding: FragmentEmulationBinding? = null
private val binding get() = _binding!! private val binding get() = _binding!!
val args by navArgs<EmulationFragmentArgs>() private val args by navArgs<EmulationFragmentArgs>()
private lateinit var game: Game
private var isInFoldableLayout = false private var isInFoldableLayout = false
private lateinit var onReturnFromSettings: ActivityResultLauncher<Intent>
override fun onAttach(context: Context) { override fun onAttach(context: Context) {
super.onAttach(context) super.onAttach(context)
if (context is EmulationActivity) { if (context is EmulationActivity) {
@ -81,11 +80,6 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
.collect { updateFoldableLayout(context, it) } .collect { updateFoldableLayout(context, it) }
} }
} }
onReturnFromSettings = context.activityResultRegistry.register(
"SettingsResult",
ActivityResultContracts.StartActivityForResult()
) { updateScreenLayout() }
} else { } else {
throw IllegalStateException("EmulationFragment must have EmulationActivity parent") throw IllegalStateException("EmulationFragment must have EmulationActivity parent")
} }
@ -97,10 +91,25 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
val intentUri: Uri? = requireActivity().intent.data
var intentGame: Game? = null
if (intentUri != null) {
intentGame = if (Game.extensions.contains(FileUtil.getExtension(intentUri))) {
GameHelper.getGame(requireActivity().intent.data!!, false)
} else {
null
}
}
game = if (args.game != null) {
args.game!!
} else {
intentGame ?: error("[EmulationFragment] No bootable game present!")
}
// So this fragment doesn't restart on configuration changes; i.e. rotation. // So this fragment doesn't restart on configuration changes; i.e. rotation.
retainInstance = true retainInstance = true
preferences = PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext) preferences = PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext)
emulationState = EmulationState(args.game.path) emulationState = EmulationState(game.path)
} }
/** /**
@ -124,7 +133,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
updateShowFpsOverlay() updateShowFpsOverlay()
binding.inGameMenu.getHeaderView(0).findViewById<TextView>(R.id.text_game_title).text = binding.inGameMenu.getHeaderView(0).findViewById<TextView>(R.id.text_game_title).text =
args.game.title game.title
binding.inGameMenu.setNavigationItemSelectedListener { binding.inGameMenu.setNavigationItemSelectedListener {
when (it.itemId) { when (it.itemId) {
R.id.menu_pause_emulation -> { R.id.menu_pause_emulation -> {
@ -149,12 +158,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
} }
R.id.menu_settings -> { R.id.menu_settings -> {
SettingsActivity.launch( SettingsActivity.launch(requireContext(), SettingsFile.FILE_NAME_CONFIG, "")
requireContext(),
onReturnFromSettings,
SettingsFile.FILE_NAME_CONFIG,
""
)
true true
} }

View File

@ -63,13 +63,13 @@ object GameHelper {
) )
} else { } else {
if (Game.extensions.contains(FileUtil.getExtension(it.uri))) { if (Game.extensions.contains(FileUtil.getExtension(it.uri))) {
games.add(getGame(it.uri)) games.add(getGame(it.uri, true))
} }
} }
} }
} }
private fun getGame(uri: Uri): Game { fun getGame(uri: Uri, addedToLibrary: Boolean): Game {
val filePath = uri.toString() val filePath = uri.toString()
var name = NativeLibrary.getTitle(filePath) var name = NativeLibrary.getTitle(filePath)
@ -94,11 +94,13 @@ object GameHelper {
NativeLibrary.isHomebrew(filePath) NativeLibrary.isHomebrew(filePath)
) )
val addedTime = preferences.getLong(newGame.keyAddedToLibraryTime, 0L) if (addedToLibrary) {
if (addedTime == 0L) { val addedTime = preferences.getLong(newGame.keyAddedToLibraryTime, 0L)
preferences.edit() if (addedTime == 0L) {
.putLong(newGame.keyAddedToLibraryTime, System.currentTimeMillis()) preferences.edit()
.apply() .putLong(newGame.keyAddedToLibraryTime, System.currentTimeMillis())
.apply()
}
} }
return newGame return newGame

View File

@ -7,7 +7,6 @@ import android.content.Context
import android.util.AttributeSet import android.util.AttributeSet
import android.util.Rational import android.util.Rational
import android.view.SurfaceView import android.view.SurfaceView
import kotlin.math.roundToInt
class FixedRatioSurfaceView @JvmOverloads constructor( class FixedRatioSurfaceView @JvmOverloads constructor(
context: Context, context: Context,
@ -22,27 +21,44 @@ class FixedRatioSurfaceView @JvmOverloads constructor(
*/ */
fun setAspectRatio(ratio: Rational?) { fun setAspectRatio(ratio: Rational?) {
aspectRatio = ratio?.toFloat() ?: 0f aspectRatio = ratio?.toFloat() ?: 0f
requestLayout()
} }
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec) val displayWidth: Float = MeasureSpec.getSize(widthMeasureSpec).toFloat()
val width = MeasureSpec.getSize(widthMeasureSpec) val displayHeight: Float = MeasureSpec.getSize(heightMeasureSpec).toFloat()
val height = MeasureSpec.getSize(heightMeasureSpec)
if (aspectRatio != 0f) { if (aspectRatio != 0f) {
val newWidth: Int val displayAspect = displayWidth / displayHeight
val newHeight: Int if (displayAspect < aspectRatio) {
if (height * aspectRatio < width) { // Max out width
newWidth = (height * aspectRatio).roundToInt() val halfHeight = displayHeight / 2
newHeight = height val surfaceHeight = displayWidth / aspectRatio
val newTop: Float = halfHeight - (surfaceHeight / 2)
val newBottom: Float = halfHeight + (surfaceHeight / 2)
super.onMeasure(
widthMeasureSpec,
MeasureSpec.makeMeasureSpec(
newBottom.toInt() - newTop.toInt(),
MeasureSpec.EXACTLY
)
)
return
} else { } else {
newWidth = width // Max out height
newHeight = (width / aspectRatio).roundToInt() val halfWidth = displayWidth / 2
val surfaceWidth = displayHeight * aspectRatio
val newLeft: Float = halfWidth - (surfaceWidth / 2)
val newRight: Float = halfWidth + (surfaceWidth / 2)
super.onMeasure(
MeasureSpec.makeMeasureSpec(
newRight.toInt() - newLeft.toInt(),
MeasureSpec.EXACTLY
),
heightMeasureSpec
)
return
} }
val left = (width - newWidth) / 2
val top = (height - newHeight) / 2
setLeftTopRightBottom(left, top, left + newWidth, top + newHeight)
} else {
setLeftTopRightBottom(0, 0, width, height)
} }
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
} }
} }

View File

@ -12,7 +12,9 @@
tools:layout="@layout/fragment_emulation" > tools:layout="@layout/fragment_emulation" >
<argument <argument
android:name="game" android:name="game"
app:argType="org.yuzu.yuzu_emu.model.Game" /> app:argType="org.yuzu.yuzu_emu.model.Game"
app:nullable="true"
android:defaultValue="@null" />
</fragment> </fragment>
</navigation> </navigation>

View File

@ -62,7 +62,9 @@
android:label="EmulationActivity"> android:label="EmulationActivity">
<argument <argument
android:name="game" android:name="game"
app:argType="org.yuzu.yuzu_emu.model.Game" /> app:argType="org.yuzu.yuzu_emu.model.Game"
app:nullable="true"
android:defaultValue="@null" />
</activity> </activity>
<action <action

View File

@ -778,7 +778,7 @@ u32 System::DropVoices(CommandBuffer& command_buffer, u32 estimated_process_time
while (i < command_buffer.count) { while (i < command_buffer.count) {
const auto node_id{cmd->node_id}; const auto node_id{cmd->node_id};
const auto node_id_type{cmd->node_id >> 28}; const auto node_id_type{cmd->node_id >> 28};
const auto node_id_base{cmd->node_id & 0xFFF}; const auto node_id_base{(cmd->node_id >> 16) & 0xFFF};
// If the new estimated process time falls below the limit, we're done dropping. // If the new estimated process time falls below the limit, we're done dropping.
if (estimated_process_time <= time_limit) { if (estimated_process_time <= time_limit) {

View File

@ -364,7 +364,7 @@ bool IsCubebSuitable() {
} }
#endif #endif
// Test min latency // Get min latency
cubeb_stream_params params{}; cubeb_stream_params params{};
params.rate = TargetSampleRate; params.rate = TargetSampleRate;
params.channels = 2; params.channels = 2;
@ -380,11 +380,6 @@ bool IsCubebSuitable() {
} }
latency = std::max(latency, TargetSampleCount * 2); latency = std::max(latency, TargetSampleCount * 2);
if (latency > TargetSampleCount * 3) {
LOG_ERROR(Audio_Sink, "Cubeb latency is too high, it is not suitable.");
return false;
}
// Test opening a device with standard parameters // Test opening a device with standard parameters
cubeb_devid output_device{0}; cubeb_devid output_device{0};
cubeb_devid input_device{0}; cubeb_devid input_device{0};

View File

@ -83,8 +83,8 @@ const SinkDetails& GetOutputSinkDetails(Settings::AudioEngine sink_id) {
break; break;
} }
} }
LOG_ERROR(Service_Audio, "Auto-selecting the {} backend", LOG_INFO(Service_Audio, "Auto-selecting the {} backend",
Settings::CanonicalizeEnum(iter->id)); Settings::CanonicalizeEnum(iter->id));
} else { } else {
if (iter != std::end(sink_details) && !iter->is_suitable()) { if (iter != std::end(sink_details) && !iter->is_suitable()) {
LOG_ERROR(Service_Audio, "Selected backend {} is not suitable, falling back to null", LOG_ERROR(Service_Audio, "Selected backend {} is not suitable, falling back to null",

View File

@ -174,7 +174,7 @@ public:
{6, &IHardwareOpusDecoderManager::DecodeInterleaved, "DecodeInterleavedWithPerfAndResetOld"}, {6, &IHardwareOpusDecoderManager::DecodeInterleaved, "DecodeInterleavedWithPerfAndResetOld"},
{7, nullptr, "DecodeInterleavedForMultiStreamWithPerfAndResetOld"}, {7, nullptr, "DecodeInterleavedForMultiStreamWithPerfAndResetOld"},
{8, &IHardwareOpusDecoderManager::DecodeInterleaved, "DecodeInterleaved"}, {8, &IHardwareOpusDecoderManager::DecodeInterleaved, "DecodeInterleaved"},
{9, nullptr, "DecodeInterleavedForMultiStream"}, {9, &IHardwareOpusDecoderManager::DecodeInterleavedForMultiStream, "DecodeInterleavedForMultiStream"},
}; };
// clang-format on // clang-format on
@ -206,6 +206,16 @@ private:
decoder_state.DecodeInterleaved(ctx, OpusDecoderState::PerfTime::Enabled, extra_behavior); decoder_state.DecodeInterleaved(ctx, OpusDecoderState::PerfTime::Enabled, extra_behavior);
} }
void DecodeInterleavedForMultiStream(HLERequestContext& ctx) {
LOG_DEBUG(Audio, "called");
IPC::RequestParser rp{ctx};
const auto extra_behavior = rp.Pop<bool>() ? OpusDecoderState::ExtraBehavior::ResetContext
: OpusDecoderState::ExtraBehavior::None;
decoder_state.DecodeInterleaved(ctx, OpusDecoderState::PerfTime::Enabled, extra_behavior);
}
OpusDecoderState decoder_state; OpusDecoderState decoder_state;
}; };
@ -354,6 +364,40 @@ void HwOpus::OpenHardwareOpusDecoderEx(HLERequestContext& ctx) {
system, OpusDecoderState{std::move(decoder), sample_rate, channel_count}); system, OpusDecoderState{std::move(decoder), sample_rate, channel_count});
} }
void HwOpus::OpenHardwareOpusDecoderForMultiStreamEx(HLERequestContext& ctx) {
OpusMultiStreamParametersEx params;
std::memcpy(&params, ctx.ReadBuffer().data(), ctx.GetReadBufferSize());
const auto& sample_rate = params.sample_rate;
const auto& channel_count = params.channel_count;
LOG_INFO(
Audio,
"called with sample_rate={}, channel_count={}, number_streams={}, number_stereo_streams={}",
sample_rate, channel_count, params.number_streams, params.number_stereo_streams);
ASSERT_MSG(sample_rate == 48000 || sample_rate == 24000 || sample_rate == 16000 ||
sample_rate == 12000 || sample_rate == 8000,
"Invalid sample rate");
int error = 0;
OpusDecoderPtr decoder{opus_multistream_decoder_create(
sample_rate, static_cast<int>(channel_count), params.number_streams,
params.number_stereo_streams, params.channel_mappings.data(), &error)};
if (error != OPUS_OK || decoder == nullptr) {
LOG_ERROR(Audio, "Failed to create Opus decoder (error={}).", error);
IPC::ResponseBuilder rb{ctx, 2};
// TODO(ogniK): Use correct error code
rb.Push(ResultUnknown);
return;
}
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<IHardwareOpusDecoderManager>(
system, OpusDecoderState{std::move(decoder), sample_rate, channel_count});
}
HwOpus::HwOpus(Core::System& system_) : ServiceFramework{system_, "hwopus"} { HwOpus::HwOpus(Core::System& system_) : ServiceFramework{system_, "hwopus"} {
static const FunctionInfo functions[] = { static const FunctionInfo functions[] = {
{0, &HwOpus::OpenHardwareOpusDecoder, "OpenHardwareOpusDecoder"}, {0, &HwOpus::OpenHardwareOpusDecoder, "OpenHardwareOpusDecoder"},
@ -362,7 +406,8 @@ HwOpus::HwOpus(Core::System& system_) : ServiceFramework{system_, "hwopus"} {
{3, nullptr, "GetWorkBufferSizeForMultiStream"}, {3, nullptr, "GetWorkBufferSizeForMultiStream"},
{4, &HwOpus::OpenHardwareOpusDecoderEx, "OpenHardwareOpusDecoderEx"}, {4, &HwOpus::OpenHardwareOpusDecoderEx, "OpenHardwareOpusDecoderEx"},
{5, &HwOpus::GetWorkBufferSizeEx, "GetWorkBufferSizeEx"}, {5, &HwOpus::GetWorkBufferSizeEx, "GetWorkBufferSizeEx"},
{6, nullptr, "OpenHardwareOpusDecoderForMultiStreamEx"}, {6, &HwOpus::OpenHardwareOpusDecoderForMultiStreamEx,
"OpenHardwareOpusDecoderForMultiStreamEx"},
{7, &HwOpus::GetWorkBufferSizeForMultiStreamEx, "GetWorkBufferSizeForMultiStreamEx"}, {7, &HwOpus::GetWorkBufferSizeForMultiStreamEx, "GetWorkBufferSizeForMultiStreamEx"},
{8, nullptr, "GetWorkBufferSizeExEx"}, {8, nullptr, "GetWorkBufferSizeExEx"},
{9, nullptr, "GetWorkBufferSizeForMultiStreamExEx"}, {9, nullptr, "GetWorkBufferSizeForMultiStreamExEx"},

View File

@ -18,8 +18,10 @@ struct OpusMultiStreamParametersEx {
u32 number_stereo_streams; u32 number_stereo_streams;
u32 use_large_frame_size; u32 use_large_frame_size;
u32 padding; u32 padding;
std::array<u32, 64> channel_mappings; std::array<u8, 0x100> channel_mappings;
}; };
static_assert(sizeof(OpusMultiStreamParametersEx) == 0x118,
"OpusMultiStreamParametersEx has incorrect size");
class HwOpus final : public ServiceFramework<HwOpus> { class HwOpus final : public ServiceFramework<HwOpus> {
public: public:
@ -29,6 +31,7 @@ public:
private: private:
void OpenHardwareOpusDecoder(HLERequestContext& ctx); void OpenHardwareOpusDecoder(HLERequestContext& ctx);
void OpenHardwareOpusDecoderEx(HLERequestContext& ctx); void OpenHardwareOpusDecoderEx(HLERequestContext& ctx);
void OpenHardwareOpusDecoderForMultiStreamEx(HLERequestContext& ctx);
void GetWorkBufferSize(HLERequestContext& ctx); void GetWorkBufferSize(HLERequestContext& ctx);
void GetWorkBufferSizeEx(HLERequestContext& ctx); void GetWorkBufferSizeEx(HLERequestContext& ctx);
void GetWorkBufferSizeForMultiStreamEx(HLERequestContext& ctx); void GetWorkBufferSizeForMultiStreamEx(HLERequestContext& ctx);

View File

@ -19,6 +19,12 @@ enum class ServerEnvironmentType : u8 {
Dp, Dp,
}; };
// This is nn::nsd::EnvironmentIdentifier
struct EnvironmentIdentifier {
std::array<u8, 8> identifier;
};
static_assert(sizeof(EnvironmentIdentifier) == 0x8);
NSD::NSD(Core::System& system_, const char* name) : ServiceFramework{system_, name} { NSD::NSD(Core::System& system_, const char* name) : ServiceFramework{system_, name} {
// clang-format off // clang-format off
static const FunctionInfo functions[] = { static const FunctionInfo functions[] = {
@ -101,8 +107,9 @@ void NSD::ResolveEx(HLERequestContext& ctx) {
} }
void NSD::GetEnvironmentIdentifier(HLERequestContext& ctx) { void NSD::GetEnvironmentIdentifier(HLERequestContext& ctx) {
const std::string environment_identifier = "lp1"; constexpr EnvironmentIdentifier lp1 = {
ctx.WriteBuffer(environment_identifier); .identifier = {'l', 'p', '1', '\0', '\0', '\0', '\0', '\0'}};
ctx.WriteBuffer(lp1);
IPC::ResponseBuilder rb{ctx, 2}; IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess); rb.Push(ResultSuccess);

View File

@ -150,6 +150,12 @@ static std::pair<u32, GetAddrInfoError> GetHostByNameRequestImpl(HLERequestConte
const std::string host = Common::StringFromBuffer(host_buffer); const std::string host = Common::StringFromBuffer(host_buffer);
// For now, ignore options, which are in input buffer 1 for GetHostByNameRequestWithOptions. // For now, ignore options, which are in input buffer 1 for GetHostByNameRequestWithOptions.
// Prevent resolution of Nintendo servers
if (host.find("srv.nintendo.net") != std::string::npos) {
LOG_WARNING(Network, "Resolution of hostname {} requested, returning EAI_AGAIN", host);
return {0, GetAddrInfoError::AGAIN};
}
auto res = Network::GetAddressInfo(host, /*service*/ std::nullopt); auto res = Network::GetAddressInfo(host, /*service*/ std::nullopt);
if (!res.has_value()) { if (!res.has_value()) {
return {0, Translate(res.error())}; return {0, Translate(res.error())};
@ -261,6 +267,12 @@ static std::pair<u32, GetAddrInfoError> GetAddrInfoRequestImpl(HLERequestContext
const auto host_buffer = ctx.ReadBuffer(0); const auto host_buffer = ctx.ReadBuffer(0);
const std::string host = Common::StringFromBuffer(host_buffer); const std::string host = Common::StringFromBuffer(host_buffer);
// Prevent resolution of Nintendo servers
if (host.find("srv.nintendo.net") != std::string::npos) {
LOG_WARNING(Network, "Resolution of hostname {} requested, returning EAI_AGAIN", host);
return {0, GetAddrInfoError::AGAIN};
}
std::optional<std::string> service = std::nullopt; std::optional<std::string> service = std::nullopt;
if (ctx.CanReadBuffer(1)) { if (ctx.CanReadBuffer(1)) {
const std::span<const u8> service_buffer = ctx.ReadBuffer(1); const std::span<const u8> service_buffer = ctx.ReadBuffer(1);

View File

@ -289,8 +289,11 @@ std::pair<typename P::Buffer*, u32> BufferCache<P>::ObtainBuffer(GPUVAddr gpu_ad
MarkWrittenBuffer(buffer_id, *cpu_addr, size); MarkWrittenBuffer(buffer_id, *cpu_addr, size);
break; break;
case ObtainBufferOperation::DiscardWrite: { case ObtainBufferOperation::DiscardWrite: {
IntervalType interval{*cpu_addr, 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); ClearDownload(interval);
common_ranges.subtract(interval);
break; break;
} }
default: default:
@ -1159,6 +1162,11 @@ void BufferCache<P>::UpdateDrawIndirect() {
.size = static_cast<u32>(size), .size = static_cast<u32>(size),
.buffer_id = FindBuffer(*cpu_addr, 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) { if (current_draw_indirect->include_count) {
update(current_draw_indirect->count_start_address, sizeof(u32), update(current_draw_indirect->count_start_address, sizeof(u32),

View File

@ -319,6 +319,7 @@ void Codec::Decode() {
LOG_WARNING(Service_NVDRV, "Zero width or height in frame"); LOG_WARNING(Service_NVDRV, "Zero width or height in frame");
return; return;
} }
bool is_interlaced = initial_frame->interlaced_frame != 0;
if (av_codec_ctx->hw_device_ctx) { if (av_codec_ctx->hw_device_ctx) {
final_frame = AVFramePtr{av_frame_alloc(), AVFrameDeleter}; final_frame = AVFramePtr{av_frame_alloc(), AVFrameDeleter};
ASSERT_MSG(final_frame, "av_frame_alloc final_frame failed"); ASSERT_MSG(final_frame, "av_frame_alloc final_frame failed");
@ -334,7 +335,7 @@ void Codec::Decode() {
UNIMPLEMENTED_MSG("Unexpected video format: {}", final_frame->format); UNIMPLEMENTED_MSG("Unexpected video format: {}", final_frame->format);
return; return;
} }
if (!final_frame->interlaced_frame) { if (!is_interlaced) {
av_frames.push(std::move(final_frame)); av_frames.push(std::move(final_frame));
} else { } else {
if (!filters_initialized) { if (!filters_initialized) {