Merge pull request #55 from mihaip/upstreaming

Add Emscripten build target
This commit is contained in:
dingusdev 2023-10-27 12:24:56 -07:00 committed by GitHub
commit 8cad7ee509
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 444 additions and 207 deletions

View File

@ -1,20 +1,23 @@
cmake_minimum_required(VERSION 3.1)
project(dingusppc)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
include(PlatformGlob)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
set(LIBRARY_OUTPUT_PATH ${CMAKE_BINARY_DIR}/lib)
if (NOT WIN32)
if (NOT WIN32 AND NOT EMSCRIPTEN)
find_package(SDL2 REQUIRED)
include_directories(${SDL2_INCLUDE_DIRS})
if (UNIX AND NOT APPLE)
find_package (Threads)
endif()
else() # Windows build relies on vcpkg
elseif (WIN32) # Windows build relies on vcpkg
# pick up system wide vcpkg if exists
if (DEFINED ENV{VCPKG_ROOT} AND EXISTS $ENV{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake)
message(STATUS "Using system vcpkg at $ENV{VCPKG_ROOT}")
@ -40,6 +43,12 @@ else() # Windows build relies on vcpkg
add_compile_definitions(SDL_MAIN_HANDLED)
endif()
if (EMSCRIPTEN)
message(STATUS "Targeting Emscripten")
# loguru tries to include excinfo.h, which is not available under Emscripten.
add_compile_definitions(LOGURU_STACKTRACES=0)
endif()
option(DPPC_BUILD_PPC_TESTS "Build PowerPC tests" OFF)
option(DPPC_BUILD_BENCHMARKS "Build benchmarking programs" OFF)
@ -83,11 +92,12 @@ add_subdirectory("${PROJECT_SOURCE_DIR}/machines/")
add_subdirectory("${PROJECT_SOURCE_DIR}/utils/")
add_subdirectory("${PROJECT_SOURCE_DIR}/thirdparty/loguru/")
set(BUILD_TESTS OFF CACHE BOOL "Build Cubeb tests")
set(BUILD_SHARED_LIBS OFF CACHE BOOL "Build shared libraries")
set(BUILD_TOOLS OFF CACHE BOOL "Build Cubeb tools")
add_subdirectory(thirdparty/cubeb EXCLUDE_FROM_ALL)
if (NOT EMSCRIPTEN)
set(BUILD_TESTS OFF CACHE BOOL "Build Cubeb tests")
set(BUILD_SHARED_LIBS OFF CACHE BOOL "Build shared libraries")
set(BUILD_TOOLS OFF CACHE BOOL "Build Cubeb tools")
add_subdirectory(thirdparty/cubeb EXCLUDE_FROM_ALL)
endif()
set(CLI11_ROOT ${PROJECT_SOURCE_DIR}/thirdparty/CLI11)
@ -101,10 +111,10 @@ include_directories("${PROJECT_SOURCE_DIR}"
"${PROJECT_SOURCE_DIR}/thirdparty/CLI11/"
"${PROJECT_SOURCE_DIR}/thirdparty/cubeb/include")
file(GLOB SOURCES "${PROJECT_SOURCE_DIR}/*.cpp"
"${PROJECT_SOURCE_DIR}/*.c"
"${PROJECT_SOURCE_DIR}/*.hpp"
"${PROJECT_SOURCE_DIR}/*.h")
platform_glob(SOURCES "${PROJECT_SOURCE_DIR}/*.cpp"
"${PROJECT_SOURCE_DIR}/*.c"
"${PROJECT_SOURCE_DIR}/*.hpp"
"${PROJECT_SOURCE_DIR}/*.h")
file(GLOB TEST_SOURCES "${PROJECT_SOURCE_DIR}/cpu/ppc/test/*.cpp")
@ -118,6 +128,16 @@ add_executable(dingusppc ${SOURCES} $<TARGET_OBJECTS:core>
if (WIN32)
target_link_libraries(dingusppc PRIVATE SDL2::SDL2 SDL2::SDL2main cubeb)
elseif (EMSCRIPTEN)
target_link_libraries(dingusppc PRIVATE
${CMAKE_DL_LIBS} ${CMAKE_THREAD_LIBS_INIT}
"-gsource-map"
# 256 MB max for emulated Mac RAM, plus 32 MB of emulator overhead
"-s INITIAL_MEMORY=301989888"
"-s MODULARIZE"
"-s EXPORT_ES6"
"-s EXPORT_NAME=emulator"
"-s 'EXTRA_EXPORTED_RUNTIME_METHODS=[\"FS\"]'")
else()
target_link_libraries(dingusppc PRIVATE SDL2::SDL2 SDL2::SDL2main cubeb
${CMAKE_DL_LIBS} ${CMAKE_THREAD_LIBS_INIT})

21
cmake/PlatformGlob.cmake Normal file
View File

@ -0,0 +1,21 @@
# Detect platform suffix
if (EMSCRIPTEN)
set(PLATFORM_SUFFIX "_js$")
else()
set(PLATFORM_SUFFIX "_sdl|_cubeb$")
endif()
# Function to perform a platform-specific glob
function(platform_glob RESULT_VAR)
set(PLATFORM_SOURCES)
foreach(GLOB_PATTERN ${ARGN})
file(GLOB GLOB_RESULT ${GLOB_PATTERN})
foreach(FILE_PATH ${GLOB_RESULT})
get_filename_component(BASE_NAME ${FILE_PATH} NAME_WE)
if("${BASE_NAME}" MATCHES ${PLATFORM_SUFFIX} OR NOT "${BASE_NAME}" MATCHES "_js$|_sdl|_cubeb$")
list(APPEND PLATFORM_SOURCES ${FILE_PATH})
endif()
endforeach()
endforeach()
set(${RESULT_VAR} ${PLATFORM_SOURCES} PARENT_SCOPE)
endfunction()

View File

@ -2,7 +2,11 @@ include_directories("${PROJECT_SOURCE_DIR}"
"${PROJECT_SOURCE_DIR}/thirdparty/loguru/"
)
file(GLOB SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp")
platform_glob(SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp")
add_library(core OBJECT ${SOURCES})
target_link_libraries(core PRIVATE SDL2::SDL2)
if (EMSCRIPTEN)
target_link_libraries(core PRIVATE)
else()
target_link_libraries(core PRIVATE SDL2::SDL2)
endif()

View File

@ -1,23 +1,30 @@
list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
include(PlatformGlob)
include_directories("${PROJECT_SOURCE_DIR}"
"${PROJECT_SOURCE_DIR}/thirdparty/loguru/"
)
file(GLOB SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/common/*.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/common/adb/*.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/common/i2c/*.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/common/ata/*.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/common/pci/*.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/common/scsi/*.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/ethernet/*.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/floppy/*.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/ioctrl/*.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/memctrl/*.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/serial/*.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/sound/*.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/storage/*.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/video/*.cpp"
platform_glob(SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/common/*.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/common/adb/*.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/common/i2c/*.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/common/ata/*.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/common/pci/*.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/common/scsi/*.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/ethernet/*.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/floppy/*.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/ioctrl/*.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/memctrl/*.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/serial/*.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/sound/*.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/storage/*.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/video/*.cpp"
)
add_library(devices OBJECT ${SOURCES})
target_link_libraries(devices PRIVATE cubeb SDL2::SDL2)
if (EMSCRIPTEN)
target_link_libraries(devices PRIVATE)
else()
target_link_libraries(devices PRIVATE cubeb SDL2::SDL2)
endif()

View File

@ -301,7 +301,7 @@ FloppyImgConverter* open_floppy_image(std::string& img_path)
img_file.open(img_path, std::ios::in | std::ios::binary);
if (img_file.fail()) {
img_file.close();
LOG_F(ERROR, "Could not open specified floppy image!");
LOG_F(ERROR, "Could not open specified floppy image (%s)!", img_path.c_str());
return nullptr;
}

View File

@ -34,25 +34,14 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#ifndef SOUND_SERVER_H
#define SOUND_SERVER_H
#include <cubeb/cubeb.h>
#include <devices/common/hwcomponent.h>
enum {
SND_SERVER_DOWN = 0,
SND_API_READY,
SND_SERVER_UP,
SND_STREAM_OPENED,
SND_STREAM_CLOSED
};
#include <memory>
class SoundServer : public HWComponent {
public:
SoundServer() {
supports_types(HWCompType::SND_SERVER);
this->start();
};
~SoundServer() { this->shutdown(); };
SoundServer();
~SoundServer();
int start();
void shutdown();
@ -61,10 +50,8 @@ public:
void close_out_stream();
private:
int status; /* server status */
cubeb *cubeb_ctx;
cubeb_stream *out_stream;
class Impl; // Holds private fields
std::unique_ptr<Impl> impl;
};
#endif /* SOUND_SERVER_H */

View File

@ -29,60 +29,87 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <objbase.h>
#endif
enum {
SND_SERVER_DOWN = 0,
SND_API_READY,
SND_SERVER_UP,
SND_STREAM_OPENED,
SND_STREAM_CLOSED
};
class SoundServer::Impl {
public:
int status; /* server status */
cubeb *cubeb_ctx;
cubeb_stream *out_stream;
};
SoundServer::SoundServer(): impl(std::make_unique<Impl>())
{
supports_types(HWCompType::SND_SERVER);
this->start();
}
SoundServer::~SoundServer()
{
this->shutdown();
}
#if 0
int SoundServer::start()
{
int err;
this->status = SND_SERVER_DOWN;
impl->status = SND_SERVER_DOWN;
this->soundio = soundio_create();
if (!this->soundio) {
impl->soundio = soundio_create();
if (!impl->soundio) {
LOG_F(ERROR, "Sound Server: out of memory");
return -1;
}
if ((err = soundio_connect(this->soundio))) {
if ((err = soundio_connect(impl->soundio))) {
LOG_F(ERROR, "Unable to connect to backend: %s", soundio_strerror(err));
return -1;
}
LOG_F(INFO, "Connected to backend: %s", soundio_backend_name(soundio->current_backend));
soundio_flush_events(this->soundio);
soundio_flush_events(impl->soundio);
this->status = SND_API_READY;
impl->status = SND_API_READY;
this->out_dev_index = soundio_default_output_device_index(this->soundio);
if (this->out_dev_index < 0) {
impl->out_dev_index = soundio_default_output_device_index(impl->soundio);
if (impl->out_dev_index < 0) {
LOG_F(ERROR, "Sound Server: no output device found");
return -1;
}
this->out_device = soundio_get_output_device(this->soundio, this->out_dev_index);
if (!this->out_device) {
impl->out_device = soundio_get_output_device(this->soundio, this->out_dev_index);
if (!impl->out_device) {
LOG_F(ERROR, "Sound Server: out of memory");
return -1;
}
LOG_F(INFO, "Sound Server output device: %s", this->out_device->name);
LOG_F(INFO, "Sound Server output device: %s", impl->out_device->name);
this->status = SND_SERVER_UP;
impl->status = SND_SERVER_UP;
return 0;
}
void SoundServer::shutdown()
{
switch (this->status) {
switch (impl->status) {
case SND_SERVER_UP:
soundio_device_unref(this->out_device);
soundio_device_unref(impl->out_device);
/* fall through */
case SND_API_READY:
soundio_destroy(this->soundio);
soundio_destroy(impl->soundio);
}
this->status = SND_SERVER_DOWN;
impl->status = SND_SERVER_DOWN;
LOG_F(INFO, "Sound Server shut down.");
}
@ -96,24 +123,24 @@ int SoundServer::start()
CoInitialize(nullptr);
#endif
this->status = SND_SERVER_DOWN;
impl->status = SND_SERVER_DOWN;
res = cubeb_init(&this->cubeb_ctx, "Dingus sound server", NULL);
res = cubeb_init(&impl->cubeb_ctx, "Dingus sound server", NULL);
if (res != CUBEB_OK) {
LOG_F(ERROR, "Could not initialize Cubeb library");
return -1;
}
LOG_F(INFO, "Connected to backend: %s", cubeb_get_backend_id(this->cubeb_ctx));
LOG_F(INFO, "Connected to backend: %s", cubeb_get_backend_id(impl->cubeb_ctx));
this->status = SND_API_READY;
impl->status = SND_API_READY;
return 0;
}
void SoundServer::shutdown()
{
switch (this->status) {
switch (impl->status) {
case SND_STREAM_OPENED:
close_out_stream();
/* fall through */
@ -122,10 +149,10 @@ void SoundServer::shutdown()
case SND_SERVER_UP:
/* fall through */
case SND_API_READY:
cubeb_destroy(this->cubeb_ctx);
cubeb_destroy(impl->cubeb_ctx);
}
this->status = SND_SERVER_DOWN;
impl->status = SND_SERVER_DOWN;
LOG_F(INFO, "Sound Server shut down.");
}
@ -189,7 +216,7 @@ int SoundServer::open_out_stream(uint32_t sample_rate, void *user_data)
params.layout = CUBEB_LAYOUT_STEREO;
params.prefs = CUBEB_STREAM_PREF_NONE;
res = cubeb_get_min_latency(this->cubeb_ctx, &params, &latency_frames);
res = cubeb_get_min_latency(impl->cubeb_ctx, &params, &latency_frames);
if (res != CUBEB_OK) {
LOG_F(ERROR, "Could not get minimum latency, error: %d", res);
return -1;
@ -197,7 +224,7 @@ int SoundServer::open_out_stream(uint32_t sample_rate, void *user_data)
LOG_F(9, "Minimum sound latency: %d frames", latency_frames);
}
res = cubeb_stream_init(this->cubeb_ctx, &this->out_stream, "SndOut stream",
res = cubeb_stream_init(impl->cubeb_ctx, &impl->out_stream, "SndOut stream",
NULL, NULL, NULL, &params, latency_frames,
sound_out_callback, status_callback, user_data);
if (res != CUBEB_OK) {
@ -207,20 +234,20 @@ int SoundServer::open_out_stream(uint32_t sample_rate, void *user_data)
LOG_F(9, "Sound output stream opened.");
this->status = SND_STREAM_OPENED;
impl->status = SND_STREAM_OPENED;
return 0;
}
int SoundServer::start_out_stream()
{
return cubeb_stream_start(this->out_stream);
return cubeb_stream_start(impl->out_stream);
}
void SoundServer::close_out_stream()
{
cubeb_stream_stop(this->out_stream);
cubeb_stream_destroy(this->out_stream);
this->status = SND_STREAM_CLOSED;
cubeb_stream_stop(impl->out_stream);
cubeb_stream_destroy(impl->out_stream);
impl->status = SND_STREAM_CLOSED;
LOG_F(9, "Sound output stream closed.");
}

53
devices/video/display.h Normal file
View File

@ -0,0 +1,53 @@
/*
DingusPPC - The Experimental PowerPC Macintosh emulator
Copyright (C) 2018-23 divingkatae and maximum
(theweirdo) spatium
(Contact divingkatae#1017 or powermax#2286 on Discord for more info)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
/** @file Display/screen abstraction (implemented on each platform). */
#ifndef DISPLAY_H
#define DISPLAY_H
#include <core/hostevents.h>
#include <functional>
#include <memory>
class Display {
public:
Display();
~Display();
// Configures the display for the given width/height.
// Returns true if this is the first time the screen has been configured.
bool configure(int width, int height);
// Clears the display
void blank();
void update(std::function<void(uint8_t *dst_buf, int dst_pitch)> convert_fb_cb, bool draw_hw_cursor, int cursor_x, int cursor_y);
void handle_events(const WindowEvent& wnd_event);
void setup_hw_cursor(std::function<void(uint8_t *dst_buf, int dst_pitch)> draw_hw_cursor, int cursor_width, int cursor_height);
private:
class Impl; // Holds private fields
std::unique_ptr<Impl> impl;
};
#endif // DISPLAY_H

View File

@ -0,0 +1,157 @@
#include <devices/video/display.h>
#include <SDL.h>
#include <loguru.hpp>
class Display::Impl {
public:
bool resizing = false;
uint32_t disp_wnd_id = 0;
SDL_Window* display_wnd = 0;
SDL_Renderer* renderer = 0;
SDL_Texture* disp_texture = 0;
SDL_Texture* cursor_texture = 0;
SDL_Rect cursor_rect; // destination rectangle for cursor drawing
};
Display::Display(): impl(std::make_unique<Impl>())
{
}
Display::~Display()
{
if (impl->cursor_texture) {
SDL_DestroyTexture(impl->cursor_texture);
}
if (impl->disp_texture) {
SDL_DestroyTexture(impl->disp_texture);
}
if (impl->renderer) {
SDL_DestroyRenderer(impl->renderer);
}
if (impl->display_wnd) {
SDL_DestroyWindow(impl->display_wnd);
}
}
bool Display::configure(int width, int height)
{
bool is_initialization = false;
if (!impl->display_wnd) { // create display window
impl->display_wnd = SDL_CreateWindow(
"DingusPPC Display",
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
width, height,
SDL_WINDOW_OPENGL
);
impl->disp_wnd_id = SDL_GetWindowID(impl->display_wnd);
if (impl->display_wnd == NULL) {
ABORT_F("Display: SDL_CreateWindow failed with %s", SDL_GetError());
}
impl->renderer = SDL_CreateRenderer(impl->display_wnd, -1, SDL_RENDERER_ACCELERATED);
if (impl->renderer == NULL) {
ABORT_F("Display: SDL_CreateRenderer failed with %s", SDL_GetError());
}
is_initialization = true;
} else { // resize display window
SDL_SetWindowSize(impl->display_wnd, width, height);
impl->resizing = true;
}
if (impl->disp_texture) {
SDL_DestroyTexture(impl->disp_texture);
}
impl->disp_texture = SDL_CreateTexture(
impl->renderer,
SDL_PIXELFORMAT_ARGB8888,
SDL_TEXTUREACCESS_STREAMING,
width, height
);
if (impl->disp_texture == NULL) {
ABORT_F("Display: SDL_CreateTexture failed with %s", SDL_GetError());
}
return is_initialization;
}
void Display::handle_events(const WindowEvent& wnd_event)
{
if (wnd_event.sub_type == SDL_WINDOWEVENT_SIZE_CHANGED &&
wnd_event.window_id == impl->disp_wnd_id)
impl->resizing = false;
}
void Display::blank()
{
SDL_SetRenderDrawColor(impl->renderer, 0, 0, 0, 255);
SDL_RenderClear(impl->renderer);
SDL_RenderPresent(impl->renderer);
}
void Display::update(std::function<void(uint8_t *dst_buf, int dst_pitch)> convert_fb_cb, bool draw_hw_cursor, int cursor_x, int cursor_y)
{
if (impl->resizing)
return;
uint8_t* dst_buf;
int dst_pitch;
SDL_LockTexture(impl->disp_texture, NULL, (void **)&dst_buf, &dst_pitch);
// texture update callback to get ARGB data from guest framebuffer
convert_fb_cb(dst_buf, dst_pitch);
SDL_UnlockTexture(impl->disp_texture);
SDL_RenderClear(impl->renderer);
SDL_RenderCopy(impl->renderer, impl->disp_texture, NULL, NULL);
// draw HW cursor if enabled
if (draw_hw_cursor) {
impl->cursor_rect.x = cursor_x;
impl->cursor_rect.y = cursor_y;
SDL_RenderCopy(impl->renderer, impl->cursor_texture, NULL, &impl->cursor_rect);
}
SDL_RenderPresent(impl->renderer);
}
void Display::setup_hw_cursor(std::function<void(uint8_t *dst_buf, int dst_pitch)> draw_hw_cursor, int cursor_width, int cursor_height)
{
uint8_t* dst_buf;
int dst_pitch;
if (impl->cursor_texture) {
SDL_DestroyTexture(impl->cursor_texture);
}
impl->cursor_texture = SDL_CreateTexture(
impl->renderer,
SDL_PIXELFORMAT_ARGB8888,
SDL_TEXTUREACCESS_STREAMING,
cursor_width, cursor_height
);
if (impl->cursor_texture == NULL) {
ABORT_F("SDL_CreateTexture for HW cursor failed with %s", SDL_GetError());
}
SDL_LockTexture(impl->cursor_texture, NULL, (void **)&dst_buf, &dst_pitch);
SDL_SetTextureBlendMode(impl->cursor_texture, SDL_BLENDMODE_BLEND);
draw_hw_cursor(dst_buf, dst_pitch);
SDL_UnlockTexture(impl->cursor_texture);
impl->cursor_rect.x = 0;
impl->cursor_rect.y = 0;
impl->cursor_rect.w = cursor_width;
impl->cursor_rect.h = cursor_height;
}

View File

@ -23,11 +23,8 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <core/timermanager.h>
#include <devices/video/videoctrl.h>
#include <loguru.hpp>
#include <memaccess.h>
#include <SDL.h>
#include <chrono>
#include <cinttypes>
VideoCtrlBase::VideoCtrlBase(int width, int height)
@ -39,115 +36,45 @@ VideoCtrlBase::VideoCtrlBase(int width, int height)
VideoCtrlBase::~VideoCtrlBase()
{
if (this->cursor_texture) {
SDL_DestroyTexture(this->cursor_texture);
}
if (this->disp_texture) {
SDL_DestroyTexture(this->disp_texture);
}
if (this->renderer) {
SDL_DestroyRenderer(this->renderer);
}
if (this->display_wnd) {
SDL_DestroyWindow(this->display_wnd);
}
}
void VideoCtrlBase::handle_events(const WindowEvent& wnd_event) {
if (wnd_event.sub_type == SDL_WINDOWEVENT_SIZE_CHANGED &&
wnd_event.window_id == this->disp_wnd_id)
this->resizing = false;
this->display.handle_events(wnd_event);
}
// TODO: consider renaming, since it's not always a window
void VideoCtrlBase::create_display_window(int width, int height)
{
if (!this->display_wnd) { // create display window
this->display_wnd = SDL_CreateWindow(
"DingusPPC Display",
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
width, height,
SDL_WINDOW_OPENGL
);
this->disp_wnd_id = SDL_GetWindowID(this->display_wnd);
if (this->display_wnd == NULL) {
ABORT_F("Display: SDL_CreateWindow failed with %s", SDL_GetError());
}
this->renderer = SDL_CreateRenderer(this->display_wnd, -1, SDL_RENDERER_ACCELERATED);
if (this->renderer == NULL) {
ABORT_F("Display: SDL_CreateRenderer failed with %s", SDL_GetError());
}
bool is_initialization = this->display.configure(width, height);
if (is_initialization) {
this->blank_on = true; // TODO: should be true!
this->blank_display();
} else { // resize display window
SDL_SetWindowSize(this->display_wnd, width, height);
this->resizing = true;
}
this->active_width = width;
this->active_height = height;
if (this->disp_texture) {
SDL_DestroyTexture(this->disp_texture);
}
this->disp_texture = SDL_CreateTexture(
this->renderer,
SDL_PIXELFORMAT_ARGB8888,
SDL_TEXTUREACCESS_STREAMING,
width, height
);
if (this->disp_texture == NULL) {
ABORT_F("Display: SDL_CreateTexture failed with %s", SDL_GetError());
}
}
void VideoCtrlBase::blank_display() {
SDL_SetRenderDrawColor(this->renderer, 0, 0, 0, 255);
SDL_RenderClear(this->renderer);
SDL_RenderPresent(this->renderer);
this->display.blank();
}
void VideoCtrlBase::update_screen()
{
uint8_t* dst_buf;
int dst_pitch;
//auto start_time = std::chrono::steady_clock::now();
if (this->resizing)
return;
if (this->blank_on) {
this->blank_display();
this->display.blank();
return;
}
SDL_LockTexture(this->disp_texture, NULL, (void **)&dst_buf, &dst_pitch);
// texture update callback to get ARGB data from guest framebuffer
this->convert_fb_cb(dst_buf, dst_pitch);
SDL_UnlockTexture(this->disp_texture);
SDL_RenderClear(this->renderer);
SDL_RenderCopy(this->renderer, this->disp_texture, NULL, NULL);
// draw HW cursor if enabled
int cursor_x = 0;
int cursor_y = 0;
if (this->cursor_on) {
this->get_cursor_position(cursor_rect.x, cursor_rect.y);
SDL_RenderCopy(this->renderer, this->cursor_texture, NULL, &cursor_rect);
this->get_cursor_position(cursor_x, cursor_y);
}
SDL_RenderPresent(this->renderer);
this->display.update(
this->convert_fb_cb,
this->cursor_on, cursor_x, cursor_y);
}
void VideoCtrlBase::start_refresh_task() {
@ -200,34 +127,11 @@ void VideoCtrlBase::set_palette_color(uint8_t index, uint8_t r, uint8_t g, uint8
void VideoCtrlBase::setup_hw_cursor(int cursor_width, int cursor_height)
{
uint8_t* dst_buf;
int dst_pitch;
if (this->cursor_texture) {
SDL_DestroyTexture(this->cursor_texture);
}
this->cursor_texture = SDL_CreateTexture(
this->renderer,
SDL_PIXELFORMAT_ARGB8888,
SDL_TEXTUREACCESS_STREAMING,
cursor_width, cursor_height
);
if (this->cursor_texture == NULL) {
ABORT_F("SDL_CreateTexture for HW cursor failed with %s", SDL_GetError());
}
SDL_LockTexture(this->cursor_texture, NULL, (void **)&dst_buf, &dst_pitch);
SDL_SetTextureBlendMode(this->cursor_texture, SDL_BLENDMODE_BLEND);
this->draw_hw_cursor(dst_buf, dst_pitch);
SDL_UnlockTexture(this->cursor_texture);
this->cursor_rect.x = 0;
this->cursor_rect.y = 0;
this->cursor_rect.w = cursor_width;
this->cursor_rect.h = cursor_height;
this->display.setup_hw_cursor(
[this](uint8_t *dst_buf, int dst_pitch) {
this->draw_hw_cursor(dst_buf, dst_pitch);
},
cursor_width, cursor_height);
this->cursor_on = true;
}

View File

@ -26,7 +26,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <core/hostevents.h>
#include <devices/common/hwinterrupt.h>
#include <SDL.h>
#include <devices/video/display.h>
#include <cinttypes>
#include <functional>
@ -61,7 +61,6 @@ protected:
// CRT controller parameters
bool crtc_on = false;
bool blank_on = true;
bool resizing = false;
bool cursor_on = false;
int active_width; // width of the visible display area
int active_height; // height of the visible display area
@ -88,12 +87,7 @@ protected:
std::function<void(uint8_t *dst_buf, int dst_pitch)> convert_fb_cb;
private:
uint32_t disp_wnd_id = 0;
SDL_Window* display_wnd = 0;
SDL_Renderer* renderer = 0;
SDL_Texture* disp_texture = 0;
SDL_Texture* cursor_texture = 0;
SDL_Rect cursor_rect; // destination rectangle for cursor drawing
Display display;
};
#endif // VIDEO_CTRL_H

View File

@ -7,4 +7,4 @@ include_directories("${PROJECT_SOURCE_DIR}"
file(GLOB SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp")
add_library(machines OBJECT ${SOURCES})
target_link_libraries(machines PRIVATE cubeb SDL2::SDL2)
target_link_libraries(machines PRIVATE)

View File

@ -29,6 +29,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <machines/machinefactory.h>
#include <machines/machineproperties.h>
#include <utils/profiler.h>
#include <main.h>
#include <cinttypes>
#include <csignal>
@ -38,7 +39,6 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <sstream>
#include <stdio.h>
#include <CLI11.hpp>
#include <SDL.h>
#include <loguru.hpp>
using namespace std;
@ -49,7 +49,7 @@ void sigint_handler(int signum) {
LOG_F(INFO, "Shutting down...");
delete gMachineObj.release();
SDL_Quit();
cleanup();
exit(0);
}
@ -57,7 +57,7 @@ void sigabrt_handler(int signum) {
LOG_F(INFO, "Shutting down...");
delete gMachineObj.release();
SDL_Quit();
cleanup();
}
static string appDescription = string(
@ -166,8 +166,8 @@ int main(int argc, char** argv) {
cout << "BootROM path: " << bootrom_path << endl;
cout << "Execution mode: " << execution_mode << endl;
if (SDL_Init(SDL_INIT_VIDEO)) {
LOG_F(ERROR, "SDL_Init error: %s", SDL_GetError());
if (!init()) {
LOG_F(ERROR, "Cannot initialize");
return 1;
}
@ -217,7 +217,7 @@ bail:
delete gMachineObj.release();
SDL_Quit();
cleanup();
return 0;
}

25
main.h Normal file
View File

@ -0,0 +1,25 @@
/*
DingusPPC - The Experimental PowerPC Macintosh emulator
Copyright (C) 2018-23 divingkatae and maximum
(theweirdo) spatium
(Contact divingkatae#1017 or powermax#2286 on Discord for more info)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
/** @file Platform-specific main functions. */
bool init();
void cleanup();

38
main_sdl.cpp Normal file
View File

@ -0,0 +1,38 @@
/*
DingusPPC - The Experimental PowerPC Macintosh emulator
Copyright (C) 2018-23 divingkatae and maximum
(theweirdo) spatium
(Contact divingkatae#1017 or powermax#2286 on Discord for more info)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
/** @file SDL-specific main functions. */
#include <main.h>
#include <loguru.hpp>
#include <SDL.h>
bool init() {
if (SDL_Init(SDL_INIT_VIDEO)) {
LOG_F(ERROR, "SDL_Init error: %s", SDL_GetError());
return false;
}
return true;
}
void cleanup() {
SDL_Quit();
}

View File

@ -3,4 +3,4 @@ include_directories("${PROJECT_SOURCE_DIR}")
file(GLOB SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp")
add_library(utils OBJECT ${SOURCES})
target_link_libraries(utils PRIVATE cubeb)
target_link_libraries(utils PRIVATE)