Start working in the new interfaces.

Seriously broken WinAPI stuff, no input, no multi-
threading a bunch of other terrible stuff (yet).
This commit is contained in:
Tyler J. Stachecki 2015-04-27 08:23:05 -04:00
parent b5fbc3d939
commit 7f203b7175
20 changed files with 222 additions and 771 deletions

View file

@ -49,7 +49,7 @@ if (${CMAKE_C_COMPILER_ID} MATCHES GNU)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -msse4")
set(CMAKE_ASM-ATT_FLAGS "${CMAKE_ASM-ATT_FLAGS} -march=sse4.1 --defsym __SSE4_1__=1 --defsym __SSSE3__=1 --defsym __SSE3__=1")
elseif (${CEN64_ARCH_SUPPORT} MATCHES "AVX")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mavx")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mavx -march=native")
set(CMAKE_ASM-ATT_FLAGS "${CMAKE_ASM-ATT_FLAGS} -march=avx --defsym __AVX__=1")
endif ()
@ -229,6 +229,7 @@ option(VR4300_BUSY_WAIT_DETECTION "Detect and special case VR4300 busy wait loop
include_directories(${PROJECT_BINARY_DIR})
include_directories(${PROJECT_SOURCE_DIR})
include_directories(${PROJECT_SOURCE_DIR}/arch/${CEN64_ARCH_DIR})
include_directories(${PROJECT_SOURCE_DIR}/os/common)
file(GLOB AI_SOURCES ${PROJECT_SOURCE_DIR}/ai/*.c)
file(GLOB BUS_SOURCES ${PROJECT_SOURCE_DIR}/bus/*.c)
@ -256,17 +257,33 @@ if (DEFINED UNIX)
file(GLOB OS_SOURCES ${PROJECT_SOURCE_DIR}/os/unix/*.c)
if (NOT DISABLE_X11)
#if (NOT DISABLE_X11)
find_package(X11 REQUIRED)
include_directories(${X11_xf86vmode_INCLUDE_PATH})
include_directories(${PROJECT_SOURCE_DIR}/os/x11)
set(EXTRA_OS_LIBS ${X11_X11_LIB} ${X11_Xxf86vm_LIB})
set(EXTRA_OS_EXE "")
file(GLOB X11_SOURCES ${PROJECT_SOURCE_DIR}/os/unix/x11/*.c)
list(APPEND X11_SOURCES
${PROJECT_SOURCE_DIR}/os/common/gl_hints.c
${PROJECT_SOURCE_DIR}/os/x11/gl_config.c
${PROJECT_SOURCE_DIR}/os/x11/gl_window.c
${PROJECT_SOURCE_DIR}/os/posix/alloc.c
)
list(APPEND OS_SOURCES ${X11_SOURCES})
endif (NOT DISABLE_X11)
#endif (NOT DISABLE_X11)
elseif (DEFINED WIN32)
include_directories(${PROJECT_SOURCE_DIR}/os/winapi)
file(GLOB OS_SOURCES ${PROJECT_SOURCE_DIR}/os/windows/*.c)
list(APPEND OS_SOURCES
${PROJECT_SOURCE_DIR}/os/common/gl_hints.c
${PROJECT_SOURCE_DIR}/os/winapi/gl_config.c
${PROJECT_SOURCE_DIR}/os/winapi/gl_window.c
${PROJECT_SOURCE_DIR}/os/winapi/alloc.c
)
set(EXTRA_OS_LIBS ws2_32 winmm opengl32)
set(EXTRA_OS_EXE WIN32)
endif (DEFINED UNIX)
@ -308,6 +325,6 @@ add_library(cen64vr4300 STATIC ${VR4300_SOURCES})
add_executable(cen64 ${EXTRA_OS_EXE} "${PROJECT_SOURCE_DIR}/device/device.c" "${PROJECT_SOURCE_DIR}/device/netapi.c")
target_link_libraries(cen64
cen64ai cen64bus cen64dd cen64pi cen64rdp cen64ri cen64rsp cen64si cen64vr4300 cen64arch cen64os cen64vi
cen64ai cen64bus cen64dd cen64pi cen64rdp cen64ri cen64rsp cen64si cen64vr4300 cen64arch cen64vi cen64os
${EXTRA_OS_LIBS} ${OPENGL_gl_LIBRARY} ${CMAKE_THREAD_LIBS_INIT})

46
cen64.c
View file

@ -8,25 +8,36 @@
// 'LICENSE', which is part of this source code package.
//
#include "bus/controller.h"
#include "common.h"
#include "bus/controller.h"
#include "cen64.h"
#include "device/device.h"
#include "device/options.h"
#include "os/common/alloc.h"
#include "os/main.h"
#include "os/rom_file.h"
#include <stdlib.h>
static int load_roms(const char *ddipl_path, const char *ddrom_path,
cen64_cold static int load_roms(const char *ddipl_path, const char *ddrom_path,
const char *pifrom_path, const char *cart_path, struct rom_file *ddipl,
struct rom_file *ddrom, struct rom_file *pifrom, struct rom_file *cart);
// Called when another simulation instance is desired.
int cen64_cmdline_main(int argc, const char *argv[]) {
int cen64_main(int argc, const char *argv[]) {
struct cen64_options options = default_cen64_options;
struct rom_file ddipl, ddrom, pifrom, cart;
struct cen64_mem cen64_device_mem;
struct cen64_device *device;
int status;
if (cen64_alloc_init()) {
printf("Failed to initialize the low-level allocators.\n");
return EXIT_FAILURE;
}
if (argc < 3) {
print_command_line_usage(argv[0]);
cen64_alloc_cleanup();
return EXIT_SUCCESS;
}
@ -34,6 +45,7 @@ int cen64_cmdline_main(int argc, const char *argv[]) {
printf("Invalid command line argument(s) specified.\n");
print_command_line_usage(argv[0]);
cen64_alloc_cleanup();
return EXIT_FAILURE;
}
@ -42,11 +54,34 @@ int cen64_cmdline_main(int argc, const char *argv[]) {
memset(&cart, 0, sizeof(cart));
if (load_roms(options.ddipl_path, options.ddrom_path, options.pifrom_path,
options.cart_path, &ddipl, &ddrom, &pifrom, &cart))
options.cart_path, &ddipl, &ddrom, &pifrom, &cart)) {
cen64_alloc_cleanup();
return EXIT_FAILURE;
}
status = os_main(&options, &ddipl, &ddrom, &pifrom, &cart);
// Allocate memory for and create the device.
if (cen64_alloc(&cen64_device_mem, sizeof(*device), false) == NULL) {
printf("Failed to allocate enough memory for a device.\n");
status = EXIT_FAILURE;
}
else {
device = (struct cen64_device *) cen64_device_mem.ptr;
if (device_create(device, &ddipl, &ddrom, &pifrom, &cart) == NULL) {
printf("Failed to create a device.\n");
status = EXIT_FAILURE;
}
else {
status = os_main(device, &options);
device_destroy(device);
}
cen64_free(&cen64_device_mem);
}
// Release resources.
if (options.ddipl_path)
close_rom_file(&ddipl);
@ -57,6 +92,7 @@ int cen64_cmdline_main(int argc, const char *argv[]) {
close_rom_file(&cart);
close_rom_file(&pifrom);
cen64_alloc_cleanup();
return status;
}

View file

@ -12,7 +12,7 @@
#define __cen64_h__
#include "common.h"
cen64_cold int cen64_cmdline_main(int argc, const char *argv[]);
cen64_cold int cen64_main(int argc, const char *argv[]);
#endif

View file

@ -33,7 +33,7 @@ cen64_cold static int device_debug_spin(struct cen64_device *device);
cen64_flatten cen64_hot static int device_spin(struct cen64_device *device);
// Creates and initializes a device.
struct cen64_device *device_create(struct cen64_device *device, uint8_t *ram,
struct cen64_device *device_create(struct cen64_device *device,
const struct rom_file *ddipl, const struct rom_file *ddrom,
const struct rom_file *pifrom, const struct rom_file *cart) {
@ -75,7 +75,7 @@ struct cen64_device *device_create(struct cen64_device *device, uint8_t *ram,
}
// Initialize the RI.
if (ri_init(&device->ri, &device->bus, ram)) {
if (ri_init(&device->ri, &device->bus)) {
debug("create_device: Failed to initialize the RI.\n");
return NULL;
}

View file

@ -11,7 +11,7 @@
#ifndef __device_h__
#define __device_h__
#include "common.h"
#include "options.h"
#include "device/options.h"
#include "os/rom_file.h"
#include "ai/controller.h"
@ -25,8 +25,6 @@
#include "vi/controller.h"
#include "vr4300/cpu.h"
#define DEVICE_RAMSIZE 0x800000U
// Only used when passed -nointerface.
extern bool device_exit_requested;
@ -48,7 +46,7 @@ struct cen64_device {
cen64_cold void device_destroy(struct cen64_device *device);
cen64_cold struct cen64_device *device_create(struct cen64_device *device,
uint8_t *ram, const struct rom_file *ddipl, const struct rom_file *ddrom,
const struct rom_file *ddipl, const struct rom_file *ddrom,
const struct rom_file *pifrom, const struct rom_file *cart);
cen64_cold void device_exit(struct bus_controller *bus);

View file

@ -97,11 +97,15 @@ int parse_options(struct cen64_options *options, int argc, const char *argv[]) {
// Prints the command-line usage string.
void print_command_line_usage(const char *invokation_string) {
#ifdef _WIN32
show_console();
#endif
printf("%s [Options] <PIF IPL ROM Path> [Cart ROM Path]\n\n"
"Options:\n"
#ifdef _WIN32
" -console : Creates/shows the system console.\n"
" -console : Creates/shows this system console window.\n"
#endif
" -debug [addr][:port] : Starts the debugger on interface:port.\n"
" By default, CEN64 uses localhost:64646.\n"
@ -111,5 +115,9 @@ void print_command_line_usage(const char *invokation_string) {
,invokation_string
);
#ifdef _WIN32
hide_console();
#endif
}

View file

@ -15,7 +15,7 @@ const cen64_gl_hints cen64_default_gl_hints = {
CEN64_GL_CONTEXT_TYPE_RGBA,
CEN64_GL_DRAWABLE_TYPE_WINDOW,
-1, // double_buffered
1, // double_buffered
-1, // stereoscopic
-1, // rgb_color_depth

View file

@ -23,9 +23,6 @@ struct bus_controller;
struct gl_window {
void *window;
float viuv[8];
float quad[8];
};
struct gl_window_hints {

View file

@ -9,15 +9,16 @@
#ifndef __os_main_h__
#define __os_main_h__
#include "device/device.h"
#include "device/options.h"
#include "os/gl_window.h"
#include "rom_file.h"
cen64_cold int os_main(struct cen64_options *options, struct rom_file *ddipl,
struct rom_file *ddrom, struct rom_file *pifrom, struct rom_file *cart);
cen64_cold int os_main(struct cen64_device *device,
struct cen64_options *options);
cen64_cold bool os_exit_requested(struct gl_window *gl_window);
cen64_cold void os_render_frame(struct gl_window *gl_window, const void *data,
cen64_cold void os_render_frame(cen64_gl_window window, const void *data,
unsigned xres, unsigned yres, unsigned xskip, unsigned type);
cen64_cold void os_acquire_input(struct gl_window *gl_window);

View file

@ -11,6 +11,7 @@
#include "device/device.h"
#include "device/netapi.h"
#include "device/options.h"
#include "os/common/alloc.h"
#include "os/gl_window.h"
#include "os/main.h"
#include "os/unix/x11/glx_window.h"
@ -21,14 +22,6 @@
#include <sys/stat.h>
#include <unistd.h>
struct ram_hunk {
size_t size;
void *ptr;
};
cen64_cold static uint8_t *allocate_ram(struct ram_hunk *ram, size_t size);
cen64_cold static void deallocate_ram(struct ram_hunk *ram);
cen64_cold static void *run_device_thread(void *opaque);
// Only used when passed -nointerface.
@ -38,56 +31,9 @@ cen64_cold static void device_sigint(int signum) {
device_exit_requested = true;
}
// Global file descriptor for allocations.
#ifdef __linux__
const char *zero_page_path = "/dev/zero";
#else
const char *zero_page_path = "/dev/null";
#endif
int zero_page_fd;
// Allocates a large hunk of zeroed RAM.
uint8_t *allocate_ram(struct ram_hunk *ram, size_t size) {
#ifdef __APPLE__
// Use MAP_ANON on OSX because it really does not enjoy trying to mmap
// from devices.
if ((ram->ptr = mmap(NULL, size, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANON, -1, 0)) == MAP_FAILED) {
return NULL;
}
#else
if ((ram->ptr = mmap(NULL, size, PROT_READ | PROT_WRITE,
MAP_PRIVATE, zero_page_fd, 0)) == MAP_FAILED) {
return NULL;
}
#endif //__APPLE__
#ifndef __linux__
memset(ram->ptr, 0, size);
#endif
ram->size = size;
return ram->ptr;
}
// Deallocates a large hunk of RAM.
void deallocate_ram(struct ram_hunk *ram) {
munmap(ram->ptr, ram->size);
}
// Unix application entry point.
int main(int argc, const char *argv[]) {
int status;
if ((zero_page_fd = open(zero_page_path, O_RDWR)) < 0) {
printf("Failed to open: %s\n", zero_page_path);
return EXIT_FAILURE;
}
status = cen64_cmdline_main(argc, argv);
close(zero_page_fd);
return status;
return cen64_main(argc, argv);
}
// Grabs the input lock.
@ -105,49 +51,28 @@ void os_release_input(struct gl_window *gl_window) {
}
// Informs the simulation thread if an exit was requested.
#if 0
bool os_exit_requested(struct gl_window *gl_window) {
struct glx_window *glx_window = (struct glx_window *) (gl_window->window);
return glx_window_exit_requested(glx_window);
}
#endif
// Allocates memory for a new device, runs it.
int os_main(struct cen64_options *options, struct rom_file *ddipl,
struct rom_file *ddrom, struct rom_file *pifrom, struct rom_file *cart) {
int os_main(struct cen64_device *device, struct cen64_options *options) {
struct gl_window_hints hints;
struct glx_window window;
pthread_t device_thread;
// Allocate the device on the stack.
struct cen64_device device;
struct ram_hunk hunk;
uint8_t *ram;
if ((ram = allocate_ram(&hunk, DEVICE_RAMSIZE)) == NULL) {
printf("Failed to allocate enough memory.\n");
return 1;
}
// Prevent debugging tools from raising warnings
// about uninitialized memory being read, etc.
memset(&device, 0, sizeof(device));
if (device_create(&device, ram, ddipl, ddrom, pifrom, cart) == NULL) {
printf("Failed to create a device.\n");
deallocate_ram(&hunk);
return 1;
}
#if 0
// Spawn the user interface (or signal handler).
if (!options->no_interface) {
device.vi.gl_window.window = &window;
device->vi.gl_window.window = &window;
get_default_gl_window_hints(&hints);
if (create_gl_window(&device.bus, &device.vi.gl_window, &hints)) {
if (create_gl_window(&device->bus, &device->vi.gl_window, &hints)) {
printf("Failed to create a window.\n");
deallocate_ram(&hunk);
return 1;
}
}
@ -156,47 +81,50 @@ int os_main(struct cen64_options *options, struct rom_file *ddipl,
if (signal(SIGINT, device_sigint) == SIG_ERR)
printf("Failed to register SIGINT handler.\n");
}
#endif
// Pull up the debug API if it was requested.
device.debug_sfd = -1;
device->debug_sfd = -1;
if (options->enable_debugger) {
if ((device.debug_sfd = netapi_open_connection()) < 0) {
if ((device->debug_sfd = netapi_open_connection()) < 0) {
printf("Failed to bind/listen for a connection.\n");
destroy_gl_window(&device.vi.gl_window);
device_destroy(&device);
deallocate_ram(&hunk);
//destroy_gl_window(&device->vi.gl_window);
device_destroy(device);
return 1;
}
}
device_run(device);
#if 0
// Start the device thread, hand over control to the UI thread on success.
if ((pthread_create(&device_thread, NULL, run_device_thread, &device)) == 0) {
gl_window_thread(&device.vi.gl_window, &device.bus);
if ((pthread_create(&device_thread, NULL, run_device_thread, device)) == 0) {
//gl_window_thread(&device->vi.gl_window, &device->bus);
pthread_join(device_thread, NULL);
}
else
printf("Unable to spawn a thread for the device.\n");
#endif
if (device.debug_sfd >= 0)
netapi_close_connection(device.debug_sfd);
if (device->debug_sfd >= 0)
netapi_close_connection(device->debug_sfd);
#if 0
if (!options->no_interface)
destroy_gl_window(&device.vi.gl_window);
destroy_gl_window(&device->vi.gl_window);
#endif
device_destroy(&device);
deallocate_ram(&hunk);
return 0;
}
// Pushes a frame to the rendering thread.
void os_render_frame(struct gl_window *gl_window, const void *data,
void os_render_frame(cen64_gl_window window, const void *data,
unsigned xres, unsigned yres, unsigned xskip, unsigned type) {
struct glx_window *glx_window = (struct glx_window *) (gl_window->window);
// struct glx_window *glx_window = (struct glx_window *) (gl_window->window);
glx_window_render_frame(glx_window, data, xres, yres, xskip, type);
// glx_window_render_frame(glx_window, data, xres, yres, xskip, type);
}
// Runs the device, always returns NULL.

View file

@ -1,614 +0,0 @@
//
// os/unix/x11/glx_window.c
//
// Convenience functions for managing rendering windows.
//
// This file is subject to the terms and conditions defined in
// 'LICENSE', which is part of this source code package.
//
#include "bus/controller.h"
#include "common.h"
#include "common/debug.h"
#include "os/gl_window.h"
#include "os/input.h"
#include "os/timer.h"
#include "os/unix/x11/glx_window.h"
#include "vi/controller.h"
#include <errno.h>
#include <pthread.h>
#include <stddef.h>
#include <string.h>
#include <stdio.h>
#include <sys/select.h>
#include <unistd.h>
#include <GL/glx.h>
#include <X11/Xatom.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/extensions/xf86vmode.h>
// Functions to assist in taming X11.
cen64_cold static int create_glx_context(
struct glx_window *glx_window, GLXContext *context);
cen64_cold static int destroy_glx_window(struct glx_window *glx_window);
cen64_cold static void generate_attribute_list(int *attribute_list,
const struct gl_window_hints *hints);
cen64_cold static int get_matching_visual_info(struct glx_window *glx_window,
int *attribute_list, XVisualInfo **visual_info);
cen64_cold static int get_matching_window_mode(struct glx_window *glx_window,
const struct gl_window_hints *hints, XF86VidModeModeInfo *mode);
cen64_cold static bool glx_window_poll_events(struct bus_controller *bus,
struct glx_window *glx_window);
cen64_cold static int glx_window_thread(struct gl_window *gl_window,
struct glx_window *glx_window, struct bus_controller *bus);
cen64_cold static void glx_window_update_window_title(
struct glx_window *glx_window, cen64_time *last_report_time);
cen64_cold static int switch_to_fullscreen(struct glx_window *glx_window,
const struct gl_window_hints *hints);
// Creates a new rendering context.
int create_glx_context(struct glx_window *glx_window, GLXContext *context) {
GLXContext check_context = glXCreateContext(glx_window->display,
glx_window->visual_info, 0, GL_TRUE);
if (check_context == NULL) {
debug("create_glx_context: Unknown client-side error.\n");
return 1;
}
else if (check_context == (void*) BadAlloc) {
debug("create_glx_context: Server is out of resources.\n");
return 1;
}
else if (check_context == (void*) BadMatch) {
debug("create_glx_context: Context address space mismatch.\n");
return 1;
}
else if (check_context == (void*) BadValue) {
debug("create_glx_context: Unsupported visual mode specified.\n");
return 1;
}
*context = check_context;
return 0;
}
// Jumps to the entry point for the user interface code.
int gl_window_thread(struct gl_window *gl_window, struct bus_controller *bus) {
struct glx_window *glx_window = (struct glx_window *) (gl_window->window);
return glx_window_thread(gl_window, glx_window, bus);
}
// Creates a new rendering window.
int create_gl_window(struct bus_controller *bus,
struct gl_window *gl_window, const struct gl_window_hints *hints) {
struct glx_window *glx_window;
int window_valuemask;
Window root_window;
// We may set this to false if we fail
// to change active the windowing mode.
int fullscreen = hints->fullscreen;
// Magic number was chosen based on the glXChooseFBConfig man page.
// It is at least large enough to hold the supported attributes, as
// well as a few additional ones. Expand it at your convenience.
int attribute_list[64];
debug("create_gl_window: Creating window...\n");
glx_window = (struct glx_window *) (gl_window->window);
memset(glx_window, 0, sizeof(*glx_window));
if (pipe(glx_window->select_pipefds) < 0) {
debug("create_gl_window: Could not open pipe for thread comm.\n");
return 1;
}
pthread_mutex_init(&glx_window->event_lock, NULL);
pthread_mutex_init(&glx_window->render_lock, NULL);
pthread_cond_init(&glx_window->render_cv, NULL);
// Open a connection and get the default screen number.
if ((glx_window->display = XOpenDisplay(NULL)) == NULL) {
debug("create_gl_window: Could not open connection to server.\n");
goto create_out_destroy;
}
glx_window->screen = DefaultScreen(glx_window->display);
root_window = RootWindow(glx_window->display, glx_window->screen);
// Use hints to create a window, then bind the GL context.
generate_attribute_list(attribute_list, hints);
if (get_matching_visual_info(glx_window,
attribute_list, &glx_window->visual_info)) {
debug("create_gl_window: Failed to match window hints.\n");
goto create_out_destroy;
}
if (create_glx_context(glx_window, &glx_window->context)) {
debug("create_gl_window: Failed to acquire a GL context.\n");
goto create_out_destroy;
}
glx_window->attr.event_mask = ExposureMask | KeyPressMask |
KeyReleaseMask | ButtonPressMask | StructureNotifyMask;
if (!(glx_window->attr.colormap = XCreateColormap(glx_window->display,
root_window, glx_window->visual_info->visual, AllocNone))) {
debug("create_gl_window: Failed to create a colormap.\n");
goto create_out_destroy;
}
window_valuemask = CWBorderPixel | CWColormap | CWEventMask;
// If going fullscreen, tell XF86 to set the mode.
if (fullscreen) {
if (!switch_to_fullscreen(glx_window, hints)) {
glx_window->went_fullscreen = 1;
glx_window->attr.override_redirect = True;
window_valuemask |= CWOverrideRedirect;
}
else {
debug("create_gl_window: Failed to to go fullscreen; falling back.\n");
fullscreen = 0;
}
}
if (!(glx_window->window = XCreateWindow(glx_window->display, root_window,
0, 0, hints->width, hints->height, 0, glx_window->visual_info->depth,
InputOutput, glx_window->visual_info->visual, window_valuemask,
&glx_window->attr))) {
debug("create_gl_window: Failed to create a window.\n");
goto create_out_destroy;
}
glx_window->wm_delete_message = XInternAtom(
glx_window->display, "WM_DELETE_WINDOW", False);
XSetWMProtocols(glx_window->display, glx_window->window,
&glx_window->wm_delete_message, 1);
// If going fullscreen, hide the pointer, trap input devices, etc.
if (fullscreen) {
XWarpPointer(glx_window->display, None,
glx_window->window, 0, 0, 0, 0, 0, 0);
XGrabKeyboard(glx_window->display, glx_window->window, True,
GrabModeAsync, GrabModeAsync, CurrentTime);
XGrabPointer(glx_window->display, glx_window->window, True,
ButtonPressMask, GrabModeAsync, GrabModeAsync,
glx_window->window, None, CurrentTime);
}
XSetStandardProperties(glx_window->display, glx_window->window,
"CEN64 ["CEN64_COMPILER" - "CEN64_ARCH_DIR"/"CEN64_ARCH_SUPPORT"]",
"CEN64", None, NULL, 0, NULL);
XMapRaised(glx_window->display, glx_window->window);
return 0;
create_out_destroy:
destroy_glx_window(glx_window);
return 1;
}
// Destroys an existing rendering window.
int destroy_gl_window(struct gl_window *gl_window) {
struct glx_window *glx_window = (struct glx_window *) (gl_window->window);
destroy_glx_window(glx_window);
pthread_cond_destroy(&glx_window->render_cv);
pthread_mutex_destroy(&glx_window->render_lock);
pthread_mutex_destroy(&glx_window->event_lock);
return 0;
}
// Releases resources acquired for a rendering window.
int destroy_glx_window(struct glx_window *glx_window) {
if (glx_window->went_fullscreen) {
XF86VidModeSwitchToMode(glx_window->display,
glx_window->screen, &glx_window->old_mode);
}
if (glx_window->context) {
if (!glXMakeCurrent(glx_window->display, None, NULL)) {
debug("destroy_glx_window: Could not release rendering context.\n");
return 1;
}
glXDestroyContext(glx_window->display, glx_window->context);
glx_window->context = NULL;
}
if (glx_window->window) {
XDestroyWindow(glx_window->display, glx_window->window);
glx_window->window = 0;
}
if (glx_window->attr.colormap) {
XFreeColormap(glx_window->display, glx_window->attr.colormap);
glx_window->attr.colormap = 0;
}
if (glx_window->visual_info) {
XFree(glx_window->visual_info);
glx_window->visual_info = NULL;
}
if (glx_window->display) {
XCloseDisplay(glx_window->display);
glx_window->display = NULL;
}
close(glx_window->select_pipefds[0]);
close(glx_window->select_pipefds[1]);
return 0;
}
// Fills the array with attributes that best match the hints.
void generate_attribute_list(int *attribute_list,
const struct gl_window_hints *hints) {
int idx = 0;
attribute_list[idx++] = GLX_DRAWABLE_TYPE;
attribute_list[idx++] = GLX_WINDOW_BIT;
attribute_list[idx++] = GLX_RENDER_TYPE;
attribute_list[idx++] = GLX_RGBA_BIT;
attribute_list[idx++] = GLX_DOUBLEBUFFER;
attribute_list[idx++] = hints->double_buffered
? True : False;
attribute_list[idx++] = GLX_RED_SIZE;
attribute_list[idx++] = hints->color_bits;
attribute_list[idx++] = GLX_GREEN_SIZE;
attribute_list[idx++] = hints->color_bits;
attribute_list[idx++] = GLX_BLUE_SIZE;
attribute_list[idx++] = hints->color_bits;
attribute_list[idx++] = GLX_ALPHA_SIZE;
attribute_list[idx++] = hints->alpha_bits;
attribute_list[idx++] = GLX_DEPTH_SIZE;
attribute_list[idx++] = hints->depth_bits;
attribute_list[idx++] = GLX_STENCIL_SIZE;
attribute_list[idx++] = hints->stencil_bits;
attribute_list[idx++] = GLX_ACCUM_RED_SIZE;
attribute_list[idx++] = hints->accum_color_bits;
attribute_list[idx++] = GLX_ACCUM_GREEN_SIZE;
attribute_list[idx++] = hints->accum_color_bits;
attribute_list[idx++] = GLX_ACCUM_BLUE_SIZE;
attribute_list[idx++] = hints->accum_color_bits;
attribute_list[idx++] = GLX_ACCUM_ALPHA_SIZE;
attribute_list[idx++] = hints->accum_alpha_bits;
attribute_list[idx++] = GLX_AUX_BUFFERS;
attribute_list[idx++] = hints->auxiliary_buffers;
/* Terminate the list. */
attribute_list[idx++] = None;
}
// Packs hints with a reasonable set of default hints.
void get_default_gl_window_hints(struct gl_window_hints *hints) {
memset(hints, 0, sizeof(*hints));
hints->width = 640;
hints->height = 480;
hints->fullscreen = 0;
hints->double_buffered = 1;
}
// Generates a XVisualInfo that matches the attributes.
int get_matching_visual_info(struct glx_window *window,
int *attribute_list, XVisualInfo **visual_info) {
XVisualInfo *check_visual_info = NULL;
int i, status = 0, num_configs = 0;
GLXFBConfig *fb_configs;
if ((fb_configs = glXChooseFBConfig(window->display, window->screen,
attribute_list, &num_configs)) == NULL || num_configs == 0) {
debug("get_matching_visual_info: No matching framebuffer configs.\n");
return 1;
}
for (i = 0; i < num_configs && check_visual_info == NULL; i++)
check_visual_info = glXGetVisualFromFBConfig(window->display, *fb_configs);
if (check_visual_info == NULL) {
debug("get_matching_visual_info: Could not get associated visual info.\n");
status = 1;
}
*visual_info = check_visual_info;
XFree(fb_configs);
return status;
}
// Finds a windowing most at least as big as desired resolution.
int get_matching_window_mode(struct glx_window *glx_window,
const struct gl_window_hints *hints, XF86VidModeModeInfo *mode) {
XF86VidModeModeInfo **modes;
int i, not_found, num_modes;
not_found = 1;
num_modes = 0;
if (!XF86VidModeGetAllModeLines(glx_window->display,
glx_window->screen, &num_modes, &modes) || num_modes <= 0) {
debug("get_matching_window_mode: Failed to query window modes.\n");
return 1;
}
*mode = *modes[0];
for (i = 0; i < num_modes - 1; i++) {
unsigned width = modes[i]->hdisplay;
unsigned height = modes[i]->vdisplay;
if (width == hints->width && height == hints->height) {
*mode = *modes[i];
not_found = 0;
break;
}
}
XFree(modes);
return not_found;
}
// Promotes the contents of the back buffer to the front buffer.
int gl_swap_buffers(const struct gl_window *window) {
const struct glx_window *glx_window;
glx_window = (const struct glx_window *) (window->window);
glXSwapBuffers(glx_window->display, glx_window->window);
return 0;
}
// Informs the caller if an exit was requested.
bool glx_window_exit_requested(struct glx_window *window) {
bool exit_requested;
pthread_mutex_lock(&window->event_lock);
exit_requested = window->exit_requested;
pthread_mutex_unlock(&window->event_lock);
return exit_requested;
}
// Handles events that come from X11.
bool glx_window_poll_events(struct bus_controller *bus,
struct glx_window *glx_window) {
bool released, exit_requested;
XEvent event;
if (!XPending(glx_window->display))
return false;
exit_requested = false;
pthread_mutex_lock(&glx_window->event_lock);
do {
XNextEvent(glx_window->display, &event);
switch (event.type) {
case ClientMessage:
if ((unsigned) event.xclient.data.l[0] == glx_window->wm_delete_message)
glx_window->exit_requested = exit_requested = true;
break;
case ConfigureNotify:
gl_window_resize_cb(event.xconfigure.width, event.xconfigure.height);
break;
case KeyPress:
keyboard_press_callback(bus, XLookupKeysym(&event.xkey, 0));
break;
case KeyRelease:
released = true;
// Detect and correct auto-repeated keys. Auto-repeated KeyEvents
// will be inserted immediately after the release.
if (XEventsQueued(glx_window->display, QueuedAfterReading)) {
XEvent next_event;
XPeekEvent(glx_window->display, &next_event);
if (next_event.type == KeyPress && next_event.xkey.time ==
event.xkey.time && next_event.xkey.keycode == event.xkey.keycode) {
XNextEvent(glx_window->display, &event);
released = false;
}
}
if (released)
keyboard_release_callback(bus, XLookupKeysym(&event.xkey, 0));
break;
}
} while (XPending(glx_window->display));
pthread_mutex_unlock(&glx_window->event_lock);
return exit_requested;
}
// Copies the frame data to the render thread.
void glx_window_render_frame(struct glx_window *window, const void *data,
unsigned xres, unsigned yres, unsigned xskip, unsigned type) {
size_t copy_size;
switch (type & 0x3) {
case 0:
case 1:
copy_size = 0;
break;
// TODO: Why 4?
case 2:
copy_size = 4;
break;
case 3:
copy_size = 4;
break;
}
copy_size *= xres * yres;
// Grab the locks and pass the next frame to the UI.
// Wait for the UI if it didn't push out the last frame.
pthread_mutex_lock(&window->render_lock);
while (unlikely(window->frame_pending))
pthread_cond_wait(&window->render_cv, &window->render_lock);
memcpy(window->frame_data, data, copy_size);
window->frame_xres = xres;
window->frame_yres = yres;
window->frame_xskip = xskip;
window->frame_type = type;
window->frame_pending = true;
pthread_mutex_unlock(&window->render_lock);
// Write a dummy value to trigger the select() call.
write(window->select_pipefds[1], window, 1);
}
// Main window threads. Handles and pumps events.
int glx_window_thread(struct gl_window *gl_window,
struct glx_window *glx_window, struct bus_controller *bus) {
int frame_count, max_fds, x11_fd, pipe_fd;
cen64_time last_report_time;
fd_set fdset;
// Activate the rendering context from THIS thread.
// Any kind of GL call has to be done from here, or else.
if (!glXMakeCurrent(glx_window->display,
glx_window->window, glx_window->context)) {
debug("glx_window_thread: Could not attach rendering context.\n");
return 1;
}
gl_window_init(gl_window);
// Setup the fd_set and max_fds for the select() call.
x11_fd = ConnectionNumber(glx_window->display);
pipe_fd = glx_window->select_pipefds[0];
max_fds = x11_fd > pipe_fd ? x11_fd: pipe_fd;
max_fds++;
FD_ZERO(&fdset);
FD_SET(pipe_fd, &fdset);
FD_SET(x11_fd, &fdset);
// Prime the timer we use to report the VI/s.
// Then stick ourselves into the UI main loop.
get_time(&last_report_time);
for (frame_count = 0; ;) {
fd_set ready_to_read = fdset;
// Wait for the next "draw frame" and/or X11 event.
if (select(max_fds, &ready_to_read, NULL, NULL, NULL) > 0) {
if (FD_ISSET(x11_fd, &ready_to_read)) {
if (unlikely(glx_window_poll_events(bus, glx_window)))
break;
}
if (FD_ISSET(pipe_fd, &ready_to_read)) {
char dummy;
// Deal with any of the synchronized state first.
pthread_mutex_lock(&glx_window->render_lock);
glx_window->frame_pending = false;
gl_window_render_frame(gl_window, glx_window->frame_data,
glx_window->frame_xres, glx_window->frame_yres,
glx_window->frame_xskip, glx_window->frame_type);
pthread_mutex_unlock(&glx_window->render_lock);
pthread_cond_signal(&glx_window->render_cv);
// Clear the notification, possible update VI/s indicator.
read(pipe_fd, &dummy, sizeof(dummy));
if (unlikely(++frame_count == 60)) {
glx_window_update_window_title(glx_window, &last_report_time);
frame_count = 0;
}
}
}
}
return 0;
}
// Updates the window title.
void glx_window_update_window_title(
struct glx_window *glx_window, cen64_time *last_report_time) {
cen64_time current_time;
unsigned long long ns;
char window_title[64];
get_time(&current_time);
ns = compute_time_difference(&current_time, last_report_time);
snprintf(window_title, sizeof(window_title),
"CEN64 ["CEN64_COMPILER" - "CEN64_ARCH_DIR"/"CEN64_ARCH_SUPPORT"]"
" - %.1f VI/s", (60 / ((double) ns / NS_PER_SEC)));
XStoreName(glx_window->display, glx_window->window, window_title);
XFlush(glx_window->display);
*last_report_time = current_time;
}
// Attempts to switch to fullscreen mode.
int switch_to_fullscreen(struct glx_window *glx_window,
const struct gl_window_hints *hints) {
XF86VidModeModeInfo mode, **modes;
int num_modes;
// Get the current mode (so we can switch back later).
if (!XF86VidModeGetAllModeLines(glx_window->display,
glx_window->screen, &num_modes, &modes)) {
debug("switch_to_fullscreen: Failed to query current mode.\n");
return 1;
}
glx_window->old_mode = *modes[0];
XFree(modes);
// Try to switch the mode, possibly falling back to windowed mode.
if (get_matching_window_mode(glx_window, hints, &mode) ||
!XF86VidModeSwitchToMode(glx_window->display, glx_window->screen, &mode)) {
return 1;
}
XF86VidModeSetViewPort(glx_window->display, glx_window->screen, 0, 0);
return 0;
}

View file

@ -11,6 +11,7 @@
#include "device/device.h"
#include "device/options.h"
#include "device/netapi.h"
#include "os/common/alloc.h"
#include "os/gl_window.h"
#include "os/main.h"
#include "os/windows/winapi_window.h"
@ -29,8 +30,6 @@ static void show_console(void);
cen64_cold static DWORD run_device_thread(void *opaque);
HANDLE dynarec_heap;
// Only used when passed -nointerface.
bool device_exit_requested;
@ -51,6 +50,7 @@ int WINAPI WinMain(HINSTANCE hInstance,
return status;
}
#if 0
if ((dynarec_heap = HeapCreate(HEAP_CREATE_ENABLE_EXECUTE, 0, 0)) == NULL) {
MessageBox(NULL, "Failed to create the dynarec heap.", "CEN64",
MB_OK | MB_ICONEXCLAMATION);
@ -58,9 +58,10 @@ int WINAPI WinMain(HINSTANCE hInstance,
WSACleanup();
return EXIT_FAILURE;
}
#endif
status = cen64_win32_main(__argc, __argv);
HeapDestroy(dynarec_heap);
//HeapDestroy(dynarec_heap);
WSACleanup();
return status;
@ -72,6 +73,14 @@ int cen64_win32_main(int argc, const char *argv[]) {
struct rom_file ddipl, ddrom, pifrom, cart;
int status;
cen64_gl_window w;
cen64_gl_screen s;
cen64_gl_display d;
cen64_gl_hints h;
cen64_gl_config *c;
cen64_gl_context x;
int m;
if (argc < 3) {
show_console();
print_command_line_usage(argv[0]);
@ -207,7 +216,11 @@ int os_main(struct cen64_options *options, struct rom_file *ddipl,
// about uninitialized memory being read, etc.
memset(&device, 0, sizeof(device));
if (device_create(&device, malloc(DEVICE_RAMSIZE),
struct cen64_mem m;
cen64_alloc(&m, DEVICE_RAMSIZE, false);
if (device_create(&device, m.ptr, //malloc(DEVICE_RAMSIZE),
ddipl, ddrom, pifrom, cart) == NULL) {
printf("Failed to create a device.\n");

View file

@ -38,7 +38,7 @@ static void winapi_window_update_window_title(
static const LPCSTR CLASSNAME = "CEN64";
// Callback function to handle message sent to the window.
LRESULT CALLBACK WndProc(HWND hWnd,
LRESULT CALLBACK WndProcA(HWND hWnd,
UINT message, WPARAM wParam, LPARAM lParam) {
switch(message) {
case WM_DESTROY:
@ -106,7 +106,7 @@ int create_gl_window(struct bus_controller *bus,
winapi_window->h_instance = GetModuleHandle(NULL);
wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
wc.lpfnWndProc = (WNDPROC) WndProc;
wc.lpfnWndProc = (WNDPROC) WndProcA;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = winapi_window->h_instance;

View file

@ -31,6 +31,8 @@ struct cen64_gl_window {
typedef struct cen64_gl_window *cen64_gl_window;
struct vi_controller;
//
// Creates a (hidden) cen64_gl_window.
//
@ -86,6 +88,9 @@ static inline void cen64_gl_window_destroy(cen64_gl_window window) {
free(window);
}
// Handles events that come from X11.
bool cen64_gl_window_pump_events(struct vi_controller *vi);
//
// Swaps the front and back buffers of the cen65_gl_window.
//

View file

@ -30,10 +30,8 @@ const char *ri_register_mnemonics[NUM_RI_REGISTERS] = {
#endif
// Initializes the RI.
int ri_init(struct ri_controller *ri,
struct bus_controller *bus, uint8_t *ram) {
int ri_init(struct ri_controller *ri, struct bus_controller *bus) {
ri->bus = bus;
ri->ram = ram;
// MESS uses these, so we will too?
ri->regs[RI_MODE_REG] = 0xE;

View file

@ -12,6 +12,8 @@
#define __ri_controller_h__
#include "common.h"
#define MAX_RDRAM_SIZE 0x800000U
struct bus_controller *bus;
enum rdram_register {
@ -38,14 +40,13 @@ extern const char *ri_register_mnemonics[NUM_RI_REGISTERS];
struct ri_controller {
struct bus_controller *bus;
uint8_t *ram;
uint32_t rdram_regs[NUM_RDRAM_REGISTERS];
uint32_t regs[NUM_RI_REGISTERS];
uint8_t ram[MAX_RDRAM_SIZE];
};
cen64_cold int ri_init(struct ri_controller *ri,
struct bus_controller *bus, uint8_t *ram);
cen64_cold int ri_init(struct ri_controller *ri, struct bus_controller *bus);
cen64_hot int read_rdram(void *opaque, uint32_t address, uint32_t *word);
cen64_hot int write_rdram(void *opaque, uint32_t address, uint32_t word, uint32_t dqm);

View file

@ -107,9 +107,9 @@ int pif_perform_command(struct si_controller *si,
case 0x01:
switch(channel) {
case 0:
os_acquire_input(&si->bus->vi->gl_window);
//os_acquire_input(&si->bus->vi->gl_window);
memcpy(recv_buf, si->input, sizeof(si->input));
os_release_input(&si->bus->vi->gl_window);
//os_release_input(&si->bus->vi->gl_window);
break;
default:

View file

@ -17,6 +17,12 @@
#include "vi/controller.h"
#include "vr4300/interface.h"
#include "gl_common.h"
#include "gl_context.h"
#include "gl_display.h"
#include "gl_screen.h"
#include "gl_window.h"
#define VI_COUNTER_START (62500000.0 / 60.0) + 1;
#ifdef DEBUG_MMIO_REGISTER_ACCESS
@ -85,6 +91,9 @@ void vi_cycle(struct vi_controller *vi) {
type = 0;
// Interact with the user interface?
cen64_gl_window_pump_events(vi);
gl_window_render_frame(vi, buffer, hres, vres, hskip, type);
#if 0
if (likely(vi->gl_window.window)) {
if (os_exit_requested(&vi->gl_window))
device_exit(vi->bus);
@ -94,6 +103,7 @@ void vi_cycle(struct vi_controller *vi) {
else if (device_exit_requested)
device_exit(vi->bus);
#endif
// Raise an interrupt to indicate refresh.
signal_rcp_interrupt(vi->bus->vr4300, MI_INTR_VI);
@ -101,12 +111,51 @@ void vi_cycle(struct vi_controller *vi) {
}
// Initializes the VI.
int vi_init(struct vi_controller *vi,
struct bus_controller *bus) {
int vi_init(struct vi_controller *vi, struct bus_controller *bus) {
vi->counter = VI_COUNTER_START;
vi->bus = bus;
return 0;
// Create a window for rendering. If we're successful,
// we'll work our way into the nested statements and
// return success.
if ((vi->display = cen64_gl_display_create(
NULL)) != CEN64_GL_DISPLAY_BAD) {
if ((vi->screen = cen64_gl_screen_create(
vi->display, -1)) != CEN64_GL_SCREEN_BAD) {
struct cen64_gl_hints hints = cen64_default_gl_hints;
struct cen64_gl_config *config;
int num_matching;
if ((config = cen64_gl_config_create(vi->display, vi->screen,
&hints, &num_matching)) != CEN64_GL_CONFIG_BAD) {
if ((vi->window = cen64_gl_window_create(vi->display, vi->screen,
config, "CEN64")) != CEN64_GL_WINDOW_BAD) {
cen64_gl_config_destroy(config);
if ((vi->context = cen64_gl_context_create(
vi->window)) != CEN64_GL_CONTEXT_BAD) {
cen64_gl_window_unhide(vi->window);
gl_window_init(vi);
return 0;
}
}
// Something failed, and it's hard to perform RAII in C.
// So now we release resources and return an error.
cen64_gl_window_destroy(vi->window);
cen64_gl_config_destroy(config);
}
cen64_gl_screen_destroy(vi->screen);
}
cen64_gl_display_destroy(vi->display);
}
return -1;
}
// Writes a word to the VI MMIO register space.

View file

@ -11,7 +11,11 @@
#ifndef __vi_controller_h__
#define __vi_controller_h__
#include "common.h"
#include "os/gl_window.h"
#include "gl_common.h"
#include "gl_context.h"
#include "gl_display.h"
#include "gl_screen.h"
#include "gl_window.h"
struct bus_controller *bus;
@ -43,17 +47,24 @@ struct render_area {
};
struct vi_controller {
struct gl_window gl_window;
struct bus_controller *bus;
uint32_t regs[NUM_VI_REGISTERS];
uint32_t counter;
// Client rendering structures.
cen64_gl_display display;
cen64_gl_screen screen;
cen64_gl_window window;
cen64_gl_context context;
struct render_area render_area;
float viuv[8];
float quad[8];
};
cen64_cold void gl_window_init(struct gl_window *window);
void gl_window_render_frame(struct gl_window *gl_window, const uint8_t *buffer,
cen64_cold void gl_window_init(struct vi_controller *vi);
void gl_window_render_frame(struct vi_controller *vi, const uint8_t *buffer,
unsigned hres, unsigned vres, unsigned hskip, unsigned type);
cen64_cold int vi_init(struct vi_controller *vi, struct bus_controller *bus);
@ -63,5 +74,8 @@ cen64_flatten cen64_hot void vi_cycle(struct vi_controller *vi);
cen64_cold int read_vi_regs(void *opaque, uint32_t address, uint32_t *word);
cen64_cold int write_vi_regs(void *opaque, uint32_t address, uint32_t word, uint32_t dqm);
// Render callbacks.
void cen64_gl_window_resize_cb(int width, int height);
#endif

View file

@ -13,7 +13,7 @@
#include "os/main.h"
// Initializes OpenGL to an default state.
void gl_window_init(struct gl_window *window) {
void gl_window_init(struct vi_controller *vi) {
glDisable(GL_DEPTH_TEST);
glDisable(GL_LIGHTING);
glDisable(GL_BLEND);
@ -29,22 +29,22 @@ void gl_window_init(struct gl_window *window) {
// Initialize vertex arrays for drawing.
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(2, GL_FLOAT, 0, window->viuv);
glVertexPointer(2, GL_FLOAT, 0, window->quad);
glTexCoordPointer(2, GL_FLOAT, 0, vi->viuv);
glVertexPointer(2, GL_FLOAT, 0, vi->quad);
window->quad[0] = window->quad[5] =
window->quad[6] = window->quad[7] = -1;
window->quad[1] = window->quad[2] =
window->quad[3] = window->quad[4] = 1;
window->viuv[2] = window->viuv[4] =
window->viuv[5] = window->viuv[7] = 1;
vi->quad[0] = vi->quad[5] =
vi->quad[6] = vi->quad[7] = -1;
vi->quad[1] = vi->quad[2] =
vi->quad[3] = vi->quad[4] = 1;
vi->viuv[2] = vi->viuv[4] =
vi->viuv[5] = vi->viuv[7] = 1;
// Tell OpenGL that the byte order is swapped.
glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_TRUE);
}
// Renders a frame.
void gl_window_render_frame(struct gl_window *gl_window, const uint8_t *buffer,
void gl_window_render_frame(struct vi_controller *vi, const uint8_t *buffer,
unsigned hres, unsigned vres, unsigned hskip, unsigned type) {
float aspect;
@ -68,14 +68,14 @@ void gl_window_render_frame(struct gl_window *gl_window, const uint8_t *buffer,
}
aspect = (float) hres / (hres + hskip);
gl_window->viuv[2] = gl_window->viuv[4] = aspect;
vi->viuv[2] = vi->viuv[4] = aspect;
glDrawArrays(GL_QUADS, 0, 4);
gl_swap_buffers(gl_window);
cen64_gl_window_swap_buffers(vi->window);
}
// Called when the window was resized.
void gl_window_resize_cb(int width, int height) {
void cen64_gl_window_resize_cb(int width, int height) {
float aspect = 4.0 / 3.0;
if (height <= 0)