From 9b0817b04b93c21b1d8efb1009a37293622b4042 Mon Sep 17 00:00:00 2001 From: Dimitris Panokostas Date: Fri, 23 Dec 2016 19:33:28 +0100 Subject: [PATCH] Added GLES target and updated Makefile --- Makefile | 16 +- src/od-gles/gl.cpp | 282 +++++++++++++ src/od-gles/gl.h | 35 ++ src/od-gles/gl_platform.cpp | 156 ++++++++ src/od-gles/gl_platform.h | 2 + src/od-gles/gles_gfx.cpp | 748 +++++++++++++++++++++++++++++++++++ src/od-gles/shader_stuff.cpp | 489 +++++++++++++++++++++++ src/od-gles/shader_stuff.h | 12 + 8 files changed, 1738 insertions(+), 2 deletions(-) create mode 100644 src/od-gles/gl.cpp create mode 100644 src/od-gles/gl.h create mode 100644 src/od-gles/gl_platform.cpp create mode 100644 src/od-gles/gl_platform.h create mode 100644 src/od-gles/gles_gfx.cpp create mode 100644 src/od-gles/shader_stuff.cpp create mode 100644 src/od-gles/shader_stuff.h diff --git a/Makefile b/Makefile index f40e4637..a5b38f71 100644 --- a/Makefile +++ b/Makefile @@ -10,6 +10,10 @@ else ifeq ($(PLATFORM),rpi2) MORE_CFLAGS += -DARMV6T2 -DUSE_ARMNEON else ifeq ($(PLATFORM),rpi1) CPU_FLAGS += -march=armv6zk -mfpu=vfp -mfloat-abi=hard +else ifeq ($(PLATFORM),gles) + CPU_FLAGS += -march=armv8-a -mfpu=neon-fp-armv8 -mfloat-abi=hard + MORE_CFLAGS += -DARMV6T2 -DUSE_ARMNEON -DHAVE_GLES + LDFLAGS += -lEGL -lGLESv1_CM endif NAME = uae4arm @@ -193,8 +197,16 @@ OBJS = \ src/od-pandora/gui/PanelSavestate.o \ src/od-pandora/gui/main_window.o \ src/od-pandora/gui/Navigation.o - -OBJS += src/od-rasp/rasp_gfx.o + +ifeq ($(PLATFORM),gles) + OBJS += src/od-gles/gl.o + OBJS += src/od-gles/shader_stuff.o + OBJS += src/od-gles/gl_platform.o + OBJS += src/od-gles/gles_gfx.o +else + OBJS += src/od-rasp/rasp_gfx.o +endif + OBJS += src/od-pandora/gui/sdltruetypefont.o OBJS += src/od-pandora/picasso96.o diff --git a/src/od-gles/gl.cpp b/src/od-gles/gl.cpp new file mode 100644 index 00000000..781c8199 --- /dev/null +++ b/src/od-gles/gl.cpp @@ -0,0 +1,282 @@ +#include +#include + +#include + +#include +#include + +#include "gl_platform.h" +#include "gl.h" + +#include "shader_stuff.h" + + +static EGLDisplay edpy; +static EGLSurface esfc; +static EGLContext ectxt; + +/* for external flips */ +void *gl_es_display; +void *gl_es_surface; + + +static float vertex_coords[] = { + -1.0f, 1.0f, 0.0f, // 0 0 1 + 1.0f, 1.0f, 0.0f, // 1 ^ + -1.0f, -1.0f, 0.0f, // 2 | 2 3 + 1.0f, -1.0f, 0.0f, // 3 +--> +}; + +static float orig_texture_coords[] = { + -0.5f, -0.5f, + 0.5f, -0.5f, + -0.5f, 0.5f, + 0.5f, 0.5f, +}; + +static float texture_coords[] = { + 0.0f, 0.0f, // we flip this: + 1.0f, 0.0f, // v^ + 0.0f, 1.0f, // | u + 1.0f, 1.0f, // +--> +}; + + +static int gl_have_error(const char *name) +{ + GLenum e = glGetError(); + if (e != GL_NO_ERROR) { + printf("GL error: %s %x\n", name, e); + return 1; + } + return 0; +} + +static int gles_have_error(const char *name) +{ + EGLint e = eglGetError(); + if (e != EGL_SUCCESS) { + printf("%s %x\n", name, e); + return 1; + } + return 0; +} + +int gl_init(void *display, void *window, int *quirks) +{ + EGLConfig ecfg = NULL; + GLuint texture_name = 0; + void *tmp_texture_mem = NULL; + EGLint num_config; + int retval = -1; + int ret; + + static const EGLint config_attributes[] = + { + EGL_RED_SIZE, 8, + EGL_GREEN_SIZE, 8, + EGL_BLUE_SIZE, 8, + EGL_ALPHA_SIZE, 8, + EGL_SURFACE_TYPE, EGL_WINDOW_BIT, + EGL_NONE + }; + + static const EGLint context_attributes[] = + { + EGL_CONTEXT_CLIENT_VERSION, 2, + EGL_NONE + }; + + + // gl_platform_init() does Raspi-specific stuff like bcm_host_init() + ret = gl_platform_init(&display, &window, quirks); + if (ret != 0) { + printf("gl_platform_init failed with %d\n", ret); + goto out; + } + + tmp_texture_mem = calloc(1, 1024 * 512 * 2); + if (tmp_texture_mem == NULL) { + printf("OOM\n"); + goto out; + } + + edpy = eglGetDisplay((EGLNativeDisplayType)display); + if (edpy == EGL_NO_DISPLAY) { + printf("Failed to get EGL display\n"); + goto out; + } + + if (!eglInitialize(edpy, NULL, NULL)) { + printf("Failed to initialize EGL\n"); + goto out; + } + + if (!eglChooseConfig(edpy, config_attributes, &ecfg, 1, &num_config)) { + printf("Failed to choose config (%x)\n", eglGetError()); + goto out; + } + + if (ecfg == NULL || num_config == 0) { + printf("No EGL configs available\n"); + goto out; + } + + esfc = eglCreateWindowSurface(edpy, ecfg, + (EGLNativeWindowType)window, NULL); + if (esfc == EGL_NO_SURFACE) { + printf("Unable to create EGL surface (%x)\n", + eglGetError()); + goto out; + } + +// ectxt = eglCreateContext(edpy, ecfg, EGL_NO_CONTEXT, NULL); + ectxt = eglCreateContext(edpy, ecfg, EGL_NO_CONTEXT, context_attributes); + if (ectxt == EGL_NO_CONTEXT) { + printf("Unable to create EGL context (%x)\n", + eglGetError()); + goto out; + } + + eglMakeCurrent(edpy, esfc, esfc, ectxt); + + //glEnable(GL_TEXTURE_2D); // for old fixed-function pipeline + //if (gl_have_error("glEnable(GL_TEXTURE_2D)")) goto out; + + glGenTextures(1, &texture_name); + if (gl_have_error("glGenTextures")) goto out; + + + + glBindTexture(GL_TEXTURE_2D, texture_name); + if (gl_have_error("glBindTexture")) goto out; + + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1024, 512, 0, GL_RGB, + GL_UNSIGNED_SHORT_5_6_5, tmp_texture_mem); + if (gl_have_error("glTexImage2D")) goto out; + + // no mipmaps + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + //glViewport(0, 0, 512, 512); + glLoadIdentity(); + glFrontFace(GL_CW); + glEnable(GL_CULL_FACE); + + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glEnableClientState(GL_VERTEX_ARRAY); + + if (gl_have_error("init")) + goto out; + + gl_es_display = (void *)edpy; + gl_es_surface = (void *)esfc; + retval = 0; + + int shader_stuff_result; + shader_stuff_result = shader_stuff_init(); + shader_stuff_result = shader_stuff_reload_shaders(); + shader_stuff_result = shader_stuff_set_data(vertex_coords, texture_coords, texture_name); + +out: + free(tmp_texture_mem); + return retval; +} + +static int framecount = 0; + +int gl_flip(const void *fb, int w, int h) +{ + static int old_w, old_h; + + if (framecount % 60 == 0) + { +// printf("gl_flip() w: %d, h: %d\n", w, h); + } + + if (framecount % 30 == 0) + { + if (shader_stuff_shader_needs_reload()) { + shader_stuff_reload_shaders(); + // shader_stuff_set_data(vertex_coords, texture_coords, texture_name); + + } + } + + framecount++; + float floattime = (framecount * 0.04f); + + if (fb != NULL) { + if (w != old_w || h != old_h) { + float f_w = (float)w / 1024.0f; + float f_h = (float)h / 512.0f; + texture_coords[1*2 + 0] = f_w; + texture_coords[2*2 + 1] = f_h; + texture_coords[3*2 + 0] = f_w; + texture_coords[3*2 + 1] = f_h; + old_w = w; + old_h = h; + } +/* + float rotmat[4]; // 2d rotation matrix + rotmat[0] = cos(floattime); + rotmat[1] = sin(floattime); + rotmat[2] = -sin(floattime); + rotmat[3] = cos(floattime); + + for (int i=0; i<4; i++) { + float f_w = (float)w / 1024.0f; + float f_h = (float)h / 512.0f; + float x = orig_texture_coords[i*2 + 0] * f_w; + float y = orig_texture_coords[i*2 + 1] * f_h; + texture_coords[i*2 + 0] = + f_w * 0.5f + (x * rotmat[0] + y * rotmat[1]); + texture_coords[i*2 + 1] = + f_h * 0.5f + (x * rotmat[2] + y * rotmat[3]); + + } +*/ + + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, + GL_RGB, GL_UNSIGNED_SHORT_5_6_5, fb); + if (gl_have_error("glTexSubImage2D")) + return -1; + } // if (fb != NULL) + + // glVertexPointer(3, GL_FLOAT, 0, vertex_coords); + // if (gl_have_error("glVertexPointer")) return -1; + + // glTexCoordPointer(2, GL_FLOAT, 0, texture_coords); + // if (gl_have_error("glTexCoordPointer")) return -1; + + shader_stuff_frame(framecount, w, h, 800, 480); // TODO! hard-coded output size + if (gl_have_error("use program")) return -1; + + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); +// glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + + if (gl_have_error("glDrawArrays")) return -1; + + eglSwapBuffers(edpy, esfc); + if (gles_have_error("eglSwapBuffers")) return -1; + + return 0; +} + +void gl_finish(void) +{ + eglMakeCurrent(edpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + eglDestroyContext(edpy, ectxt); + ectxt = EGL_NO_CONTEXT; + eglDestroySurface(edpy, esfc); + esfc = EGL_NO_SURFACE; + eglTerminate(edpy); + edpy = EGL_NO_DISPLAY; + + gl_es_display = (void *)edpy; + gl_es_surface = (void *)esfc; + + gl_platform_finish(); +} diff --git a/src/od-gles/gl.h b/src/od-gles/gl.h new file mode 100644 index 00000000..cb480710 --- /dev/null +++ b/src/od-gles/gl.h @@ -0,0 +1,35 @@ +#ifndef LIBPICOFE_GL_H +#define LIBPICOFE_GL_H + +#ifdef HAVE_GLES + +int gl_init(void *display, void *window, int *quirks); +int gl_flip(const void *fb, int w, int h); +void gl_finish(void); + +/* for external flips */ +extern void *gl_es_display; +extern void *gl_es_surface; + +#else + +static __inline int gl_init(void *display, void *window, int *quirks) +{ + return -1; +} +static __inline int gl_flip(const void *fb, int w, int h) +{ + return -1; +} +static __inline void gl_finish(void) +{ +} + +#define gl_es_display (void *)0 +#define gl_es_surface (void *)0 + +#endif + +#define GL_QUIRK_ACTIVATE_RECREATE 1 + +#endif // LIBPICOFE_GL_H diff --git a/src/od-gles/gl_platform.cpp b/src/od-gles/gl_platform.cpp new file mode 100644 index 00000000..ac24594a --- /dev/null +++ b/src/od-gles/gl_platform.cpp @@ -0,0 +1,156 @@ +#include +#include +#include +#include + +#include "gl.h" +#include "gl_platform.h" + +#ifdef VCOS_VERSION + +/* + * hacks for Broadcom VideoCore / Raspberry Pi.. + * Why do I have to do this proprietary API stuff, + * couldn't they implement EGL properly? D: + */ +#include +#include +#include + +static Display *x11display; +static Window x11window; +static DISPMANX_DISPLAY_HANDLE_T m_dispmanDisplay; +static EGL_DISPMANX_WINDOW_T m_nativeWindow; + +static void *x11lib; +#define FPTR(f) typeof(f) * p##f +static FPTR(XGetGeometry); +static FPTR(XGetWindowAttributes); +static FPTR(XTranslateCoordinates); + +static void get_window_rect(VC_RECT_T *rect) +{ + XWindowAttributes xattrs_root; + uint32_t disp_w = 0, disp_h = 0; + int dx = 0, dy = 0; + unsigned int dw = 0, dh = 0, dummy; + Window root, dummyw; + + graphics_get_display_size(0, &disp_w, &disp_h); + if (disp_w == 0 || disp_h == 0) + fprintf(stderr, "ERROR: graphics_get_display_size is broken\n"); + + // default to fullscreen + // Chips: rpi cut border when full screen... + #if 1 + rect->x = (disp_w*2)/100; + rect->y = 0; + rect->width = disp_w - (disp_w*2)/100; + rect->height = disp_h - (disp_h*2)/100; + #else + rect->x = rect->y = 0; + rect->width = disp_w; + rect->height = disp_h; + #endif + + if (x11display == NULL || x11window == 0) + return; // use fullscreen + + pXGetGeometry(x11display, x11window, &root, &dx, &dy, &dw, &dh, + &dummy, &dummy); + pXGetWindowAttributes(x11display, root, &xattrs_root); + + if (dw == xattrs_root.width && dh == xattrs_root.height) + return; // use fullscreen + + pXTranslateCoordinates(x11display, x11window, root, + dx, dy, &dx, &dy, &dummyw); + + // how to deal with that weird centering thing? + // this is not quite right.. + dx += (disp_w - xattrs_root.width) / 2; + dy += (disp_h - xattrs_root.height) / 2; + + rect->x = dx; + rect->y = dy; + rect->width = dw; + rect->height = dh; +} + +static void submit_rect(void) +{ + DISPMANX_UPDATE_HANDLE_T m_dispmanUpdate; + DISPMANX_ELEMENT_HANDLE_T m_dispmanElement; + VC_RECT_T srcRect = { 0, }; // unused, but we segfault without passing it?? + VC_RECT_T dstRect; + + get_window_rect(&dstRect); + + m_dispmanDisplay = vc_dispmanx_display_open(0); + m_dispmanUpdate = vc_dispmanx_update_start(0); + + m_dispmanElement = vc_dispmanx_element_add(m_dispmanUpdate, + m_dispmanDisplay, 0, &dstRect, 0, &srcRect, + DISPMANX_PROTECTION_NONE, 0, 0, DISPMANX_NO_ROTATE); + + m_nativeWindow.element = m_dispmanElement; + m_nativeWindow.width = dstRect.width; + m_nativeWindow.height = dstRect.height; + + vc_dispmanx_update_submit_sync(m_dispmanUpdate); +} + +int gl_platform_init(void **display, void **window, int *quirks) +{ + x11display = NULL; + x11window = 0; + + x11lib = dlopen("libX11.so.6", RTLD_LAZY); + if (x11lib != NULL) { + pXGetGeometry = dlsym(x11lib, "XGetGeometry"); + pXGetWindowAttributes = dlsym(x11lib, "XGetWindowAttributes"); + pXTranslateCoordinates = dlsym(x11lib, "XTranslateCoordinates"); + if (pXGetGeometry != NULL && pXGetWindowAttributes != NULL + && pXTranslateCoordinates != NULL) + { + x11display = *display; + x11window = (Window)*window; + } + } + + bcm_host_init(); + submit_rect(); + + *display = EGL_DEFAULT_DISPLAY; + *window = &m_nativeWindow; + *quirks |= GL_QUIRK_ACTIVATE_RECREATE; + + return 0; +} + +void gl_platform_finish(void) +{ + vc_dispmanx_display_close(m_dispmanDisplay); + bcm_host_deinit(); + + if (x11lib) { + dlclose(x11lib); + x11lib = NULL; + } + + x11display = NULL; + x11window = 0; +} + +#else + +int gl_platform_init(void **display, void **window, int *quirks) +{ + return 0; +} + +void gl_platform_finish(void) +{ +} + +#endif diff --git a/src/od-gles/gl_platform.h b/src/od-gles/gl_platform.h new file mode 100644 index 00000000..3e0bbb14 --- /dev/null +++ b/src/od-gles/gl_platform.h @@ -0,0 +1,2 @@ +int gl_platform_init(void **display, void **window, int *quirks); +void gl_platform_finish(void); diff --git a/src/od-gles/gles_gfx.cpp b/src/od-gles/gles_gfx.cpp new file mode 100644 index 00000000..6ab735b7 --- /dev/null +++ b/src/od-gles/gles_gfx.cpp @@ -0,0 +1,748 @@ +#include "sysconfig.h" +#include "sysdeps.h" +#include "config.h" +#include "uae.h" +#include "options.h" +#include "gui.h" +#include "memory.h" +#include "newcpu.h" +#include "inputdevice.h" +#include "custom.h" +#include "xwin.h" +#include "drawing.h" +#include "savestate.h" +#include "picasso96.h" + +#include +#include +#include +#include +#ifdef ANDROIDSDL +#include +#endif +#include "gl.h" +#include + +/* SDL surface variable for output of emulation */ +SDL_Surface *prSDLScreen = NULL; +/* Dummy SDL variable for screen init */ +SDL_Surface *Dummy_prSDLScreen = NULL; +static SDL_Surface *current_screenshot = NULL; +/* Possible screen modes (x and y resolutions) */ +#define MAX_SCREEN_MODES 6 +static int x_size_table[MAX_SCREEN_MODES] = { 640, 640, 800, 1024, 1152, 1280 }; +static int y_size_table[MAX_SCREEN_MODES] = { 400, 480, 480, 768, 864, 960 }; + +static int red_bits, green_bits, blue_bits; +static int red_shift, green_shift, blue_shift; + +struct PicassoResolution *DisplayModes; +struct MultiDisplay Displays[MAX_DISPLAYS]; + +int screen_is_picasso = 0; + +static int curr_layer_width = 0; + +static char vid_drv_name[32]; +static void *display, *window; +static int gl_quirks; + +static char screenshot_filename_default[255]={ + '/', 't', 'm', 'p', '/', 'n', 'u', 'l', 'l', '.', 'p', 'n', 'g', '\0' +}; +char *screenshot_filename=(char *)&screenshot_filename_default[0]; +FILE *screenshot_file=NULL; +static void CreateScreenshot(void); +static int save_thumb(char *path); +int delay_savestate_frame = 0; + +int justClicked = 0; +int mouseMoving = 0; +int fcounter = 0; +int doStylusRightClick = 0; + +static long next_synctime = 0; + + +unsigned char current_resource_amigafb = 0; + + +int graphics_setup (void) +{ +#ifdef PICASSO96 + picasso_InitResolutions(); + InitPicasso96(); +#endif + + return 1; +} + + +void InitAmigaVidMode(struct uae_prefs *p) +{ + /* Initialize structure for Amiga video modes */ + gfxvidinfo.pixbytes = 2; + gfxvidinfo.bufmem = (uae_u8 *)prSDLScreen->pixels; + gfxvidinfo.outwidth = p->gfx_size.width; + gfxvidinfo.outheight = p->gfx_size.height; +#ifdef PICASSO96 + if(screen_is_picasso) + { + gfxvidinfo.outwidth = picasso_vidinfo.width; + //gfxvidinfo.outheight = picasso_vidinfo.height; + } +#endif + gfxvidinfo.rowbytes = prSDLScreen->pitch; + //gfxvidinfo.rowbytes = blit_rect.width * 2; +} + +void graphics_dispmanshutdown (void) +{ + printf("dispmanshutdown\n"); +} + + +void graphics_subshutdown (void) +{ + gl_finish(); + // Dunno if below lines are usefull for Rpi... + //SDL_FreeSurface(prSDLScreen); + //prSDLScreen = NULL; +} + + + + + +static void open_screen(struct uae_prefs *p) +{ + int width; + int height; + SDL_SysWMinfo wminfo; + int ret; + int gl_works = 0; + + +#ifdef PICASSO96 + if (screen_is_picasso) + { + width = picasso_vidinfo.width; + height = picasso_vidinfo.height; + } else +#endif + { + p->gfx_resolution = p->gfx_size.width > 600 ? 1 : 0; + width = p->gfx_size.width; + height = p->gfx_size.height; + } + + + if(Dummy_prSDLScreen) + { // y.f. 2016-10-13 : free the previous screen surface every time, + // so we can have fullscreen while running and windowed while in config window. + // Apparently, something somewhere is resetting the screen. + SDL_FreeSurface(Dummy_prSDLScreen); + Dummy_prSDLScreen = NULL; + } + + if(Dummy_prSDLScreen == NULL ) + { + const SDL_VideoInfo* videoInfo = SDL_GetVideoInfo (); + printf("Current resolution: %d x %d %d bpp\n",videoInfo->current_w, videoInfo->current_h, videoInfo->vfmt->BitsPerPixel); + //Dummy_prSDLScreen = SDL_SetVideoMode(videoInfo->current_w,videoInfo->current_h,16,SDL_SWSURFACE |SDL_FULLSCREEN); + Dummy_prSDLScreen = SDL_SetVideoMode(800,480,16,SDL_SWSURFACE ); + } + + SDL_ShowCursor(SDL_DISABLE); + + printf("Emulation resolution: Width %i Height: %i\n",width,height); + prSDLScreen = SDL_CreateRGBSurface(SDL_SWSURFACE,width,height,16, + Dummy_prSDLScreen->format->Rmask, + Dummy_prSDLScreen->format->Gmask, + Dummy_prSDLScreen->format->Bmask, + Dummy_prSDLScreen->format->Amask); + + + // get x11 display/window for GL + SDL_VideoDriverName(vid_drv_name, sizeof(vid_drv_name)); +#ifdef SDL_VIDEO_DRIVER_X11 + if (strcmp(vid_drv_name, "x11") == 0) { + SDL_VERSION(&wminfo.version); + ret = SDL_GetWMInfo(&wminfo); + if (ret > 0) { + display = wminfo.info.x11.display; + window = (void *)wminfo.info.x11.window; + } + } +#else + (void)wminfo; +#endif + ret = gl_init(display, window, &gl_quirks); + if (ret == 0) { + gl_works = 1; + } + + + if(prSDLScreen != NULL) + { + InitAmigaVidMode(p); + init_row_map(); + } + //framecnt = 1; // Don't draw frame before reset done +} + + +void update_display(struct uae_prefs *p) +{ + open_screen(p); + + SDL_ShowCursor(SDL_DISABLE); + + framecnt = 1; // Don't draw frame before reset done +} + + +int check_prefs_changed_gfx (void) +{ + int changed = 0; + + if(currprefs.gfx_size.height != changed_prefs.gfx_size.height || + currprefs.gfx_size.width != changed_prefs.gfx_size.width || + currprefs.gfx_size_fs.width != changed_prefs.gfx_size_fs.width || + currprefs.gfx_resolution != changed_prefs.gfx_resolution) + { + cfgfile_configuration_change(1); + currprefs.gfx_size.height = changed_prefs.gfx_size.height; + currprefs.gfx_size.width = changed_prefs.gfx_size.width; + currprefs.gfx_size_fs.width = changed_prefs.gfx_size_fs.width; + currprefs.gfx_resolution = changed_prefs.gfx_resolution; + update_display(&currprefs); + changed = 1; + } + if (currprefs.leds_on_screen != changed_prefs.leds_on_screen || + currprefs.pandora_hide_idle_led != changed_prefs.pandora_hide_idle_led || + currprefs.pandora_vertical_offset != changed_prefs.pandora_vertical_offset) + { + currprefs.leds_on_screen = changed_prefs.leds_on_screen; + currprefs.pandora_hide_idle_led = changed_prefs.pandora_hide_idle_led; + currprefs.pandora_vertical_offset = changed_prefs.pandora_vertical_offset; + changed = 1; + } + if (currprefs.chipset_refreshrate != changed_prefs.chipset_refreshrate) + { + currprefs.chipset_refreshrate = changed_prefs.chipset_refreshrate; + init_hz_full (); + changed = 1; + } + + return changed; +} + + +int lockscr (void) +{ + //SDL_LockSurface(prSDLScreen); + return 1; +} + + +void unlockscr (void) +{ + //SDL_UnlockSurface(prSDLScreen); +} + +void wait_for_vsync(void) +{ + // Temporary +} + +void flush_screen () +{ + //SDL_UnlockSurface (prSDLScreen); + + + if (savestate_state == STATE_DOSAVE) + { + if(delay_savestate_frame > 0) + --delay_savestate_frame; + else + { + CreateScreenshot(); + save_thumb(screenshot_filename); + savestate_state = 0; + } + } + + long start = read_processor_time(); + //if(start < next_synctime && next_synctime - start > time_per_frame - 1000) + // usleep((next_synctime - start) - 1000); + + gl_flip(gfxvidinfo.bufmem, currprefs.gfx_size.width, currprefs.gfx_size.height); + + + last_synctime = read_processor_time(); + + if(last_synctime - next_synctime > time_per_frame * (1 + currprefs.gfx_framerate) - (long)1000) + adjust_idletime(-1); + else + adjust_idletime(last_synctime - start); + + next_synctime = last_synctime + time_per_frame * (1 + currprefs.gfx_framerate); + + init_row_map(); + +} + + +void black_screen_now(void) +{ + SDL_FillRect(Dummy_prSDLScreen,NULL,0); + SDL_Flip(Dummy_prSDLScreen); +} + + +static void graphics_subinit (void) +{ + if (prSDLScreen == NULL) + { + fprintf(stderr, "Unable to set video mode: %s\n", SDL_GetError()); + return; + } + else + { + SDL_ShowCursor(SDL_DISABLE); + + InitAmigaVidMode(&currprefs); + } +} + +STATIC_INLINE int bitsInMask (unsigned long mask) +{ + /* count bits in mask */ + int n = 0; + while (mask) + { + n += mask & 1; + mask >>= 1; + } + return n; +} + + +STATIC_INLINE int maskShift (unsigned long mask) +{ + /* determine how far mask is shifted */ + int n = 0; + while (!(mask & 1)) + { + n++; + mask >>= 1; + } + return n; +} + + +static int init_colors (void) +{ + int i; + int red_bits, green_bits, blue_bits; + int red_shift, green_shift, blue_shift; + + /* Truecolor: */ + red_bits = bitsInMask(prSDLScreen->format->Rmask); + green_bits = bitsInMask(prSDLScreen->format->Gmask); + blue_bits = bitsInMask(prSDLScreen->format->Bmask); + red_shift = maskShift(prSDLScreen->format->Rmask); + green_shift = maskShift(prSDLScreen->format->Gmask); + blue_shift = maskShift(prSDLScreen->format->Bmask); + alloc_colors64k (red_bits, green_bits, blue_bits, red_shift, green_shift, blue_shift, 0); + notice_new_xcolors(); + for (i = 0; i < 4096; i++) + xcolors[i] = xcolors[i] * 0x00010001; + + return 1; +} + + +/* + * Find the colour depth of the display + */ +static int get_display_depth (void) +{ + const SDL_VideoInfo *vid_info; + int depth = 0; + + if ((vid_info = SDL_GetVideoInfo())) { + depth = vid_info->vfmt->BitsPerPixel; + + /* Don't trust the answer if it's 16 bits; the display + * could actually be 15 bits deep. We'll count the bits + * ourselves */ + if (depth == 16) + depth = bitsInMask (vid_info->vfmt->Rmask) + bitsInMask (vid_info->vfmt->Gmask) + bitsInMask (vid_info->vfmt->Bmask); + } + return depth; +} + +int GetSurfacePixelFormat(void) +{ + int depth = get_display_depth(); + int unit = (depth + 1) & 0xF8; + + return (unit == 8 ? RGBFB_CHUNKY + : depth == 15 && unit == 16 ? RGBFB_R5G5B5 + : depth == 16 && unit == 16 ? RGBFB_R5G6B5 + : unit == 24 ? RGBFB_B8G8R8 + : unit == 32 ? RGBFB_R8G8B8A8 + : RGBFB_NONE); +} + + +int graphics_init (bool mousecapture) +{ + int i,j; + + //uae_sem_init (&vsync_wait_sem, 0, 1); + + graphics_subinit (); + + + if (!init_colors ()) + return 0; + + //buttonstate[0] = buttonstate[1] = buttonstate[2] = 0; + //keyboard_init(); + + return 1; +} + +void graphics_leave (void) +{ + graphics_subshutdown (); + SDL_FreeSurface(Dummy_prSDLScreen); + SDL_VideoQuit(); +} + + +#define systemRedShift (prSDLScreen->format->Rshift) +#define systemGreenShift (prSDLScreen->format->Gshift) +#define systemBlueShift (prSDLScreen->format->Bshift) +#define systemRedMask (prSDLScreen->format->Rmask) +#define systemGreenMask (prSDLScreen->format->Gmask) +#define systemBlueMask (prSDLScreen->format->Bmask) + +static int save_png(SDL_Surface* surface, char *path) +{ + int w = surface->w; + int h = surface->h; + unsigned char * pix = (unsigned char *)surface->pixels; + unsigned char writeBuffer[1024 * 3]; + FILE *f = fopen(path,"wb"); + if(!f) return 0; + png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, + NULL, + NULL, + NULL); + if(!png_ptr) { + fclose(f); + return 0; + } + + png_infop info_ptr = png_create_info_struct(png_ptr); + + if(!info_ptr) { + png_destroy_write_struct(&png_ptr,NULL); + fclose(f); + return 0; + } + + png_init_io(png_ptr,f); + + png_set_IHDR(png_ptr, + info_ptr, + w, + h, + 8, + PNG_COLOR_TYPE_RGB, + PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_DEFAULT, + PNG_FILTER_TYPE_DEFAULT); + + png_write_info(png_ptr,info_ptr); + + unsigned char *b = writeBuffer; + + int sizeX = w; + int sizeY = h; + int y; + int x; + + unsigned short *p = (unsigned short *)pix; + for(y = 0; y < sizeY; y++) + { + for(x = 0; x < sizeX; x++) + { + unsigned short v = p[x]; + + *b++ = ((v & systemRedMask ) >> systemRedShift ) << 3; // R + *b++ = ((v & systemGreenMask) >> systemGreenShift) << 2; // G + *b++ = ((v & systemBlueMask ) >> systemBlueShift ) << 3; // B + } + p += surface->pitch / 2; + png_write_row(png_ptr,writeBuffer); + b = writeBuffer; + } + + png_write_end(png_ptr, info_ptr); + + png_destroy_write_struct(&png_ptr, &info_ptr); + + fclose(f); + return 1; +} + + +static void CreateScreenshot(void) +{ + int w, h; + + if(current_screenshot != NULL) + { + SDL_FreeSurface(current_screenshot); + current_screenshot = NULL; + } + + w=prSDLScreen->w; + h=prSDLScreen->h; + + current_screenshot = SDL_CreateRGBSurface(prSDLScreen->flags,w,h,prSDLScreen->format->BitsPerPixel,prSDLScreen->format->Rmask,prSDLScreen->format->Gmask,prSDLScreen->format->Bmask,prSDLScreen->format->Amask); + SDL_BlitSurface(prSDLScreen, NULL, current_screenshot, NULL); +} + + +static int save_thumb(char *path) +{ + int ret = 0; + if(current_screenshot != NULL) + { + ret = save_png(current_screenshot, path); + SDL_FreeSurface(current_screenshot); + current_screenshot = NULL; + } + return ret; +} + +bool vsync_switchmode (int hz) +{ + int changed_height = changed_prefs.gfx_size.height; + + if (hz >= 55) + hz = 60; + else + hz = 50; + + if(hz == 50 && currVSyncRate == 60) + { + // Switch from NTSC -> PAL + switch(changed_height) { + case 200: changed_height = 240; break; + case 216: changed_height = 262; break; + case 240: changed_height = 270; break; + case 256: changed_height = 270; break; + case 262: changed_height = 270; break; + case 270: changed_height = 270; break; + } + } + else if(hz == 60 && currVSyncRate == 50) + { + // Switch from PAL -> NTSC + switch(changed_height) { + case 200: changed_height = 200; break; + case 216: changed_height = 200; break; + case 240: changed_height = 200; break; + case 256: changed_height = 216; break; + case 262: changed_height = 216; break; + case 270: changed_height = 240; break; + } + } + + if(changed_height == currprefs.gfx_size.height && hz == currprefs.chipset_refreshrate) + return true; + + changed_prefs.gfx_size.height = changed_height; + + return true; +} + +bool target_graphics_buffer_update (void) +{ + bool rate_changed = 0; + //bool rate_changed = SetVSyncRate(currprefs.chipset_refreshrate); + + if(currprefs.gfx_size.height != changed_prefs.gfx_size.height) + { + update_display(&changed_prefs); + rate_changed = true; + } + + if(rate_changed) + { + black_screen_now(); + fpscounter_reset(); + time_per_frame = 1000 * 1000 / (currprefs.chipset_refreshrate); + } + + return true; +} + + + +#ifdef PICASSO96 + + +static int resolution_compare (const void *a, const void *b) +{ + struct PicassoResolution *ma = (struct PicassoResolution *)a; + struct PicassoResolution *mb = (struct PicassoResolution *)b; + if (ma->res.width < mb->res.width) + return -1; + if (ma->res.width > mb->res.width) + return 1; + if (ma->res.height < mb->res.height) + return -1; + if (ma->res.height > mb->res.height) + return 1; + return ma->depth - mb->depth; +} +static void sortmodes (void) +{ + int i = 0, idx = -1; + int pw = -1, ph = -1; + while (DisplayModes[i].depth >= 0) + i++; + qsort (DisplayModes, i, sizeof (struct PicassoResolution), resolution_compare); + for (i = 0; DisplayModes[i].depth >= 0; i++) { + if (DisplayModes[i].res.height != ph || DisplayModes[i].res.width != pw) { + ph = DisplayModes[i].res.height; + pw = DisplayModes[i].res.width; + idx++; + } + DisplayModes[i].residx = idx; + } +} + +static void modesList (void) +{ + int i, j; + + i = 0; + while (DisplayModes[i].depth >= 0) { + write_log ("%d: %s (", i, DisplayModes[i].name); + j = 0; + while (DisplayModes[i].refresh[j] > 0) { + if (j > 0) + write_log (","); + write_log ("%d", DisplayModes[i].refresh[j]); + j++; + } + write_log (")\n"); + i++; + } +} + +void picasso_InitResolutions (void) +{ + struct MultiDisplay *md1; + int i, count = 0; + char tmp[200]; + int bitdepth; + + Displays[0].primary = 1; + Displays[0].disabled = 0; + Displays[0].rect.left = 0; + Displays[0].rect.top = 0; + Displays[0].rect.right = 800; + Displays[0].rect.bottom = 640; + sprintf (tmp, "%s (%d*%d)", "Display", Displays[0].rect.right, Displays[0].rect.bottom); + Displays[0].name = my_strdup(tmp); + Displays[0].name2 = my_strdup("Display"); + + md1 = Displays; + DisplayModes = md1->DisplayModes = (struct PicassoResolution*) xmalloc (sizeof (struct PicassoResolution) * MAX_PICASSO_MODES); + for (i = 0; i < MAX_SCREEN_MODES && count < MAX_PICASSO_MODES; i++) { + for(bitdepth = 16; bitdepth <= 32; bitdepth += 16) { + int bit_unit = (bitdepth + 1) & 0xF8; + int rgbFormat = (bitdepth == 16 ? RGBFB_R5G6B5 : RGBFB_R8G8B8A8); + int pixelFormat = 1 << rgbFormat; + pixelFormat |= RGBFF_CHUNKY; + + if (SDL_VideoModeOK (x_size_table[i], y_size_table[i], bitdepth, SDL_SWSURFACE)) + { + DisplayModes[count].res.width = x_size_table[i]; + DisplayModes[count].res.height = y_size_table[i]; + DisplayModes[count].depth = bit_unit >> 3; + DisplayModes[count].refresh[0] = 50; + DisplayModes[count].refresh[1] = 60; + DisplayModes[count].refresh[2] = 0; + DisplayModes[count].colormodes = pixelFormat; + sprintf(DisplayModes[count].name, "%dx%d, %d-bit", + DisplayModes[count].res.width, DisplayModes[count].res.height, DisplayModes[count].depth * 8); + + count++; + } + } + } + DisplayModes[count].depth = -1; + sortmodes(); + modesList(); + DisplayModes = Displays[0].DisplayModes; +} + + +void gfx_set_picasso_modeinfo (uae_u32 w, uae_u32 h, uae_u32 depth, RGBFTYPE rgbfmt) +{ + depth >>= 3; + if( ((unsigned)picasso_vidinfo.width == w ) && + ( (unsigned)picasso_vidinfo.height == h ) && + ( (unsigned)picasso_vidinfo.depth == depth ) && + ( picasso_vidinfo.selected_rgbformat == rgbfmt) ) + return; + + picasso_vidinfo.selected_rgbformat = rgbfmt; + picasso_vidinfo.width = w; + picasso_vidinfo.height = h; + picasso_vidinfo.depth = depth; + picasso_vidinfo.extra_mem = 1; + + picasso_vidinfo.pixbytes = depth; + if (screen_is_picasso) + { + open_screen(&currprefs); + picasso_vidinfo.rowbytes = prSDLScreen->pitch; + } +} + + +void gfx_set_picasso_state (int on) +{ + if (on == screen_is_picasso) + return; + + screen_is_picasso = on; + open_screen(&currprefs); + picasso_vidinfo.rowbytes = prSDLScreen->pitch; +} + +uae_u8 *gfx_lock_picasso (void) +{ + // We lock the surface directly after create and flip + picasso_vidinfo.rowbytes = prSDLScreen->pitch; + return (uae_u8 *)prSDLScreen->pixels; +} + +void gfx_unlock_picasso (void) +{ + // We lock the surface directly after create and flip, so no unlock here +} + +#endif // PICASSO96 diff --git a/src/od-gles/shader_stuff.cpp b/src/od-gles/shader_stuff.cpp new file mode 100644 index 00000000..c6f691b2 --- /dev/null +++ b/src/od-gles/shader_stuff.cpp @@ -0,0 +1,489 @@ + +#include +#include + +#include + +#include + +#include "shader_stuff.h" + + +typedef struct +{ + // Handle to a program object + GLuint programObject; + + // Attribute locations + GLint positionLoc; + GLint texCoordLoc; + + // Sampler location + GLint samplerLoc; + + // Other locations + GLint frameCountLoc; + GLint emulatorFrameSizeLoc; + GLint outputFrameSizeLoc; + + // Texture handle + GLuint textureId; + +} UserData; + +typedef struct STATE_T +{ + uint32_t width; + uint32_t height; + + EGLDisplay display; + EGLSurface surface; + EGLContext context; + + EGL_DISPMANX_WINDOW_T nativewindow; + UserData *user_data; + void (*draw_func) (struct STATE_T* ); +} STATE_T; + + + +// for checking if file has changed +#include +#include + + +time_t get_file_date(const char *path) +{ + struct stat file_stat; + int err = stat(path, &file_stat); + if (err) + return 0; + else + return file_stat.st_mtime; +} + + +void showlog(GLint shader) +{ + char log[1024]; + + glGetShaderInfoLog(shader,sizeof log,NULL,log); + printf("%d:shader:\n%s\n", shader, log); +} + +static void showprogramlog(GLint shader) +{ + char log[1024]; + glGetProgramInfoLog(shader,sizeof log,NULL,log); + printf("%d:program:\n%s\n", shader, log); +} + +//static char fshader_file_name[10000]; +static char fshader_file_name[] = "fshader.glsl"; +static time_t fshader_file_date=0; +static GLchar *fshader_source = NULL; + + +static GLchar default_vShaderStr[] = + "attribute vec4 a_position; \n" + "attribute vec2 a_texCoord; \n" + "varying vec2 v_texCoord; \n" + "void main() \n" + "{ \n" + " gl_Position = a_position; \n" + " v_texCoord = a_texCoord; \n" + "} \n"; + +static GLchar default_fShaderStr[] = + "precision mediump float;\n" + "varying vec2 v_texCoord;\n" + "uniform sampler2D s_texture;\n" + "uniform float u_framecount;\n" + "uniform vec2 u_emulator_frame_size;\n" + "uniform vec2 u_output_frame_size;\n" + "void main()\n" + "{\n" +// " gl_FragColor = texture2D( s_texture, v_texCoord );\n" + " gl_FragColor = texture2D( s_texture, v_texCoord )\n" +// " * (cos(gl_FragCoord.y * 3.14159) * 0.5 + 0.5); \n" +// " * (cos(v_texCoord.y * 3.14159 * 262.0 * 2.0 * 2.0) * 0.45 + 0.55); \n" + " * (cos(gl_FragCoord.y * 3.1415926) * 0.35 + 0.65); \n" + "}\n"; + + +/* +void set_fshader_file_name(char *shaderdir) +{ + strcpy(fshader_file_name,shaderdir); + if(shaderdir[strlen(shaderdir)-1]!='/') + strcat(fshader_file_name,"/"); + strcat(fshader_file_name,"fshader.glsl"); +} +*/ + +/* Returns non-zero, if the fragment shaders should be reloaded. + * Because the file has been changed or deleted or something. + * Returns zero, if the shader doesn't need to be reloaded. + */ +int shader_stuff_shader_needs_reload() +{ + if ((fshader_file_name == NULL) || (fshader_source == default_fShaderStr)) + return 0; + + return (get_file_date(fshader_file_name) != fshader_file_date); +} + + +/* Tries to load file named file_name. + * + * If opening the file succeeds: + * Allocates memory for *file_data with malloc() and loads the file + * contents in the allocated buffer. An extra terminator char is added. + * Previous pointer value is overwritten. + * + * *file_date is set to the time/date stamp of the file. + * + * Returns 0. + * + * If opening the file fails: + * *file_data and *file_date are left untouched. + * Returns -1. + * + */ +int load_file(char *file_name, GLchar **file_data, time_t *file_date) +{ + GLchar *data = NULL; + + FILE *f = fopen(file_name, "rb"); + if(f!=NULL) + { + fseek(f, 0, SEEK_END); + int len = ftell(f); + *file_data = (GLchar *)malloc(len+1); + fseek(f, 0, SEEK_SET); + fread(*file_data, 1, len, f); + fclose(f); + (*file_data)[len] = 0; // String terminator + + *file_date = get_file_date(file_name); + } + else { + printf("Fragment shader file %s won't open\n", file_name); + return -1; + } + + return 0; +} + +void free_fshader_source() +{ + if ((fshader_source != NULL) && (fshader_source != default_fShaderStr)) { + free(fshader_source); + fshader_source = NULL; + } +} + +/// +// Create a shader object, load the shader source, and +// compile the shader. +// +GLuint LoadShader(GLenum type, const GLchar *shaderSrc) +{ + GLuint shader; + GLint compiled; + // Create the shader object + shader = glCreateShader(type); + if(shader == 0) + return 0; + // Load the shader source + glShaderSource(shader, 1, &shaderSrc, NULL); + // Compile the shader + glCompileShader(shader); + // Check the compile status + glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled); + if(!compiled) + { + GLint infoLen = 0; + glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen); + if(infoLen > 1) + { + char* infoLog = (char *)malloc(sizeof(char) * infoLen); + glGetShaderInfoLog(shader, infoLen, NULL, infoLog); + fprintf(stderr, "Error compiling shader:\n%s\n", infoLog); + free(infoLog); + } + glDeleteShader(shader); + return 0; + } + return shader; +} + +GLuint LoadProgram ( const GLchar *vertShaderSrc, const GLchar *fragShaderSrc ) +{ + GLuint vertexShader; + GLuint fragmentShader; + GLuint programObject; + GLint linked; + + // Load the vertex/fragment shaders + vertexShader = LoadShader ( GL_VERTEX_SHADER, vertShaderSrc ); + if ( vertexShader == 0 ) + return 0; + + fragmentShader = LoadShader ( GL_FRAGMENT_SHADER, fragShaderSrc ); + // if it didn't compile, let's try the default shader + if ((fragmentShader == 0) && (fshader_source != default_fShaderStr)) { + fshader_source = default_fShaderStr; + fragmentShader = LoadShader ( GL_FRAGMENT_SHADER, default_fShaderStr ); + } + + if ( fragmentShader == 0 ) + { + glDeleteShader( vertexShader ); + return 0; + } + + // Create the program object + programObject = glCreateProgram ( ); + + if ( programObject == 0 ) + return 0; + + glAttachShader ( programObject, vertexShader ); + glAttachShader ( programObject, fragmentShader ); + + // Link the program + glLinkProgram ( programObject ); + + // Check the link status + glGetProgramiv ( programObject, GL_LINK_STATUS, &linked ); + + if ( !linked ) + { + GLint infoLen = 0; + glGetProgramiv ( programObject, GL_INFO_LOG_LENGTH, &infoLen ); + + if ( infoLen > 1 ) + { + char* infoLog = (char *)malloc (sizeof(char) * infoLen ); + + glGetProgramInfoLog ( programObject, infoLen, NULL, infoLog ); + fprintf (stderr, "Error linking program:\n%s\n", infoLog ); + + free ( infoLog ); + } + + glDeleteProgram ( programObject ); + return 0; + } + + // Free up no longer needed shader resources + glDeleteShader ( vertexShader ); + glDeleteShader ( fragmentShader ); + + return programObject; +} + +static STATE_T shader_stuff_state; + +int shader_stuff_init() +{ + STATE_T *p_state = &shader_stuff_state; + p_state->user_data = (UserData *)malloc(sizeof(UserData)); + return GL_TRUE; +} + +/// +// Initialize the shader and program object +// +int shader_stuff_reload_shaders() +{ + STATE_T *p_state = &shader_stuff_state; + UserData *userData = p_state->user_data; + +// ----- these lines could be moved to a separate "delete program" routine + + free_fshader_source(); + + // If there was an existing program object, delete it. + if (userData->programObject != 0) { + glDeleteProgram(userData->programObject); + userData->programObject = 0; + } +// ----- + + + if (load_file(fshader_file_name, &fshader_source, &fshader_file_date) != 0) { + printf("Cannot open %s. Using built-in default fragment shader.", fshader_file_name); + fshader_source = default_fShaderStr; + } + + // Load the shaders and get a linked program object + userData->programObject = LoadProgram ( default_vShaderStr, fshader_source ); + + + return GL_TRUE; +} + +int shader_stuff_set_data(GLfloat *vertex_coords_3f, GLfloat *texture_coords_2f, GLuint texture_name) +{ + STATE_T *p_state = &shader_stuff_state; + UserData *userData = p_state->user_data; + + glClearColor ( 0.0f, 0.0f, 0.0f, 0.0f ); + + // Get the attribute locations + userData->positionLoc = glGetAttribLocation ( userData->programObject, "a_position" ); + userData->texCoordLoc = glGetAttribLocation ( userData->programObject, "a_texCoord" ); + + // Get the sampler location + userData->samplerLoc = glGetUniformLocation ( userData->programObject, "s_texture" ); + + // Get the sampler location + userData->frameCountLoc = glGetUniformLocation ( userData->programObject, "u_framecount" ); + printf("frameCountLoc = %d\n", userData->frameCountLoc); + userData->emulatorFrameSizeLoc = glGetUniformLocation ( userData->programObject, "u_emulator_frame_size" ); + printf("emulatorFrameSizeLoc = %d\n", userData->emulatorFrameSizeLoc); + userData->outputFrameSizeLoc = glGetUniformLocation ( userData->programObject, "u_output_frame_size" ); + + // Load the texture + userData->textureId = texture_name; + + // Load the vertex position + glVertexAttribPointer ( userData->positionLoc, 3, GL_FLOAT, + GL_FALSE, 3 * sizeof(GLfloat), vertex_coords_3f ); + // Load the texture coordinate + glVertexAttribPointer ( userData->texCoordLoc, 2, GL_FLOAT, + GL_FALSE, 2 * sizeof(GLfloat), texture_coords_2f ); + + glEnableVertexAttribArray ( userData->positionLoc ); + glEnableVertexAttribArray ( userData->texCoordLoc ); + + // Bind the texture + glActiveTexture ( GL_TEXTURE0 ); + glBindTexture ( GL_TEXTURE_2D, userData->textureId ); + + // Set the sampler texture unit to 0 + glUniform1i ( userData->samplerLoc, 0 ); + + + return GL_TRUE; +} + +// call this for every frame +// todo: merge all this "stuff" properly to gl.cpp +int shader_stuff_frame(int framecount, int emu_width, int emu_height, int out_width, int out_height) +{ + STATE_T *p_state = &shader_stuff_state; + UserData *userData = p_state->user_data; + + glUseProgram ( userData->programObject ); + + glUniform1f ( userData->frameCountLoc, (GLfloat)(framecount) ); + glUniform2f( userData->emulatorFrameSizeLoc, (GLfloat)(emu_width), (GLfloat)(emu_height)); + glUniform2f ( userData->outputFrameSizeLoc, (GLfloat)(out_width), (GLfloat)(out_height)); + +} + + +/* + +// for checking if file has changed +#include +#include + + +void showlog(GLint shader) +{ + char log[1024]; + + glGetShaderInfoLog(shader,sizeof log,NULL,log); + printf("%d:shader:\n%s\n", shader, log); +} + +static void showprogramlog(GLint shader) +{ + char log[1024]; + glGetProgramInfoLog(shader,sizeof log,NULL,log); + printf("%d:program:\n%s\n", shader, log); +} + +static char fshader_file_name[10000]; +static time_t fshader_file_date=0; + +void set_fshader_file_name(char *shaderdir) +{ + strcpy(fshader_file_name,shaderdir); + if(shaderdir[strlen(shaderdir)-1]!='/') + strcat(fshader_file_name,"/"); + strcat(fshader_file_name,"fshader.glsl"); +} + +static int init_shader() +{ + FILE *f; + int len; + static GLchar *fsource=NULL,*vsource= + "attribute vec2 vertex;" + "void main(void) {" + " gl_Position = vec4(vertex.x,vertex.y,0.0,1.0);" + "}"; + + f=fopen(fshader_file_name,"rb"); + if(f==NULL) + { + printf("Fragment shader won't open\n"); + return -1; + } + fseek(f,0,SEEK_END); + len=ftell(f); + if(fsource!=NULL) + free(fsource); + fsource=malloc(len+1); + fseek(f,0,SEEK_SET); + fread(fsource,1,len,f); + fclose(f); + fsource[len]=0; // Need to terminate! + + fshader_file_date = get_file_date(fshader_file_name); + + vshader=glCreateShader(GL_VERTEX_SHADER); + glShaderSource(vshader,1,(const GLchar **)&vsource,0); + glCompileShader(vshader); + showlog(vshader); + + fshader=glCreateShader(GL_FRAGMENT_SHADER); + glShaderSource(fshader,1,(const GLchar **)&fsource,0); + glCompileShader(fshader); + showlog(fshader); + + program=glCreateProgram(); + glAttachShader(program,vshader); + glAttachShader(program,fshader); + glLinkProgram(program); + + return 0; +} + +void delete_shader() +{ + glDetachShader(program, fshader); + glDetachShader(program, vshader); + glDeleteShader(fshader); + glDeleteShader(vshader); + glUseProgram(0); + glDeleteProgram(program); + glUseProgram(0); +} + +void koelli_reload_shader() +{ + delete_shader(); + init_shader(); +} +* +int koelli_fshader_file_changed(void) +{ + return (get_file_date(fshader_file_name) != fshader_file_date); +} +*/ diff --git a/src/od-gles/shader_stuff.h b/src/od-gles/shader_stuff.h new file mode 100644 index 00000000..b50fb7e8 --- /dev/null +++ b/src/od-gles/shader_stuff.h @@ -0,0 +1,12 @@ +#ifndef __SHADER_STUFF_H +#define __SHADER_STUFF_H + +#include + +extern int shader_stuff_init(); +extern int shader_stuff_shader_needs_reload(); +extern int shader_stuff_reload_shaders(); +extern int shader_stuff_set_data(GLfloat *vertex_coords_3f, GLfloat *texture_coords_2f, GLuint texture_name); +extern int shader_stuff_frame(int framecount, int emu_width, int emu_height, int out_width, int out_height); + +#endif