Merge pull request #21 from audetto/sdlimgui

Integrate Dear ImGui as a renderer over SDL2
This commit is contained in:
Andrea 2021-02-06 17:36:39 +00:00 committed by GitHub
commit f3d5cb3f10
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 505 additions and 72 deletions

View file

@ -28,3 +28,4 @@ matrix:
- libevdev-dev
- libsdl2-dev
- libsdl2-image-dev
- libgles-dev

View file

@ -24,6 +24,7 @@ bool getEmulatorOptions(int argc, const char * argv [], const std::string & edit
("multi-threaded,m", "Multi threaded")
("loose-mutex,l", "Loose mutex")
("sdl-driver", po::value<int>()->default_value(options.sdlDriver), "SDL driver")
("imgui", "Render with Dear ImGui")
("timer-interval,i", po::value<int>()->default_value(options.timerInterval), "Timer interval in ms");
po::options_description configDesc("configuration");
@ -82,6 +83,7 @@ bool getEmulatorOptions(int argc, const char * argv [], const std::string & edit
options.looseMutex = vm.count("loose-mutex");
options.timerInterval = vm["timer-interval"].as<int>();
options.sdlDriver = vm["sdl-driver"].as<int>();
options.imgui = vm.count("imgui");
if (vm.count("config"))
{

View file

@ -36,6 +36,7 @@ struct EmulatorOptions
bool fixedSpeed = false; // default adaptive
int sdlDriver = -1; // default = -1 to let SDL choose
bool imgui = false; // use imgui renderer
std::vector<std::string> registryOptions;
};

View file

@ -1,5 +1,7 @@
include(FindPkgConfig)
add_executable(sa2)
set(SOURCE_FILES
main.cpp
emulator.cpp
@ -7,6 +9,7 @@ set(SOURCE_FILES
sdirectsound.cpp
utils.cpp
sdlframe.cpp
renderer/sdlrendererframe.cpp
)
set(HEADER_FILES
@ -15,11 +18,7 @@ set(HEADER_FILES
sdirectsound.h
utils.h
sdlframe.h
)
add_executable(sa2
${SOURCE_FILES}
${HEADER_FILES}
renderer/sdlrendererframe.h
)
find_package(SDL2 REQUIRED)
@ -39,5 +38,52 @@ target_link_libraries(sa2 PRIVATE
common2
)
target_sources(sa2 PRIVATE
${SOURCE_FILES}
${HEADER_FILES}
)
set(IMGUI_PATH NONE CACHE PATH "path to imgui")
if (EXISTS ${IMGUI_PATH}/imgui.h)
message("Using IMGUI_PATH=${IMGUI_PATH}")
pkg_search_module(GLES2 REQUIRED glesv2)
target_sources(sa2 PRIVATE
imgui/sdlimguiframe.cpp
imgui/image.cpp
imgui/imconfig.h
imgui/gles.h
imgui/image.h
imgui/sdlimguiframe.h
${IMGUI_PATH}/imgui.cpp
${IMGUI_PATH}/imgui_demo.cpp
${IMGUI_PATH}/imgui_draw.cpp
${IMGUI_PATH}/imgui_tables.cpp
${IMGUI_PATH}/imgui_widgets.cpp
${IMGUI_PATH}/backends/imgui_impl_sdl.cpp
${IMGUI_PATH}/backends/imgui_impl_opengl3.cpp
)
target_include_directories(sa2 PRIVATE
${IMGUI_PATH}
${IMGUI_PATH}/backends
)
target_link_libraries(sa2 PRIVATE
${GLES2_LIBRARIES}
)
target_compile_definitions(sa2 PRIVATE
SA2_IMGUI
IMGUI_IMPL_OPENGL_ES2
IMGUI_USER_CONFIG="frontends/sdl/imgui/imconfig.h"
)
else()
message("Bad IMGUI_PATH=${IMGUI_PATH}, skipping imgui code")
endif()
install(TARGETS sa2
DESTINATION bin)

View file

@ -19,6 +19,14 @@ It is possible to run the CPU in a separate thread to keep the emulator running
- ``sa2 -m``
- optionally add ``-l``
## Dear ImGui
Rendering with [Dear ImGui](https://github.com/ocornut/imgui) is possible, although no fancy features are used.
Must be configured in ``cmake`` via the external path ``IMGUI_PATH``, and enabled at runtime with ``--imgui``. It requires a working OpenGL ES2.0 implementation (works on Pi3 and Pi4).
Output mentions the Dear ImGui version, e.g.: ``IMGUI_VERSION: 1.81 WIP``.
## Hotkeys
``F2``, ``F5``, ``F6``, ``F9``, ``F11``, ``F12`` and ``Pause`` have the same meaning as in AppleWin.

View file

@ -0,0 +1,33 @@
#pragma once
#if defined(IMGUI_IMPL_OPENGL_ES2)
// Pi3 with Fake KMS
// "OpenGL ES 2.0 Mesa 19.3.2"
// "Supported versions are: 1.00 ES"
#include <GLES2/gl2.h>
#define SDL_CONTEXT_MAJOR 2
#elif defined(IMGUI_IMPL_OPENGL_ES3)
// Pi4 with Fake KMS
// "OpenGL ES 3.1 Mesa 19.3.2"
// "Supported versions are: 1.00 ES, 3.00 ES, and 3.10 ES"
// On my desktop
// "OpenGL ES 3.1 Mesa 20.2.6"
// "Supported versions are: 1.00 ES, 3.00 ES, and 3.10 ES"
#include <GLES3/gl3.h>
#define SDL_CONTEXT_MAJOR 3
// "310 es" is accepted on a Pi4, but the imgui shaders do not compile
#endif
// this is used in all cases for GL_BGRA_EXT
#include <GLES2/gl2ext.h>
#include "imgui.h"
#include "imgui_impl_sdl.h"
#include "imgui_impl_opengl3.h"

View file

@ -0,0 +1,43 @@
#include "frontends/sdl/imgui/image.h"
#ifdef GL_UNPACK_ROW_LENGTH
// GLES3: defined in gl3.h
#define UGL_UNPACK_LENGTH GL_UNPACK_ROW_LENGTH
#else
// GLES2: defined in gl2ext.h as an extension GL_EXT_unpack_subimage
#define UGL_UNPACK_LENGTH GL_UNPACK_ROW_LENGTH_EXT
#endif
/*
2 extensions are used here
ES2: GL_UNPACK_ROW_LENGTH_EXT and GL_BGRA_EXT
ES3: GL_BGRA_EXT
They both work on Pi3/4 and my Intel Haswell card.
What does SDL do about it?
GL_UNPACK_ROW_LENGTH_EXT: it uses instead texture coordinates
GL_BGRA_EXT: it uses a shader to swap the color bytes
For simplicity (and because it just works) here we are using these 2 extensions.
*/
void LoadTextureFromData(GLuint texture, const uint8_t * data, size_t width, size_t height, size_t pitch)
{
glBindTexture(GL_TEXTURE_2D, texture);
glPixelStorei(UGL_UNPACK_LENGTH, pitch); // in pixels
// Setup filtering parameters for display
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
const GLenum format = GL_BGRA_EXT; // this is defined in gl2ext.h and nowhere in gl3.h
const GLenum type = GL_UNSIGNED_BYTE;
glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, type, data);
// reset to default state
glPixelStorei(UGL_UNPACK_LENGTH, 0);
}

View file

@ -0,0 +1,6 @@
#pragma once
#include <cstddef>
#include "frontends/sdl/imgui/gles.h"
void LoadTextureFromData(GLuint texture, const uint8_t * data, size_t width, size_t height, size_t pitch);

View file

@ -0,0 +1,121 @@
//-----------------------------------------------------------------------------
// COMPILE-TIME OPTIONS FOR DEAR IMGUI
// Runtime options (clipboard callbacks, enabling various features, etc.) can generally be set via the ImGuiIO structure.
// You can use ImGui::SetAllocatorFunctions() before calling ImGui::CreateContext() to rewire memory allocation functions.
//-----------------------------------------------------------------------------
// A) You may edit imconfig.h (and not overwrite it when updating Dear ImGui, or maintain a patch/rebased branch with your modifications to it)
// B) or '#define IMGUI_USER_CONFIG "my_imgui_config.h"' in your project and then add directives in your own file without touching this template.
//-----------------------------------------------------------------------------
// You need to make sure that configuration settings are defined consistently _everywhere_ Dear ImGui is used, which include the imgui*.cpp
// files but also _any_ of your code that uses Dear ImGui. This is because some compile-time options have an affect on data structures.
// Defining those options in imconfig.h will ensure every compilation unit gets to see the same data structure layouts.
// Call IMGUI_CHECKVERSION() from your .cpp files to verify that the data structures your files are using are matching the ones imgui.cpp is using.
//-----------------------------------------------------------------------------
#pragma once
//---- Define assertion handler. Defaults to calling assert().
// If your macro uses multiple statements, make sure is enclosed in a 'do { .. } while (0)' block so it can be used as a single statement.
//#define IM_ASSERT(_EXPR) MyAssert(_EXPR)
//#define IM_ASSERT(_EXPR) ((void)(_EXPR)) // Disable asserts
//---- Define attributes of all API symbols declarations, e.g. for DLL under Windows
// Using dear imgui via a shared library is not recommended, because of function call overhead and because we don't guarantee backward nor forward ABI compatibility.
//#define IMGUI_API __declspec( dllexport )
//#define IMGUI_API __declspec( dllimport )
//---- Don't define obsolete functions/enums/behaviors. Consider enabling from time to time after updating to avoid using soon-to-be obsolete function/names.
//#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS
//---- Disable all of Dear ImGui or don't implement standard windows.
// It is very strongly recommended to NOT disable the demo windows during development. Please read comments in imgui_demo.cpp.
//#define IMGUI_DISABLE // Disable everything: all headers and source files will be empty.
//#define IMGUI_DISABLE_DEMO_WINDOWS // Disable demo windows: ShowDemoWindow()/ShowStyleEditor() will be empty. Not recommended.
//#define IMGUI_DISABLE_METRICS_WINDOW // Disable metrics/debugger window: ShowMetricsWindow() will be empty.
//---- Don't implement some functions to reduce linkage requirements.
//#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS // [Win32] Don't implement default clipboard handler. Won't use and link with OpenClipboard/GetClipboardData/CloseClipboard etc.
//#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] Don't implement default IME handler. Won't use and link with ImmGetContext/ImmSetCompositionWindow.
//#define IMGUI_DISABLE_WIN32_FUNCTIONS // [Win32] Won't use and link with any Win32 function (clipboard, ime).
//#define IMGUI_ENABLE_OSX_DEFAULT_CLIPBOARD_FUNCTIONS // [OSX] Implement default OSX clipboard handler (need to link with '-framework ApplicationServices', this is why this is not the default).
//#define IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS // Don't implement ImFormatString/ImFormatStringV so you can implement them yourself (e.g. if you don't want to link with vsnprintf)
//#define IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS // Don't implement ImFabs/ImSqrt/ImPow/ImFmod/ImCos/ImSin/ImAcos/ImAtan2 so you can implement them yourself.
//#define IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite so you can implement them yourself if you don't want to link with fopen/fclose/fread/fwrite. This will also disable the LogToTTY() function.
//#define IMGUI_DISABLE_DEFAULT_ALLOCATORS // Don't implement default allocators calling malloc()/free() to avoid linking with them. You will need to call ImGui::SetAllocatorFunctions().
//---- Include imgui_user.h at the end of imgui.h as a convenience
//#define IMGUI_INCLUDE_IMGUI_USER_H
//---- Pack colors to BGRA8 instead of RGBA8 (to avoid converting from one to another)
//#define IMGUI_USE_BGRA_PACKED_COLOR
//---- Use 32-bit for ImWchar (default is 16-bit) to support unicode planes 1-16. (e.g. point beyond 0xFFFF like emoticons, dingbats, symbols, shapes, ancient languages, etc...)
//#define IMGUI_USE_WCHAR32
//---- Avoid multiple STB libraries implementations, or redefine path/filenames to prioritize another version
// By default the embedded implementations are declared static and not available outside of Dear ImGui sources files.
//#define IMGUI_STB_TRUETYPE_FILENAME "my_folder/stb_truetype.h"
//#define IMGUI_STB_RECT_PACK_FILENAME "my_folder/stb_rect_pack.h"
//#define IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION
//#define IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION
//---- Use stb_printf's faster implementation of vsnprintf instead of the one from libc (unless IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS is defined)
// Requires 'stb_sprintf.h' to be available in the include path. Compatibility checks of arguments and formats done by clang and GCC will be disabled in order to support the extra formats provided by STB sprintf.
// #define IMGUI_USE_STB_SPRINTF
//---- Use FreeType to build and rasterize the font atlas (instead of stb_truetype which is embedded by default in Dear ImGui)
// Requires FreeType headers to be available in the include path. Requires program to be compiled with 'misc/freetype/imgui_freetype.cpp' (in this repository) + the FreeType library (not provided).
// On Windows you may use vcpkg with 'vcpkg install freetype' + 'vcpkg integrate install'.
//#define IMGUI_ENABLE_FREETYPE
//---- Use stb_truetype to build and rasterize the font atlas (default)
// The only purpose of this define is if you want force compilation of the stb_truetype backend ALONG with the FreeType backend.
//#define IMGUI_ENABLE_STB_TRUETYPE
//---- Define constructor and implicit cast operators to convert back<>forth between your math types and ImVec2/ImVec4.
// This will be inlined as part of ImVec2 and ImVec4 class declarations.
/*
#define IM_VEC2_CLASS_EXTRA \
ImVec2(const MyVec2& f) { x = f.x; y = f.y; } \
operator MyVec2() const { return MyVec2(x,y); }
#define IM_VEC4_CLASS_EXTRA \
ImVec4(const MyVec4& f) { x = f.x; y = f.y; z = f.z; w = f.w; } \
operator MyVec4() const { return MyVec4(x,y,z,w); }
*/
//---- Use 32-bit vertex indices (default is 16-bit) is one way to allow large meshes with more than 64K vertices.
// Your renderer backend will need to support it (most example renderer backends support both 16/32-bit indices).
// Another way to allow large meshes while keeping 16-bit indices is to handle ImDrawCmd::VtxOffset in your renderer.
// Read about ImGuiBackendFlags_RendererHasVtxOffset for details.
//#define ImDrawIdx unsigned int
//---- Override ImDrawCallback signature (will need to modify renderer backends accordingly)
//struct ImDrawList;
//struct ImDrawCmd;
//typedef void (*MyImDrawCallback)(const ImDrawList* draw_list, const ImDrawCmd* cmd, void* my_renderer_user_data);
//#define ImDrawCallback MyImDrawCallback
//---- Debug Tools: Macro to break in Debugger
// (use 'Metrics->Tools->Item Picker' to pick widgets with the mouse and break into them for easy debugging.)
//#define IM_DEBUG_BREAK IM_ASSERT(0)
//#define IM_DEBUG_BREAK __debugbreak()
//---- Debug Tools: Have the Item Picker break in the ItemAdd() function instead of ItemHoverable(),
// (which comes earlier in the code, will catch a few extra items, allow picking items other than Hovered one.)
// This adds a small runtime cost which is why it is not enabled by default.
//#define IMGUI_DEBUG_TOOL_ITEM_PICKER_EX
//---- Debug Tools: Enable slower asserts
//#define IMGUI_DEBUG_PARANOID
//---- Tip: You can add extra functions within the ImGui:: namespace, here or in your own headers files.
/*
namespace ImGui
{
void MyFunction(const char* name, const MyMatrix44& v);
}
*/
// can't easily use GLunit here (defines in gl2/3.h)
#define ImTextureID unsigned int

View file

@ -0,0 +1,105 @@
#include "StdAfx.h"
#include "frontends/sdl/imgui/sdlimguiframe.h"
#include "frontends/sdl/imgui/image.h"
#include "frontends/sdl/utils.h"
#include "Interface.h"
#include "Core.h"
#include <iostream>
SDLImGuiFrame::SDLImGuiFrame()
{
Video & video = GetVideo();
myBorderlessWidth = video.GetFrameBufferBorderlessWidth();
myBorderlessHeight = video.GetFrameBufferBorderlessHeight();
SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, 0);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, SDL_CONTEXT_MAJOR); // from local gles.h
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
// Create window with graphics context
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
SDL_WindowFlags windowFlags = (SDL_WindowFlags)(SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);
myWindow.reset(SDL_CreateWindow(g_pAppTitle.c_str(), SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, myBorderlessWidth, myBorderlessHeight, windowFlags), SDL_DestroyWindow);
if (!myWindow)
{
throw std::runtime_error(SDL_GetError());
}
myGLContext = SDL_GL_CreateContext(myWindow.get());
if (!myGLContext)
{
throw std::runtime_error(SDL_GetError());
}
SDL_GL_MakeCurrent(myWindow.get(), myGLContext);
// Setup Platform/Renderer backends
std::cerr << "IMGUI_VERSION: " << IMGUI_VERSION << std::endl;
std::cerr << "GL_VENDOR: " << glGetString(GL_VENDOR) << std::endl;
std::cerr << "GL_RENDERER: " << glGetString(GL_RENDERER) << std::endl;
std::cerr << "GL_VERSION: " << glGetString(GL_VERSION) << std::endl;
std::cerr << "GL_SHADING_LANGUAGE_VERSION: " << glGetString(GL_SHADING_LANGUAGE_VERSION) << std::endl;
// const char* runtime_gl_extensions = (const char*)glGetString(GL_EXTENSIONS);
// std::cerr << "GL_EXTENSIONS: " << runtime_gl_extensions << std::endl;
// Setup Dear ImGui context
IMGUI_CHECKVERSION();
ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO(); (void)io;
//io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
//io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls
ImGui::StyleColorsDark();
ImGui_ImplSDL2_InitForOpenGL(myWindow.get(), myGLContext);
ImGui_ImplOpenGL3_Init();
glGenTextures(1, &myTexture);
const int width = video.GetFrameBufferWidth();
const size_t borderWidth = video.GetFrameBufferBorderWidth();
const size_t borderHeight = video.GetFrameBufferBorderHeight();
myPitch = width;
myOffset = (width * borderHeight + borderWidth) * sizeof(bgra_t);
}
SDLImGuiFrame::~SDLImGuiFrame()
{
glDeleteTextures(1, &myTexture);
ImGui_ImplOpenGL3_Shutdown();
ImGui_ImplSDL2_Shutdown();
ImGui::DestroyContext();
SDL_GL_DeleteContext(myGLContext);
}
void SDLImGuiFrame::UpdateTexture()
{
LoadTextureFromData(myTexture, myFramebuffer.data() + myOffset, myBorderlessWidth, myBorderlessHeight, myPitch);
}
void SDLImGuiFrame::RenderPresent()
{
ImGui_ImplOpenGL3_NewFrame();
ImGui_ImplSDL2_NewFrame(myWindow.get());
ImGui::NewFrame();
// need to flip the texture vertically
const ImVec2 uv0(0, 1);
const ImVec2 uv1(1, 0);
const ImVec2 zero(0, 0);
// draw on the background
ImGui::GetBackgroundDrawList()->AddImage(myTexture, zero, ImGui::GetIO().DisplaySize, uv0, uv1);
ImGui::Render();
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
SDL_GL_SwapWindow(myWindow.get());
}

View file

@ -0,0 +1,24 @@
#pragma once
#include "frontends/sdl/sdlframe.h"
#include "frontends/sdl/imgui/gles.h"
class SDLImGuiFrame : public SDLFrame
{
public:
SDLImGuiFrame();
~SDLImGuiFrame() override;
void UpdateTexture() override;
void RenderPresent() override;
private:
size_t myPitch;
size_t myOffset;
size_t myBorderlessWidth;
size_t myBorderlessHeight;
SDL_GLContext myGLContext;
ImTextureID myTexture;
};

View file

@ -2,6 +2,7 @@
#include <iostream>
#include <memory>
#include <iomanip>
#include "StdAfx.h"
#include "linux/interface.h"
@ -16,7 +17,12 @@
#include "frontends/sdl/gamepad.h"
#include "frontends/sdl/sdirectsound.h"
#include "frontends/sdl/utils.h"
#include "frontends/sdl/sdlframe.h"
#include "frontends/sdl/renderer/sdlrendererframe.h"
#ifdef SA2_IMGUI
#include "frontends/sdl/imgui/sdlimguiframe.h"
#endif
#include "Core.h"
#include "Log.h"
@ -69,6 +75,8 @@ namespace
void run_sdl(int argc, const char * argv [])
{
std::cerr << std::fixed << std::setprecision(2);
EmulatorOptions options;
options.memclear = g_nMemoryClearType;
const bool run = getEmulatorOptions(argc, argv, "SDL2", options);
@ -76,7 +84,21 @@ void run_sdl(int argc, const char * argv [])
if (!run)
return;
const std::shared_ptr<SDLFrame> frame(new SDLFrame(options));
std::shared_ptr<SDLFrame> frame;
#ifdef SA2_IMGUI
if (options.imgui)
{
frame.reset(new SDLImGuiFrame());
}
else
{
frame.reset(new SDLRendererFrame(options));
}
#else
frame.reset(new SDLRendererFrame(options));
#endif
SetFrame(frame);
if (options.log)

View file

@ -0,0 +1,55 @@
#include "StdAfx.h"
#include "frontends/sdl/renderer/sdlrendererframe.h"
#include "frontends/sdl/utils.h"
#include "frontends/common2/programoptions.h"
#include "Interface.h"
#include "Core.h"
#include <iostream>
SDLRendererFrame::SDLRendererFrame(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();
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)
{
throw std::runtime_error(SDL_GetError());
}
SetApplicationIcon();
myRenderer.reset(SDL_CreateRenderer(myWindow.get(), options.sdlDriver, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC), SDL_DestroyRenderer);
if (!myRenderer)
{
throw std::runtime_error(SDL_GetError());
}
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 = sw;
myRect.h = sw;
myPitch = width * sizeof(bgra_t);
}
void SDLRendererFrame::UpdateTexture()
{
SDL_UpdateTexture(myTexture.get(), nullptr, myFramebuffer.data(), myPitch);
}
void SDLRendererFrame::RenderPresent()
{
SDL_RenderCopyEx(myRenderer.get(), myTexture.get(), &myRect, nullptr, 0.0, nullptr, SDL_FLIP_VERTICAL);
SDL_RenderPresent(myRenderer.get());
}

View file

@ -0,0 +1,21 @@
#pragma once
#include "frontends/sdl/sdlframe.h"
class EmulatorOptions;
class SDLRendererFrame : public SDLFrame
{
public:
SDLRendererFrame(const EmulatorOptions & options);
void UpdateTexture() override;
void RenderPresent() override;
private:
SDL_Rect myRect;
int myPitch;
std::shared_ptr<SDL_Renderer> myRenderer;
std::shared_ptr<SDL_Texture> myTexture;
};

View file

@ -1,56 +1,16 @@
#include "StdAfx.h"
#include "frontends/sdl/sdlframe.h"
#include "frontends/sdl/utils.h"
#include "frontends/common2/programoptions.h"
#include "Interface.h"
#include "Core.h"
#include "Utilities.h"
#include "Log.h"
#include <iostream>
#include <iomanip>
#include <algorithm>
#include <SDL_image.h>
SDLFrame::SDLFrame(const EmulatorOptions & options)
SDLFrame::SDLFrame()
{
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)
@ -72,17 +32,6 @@ void SDLFrame::SetApplicationIcon()
}
}
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();

View file

@ -3,30 +3,23 @@
#include "frontends/common2/commonframe.h"
#include <SDL.h>
class EmulatorOptions;
class SDLFrame : public CommonFrame
{
public:
SDLFrame(const EmulatorOptions & options);
SDLFrame();
void VideoPresentScreen() override;
void FrameRefreshStatus(int drawflags) override;
int FrameMessageBox(LPCSTR lpText, LPCSTR lpCaption, UINT uType) override;
void GetBitmap(LPCSTR lpBitmapName, LONG cb, LPVOID lpvBits) override;
void UpdateTexture();
void RenderPresent();
virtual void UpdateTexture() = 0;
virtual void RenderPresent() = 0;
const std::shared_ptr<SDL_Window> & GetWindow() const;
private:
protected:
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

@ -2,10 +2,12 @@
set -euxo pipefail
wget https://raw.githubusercontent.com/libretro/RetroArch/master/libretro-common/include/libretro.h -P build/libretro-common/include
wget https://raw.githubusercontent.com/libretro/RetroArch/master/libretro-common/include/libretro.h -P libretro-common/include
git clone --depth=1 https://github.com/ocornut/imgui.git
mkdir -p build
cd build
cmake -DCMAKE_BUILD_TYPE=RELEASE -DLIBRETRO_COMMON_PATH=libretro-common ..
cmake -DCMAKE_BUILD_TYPE=RELEASE -DLIBRETRO_COMMON_PATH=../libretro-common -DIMGUI_PATH=../imgui ..
make

View file

@ -10,3 +10,4 @@ libncurses-dev
libevdev-dev
libsdl2-image-dev
libsdl2-dev
libgles-dev