Introduce SDL Frame.

This commit is contained in:
Andrea Odetti 2021-01-10 11:47:44 +00:00
parent 4e357b59bd
commit 8a41ed4d73
11 changed files with 224 additions and 137 deletions

View file

@ -60,13 +60,13 @@ set(SOURCE_FILES
linux/registry.cpp
linux/keyboard.cpp
linux/linuxframe.cpp
linux/context.cpp
linux/duplicates/Debug.cpp
linux/duplicates/Joystick.cpp
linux/duplicates/SerialComms.cpp
linux/duplicates/PropertySheet.cpp
linux/duplicates/Tfe.cpp
linux/duplicates/AppleWin.cpp
Z80VICE/z80.cpp
Z80VICE/z80mem.cpp

View file

@ -7,6 +7,7 @@ set(SOURCE_FILES
gamepad.cpp
sdirectsound.cpp
utils.cpp
sdlframe.cpp
)
set(HEADER_FILES
@ -14,6 +15,7 @@ set(HEADER_FILES
gamepad.h
sdirectsound.h
utils.h
sdlframe.h
)
add_executable(sa2

View file

@ -1,13 +1,15 @@
#include "StdAfx.h"
#include "frontends/sdl/emulator.h"
#include "frontends/sdl/sdirectsound.h"
#include "frontends/sdl/utils.h"
#include "frontends/sdl/sdlframe.h"
#include <iostream>
#include "linux/paddle.h"
#include "linux/keyboard.h"
#include "StdAfx.h"
#include "Common.h"
#include "Interface.h"
#include "CardManager.h"
@ -27,38 +29,6 @@
namespace
{
void updateWindowTitle(const std::shared_ptr<SDL_Window> & win)
{
GetAppleWindowTitle();
SDL_SetWindowTitle(win.get(), g_pAppTitle.c_str());
}
void cycleVideoType(const std::shared_ptr<SDL_Window> & win)
{
Video & video = GetVideo();
video.IncVideoType();
video.VideoReinitialize(false);
video.Config_Save_Video();
updateWindowTitle(win);
}
void cycle50ScanLines(const std::shared_ptr<SDL_Window> & win)
{
Video & video = GetVideo();
VideoStyle_e videoStyle = video.GetVideoStyle();
videoStyle = VideoStyle_e(videoStyle ^ VS_HALF_SCANLINES);
video.SetVideoStyle(videoStyle);
video.VideoReinitialize(false);
video.Config_Save_Video();
updateWindowTitle(win);
}
void processAppleKey(const SDL_KeyboardEvent & key)
{
// using keycode (or scan code) one takes a physical view of the keyboard
@ -141,27 +111,14 @@ namespace
Emulator::Emulator(
const std::shared_ptr<SDL_Window> & window,
const std::shared_ptr<SDL_Renderer> & renderer,
const std::shared_ptr<SDL_Texture> & texture,
const std::shared_ptr<SDLFrame> & frame,
const bool fixedSpeed
)
: myWindow(window)
, myRenderer(renderer)
, myTexture(texture)
: myFrame(frame)
, myMultiplier(1)
, myFullscreen(false)
, mySpeed(fixedSpeed)
{
Video & video = GetVideo();
myRect.x = video.GetFrameBufferBorderWidth();
myRect.y = video.GetFrameBufferBorderHeight();
myRect.w = video.GetFrameBufferBorderlessWidth();
myRect.h = video.GetFrameBufferBorderlessHeight();
myPitch = video.GetFrameBufferWidth() * sizeof(bgra_t);
myFrameBuffer = video.GetFrameBuffer();
}
void Emulator::execute(const size_t next)
@ -182,17 +139,6 @@ void Emulator::execute(const size_t next)
}
}
void Emulator::updateTexture()
{
SDL_UpdateTexture(myTexture.get(), nullptr, myFrameBuffer, myPitch);
}
void Emulator::refreshVideo()
{
SDL_RenderCopyEx(myRenderer.get(), myTexture.get(), &myRect, nullptr, 0.0, nullptr, SDL_FLIP_VERTICAL);
SDL_RenderPresent(myRenderer.get());
}
void Emulator::processEvents(bool & quit)
{
SDL_Event e;
@ -232,6 +178,7 @@ void Emulator::processKeyDown(const SDL_KeyboardEvent & key, bool & quit)
// if the user has decided to change the layout, we just go with it and use the keycode
if (!key.repeat)
{
const std::shared_ptr<SDL_Window> & window = myFrame->GetWindow();
switch (key.keysym.sym)
{
case SDLK_F12:
@ -245,7 +192,7 @@ void Emulator::processKeyDown(const SDL_KeyboardEvent & key, bool & quit)
const std::string & pathname = Snapshot_GetPathname();
const std::string message = "Do you want to save the state to " + pathname + "?";
SoundCore_SetFade(FADE_OUT);
if (show_yes_no_dialog(myWindow, "Save state", message))
if (show_yes_no_dialog(window, "Save state", message))
{
Snapshot_SaveState();
}
@ -255,14 +202,14 @@ void Emulator::processKeyDown(const SDL_KeyboardEvent & key, bool & quit)
}
case SDLK_F9:
{
cycleVideoType(myWindow);
myFrame->CycleVideoType();
break;
}
case SDLK_F6:
{
if ((key.keysym.mod & KMOD_CTRL) && (key.keysym.mod & KMOD_SHIFT))
{
cycle50ScanLines(myWindow);
myFrame->Cycle50ScanLines();
}
else if (key.keysym.mod & KMOD_CTRL)
{
@ -270,12 +217,12 @@ void Emulator::processKeyDown(const SDL_KeyboardEvent & key, bool & quit)
myMultiplier = myMultiplier == 1 ? 2 : 1;
const int sw = video.GetFrameBufferBorderlessWidth();
const int sh = video.GetFrameBufferBorderlessHeight();
SDL_SetWindowSize(myWindow.get(), sw * myMultiplier, sh * myMultiplier);
SDL_SetWindowSize(window.get(), sw * myMultiplier, sh * myMultiplier);
}
else if (!(key.keysym.mod & KMOD_SHIFT))
{
myFullscreen = !myFullscreen;
SDL_SetWindowFullscreen(myWindow.get(), myFullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
SDL_SetWindowFullscreen(window.get(), myFullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
}
break;
}
@ -329,7 +276,7 @@ void Emulator::processKeyDown(const SDL_KeyboardEvent & key, bool & quit)
mySpeed.reset();
break;
}
updateWindowTitle(myWindow);
GetFrame().FrameRefreshStatus(DRAW_TITLE);
break;
}
}

View file

@ -5,21 +5,18 @@
#include "frontends/common2/speed.h"
class SDLFrame;
class Emulator
{
public:
Emulator(
const std::shared_ptr<SDL_Window> & window,
const std::shared_ptr<SDL_Renderer> & renderer,
const std::shared_ptr<SDL_Texture> & texture,
const std::shared_ptr<SDLFrame> & frame,
const bool fixedSpeed
);
void execute(const size_t milliseconds);
void updateTexture();
void refreshVideo();
void processEvents(bool & quit);
private:
@ -27,16 +24,10 @@ private:
void processKeyUp(const SDL_KeyboardEvent & key);
void processText(const SDL_TextInputEvent & text);
const std::shared_ptr<SDL_Window> myWindow;
const std::shared_ptr<SDL_Renderer> myRenderer;
const std::shared_ptr<SDL_Texture> myTexture;
const std::shared_ptr<SDLFrame> myFrame;
int myMultiplier;
bool myFullscreen;
Speed mySpeed;
SDL_Rect myRect;
int myPitch;
uint8_t* myFrameBuffer;
};

View file

@ -1,11 +1,11 @@
#include <iostream>
#include <SDL.h>
#include <SDL_image.h>
#include <iostream>
#include <memory>
#include <iomanip>
#include "linux/interface.h"
#include "linux/benchmark.h"
#include "linux/context.h"
#include "frontends/common2/fileregistry.h"
#include "frontends/common2/utils.h"
@ -16,6 +16,7 @@
#include "frontends/sdl/gamepad.h"
#include "frontends/sdl/sdirectsound.h"
#include "frontends/sdl/utils.h"
#include "frontends/sdl/sdlframe.h"
#include "StdAfx.h"
#include "Core.h"
@ -30,6 +31,7 @@
namespace
{
int getRefreshRate()
{
SDL_DisplayMode current;
@ -64,16 +66,6 @@ namespace
return interval;
}
void setApplicationIcon(const std::shared_ptr<SDL_Window> & win)
{
const std::string path = getResourcePath() + "APPLEWIN.ICO";
std::shared_ptr<SDL_Surface> icon(IMG_Load(path.c_str()), SDL_FreeSurface);
if (icon)
{
SDL_SetWindowIcon(win.get(), icon.get());
}
}
}
int MessageBox(HWND, const char * text, const char * caption, UINT type)
@ -94,6 +86,9 @@ void run_sdl(int argc, const char * argv [])
if (!run)
return;
const std::shared_ptr<SDLFrame> frame(new SDLFrame(options));
SetFrame(frame);
if (options.log)
{
LogInit();
@ -110,38 +105,10 @@ void run_sdl(int argc, const char * argv [])
Video & video = GetVideo();
const int width = video.GetFrameBufferWidth();
const int height = video.GetFrameBufferHeight();
const int sw = video.GetFrameBufferBorderlessWidth();
const int sh = video.GetFrameBufferBorderlessHeight();
std::cerr << std::fixed << std::setprecision(2);
std::shared_ptr<SDL_Window> win(SDL_CreateWindow(g_pAppTitle.c_str(), SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, sw, sh, SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE), SDL_DestroyWindow);
if (!win)
{
std::cerr << "SDL_CreateWindow Error: " << SDL_GetError() << std::endl;
return;
}
setApplicationIcon(win);
std::shared_ptr<SDL_Renderer> ren(SDL_CreateRenderer(win.get(), options.sdlDriver, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC), SDL_DestroyRenderer);
if (!ren)
{
std::cout << "SDL_CreateRenderer Error: " << SDL_GetError() << std::endl;
return;
}
const Uint32 format = SDL_PIXELFORMAT_ARGB8888;
printRendererInfo(std::cerr, ren, format, options.sdlDriver);
std::shared_ptr<SDL_Texture> tex(SDL_CreateTexture(ren.get(), format, SDL_TEXTUREACCESS_STATIC, width, height), SDL_DestroyTexture);
const int fps = getRefreshRate();
std::cerr << "Video refresh rate: " << fps << " Hz, " << 1000.0 / fps << " ms" << std::endl;
Emulator emulator(win, ren, tex, options.fixedSpeed);
Emulator emulator(frame, options.fixedSpeed);
#ifdef EMULATOR_RUN
if (options.benchmark)
@ -151,10 +118,10 @@ void run_sdl(int argc, const char * argv [])
const int res = SDL_GL_SetSwapInterval(0);
// if this fails, should we throw, print something or just ignore?
const auto redraw = [&emulator, res]{
emulator.updateTexture();
const auto redraw = [&frame, res]{
frame->UpdateTexture();
if (res == 0) {
emulator.refreshVideo();
frame->RenderPresent();
}
};
@ -221,7 +188,7 @@ void run_sdl(int argc, const char * argv [])
}
updateTextureTimer.tic();
emulator.updateTexture();
frame->UpdateTexture();
updateTextureTimer.toc();
if (!options.looseMutex)
@ -234,7 +201,7 @@ void run_sdl(int argc, const char * argv [])
if (!options.headless)
{
refreshScreenTimer.tic();
emulator.refreshVideo();
frame->RenderPresent();
refreshScreenTimer.toc();
}
@ -270,13 +237,13 @@ void run_sdl(int argc, const char * argv [])
cpuTimer.toc();
updateTextureTimer.tic();
emulator.updateTexture();
frame->UpdateTexture();
updateTextureTimer.toc();
if (!options.headless)
{
refreshScreenTimer.tic();
emulator.refreshVideo();
frame->RenderPresent();
refreshScreenTimer.toc();
}
} while (!quit);
@ -324,9 +291,9 @@ int main(int argc, const char * argv [])
std::cerr << e.what() << std::endl;
}
// this must happen BEFORE the SDL_Quit() as otherwise we have a double free (of the game controller).
Paddle::instance.reset();
SetFrame(std::shared_ptr<FrameBase>());
SDL_Quit();
return exit;

View file

@ -0,0 +1,94 @@
#include "StdAfx.h"
#include "frontends/sdl/sdlframe.h"
#include "frontends/sdl/utils.h"
#include "frontends/common2/programoptions.h"
#include "frontends/common2/resources.h"
#include "Interface.h"
#include "Core.h"
#include "Utilities.h"
#include <iostream>
#include <iomanip>
#include <SDL_image.h>
SDLFrame::SDLFrame(const EmulatorOptions & options)
{
Video & video = GetVideo();
const int width = video.GetFrameBufferWidth();
const int height = video.GetFrameBufferHeight();
const int sw = video.GetFrameBufferBorderlessWidth();
const int sh = video.GetFrameBufferBorderlessHeight();
std::cerr << std::fixed << std::setprecision(2);
myWindow.reset(SDL_CreateWindow(g_pAppTitle.c_str(), SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, sw, sh, SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE), SDL_DestroyWindow);
if (!myWindow)
{
std::cerr << "SDL_CreateWindow Error: " << SDL_GetError() << std::endl;
return;
}
SetApplicationIcon();
myRenderer.reset(SDL_CreateRenderer(myWindow.get(), options.sdlDriver, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC), SDL_DestroyRenderer);
if (!myRenderer)
{
std::cout << "SDL_CreateRenderer Error: " << SDL_GetError() << std::endl;
return;
}
const Uint32 format = SDL_PIXELFORMAT_ARGB8888;
printRendererInfo(std::cerr, myRenderer, format, options.sdlDriver);
myTexture.reset(SDL_CreateTexture(myRenderer.get(), format, SDL_TEXTUREACCESS_STATIC, width, height), SDL_DestroyTexture);
myRect.x = video.GetFrameBufferBorderWidth();
myRect.y = video.GetFrameBufferBorderHeight();
myRect.w = video.GetFrameBufferBorderlessWidth();
myRect.h = video.GetFrameBufferBorderlessHeight();
myPitch = video.GetFrameBufferWidth() * sizeof(bgra_t);
}
void SDLFrame::FrameRefreshStatus(int drawflags)
{
if (drawflags & DRAW_TITLE)
{
GetAppleWindowTitle();
SDL_SetWindowTitle(myWindow.get(), g_pAppTitle.c_str());
}
}
void SDLFrame::SetApplicationIcon()
{
const std::string path = getResourcePath() + "APPLEWIN.ICO";
std::shared_ptr<SDL_Surface> icon(IMG_Load(path.c_str()), SDL_FreeSurface);
if (icon)
{
SDL_SetWindowIcon(myWindow.get(), icon.get());
}
}
void SDLFrame::UpdateTexture()
{
SDL_UpdateTexture(myTexture.get(), nullptr, myFramebuffer.data(), myPitch);
}
void SDLFrame::RenderPresent()
{
SDL_RenderCopyEx(myRenderer.get(), myTexture.get(), &myRect, nullptr, 0.0, nullptr, SDL_FLIP_VERTICAL);
SDL_RenderPresent(myRenderer.get());
}
void SDLFrame::VideoPresentScreen()
{
UpdateTexture();
RenderPresent();
}
const std::shared_ptr<SDL_Window> & SDLFrame::GetWindow() const
{
return myWindow;
}

View file

@ -0,0 +1,30 @@
#pragma once
#include "linux/linuxframe.h"
#include <SDL.h>
class EmulatorOptions;
class SDLFrame : public LinuxFrame
{
public:
SDLFrame(const EmulatorOptions & options);
virtual void VideoPresentScreen();
virtual void FrameRefreshStatus(int drawflags);
void UpdateTexture();
void RenderPresent();
const std::shared_ptr<SDL_Window> & GetWindow() const;
private:
void SetApplicationIcon();
SDL_Rect myRect;
int myPitch;
std::shared_ptr<SDL_Window> myWindow;
std::shared_ptr<SDL_Renderer> myRenderer;
std::shared_ptr<SDL_Texture> myTexture;
};

View file

@ -1,9 +1,16 @@
#include "StdAfx.h"
#include "linux/context.h"
#include "Interface.h"
#include "linux/duplicates/PropertySheet.h"
#include "linux/linuxframe.h"
namespace
{
std::shared_ptr<FrameBase> sg_LinuxFrame;
}
IPropertySheet& GetPropertySheet()
{
static CPropertySheet sg_PropertySheet;
@ -12,8 +19,12 @@ IPropertySheet& GetPropertySheet()
FrameBase& GetFrame()
{
static LinuxFrame sg_LinuxFrame;
return sg_LinuxFrame;
return *sg_LinuxFrame;
}
void SetFrame(const std::shared_ptr<FrameBase> & frame)
{
sg_LinuxFrame = frame;
}
Video& GetVideo()

7
source/linux/context.h Normal file
View file

@ -0,0 +1,7 @@
#pragma once
#include <memory>
class FrameBase;
void SetFrame(const std::shared_ptr<FrameBase> & frame);

View file

@ -10,7 +10,7 @@ void LinuxFrame::FrameDrawDiskStatus()
{
}
void LinuxFrame::FrameRefreshStatus(int drawflags)
void LinuxFrame::FrameRefreshStatus(int /* drawflags */)
{
}
@ -51,13 +51,13 @@ void LinuxFrame::Initialize()
const size_t numberOfPixels = video.GetFrameBufferWidth() * video.GetFrameBufferHeight();
const size_t numberOfBytes = sizeof(bgra_t) * numberOfPixels;
myFramebufferbits.resize(numberOfBytes);
video.Initialize(myFramebufferbits.data());
myFramebuffer.resize(numberOfBytes);
video.Initialize(myFramebuffer.data());
}
void LinuxFrame::Destroy()
{
myFramebufferbits.clear();
myFramebuffer.clear();
GetVideo().Destroy(); // this resets the Video's FrameBuffer pointer
}
@ -76,3 +76,36 @@ void LinuxFrame::Benchmark()
void LinuxFrame::DisplayLogo()
{
}
void LinuxFrame::ApplyVideoModeChange()
{
// this is similar to Win32Frame::ApplyVideoModeChange
// but it does not refresh the screen
// TODO see if the screen should refresh right now
Video & video = GetVideo();
video.VideoReinitialize(false);
video.Config_Save_Video();
FrameRefreshStatus(DRAW_TITLE);
}
void LinuxFrame::CycleVideoType()
{
Video & video = GetVideo();
video.IncVideoType();
ApplyVideoModeChange();
}
void LinuxFrame::Cycle50ScanLines()
{
Video & video = GetVideo();
VideoStyle_e videoStyle = video.GetVideoStyle();
videoStyle = VideoStyle_e(videoStyle ^ VS_HALF_SCANLINES);
video.SetVideoStyle(videoStyle);
ApplyVideoModeChange();
}

View file

@ -28,6 +28,11 @@ public:
virtual void Benchmark();
virtual void DisplayLogo();
private:
std::vector<uint8_t> myFramebufferbits;
void CycleVideoType();
void Cycle50ScanLines();
protected:
void ApplyVideoModeChange();
std::vector<uint8_t> myFramebuffer;
};