mirror of
https://github.com/stenzek/duckstation.git
synced 2025-07-29 06:11:47 +00:00
CDROM: Add option to disable speedup on MDEC/FMVs
This commit is contained in:
parent
4f1af2f6eb
commit
b6b1a5e33c
@ -8,6 +8,7 @@
|
||||
#include "fullscreen_ui.h"
|
||||
#include "host.h"
|
||||
#include "interrupt_controller.h"
|
||||
#include "mdec.h"
|
||||
#include "settings.h"
|
||||
#include "spu.h"
|
||||
#include "system.h"
|
||||
@ -74,6 +75,9 @@ enum : u32
|
||||
MINIMUM_INTERRUPT_DELAY = 1000,
|
||||
INTERRUPT_DELAY_CYCLES = 500,
|
||||
MISSED_INT1_DELAY_CYCLES = 5000, // See CheckForSectorBufferReadComplete().
|
||||
|
||||
SINGLE_SPEED_SECTORS_PER_SECOND = 75, // 1X speed is 75 sectors per second.
|
||||
DOUBLE_SPEED_SECTORS_PER_SECOND = 150, // 2X speed is 150 sectors per second.
|
||||
};
|
||||
|
||||
static constexpr u8 INTERRUPT_REGISTER_MASK = 0x1F;
|
||||
@ -1488,7 +1492,25 @@ bool CDROM::HasPendingDiscEvent()
|
||||
bool CDROM::CanUseReadSpeedup()
|
||||
{
|
||||
// Only use read speedup in 2X mode and when we're not playing/filtering XA.
|
||||
return (!s_state.mode.cdda && !s_state.mode.xa_enable && s_state.mode.double_speed);
|
||||
// Use MDEC as a heuristic for games that don't use XA audio in FMVs. But this is opt-in for now.
|
||||
return (!s_state.mode.cdda && !s_state.mode.xa_enable && s_state.mode.double_speed &&
|
||||
(!g_settings.mdec_disable_cdrom_speedup || !MDEC::IsActive()));
|
||||
}
|
||||
|
||||
void CDROM::DisableReadSpeedup()
|
||||
{
|
||||
if (s_state.drive_state != CDROM::DriveState::Reading || !CanUseReadSpeedup())
|
||||
return;
|
||||
|
||||
// Can't test the interval directly because max speedup changes the downcount directly.
|
||||
const TickCount expected_ticks = System::GetTicksPerSecond() / DOUBLE_SPEED_SECTORS_PER_SECOND;
|
||||
const TickCount ticks_since_last_sector = s_state.drive_event.GetTicksSinceLastExecution();
|
||||
const TickCount ticks_until_next_sector = s_state.drive_event.GetTicksUntilNextExecution();
|
||||
const TickCount sector_ticks = ticks_since_last_sector + ticks_until_next_sector;
|
||||
if (sector_ticks >= expected_ticks)
|
||||
return;
|
||||
|
||||
s_state.drive_event.Schedule(expected_ticks - ticks_since_last_sector);
|
||||
}
|
||||
|
||||
TickCount CDROM::GetAckDelayForCommand(Command command)
|
||||
@ -1526,9 +1548,9 @@ TickCount CDROM::GetTicksForRead()
|
||||
const TickCount tps = System::GetTicksPerSecond();
|
||||
|
||||
if (g_settings.cdrom_read_speedup > 1 && CanUseReadSpeedup())
|
||||
return tps / (150 * g_settings.cdrom_read_speedup);
|
||||
return tps / (DOUBLE_SPEED_SECTORS_PER_SECOND * g_settings.cdrom_read_speedup);
|
||||
|
||||
return s_state.mode.double_speed ? (tps / 150) : (tps / 75);
|
||||
return s_state.mode.double_speed ? (tps / DOUBLE_SPEED_SECTORS_PER_SECOND) : (tps / SINGLE_SPEED_SECTORS_PER_SECOND);
|
||||
}
|
||||
|
||||
u32 CDROM::GetSectorsPerTrack(CDImage::LBA lba)
|
||||
@ -4276,6 +4298,13 @@ void CDROM::DrawDebugWindow(float scale)
|
||||
ImGui::TextColored(active_color, "Drive: %s (%d ticks remaining)",
|
||||
s_drive_state_names[static_cast<u8>(s_state.drive_state)],
|
||||
s_state.drive_event.IsActive() ? s_state.drive_event.GetTicksUntilNextExecution() : 0);
|
||||
|
||||
if (g_settings.cdrom_read_speedup != 1 && !CanUseReadSpeedup())
|
||||
{
|
||||
ImGui::SameLine();
|
||||
ImGui::SetCursorPosX(std::max(ImGui::GetCursorPosX(), 400.0f));
|
||||
ImGui::TextColored(ImVec4(1.0f, 0.3f, 0.3f, 1.0f), "SPEEDUP BLOCKED");
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::Text("Interrupt Enable Register: 0x%02X", s_state.interrupt_enable_register);
|
||||
|
@ -47,6 +47,7 @@ void DMARead(u32* words, u32 word_count);
|
||||
void DrawDebugWindow(float scale);
|
||||
|
||||
void SetReadaheadSectors(u32 readahead_sectors);
|
||||
void DisableReadSpeedup();
|
||||
|
||||
/// Reads a frame from the audio FIFO, used by the SPU.
|
||||
std::tuple<s16, s16> GetAudioFrame();
|
||||
|
@ -6663,6 +6663,11 @@ void FullscreenUI::DrawAdvancedSettingsPage()
|
||||
"MaxReadSpeedupCycles", Settings::DEFAULT_CDROM_MAX_READ_SPEEDUP_CYCLES, 1, 1000000,
|
||||
FSUI_CSTR("%d cycles"));
|
||||
|
||||
DrawToggleSetting(
|
||||
bsi, FSUI_VSTR("Disable Speedup on MDEC"),
|
||||
FSUI_VSTR("Tries to detect FMVs and disable read speedup during games that don't use XA streaming audio."), "CDROM",
|
||||
"DisableSpeedupOnMDEC", false);
|
||||
|
||||
DrawToggleSetting(bsi, FSUI_VSTR("Enable Region Check"),
|
||||
FSUI_VSTR("Simulates the region check present in original, unmodified consoles."), "CDROM",
|
||||
"RegionCheck", false);
|
||||
@ -9540,6 +9545,7 @@ TRANSLATE_NOOP("FullscreenUI", "Determines whether a prompt will be displayed to
|
||||
TRANSLATE_NOOP("FullscreenUI", "Determines which algorithm is used to convert interlaced frames to progressive for display on your system.");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Device Settings");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Disable Mailbox Presentation");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Disable Speedup on MDEC");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Disable Subdirectory Scanning");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Disable on 2D Polygons");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Disabled");
|
||||
@ -10031,6 +10037,7 @@ TRANSLATE_NOOP("FullscreenUI", "Toggle Fullscreen");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Toggle every %d frames");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Toggles the macro when the button is pressed, instead of held.");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Top: ");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Tries to detect FMVs and disable read speedup during games that don't use XA streaming audio.");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Trigger");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Turbo Speed");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Type");
|
||||
|
@ -40,7 +40,7 @@ namespace GameDatabase {
|
||||
enum : u32
|
||||
{
|
||||
GAME_DATABASE_CACHE_SIGNATURE = 0x45434C48,
|
||||
GAME_DATABASE_CACHE_VERSION = 26,
|
||||
GAME_DATABASE_CACHE_VERSION = 27,
|
||||
};
|
||||
|
||||
static const Entry* GetEntryForId(std::string_view code);
|
||||
@ -87,6 +87,7 @@ static constexpr const std::array s_trait_names = {
|
||||
"DisableMultitap",
|
||||
"DisableCDROMReadSpeedup",
|
||||
"DisableCDROMSeekSpeedup",
|
||||
"DisableCDROMSpeedupOnMDEC",
|
||||
"DisableTrueColor",
|
||||
"DisableFullTrueColor",
|
||||
"DisableUpscaling",
|
||||
@ -122,6 +123,7 @@ static constexpr const std::array s_trait_display_names = {
|
||||
TRANSLATE_DISAMBIG_NOOP("GameDatabase", "Disable Multitap", "GameDatabase::Trait"),
|
||||
TRANSLATE_DISAMBIG_NOOP("GameDatabase", "Disable CD-ROM Read Speedup", "GameDatabase::Trait"),
|
||||
TRANSLATE_DISAMBIG_NOOP("GameDatabase", "Disable CD-ROM Seek Speedup", "GameDatabase::Trait"),
|
||||
TRANSLATE_DISAMBIG_NOOP("GameDatabase", "Disable CD-ROM Speedup on MDEC", "GameDatabase::Trait"),
|
||||
TRANSLATE_DISAMBIG_NOOP("GameDatabase", "Disable True Color", "GameDatabase::Trait"),
|
||||
TRANSLATE_DISAMBIG_NOOP("GameDatabase", "Disable Full True Color", "GameDatabase::Trait"),
|
||||
TRANSLATE_DISAMBIG_NOOP("GameDatabase", "Disable Upscaling", "GameDatabase::Trait"),
|
||||
@ -496,6 +498,19 @@ void GameDatabase::Entry::ApplySettings(Settings& settings, bool display_osd_mes
|
||||
settings.cdrom_seek_speedup = 1;
|
||||
}
|
||||
|
||||
if (HasTrait(Trait::DisableCDROMSpeedupOnMDEC))
|
||||
{
|
||||
WARNING_LOG("Disabling CD-ROM speedup on MDEC.");
|
||||
settings.mdec_disable_cdrom_speedup = true;
|
||||
}
|
||||
else if (settings.mdec_disable_cdrom_speedup && settings.cdrom_read_speedup != 1)
|
||||
{
|
||||
Host::AddIconOSDWarning(
|
||||
"GameDBDisableCDROMSpeedupUnnecessary", ICON_EMOJI_WARNING,
|
||||
TRANSLATE_STR("GameDatabase", "Disable CD-ROM speedup on MDEC is enabled, but it is not required for this game."),
|
||||
Host::OSD_WARNING_DURATION);
|
||||
}
|
||||
|
||||
if (display_crop_mode.has_value())
|
||||
{
|
||||
if (display_osd_messages && settings.display_crop_mode != display_crop_mode.value())
|
||||
|
@ -45,6 +45,7 @@ enum class Trait : u32
|
||||
DisableMultitap,
|
||||
DisableCDROMReadSpeedup,
|
||||
DisableCDROMSeekSpeedup,
|
||||
DisableCDROMSpeedupOnMDEC,
|
||||
DisableTrueColor,
|
||||
DisableFullTrueColor,
|
||||
DisableUpscaling,
|
||||
|
@ -1,7 +1,8 @@
|
||||
// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
|
||||
// SPDX-FileCopyrightText: 2019-2025 Connor McLaughlin <stenzek@gmail.com>
|
||||
// SPDX-License-Identifier: CC-BY-NC-ND-4.0
|
||||
|
||||
#include "mdec.h"
|
||||
#include "cdrom.h"
|
||||
#include "cpu_core.h"
|
||||
#include "dma.h"
|
||||
#include "system.h"
|
||||
@ -29,6 +30,7 @@ static constexpr u32 DATA_IN_FIFO_SIZE = 1024;
|
||||
static constexpr u32 DATA_OUT_FIFO_SIZE = 768;
|
||||
static constexpr u32 NUM_BLOCKS = 6;
|
||||
static constexpr TickCount TICKS_PER_BLOCK = 448;
|
||||
static constexpr u8 ACTIVE_FRAME_COUNT = 30;
|
||||
|
||||
enum DataOutputDepth : u8
|
||||
{
|
||||
@ -131,12 +133,13 @@ struct MDECState
|
||||
StatusRegister status = {};
|
||||
bool enable_dma_in = false;
|
||||
bool enable_dma_out = false;
|
||||
State state = State::Idle;
|
||||
u8 active_frame_count = 0;
|
||||
u32 remaining_halfwords = 0;
|
||||
|
||||
// Even though the DMA is in words, we access the FIFO as halfwords.
|
||||
InlineFIFOQueue<u16, DATA_IN_FIFO_SIZE / sizeof(u16)> data_in_fifo;
|
||||
InlineFIFOQueue<u32, DATA_OUT_FIFO_SIZE / sizeof(u32)> data_out_fifo;
|
||||
State state = State::Idle;
|
||||
u32 remaining_halfwords = 0;
|
||||
|
||||
std::array<u8, 64> iq_uv{};
|
||||
std::array<u8, 64> iq_y{};
|
||||
@ -152,7 +155,9 @@ struct MDECState
|
||||
alignas(VECTOR_ALIGNMENT) std::array<u32, 256> block_rgb{};
|
||||
TimingEvent block_copy_out_event{"MDEC Block Copy Out", 1, 1, &MDEC::CopyOutBlock, nullptr};
|
||||
|
||||
#if defined(_DEBUG) || defined(_DEVEL)
|
||||
u32 total_blocks_decoded = 0;
|
||||
#endif
|
||||
};
|
||||
} // namespace
|
||||
|
||||
@ -161,7 +166,10 @@ ALIGN_TO_CACHE_LINE static MDECState s_state;
|
||||
|
||||
void MDEC::Initialize()
|
||||
{
|
||||
#if defined(_DEBUG) || defined(_DEVEL)
|
||||
s_state.total_blocks_decoded = 0;
|
||||
#endif
|
||||
s_state.active_frame_count = 0;
|
||||
Reset();
|
||||
}
|
||||
|
||||
@ -172,6 +180,7 @@ void MDEC::Shutdown()
|
||||
|
||||
void MDEC::Reset()
|
||||
{
|
||||
s_state.active_frame_count = 0;
|
||||
s_state.block_copy_out_event.Deactivate();
|
||||
SoftReset();
|
||||
}
|
||||
@ -208,11 +217,24 @@ bool MDEC::DoState(StateWrapper& sw)
|
||||
bool block_copy_out_pending = HasPendingBlockCopyOut();
|
||||
sw.Do(&block_copy_out_pending);
|
||||
if (sw.IsReading())
|
||||
{
|
||||
s_state.block_copy_out_event.SetState(block_copy_out_pending);
|
||||
s_state.active_frame_count = 0;
|
||||
}
|
||||
|
||||
return !sw.HasError();
|
||||
}
|
||||
|
||||
bool MDEC::IsActive()
|
||||
{
|
||||
return (s_state.active_frame_count > 0);
|
||||
}
|
||||
|
||||
void MDEC::EndFrame()
|
||||
{
|
||||
s_state.active_frame_count = (s_state.active_frame_count > 0) ? (s_state.active_frame_count - 1) : 0;
|
||||
}
|
||||
|
||||
u32 MDEC::ReadRegister(u32 offset)
|
||||
{
|
||||
switch (offset)
|
||||
@ -226,11 +248,11 @@ u32 MDEC::ReadRegister(u32 offset)
|
||||
return s_state.status.bits;
|
||||
}
|
||||
|
||||
[[unlikely]] default:
|
||||
{
|
||||
ERROR_LOG("Unknown MDEC register read: 0x{:08X}", offset);
|
||||
return UINT32_C(0xFFFFFFFF);
|
||||
}
|
||||
[[unlikely]] default:
|
||||
{
|
||||
ERROR_LOG("Unknown MDEC register read: 0x{:08X}", offset);
|
||||
return UINT32_C(0xFFFFFFFF);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -258,11 +280,11 @@ void MDEC::WriteRegister(u32 offset, u32 value)
|
||||
return;
|
||||
}
|
||||
|
||||
[[unlikely]] default:
|
||||
{
|
||||
ERROR_LOG("Unknown MDEC register write: 0x{:08X} <- 0x{:08X}", offset, value);
|
||||
return;
|
||||
}
|
||||
[[unlikely]] default:
|
||||
{
|
||||
ERROR_LOG("Unknown MDEC register write: 0x{:08X} <- 0x{:08X}", offset, value);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -381,6 +403,12 @@ void MDEC::WriteCommandRegister(u32 value)
|
||||
|
||||
void MDEC::Execute()
|
||||
{
|
||||
if (std::exchange(s_state.active_frame_count, ACTIVE_FRAME_COUNT) == 0)
|
||||
{
|
||||
if (g_settings.mdec_disable_cdrom_speedup)
|
||||
CDROM::DisableReadSpeedup();
|
||||
}
|
||||
|
||||
for (;;)
|
||||
{
|
||||
switch (s_state.state)
|
||||
@ -544,7 +572,9 @@ bool MDEC::DecodeMonoMacroblock()
|
||||
|
||||
ScheduleBlockCopyOut(TICKS_PER_BLOCK * 6);
|
||||
|
||||
#if defined(_DEBUG) || defined(_DEVEL)
|
||||
s_state.total_blocks_decoded++;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -599,7 +629,9 @@ bool MDEC::DecodeColoredMacroblock()
|
||||
YUVToRGB_New(8, 8, s_state.blocks[0], s_state.blocks[1], s_state.blocks[5]);
|
||||
}
|
||||
|
||||
#if defined(_DEBUG) || defined(_DEVEL)
|
||||
s_state.total_blocks_decoded += 4;
|
||||
#endif
|
||||
|
||||
ScheduleBlockCopyOut(TICKS_PER_BLOCK * 6);
|
||||
return true;
|
||||
@ -1128,7 +1160,9 @@ void MDEC::DrawDebugStateWindow(float scale)
|
||||
static constexpr std::array<const char*, 4> output_depths = {{"4-bit", "8-bit", "24-bit", "15-bit"}};
|
||||
static constexpr std::array<const char*, 7> block_names = {{"Crblk", "Cbblk", "Y1", "Y2", "Y3", "Y4", "Output"}};
|
||||
|
||||
#if defined(_DEBUG) || defined(_DEVEL)
|
||||
ImGui::Text("Blocks Decoded: %u", s_state.total_blocks_decoded);
|
||||
#endif
|
||||
ImGui::Text("Data-In FIFO Size: %u (%u bytes)", s_state.data_in_fifo.GetSize(), s_state.data_in_fifo.GetSize() * 4);
|
||||
ImGui::Text("Data-Out FIFO Size: %u (%u bytes)", s_state.data_out_fifo.GetSize(),
|
||||
s_state.data_out_fifo.GetSize() * 4);
|
||||
|
@ -14,6 +14,9 @@ void Shutdown();
|
||||
void Reset();
|
||||
bool DoState(StateWrapper& sw);
|
||||
|
||||
bool IsActive();
|
||||
void EndFrame();
|
||||
|
||||
// I/O
|
||||
u32 ReadRegister(u32 offset);
|
||||
void WriteRegister(u32 offset, u32 value);
|
||||
|
@ -371,6 +371,7 @@ void Settings::Load(const SettingsInterface& si, const SettingsInterface& contro
|
||||
std::max(si.GetUIntValue("CDROM", "MaxSeekSpeedupCycles", DEFAULT_CDROM_MAX_SEEK_SPEEDUP_CYCLES), 1u);
|
||||
cdrom_max_read_speedup_cycles =
|
||||
std::max(si.GetUIntValue("CDROM", "MaxReadSpeedupCycles", DEFAULT_CDROM_MAX_READ_SPEEDUP_CYCLES), 1u);
|
||||
mdec_disable_cdrom_speedup = si.GetBoolValue("CDROM", "DisableSpeedupOnMDEC", false);
|
||||
|
||||
audio_backend =
|
||||
AudioStream::ParseBackendName(
|
||||
@ -686,6 +687,7 @@ void Settings::Save(SettingsInterface& si, bool ignore_base) const
|
||||
si.SetUIntValue("CDROM", "SeekSpeedup", cdrom_seek_speedup);
|
||||
si.SetUIntValue("CDROM", "MaxReadSpeedupCycles", cdrom_max_seek_speedup_cycles);
|
||||
si.SetUIntValue("CDROM", "MaxSeekSpeedupCycles", cdrom_max_read_speedup_cycles);
|
||||
si.SetBoolValue("CDROM", "DisableSpeedupOnMDEC", mdec_disable_cdrom_speedup);
|
||||
|
||||
si.SetStringValue("Audio", "Backend", AudioStream::GetBackendName(audio_backend));
|
||||
si.SetStringValue("Audio", "Driver", audio_driver.c_str());
|
||||
|
@ -329,6 +329,7 @@ struct Settings : public GPUSettings
|
||||
bool audio_output_muted : 1 = false;
|
||||
|
||||
bool use_old_mdec_routines : 1 = false;
|
||||
bool mdec_disable_cdrom_speedup : 1 = false;
|
||||
bool pcdrv_enable : 1 = false;
|
||||
bool export_shared_memory : 1 = false;
|
||||
|
||||
|
@ -2089,6 +2089,8 @@ void System::FrameDone()
|
||||
// TODO: when running ahead, we can skip this (and the flush above)
|
||||
if (!IsReplayingGPUDump()) [[likely]]
|
||||
{
|
||||
MDEC::EndFrame();
|
||||
|
||||
SPU::GeneratePendingSamples();
|
||||
|
||||
Cheats::ApplyFrameEndCodes();
|
||||
|
@ -310,6 +310,8 @@ void AdvancedSettingsWidget::addTweakOptions()
|
||||
addIntRangeTweakOption(m_dialog, m_ui.tweakOptionTable, tr("CD-ROM Max Seek Speedup Cycles"), "CDROM",
|
||||
"MaxSeekSpeedupCycles", 1, 1000000, Settings::DEFAULT_CDROM_MAX_SEEK_SPEEDUP_CYCLES,
|
||||
tr(" cycles"));
|
||||
addBooleanTweakOption(m_dialog, m_ui.tweakOptionTable, tr("CD-ROM Disable Speedup on MDEC"), "CDROM",
|
||||
"DisableSpeedupOnMDEC", false);
|
||||
addBooleanTweakOption(m_dialog, m_ui.tweakOptionTable, tr("CD-ROM Region Check"), "CDROM", "RegionCheck", false);
|
||||
addBooleanTweakOption(m_dialog, m_ui.tweakOptionTable, tr("CD-ROM SubQ Skew"), "CDROM", "SubQSkew", false);
|
||||
addBooleanTweakOption(m_dialog, m_ui.tweakOptionTable, tr("Allow Booting Without SBI File"), "CDROM",
|
||||
@ -359,6 +361,7 @@ void AdvancedSettingsWidget::onResetToDefaultClicked()
|
||||
Settings::DEFAULT_CDROM_MAX_READ_SPEEDUP_CYCLES); // CD-ROM Max Speedup Read Cycles
|
||||
setIntRangeTweakOption(m_ui.tweakOptionTable, i++,
|
||||
Settings::DEFAULT_CDROM_MAX_SEEK_SPEEDUP_CYCLES); // CD-ROM Max Speedup Seek Cycles
|
||||
setBooleanTweakOption(m_ui.tweakOptionTable, i++, false); // CDROM Disable Speedup on MDEC
|
||||
setBooleanTweakOption(m_ui.tweakOptionTable, i++, false); // CDROM Region Check
|
||||
setBooleanTweakOption(m_ui.tweakOptionTable, i++, false); // CDROM SubQ Skew
|
||||
setBooleanTweakOption(m_ui.tweakOptionTable, i++, false); // Allow booting without SBI file
|
||||
@ -395,6 +398,7 @@ void AdvancedSettingsWidget::onResetToDefaultClicked()
|
||||
sif->DeleteValue("CDROM", "ReadaheadSectors");
|
||||
sif->DeleteValue("CDROM", "MaxReadSpeedupCycles");
|
||||
sif->DeleteValue("CDROM", "MaxSeekSpeedupCycles");
|
||||
sif->DeleteValue("CDROM", "DisableSpeedupOnMDEC");
|
||||
sif->DeleteValue("CDROM", "RegionCheck");
|
||||
sif->DeleteValue("CDROM", "SubQSkew");
|
||||
sif->DeleteValue("CDROM", "AllowBootingWithoutSBIFile");
|
||||
|
Loading…
x
Reference in New Issue
Block a user