Fairly huge refactoring of FrameBuffer class into FBBackend and friends.

Only tested in Linux and libretro for now; Windows and Mac will follow soon.
This commit is contained in:
Stephen Anthony 2020-10-23 10:27:06 -02:30
parent d0448a431e
commit b6d18845d8
31 changed files with 734 additions and 747 deletions

View File

@ -27,11 +27,11 @@
#include "ThreadDebugging.hxx"
#include "FBSurfaceSDL2.hxx"
#include "FrameBufferSDL2.hxx"
#include "FBBackendSDL2.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FrameBufferSDL2::FrameBufferSDL2(OSystem& osystem)
: FrameBuffer(osystem)
FBBackendSDL2::FBBackendSDL2(OSystem& osystem)
: myOSystem(osystem)
{
ASSERT_MAIN_THREAD;
@ -43,7 +43,7 @@ FrameBufferSDL2::FrameBufferSDL2(OSystem& osystem)
Logger::error(buf.str());
throw runtime_error("FATAL ERROR");
}
Logger::debug("FrameBufferSDL2::FrameBufferSDL2 SDL_Init()");
Logger::debug("FBBackendSDL2::FBBackendSDL2 SDL_Init()");
// We need a pixel format for palette value calculations
// It's done this way (vs directly accessing a FBSurfaceSDL2 object)
@ -53,7 +53,7 @@ FrameBufferSDL2::FrameBufferSDL2(OSystem& osystem)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FrameBufferSDL2::~FrameBufferSDL2()
FBBackendSDL2::~FBBackendSDL2()
{
ASSERT_MAIN_THREAD;
@ -61,12 +61,6 @@ FrameBufferSDL2::~FrameBufferSDL2()
if(myRenderer)
{
// Make sure to free surfaces/textures before destroying the renderer itself
// Most platforms are fine with doing this in either order, but it seems
// that OpenBSD in particular crashes when attempting to destroy textures
// *after* the renderer is already destroyed
freeSurfaces();
SDL_DestroyRenderer(myRenderer);
myRenderer = nullptr;
}
@ -81,9 +75,9 @@ FrameBufferSDL2::~FrameBufferSDL2()
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FrameBufferSDL2::queryHardware(vector<Common::Size>& fullscreenRes,
vector<Common::Size>& windowedRes,
VariantList& renderers)
void FBBackendSDL2::queryHardware(vector<Common::Size>& fullscreenRes,
vector<Common::Size>& windowedRes,
VariantList& renderers)
{
ASSERT_MAIN_THREAD;
@ -105,7 +99,7 @@ void FrameBufferSDL2::queryHardware(vector<Common::Size>& fullscreenRes,
string lastRes = "";
for (int m = 0; m < numModes; m++)
for(int m = 0; m < numModes; ++m)
{
SDL_DisplayMode mode;
ostringstream res;
@ -196,7 +190,7 @@ void FrameBufferSDL2::queryHardware(vector<Common::Size>& fullscreenRes,
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool FrameBufferSDL2::isCurrentWindowPositioned() const
bool FBBackendSDL2::isCurrentWindowPositioned() const
{
ASSERT_MAIN_THREAD;
@ -205,7 +199,7 @@ bool FrameBufferSDL2::isCurrentWindowPositioned() const
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Common::Point FrameBufferSDL2::getCurrentWindowPos() const
Common::Point FBBackendSDL2::getCurrentWindowPos() const
{
ASSERT_MAIN_THREAD;
@ -217,7 +211,7 @@ Common::Point FrameBufferSDL2::getCurrentWindowPos() const
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Int32 FrameBufferSDL2::getCurrentDisplayIndex() const
Int32 FBBackendSDL2::getCurrentDisplayIndex() const
{
ASSERT_MAIN_THREAD;
@ -225,8 +219,8 @@ Int32 FrameBufferSDL2::getCurrentDisplayIndex() const
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool FrameBufferSDL2::activateVideoMode(const string& title,
const VideoModeHandler::Mode& mode)
bool FBBackendSDL2::setVideoMode(const VideoModeHandler::Mode& mode,
int winIdx, const Common::Point& winPos)
{
ASSERT_MAIN_THREAD;
@ -236,26 +230,22 @@ bool FrameBufferSDL2::activateVideoMode(const string& title,
const bool fullScreen = mode.fsIndex != -1;
bool forceCreateRenderer = false;
// Get windowed window's last display
Int32 displayIndex = std::min(myNumDisplays, myOSystem.settings().getInt(getDisplayKey()));
// Get windowed window's last position
myWindowedPos = myOSystem.settings().getPoint(getPositionKey());
Int32 displayIndex = std::min(myNumDisplays, winIdx);
int posX, posY;
myCenter = myOSystem.settings().getBool("center");
if (myCenter)
if(myCenter)
posX = posY = SDL_WINDOWPOS_CENTERED_DISPLAY(displayIndex);
else
{
posX = myWindowedPos.x;
posY = myWindowedPos.y;
posX = winPos.x;
posY = winPos.y;
// Make sure the window is at least partially visibile
int x0 = 0, y0 = 0, x1 = 0, y1 = 0;
for (int display = SDL_GetNumVideoDisplays() - 1; display >= 0; display--)
for(int display = SDL_GetNumVideoDisplays() - 1; display >= 0; --display)
{
SDL_Rect rect;
@ -273,16 +263,22 @@ bool FrameBufferSDL2::activateVideoMode(const string& title,
#ifdef ADAPTABLE_REFRESH_SUPPORT
SDL_DisplayMode adaptedSdlMode;
const bool shouldAdapt = fullScreen && myOSystem.settings().getBool("tia.fs_refresh")
&& gameRefreshRate()
const int gameRefreshRate =
myOSystem.hasConsole() ? myOSystem.console().gameRefreshRate() : 0;
const bool shouldAdapt = fullScreen
&& myOSystem.settings().getBool("tia.fs_refresh")
&& gameRefreshRate
// take care of 59.94 Hz
&& refreshRate() % gameRefreshRate() != 0 && refreshRate() % (gameRefreshRate() - 1) != 0;
const bool adaptRefresh = shouldAdapt && adaptRefreshRate(displayIndex, adaptedSdlMode);
&& refreshRate() % gameRefreshRate != 0
&& refreshRate() % (gameRefreshRate - 1) != 0;
const bool adaptRefresh = shouldAdapt &&
adaptRefreshRate(displayIndex, adaptedSdlMode);
#else
const bool adaptRefresh = false;
#endif
const uInt32 flags = SDL_WINDOW_ALLOW_HIGHDPI
| (fullScreen ? adaptRefresh ? SDL_WINDOW_FULLSCREEN : SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
| (fullScreen ? adaptRefresh ? SDL_WINDOW_FULLSCREEN :
SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
// Don't re-create the window if its display and size hasn't changed,
// as it's not necessary, and causes flashing in fullscreen mode
@ -303,13 +299,13 @@ bool FrameBufferSDL2::activateVideoMode(const string& title,
if(myWindow)
{
// Even though window size stayed the same, the title may have changed
SDL_SetWindowTitle(myWindow, title.c_str());
SDL_SetWindowTitle(myWindow, myScreenTitle.c_str());
SDL_SetWindowPosition(myWindow, posX, posY);
}
else
{
forceCreateRenderer = true;
myWindow = SDL_CreateWindow(title.c_str(), posX, posY,
myWindow = SDL_CreateWindow(myScreenTitle.c_str(), posX, posY,
mode.screenS.w, mode.screenS.h, flags);
if(myWindow == nullptr)
{
@ -333,7 +329,8 @@ bool FrameBufferSDL2::activateVideoMode(const string& title,
{
ostringstream msg;
msg << "Display refresh rate changed to " << adaptedSdlMode.refresh_rate << " Hz";
msg << "Display refresh rate changed to "
<< adaptedSdlMode.refresh_rate << " Hz";
Logger::info(msg.str());
}
}
@ -343,8 +340,11 @@ bool FrameBufferSDL2::activateVideoMode(const string& title,
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool FrameBufferSDL2::adaptRefreshRate(Int32 displayIndex, SDL_DisplayMode& adaptedSdlMode)
bool FBBackendSDL2::adaptRefreshRate(Int32 displayIndex,
SDL_DisplayMode& adaptedSdlMode)
{
ASSERT_MAIN_THREAD;
SDL_DisplayMode sdlMode;
if(SDL_GetCurrentDisplayMode(displayIndex, &sdlMode) != 0)
@ -354,7 +354,8 @@ bool FrameBufferSDL2::adaptRefreshRate(Int32 displayIndex, SDL_DisplayMode& adap
}
const int currentRefreshRate = sdlMode.refresh_rate;
const int wantedRefreshRate = gameRefreshRate();
const int wantedRefreshRate =
myOSystem.hasConsole() ? myOSystem.console().gameRefreshRate() : 0;
// Take care of rounded refresh rates (e.g. 59.94 Hz)
float factor = std::min(float(currentRefreshRate) / wantedRefreshRate,
float(currentRefreshRate) / (wantedRefreshRate - 1));
@ -398,8 +399,10 @@ bool FrameBufferSDL2::adaptRefreshRate(Int32 displayIndex, SDL_DisplayMode& adap
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool FrameBufferSDL2::createRenderer(bool force)
bool FBBackendSDL2::createRenderer(bool force)
{
ASSERT_MAIN_THREAD;
// A new renderer is only created when necessary:
// - new myWindow (force = true)
// - no renderer existing
@ -451,7 +454,7 @@ bool FrameBufferSDL2::createRenderer(bool force)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FrameBufferSDL2::setTitle(const string& title)
void FBBackendSDL2::setTitle(const string& title)
{
ASSERT_MAIN_THREAD;
@ -462,7 +465,7 @@ void FrameBufferSDL2::setTitle(const string& title)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
string FrameBufferSDL2::about() const
string FBBackendSDL2::about() const
{
ASSERT_MAIN_THREAD;
@ -484,7 +487,7 @@ string FrameBufferSDL2::about() const
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FrameBufferSDL2::showCursor(bool show)
void FBBackendSDL2::showCursor(bool show)
{
ASSERT_MAIN_THREAD;
@ -492,7 +495,7 @@ void FrameBufferSDL2::showCursor(bool show)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FrameBufferSDL2::grabMouse(bool grab)
void FBBackendSDL2::grabMouse(bool grab)
{
ASSERT_MAIN_THREAD;
@ -500,7 +503,7 @@ void FrameBufferSDL2::grabMouse(bool grab)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool FrameBufferSDL2::fullScreen() const
bool FBBackendSDL2::fullScreen() const
{
ASSERT_MAIN_THREAD;
@ -512,7 +515,7 @@ bool FrameBufferSDL2::fullScreen() const
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
int FrameBufferSDL2::refreshRate() const
int FBBackendSDL2::refreshRate() const
{
ASSERT_MAIN_THREAD;
@ -529,20 +532,7 @@ int FrameBufferSDL2::refreshRate() const
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
int FrameBufferSDL2::gameRefreshRate() const
{
if(myOSystem.hasConsole())
{
const string format = myOSystem.console().getFormatString();
const bool isNtsc = format == "NTSC" || format == "PAL60" || format == "SECAM60";
return isNtsc ? 60 : 50; // The code will take care of 59/49 Hz
}
return 0;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FrameBufferSDL2::renderToScreen()
void FBBackendSDL2::renderToScreen()
{
ASSERT_MAIN_THREAD;
@ -551,7 +541,7 @@ void FrameBufferSDL2::renderToScreen()
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FrameBufferSDL2::setWindowIcon()
void FBBackendSDL2::setWindowIcon()
{
#if !defined(BSPF_MACOS) && !defined(RETRON77)
#include "stella_icon.hxx"
@ -565,19 +555,20 @@ void FrameBufferSDL2::setWindowIcon()
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
unique_ptr<FBSurface> FrameBufferSDL2::createSurface(
unique_ptr<FBSurface> FBBackendSDL2::createSurface(
uInt32 w,
uInt32 h,
ScalingInterpolation interpolation,
ScalingInterpolation inter,
const uInt32* data
) const
{
return make_unique<FBSurfaceSDL2>(const_cast<FrameBufferSDL2&>(*this), w, h, interpolation, data);
return make_unique<FBSurfaceSDL2>
(const_cast<FBBackendSDL2&>(*this), w, h, inter, data);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FrameBufferSDL2::readPixels(uInt8* pixels, uInt32 pitch,
const Common::Rect& rect) const
void FBBackendSDL2::readPixels(uInt8* pixels, uInt32 pitch,
const Common::Rect& rect) const
{
ASSERT_MAIN_THREAD;
@ -589,7 +580,7 @@ void FrameBufferSDL2::readPixels(uInt8* pixels, uInt32 pitch,
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FrameBufferSDL2::clear()
void FBBackendSDL2::clear()
{
ASSERT_MAIN_THREAD;
@ -597,49 +588,34 @@ void FrameBufferSDL2::clear()
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
SDL_Renderer* FrameBufferSDL2::renderer()
{
return myRenderer;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool FrameBufferSDL2::isInitialized() const
{
return myRenderer != nullptr;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const SDL_PixelFormat& FrameBufferSDL2::pixelFormat() const
{
return *myPixelFormat;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FrameBufferSDL2::detectFeatures()
void FBBackendSDL2::detectFeatures()
{
myRenderTargetSupport = detectRenderTargetSupport();
if (myRenderer) {
if (!myRenderTargetSupport) {
Logger::info("Render targets are not supported --- QIS not available");
}
}
if(myRenderer && !myRenderTargetSupport)
Logger::info("Render targets are not supported --- QIS not available");
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool FrameBufferSDL2::detectRenderTargetSupport()
bool FBBackendSDL2::detectRenderTargetSupport()
{
if (myRenderer == nullptr) return false;
ASSERT_MAIN_THREAD;
if(myRenderer == nullptr)
return false;
SDL_RendererInfo info;
SDL_GetRendererInfo(myRenderer, &info);
if (!(info.flags & SDL_RENDERER_TARGETTEXTURE)) return false;
if(!(info.flags & SDL_RENDERER_TARGETTEXTURE))
return false;
SDL_Texture* tex = SDL_CreateTexture(myRenderer, myPixelFormat->format, SDL_TEXTUREACCESS_TARGET, 16, 16);
SDL_Texture* tex =
SDL_CreateTexture(myRenderer, myPixelFormat->format,
SDL_TEXTUREACCESS_TARGET, 16, 16);
if (!tex) return false;
if(!tex)
return false;
int sdlError = SDL_SetRenderTarget(myRenderer, tex);
SDL_SetRenderTarget(myRenderer, nullptr);
@ -650,20 +626,17 @@ bool FrameBufferSDL2::detectRenderTargetSupport()
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool FrameBufferSDL2::hasRenderTargetSupport() const
void FBBackendSDL2::determineDimensions()
{
return myRenderTargetSupport;
}
ASSERT_MAIN_THREAD;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FrameBufferSDL2::determineDimensions()
{
SDL_GetWindowSize(myWindow, &myWindowW, &myWindowH);
if (myRenderer == nullptr) {
if(myRenderer == nullptr)
{
myRenderW = myWindowW;
myRenderH = myWindowH;
} else {
SDL_GetRendererOutputSize(myRenderer, &myRenderW, &myRenderH);
}
else
SDL_GetRendererOutputSize(myRenderer, &myRenderW, &myRenderH);
}

View File

@ -15,8 +15,8 @@
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//============================================================================
#ifndef FRAMEBUFFER_SDL2_HXX
#define FRAMEBUFFER_SDL2_HXX
#ifndef FB_BACKEND_SDL2_HXX
#define FB_BACKEND_SDL2_HXX
#include "SDL_lib.hxx"
@ -24,27 +24,55 @@ class OSystem;
class FBSurfaceSDL2;
#include "bspf.hxx"
#include "FrameBuffer.hxx"
#include "FBBackend.hxx"
/**
This class implements a standard SDL2 2D, hardware accelerated framebuffer.
Behind the scenes, it may be using Direct3D, OpenGL(ES), etc.
This class implements a standard SDL2 2D, hardware accelerated framebuffer
backend. Behind the scenes, it may be using Direct3D, OpenGL(ES), etc.
@author Stephen Anthony
*/
class FrameBufferSDL2 : public FrameBuffer
class FBBackendSDL2 : public FBBackend
{
public:
/**
Creates a new SDL2 framebuffer
*/
explicit FrameBufferSDL2(OSystem& osystem);
~FrameBufferSDL2() override;
explicit FBBackendSDL2(OSystem& osystem);
~FBBackendSDL2() override;
//////////////////////////////////////////////////////////////////////
// The following are derived from public methods in FrameBuffer.hxx
//////////////////////////////////////////////////////////////////////
public:
/**
Get a pointer to the SDL renderer.
*/
SDL_Renderer* renderer() { return myRenderer; }
/**
Is the renderer initialized?
*/
bool isInitialized() const { return myRenderer != nullptr; }
/**
Get the SDL pixel format.
*/
const SDL_PixelFormat& pixelFormat() const { return *myPixelFormat; }
/**
Does the renderer support render targets?
*/
bool hasRenderTargetSupport() const { return myRenderTargetSupport; }
/**
Transform from window to renderer coordinates, x direction
*/
int scaleX(int x) const override { return (x * myRenderW) / myWindowW; }
/**
Transform from window to renderer coordinates, y direction
*/
int scaleY(int y) const override { return (y * myRenderH) / myWindowH; }
protected:
/**
Updates window title.
@ -93,7 +121,8 @@ class FrameBufferSDL2 : public FrameBuffer
@param pitch The pitch (in bytes) for the pixel data
@param rect The bounding rectangle for the buffer
*/
void readPixels(uInt8* buffer, uInt32 pitch, const Common::Rect& rect) const override;
void readPixels(uInt8* buffer, uInt32 pitch,
const Common::Rect& rect) const override;
/**
This method is called to query if the current window is not centered
@ -110,6 +139,7 @@ class FrameBufferSDL2 : public FrameBuffer
@return The position of the currently displayed window
*/
Common::Point getCurrentWindowPos() const override;
/**
This method is called to query the video hardware for the index
of the display the current window is displayed on
@ -124,40 +154,6 @@ class FrameBufferSDL2 : public FrameBuffer
*/
void clear() override;
/**
Get a pointer to the SDL renderer.
*/
SDL_Renderer* renderer();
/**
Get the SDL pixel format.
*/
const SDL_PixelFormat& pixelFormat() const;
/**
Is the renderer initialized?
*/
bool isInitialized() const;
/**
Does the renderer support render targets?
*/
bool hasRenderTargetSupport() const;
/**
Transform from window to renderer coordinates, x direction
*/
int scaleX(int x) const override { return (x * myRenderW) / myWindowW; }
/**
Transform from window to renderer coordinates, y direction
*/
int scaleY(int y) const override { return (y * myRenderH) / myWindowH; }
protected:
//////////////////////////////////////////////////////////////////////
// The following are derived from protected methods in FrameBuffer.hxx
//////////////////////////////////////////////////////////////////////
/**
This method is called to query and initialize the video hardware
for desktop and fullscreen resolution information. Since several
@ -174,46 +170,28 @@ class FrameBufferSDL2 : public FrameBuffer
/**
This method is called to change to the given video mode.
@param title The title for the created window
@param mode The video mode to use
@param mode The video mode to use
@param winIdx The display/monitor that the window last opened on
@param winPos The position that the window last opened at
@return False on any errors, else true
*/
bool activateVideoMode(const string& title,
const VideoModeHandler::Mode& mode) override;
/**
Checks if the display refresh rate should be adapted to game refresh rate in (real) fullscreen mode
@param displayIndex The display which should be checked
@param adaptedSdlMode The best matching mode if the refresh rate should be changed
@return True if the refresh rate should be changed
*/
bool adaptRefreshRate(Int32 displayIndex, SDL_DisplayMode& adaptedSdlMode);
/**
Create a new renderer if required
@param force If true, force new renderer creation
@return False on any errors, else true
*/
bool createRenderer(bool force);
bool setVideoMode(const VideoModeHandler::Mode& mode,
int winIdx, const Common::Point& winPos) override;
/**
This method is called to create a surface with the given attributes.
@param w The requested width of the new surface.
@param h The requested height of the new surface.
@param interpolation Interpolation mode
@param data If non-null, use the given data values as a static surface
@param w The requested width of the new surface.
@param h The requested height of the new surface.
@param inter Interpolation mode
@param data If non-null, use the given data values as a static surface
*/
unique_ptr<FBSurface>
createSurface(
uInt32 w,
uInt32 h,
ScalingInterpolation interpolation,
ScalingInterpolation inter,
const uInt32* data
) const override;
@ -223,28 +201,49 @@ class FrameBufferSDL2 : public FrameBuffer
void grabMouse(bool grab) override;
/**
Set the icon for the main SDL window.
*/
void setWindowIcon() override;
/**
This method is called to provide information about the FrameBuffer.
This method is called to provide information about the backend.
*/
string about() const override;
/**
Create a new renderer if required.
@param force If true, force new renderer creation
@return False on any errors, else true
*/
bool createRenderer(bool force);
/**
This method must be called after all drawing is done, and indicates
that the buffers should be pushed to the physical screen.
*/
void renderToScreen() override;
/**
Retrieve the current display's refresh rate, or 0 if no window.
*/
int refreshRate() const override;
/**
Checks if the display refresh rate should be adapted to game refresh
rate in (real) fullscreen mode.
@param displayIndex The display which should be checked
@param adaptedSdlMode The best matching mode if the refresh rate
should be changed
@return True if the refresh rate should be changed
*/
bool adaptRefreshRate(Int32 displayIndex, SDL_DisplayMode& adaptedSdlMode);
/**
After the renderer has been created, detect the features it supports.
*/
void detectFeatures();
/**
Detect render target support;
Detect render target support.
*/
bool detectRenderTargetSupport();
@ -254,16 +253,13 @@ class FrameBufferSDL2 : public FrameBuffer
void determineDimensions();
/**
Retrieve the current display's refresh rate, or 0 if no window
Set the icon for the main SDL window.
*/
int refreshRate() const override;
/**
Retrieve the current game's refresh rate, or 60 if no game
*/
int gameRefreshRate() const;
void setWindowIcon();
private:
OSystem& myOSystem;
// The SDL video buffer
SDL_Window* myWindow{nullptr};
SDL_Renderer* myRenderer{nullptr};
@ -274,22 +270,25 @@ class FrameBufferSDL2 : public FrameBuffer
// Center setting of current window
bool myCenter{false};
// last position of windowed window
Common::Point myWindowedPos;
// Does the renderer support render targets?
bool myRenderTargetSupport{false};
// Title of the main window/screen
string myScreenTitle;
// Number of displays
int myNumDisplays{1};
// Window and renderer dimensions
int myWindowW{0}, myWindowH{0}, myRenderW{0}, myRenderH{0};
private:
// Following constructors and assignment operators not supported
FrameBufferSDL2() = delete;
FrameBufferSDL2(const FrameBufferSDL2&) = delete;
FrameBufferSDL2(FrameBufferSDL2&&) = delete;
FrameBufferSDL2& operator=(const FrameBufferSDL2&) = delete;
FrameBufferSDL2& operator=(FrameBufferSDL2&&) = delete;
FBBackendSDL2() = delete;
FBBackendSDL2(const FBBackendSDL2&) = delete;
FBBackendSDL2(FBBackendSDL2&&) = delete;
FBBackendSDL2& operator=(const FBBackendSDL2&) = delete;
FBBackendSDL2& operator=(FBBackendSDL2&&) = delete;
};
#endif

View File

@ -22,9 +22,9 @@
#include "sdl_blitter/BlitterFactory.hxx"
namespace {
BlitterFactory::ScalingAlgorithm scalingAlgorithm(ScalingInterpolation interpolation)
BlitterFactory::ScalingAlgorithm scalingAlgorithm(ScalingInterpolation inter)
{
switch (interpolation) {
switch (inter) {
case ScalingInterpolation::none:
return BlitterFactory::ScalingAlgorithm::nearestNeighbour;
@ -41,12 +41,12 @@ namespace {
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FBSurfaceSDL2::FBSurfaceSDL2(FrameBufferSDL2& buffer,
FBSurfaceSDL2::FBSurfaceSDL2(FBBackendSDL2& backend,
uInt32 width, uInt32 height,
ScalingInterpolation interpolation,
ScalingInterpolation inter,
const uInt32* staticData)
: myFB(buffer),
myInterpolationMode(interpolation)
: myBackend(backend),
myInterpolationMode(inter)
{
createSurface(width, height, staticData);
}
@ -214,7 +214,7 @@ void FBSurfaceSDL2::createSurface(uInt32 width, uInt32 height,
ASSERT_MAIN_THREAD;
// Create a surface in the same format as the parent GL class
const SDL_PixelFormat& pf = myFB.pixelFormat();
const SDL_PixelFormat& pf = myBackend.pixelFormat();
mySurface = SDL_CreateRGBSurface(0, width, height,
pf.BitsPerPixel, pf.Rmask, pf.Gmask, pf.Bmask, pf.Amask);
@ -242,11 +242,13 @@ void FBSurfaceSDL2::createSurface(uInt32 width, uInt32 height,
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurfaceSDL2::reinitializeBlitter()
{
if (!myBlitter && myFB.isInitialized())
myBlitter = BlitterFactory::createBlitter(myFB, scalingAlgorithm(myInterpolationMode));
if (!myBlitter && myBackend.isInitialized())
myBlitter = BlitterFactory::createBlitter(
myBackend, scalingAlgorithm(myInterpolationMode));
if (myBlitter)
myBlitter->reinitialize(mySrcR, myDstR, myAttributes, myIsStatic ? mySurface : nullptr);
myBlitter->reinitialize(mySrcR, myDstR, myAttributes,
myIsStatic ? mySurface : nullptr);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -20,7 +20,7 @@
#include "bspf.hxx"
#include "FBSurface.hxx"
#include "FrameBufferSDL2.hxx"
#include "FBBackendSDL2.hxx"
#include "sdl_blitter/Blitter.hxx"
/**
@ -32,9 +32,8 @@
class FBSurfaceSDL2 : public FBSurface
{
public:
FBSurfaceSDL2(FrameBufferSDL2& buffer, uInt32 width, uInt32 height,
ScalingInterpolation interpolation,
const uInt32* staticData);
FBSurfaceSDL2(FBBackendSDL2& backend, uInt32 width, uInt32 height,
ScalingInterpolation inter, const uInt32* staticData);
~FBSurfaceSDL2() override;
// Most of the surface drawing primitives are implemented in FBSurface;
@ -95,7 +94,7 @@ class FBSurfaceSDL2 : public FBSurface
FBSurfaceSDL2& operator=(FBSurfaceSDL2&&) = delete;
private:
FrameBufferSDL2& myFB;
FBBackendSDL2& myBackend;
unique_ptr<Blitter> myBlitter;
ScalingInterpolation myInterpolationMode

View File

@ -51,10 +51,10 @@
#if defined(__LIB_RETRO__)
#include "EventHandlerLIBRETRO.hxx"
#include "FrameBufferLIBRETRO.hxx"
#include "FBBackendLIBRETRO.hxx"
#elif defined(SDL_SUPPORT)
#include "EventHandlerSDL2.hxx"
#include "FrameBufferSDL2.hxx"
#include "FBBackendSDL2.hxx"
#else
#error Unsupported backend!
#endif
@ -128,12 +128,12 @@ class MediaFactory
#endif
}
static unique_ptr<FrameBuffer> createVideo(OSystem& osystem)
static unique_ptr<FBBackend> createVideoBackend(OSystem& osystem)
{
#if defined(__LIB_RETRO__)
return make_unique<FrameBufferLIBRETRO>(osystem);
return make_unique<FBBackendLIBRETRO>(osystem);
#elif defined(SDL_SUPPORT)
return make_unique<FrameBufferSDL2>(osystem);
return make_unique<FBBackendSDL2>(osystem);
#else
#error Unsupported platform for FrameBuffer!
#endif

View File

@ -5,9 +5,9 @@ MODULE_OBJS := \
src/common/AudioSettings.o \
src/common/Base.o \
src/common/EventHandlerSDL2.o \
src/common/FBBackendSDL2.o \
src/common/FBSurfaceSDL2.o \
src/common/FpsMeter.o \
src/common/FrameBufferSDL2.o \
src/common/FSNodeZIP.o \
src/common/JoyMap.o \
src/common/KeyMap.o \

View File

@ -15,12 +15,12 @@
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//============================================================================
#include "FrameBufferSDL2.hxx"
#include "FBBackendSDL2.hxx"
#include "ThreadDebugging.hxx"
#include "BilinearBlitter.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
BilinearBlitter::BilinearBlitter(FrameBufferSDL2& fb, bool interpolate)
BilinearBlitter::BilinearBlitter(FBBackendSDL2& fb, bool interpolate)
: myFB(fb),
myInterpolate(interpolate)
{

View File

@ -18,7 +18,7 @@
#ifndef BILINEAR_BLITTER_HXX
#define BILINEAR_BLITTER_HXX
class FrameBufferSDL2;
class FBBackendSDL2;
#include "Blitter.hxx"
#include "SDL_lib.hxx"
@ -27,7 +27,7 @@ class BilinearBlitter : public Blitter {
public:
BilinearBlitter(FrameBufferSDL2& fb, bool interpolate);
BilinearBlitter(FBBackendSDL2& fb, bool interpolate);
~BilinearBlitter() override;
@ -41,7 +41,7 @@ class BilinearBlitter : public Blitter {
virtual void blit(SDL_Surface& surface) override;
private:
FrameBufferSDL2& myFB;
FBBackendSDL2& myFB;
SDL_Texture* myTexture{nullptr};
SDL_Texture* mySecondaryTexture{nullptr};

View File

@ -21,7 +21,7 @@
#include "BilinearBlitter.hxx"
#include "QisBlitter.hxx"
unique_ptr<Blitter> BlitterFactory::createBlitter(FrameBufferSDL2& fb, ScalingAlgorithm scaling)
unique_ptr<Blitter> BlitterFactory::createBlitter(FBBackendSDL2& fb, ScalingAlgorithm scaling)
{
if (!fb.isInitialized()) {
throw runtime_error("BlitterFactory requires an initialized framebuffer!");

View File

@ -21,8 +21,8 @@
#include <string>
#include "Blitter.hxx"
#include "FBBackendSDL2.hxx"
#include "bspf.hxx"
#include "FrameBufferSDL2.hxx"
class BlitterFactory {
public:
@ -35,7 +35,7 @@ class BlitterFactory {
public:
static unique_ptr<Blitter> createBlitter(FrameBufferSDL2& fb, ScalingAlgorithm scaling);
static unique_ptr<Blitter> createBlitter(FBBackendSDL2& fb, ScalingAlgorithm scaling);
};
#endif // BLITTER_FACTORY_HXX

View File

@ -15,12 +15,12 @@
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//============================================================================
#include "FrameBufferSDL2.hxx"
#include "FBBackendSDL2.hxx"
#include "ThreadDebugging.hxx"
#include "QisBlitter.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
QisBlitter::QisBlitter(FrameBufferSDL2& fb)
QisBlitter::QisBlitter(FBBackendSDL2& fb)
: myFB(fb)
{
}
@ -32,7 +32,7 @@ QisBlitter::~QisBlitter()
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool QisBlitter::isSupported(FrameBufferSDL2 &fb)
bool QisBlitter::isSupported(FBBackendSDL2& fb)
{
if (!fb.isInitialized()) throw runtime_error("framebuffer not initialized");

View File

@ -18,7 +18,7 @@
#ifndef QIS_BLITTER_HXX
#define QIS_BLITTER_HXX
class FrameBufferSDL2;
class FBBackendSDL2;
#include "Blitter.hxx"
#include "SDL_lib.hxx"
@ -27,9 +27,9 @@ class QisBlitter : public Blitter {
public:
explicit QisBlitter(FrameBufferSDL2& fb);
explicit QisBlitter(FBBackendSDL2& fb);
static bool isSupported(FrameBufferSDL2 &fb);
static bool isSupported(FBBackendSDL2& fb);
~QisBlitter() override;
@ -44,7 +44,7 @@ class QisBlitter : public Blitter {
private:
FrameBufferSDL2& myFB;
FBBackendSDL2& myFB;
SDL_Texture* mySrcTexture{nullptr};
SDL_Texture* mySecondarySrcTexture{nullptr};

View File

@ -250,7 +250,6 @@ Console::~Console()
myOSystem.sound().close();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Console::setConsoleTiming()
{
@ -728,7 +727,8 @@ void Console::changeVSizeAdjust(int direction)
ostringstream val;
val << (newAdjustVSize ? newAdjustVSize > 0 ? "+" : "" : " ") << newAdjustVSize << "%";
val << (newAdjustVSize ? newAdjustVSize > 0 ? "+" : "" : " ")
<< newAdjustVSize << "%";
myOSystem.frameBuffer().showMessage("V-Size", val.str(), newAdjustVSize, -5, 5);
}
@ -743,7 +743,8 @@ void Console::toggleCorrectAspectRatio(bool toggle)
myOSystem.settings().setValue("tia.correct_aspect", enabled);
initializeVideo();
}
const string message = string("Correct aspect ratio ") + (enabled ? "enabled" : "disabled");
const string& message = string("Correct aspect ratio ") +
(enabled ? "enabled" : "disabled");
myOSystem.frameBuffer().showMessage(message);
}
@ -755,8 +756,7 @@ void Console::setTIAProperties()
static_cast<Int32>(BSPF::stringToInt(myProperties.get(PropType::Display_VCenter))), TIAConstants::minVcenter, TIAConstants::maxVcenter
);
if(myDisplayFormat == "NTSC" || myDisplayFormat == "PAL60" ||
myDisplayFormat == "SECAM60")
if(gameRefreshRate() == 60)
{
// Assume we've got ~262 scanlines (NTSC-like format)
myTIA->setLayout(FrameLayout::ntsc);
@ -805,17 +805,22 @@ void Console::setControllers(const string& romMd5)
myLeftControl = std::move(myCMHandler->leftController());
myRightControl = std::move(myCMHandler->rightController());
myOSystem.eventHandler().defineKeyControllerMappings(Controller::Type::CompuMate, Controller::Jack::Left);
myOSystem.eventHandler().defineJoyControllerMappings(Controller::Type::CompuMate, Controller::Jack::Left);
myOSystem.eventHandler().defineKeyControllerMappings(
Controller::Type::CompuMate, Controller::Jack::Left);
myOSystem.eventHandler().defineJoyControllerMappings(
Controller::Type::CompuMate, Controller::Jack::Left);
}
else
{
// Setup the controllers based on properties
Controller::Type leftType = Controller::getType(myProperties.get(PropType::Controller_Left));
Controller::Type rightType = Controller::getType(myProperties.get(PropType::Controller_Right));
Controller::Type leftType =
Controller::getType(myProperties.get(PropType::Controller_Left));
Controller::Type rightType =
Controller::getType(myProperties.get(PropType::Controller_Right));
size_t size = 0;
const ByteBuffer& image = myCart->getImage(size);
const bool swappedPorts = myProperties.get(PropType::Console_SwapPorts) == "YES";
const bool swappedPorts =
myProperties.get(PropType::Console_SwapPorts) == "YES";
// Try to detect controllers
if(image != nullptr && size != 0)
@ -827,7 +832,8 @@ void Console::setControllers(const string& romMd5)
!swappedPorts ? Controller::Jack::Right : Controller::Jack::Left, myOSystem.settings());
}
unique_ptr<Controller> leftC = getControllerPort(leftType, Controller::Jack::Left, romMd5),
unique_ptr<Controller>
leftC = getControllerPort(leftType, Controller::Jack::Left, romMd5),
rightC = getControllerPort(rightType, Controller::Jack::Right, romMd5);
// Swap the ports if necessary
@ -985,13 +991,21 @@ void Console::changeAutoFireRate(int direction)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
float Console::getFramerate() const
float Console::currentFrameRate() const
{
return
(myConsoleTiming == ConsoleTiming::ntsc ? 262.F * 60.F : 312.F * 50.F) /
myTIA->frameBufferScanlinesLastFrame();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
int Console::gameRefreshRate() const
{
return
myDisplayFormat == "NTSC" || myDisplayFormat == "PAL60" ||
myDisplayFormat == "SECAM60" ? 60 : 50;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Console::toggleTIABit(TIABit bit, const string& bitname, bool show, bool toggle) const
{

View File

@ -185,6 +185,11 @@ class Console : public Serializable, public ConsoleIO
*/
EmulationTiming& emulationTiming() { return myEmulationTiming; }
/**
Retrieve the current game's refresh rate, or 0 if no game.
*/
int refreshRate() const;
public:
/**
Toggle between NTSC/PAL/SECAM (and variants) display format.
@ -282,9 +287,16 @@ class Console : public Serializable, public ConsoleIO
void toggleCorrectAspectRatio(bool toggle = true);
/**
Returns the current framerate.
Returns the current framerate. Note that this is the actual,
dynamic frame rate while a game is running.
*/
float getFramerate() const;
float currentFrameRate() const;
/**
Retrieve the current game's refresh rate. Note that this is a
static, basic frame rate based on the current TV format.
*/
int gameRefreshRate() const;
/**
Toggles the TIA bit specified in the method name.

207
src/emucore/FBBackend.hxx Normal file
View File

@ -0,0 +1,207 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2020 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//============================================================================
#ifndef FB_BACKEND_HXX
#define FB_BACKEND_HXX
class FBSurface;
#include "Rect.hxx"
#include "Variant.hxx"
#include "FrameBufferConstants.hxx"
#include "VideoModeHandler.hxx"
#include "bspf.hxx"
/**
This class provides an interface/abstraction for platform-specific,
framebuffer-related rendering operations. Different graphical
platforms will inherit from this. For most ports that means SDL2,
but some (such as libretro) use their own graphical subsystem.
@author Stephen Anthony
*/
class FBBackend
{
friend class FrameBuffer;
public:
FBBackend() = default;
virtual ~FBBackend() = default;
protected:
/**
This method is called to query and initialize the video hardware
for desktop and fullscreen resolution information. Since several
monitors may be attached, we need the resolution for all of them.
@param fullscreenRes Maximum resolution supported in fullscreen mode
@param windowedRes Maximum resolution supported in windowed mode
@param renderers List of renderer names (internal name -> end-user name)
*/
virtual void queryHardware(vector<Common::Size>& fullscreenRes,
vector<Common::Size>& windowedRes,
VariantList& renderers) = 0;
/**
This method is called to change to the given video mode.
@param mode The video mode to use
@param winIdx The display/monitor that the window last opened on
@param winPos The position that the window last opened at
@return False on any errors, else true
*/
virtual bool setVideoMode(const VideoModeHandler::Mode& mode,
int winIdx, const Common::Point& winPos) = 0;
/**
Clear the framebuffer.
*/
virtual void clear() = 0;
/**
Transform from window to renderer coordinates, x direction
*/
virtual int scaleX(int x) const = 0;
/**
Transform from window to renderer coordinates, y direction
*/
virtual int scaleY(int y) const = 0;
/**
Updates window title.
@param title The title of the application / window
*/
virtual void setTitle(const string& title) = 0;
/**
Shows or hides the cursor based on the given boolean value.
*/
virtual void showCursor(bool show) = 0;
/**
Grabs or ungrabs the mouse based on the given boolean value.
*/
virtual void grabMouse(bool grab) = 0;
/**
This method must be called after all drawing is done, and indicates
that the buffers should be pushed to the physical screen.
*/
virtual void renderToScreen() = 0;
/**
Answers if the display is currently in fullscreen mode.
@return Whether the display is actually in fullscreen mode
*/
virtual bool fullScreen() const = 0;
/**
Retrieve the current display's refresh rate.
*/
virtual int refreshRate() const = 0;
/**
This method is called to retrieve the R/G/B data from the given pixel.
@param pixel The pixel containing R/G/B data
@param r The red component of the color
@param g The green component of the color
@param b The blue component of the color
*/
virtual void getRGB(uInt32 pixel, uInt8* r, uInt8* g, uInt8* b) const = 0;
/**
This method is called to map a given R/G/B triple to the screen palette.
@param r The red component of the color.
@param g The green component of the color.
@param b The blue component of the color.
*/
virtual uInt32 mapRGB(uInt8 r, uInt8 g, uInt8 b) const = 0;
/**
This method is called to get the specified ARGB data from the viewable
FrameBuffer area. Note that this isn't the same as any internal
surfaces that may be in use; it should return the actual data as it
is currently seen onscreen.
@param buffer The actual pixel data in ARGB8888 format
@param pitch The pitch (in bytes) for the pixel data
@param rect The bounding rectangle for the buffer
*/
virtual void readPixels(uInt8* buffer, uInt32 pitch,
const Common::Rect& rect) const = 0;
/**
This method is called to query if the current window is not
centered or fullscreen.
@return True, if the current window is positioned
*/
virtual bool isCurrentWindowPositioned() const = 0;
/**
This method is called to query the video hardware for position of
the current window.
@return The position of the currently displayed window
*/
virtual Common::Point getCurrentWindowPos() const = 0;
/**
This method is called to query the video hardware for the index
of the display the current window is displayed on.
@return The current display index or a negative value if no
window is displayed
*/
virtual Int32 getCurrentDisplayIndex() const = 0;
/**
This method is called to create a surface with the given attributes.
@param w The requested width of the new surface.
@param h The requested height of the new surface.
@param inter Interpolation mode
@param data If non-null, use the given data values as a static surface
*/
virtual unique_ptr<FBSurface>
createSurface(
uInt32 w,
uInt32 h,
ScalingInterpolation inter = ScalingInterpolation::none,
const uInt32* data = nullptr
) const = 0;
/**
This method is called to provide information about the backend.
*/
virtual string about() const = 0;
private:
// Following constructors and assignment operators not supported
FBBackend(const FBBackend&) = delete;
FBBackend(FBBackend&&) = delete;
FBBackend& operator=(const FBBackend&) = delete;
FBBackend& operator=(FBBackend&&) = delete;
};
#endif

View File

@ -177,7 +177,8 @@ class FBSurface
@param y The destination y-location to start drawing pixels
@param numpixels The number of pixels to draw
*/
virtual void drawPixels(const uInt32* data, uInt32 x, uInt32 y, uInt32 numpixels);
virtual void drawPixels(const uInt32* data, uInt32 x, uInt32 y,
uInt32 numpixels);
/**
This method should be called to draw a rectangular box with sides

View File

@ -25,6 +25,7 @@
#include "Settings.hxx"
#include "TIA.hxx"
#include "Sound.hxx"
#include "MediaFactory.hxx"
#include "FBSurface.hxx"
#include "TIASurface.hxx"
@ -63,14 +64,24 @@ FrameBuffer::FrameBuffer(OSystem& osystem)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FrameBuffer::~FrameBuffer()
{
// Make sure to free surfaces/textures before destroying the backend itself
// Most platforms are fine with doing this in either order, but it seems
// that OpenBSD in particular crashes when attempting to destroy textures
// *after* the renderer is already destroyed
freeSurfaces();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool FrameBuffer::initialize()
void FrameBuffer::initialize()
{
// First create the platform-specific backend; it is needed before anything
// else can be used
try { myBackend = MediaFactory::createVideoBackend(myOSystem); }
catch(const runtime_error& e) { throw e; }
// Get desktop resolution and supported renderers
vector<Common::Size> windowedDisplays;
queryHardware(myFullscreenDisplays, windowedDisplays, myRenderers);
myBackend->queryHardware(myFullscreenDisplays, windowedDisplays, myRenderers);
uInt32 query_w = windowedDisplays[0].w, query_h = windowedDisplays[0].h;
// Check the 'maxres' setting, which is an undocumented developer feature
@ -116,8 +127,6 @@ bool FrameBuffer::initialize()
// Create a TIA surface; we need it for rendering TIA images
myTIASurface = make_unique<TIASurface>(myOSystem);
return true;
}
#ifdef GUI_SUPPORT
@ -210,7 +219,7 @@ FBInitStatus FrameBuffer::createDisplay(const string& title, BufferType type,
Common::Size size, bool honourHiDPI)
{
++myInitializedCount;
myScreenTitle = title;
myBackend->setTitle(title);
// In HiDPI mode, all created displays must be scaled appropriately
if(honourHiDPI && hidpiEnabled())
@ -254,7 +263,7 @@ FBInitStatus FrameBuffer::createDisplay(const string& title, BufferType type,
myBufferType = type;
// Initialize video subsystem
string pre_about = about();
string pre_about = myBackend->about();
FBInitStatus status = applyVideoMode();
if(status != FBInitStatus::Success)
return status;
@ -289,11 +298,11 @@ FBInitStatus FrameBuffer::createDisplay(const string& title, BufferType type,
// Print initial usage message, but only print it later if the status has changed
if(myInitializedCount == 1)
{
Logger::info(about());
Logger::info(myBackend->about());
}
else
{
string post_about = about();
string post_about = myBackend->about();
if(post_about != pre_about)
Logger::info(post_about);
}
@ -467,7 +476,7 @@ void FrameBuffer::update(bool force)
// Push buffers to screen only when necessary
if(force)
renderToScreen();
myBackend->renderToScreen();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -493,7 +502,7 @@ void FrameBuffer::updateInEmulationMode(float framesPerSecond)
drawMessage();
// Push buffers to screen
renderToScreen();
myBackend->renderToScreen();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -600,7 +609,8 @@ void FrameBuffer::drawFrameStats(float framesPerSecond)
ss
<< myOSystem.console().tia().frameBufferScanlinesLastFrame()
<< " / "
<< std::fixed << std::setprecision(1) << myOSystem.console().getFramerate()
<< std::fixed << std::setprecision(1)
<< myOSystem.console().currentFrameRate()
<< "Hz => "
<< info.DisplayFormat;
@ -803,11 +813,11 @@ void FrameBuffer::setPauseDelay()
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
shared_ptr<FBSurface> FrameBuffer::allocateSurface(
int w, int h, ScalingInterpolation interpolation, const uInt32* data
int w, int h, ScalingInterpolation inter, const uInt32* data
)
{
// Add new surface to the list
mySurfaceList.push_back(createSurface(w, h, interpolation, data));
mySurfaceList.push_back(myBackend->createSurface(w, h, inter, data));
// And return a pointer to it (pointer should be treated read-only)
return mySurfaceList.at(mySurfaceList.size() - 1);
@ -945,9 +955,11 @@ string FrameBuffer::getPositionKey()
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FrameBuffer::saveCurrentWindowPosition()
{
myOSystem.settings().setValue(getDisplayKey(), getCurrentDisplayIndex());
if(isCurrentWindowPositioned())
myOSystem.settings().setValue(getPositionKey(), getCurrentWindowPos());
myOSystem.settings().setValue(
getDisplayKey(), myBackend->getCurrentDisplayIndex());
if(myBackend->isCurrentWindowPositioned())
myOSystem.settings().setValue(
getPositionKey(), myBackend->getCurrentWindowPos());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -997,7 +1009,7 @@ void FrameBuffer::toggleFullscreen(bool toggle)
ostringstream msg;
msg << "Fullscreen ";
if(isFullscreen)
msg << "enabled (" << refreshRate() << " Hz, ";
msg << "enabled (" << myBackend->refreshRate() << " Hz, ";
else
msg << "disabled (";
msg << "Zoom " << myActiveVidMode.zoom * 100 << "%)";
@ -1033,7 +1045,7 @@ void FrameBuffer::toggleAdaptRefresh(bool toggle)
msg << "Adapt refresh rate ";
msg << (isAdaptRefresh ? "enabled" : "disabled");
msg << " (" << refreshRate() << " Hz)";
msg << " (" << myBackend->refreshRate() << " Hz)";
showMessage(msg.str());
}
@ -1112,7 +1124,7 @@ FBInitStatus FrameBuffer::applyVideoMode()
const Settings& s = myOSystem.settings();
if(s.getBool("fullscreen"))
{
Int32 fsIndex = std::max(getCurrentDisplayIndex(), 0);
Int32 fsIndex = std::max(myBackend->getCurrentDisplayIndex(), 0);
myVidModeHandler.setDisplaySize(myFullscreenDisplays[fsIndex], fsIndex);
}
else
@ -1130,7 +1142,11 @@ FBInitStatus FrameBuffer::applyVideoMode()
// So we mute the sound until the operation completes
bool oldMuteState = myOSystem.sound().mute(true);
FBInitStatus status = FBInitStatus::FailNotSupported;
if(activateVideoMode(myScreenTitle, mode))
if(myBackend->setVideoMode(mode,
myOSystem.settings().getInt(getDisplayKey()),
myOSystem.settings().getPoint(getPositionKey()))
)
{
myActiveVidMode = mode;
status = FBInitStatus::Success;
@ -1218,7 +1234,7 @@ void FrameBuffer::setCursorState()
break;
}
grabMouse(emulation && (analog || alwaysUseMouse) && myGrabMouse);
myBackend->grabMouse(emulation && (analog || alwaysUseMouse) && myGrabMouse);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -33,6 +33,7 @@ class TIASurface;
#include "Rect.hxx"
#include "Variant.hxx"
#include "TIAConstants.hxx"
#include "FBBackend.hxx"
#include "FrameBufferConstants.hxx"
#include "EventHandlerConstants.hxx"
#include "VideoModeHandler.hxx"
@ -55,16 +56,14 @@ class FrameBuffer
static constexpr float ZOOM_STEPS = 0.25;
public:
/**
Creates a new Frame Buffer
*/
FrameBuffer(OSystem& osystem);
virtual ~FrameBuffer();
~FrameBuffer();
/**
Initialize the framebuffer object (set up the underlying hardware)
Initialize the framebuffer object (set up the underlying hardware).
Throws an exception upon encountering any errors.
*/
bool initialize();
void initialize();
/**
(Re)creates the framebuffer display. This must be called before any
@ -141,17 +140,17 @@ class FrameBuffer
Allocate a new surface. The FrameBuffer class takes all responsibility
for freeing this surface (ie, other classes must not delete it directly).
@param w The requested width of the new surface.
@param h The requested height of the new surface.
@param interpolation Interpolation mode
@param data If non-null, use the given data values as a static surface
@param w The requested width of the new surface
@param h The requested height of the new surface
@param inter Interpolation mode
@param data If non-null, use the given data values as a static surface
@return A pointer to a valid surface object, or nullptr.
@return A pointer to a valid surface object, or nullptr
*/
shared_ptr<FBSurface> allocateSurface(
int w,
int h,
ScalingInterpolation interpolation = ScalingInterpolation::none,
ScalingInterpolation inter = ScalingInterpolation::none,
const uInt32* data = nullptr
);
@ -304,27 +303,15 @@ class FrameBuffer
FontDesc getFontDesc(const string& name) const;
#endif
//////////////////////////////////////////////////////////////////////
// The following methods are system-specific and can/must be
// implemented in derived classes.
//////////////////////////////////////////////////////////////////////
public:
/**
Updates window title
@param title The title of the application / window
*/
virtual void setTitle(const string& title) = 0;
/**
Shows or hides the cursor based on the given boolean value.
*/
virtual void showCursor(bool show) = 0;
void showCursor(bool show) { myBackend->showCursor(show); }
/**
Answers if the display is currently in fullscreen mode.
*/
virtual bool fullScreen() const = 0;
bool fullScreen() const { return myBackend->fullScreen(); }
/**
This method is called to retrieve the R/G/B data from the given pixel.
@ -334,7 +321,9 @@ class FrameBuffer
@param g The green component of the color
@param b The blue component of the color
*/
virtual void getRGB(uInt32 pixel, uInt8* r, uInt8* g, uInt8* b) const = 0;
void getRGB(uInt32 pixel, uInt8* r, uInt8* g, uInt8* b) const {
myBackend->getRGB(pixel, r, g, b);
}
/**
This method is called to map a given R/G/B triple to the screen palette.
@ -343,7 +332,9 @@ class FrameBuffer
@param g The green component of the color.
@param b The blue component of the color.
*/
virtual uInt32 mapRGB(uInt8 r, uInt8 g, uInt8 b) const = 0;
uInt32 mapRGB(uInt8 r, uInt8 g, uInt8 b) const {
return myBackend->mapRGB(r, g, b);
}
/**
This method is called to get the specified ARGB data from the viewable
@ -355,88 +346,22 @@ class FrameBuffer
@param pitch The pitch (in bytes) for the pixel data
@param rect The bounding rectangle for the buffer
*/
virtual void readPixels(uInt8* buffer, uInt32 pitch, const Common::Rect& rect) const = 0;
/**
This method is called to query if the current window is not centered or fullscreen.
@return True, if the current window is positioned
*/
virtual bool isCurrentWindowPositioned() const = 0;
/**
This method is called to query the video hardware for position of
the current window
@return The position of the currently displayed window
*/
virtual Common::Point getCurrentWindowPos() const = 0;
/**
This method is called to query the video hardware for the index
of the display the current window is displayed on
@return the current display index or a negative value if no
window is displayed
*/
virtual Int32 getCurrentDisplayIndex() const = 0;
void readPixels(uInt8* buffer, uInt32 pitch, const Common::Rect& rect) const {
myBackend->readPixels(buffer, pitch, rect);
}
/**
Clear the framebuffer.
*/
virtual void clear() = 0;
void clear() { myBackend->clear(); }
/**
Transform from window to renderer coordinates, x direction
Transform from window to renderer coordinates, x/y direction
*/
virtual int scaleX(int x) const { return x; }
/**
Transform from window to renderer coordinates, y direction
*/
virtual int scaleY(int y) const { return y; }
protected:
/**
This method is called to query and initialize the video hardware
for desktop and fullscreen resolution information. Since several
monitors may be attached, we need the resolution for all of them.
@param fullscreenRes Maximum resolution supported in fullscreen mode
@param windowedRes Maximum resolution supported in windowed mode
@param renderers List of renderer names (internal name -> end-user name)
*/
virtual void queryHardware(vector<Common::Size>& fullscreenRes,
vector<Common::Size>& windowedRes,
VariantList& renderers) = 0;
/**
This method is called to change to the given video mode.
@param title The title for the created window
@param mode The video mode to use
@return False on any errors, else true
*/
virtual bool activateVideoMode(const string& title,
const VideoModeHandler::Mode& mode) = 0;
/**
This method is called to create a surface with the given attributes.
@param w The requested width of the new surface.
@param h The requested height of the new surface.
@param interpolation Interpolation mode
@param data If non-null, use the given data values as a static surface
*/
virtual unique_ptr<FBSurface>
createSurface(
uInt32 w,
uInt32 h,
ScalingInterpolation interpolation = ScalingInterpolation::none,
const uInt32* data = nullptr
) const = 0;
int scaleX(int x) const { return myBackend->scaleX(x); }
int scaleY(int y) const { return myBackend->scaleY(y); }
private:
/**
Calls 'free()' on all surfaces that the framebuffer knows about.
*/
@ -447,42 +372,6 @@ class FrameBuffer
*/
void reloadSurfaces();
/**
Grabs or ungrabs the mouse based on the given boolean value.
*/
virtual void grabMouse(bool grab) = 0;
/**
Set the icon for the main window.
*/
virtual void setWindowIcon() = 0;
/**
This method must be called after all drawing is done, and indicates
that the buffers should be pushed to the physical screen.
*/
virtual void renderToScreen() = 0;
/**
This method is called to provide information about the FrameBuffer.
*/
virtual string about() const = 0;
/**
Retrieve the current display's refresh rate
*/
virtual int refreshRate() const { return 0; }
protected:
// The parent system for the framebuffer
OSystem& myOSystem;
private:
// Maximum message width [chars]
static constexpr int MESSAGE_WIDTH = 56;
// Maximum gauge bar width [chars]
static constexpr int GAUGEBAR_WIDTH = 30;
/**
Draw pending messages.
@ -523,22 +412,13 @@ class FrameBuffer
void setupFonts();
#endif
protected:
// Title of the main window/screen
string myScreenTitle;
// Type of the frame buffer
BufferType myBufferType{BufferType::None};
// Number of displays
int myNumDisplays{1};
// The resolution of the attached displays in fullscreen mode
// The primary display is typically the first in the array
// Windowed modes use myDesktopSize directly
vector<Common::Size> myFullscreenDisplays;
private:
// The parent system for the framebuffer
OSystem& myOSystem;
// Backend used for all platform-specific graphics operations
unique_ptr<FBBackend> myBackend;
// Indicates the number of times the framebuffer was initialized
uInt32 myInitializedCount{0};
@ -553,6 +433,11 @@ class FrameBuffer
// Maximum absolute dimensions of the desktop area
Common::Size myAbsDesktopSize;
// The resolution of the attached displays in fullscreen mode
// The primary display is typically the first in the array
// Windowed modes use myDesktopSize directly
vector<Common::Size> myFullscreenDisplays;
// Supported renderers
VariantList myRenderers;
@ -561,6 +446,9 @@ class FrameBuffer
VideoModeHandler myVidModeHandler;
VideoModeHandler::Mode myActiveVidMode;
// Type of the frame buffer
BufferType myBufferType{BufferType::None};
#ifdef GUI_SUPPORT
// The font object to use for the normal in-game GUI
unique_ptr<GUI::Font> myFont;
@ -609,6 +497,11 @@ class FrameBuffer
// Holds a reference to all the surfaces that have been created
vector<shared_ptr<FBSurface>> mySurfaceList;
// Maximum message width [chars]
static constexpr int MESSAGE_WIDTH = 56;
// Maximum gauge bar width [chars]
static constexpr int GAUGEBAR_WIDTH = 30;
FullPaletteArray myFullPalette;
// Holds UI palette data (for each variation)
static UIPaletteArray ourStandardUIPalette, ourClassicUIPalette,

View File

@ -143,10 +143,15 @@ bool OSystem::create()
// Get relevant information about the video hardware
// This must be done before any graphics context is created, since
// it may be needed to initialize the size of graphical objects
try { myFrameBuffer = MediaFactory::createVideo(*this); }
catch(...) { return false; }
if(!myFrameBuffer->initialize())
try
{
myFrameBuffer = make_unique<FrameBuffer>(*this);
myFrameBuffer->initialize();
}
catch(...)
{
return false;
}
// Create the event handler for the system
myEventHandler = MediaFactory::createEventHandler(*this);
@ -722,7 +727,7 @@ string OSystem::getROMInfo(const Console& console)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
float OSystem::frameRate() const
{
return myConsole ? myConsole->getFramerate() : 0;
return myConsole ? myConsole->currentFrameRate() : 0;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -167,7 +167,6 @@ uInt32 TIASurface::mapIndexedPixel(uInt8 indexedColor, uInt8 shift) const
return myPalette[indexedColor | shift];
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void TIASurface::setNTSC(NTSCFilter::Preset preset, bool show)
{
@ -512,13 +511,16 @@ void TIASurface::renderForSnapshot()
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void TIASurface::updateSurfaceSettings()
{
myTiaSurface->setScalingInterpolation(interpolationModeFromSettings(myOSystem.settings()));
myTiaSurface->setScalingInterpolation(
interpolationModeFromSettings(myOSystem.settings())
);
mySLineSurface->setScalingInterpolation(
interpolationModeFromSettings(myOSystem.settings())
);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool TIASurface::correctAspect() const {
bool TIASurface::correctAspect() const
{
return myOSystem.settings().getBool("tia.correct_aspect");
}

View File

@ -67,7 +67,8 @@ class TIASurface
@param rgb_palette The RGB components of the palette, needed for
calculating a phosphor palette
*/
void setPalette(const PaletteArray& tia_palette, const PaletteArray& rgb_palette);
void setPalette(const PaletteArray& tia_palette,
const PaletteArray& rgb_palette);
/**
Get a TIA surface that has no post-processing whatsoever. This is
@ -77,6 +78,11 @@ class TIASurface
*/
const FBSurface& baseSurface(Common::Rect& rect) const;
/**
Get a underlying FBSurface that the TIA is being rendered into.
*/
const FBSurface& tiaSurface() const { return *myTiaSurface; }
/**
Use the palette to map a single indexed pixel color. This is used by the
TIA output widget.

View File

@ -16,25 +16,13 @@
//============================================================================
#include "bspf.hxx"
#include "OSystem.hxx"
#include "AtariNTSC.hxx"
#include "TIAConstants.hxx"
#include "FBSurfaceLIBRETRO.hxx"
#include "FrameBufferLIBRETRO.hxx"
#include "FBBackendLIBRETRO.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FrameBufferLIBRETRO::FrameBufferLIBRETRO(OSystem& osystem)
: FrameBuffer(osystem),
myRenderSurface(nullptr)
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FrameBufferLIBRETRO::queryHardware(vector<Common::Size>& fullscreenRes,
vector<Common::Size>& windowedRes,
VariantList& renderers)
void FBBackendLIBRETRO::queryHardware(vector<Common::Size>& fullscreenRes,
vector<Common::Size>& windowedRes,
VariantList& renderers)
{
fullscreenRes.emplace_back(1920, 1080);
windowedRes.emplace_back(1920, 1080);
@ -43,18 +31,8 @@ void FrameBufferLIBRETRO::queryHardware(vector<Common::Size>& fullscreenRes,
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
unique_ptr<FBSurface>
FrameBufferLIBRETRO::createSurface(uInt32 w, uInt32 h, ScalingInterpolation, const uInt32* data) const
unique_ptr<FBSurface> FBBackendLIBRETRO::createSurface(
uInt32 w, uInt32 h, ScalingInterpolation, const uInt32*) const
{
unique_ptr<FBSurface> ptr = make_unique<FBSurfaceLIBRETRO>
(const_cast<FrameBufferLIBRETRO&>(*this), w, h, data);
if(w == AtariNTSC::outWidth(TIAConstants::frameBufferWidth) &&
h == TIAConstants::frameBufferHeight)
{
uInt32 pitch;
ptr.get()->basePtr(myRenderSurface, pitch);
}
return ptr;
return make_unique<FBSurfaceLIBRETRO>(w, h);
}

View File

@ -0,0 +1,113 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2020 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//============================================================================
#ifndef FB_BACKEND_LIBRETRO_HXX
#define FB_BACKEND_LIBRETRO_HXX
class OSystem;
#include "bspf.hxx"
#include "FBBackend.hxx"
/**
This class implements a standard LIBRETRO backend. Most of the
functionality is not used, since libretro has its own rendering system.
@author Stephen Anthony
*/
class FBBackendLIBRETRO : public FBBackend
{
public:
/**
Creates a new LIBRETRO framebuffer.
*/
explicit FBBackendLIBRETRO(OSystem&) { }
~FBBackendLIBRETRO() override { }
protected:
/**
This method is called to map a given R/G/B triple to the screen palette.
@param r The red component of the color.
@param g The green component of the color.
@param b The blue component of the color.
*/
uInt32 mapRGB(uInt8 r, uInt8 g, uInt8 b) const override {
return (r << 16) | (g << 8) | b;
}
/**
This method is called to query and initialize the video hardware
for desktop and fullscreen resolution information. Since several
monitors may be attached, we need the resolution for all of them.
@param fullscreenRes Maximum resolution supported in fullscreen mode
@param windowedRes Maximum resolution supported in windowed mode
@param renderers List of renderer names (internal name -> end-user name)
*/
void queryHardware(vector<Common::Size>& fullscreenRes,
vector<Common::Size>& windowedRes,
VariantList& renderers) override;
/**
This method is called to create a surface with the given attributes.
@param w The requested width of the new surface.
@param h The requested height of the new surface.
*/
unique_ptr<FBSurface>
createSurface(uInt32 w, uInt32 h, ScalingInterpolation,
const uInt32*) const override;
/**
This method is called to provide information about the backend.
*/
string about() const override { return "Video system: libretro"; }
//////////////////////////////////////////////////////////////////////
// Most methods here aren't used at all. See FBBacked class for
// description, if needed.
//////////////////////////////////////////////////////////////////////
int scaleX(int x) const override { return x; }
int scaleY(int y) const override { return y; }
void setTitle(const string&) override { }
void showCursor(bool) override { }
bool fullScreen() const override { return true; }
void getRGB(uInt32, uInt8*, uInt8*, uInt8*) const override { }
void readPixels(uInt8*, uInt32, const Common::Rect&) const override { }
bool isCurrentWindowPositioned() const override { return true; }
Common::Point getCurrentWindowPos() const override { return Common::Point{}; }
Int32 getCurrentDisplayIndex() const override { return 0; }
void clear() override { }
bool setVideoMode(const VideoModeHandler::Mode&,
int, const Common::Point&) override { return true; }
void grabMouse(bool) override { }
void renderToScreen() override { }
int refreshRate() const override { return 0; }
private:
// Following constructors and assignment operators not supported
FBBackendLIBRETRO() = delete;
FBBackendLIBRETRO(const FBBackendLIBRETRO&) = delete;
FBBackendLIBRETRO(FBBackendLIBRETRO&&) = delete;
FBBackendLIBRETRO& operator=(const FBBackendLIBRETRO&) = delete;
FBBackendLIBRETRO& operator=(FBBackendLIBRETRO&&) = delete;
};
#endif

View File

@ -18,15 +18,7 @@
#include "FBSurfaceLIBRETRO.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FBSurfaceLIBRETRO::FBSurfaceLIBRETRO(FrameBufferLIBRETRO&,
uInt32 width, uInt32 height, const uInt32* data)
{
createSurface(width, height, data);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurfaceLIBRETRO::createSurface(uInt32 width, uInt32 height,
const uInt32* data)
FBSurfaceLIBRETRO::FBSurfaceLIBRETRO(uInt32 width, uInt32 height)
{
myWidth = width;
myHeight = height;
@ -39,9 +31,3 @@ void FBSurfaceLIBRETRO::createSurface(uInt32 width, uInt32 height,
myPitch = width;
////////////////////////////////////////////////////
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool FBSurfaceLIBRETRO::render()
{
return true;
}

View File

@ -20,23 +20,22 @@
#include "bspf.hxx"
#include "FBSurface.hxx"
#include "FrameBufferLIBRETRO.hxx"
/**
An FBSurface suitable for the LIBRETRO Render2D API, making use of hardware
acceleration behind the scenes.
An FBSurface suitable for the LIBRETRO Render2D API. As with FBBackend,
most of the functionality here is handled by libretro directly.
@author Stephen Anthony
*/
class FBSurfaceLIBRETRO : public FBSurface
{
public:
FBSurfaceLIBRETRO(FrameBufferLIBRETRO& buffer, uInt32 width, uInt32 height,
const uInt32* data);
FBSurfaceLIBRETRO(uInt32 width, uInt32 height);
~FBSurfaceLIBRETRO() override { }
// Most of the surface drawing primitives are implemented in FBSurface;
void fillRect(uInt32 x, uInt32 y, uInt32 w, uInt32 h, ColorId color) override { }
void fillRect(uInt32 x, uInt32 y, uInt32 w,
uInt32 h, ColorId color) override { }
uInt32 width() const override { return myWidth; }
uInt32 height() const override { return myHeight; }
@ -50,7 +49,7 @@ class FBSurfaceLIBRETRO : public FBSurface
void setVisible(bool visible) override { }
void translateCoords(Int32& x, Int32& y) const override { }
bool render() override;
bool render() override { return true; }
void invalidate() override { }
void free() override { }
void reload() override { }
@ -61,22 +60,17 @@ class FBSurfaceLIBRETRO : public FBSurface
void applyAttributes() override { }
private:
void createSurface(uInt32 width, uInt32 height, const uInt32* data);
unique_ptr<uInt32[]> myPixelData;
uInt32 myWidth, myHeight;
Common::Rect mySrcGUIR, myDstGUIR;
private:
// Following constructors and assignment operators not supported
FBSurfaceLIBRETRO() = delete;
FBSurfaceLIBRETRO(const FBSurfaceLIBRETRO&) = delete;
FBSurfaceLIBRETRO(FBSurfaceLIBRETRO&&) = delete;
FBSurfaceLIBRETRO& operator=(const FBSurfaceLIBRETRO&) = delete;
FBSurfaceLIBRETRO& operator=(FBSurfaceLIBRETRO&&) = delete;
private:
Common::Rect mySrcGUIR, myDstGUIR;
private:
unique_ptr<uInt32[]> myPixelData;
uInt32 myWidth, myHeight;
};
#endif

View File

@ -1,202 +0,0 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2020 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//============================================================================
#ifndef FRAMEBUFFER_LIBRETRO_HXX
#define FRAMEBUFFER_LIBRETRO_HXX
class OSystem;
class FBSurfaceLIBRETRO;
#include "bspf.hxx"
#include "FrameBuffer.hxx"
/**
This class implements a standard LIBRETRO 2D, hardware accelerated framebuffer.
Behind the scenes, it may be using Direct3D, OpenGL(ES), etc.
@author Stephen Anthony
*/
class FrameBufferLIBRETRO : public FrameBuffer
{
friend class FBSurfaceLIBRETRO;
public:
/**
Creates a new LIBRETRO framebuffer
*/
explicit FrameBufferLIBRETRO(OSystem& osystem);
~FrameBufferLIBRETRO() override { }
//////////////////////////////////////////////////////////////////////
// The following are derived from public methods in FrameBuffer.hxx
//////////////////////////////////////////////////////////////////////
/**
Updates window title.
@param title The title of the application / window
*/
void setTitle(const string& title) override { }
/**
Shows or hides the cursor based on the given boolean value.
*/
void showCursor(bool show) override { }
/**
Answers if the display is currently in fullscreen mode.
*/
bool fullScreen() const override { return true; }
/**
This method is called to retrieve the R/G/B data from the given pixel.
@param pixel The pixel containing R/G/B data
@param r The red component of the color
@param g The green component of the color
@param b The blue component of the color
*/
inline void getRGB(uInt32 pixel, uInt8* r, uInt8* g, uInt8* b) const override { }
/**
This method is called to map a given R/G/B triple to the screen palette.
@param r The red component of the color.
@param g The green component of the color.
@param b The blue component of the color.
*/
inline uInt32 mapRGB(uInt8 r, uInt8 g, uInt8 b) const override { return (r << 16) | (g << 8) | b; }
/**
This method is called to get a copy of the specified ARGB data from the
viewable FrameBuffer area. Note that this isn't the same as any
internal surfaces that may be in use; it should return the actual data
as it is currently seen onscreen.
@param buffer A copy of the pixel data in ARGB8888 format
@param pitch The pitch (in bytes) for the pixel data
@param rect The bounding rectangle for the buffer
*/
void readPixels(uInt8* buffer, uInt32 pitch, const Common::Rect& rect) const override { }
/**
Clear the frame buffer
*/
void clear() override { }
protected:
//////////////////////////////////////////////////////////////////////
// The following are derived from protected methods in FrameBuffer.hxx
//////////////////////////////////////////////////////////////////////
/**
This method is called to query and initialize the video hardware
for desktop and fullscreen resolution information. Since several
monitors may be attached, we need the resolution for all of them.
@param fullscreenRes Maximum resolution supported in fullscreen mode
@param windowedRes Maximum resolution supported in windowed mode
@param renderers List of renderer names (internal name -> end-user name)
*/
void queryHardware(vector<Common::Size>& fullscreenRes,
vector<Common::Size>& windowedRes,
VariantList& renderers) override;
/**
This method is called to query if the current window is not centered or fullscreen.
@return True, if the current window is positioned
*/
bool isCurrentWindowPositioned() const override { return true; }
/**
This method is called to query the video hardware for position of
the current window
@return The position of the currently displayed window
*/
Common::Point getCurrentWindowPos() const override { return Common::Point{}; }
/**
This method is called to query the video hardware for the index
of the display the current window is displayed on
@return the current display index or a negative value if no
window is displayed
*/
Int32 getCurrentDisplayIndex() const override { return 0; }
/**
This method is called to change to the given video mode.
@param title The title for the created window
@param mode The video mode to use
@return False on any errors, else true
*/
bool activateVideoMode(const string& title,
const VideoModeHandler::Mode& mode) override { return true; }
/**
This method is called to create a surface with the given attributes.
@param w The requested width of the new surface.
@param h The requested height of the new surface.
@param data If non-null, use the given data values as a static surface
*/
unique_ptr<FBSurface>
createSurface(uInt32 w, uInt32 h, ScalingInterpolation, const uInt32* data) const override;
/**
Grabs or ungrabs the mouse based on the given boolean value.
*/
void grabMouse(bool grab) override { }
/**
Set the icon for the main SDL window.
*/
void setWindowIcon() override { }
/**
This method is called to provide information about the FrameBuffer.
*/
string about() const override { return "Video system: libretro"; }
/**
This method must be called after all drawing is done, and indicates
that the buffers should be pushed to the physical screen.
*/
void renderToScreen() override { }
public:
/**
Returns a pointer to the output rendering buffer
*/
uInt32* getRenderSurface() const { return myRenderSurface; }
private:
mutable uInt32* myRenderSurface;
private:
// Following constructors and assignment operators not supported
FrameBufferLIBRETRO() = delete;
FrameBufferLIBRETRO(const FrameBufferLIBRETRO&) = delete;
FrameBufferLIBRETRO(FrameBufferLIBRETRO&&) = delete;
FrameBufferLIBRETRO& operator=(const FrameBufferLIBRETRO&) = delete;
FrameBufferLIBRETRO& operator=(FrameBufferLIBRETRO&&) = delete;
};
#endif

View File

@ -9,8 +9,8 @@ SOURCES_CXX := \
$(CORE_DIR)/libretro/libretro.cxx \
$(CORE_DIR)/libretro/EventHandlerLIBRETRO.cxx \
$(CORE_DIR)/libretro/FSNodeLIBRETRO.cxx \
$(CORE_DIR)/libretro/FBBackendLIBRETRO.cxx \
$(CORE_DIR)/libretro/FBSurfaceLIBRETRO.cxx \
$(CORE_DIR)/libretro/FrameBufferLIBRETRO.cxx \
$(CORE_DIR)/libretro/OSystemLIBRETRO.cxx \
$(CORE_DIR)/libretro/SoundLIBRETRO.cxx \
$(CORE_DIR)/libretro/StellaLIBRETRO.cxx \

View File

@ -18,10 +18,10 @@
#include "bspf.hxx"
#include "StellaLIBRETRO.hxx"
#include "SoundLIBRETRO.hxx"
#include "FrameBufferLIBRETRO.hxx"
#include "FBBackendLIBRETRO.hxx"
#include "FBSurfaceLIBRETRO.hxx"
#include "AtariNTSC.hxx"
#include "PaletteHandler.hxx"
#include "AudioSettings.hxx"
#include "Serializer.hxx"
#include "StateManager.hxx"
@ -33,27 +33,7 @@
StellaLIBRETRO::StellaLIBRETRO()
{
audio_buffer = make_unique<Int16[]>(audio_buffer_max);
console_timing = ConsoleTiming::ntsc;
console_format = "AUTO";
video_aspect_ntsc = 0;
video_aspect_pal = 0;
video_palette = PaletteHandler::SETTING_STANDARD;
video_filter = NTSCFilter::Preset::OFF;
video_ready = false;
audio_samples = 0;
audio_mode = "byrom";
video_phosphor = "byrom";
video_phosphor_blend = 60;
phosphor_default = false;
rom_image = make_unique<uInt8[]>(getROMMax());
system_ready = false;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -302,9 +282,16 @@ float StellaLIBRETRO::getVideoAspect() const
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void* StellaLIBRETRO::getVideoBuffer() const
{
FrameBufferLIBRETRO& frame = static_cast<FrameBufferLIBRETRO&>(myOSystem->frameBuffer());
if (!render_surface)
{
const FBSurface& surface =
myOSystem->frameBuffer().tiaSurface().tiaSurface();
return static_cast<void*>(frame.getRenderSurface());
uInt32 pitch = 0;
surface.basePtr(render_surface, pitch);
}
return render_surface;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -29,6 +29,7 @@
#include "EventHandler.hxx"
#include "M6532.hxx"
#include "Paddles.hxx"
#include "PaletteHandler.hxx"
#include "System.hxx"
#include "TIA.hxx"
#include "TIASurface.hxx"
@ -122,7 +123,7 @@ class StellaLIBRETRO
void setAudioStereo(int mode);
void setInputEvent(Event::Type type, Int32 state) {
myOSystem->eventHandler().handleEvent(type, state);
myOSystem->eventHandler().handleEvent(type, state);
}
Controller::Type getLeftControllerType() const {
@ -153,39 +154,40 @@ class StellaLIBRETRO
StellaLIBRETRO& operator=(StellaLIBRETRO&&) = delete;
unique_ptr<OSystemLIBRETRO> myOSystem;
uInt32 system_ready;
uInt32 system_ready{false};
ByteBuffer rom_image;
uInt32 rom_size;
uInt32 rom_size{0};
string rom_path;
ConsoleTiming console_timing;
string console_format;
ConsoleTiming console_timing{ConsoleTiming::ntsc};
string console_format{"AUTO"};
uInt32 render_width, render_height;
mutable uInt32* render_surface{nullptr};
uInt32 render_width{0}, render_height{0};
bool video_ready;
bool video_ready{false};
unique_ptr<Int16[]> audio_buffer;
uInt32 audio_samples;
// (31440 rate / 50 Hz) * 16-bit stereo * 1.25x padding
const uInt32 audio_buffer_max = (31440 / 50 * 4 * 5) / 4;
uInt32 audio_samples{0};
uInt8 system_ram[128];
// (31440 rate / 50 Hz) * 16-bit stereo * 1.25x padding
static constexpr uInt32 audio_buffer_max = (31440 / 50 * 4 * 5) / 4;
private:
string video_palette;
string video_phosphor;
uInt32 video_phosphor_blend;
string video_palette{PaletteHandler::SETTING_STANDARD};
string video_phosphor{"byrom"};
uInt32 video_phosphor_blend{60};
uInt32 video_aspect_ntsc;
uInt32 video_aspect_pal;
NTSCFilter::Preset video_filter;
uInt32 video_aspect_ntsc{0};
uInt32 video_aspect_pal{0};
NTSCFilter::Preset video_filter{NTSCFilter::Preset::OFF};
string audio_mode;
string audio_mode{"byrom"};
bool phosphor_default;
bool phosphor_default{false};
};
#endif

View File

@ -495,9 +495,9 @@
<ClCompile Include="..\common\audio\SimpleResampler.cxx" />
<ClCompile Include="..\common\Base.cxx" />
<ClCompile Include="..\common\EventHandlerSDL2.cxx" />
<ClCompile Include="..\common\FBBackendSDL2.cxx" />
<ClCompile Include="..\common\FBSurfaceSDL2.cxx" />
<ClCompile Include="..\common\FpsMeter.cxx" />
<ClCompile Include="..\common\FrameBufferSDL2.cxx" />
<ClCompile Include="..\common\FSNodeZIP.cxx" />
<ClCompile Include="..\common\JoyMap.cxx" />
<ClCompile Include="..\common\KeyMap.cxx" />
@ -1508,9 +1508,9 @@
<ClInclude Include="..\common\Base.hxx" />
<ClInclude Include="..\common\bspf.hxx" />
<ClInclude Include="..\common\EventHandlerSDL2.hxx" />
<ClInclude Include="..\common\FBBackendSDL2.hxx" />
<ClInclude Include="..\common\FBSurfaceSDL2.hxx" />
<ClInclude Include="..\common\FpsMeter.hxx" />
<ClInclude Include="..\common\FrameBufferSDL2.hxx" />
<ClInclude Include="..\common\FSNodeFactory.hxx" />
<ClInclude Include="..\common\FSNodeZIP.hxx" />
<ClInclude Include="..\common\JoyMap.hxx" />
@ -2060,4 +2060,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
</Project>

View File

@ -72,7 +72,7 @@
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\common\FrameBufferSDL2.cxx">
<ClCompile Include="..\common\FBBackendSDL2.cxx">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="FSNodeWINDOWS.cxx">
@ -1034,7 +1034,7 @@
<ClInclude Include="..\common\bspf.hxx">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\common\FrameBufferSDL2.hxx">
<ClInclude Include="..\common\FBBackendSDL2.hxx">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="HomeFinder.hxx">
@ -2126,4 +2126,4 @@
<Filter>Resource Files</Filter>
</ResourceCompile>
</ItemGroup>
</Project>
</Project>