Skip to content

Commit

Permalink
Misc code clean up and support for bob deinterlacing
Browse files Browse the repository at this point in the history
* Imagine: Clean up naming of some configuration macros
* Imagine: Update bundled libxcb, libX11 and clean up various makefiles
* Imagine: Fix various issues in Linux build for Pandora
* Imagine: Skip writing imagine config header if no variables are defined
* Imagine: Wrap pwritev() syscall if needed by platform
* Imagine: Tweak warning flags and add the system linker flags after library flags
* EmuFramework: Add flag in EmuVideo for offsetting output with bob deinterlacing
* EmuFramework: Add key binding to close content
* Saturn.emu & Snes9x: Add option to set deinterlace mode and default to bob deinterlacing
  • Loading branch information
Robert Broglia committed Feb 13, 2024
1 parent 342c0c1 commit 3b1cb19
Show file tree
Hide file tree
Showing 98 changed files with 443 additions and 247 deletions.
2 changes: 1 addition & 1 deletion EmuFramework/build.mk
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ pkgDescription := Emulator App Framework
pkgVersion := $(metadata_version)
LDLIBS := -l$(libName) $(LDLIBS)

CFLAGS_WARN += -Werror=implicit-fallthrough
CFLAGS_WARN += -Werror

include $(IMAGINE_PATH)/make/package/imagine.mk
include $(IMAGINE_PATH)/make/package/stdc++.mk
Expand Down
2 changes: 2 additions & 0 deletions EmuFramework/include/emuframework/AppKeyCode.hh
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,15 @@ enum class AppKeyCode : KeyCode
softReset,
hardReset,
resetMenu,
closeContent,
};

constexpr struct AppKeys
{
KeyInfo
openMenu = KeyInfo::appKey(AppKeyCode::openMenu),
openContent = KeyInfo::appKey(AppKeyCode::openContent),
closeContent = KeyInfo::appKey(AppKeyCode::closeContent),
openSystemActions = KeyInfo::appKey(AppKeyCode::openSystemActions),
saveState = KeyInfo::appKey(AppKeyCode::saveState),
loadState = KeyInfo::appKey(AppKeyCode::loadState),
Expand Down
2 changes: 2 additions & 0 deletions EmuFramework/include/emuframework/EmuApp.hh
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ namespace IG
class BluetoothAdapter;
class FileIO;
class BasicNavView;
class YesNoAlertView;
}

namespace EmuEx
Expand Down Expand Up @@ -252,6 +253,7 @@ public:
Gfx::TextureSpan asset(AssetDesc) const;
VController &defaultVController() { return inputManager.vController; }
static std::unique_ptr<View> makeView(ViewAttachParams, ViewID);
std::unique_ptr<YesNoAlertView> makeCloseContentView();
void applyOSNavStyle(IG::ApplicationContext, bool inGame);
void setCPUNeedsLowLatency(IG::ApplicationContext, bool needed);
bool advanceFrames(FrameParams, EmuSystemTask *);
Expand Down
6 changes: 6 additions & 0 deletions EmuFramework/include/emuframework/EmuSystem.hh
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include <imagine/audio/SampleFormat.hh>
#include <imagine/util/rectangle2.h>
#include <imagine/util/memory/DynArray.hh>
#include <imagine/util/enum.hh>
#include <emuframework/EmuTiming.hh>
#include <emuframework/VController.hh>
#include <emuframework/EmuInput.hh>
Expand Down Expand Up @@ -128,6 +129,11 @@ enum class VideoSystem: uint8_t
NATIVE_NTSC, PAL
};

WISE_ENUM_CLASS((DeinterlaceMode, uint8_t),
Bob,
Weave
);

using FrameTime = Nanoseconds;

constexpr const char *optionUserPathContentToken = ":CONTENT:";
Expand Down
4 changes: 4 additions & 0 deletions EmuFramework/include/emuframework/EmuVideo.hh
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ public:
IG::PixelFormat renderPixelFormat() const;
IG::PixelFormat internalRenderPixelFormat() const;
static Gfx::TextureSamplerConfig samplerConfigForLinearFilter(bool useLinearFilter);
static MutablePixmapView takeInterlacedFields(MutablePixmapView, bool isOddField);

protected:
Gfx::RendererTask *rTask{};
Expand All @@ -98,6 +99,9 @@ protected:
void doScreenshot(EmuSystemTaskContext, IG::PixmapView pix);
void postFrameFinished(EmuSystemTaskContext);
Gfx::TextureSamplerConfig samplerConfig() const { return samplerConfigForLinearFilter(useLinearFilter); }

public:
bool isOddField{};
};

}
2 changes: 1 addition & 1 deletion EmuFramework/include/emuframework/config.hh
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ namespace EmuEx
{

#if defined __ANDROID__ || \
defined CONFIG_BASE_IOS || \
defined CONFIG_OS_IOS || \
(defined CONFIG_BASE_X11 && !defined CONFIG_MACHINE_PANDORA)
#define CONFIG_VCONTROLS_GAMEPAD
constexpr bool VCONTROLS_GAMEPAD = true;
Expand Down
1 change: 1 addition & 0 deletions EmuFramework/linux-armv7-pandora-release.mk
2 changes: 1 addition & 1 deletion EmuFramework/src/ConfigFile.cc
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ EmuApp::ConfigParams EmuApp::loadConfigFile(IG::ApplicationContext ctx)
FS::rename(oldConfigFilePath, configFilePath);
}
}
#ifdef CONFIG_BASE_IOS
#ifdef CONFIG_OS_IOS
if(ctx.isSystemApp())
{
const char *oldConfigDir = "/User/Library/Preferences/explusalpha.com";
Expand Down
21 changes: 21 additions & 0 deletions EmuFramework/src/EmuApp.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1208,6 +1208,20 @@ FS::PathString EmuApp::validSearchPath(const FS::PathString &path) const
return nullptr;
}

std::unique_ptr<YesNoAlertView> EmuApp::makeCloseContentView()
{
return std::make_unique<YesNoAlertView>(attachParams(), "Really close current content?",
YesNoAlertView::Delegates
{
.onYes = [this]
{
closeSystem(); // pops any System Actions views in the stack
viewController().popModalViews();
return false;
}
});
}

bool EmuApp::handleKeyInput(KeyInfo keyInfo, const Input::Event &srcEvent)
{
if(!keyInfo.flags.appCode)
Expand Down Expand Up @@ -1246,6 +1260,13 @@ bool EmuApp::handleAppActionKeyInput(InputAction action, const Input::Event &src
viewController().pushAndShow(FilePicker::forLoading(attachParams(), srcEvent), srcEvent, false);
return true;
}
case closeContent:
{
if(!isPushed)
break;
viewController().pushAndShowModal(makeCloseContentView(), srcEvent, false);
return true;
}
case openSystemActions:
{
if(!isPushed)
Expand Down
1 change: 1 addition & 0 deletions EmuFramework/src/EmuInput.cc
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,7 @@ std::string_view toString(AppKeyCode code)
switch(code)
{
case AppKeyCode::openContent: return "Open Content";
case AppKeyCode::closeContent: return "Close Content";
case AppKeyCode::openSystemActions: return "Open System Actions";
case AppKeyCode::saveState: return "Save State";
case AppKeyCode::loadState: return "Load State";
Expand Down
2 changes: 1 addition & 1 deletion EmuFramework/src/EmuOptions.cc
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ constexpr SystemLogger log{"App"};

void EmuApp::initOptions(IG::ApplicationContext ctx)
{
#ifdef CONFIG_BASE_IOS
#ifdef CONFIG_OS_IOS
if(ctx.deviceIsIPad())
defaultFontSize = 5000;
#endif
Expand Down
7 changes: 7 additions & 0 deletions EmuFramework/src/EmuVideo.cc
Original file line number Diff line number Diff line change
Expand Up @@ -334,4 +334,11 @@ Gfx::TextureSamplerConfig EmuVideo::samplerConfigForLinearFilter(bool useLinearF
return useLinearFilter ? Gfx::SamplerConfigs::noMipClamp : Gfx::SamplerConfigs::noLinearNoMipClamp;
}

MutablePixmapView EmuVideo::takeInterlacedFields(MutablePixmapView pix, bool isOddField)
{
// Take half the image on the Y axis and double the pitch to isolate the even/odd fields
WSize size = {pix.w(), pix.h() / 2};
return {pix.desc().makeNewSize(size), pix.data({0, isOddField}), {pix.pitchBytes() * 2, PixmapUnits::BYTE}};
}

}
9 changes: 8 additions & 1 deletion EmuFramework/src/EmuVideoLayer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include <imagine/gfx/Renderer.hh>
#include <imagine/gfx/RendererCommands.hh>
#include <imagine/gfx/Vec3.hh>
#include <imagine/gfx/Mat4.hh>
#include <imagine/glm/common.hpp>
#include <imagine/glm/gtc/color_space.hpp>
#include <imagine/logger/logger.h>
Expand Down Expand Up @@ -176,7 +177,13 @@ void EmuVideoLayer::draw(Gfx::RendererCommands &cmds)
}
if(srgbOutput)
cmds.setSrgbFramebufferWrite(true);
cmds.basicEffect().drawSprite(cmds, quad, 0, texture);
auto &basicEffect = cmds.basicEffect();
if(video.isOddField) // shift image by half a line to reduce interlace flicker
{
float fieldOffset = (contentRect_.size().y / float(video.size().y)) / 2.f;
basicEffect.setModelView(cmds, Mat4::makeTranslate({0, fieldOffset, 0}));
}
basicEffect.drawSprite(cmds, quad, 0, texture);
vidImgOverlay.draw(cmds, c);
if(srgbOutput)
cmds.setSrgbFramebufferWrite(false);
Expand Down
6 changes: 1 addition & 5 deletions EmuFramework/src/gui/SystemActionsView.cc
Original file line number Diff line number Diff line change
Expand Up @@ -195,11 +195,7 @@ SystemActionsView::SystemActionsView(ViewAttachParams attach, bool customMenu):
"Close Content", attach,
[this](const Input::Event &e)
{
pushAndShowModal(makeView<YesNoAlertView>("Really close current content?",
YesNoAlertView::Delegates
{
.onYes = [this] { app().closeSystem(); return false; } // pops any System Actions views in the stack
}), e);
pushAndShowModal(app().makeCloseContentView(), e);
}
}
{
Expand Down
3 changes: 2 additions & 1 deletion EmuFramework/src/vcontrols/VController.cc
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ VController::VController(IG::ApplicationContext ctx):
alphaF{defaultAlpha / 255.},
defaultButtonSize
{
#ifdef CONFIG_BASE_IOS
#ifdef CONFIG_OS_IOS
int16_t(ctx.deviceIsIPad() ? 1400 : 850)
#else
850
Expand Down Expand Up @@ -85,6 +85,7 @@ static void updateTexture(const EmuApp &app, VControllerElement &e, Gfx::Rendere
{
case openMenu: return app.asset(AssetID::more);
case openContent: return app.asset(AssetID::openFile);
case closeContent: return app.asset(AssetID::close);
case saveState: return app.asset(AssetID::save);
case loadState: return app.asset(AssetID::load);
case decStateSlot: return app.asset(AssetID::leftSwitch);
Expand Down
23 changes: 22 additions & 1 deletion Saturn.emu/src/main/EmuMenuViews.cc
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,26 @@ class ConsoleOptionView : public TableView, public MainAppHelper<ConsoleOptionVi
}
};

TextMenuItem deinterlaceModeItems[2]
{
{"Bob", attachParams(), {.id = DeinterlaceMode::Bob}},
{"Weave", attachParams(), {.id = DeinterlaceMode::Weave}},
};

MultiChoiceMenuItem deinterlaceMode
{
"Deinterlace Mode", attachParams(),
MenuId{system().deinterlaceMode},
deinterlaceModeItems,
{
.defaultItemOnSelect = [this](TextMenuItem &item)
{
system().sessionOptionSet();
system().deinterlaceMode = DeinterlaceMode(item.id.val);
}
}
};

TextMenuItem contentRotationItems[5]
{
{"Auto", attachParams(), {.id = Rotation::ANY}},
Expand Down Expand Up @@ -457,6 +477,7 @@ class ConsoleOptionView : public TableView, public MainAppHelper<ConsoleOptionVi
menuItems.emplace_back(&videoHeading);
menuItems.emplace_back(&showHOverscan);
menuItems.emplace_back(&visibleVideoLines);
menuItems.emplace_back(&deinterlaceMode);
menuItems.emplace_back(&contentRotation);
menuItems.emplace_back(&inputHeading);
menuItems.emplace_back(&multitaps[0]);
Expand Down Expand Up @@ -561,7 +582,7 @@ class CustomVideoOptionView : public VideoOptionView, public MainAppHelper<Custo
{
.defaultItemOnSelect = [this](TextMenuItem &item)
{
system().defaultNtscLines = std::bit_cast<VideoLineRange>(item.id);
system().defaultNtscLines = std::bit_cast<VideoLineRange>(item.id.val);
}
}
};
Expand Down
17 changes: 12 additions & 5 deletions Saturn.emu/src/main/Main.cc
Original file line number Diff line number Diff line change
Expand Up @@ -397,6 +397,7 @@ void SaturnSystem::updateVideoSettings()

void SaturnSystem::renderFramebuffer(EmuVideo &video)
{
espec.taskCtx = {};
espec.video = &video;
int32 lineWidths[2]{video.size().x};
espec.LineWidths = lineWidths;
Expand Down Expand Up @@ -444,12 +445,18 @@ void MDFN_MidSync(EmulateSpecStruct *espec, const unsigned flags)

void MDFND_commitVideoFrame(EmulateSpecStruct *espec)
{
auto &sys = static_cast<EmuEx::SaturnSystem&>(*espec->sys);
auto &sys = static_cast<const EmuEx::SaturnSystem&>(*espec->sys);
int width = std::max(espec->LineWidths[0], espec->LineWidths[1]);
IG::PixmapView srcPix = sys.mSurfacePix.subView(
{espec->DisplayRect.x, espec->DisplayRect.y},
{width, espec->DisplayRect.h});
espec->video->startFrameWithFormat(espec->taskCtx, srcPix);
auto &video = *espec->video;
video.isOddField = false;
auto srcPix = sys.mSurfacePix.subView({espec->DisplayRect.x, espec->DisplayRect.y}, {width, espec->DisplayRect.h});
if(MDFN_IEN_SS::VDP2::InterlaceMode && sys.deinterlaceMode == EmuEx::DeinterlaceMode::Bob)
{
bool isOddField = espec->LineWidths[1];
video.isOddField = isOddField;
srcPix = video.takeInterlacedFields(srcPix, isOddField);
}
video.startFrameWithFormat(espec->taskCtx, srcPix);
}

void MDFN_MediaStateAction(StateMem *sm, const unsigned load, const bool data_only)
Expand Down
2 changes: 2 additions & 0 deletions Saturn.emu/src/main/MainSystem.hh
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ enum
CFGKEY_VIDEO_LINES = 285, CFGKEY_CORRECT_LINE_ASPECT = 286,
CFGKEY_DEFAULT_NTSC_VIDEO_LINES = 287, CFGKEY_DEFAULT_PAL_VIDEO_LINES = 288,
CFGKEY_DEFAULT_SHOW_H_OVERSCAN = 289, CFGKEY_SHOW_H_OVERSCAN = 290,
CFGKEY_DEINTERLACE_MODE = 291,
};

struct VideoLineRange
Expand Down Expand Up @@ -120,6 +121,7 @@ public:
int8_t region{};
int8_t biosLanguage{MDFN_IEN_SS::SMPC_RTC_LANG_ENGLISH};
InputConfig inputConfig{};
DeinterlaceMode deinterlaceMode{DeinterlaceMode::Bob};
bool defaultShowHOverscan{};
bool showHOverscan{};
bool correctLineAspect{};
Expand Down
5 changes: 4 additions & 1 deletion Saturn.emu/src/main/options.cc
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ bool SaturnSystem::resetSessionOptions(EmuApp &app)
sysContentRotation = Rotation::ANY;
videoLines = {};
showHOverscan = defaultShowHOverscan;
deinterlaceMode = DeinterlaceMode::Bob;
onSessionOptionsLoaded(app);
return true;
}
Expand Down Expand Up @@ -88,6 +89,7 @@ bool SaturnSystem::readConfig(ConfigType type, MapIO &io, unsigned key, size_t r
case CFGKEY_SYSTEM_CONTENT_ROTATION: return readOptionValue(io, readSize, sysContentRotation);
case CFGKEY_VIDEO_LINES: return readOptionValue(io, readSize, videoLines);
case CFGKEY_SHOW_H_OVERSCAN: return readOptionValue(io, readSize, showHOverscan);
case CFGKEY_DEINTERLACE_MODE: return readOptionValue(io, readSize, deinterlaceMode);
}
}
return false;
Expand All @@ -105,7 +107,7 @@ void SaturnSystem::writeConfig(ConfigType type, FileIO &io)
writeOptionValueIfNotDefault(io, CFGKEY_AUTO_RTC_TIME, autoRTCTime, true);
writeOptionValueIfNotDefault(io, CFGKEY_DEFAULT_NTSC_VIDEO_LINES, defaultNtscLines, safeNtscLines);
writeOptionValueIfNotDefault(io, CFGKEY_DEFAULT_PAL_VIDEO_LINES, defaultPalLines, safePalLines);
writeOptionValueIfNotDefault(io, CFGKEY_DEFAULT_SHOW_H_OVERSCAN, defaultShowHOverscan, false);;
writeOptionValueIfNotDefault(io, CFGKEY_DEFAULT_SHOW_H_OVERSCAN, defaultShowHOverscan, false);
}
else if(type == ConfigType::SESSION)
{
Expand All @@ -115,6 +117,7 @@ void SaturnSystem::writeConfig(ConfigType type, FileIO &io)
writeOptionValueIfNotDefault(io, CFGKEY_SYSTEM_CONTENT_ROTATION, sysContentRotation, Rotation::ANY);
writeOptionValueIfNotDefault(io, CFGKEY_VIDEO_LINES, videoLines, MDFN_IEN_SS::VDP2::PAL ? defaultPalLines : defaultNtscLines);
writeOptionValueIfNotDefault(io, CFGKEY_SHOW_H_OVERSCAN, showHOverscan, defaultShowHOverscan);
writeOptionValueIfNotDefault(io, CFGKEY_DEINTERLACE_MODE, deinterlaceMode, DeinterlaceMode::Bob);
}
}

Expand Down
1 change: 1 addition & 0 deletions Snes9x/res/pandora/gpOverlay.png
23 changes: 22 additions & 1 deletion Snes9x/src/main/EmuMenuViews.cc
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,26 @@ class ConsoleOptionView : public TableView, public MainAppHelper<ConsoleOptionVi
}
};

TextMenuItem deinterlaceModeItems[2]
{
{"Bob", attachParams(), {.id = DeinterlaceMode::Bob}},
{"Weave", attachParams(), {.id = DeinterlaceMode::Weave}},
};

MultiChoiceMenuItem deinterlaceMode
{
"Deinterlace Mode", attachParams(),
MenuId{system().deinterlaceMode},
deinterlaceModeItems,
{
.defaultItemOnSelect = [this](TextMenuItem &item)
{
system().sessionOptionSet();
system().deinterlaceMode = DeinterlaceMode(item.id.val);
}
}
};

#ifndef SNES9X_VERSION_1_4
TextHeadingMenuItem emulationHacks{"Emulation Hacks", attachParams()};

Expand Down Expand Up @@ -218,13 +238,14 @@ class ConsoleOptionView : public TableView, public MainAppHelper<ConsoleOptionVi
};
#endif

std::array<MenuItem*, IS_SNES9X_VERSION_1_4 ? 5 : 9> menuItem
std::array<MenuItem*, IS_SNES9X_VERSION_1_4 ? 6 : 10> menuItem
{
&inputPorts,
&multitap,
&videoHeading,
&videoSystem,
&allowExtendedLines,
&deinterlaceMode,
#ifndef SNES9X_VERSION_1_4
&emulationHacks,
&blockInvalidVRAMAccess,
Expand Down
Loading

0 comments on commit 3b1cb19

Please sign in to comment.