Delayed game start, made UI hot reload include all files, passed input

events to UI
This commit is contained in:
Mr-Wiseguy 2023-11-05 14:34:20 -05:00
parent 346e298eb1
commit 91611c9c33
7 changed files with 124 additions and 51 deletions

9
include/recomp_ui.h Normal file
View File

@ -0,0 +1,9 @@
#ifndef __RECOMP_UI__
#define __RECOMP_UI__
#include "SDL.h"
void queue_event(const SDL_Event& event);
bool try_deque_event(SDL_Event& out);
#endif

View File

@ -95,6 +95,8 @@ extern "C" void osViSetEvent(RDRAM_ARG PTR(OSMesgQueue) mq_, OSMesg msg, u32 ret
uint64_t total_vis = 0;
void set_dummy_vi();
void vi_thread_func() {
Multilibultra::set_native_thread_name("VI Thread");
// This thread should be prioritized over every other thread in the application, as it's what allows
@ -131,11 +133,24 @@ void vi_thread_func() {
if (remaining_retraces == 0) {
remaining_retraces = events_context.vi.retrace_count;
if (events_context.vi.mq != NULLPTR) {
if (osSendMesg(PASS_RDRAM events_context.vi.mq, events_context.vi.msg, OS_MESG_NOBLOCK) == -1) {
//printf("Game skipped a VI frame!\n");
if (Multilibultra::is_game_started()) {
if (events_context.vi.mq != NULLPTR) {
if (osSendMesg(PASS_RDRAM events_context.vi.mq, events_context.vi.msg, OS_MESG_NOBLOCK) == -1) {
//printf("Game skipped a VI frame!\n");
}
}
}
else {
set_dummy_vi();
static bool swap = false;
uint32_t vi_origin = 0x400 + 0x280; // Skip initial RDRAM contents and add the usual origin offset
// Offset by one FB every other frame so RT64 continues drawing
if (swap) {
vi_origin += 0x25800;
}
osViSwapBuffer(rdram, vi_origin);
swap = !swap;
}
}
if (events_context.ai.mq != NULLPTR) {
if (osSendMesg(PASS_RDRAM events_context.ai.mq, events_context.ai.msg, OS_MESG_NOBLOCK) == -1) {
@ -238,7 +253,6 @@ void task_thread_func(uint8_t* rdram, uint8_t* rom, std::atomic_flag* thread_rea
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{};
Multilibultra::set_native_thread_name("Gfx Thread");
Multilibultra::set_native_thread_priority(Multilibultra::ThreadPriority::Normal);
@ -291,6 +305,22 @@ uint32_t hstart = 0;
uint32_t vi_origin_offset = 320 * sizeof(uint16_t);
bool vi_black = false;
void set_dummy_vi() {
VI_STATUS_REG = 0x311E;
VI_WIDTH_REG = 0x140;
VI_V_SYNC_REG = 0x20D;
VI_H_SYNC_REG = 0xC15;
VI_LEAP_REG = 0x0C150C15;
hstart = 0x006C02EC;
VI_X_SCALE_REG = 0x200;
VI_V_CURRENT_LINE_REG = 0x0;
vi_origin_offset = 0x280;
VI_Y_SCALE_REG = 0x400;
VI_V_START_REG = 0x2501FF;
VI_V_BURST_REG = 0xE0204;
VI_INTR_REG = 0x2;
}
extern "C" void osViSwapBuffer(RDRAM_ARG PTR(void) frameBufPtr) {
if (vi_black) {
VI_H_START_REG = 0;

View File

@ -123,14 +123,8 @@ struct gfx_callbacks_t {
update_gfx_t* update_gfx;
};
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:
preemption_guard();
~preemption_guard();
private:
std::lock_guard<std::mutex> lock;
};
void start_game(int game);
bool is_game_started();
} // namespace Multilibultra

View File

@ -258,16 +258,6 @@ void enable_preemption() {
#pragma warning( pop )
}
// lock's constructor is called first, so can_preempt is set after locking
preemption_guard::preemption_guard() : lock{scheduler_context.premption_mutex} {
scheduler_context.can_preempt = false;
}
// lock's destructor is called last, so can_preempt is set before unlocking
preemption_guard::~preemption_guard() {
scheduler_context.can_preempt = true;
}
void notify_scheduler() {
std::lock_guard lock{scheduler_context.mutex};
scheduler_context.notify_count.fetch_add(1);

View File

@ -14,6 +14,8 @@
#include "SDL2/SDL_syswm.h"
#endif
#include "recomp_ui.h"
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
@ -138,6 +140,9 @@ int sdl_event_filter(void* userdata, SDL_Event* event) {
case SDL_EventType::SDL_QUIT:
std::quick_exit(EXIT_SUCCESS);
break;
default:
queue_event(*event);
break;
}
return 1;
}
@ -153,7 +158,7 @@ Multilibultra::gfx_callbacks_t::gfx_data_t create_gfx() {
SDL_Window* window;
Multilibultra::WindowHandle create_window(Multilibultra::gfx_callbacks_t::gfx_data_t) {
window = SDL_CreateWindow("Majora's Mask", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1280, 720, SDL_WINDOW_RESIZABLE);
window = SDL_CreateWindow("Recomp", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1280, 720, SDL_WINDOW_RESIZABLE);
if (window == nullptr) {
exit_error("Failed to create window: %s\n", SDL_GetError());

View File

@ -183,11 +183,16 @@ EXPORT extern "C" void init() {
MEM_W(osMemSize, 0) = 8 * 1024 * 1024; // 8MB
}
// LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
// return DefWindowProc(hwnd, uMsg, wParam, lParam);
// }
std::atomic_int game_started = -1;
static Multilibultra::gfx_callbacks_t gfx_callbacks;
void Multilibultra::start_game(int game) {
game_started.store(game);
game_started.notify_all();
}
bool Multilibultra::is_game_started() {
return game_started.load() != -1;
}
void set_audio_callbacks(const Multilibultra::audio_callbacks_t& callbacks);
void set_input_callbacks(const Multilibultra::input_callbacks_t& callback);
@ -220,7 +225,13 @@ void Multilibultra::start(WindowHandle window_handle, const audio_callbacks_t& a
Multilibultra::preinit(rdram_buffer.get(), rom.get(), window_handle);
recomp_entrypoint(rdram_buffer.get(), &context);
game_started.wait(-1);
switch (game_started.load()) {
case 0:
recomp_entrypoint(rdram_buffer.get(), &context);
break;
}
debug_printf("[Recomp] Quitting\n");
}, window_handle};
@ -229,7 +240,7 @@ void Multilibultra::start(WindowHandle window_handle, const audio_callbacks_t& a
using namespace std::chrono_literals;
std::this_thread::sleep_for(1ms);
if (gfx_callbacks.update_gfx != nullptr) {
gfx_callbacks.update_gfx(nullptr);
gfx_callbacks.update_gfx(gfx_data);
}
}
}

View File

@ -5,6 +5,8 @@
#include <fstream>
#include <filesystem>
#include "concurrentqueue.h"
#include "rt64_layer.h"
#include "rt64_render_hooks.h"
#include "rt64_render_interface_builders.h"
@ -116,6 +118,8 @@ class RmlRenderInterface_RT64 : public Rml::RenderInterface {
int scissor_y_ = 0;
int scissor_width_ = 0;
int scissor_height_ = 0;
int window_width_ = 0;
int window_height_ = 0;
Rml::Matrix4f projection_mtx_ = Rml::Matrix4f::Identity();
Rml::Matrix4f transform_ = Rml::Matrix4f::Identity();
Rml::Matrix4f mvp_ = Rml::Matrix4f::Identity();
@ -274,11 +278,16 @@ public:
uint32_t total_bytes = vert_size_bytes + index_size_bytes;
uint32_t index_bytes_start = vert_size_bytes;
if (textures_.size() == 0) {
// Create a 1x1 pixel white texture as the first handle
Rml::byte white_pixel[] = { 255, 255, 255, 255 };
Rml::TextureHandle dummy_handle;
GenerateTexture(dummy_handle, white_pixel, Rml::Vector2i{ 1,1 });
if (!textures_.contains(texture)) {
if (texture == 0) {
// Create a 1x1 pixel white texture as the first handle
Rml::byte white_pixel[] = { 255, 255, 255, 255 };
create_texture(0, white_pixel, Rml::Vector2i{ 1,1 });
}
else {
assert(false && "Rendered without texture!");
}
}
uint32_t upload_buffer_offset = allocate_upload_data(total_bytes);
@ -325,17 +334,19 @@ public:
};
list_->barriers(usage_barriers, uint32_t(std::size(usage_barriers)));
// TODO set scissor, viewport
//if (scissor_enabled_) {
list_->setViewports(RT64::RenderViewport{ 0, 0, float(scissor_width_), float(scissor_height_) });
list_->setScissors(RT64::RenderRect{ 0, 0, scissor_width_, scissor_height_ });
//}
list_->setViewports(RT64::RenderViewport{ 0, 0, float(window_width_), float(window_height_) });
if (scissor_enabled_) {
list_->setScissors(RT64::RenderRect{ scissor_x_, scissor_y_, scissor_width_, scissor_height_ });
}
else {
list_->setScissors(RT64::RenderRect{ 0, 0, window_width_, window_height_ });
}
RT64::RenderIndexBufferView index_view{index_buffer_->at(0), index_size_bytes, RT64::RenderFormat::R32_UINT};
list_->setIndexBuffer(&index_view);
RT64::RenderVertexBufferView vertex_view{vertex_buffer_->at(0), vert_size_bytes};
list_->setVertexBuffers(0, &vertex_view, 1, &vertex_slot_);
list_->setGraphicsDescriptorHeap(textures_[texture].heap.get());
list_->setGraphicsDescriptorHeap(textures_.at(texture).heap.get());
RmlPushConstants constants{
.transform = mvp_,
@ -420,6 +431,7 @@ public:
texture_dimensions.x = size_x;
texture_dimensions.y = size_y;
texture_handle = texture_count_++;
create_texture(texture_handle, reinterpret_cast<const Rml::byte*>(file_data.data() + 18), texture_dimensions, true);
return true;
@ -429,11 +441,11 @@ public:
}
bool GenerateTexture(Rml::TextureHandle& texture_handle, const Rml::byte* source, const Rml::Vector2i& source_dimensions) override {
texture_handle = texture_count_++;
return create_texture(texture_handle, source, source_dimensions);
}
bool create_texture(Rml::TextureHandle& texture_handle, const Rml::byte* source, const Rml::Vector2i& source_dimensions, bool flip_y = false) {
texture_handle = texture_count_++;
bool create_texture(Rml::TextureHandle texture_handle, const Rml::byte* source, const Rml::Vector2i& source_dimensions, bool flip_y = false) {
std::unique_ptr<RT64::RenderTexture> texture =
render_context_->device->createTexture(RT64::RenderTextureDesc::Texture2D(source_dimensions.x, source_dimensions.y, 1, RmlTextureFormat));
@ -524,6 +536,9 @@ public:
list_->setPipeline(pipeline_.get());
list_->setGraphicsPipelineLayout(layout_.get());
window_width_ = image_width;
window_height_ = image_height;
projection_mtx_ = Rml::Matrix4f::ProjectOrtho(0.0f, static_cast<float>(image_width), static_cast<float>(image_height), 0.0f, -10000, 10000);
recalculate_mvp();
@ -565,6 +580,10 @@ extern SDL_Window* window;
void load_document() {
if (UIContext.render.document) {
UIContext.render.document->ReloadStyleSheet();
Rml::ReleaseTextures();
Rml::ReleaseMemoryPools();
UIContext.render.document->Hide();
UIContext.render.document->Close();
// Documents are owned by RmlUi, so we don't have anything to free here.
UIContext.render.document = nullptr;
@ -620,15 +639,17 @@ void init_hook(RT64::RenderInterface* interface, RT64::RenderDevice* device) {
load_document();
}
moodycamel::ConcurrentQueue<SDL_Event> ui_event_queue{};
void queue_event(const SDL_Event& event) {
ui_event_queue.enqueue(event);
}
bool try_deque_event(SDL_Event& out) {
return ui_event_queue.try_dequeue(out);
}
void draw_hook(RT64::RenderCommandList* command_list, RT64::RenderTexture* swap_chain_texture) {
command_list->barriers(RT64::RenderTextureBarrier::Transition(swap_chain_texture, RT64::RenderTextureState::RENDER_TARGET));
// command_list->setGraphicsPipelineLayout(UIContext.render.layout.get());
// command_list->setPipeline(UIContext.render.pipeline.get());
// command_list->setIndexBuffer(&UIContext.render.index_buffer_view);
// command_list->drawIndexedInstanced(6, 1, 0, 0, 0);
// TODO process SDL events
int num_keys;
const Uint8* key_state = SDL_GetKeyboardState(&num_keys);
@ -637,13 +658,26 @@ void draw_hook(RT64::RenderCommandList* command_list, RT64::RenderTexture* swap_
bool reload_sheets = is_reload_held && !was_reload_held;
was_reload_held = is_reload_held;
static bool menu_open = false;
static bool menu_open = true;
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;
static bool was_start_game_held = false;
bool is_start_game_held = key_state[SDL_SCANCODE_SPACE] != 0;
if (is_start_game_held && !was_start_game_held) {
Multilibultra::start_game(0);
}
was_start_game_held = is_start_game_held;
SDL_Event cur_event{};
while (try_deque_event(cur_event)) {
RmlSDL::InputEventHandler(UIContext.rml.context, cur_event);
}
if (menu_open) {
int width, height;