Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions librecomp/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ add_library(librecomp STATIC
"${CMAKE_CURRENT_SOURCE_DIR}/src/dp.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/src/eep.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/src/euc-jp.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/src/extensions.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/src/files.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/src/flash.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/src/heap.cpp"
Expand Down
11 changes: 11 additions & 0 deletions librecomp/src/extensions.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#include "recomp.h"
#include "ultramodern/extensions.h"
#include "librecomp/helpers.hpp"

extern "C" void osExQueueDisplaylistEvent_recomp(uint8_t* rdram, recomp_context* ctx) {
PTR(OSMesgQueue) mq = _arg<0, PTR(OSMesgQueue)>(rdram, ctx);
OSMesg mesg = _arg<1, OSMesg>(rdram, ctx);
PTR(void) displaylist = _arg<2, PTR(void)>(rdram, ctx);
u32 event_type = _arg<3, u32>(rdram, ctx);
osExQueueDisplaylistEvent(mq, mesg, displaylist, event_type);
}
1 change: 1 addition & 0 deletions ultramodern/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ add_library(ultramodern STATIC
"${CMAKE_CURRENT_SOURCE_DIR}/src/audio.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/src/error_handling.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/src/events.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/src/extensions.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/src/input.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/src/mesgqueue.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/src/misc_ultra.cpp"
Expand Down
48 changes: 48 additions & 0 deletions ultramodern/include/ultramodern/extensions.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#ifndef __ULTRAMODERN_EXTENSIONS_H__
#define __ULTRAMODERN_EXTENSIONS_H__

#if defined(mips) // Patch compilation
#include <ultra64.h>
#else
#include "ultramodern/ultra64.h"
#endif

#ifndef PTR
#define PTR(x) x*
#endif

#ifdef __cplusplus
extern "C" {
#endif

typedef enum {
// Triggers when a displaylist has been submitted to the renderer.
OS_EX_DISPLAYLIST_EVENT_SUBMITTED,
// Triggers when a displaylist has been fully parsed by the renderer. This includes any referenced data, such
// as vertices, matrices, and textures.
OS_EX_DISPLAYLIST_EVENT_PARSED,
// Triggers when rendering of a displaylist has been completed by the renderer. This only includes the
// rendering pass that produces an image in RAM, not the high res output images that get presented to the user.
OS_EX_DISPLAYLIST_EVENT_COMPLETED
} DisplaylistEventType;

// Queues a one-time message to be sent the next time the given event type occurs for the given displaylist.
// This allows easier detection of displaylist events without needing to patch a game's scheduler.
// The event will be cleared after it occurs.
// event_type must be a member of the DisplaylistEventType enum.
void osExQueueDisplaylistEvent(PTR(OSMesgQueue) mq, OSMesg mesg, PTR(void) displaylist, u32 event_type);

#ifdef __cplusplus
}

namespace ultramodern {
namespace extensions {
void on_displaylist_submitted(PTR(u64) displaylist);
void on_displaylist_parsed(PTR(u64) displaylist);
void on_displaylist_completed(PTR(u64) displaylist);
}
}

#endif

#endif
8 changes: 8 additions & 0 deletions ultramodern/src/events.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

#include "ultramodern/ultra64.h"
#include "ultramodern/ultramodern.hpp"
#include "ultramodern/extensions.h"

#include "ultramodern/rsp.hpp"
#include "ultramodern/renderer_context.hpp"
Expand Down Expand Up @@ -364,10 +365,17 @@ void gfx_thread_func(uint8_t* rdram, moodycamel::LightweightSemaphore* thread_re
sp_complete();
ultramodern::measure_input_latency();

PTR(u64) displaylist = task_action->task.t.data_ptr;
ultramodern::extensions::on_displaylist_submitted(displaylist);

[[maybe_unused]] auto renderer_start = std::chrono::high_resolution_clock::now();
renderer_context->send_dl(&task_action->task);
[[maybe_unused]] auto renderer_end = std::chrono::high_resolution_clock::now();

dp_complete();
// TODO hook the parsed event up to the actual parsing point when a callback is added to RT64.
ultramodern::extensions::on_displaylist_parsed(displaylist);
ultramodern::extensions::on_displaylist_completed(displaylist);
// printf("Renderer ProcessDList time: %d us\n", static_cast<u32>(std::chrono::duration_cast<std::chrono::microseconds>(renderer_end - renderer_start).count()));
}
else if (const auto* screen_update_action = std::get_if<ScreenUpdateAction>(&action)) {
Expand Down
60 changes: 60 additions & 0 deletions ultramodern/src/extensions.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#include <mutex>
#include <vector>

#include "ultramodern/extensions.h"
#include "ultramodern/ultramodern.hpp"

struct DLEvent {
PTR(OSMesgQueue) mq;
OSMesg mesg;
PTR(void) displaylist;
u32 event_type;
};

struct {
struct {
std::mutex dl_event_mutex;
std::vector<DLEvent> pending_events;
} dl_events;
} extension_state;

extern "C" void osExQueueDisplaylistEvent(PTR(OSMesgQueue) mq, OSMesg mesg, PTR(void) displaylist, u32 event_type) {
std::lock_guard lock{ extension_state.dl_events.dl_event_mutex };

assert(
event_type == OS_EX_DISPLAYLIST_EVENT_SUBMITTED ||
event_type == OS_EX_DISPLAYLIST_EVENT_PARSED ||
event_type == OS_EX_DISPLAYLIST_EVENT_COMPLETED);

extension_state.dl_events.pending_events.emplace_back(
DLEvent{ mq, mesg, displaylist, event_type }
);
}

void dispatch_displaylist_events(PTR(void) displaylist, u32 event_type) {
std::lock_guard lock{ extension_state.dl_events.dl_event_mutex };

// Check every pending DL event to see if they match this displaylist and event type.
for (auto iter = extension_state.dl_events.pending_events.begin(); iter != extension_state.dl_events.pending_events.end(); ) {
if (iter->displaylist == displaylist && iter->event_type == event_type) {
// Send the provided message to the corresponding message queue for this event, then remove this event from the queue.
ultramodern::enqueue_external_message(iter->mq, iter->mesg, false, true);
iter = extension_state.dl_events.pending_events.erase(iter);
}
else {
++iter;
}
}
}

void ultramodern::extensions::on_displaylist_submitted(PTR(void) displaylist) {
dispatch_displaylist_events(displaylist, OS_EX_DISPLAYLIST_EVENT_SUBMITTED);
}

void ultramodern::extensions::on_displaylist_parsed(PTR(void) displaylist) {
dispatch_displaylist_events(displaylist, OS_EX_DISPLAYLIST_EVENT_PARSED);
}

void ultramodern::extensions::on_displaylist_completed(PTR(void) displaylist) {
dispatch_displaylist_events(displaylist, OS_EX_DISPLAYLIST_EVENT_COMPLETED);
}
Loading