Moved window event handling out of gfx thread so resizing doesn't freeze gameplay, added full document hot reloading for UI
This commit is contained in:
parent
458ccd81fc
commit
346e298eb1
|
@ -64,7 +64,7 @@ typedef struct {
|
|||
//DLLEXPORT void (CALL *PumpEvents)(void) = nullptr;
|
||||
|
||||
#if defined(_WIN32)
|
||||
extern "C" int InitiateGFXWindows(GFX_INFO Gfx_Info, HWND hwnd);
|
||||
extern "C" int InitiateGFXWindows(GFX_INFO Gfx_Info, HWND hwnd, DWORD threadId);
|
||||
#elif defined(__ANDROID__)
|
||||
static_assert(false && "Unimplemented");
|
||||
#elif defined(__linux__)
|
||||
|
|
|
@ -6,10 +6,8 @@ static uint32_t sample_rate = 48000;
|
|||
|
||||
static Multilibultra::audio_callbacks_t audio_callbacks;
|
||||
|
||||
void Multilibultra::set_audio_callbacks(const audio_callbacks_t* callbacks) {
|
||||
if (callbacks != nullptr) {
|
||||
audio_callbacks = *callbacks;
|
||||
}
|
||||
void set_audio_callbacks(const Multilibultra::audio_callbacks_t& callbacks) {
|
||||
audio_callbacks = callbacks;
|
||||
}
|
||||
|
||||
void Multilibultra::init_audio() {
|
||||
|
|
|
@ -236,14 +236,6 @@ void task_thread_func(uint8_t* rdram, uint8_t* rom, std::atomic_flag* thread_rea
|
|||
}
|
||||
}
|
||||
|
||||
static Multilibultra::gfx_callbacks_t gfx_callbacks;
|
||||
|
||||
void Multilibultra::set_gfx_callbacks(const gfx_callbacks_t* callbacks) {
|
||||
if (callbacks != nullptr) {
|
||||
gfx_callbacks = *callbacks;
|
||||
}
|
||||
}
|
||||
|
||||
void gfx_thread_func(uint8_t* rdram, uint8_t* rom, std::atomic_flag* thread_ready, Multilibultra::WindowHandle window_handle) {
|
||||
using namespace std::chrono_literals;
|
||||
Multilibultra::gfx_callbacks_t::gfx_data_t gfx_data{};
|
||||
|
@ -251,14 +243,6 @@ void gfx_thread_func(uint8_t* rdram, uint8_t* rom, std::atomic_flag* thread_read
|
|||
Multilibultra::set_native_thread_name("Gfx Thread");
|
||||
Multilibultra::set_native_thread_priority(Multilibultra::ThreadPriority::Normal);
|
||||
|
||||
if (gfx_callbacks.create_gfx != nullptr) {
|
||||
gfx_data = gfx_callbacks.create_gfx();
|
||||
}
|
||||
|
||||
if (gfx_callbacks.create_window != nullptr) {
|
||||
window_handle = gfx_callbacks.create_window(gfx_data);
|
||||
}
|
||||
|
||||
RT64Init(rom, rdram, window_handle);
|
||||
|
||||
rsp_constants_init();
|
||||
|
@ -285,9 +269,6 @@ void gfx_thread_func(uint8_t* rdram, uint8_t* rom, std::atomic_flag* thread_read
|
|||
RT64UpdateScreen(swap_action->origin);
|
||||
}
|
||||
}
|
||||
if (gfx_callbacks.update_gfx != nullptr) {
|
||||
gfx_callbacks.update_gfx(nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -30,13 +30,18 @@ namespace Multilibultra {
|
|||
|
||||
#if defined(_WIN32)
|
||||
// Native HWND handle to the target window.
|
||||
using WindowHandle = HWND;
|
||||
struct WindowHandle {
|
||||
HWND window;
|
||||
DWORD thread_id = (DWORD)-1;
|
||||
auto operator<=>(const WindowHandle&) const = default;
|
||||
};
|
||||
#elif defined(__ANDROID__)
|
||||
using WindowHandle = ANativeWindow*;
|
||||
#elif defined(__linux__)
|
||||
struct WindowHandle {
|
||||
Display* display;
|
||||
Window window;
|
||||
auto operator<=>(const WindowHandle&) const = default;
|
||||
};
|
||||
#endif
|
||||
|
||||
|
@ -101,14 +106,12 @@ struct audio_callbacks_t {
|
|||
get_samples_remaining_t* get_frames_remaining;
|
||||
set_frequency_t* set_frequency;
|
||||
};
|
||||
void set_audio_callbacks(const audio_callbacks_t* callbacks);
|
||||
|
||||
// Input
|
||||
struct input_callbacks_t {
|
||||
using get_input_t = void(uint16_t*, float*, float*);
|
||||
get_input_t* get_input;
|
||||
};
|
||||
void set_input_callbacks(const input_callbacks_t* callback);
|
||||
|
||||
struct gfx_callbacks_t {
|
||||
using gfx_data_t = void*;
|
||||
|
@ -119,7 +122,7 @@ struct gfx_callbacks_t {
|
|||
create_window_t* create_window;
|
||||
update_gfx_t* update_gfx;
|
||||
};
|
||||
void set_gfx_callbacks(const gfx_callbacks_t* callbacks);
|
||||
void start(WindowHandle window_handle, const audio_callbacks_t& audio_callbacks, const input_callbacks_t& input_callbacks, const gfx_callbacks_t& gfx_callbacks);
|
||||
|
||||
class preemption_guard {
|
||||
public:
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
#include "multilibultra.hpp"
|
||||
|
||||
// Start time for the program
|
||||
static std::chrono::system_clock::time_point start = std::chrono::system_clock::now();
|
||||
static std::chrono::system_clock::time_point start_time = std::chrono::system_clock::now();
|
||||
// Game speed multiplier (1 means no speedup)
|
||||
constexpr uint32_t speed_multiplier = 1;
|
||||
// N64 CPU counter ticks per millisecond
|
||||
|
@ -52,11 +52,11 @@ std::chrono::microseconds ticks_to_duration(uint64_t ticks) {
|
|||
}
|
||||
|
||||
std::chrono::system_clock::time_point ticks_to_timepoint(uint64_t ticks) {
|
||||
return start + ticks_to_duration(ticks);
|
||||
return start_time + ticks_to_duration(ticks);
|
||||
}
|
||||
|
||||
uint64_t time_now() {
|
||||
return duration_to_ticks(std::chrono::system_clock::now() - start);
|
||||
return duration_to_ticks(std::chrono::system_clock::now() - start_time);
|
||||
}
|
||||
|
||||
void timer_thread(RDRAM_ARG1) {
|
||||
|
@ -142,11 +142,11 @@ uint32_t Multilibultra::get_speed_multiplier() {
|
|||
}
|
||||
|
||||
std::chrono::system_clock::time_point Multilibultra::get_start() {
|
||||
return start;
|
||||
return start_time;
|
||||
}
|
||||
|
||||
std::chrono::system_clock::duration Multilibultra::time_since_start() {
|
||||
return std::chrono::system_clock::now() - start;
|
||||
return std::chrono::system_clock::now() - start_time;
|
||||
}
|
||||
|
||||
extern "C" u32 osGetCount() {
|
||||
|
|
|
@ -3,10 +3,8 @@
|
|||
|
||||
static Multilibultra::input_callbacks_t input_callbacks;
|
||||
|
||||
void Multilibultra::set_input_callbacks(const input_callbacks_t* callbacks) {
|
||||
if (callbacks != nullptr) {
|
||||
input_callbacks = *callbacks;
|
||||
}
|
||||
void set_input_callbacks(const Multilibultra::input_callbacks_t& callbacks) {
|
||||
input_callbacks = callbacks;
|
||||
}
|
||||
|
||||
static int max_controllers = 0;
|
||||
|
|
|
@ -164,7 +164,7 @@ Multilibultra::WindowHandle create_window(Multilibultra::gfx_callbacks_t::gfx_da
|
|||
SDL_GetWindowWMInfo(window, &wmInfo);
|
||||
|
||||
#if defined(_WIN32)
|
||||
return wmInfo.info.win.window;
|
||||
return Multilibultra::WindowHandle{ wmInfo.info.win.window, GetCurrentThreadId() };
|
||||
#elif defined(__ANDROID__)
|
||||
static_assert(false && "Unimplemented");
|
||||
#elif defined(__linux__)
|
||||
|
@ -353,19 +353,7 @@ int main(int argc, char** argv) {
|
|||
.get_input = get_input,
|
||||
};
|
||||
|
||||
//create_gfx();
|
||||
//void* window_handle = create_window(nullptr);
|
||||
|
||||
Multilibultra::set_gfx_callbacks(&gfx_callbacks);
|
||||
start(Multilibultra::WindowHandle{}, &audio_callbacks, &input_callbacks);
|
||||
|
||||
// Do nothing forever
|
||||
while (1) {
|
||||
using namespace std::chrono_literals;
|
||||
std::this_thread::sleep_for(10ms);
|
||||
//update_gfx(nullptr);
|
||||
//std::this_thread::sleep_for(1ms);
|
||||
}
|
||||
Multilibultra::start({}, audio_callbacks, input_callbacks, gfx_callbacks);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
|
@ -187,31 +187,31 @@ EXPORT extern "C" void init() {
|
|||
// return DefWindowProc(hwnd, uMsg, wParam, lParam);
|
||||
// }
|
||||
|
||||
/*EXPORT extern "C"*/ void start(Multilibultra::WindowHandle window_handle, const Multilibultra::audio_callbacks_t* audio_callbacks, const Multilibultra::input_callbacks_t* input_callbacks) {
|
||||
Multilibultra::set_audio_callbacks(audio_callbacks);
|
||||
Multilibultra::set_input_callbacks(input_callbacks);
|
||||
static Multilibultra::gfx_callbacks_t gfx_callbacks;
|
||||
|
||||
//// Register window class.
|
||||
//WNDCLASS wc;
|
||||
//memset(&wc, 0, sizeof(WNDCLASS));
|
||||
//wc.lpfnWndProc = WindowProc;
|
||||
//wc.hInstance = GetModuleHandle(0);
|
||||
//wc.hbrBackground = (HBRUSH)(COLOR_BACKGROUND);
|
||||
//wc.lpszClassName = "RT64Sample";
|
||||
//RegisterClass(&wc);
|
||||
void set_audio_callbacks(const Multilibultra::audio_callbacks_t& callbacks);
|
||||
void set_input_callbacks(const Multilibultra::input_callbacks_t& callback);
|
||||
|
||||
//// Create window.
|
||||
//const int Width = 1280;
|
||||
//const int Height = 720;
|
||||
//RECT rect;
|
||||
//UINT dwStyle = WS_OVERLAPPEDWINDOW | WS_VISIBLE;
|
||||
//rect.left = (GetSystemMetrics(SM_CXSCREEN) - Width) / 2;
|
||||
//rect.top = (GetSystemMetrics(SM_CYSCREEN) - Height) / 2;
|
||||
//rect.right = rect.left + Width;
|
||||
//rect.bottom = rect.top + Height;
|
||||
//AdjustWindowRectEx(&rect, dwStyle, 0, 0);
|
||||
void Multilibultra::start(WindowHandle window_handle, const audio_callbacks_t& audio_callbacks, const input_callbacks_t& input_callbacks, const gfx_callbacks_t& gfx_callbacks_) {
|
||||
set_audio_callbacks(audio_callbacks);
|
||||
set_input_callbacks(input_callbacks);
|
||||
|
||||
//HWND hwnd = CreateWindow(wc.lpszClassName, "Recomp", dwStyle, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, 0, 0, wc.hInstance, NULL);
|
||||
gfx_callbacks_t gfx_callbacks = gfx_callbacks_;
|
||||
|
||||
gfx_callbacks_t::gfx_data_t gfx_data{};
|
||||
|
||||
if (gfx_callbacks.create_gfx) {
|
||||
gfx_data = gfx_callbacks.create_gfx();
|
||||
}
|
||||
|
||||
if (window_handle == WindowHandle{}) {
|
||||
if (gfx_callbacks.create_window) {
|
||||
window_handle = gfx_callbacks.create_window(gfx_data);
|
||||
}
|
||||
else {
|
||||
assert(false && "No create_window callback provided");
|
||||
}
|
||||
}
|
||||
|
||||
std::thread game_thread{[](Multilibultra::WindowHandle window_handle) {
|
||||
debug_printf("[Recomp] Starting\n");
|
||||
|
@ -225,5 +225,11 @@ EXPORT extern "C" void init() {
|
|||
debug_printf("[Recomp] Quitting\n");
|
||||
}, window_handle};
|
||||
|
||||
game_thread.detach();
|
||||
while (true) {
|
||||
using namespace std::chrono_literals;
|
||||
std::this_thread::sleep_for(1ms);
|
||||
if (gfx_callbacks.update_gfx != nullptr) {
|
||||
gfx_callbacks.update_gfx(nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -100,7 +100,7 @@ void RT64Init(uint8_t* rom, uint8_t* rdram, Multilibultra::WindowHandle window_h
|
|||
gfx_info.RDRAM_SIZE = &RDRAM_SIZE;
|
||||
|
||||
#if defined(_WIN32)
|
||||
InitiateGFXWindows(gfx_info, window_handle);
|
||||
InitiateGFXWindows(gfx_info, window_handle.window, window_handle.thread_id);
|
||||
#elif defined(__ANDROID__)
|
||||
static_assert(false && "Unimplemented");
|
||||
#elif defined(__linux__)
|
||||
|
|
66
src/ui.cpp
66
src/ui.cpp
|
@ -38,6 +38,7 @@
|
|||
struct UIRenderContext {
|
||||
RT64::RenderInterface* interface;
|
||||
RT64::RenderDevice* device;
|
||||
Rml::ElementDocument* document;
|
||||
};
|
||||
|
||||
// TODO deduplicate from rt64_common.h
|
||||
|
@ -99,6 +100,8 @@ T from_bytes_le(const char* input) {
|
|||
return *reinterpret_cast<const T*>(input);
|
||||
}
|
||||
|
||||
void load_document();
|
||||
|
||||
class RmlRenderInterface_RT64 : public Rml::RenderInterface {
|
||||
static constexpr uint32_t per_frame_descriptor_set = 0;
|
||||
static constexpr uint32_t per_draw_descriptor_set = 1;
|
||||
|
@ -516,7 +519,7 @@ public:
|
|||
mvp_ = projection_mtx_ * transform_;
|
||||
}
|
||||
|
||||
void start(RT64::RenderCommandList* list, uint32_t image_width, uint32_t image_height) {
|
||||
void start(RT64::RenderCommandList* list, uint32_t image_width, uint32_t image_height, bool reload_style) {
|
||||
list_ = list;
|
||||
list_->setPipeline(pipeline_.get());
|
||||
list_->setGraphicsPipelineLayout(layout_.get());
|
||||
|
@ -528,6 +531,10 @@ public:
|
|||
// Clear out any stale buffers from the last command list.
|
||||
stale_buffers_.clear();
|
||||
|
||||
if (reload_style) {
|
||||
load_document();
|
||||
}
|
||||
|
||||
// Reset and map the upload buffer.
|
||||
upload_buffer_bytes_used_ = 0;
|
||||
upload_buffer_mapped_data_ = reinterpret_cast<uint8_t*>(upload_buffer_->map());
|
||||
|
@ -556,6 +563,18 @@ struct {
|
|||
// TODO make this not be global
|
||||
extern SDL_Window* window;
|
||||
|
||||
void load_document() {
|
||||
if (UIContext.render.document) {
|
||||
UIContext.render.document->Close();
|
||||
// Documents are owned by RmlUi, so we don't have anything to free here.
|
||||
UIContext.render.document = nullptr;
|
||||
}
|
||||
UIContext.render.document = UIContext.rml.context->LoadDocument("assets/demo.rml");
|
||||
if (UIContext.render.document) {
|
||||
UIContext.render.document->Show();
|
||||
}
|
||||
}
|
||||
|
||||
void init_hook(RT64::RenderInterface* interface, RT64::RenderDevice* device) {
|
||||
printf("RT64 hook init\n");
|
||||
|
||||
|
@ -598,10 +617,7 @@ void init_hook(RT64::RenderInterface* interface, RT64::RenderDevice* device) {
|
|||
}
|
||||
}
|
||||
|
||||
if (Rml::ElementDocument* document = UIContext.rml.context->LoadDocument("assets/demo.rml")) {
|
||||
document->Show();
|
||||
}
|
||||
|
||||
load_document();
|
||||
}
|
||||
|
||||
void draw_hook(RT64::RenderCommandList* command_list, RT64::RenderTexture* swap_chain_texture) {
|
||||
|
@ -613,13 +629,41 @@ void draw_hook(RT64::RenderCommandList* command_list, RT64::RenderTexture* swap_
|
|||
|
||||
// TODO process SDL events
|
||||
|
||||
int width, height;
|
||||
SDL_GetWindowSizeInPixels(window, &width, &height);
|
||||
int num_keys;
|
||||
const Uint8* key_state = SDL_GetKeyboardState(&num_keys);
|
||||
|
||||
UIContext.rml.render_interface->start(command_list, width, height);
|
||||
UIContext.rml.context->Update();
|
||||
UIContext.rml.context->Render();
|
||||
UIContext.rml.render_interface->end(command_list);
|
||||
static bool was_reload_held = false;
|
||||
bool is_reload_held = key_state[SDL_SCANCODE_F11] != 0;
|
||||
bool reload_sheets = is_reload_held && !was_reload_held;
|
||||
was_reload_held = is_reload_held;
|
||||
|
||||
static bool menu_open = false;
|
||||
static bool was_toggle_menu_held = false;
|
||||
bool is_toggle_menu_held = key_state[SDL_SCANCODE_M] != 0;
|
||||
if (is_toggle_menu_held && !was_toggle_menu_held) {
|
||||
menu_open = !menu_open;
|
||||
}
|
||||
was_toggle_menu_held = is_toggle_menu_held;
|
||||
|
||||
if (menu_open) {
|
||||
int width, height;
|
||||
SDL_GetWindowSizeInPixels(window, &width, &height);
|
||||
|
||||
UIContext.rml.render_interface->start(command_list, width, height, reload_sheets);
|
||||
|
||||
static int prev_width = 0;
|
||||
static int prev_height = 0;
|
||||
|
||||
if (prev_width != width || prev_height != height) {
|
||||
UIContext.rml.context->SetDimensions({ width, height });
|
||||
}
|
||||
prev_width = width;
|
||||
prev_height = height;
|
||||
|
||||
UIContext.rml.context->Update();
|
||||
UIContext.rml.context->Render();
|
||||
UIContext.rml.render_interface->end(command_list);
|
||||
}
|
||||
}
|
||||
|
||||
void deinit_hook() {
|
||||
|
|
Loading…
Reference in New Issue