mirror of https://github.com/inolen/redream.git
remove unnecessary secondary GL context
This commit is contained in:
parent
3fade7f1fb
commit
1df4e5d3a4
|
@ -59,15 +59,16 @@ struct emu {
|
|||
volatile int video_resized;
|
||||
volatile unsigned frame;
|
||||
|
||||
struct render_backend *r, *r2;
|
||||
struct render_backend *r;
|
||||
struct imgui *imgui;
|
||||
struct microprofile *mp;
|
||||
struct trace_writer *trace_writer;
|
||||
|
||||
/* hosts which support creating multiple gl contexts will render video on
|
||||
a second thread. the original hardware rendered asynchronously as well,
|
||||
so many games use this time to perform additional cpu work. on many
|
||||
games this upwards of doubles the performance */
|
||||
/* when running with multiple threads, rendering is done asynchronously on a
|
||||
secondary video thread, to avoid blocking the emulated cpu. the original
|
||||
hardware rendered asynchronously as well, so many games use this time to
|
||||
perform additional cpu work. on some games this upwards of doubles the
|
||||
performance */
|
||||
int multi_threaded;
|
||||
thread_t video_thread;
|
||||
|
||||
|
@ -338,37 +339,29 @@ static void emu_start_tracing(struct emu *emu) {
|
|||
* the dreamcast, converting it into a renderable tr_context, and then rendering
|
||||
* and presenting it
|
||||
*/
|
||||
static struct render_backend *emu_video_renderer(struct emu *emu) {
|
||||
/* when using multi-threaded rendering, the video thread has its own render
|
||||
backend instance */
|
||||
return emu->multi_threaded ? emu->r2 : emu->r;
|
||||
}
|
||||
|
||||
static void emu_render_frame(struct emu *emu) {
|
||||
struct render_backend *r2 = emu_video_renderer(emu);
|
||||
|
||||
prof_counter_add(COUNTER_frames, 1);
|
||||
|
||||
/* resize the framebuffer at this time if the output size has changed */
|
||||
if (emu->video_resized) {
|
||||
r_destroy_framebuffer(r2, emu->video_fb);
|
||||
r_destroy_framebuffer(emu->r, emu->video_fb);
|
||||
|
||||
emu->video_fb = r_create_framebuffer(r2, emu->video_width,
|
||||
emu->video_fb = r_create_framebuffer(emu->r, emu->video_width,
|
||||
emu->video_height, &emu->video_tex);
|
||||
emu->video_resized = 0;
|
||||
}
|
||||
|
||||
/* render the current render context to the video framebuffer */
|
||||
framebuffer_handle_t original = r_get_framebuffer(r2);
|
||||
r_bind_framebuffer(r2, emu->video_fb);
|
||||
framebuffer_handle_t original = r_get_framebuffer(emu->r);
|
||||
r_bind_framebuffer(emu->r, emu->video_fb);
|
||||
r_viewport(emu->r, emu->video_width, emu->video_height);
|
||||
tr_render_context(r2, &emu->pending_rc);
|
||||
r_bind_framebuffer(r2, original);
|
||||
tr_render_context(emu->r, &emu->pending_rc);
|
||||
r_bind_framebuffer(emu->r, original);
|
||||
|
||||
/* insert fence for main thread to synchronize on in order to ensure that
|
||||
the context has completely rendered */
|
||||
if (emu->multi_threaded) {
|
||||
emu->video_sync = r_insert_sync(r2);
|
||||
emu->video_sync = r_insert_sync(emu->r);
|
||||
}
|
||||
|
||||
/* update frame-based profiler stats */
|
||||
|
@ -378,31 +371,34 @@ static void emu_render_frame(struct emu *emu) {
|
|||
static void *emu_video_thread(void *data) {
|
||||
struct emu *emu = data;
|
||||
|
||||
/* make secondary context active for this thread */
|
||||
video_bind_context(emu->host, emu->r2);
|
||||
|
||||
while (1) {
|
||||
mutex_lock(emu->pending_mutex);
|
||||
|
||||
/* wait for the next tile context provided by emu_start_render */
|
||||
while (!emu->pending_ctx) {
|
||||
while (emu->running && !emu->pending_ctx) {
|
||||
cond_wait(emu->pending_cond, emu->pending_mutex);
|
||||
}
|
||||
|
||||
/* check for shutdown */
|
||||
if (!emu->running) {
|
||||
emu->pending_ctx = NULL;
|
||||
mutex_unlock(emu->pending_mutex);
|
||||
break;
|
||||
}
|
||||
|
||||
video_bind_context(emu->host, emu->r);
|
||||
|
||||
/* convert the context, uploading its textures to the render backend */
|
||||
tr_convert_context(emu->r2, emu, &emu_find_texture, emu->pending_ctx,
|
||||
tr_convert_context(emu->r, emu, &emu_find_texture, emu->pending_ctx,
|
||||
&emu->pending_rc);
|
||||
emu->pending_ctx = NULL;
|
||||
|
||||
/* render the parsed context to an offscreen framebuffer */
|
||||
emu_render_frame(emu);
|
||||
|
||||
/* release the context for the main thread to use */
|
||||
video_unbind_context(emu->host);
|
||||
|
||||
/* after the context has been rendered, release the mutex to unblock
|
||||
emu_guest_finish_render
|
||||
|
||||
|
@ -416,10 +412,6 @@ static void *emu_video_thread(void *data) {
|
|||
mutex_unlock(emu->pending_mutex);
|
||||
}
|
||||
|
||||
/* unbind context from this thread before it dies, otherwise the main thread
|
||||
may not be able to bind it in order to clean it up */
|
||||
video_unbind_context(emu->host);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -680,7 +672,6 @@ static void emu_host_context_destroyed(void *userdata) {
|
|||
/* destroy the video thread */
|
||||
if (emu->multi_threaded) {
|
||||
mutex_lock(emu->pending_mutex);
|
||||
emu->pending_ctx = (struct tile_context *)(intptr_t)0xdeadbeef;
|
||||
cond_signal(emu->pending_cond);
|
||||
mutex_unlock(emu->pending_mutex);
|
||||
|
||||
|
@ -689,30 +680,23 @@ static void emu_host_context_destroyed(void *userdata) {
|
|||
}
|
||||
|
||||
/* destroy video renderer objects */
|
||||
struct render_backend *r2 = emu_video_renderer(emu);
|
||||
video_bind_context(emu->host, r2);
|
||||
|
||||
rb_for_each_entry_safe(tex, &emu->live_textures, struct emu_texture,
|
||||
live_it) {
|
||||
r_destroy_texture(r2, tex->handle);
|
||||
r_destroy_texture(emu->r, tex->handle);
|
||||
emu_free_texture(emu, tex);
|
||||
}
|
||||
|
||||
r_destroy_framebuffer(r2, emu->video_fb);
|
||||
r_destroy_framebuffer(emu->r, emu->video_fb);
|
||||
|
||||
if (emu->video_sync) {
|
||||
r_destroy_sync(r2, emu->video_sync);
|
||||
r_destroy_sync(emu->r, emu->video_sync);
|
||||
}
|
||||
|
||||
if (emu->multi_threaded) {
|
||||
r_destroy(emu->r2);
|
||||
cond_destroy(emu->pending_cond);
|
||||
mutex_destroy(emu->pending_mutex);
|
||||
}
|
||||
|
||||
/* destroy primary renderer */
|
||||
video_bind_context(emu->host, emu->r);
|
||||
|
||||
mp_destroy(emu->mp);
|
||||
imgui_destroy(emu->imgui);
|
||||
r_destroy(emu->r);
|
||||
|
@ -734,17 +718,10 @@ static void emu_host_context_reset(void *userdata) {
|
|||
if (emu->multi_threaded) {
|
||||
emu->pending_mutex = mutex_create();
|
||||
emu->pending_cond = cond_create();
|
||||
emu->r2 = video_create_renderer_from(emu->host, emu->r);
|
||||
}
|
||||
|
||||
struct render_backend *r2 = emu_video_renderer(emu);
|
||||
video_bind_context(emu->host, r2);
|
||||
|
||||
emu->video_fb = r_create_framebuffer(r2, emu->video_width, emu->video_height,
|
||||
&emu->video_tex);
|
||||
|
||||
/* make primary renderer active for the current thread */
|
||||
video_bind_context(emu->host, emu->r);
|
||||
emu->video_fb = r_create_framebuffer(emu->r, emu->video_width,
|
||||
emu->video_height, &emu->video_tex);
|
||||
|
||||
/* startup video thread */
|
||||
if (emu->multi_threaded) {
|
||||
|
@ -764,6 +741,11 @@ static void emu_host_resized(void *userdata) {
|
|||
void emu_run_frame(struct emu *emu) {
|
||||
static const int64_t MACHINE_STEP = HZ_TO_NANO(1000);
|
||||
|
||||
/* unbind the video context, making it available for the video thread */
|
||||
if (emu->multi_threaded) {
|
||||
video_unbind_context(emu->host);
|
||||
}
|
||||
|
||||
/* run dreamcast up until its next vblank */
|
||||
unsigned start_frame = emu->frame;
|
||||
while (emu->frame == start_frame) {
|
||||
|
@ -779,6 +761,10 @@ void emu_run_frame(struct emu *emu) {
|
|||
/* render the latest frame */
|
||||
int64_t now = time_nanoseconds();
|
||||
|
||||
if (emu->multi_threaded) {
|
||||
video_bind_context(emu->host, emu->r);
|
||||
}
|
||||
|
||||
prof_update(now);
|
||||
emu_paint(emu);
|
||||
|
||||
|
@ -834,8 +820,8 @@ struct emu *emu_create(struct host *host) {
|
|||
emu->dc->vertical_blank = &emu_guest_vertical_blank;
|
||||
emu->dc->poll_input = &emu_guest_poll_input;
|
||||
|
||||
/* start up the video thread */
|
||||
emu->multi_threaded = video_supports_multiple_contexts(emu->host);
|
||||
/* start up secondary video thread */
|
||||
emu->multi_threaded = video_supports_multiple_threads(emu->host);
|
||||
|
||||
/* enable debug menu by default */
|
||||
emu->debug_menu = 1;
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
#define TLB_INDEX(addr) (((addr) >> 8) & 0x3f)
|
||||
|
||||
#define PAGE_SIZE(entry) (((entry)->lo.SZ1 << 1) | (entry)->lo.SZ0)
|
||||
/*#define PAGE_SIZE(entry) (((entry)->lo.SZ1 << 1) | (entry)->lo.SZ0)*/
|
||||
|
||||
enum {
|
||||
PAGE_SIZE_1KB,
|
||||
|
|
|
@ -26,11 +26,9 @@ void audio_push(struct host *host, const int16_t *data, int frames);
|
|||
int video_width(struct host *host);
|
||||
int video_height(struct host *host);
|
||||
|
||||
int video_supports_multiple_contexts(struct host *host);
|
||||
int video_supports_multiple_threads(struct host *host);
|
||||
|
||||
struct render_backend *video_create_renderer(struct host *host);
|
||||
struct render_backend *video_create_renderer_from(struct host *host,
|
||||
struct render_backend *from);
|
||||
void video_destroy_renderer(struct host *host, struct render_backend *r);
|
||||
|
||||
void video_bind_context(struct host *host, struct render_backend *r);
|
||||
|
|
|
@ -98,24 +98,18 @@ void video_unbind_context(struct host *host) {
|
|||
}
|
||||
|
||||
void video_bind_context(struct host *base, struct render_backend *r) {
|
||||
video_context_t ctx = r_context(r);
|
||||
CHECK_EQ(ctx, NULL);
|
||||
CHECK(0);
|
||||
}
|
||||
|
||||
void video_destroy_renderer(struct host *base, struct render_backend *r) {
|
||||
r_destroy(r);
|
||||
}
|
||||
|
||||
struct render_backend *video_create_renderer_from(struct host *base,
|
||||
struct render_backend *from) {
|
||||
CHECK(0);
|
||||
}
|
||||
|
||||
struct render_backend *video_create_renderer(struct host *base) {
|
||||
return r_create(NULL);
|
||||
}
|
||||
|
||||
int video_supports_multiple_contexts(struct host *base) {
|
||||
int video_supports_multiple_threads(struct host *host) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -32,6 +32,7 @@ struct sdl_host {
|
|||
struct host;
|
||||
|
||||
struct SDL_Window *win;
|
||||
|
||||
int closed;
|
||||
int video_width;
|
||||
int video_height;
|
||||
|
@ -223,6 +224,12 @@ static void video_resized(struct sdl_host *host) {
|
|||
}
|
||||
|
||||
static void video_gl_destroy_context(struct host *base, video_context_t ctx) {
|
||||
struct sdl_host *host = (struct sdl_host *)base;
|
||||
|
||||
/* make sure the context is no longer active */
|
||||
int res = SDL_GL_MakeCurrent(host->win, NULL);
|
||||
CHECK_EQ(res, 0);
|
||||
|
||||
SDL_GL_DeleteContext(ctx);
|
||||
}
|
||||
|
||||
|
@ -243,39 +250,32 @@ static video_context_t video_gl_create_context(struct sdl_host *host) {
|
|||
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
|
||||
|
||||
SDL_GLContext ctx = SDL_GL_CreateContext(host->win);
|
||||
CHECK_NOTNULL(ctx, "OpenGL context creation failed: %s", SDL_GetError());
|
||||
CHECK_NOTNULL(ctx, "video_gl_create_context failed: %s", SDL_GetError());
|
||||
|
||||
/* disable vsync */
|
||||
int res = SDL_GL_SetSwapInterval(0);
|
||||
CHECK_EQ(res, 0, "Failed to disable vsync");
|
||||
CHECK_EQ(res, 0, "video_gl_create_context failed to disable vsync");
|
||||
|
||||
/* link in gl functions at runtime */
|
||||
res = gladLoadGLLoader((GLADloadproc)&SDL_GL_GetProcAddress);
|
||||
CHECK_EQ(res, 1, "GL initialization failed");
|
||||
CHECK_EQ(res, 1, "video_gl_create_context failed to link");
|
||||
|
||||
return (video_context_t)ctx;
|
||||
}
|
||||
|
||||
static video_context_t video_gl_create_context_from(struct sdl_host *host,
|
||||
video_context_t from) {
|
||||
int res = SDL_GL_MakeCurrent(host->win, from);
|
||||
CHECK_EQ(res, 0);
|
||||
|
||||
SDL_GL_SetAttribute(SDL_GL_SHARE_WITH_CURRENT_CONTEXT, 1);
|
||||
|
||||
return video_gl_create_context(host);
|
||||
}
|
||||
|
||||
void video_unbind_context(struct host *base) {
|
||||
struct sdl_host *host = (struct sdl_host *)base;
|
||||
|
||||
int res = SDL_GL_MakeCurrent(host->win, NULL);
|
||||
CHECK_EQ(res, 0);
|
||||
CHECK_EQ(res, 0, "video_unbind_context failed: %s", SDL_GetError());
|
||||
}
|
||||
|
||||
void video_bind_context(struct host *base, struct render_backend *r) {
|
||||
struct sdl_host *host = (struct sdl_host *)base;
|
||||
video_context_t ctx = r_context(r);
|
||||
|
||||
int res = SDL_GL_MakeCurrent(host->win, ctx);
|
||||
CHECK_EQ(res, 0);
|
||||
CHECK_EQ(res, 0, "video_bind_context failed: %s", SDL_GetError());
|
||||
}
|
||||
|
||||
void video_destroy_renderer(struct host *base, struct render_backend *r) {
|
||||
|
@ -284,26 +284,14 @@ void video_destroy_renderer(struct host *base, struct render_backend *r) {
|
|||
video_gl_destroy_context(base, ctx);
|
||||
}
|
||||
|
||||
struct render_backend *video_create_renderer_from(struct host *base,
|
||||
struct render_backend *from) {
|
||||
struct sdl_host *host = (struct sdl_host *)base;
|
||||
video_context_t from_ctx = r_context(from);
|
||||
video_context_t ctx = video_gl_create_context_from(host, from_ctx);
|
||||
return r_create(ctx);
|
||||
}
|
||||
|
||||
struct render_backend *video_create_renderer(struct host *base) {
|
||||
struct sdl_host *host = (struct sdl_host *)base;
|
||||
video_context_t ctx = video_gl_create_context(host);
|
||||
return r_create(ctx);
|
||||
}
|
||||
|
||||
int video_supports_multiple_contexts(struct host *host) {
|
||||
#if PLATFORM_ANDROID
|
||||
return 0;
|
||||
#else
|
||||
int video_supports_multiple_threads(struct host *host) {
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
int video_height(struct host *base) {
|
||||
|
@ -520,8 +508,9 @@ static void input_handle_controller_removed(struct sdl_host *host, int port) {
|
|||
return;
|
||||
}
|
||||
|
||||
LOG_INFO("controller '%s' removed from port %d", SDL_GameControllerName(ctrl),
|
||||
port);
|
||||
const char *name = SDL_GameControllerName(ctrl);
|
||||
LOG_INFO("controller '%s' removed from port %d", name, port);
|
||||
|
||||
SDL_GameControllerClose(ctrl);
|
||||
host->controllers[port] = NULL;
|
||||
}
|
||||
|
@ -773,13 +762,14 @@ struct sdl_host *host_create() {
|
|||
|
||||
/* init sdl and create window */
|
||||
int res = SDL_Init(SDL_INIT_AUDIO | SDL_INIT_VIDEO | SDL_INIT_GAMECONTROLLER);
|
||||
CHECK_GE(res, 0, "SDL initialization failed: %s", SDL_GetError());
|
||||
CHECK_GE(res, 0, "host_create sdl initialization failed: %s", SDL_GetError());
|
||||
|
||||
host->win = SDL_CreateWindow("redream", SDL_WINDOWPOS_UNDEFINED,
|
||||
SDL_WINDOWPOS_UNDEFINED, VIDEO_DEFAULT_WIDTH,
|
||||
VIDEO_DEFAULT_HEIGHT,
|
||||
SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);
|
||||
CHECK_NOTNULL(host->win, "Window creation failed: %s", SDL_GetError());
|
||||
CHECK_NOTNULL(host->win, "host_create window creation failed: %s",
|
||||
SDL_GetError());
|
||||
|
||||
/* immediately poll window size for platforms like Android where the window
|
||||
starts fullscreen, ignoring the default width and height */
|
||||
|
|
Loading…
Reference in New Issue