mirror of
https://github.com/n64dev/cen64.git
synced 2024-06-21 13:32:40 -04:00
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:
parent
b5fbc3d939
commit
7f203b7175
|
@ -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
46
cen64.c
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
2
cen64.h
2
cen64.h
|
@ -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
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -23,9 +23,6 @@ struct bus_controller;
|
|||
|
||||
struct gl_window {
|
||||
void *window;
|
||||
|
||||
float viuv[8];
|
||||
float quad[8];
|
||||
};
|
||||
|
||||
struct gl_window_hints {
|
||||
|
|
|
@ -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);
|
||||
|
|
124
os/unix/main.c
124
os/unix/main.c
|
@ -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.
|
||||
|
|
|
@ -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(¤t_time);
|
||||
ns = compute_time_difference(¤t_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;
|
||||
}
|
||||
|
|
@ -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");
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.
|
||||
//
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
26
vi/render.c
26
vi/render.c
|
@ -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)
|
||||
|
|
Loading…
Reference in a new issue