mirror of
https://github.com/bsnes-emu/bsnes.git
synced 2025-09-03 16:52:38 +02:00
Emulate the ROM to be thumbnailed
Now all that's left is actually rendering that!
This commit is contained in:
41
Makefile
41
Makefile
@@ -338,7 +338,7 @@ endif
|
||||
|
||||
cocoa: $(BIN)/SameBoy.app
|
||||
quicklook: $(BIN)/SameBoy.qlgenerator
|
||||
xdg-thumbnailer: $(BIN)/XdgThumbnailer/sameboy-thumbnailer $(BIN)/SDL/cgb_boot_fast.bin
|
||||
xdg-thumbnailer: $(BIN)/XdgThumbnailer/sameboy-thumbnailer $(BIN)/XdgThumbnailer/cgb_boot_fast.bin $(patsubst QuickLook/%.png,$(BIN)/XdgThumbnailer/%.png,$(wildcard QuickLook/*.png))
|
||||
sdl: $(SDL_TARGET) $(BIN)/SDL/dmg_boot.bin $(BIN)/SDL/mgb_boot.bin $(BIN)/SDL/cgb0_boot.bin $(BIN)/SDL/cgb_boot.bin $(BIN)/SDL/agb_boot.bin $(BIN)/SDL/sgb_boot.bin $(BIN)/SDL/sgb2_boot.bin $(BIN)/SDL/LICENSE $(BIN)/SDL/registers.sym $(BIN)/SDL/background.bmp $(BIN)/SDL/Shaders $(BIN)/SDL/Palettes
|
||||
bootroms: $(BIN)/BootROMs/agb_boot.bin $(BIN)/BootROMs/cgb_boot.bin $(BIN)/BootROMs/cgb0_boot.bin $(BIN)/BootROMs/dmg_boot.bin $(BIN)/BootROMs/mgb_boot.bin $(BIN)/BootROMs/sgb_boot.bin $(BIN)/BootROMs/sgb2_boot.bin
|
||||
tester: $(TESTER_TARGET) $(BIN)/tester/dmg_boot.bin $(BIN)/tester/cgb_boot.bin $(BIN)/tester/agb_boot.bin $(BIN)/tester/sgb_boot.bin $(BIN)/tester/sgb2_boot.bin
|
||||
@@ -615,41 +615,51 @@ $(BIN)/tester/sameboy_tester.exe: $(CORE_OBJECTS) $(SDL_OBJECTS)
|
||||
-@$(MKDIR) -p $(dir $@)
|
||||
$(CC) $^ -o $@ $(LDFLAGS) -Wl,/subsystem:console
|
||||
|
||||
$(BIN)/SDL/%.bin: $(BOOTROMS_DIR)/%.bin
|
||||
-@$(MKDIR) -p $(dir $@)
|
||||
cp -f $^ $@
|
||||
|
||||
$(BIN)/tester/%.bin: $(BOOTROMS_DIR)/%.bin
|
||||
-@$(MKDIR) -p $(dir $@)
|
||||
cp -f $^ $@
|
||||
cp -f $< $@
|
||||
|
||||
$(BIN)/SameBoy.app/Contents/Resources/%.bin: $(BOOTROMS_DIR)/%.bin
|
||||
-@$(MKDIR) -p $(dir $@)
|
||||
cp -f $^ $@
|
||||
cp -f $< $@
|
||||
|
||||
$(BIN)/SameBoy-iOS.app/%.bin: $(BOOTROMS_DIR)/%.bin
|
||||
-@$(MKDIR) -p $(dir $@)
|
||||
cp -f $^ $@
|
||||
cp -f $< $@
|
||||
|
||||
$(BIN)/XdgThumbnailer/%.png: QuickLook/%.png
|
||||
-@$(MKDIR) -p $(dir $@)
|
||||
cp -f $< $@
|
||||
|
||||
$(BIN)/XdgThumbnailer/%.bin: $(BOOTROMS_DIR)/%.bin
|
||||
-@$(MKDIR) -p $(dir $@)
|
||||
cp -f $< $@
|
||||
|
||||
$(BIN)/SDL/%.bin: $(BOOTROMS_DIR)/%.bin
|
||||
-@$(MKDIR) -p $(dir $@)
|
||||
cp -f $< $@
|
||||
|
||||
$(BIN)/SDL/LICENSE: LICENSE
|
||||
-@$(MKDIR) -p $(dir $@)
|
||||
grep -v "^ " $^ > $@
|
||||
grep -v "^ " $< > $@
|
||||
|
||||
$(BIN)/SDL/registers.sym: Misc/registers.sym
|
||||
-@$(MKDIR) -p $(dir $@)
|
||||
cp -f $^ $@
|
||||
cp -f $< $@
|
||||
|
||||
$(BIN)/SDL/background.bmp: SDL/background.bmp
|
||||
-@$(MKDIR) -p $(dir $@)
|
||||
cp -f $^ $@
|
||||
cp -f $< $@
|
||||
|
||||
$(BIN)/SDL/Shaders: Shaders
|
||||
$(BIN)/SDL/Shaders: $(wildcard Shaders/*.fsh)
|
||||
-@$(MKDIR) -p $@
|
||||
cp -rf Shaders/*.fsh $@
|
||||
cp -rf $^ $@
|
||||
touch $@
|
||||
|
||||
$(BIN)/SDL/Palettes: Misc/Palettes
|
||||
$(BIN)/SDL/Palettes: $(wildcard Misc/Palettes/*.sbp)
|
||||
-@$(MKDIR) -p $@
|
||||
cp -rf Misc/Palettes/*.sbp $@
|
||||
cp -rf $^ $@
|
||||
touch $@
|
||||
|
||||
# Boot ROMs
|
||||
|
||||
@@ -693,6 +703,7 @@ install: sdl xdg-thumbnailer $(DESTDIR)$(PREFIX)/share/mime/packages/sameboy.xml
|
||||
-@$(MKDIR) -p $(dir $(DESTDIR)$(PREFIX))
|
||||
mkdir -p $(DESTDIR)$(DATA_DIR)/ $(DESTDIR)$(PREFIX)/bin/
|
||||
cp -rf $(BIN)/SDL/* $(DESTDIR)$(DATA_DIR)/
|
||||
cp -rf $(BIN)/XdgThumbnailer/* $(DESTDIR)$(DATA_DIR)/
|
||||
mv $(DESTDIR)$(DATA_DIR)/sameboy $(DESTDIR)$(PREFIX)/bin/sameboy
|
||||
ifeq ($(DESTDIR),)
|
||||
-update-mime-database -n $(PREFIX)/share/mime
|
||||
|
96
XdgThumbnailer/emulate.c
Normal file
96
XdgThumbnailer/emulate.c
Normal file
@@ -0,0 +1,96 @@
|
||||
#include "emulate.h"
|
||||
|
||||
#include <glib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "Core/gb.h"
|
||||
#include "Core/memory.h"
|
||||
#include "glibconfig.h"
|
||||
|
||||
#define NB_FRAMES_TO_EMULATE (60 * 10)
|
||||
|
||||
#define BOOT_ROM_SIZE (0x100 + 0x800) // The two "parts" of it, which are stored contiguously.
|
||||
static char *boot_rom;
|
||||
|
||||
void load_boot_rom(void)
|
||||
{
|
||||
static char const *boot_rom_path = DATA_DIR "/cgb_boot_fast.bin";
|
||||
|
||||
size_t length;
|
||||
GError *error = NULL;
|
||||
g_file_get_contents(boot_rom_path, &boot_rom, &length, &error);
|
||||
|
||||
if (error) {
|
||||
g_error("Error loading boot ROM from \"%s\": %s", boot_rom_path, error->message);
|
||||
// NOTREACHED
|
||||
}
|
||||
else if (length != BOOT_ROM_SIZE) {
|
||||
g_error("Error loading boot ROM from \"%s\": expected to read %d bytes, got %zu",
|
||||
boot_rom_path, BOOT_ROM_SIZE, length);
|
||||
// NOTREACHED
|
||||
}
|
||||
}
|
||||
|
||||
void unload_boot_rom(void) { g_free(boot_rom); }
|
||||
|
||||
/* --- */
|
||||
|
||||
static char *async_input_callback(GB_gameboy_t *gb)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void log_callback(GB_gameboy_t *gb, const char *string, GB_log_attributes attributes)
|
||||
{
|
||||
// Swallow any logs.
|
||||
}
|
||||
|
||||
static void vblank_callback(GB_gameboy_t *gb, GB_vblank_type_t type)
|
||||
{
|
||||
unsigned nb_frames_left = GPOINTER_TO_UINT(GB_get_user_data(gb));
|
||||
nb_frames_left--;
|
||||
GB_set_user_data(gb, GUINT_TO_POINTER(nb_frames_left));
|
||||
|
||||
// *Do* render the very last frame.
|
||||
if (nb_frames_left == 0) {
|
||||
GB_set_rendering_disabled(gb, false);
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t rgb_encode(GB_gameboy_t *gb, uint8_t r, uint8_t g, uint8_t b)
|
||||
{
|
||||
return r | g << 8 | b << 16 | 0xFF << 24;
|
||||
}
|
||||
|
||||
unsigned emulate(enum FileKind kind, unsigned char const *rom, size_t rom_size, uint32_t screen[static 160 * 144])
|
||||
{
|
||||
GB_gameboy_t gb;
|
||||
GB_init(&gb, GB_MODEL_CGB_E);
|
||||
|
||||
GB_load_boot_rom_from_buffer(&gb, (unsigned char const *)boot_rom, sizeof(boot_rom));
|
||||
if (kind == KIND_ISX) {
|
||||
g_assert_not_reached(); // TODO: implement GB_load_isx_from_buffer
|
||||
}
|
||||
else {
|
||||
GB_load_rom_from_buffer(&gb, rom, rom_size);
|
||||
}
|
||||
|
||||
GB_set_user_data(&gb, GUINT_TO_POINTER(NB_FRAMES_TO_EMULATE));
|
||||
|
||||
GB_set_vblank_callback(&gb, vblank_callback);
|
||||
GB_set_pixels_output(&gb, screen);
|
||||
GB_set_rgb_encode_callback(&gb, rgb_encode);
|
||||
GB_set_async_input_callback(&gb, async_input_callback);
|
||||
GB_set_log_callback(&gb, log_callback);
|
||||
GB_set_color_correction_mode(&gb, GB_COLOR_CORRECTION_MODERN_BALANCED);
|
||||
|
||||
GB_set_rendering_disabled(&gb, true);
|
||||
GB_set_turbo_mode(&gb, true, true);
|
||||
while (GPOINTER_TO_UINT(GB_get_user_data(&gb))) {
|
||||
GB_run(&gb);
|
||||
}
|
||||
|
||||
unsigned cgb_flag = GB_read_memory(&gb, 0x143) & 0xC0;
|
||||
GB_free(&gb);
|
||||
return cgb_flag;
|
||||
}
|
15
XdgThumbnailer/emulate.h
Normal file
15
XdgThumbnailer/emulate.h
Normal file
@@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
enum FileKind {
|
||||
KIND_GB,
|
||||
KIND_GBC,
|
||||
KIND_ISX,
|
||||
};
|
||||
|
||||
void load_boot_rom(void);
|
||||
void unload_boot_rom(void);
|
||||
|
||||
unsigned emulate(enum FileKind kind, unsigned char const *rom, size_t rom_size, uint32_t screen[static 160 * 144]);
|
@@ -8,6 +8,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "emulate.h"
|
||||
#include "tasks.h"
|
||||
#include "thumbnail.h"
|
||||
|
||||
@@ -110,7 +111,7 @@ int main(int argc, char const *argv[])
|
||||
// unsigned active_worker_threads = 0;
|
||||
// Create the task queue *before* starting to accept tasks from D-Bus.
|
||||
init_tasks();
|
||||
load_boot_roms();
|
||||
load_boot_rom();
|
||||
// Likewise, create the main loop before then, so it can be aborted even before entering it.
|
||||
main_loop = g_main_loop_new(NULL, FALSE);
|
||||
|
||||
@@ -129,12 +130,12 @@ int main(int argc, char const *argv[])
|
||||
g_info("Waiting for outstanding tasks...");
|
||||
cleanup_tasks(); // Also waits for any remaining tasks.
|
||||
// "Pedantic" cleanup for Valgrind et al.
|
||||
unload_boot_roms();
|
||||
unload_boot_rom();
|
||||
g_main_loop_unref(main_loop);
|
||||
g_bus_unown_name(owner_id);
|
||||
if (thumbnailer_interface) {
|
||||
g_dbus_interface_skeleton_unexport(G_DBUS_INTERFACE_SKELETON(thumbnailer_interface));
|
||||
g_object_unref(thumbnailer_interface);
|
||||
}
|
||||
g_object_unref(thumbnailer_interface);
|
||||
return 0;
|
||||
}
|
||||
|
@@ -2,44 +2,15 @@
|
||||
|
||||
#include <gio/gio.h>
|
||||
#include <glib.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "Core/gb.h"
|
||||
#include "XdgThumbnailer/tasks.h"
|
||||
#include "emulate.h"
|
||||
#include "main.h"
|
||||
#include "tasks.h"
|
||||
|
||||
#define THUMBNAILING_ERROR_DOMAIN (g_quark_from_static_string("thumbnailing"))
|
||||
|
||||
enum FileKind {
|
||||
KIND_GB,
|
||||
KIND_GBC,
|
||||
KIND_ISX,
|
||||
};
|
||||
|
||||
#define BOOT_ROM_SIZE (0x100 + 0x800) // The two "parts" of it, which are stored contiguously.
|
||||
static char *boot_rom;
|
||||
|
||||
void load_boot_roms(void)
|
||||
{
|
||||
static char const *boot_rom_path = DATA_DIR "/cgb_boot_fast.bin";
|
||||
|
||||
size_t length;
|
||||
GError *error = NULL;
|
||||
g_file_get_contents(boot_rom_path, &boot_rom, &length, &error);
|
||||
|
||||
if (error) {
|
||||
g_error("Error loading boot ROM from \"%s\": %s", boot_rom_path, error->message);
|
||||
// NOTREACHED
|
||||
}
|
||||
else if (length != BOOT_ROM_SIZE) {
|
||||
g_error("Error loading boot ROM from \"%s\": expected to read %d bytes, got %zu",
|
||||
boot_rom_path, BOOT_ROM_SIZE, length);
|
||||
// NOTREACHED
|
||||
}
|
||||
}
|
||||
|
||||
void unload_boot_roms(void) { g_free(boot_rom); }
|
||||
|
||||
struct TaskData {
|
||||
char *contents;
|
||||
size_t length;
|
||||
@@ -59,19 +30,11 @@ static void generate_thumbnail(GTask *task, void *source_object, void *data,
|
||||
{
|
||||
struct TaskData *task_data = data;
|
||||
|
||||
GB_gameboy_t gb;
|
||||
GB_init(&gb, GB_MODEL_CGB_E);
|
||||
GB_load_boot_rom_from_buffer(&gb, (unsigned char const *)boot_rom, sizeof(boot_rom));
|
||||
|
||||
if (task_data->kind == KIND_ISX) {
|
||||
g_assert_not_reached(); // TODO: implement GB_load_isx_from_buffer
|
||||
}
|
||||
else {
|
||||
GB_load_rom_from_buffer(&gb, (unsigned char const *)task_data->contents, task_data->length);
|
||||
}
|
||||
// TODO
|
||||
|
||||
GB_free(&gb);
|
||||
uint32_t screen[160 * 144];
|
||||
unsigned cgb_flag = emulate(task_data->kind, (unsigned char const *)task_data->contents,
|
||||
task_data->length, screen);
|
||||
// TODO: generate the thumbnail from `screen` and `cgb_flag`.
|
||||
(void)cgb_flag;
|
||||
|
||||
g_task_return_boolean(task, TRUE);
|
||||
g_object_unref(task);
|
||||
@@ -112,7 +75,7 @@ static void on_thumbnailing_end(GObject *source_object, GAsyncResult *res, void
|
||||
|
||||
g_assert_null(source_object); // The object that was passed to `g_task_new`.
|
||||
GTask *task = G_TASK(res);
|
||||
g_debug("Ending thumbnailing for \"%s\"", g_task_get_name(task));
|
||||
g_info("Ending thumbnailing for \"%s\"", g_task_get_name(task));
|
||||
unsigned handle = GPOINTER_TO_UINT(user_data);
|
||||
char const *uri = g_task_get_name(task);
|
||||
|
||||
|
@@ -3,8 +3,5 @@
|
||||
#include <glib.h>
|
||||
#include <gio/gio.h>
|
||||
|
||||
void load_boot_roms(void);
|
||||
void unload_boot_roms(void);
|
||||
|
||||
void start_thumbnailing(unsigned handle, GCancellable *cancellable, gboolean is_urgent,
|
||||
char const *uri, char const *mime_type);
|
||||
|
Reference in New Issue
Block a user