diff --git a/CMakeLists.txt b/CMakeLists.txt index 66f27d0..c54fe88 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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}") @@ -89,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) @@ -107,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") @@ -125,7 +129,7 @@ add_executable(dingusppc ${SOURCES} $ if (WIN32) target_link_libraries(dingusppc PRIVATE SDL2::SDL2 SDL2::SDL2main cubeb) elseif (EMSCRIPTEN) - target_link_libraries(dingusppc PRIVATE SDL2::SDL2 SDL2::SDL2main cubeb + 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 diff --git a/cmake/PlatformGlob.cmake b/cmake/PlatformGlob.cmake new file mode 100644 index 0000000..11b3b03 --- /dev/null +++ b/cmake/PlatformGlob.cmake @@ -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() diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index c109240..8b02212 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -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() diff --git a/core/hostevents.cpp b/core/hostevents_sdl.cpp similarity index 100% rename from core/hostevents.cpp rename to core/hostevents_sdl.cpp diff --git a/devices/CMakeLists.txt b/devices/CMakeLists.txt index 3639478..4cb4fd2 100644 --- a/devices/CMakeLists.txt +++ b/devices/CMakeLists.txt @@ -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() diff --git a/devices/floppy/floppyimg.cpp b/devices/floppy/floppyimg.cpp index 69c0343..59ab541 100644 --- a/devices/floppy/floppyimg.cpp +++ b/devices/floppy/floppyimg.cpp @@ -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; } diff --git a/devices/sound/soundserver.h b/devices/sound/soundserver.h index 2b0dd7a..cd74e99 100644 --- a/devices/sound/soundserver.h +++ b/devices/sound/soundserver.h @@ -34,25 +34,14 @@ along with this program. If not, see . #ifndef SOUND_SERVER_H #define SOUND_SERVER_H -#include #include -enum { - SND_SERVER_DOWN = 0, - SND_API_READY, - SND_SERVER_UP, - SND_STREAM_OPENED, - SND_STREAM_CLOSED -}; - +#include 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; }; #endif /* SOUND_SERVER_H */ diff --git a/devices/sound/soundserver.cpp b/devices/sound/soundserver_cubeb.cpp similarity index 72% rename from devices/sound/soundserver.cpp rename to devices/sound/soundserver_cubeb.cpp index ebcd2a9..fc22805 100644 --- a/devices/sound/soundserver.cpp +++ b/devices/sound/soundserver_cubeb.cpp @@ -29,60 +29,87 @@ along with this program. If not, see . #include #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()) +{ + 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, ¶ms, &latency_frames); + res = cubeb_get_min_latency(impl->cubeb_ctx, ¶ms, &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, ¶ms, 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."); } diff --git a/devices/video/display.h b/devices/video/display.h new file mode 100644 index 0000000..435b329 --- /dev/null +++ b/devices/video/display.h @@ -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 . +*/ + +/** @file Display/screen abstraction (implemented on each platform). */ + +#ifndef DISPLAY_H +#define DISPLAY_H + +#include + +#include +#include + +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 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 draw_hw_cursor, int cursor_width, int cursor_height); +private: + class Impl; // Holds private fields + std::unique_ptr impl; +}; + +#endif // DISPLAY_H diff --git a/devices/video/display_sdl.cpp b/devices/video/display_sdl.cpp new file mode 100644 index 0000000..4655c5d --- /dev/null +++ b/devices/video/display_sdl.cpp @@ -0,0 +1,157 @@ +#include +#include +#include + +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()) +{ + +} + +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 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 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; +} diff --git a/devices/video/videoctrl.cpp b/devices/video/videoctrl.cpp index eaa91c0..1ea902f 100644 --- a/devices/video/videoctrl.cpp +++ b/devices/video/videoctrl.cpp @@ -23,11 +23,8 @@ along with this program. If not, see . #include #include -#include #include -#include -#include #include 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; } diff --git a/devices/video/videoctrl.h b/devices/video/videoctrl.h index 6ccb51b..6442fe8 100644 --- a/devices/video/videoctrl.h +++ b/devices/video/videoctrl.h @@ -26,7 +26,7 @@ along with this program. If not, see . #include #include -#include +#include #include #include @@ -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 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 diff --git a/machines/CMakeLists.txt b/machines/CMakeLists.txt index 9c71b2d..92a4ac7 100644 --- a/machines/CMakeLists.txt +++ b/machines/CMakeLists.txt @@ -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) diff --git a/main.cpp b/main.cpp index b85ea22..dad9947 100644 --- a/main.cpp +++ b/main.cpp @@ -29,6 +29,7 @@ along with this program. If not, see . #include #include #include +#include #include #include @@ -38,7 +39,6 @@ along with this program. If not, see . #include #include #include -#include #include 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; } diff --git a/main.h b/main.h new file mode 100644 index 0000000..609e695 --- /dev/null +++ b/main.h @@ -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 . +*/ + +/** @file Platform-specific main functions. */ + +bool init(); +void cleanup(); diff --git a/main_sdl.cpp b/main_sdl.cpp new file mode 100644 index 0000000..69e93d9 --- /dev/null +++ b/main_sdl.cpp @@ -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 . +*/ + +/** @file SDL-specific main functions. */ + +#include +#include +#include + +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(); +} diff --git a/utils/CMakeLists.txt b/utils/CMakeLists.txt index 0866e1e..6010b1f 100644 --- a/utils/CMakeLists.txt +++ b/utils/CMakeLists.txt @@ -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)