# HG changeset patch # User nkeynes # Date 1142253547 0 # Node ID 9b9cfc5855e045c83cd0e28eae0e71c0ac4ffe41 # Parent 844a3f2a76ffda2b779cfded08ad6a79709e29e7 More rendering work in progress. Almost there now... --- a/src/Makefile.am Mon Mar 13 12:38:39 2006 +0000 +++ b/src/Makefile.am Mon Mar 13 12:39:07 2006 +0000 @@ -12,7 +12,7 @@ main.c \ mem.c mem.h mmio.h watch.c \ asic.c asic.h \ - bios.c bios.h \ + syscall.c syscall.h bios.c dcload.c \ gdrom/ide.c gdrom/ide.h \ dreamcast.c dreamcast.h \ sh4/intc.c sh4/intc.h sh4/sh4mem.c sh4/timer.c sh4/dmac.c \ @@ -22,6 +22,7 @@ aica/aica.c aica/aica.h aica/audio.c aica/audio.h \ pvr2/pvr2.c pvr2/pvr2.h \ pvr2/ta.c pvr2/render.c \ + pvr2/texcache.c \ maple/maple.c maple/maple.h \ maple/controller.c maple/controller.h \ gui/support.c gui/support.h \ @@ -32,8 +33,7 @@ loader.c bootstrap.c util.c \ drivers/audio_null.c drivers/audio_esd.c \ drivers/video_gtk.c drivers/video_gtk.h \ - drivers/video_x11.c drivers/video_x11.h \ - drivers/gl_glx.c + drivers/video_x11.c drivers/video_x11.h dream_LDADD = @PACKAGE_LIBS@ $(INTLLIBS) -lesd --- a/src/Makefile.in Mon Mar 13 12:38:39 2006 +0000 +++ b/src/Makefile.in Mon Mar 13 12:39:07 2006 +0000 @@ -139,7 +139,7 @@ main.c \ mem.c mem.h mmio.h watch.c \ asic.c asic.h \ - bios.c bios.h \ + syscall.c syscall.h bios.c dcload.c \ gdrom/ide.c gdrom/ide.h \ dreamcast.c dreamcast.h \ sh4/intc.c sh4/intc.h sh4/sh4mem.c sh4/timer.c sh4/dmac.c \ @@ -149,6 +149,7 @@ aica/aica.c aica/aica.h aica/audio.c aica/audio.h \ pvr2/pvr2.c pvr2/pvr2.h \ pvr2/ta.c pvr2/render.c \ + pvr2/texcache.c \ maple/maple.c maple/maple.h \ maple/controller.c maple/controller.h \ gui/support.c gui/support.h \ @@ -159,8 +160,7 @@ loader.c bootstrap.c util.c \ drivers/audio_null.c drivers/audio_esd.c \ drivers/video_gtk.c drivers/video_gtk.h \ - drivers/video_x11.c drivers/video_x11.h \ - drivers/gl_glx.c + drivers/video_x11.c drivers/video_x11.h dream_LDADD = @PACKAGE_LIBS@ $(INTLLIBS) -lesd @@ -175,18 +175,19 @@ PROGRAMS = $(bin_PROGRAMS) am_dream_OBJECTS = main.$(OBJEXT) mem.$(OBJEXT) watch.$(OBJEXT) \ - asic.$(OBJEXT) bios.$(OBJEXT) ide.$(OBJEXT) dreamcast.$(OBJEXT) \ + asic.$(OBJEXT) syscall.$(OBJEXT) bios.$(OBJEXT) \ + dcload.$(OBJEXT) ide.$(OBJEXT) dreamcast.$(OBJEXT) \ intc.$(OBJEXT) sh4mem.$(OBJEXT) timer.$(OBJEXT) dmac.$(OBJEXT) \ sh4core.$(OBJEXT) sh4dasm.$(OBJEXT) sh4mmio.$(OBJEXT) \ scif.$(OBJEXT) armcore.$(OBJEXT) armdasm.$(OBJEXT) \ armmem.$(OBJEXT) aica.$(OBJEXT) audio.$(OBJEXT) pvr2.$(OBJEXT) \ - ta.$(OBJEXT) render.$(OBJEXT) maple.$(OBJEXT) \ - controller.$(OBJEXT) support.$(OBJEXT) interface.$(OBJEXT) \ - callbacks.$(OBJEXT) gui.$(OBJEXT) mmr_win.$(OBJEXT) \ - debug_win.$(OBJEXT) dump_win.$(OBJEXT) loader.$(OBJEXT) \ - bootstrap.$(OBJEXT) util.$(OBJEXT) audio_null.$(OBJEXT) \ - audio_esd.$(OBJEXT) video_gtk.$(OBJEXT) video_x11.$(OBJEXT) \ - gl_glx.$(OBJEXT) + ta.$(OBJEXT) render.$(OBJEXT) texcache.$(OBJEXT) \ + maple.$(OBJEXT) controller.$(OBJEXT) support.$(OBJEXT) \ + interface.$(OBJEXT) callbacks.$(OBJEXT) gui.$(OBJEXT) \ + mmr_win.$(OBJEXT) debug_win.$(OBJEXT) dump_win.$(OBJEXT) \ + loader.$(OBJEXT) bootstrap.$(OBJEXT) util.$(OBJEXT) \ + audio_null.$(OBJEXT) audio_esd.$(OBJEXT) video_gtk.$(OBJEXT) \ + video_x11.$(OBJEXT) dream_OBJECTS = $(am_dream_OBJECTS) dream_DEPENDENCIES = dream_LDFLAGS = @@ -200,9 +201,9 @@ @AMDEP_TRUE@ ./$(DEPDIR)/audio_esd.Po ./$(DEPDIR)/audio_null.Po \ @AMDEP_TRUE@ ./$(DEPDIR)/bios.Po ./$(DEPDIR)/bootstrap.Po \ @AMDEP_TRUE@ ./$(DEPDIR)/callbacks.Po ./$(DEPDIR)/controller.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/debug_win.Po ./$(DEPDIR)/dmac.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/dreamcast.Po ./$(DEPDIR)/dump_win.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/gl_glx.Po ./$(DEPDIR)/gui.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/dcload.Po ./$(DEPDIR)/debug_win.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/dmac.Po ./$(DEPDIR)/dreamcast.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/dump_win.Po ./$(DEPDIR)/gui.Po \ @AMDEP_TRUE@ ./$(DEPDIR)/ide.Po ./$(DEPDIR)/intc.Po \ @AMDEP_TRUE@ ./$(DEPDIR)/interface.Po ./$(DEPDIR)/loader.Po \ @AMDEP_TRUE@ ./$(DEPDIR)/main.Po ./$(DEPDIR)/maple.Po \ @@ -211,7 +212,8 @@ @AMDEP_TRUE@ ./$(DEPDIR)/scif.Po ./$(DEPDIR)/sh4core.Po \ @AMDEP_TRUE@ ./$(DEPDIR)/sh4dasm.Po ./$(DEPDIR)/sh4mem.Po \ @AMDEP_TRUE@ ./$(DEPDIR)/sh4mmio.Po ./$(DEPDIR)/support.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/ta.Po ./$(DEPDIR)/timer.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/syscall.Po ./$(DEPDIR)/ta.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/texcache.Po ./$(DEPDIR)/timer.Po \ @AMDEP_TRUE@ ./$(DEPDIR)/util.Po ./$(DEPDIR)/video_gtk.Po \ @AMDEP_TRUE@ ./$(DEPDIR)/video_x11.Po ./$(DEPDIR)/watch.Po COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ @@ -277,11 +279,11 @@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bootstrap.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/callbacks.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/controller.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dcload.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/debug_win.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dmac.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dreamcast.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dump_win.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gl_glx.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gui.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ide.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/intc.Po@am__quote@ @@ -299,7 +301,9 @@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sh4mem.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sh4mmio.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/support.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/syscall.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ta.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/texcache.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/timer.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/video_gtk.Po@am__quote@ @@ -702,6 +706,28 @@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o render.obj `if test -f 'pvr2/render.c'; then $(CYGPATH_W) 'pvr2/render.c'; else $(CYGPATH_W) '$(srcdir)/pvr2/render.c'; fi` +texcache.o: pvr2/texcache.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT texcache.o -MD -MP -MF "$(DEPDIR)/texcache.Tpo" \ +@am__fastdepCC_TRUE@ -c -o texcache.o `test -f 'pvr2/texcache.c' || echo '$(srcdir)/'`pvr2/texcache.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/texcache.Tpo" "$(DEPDIR)/texcache.Po"; \ +@am__fastdepCC_TRUE@ else rm -f "$(DEPDIR)/texcache.Tpo"; exit 1; \ +@am__fastdepCC_TRUE@ fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='pvr2/texcache.c' object='texcache.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/texcache.Po' tmpdepfile='$(DEPDIR)/texcache.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o texcache.o `test -f 'pvr2/texcache.c' || echo '$(srcdir)/'`pvr2/texcache.c + +texcache.obj: pvr2/texcache.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT texcache.obj -MD -MP -MF "$(DEPDIR)/texcache.Tpo" \ +@am__fastdepCC_TRUE@ -c -o texcache.obj `if test -f 'pvr2/texcache.c'; then $(CYGPATH_W) 'pvr2/texcache.c'; else $(CYGPATH_W) '$(srcdir)/pvr2/texcache.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/texcache.Tpo" "$(DEPDIR)/texcache.Po"; \ +@am__fastdepCC_TRUE@ else rm -f "$(DEPDIR)/texcache.Tpo"; exit 1; \ +@am__fastdepCC_TRUE@ fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='pvr2/texcache.c' object='texcache.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/texcache.Po' tmpdepfile='$(DEPDIR)/texcache.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o texcache.obj `if test -f 'pvr2/texcache.c'; then $(CYGPATH_W) 'pvr2/texcache.c'; else $(CYGPATH_W) '$(srcdir)/pvr2/texcache.c'; fi` + maple.o: maple/maple.c @am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT maple.o -MD -MP -MF "$(DEPDIR)/maple.Tpo" \ @am__fastdepCC_TRUE@ -c -o maple.o `test -f 'maple/maple.c' || echo '$(srcdir)/'`maple/maple.c; \ @@ -987,28 +1013,6 @@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/video_x11.Po' tmpdepfile='$(DEPDIR)/video_x11.TPo' @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o video_x11.obj `if test -f 'drivers/video_x11.c'; then $(CYGPATH_W) 'drivers/video_x11.c'; else $(CYGPATH_W) '$(srcdir)/drivers/video_x11.c'; fi` - -gl_glx.o: drivers/gl_glx.c -@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT gl_glx.o -MD -MP -MF "$(DEPDIR)/gl_glx.Tpo" \ -@am__fastdepCC_TRUE@ -c -o gl_glx.o `test -f 'drivers/gl_glx.c' || echo '$(srcdir)/'`drivers/gl_glx.c; \ -@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/gl_glx.Tpo" "$(DEPDIR)/gl_glx.Po"; \ -@am__fastdepCC_TRUE@ else rm -f "$(DEPDIR)/gl_glx.Tpo"; exit 1; \ -@am__fastdepCC_TRUE@ fi -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='drivers/gl_glx.c' object='gl_glx.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/gl_glx.Po' tmpdepfile='$(DEPDIR)/gl_glx.TPo' @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o gl_glx.o `test -f 'drivers/gl_glx.c' || echo '$(srcdir)/'`drivers/gl_glx.c - -gl_glx.obj: drivers/gl_glx.c -@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT gl_glx.obj -MD -MP -MF "$(DEPDIR)/gl_glx.Tpo" \ -@am__fastdepCC_TRUE@ -c -o gl_glx.obj `if test -f 'drivers/gl_glx.c'; then $(CYGPATH_W) 'drivers/gl_glx.c'; else $(CYGPATH_W) '$(srcdir)/drivers/gl_glx.c'; fi`; \ -@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/gl_glx.Tpo" "$(DEPDIR)/gl_glx.Po"; \ -@am__fastdepCC_TRUE@ else rm -f "$(DEPDIR)/gl_glx.Tpo"; exit 1; \ -@am__fastdepCC_TRUE@ fi -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='drivers/gl_glx.c' object='gl_glx.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/gl_glx.Po' tmpdepfile='$(DEPDIR)/gl_glx.TPo' @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o gl_glx.obj `if test -f 'drivers/gl_glx.c'; then $(CYGPATH_W) 'drivers/gl_glx.c'; else $(CYGPATH_W) '$(srcdir)/drivers/gl_glx.c'; fi` uninstall-info-am: ETAGS = etags --- a/src/drivers/gl_glx.c Mon Mar 13 12:38:39 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,135 +0,0 @@ -/** - * $Id: gl_glx.c,v 1.2 2006-02-15 12:39:13 nkeynes Exp $ - * - * GLX framebuffer support. Note depends on an X11 video driver - * (ie video_gtk) to maintain the X11 side of things. - * - * Copyright (c) 2005 Nathan Keynes. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include "dream.h" -#include -#include -#include "video.h" -#include "drivers/video_x11.h" - -GLXContext glx_context; -Window glx_window; -gboolean glx_open = FALSE; - -gboolean gl_glx_create_window( uint32_t width, uint32_t height ) -{ - int major, minor; - const char *glxExts, *glxServer; - int visual_attrs[] = { GLX_RGBA, GLX_RED_SIZE, 4, - GLX_GREEN_SIZE, 4, - GLX_BLUE_SIZE, 4, - GLX_ALPHA_SIZE, 4, - GLX_DEPTH_SIZE, 16, - GLX_DOUBLEBUFFER, - None }; - int screen = XScreenNumberOfScreen(video_x11_screen); - XSetWindowAttributes win_attrs; - XVisualInfo *visual; - - if( glXQueryVersion( video_x11_display, &major, &minor ) == False ) { - ERROR( "X Display lacks the GLX nature" ); - return FALSE; - } - if( major < 1 || minor < 2 ) { - ERROR( "X display supports GLX %d.%d, but we need at least 1.2", major, minor ); - return FALSE; - } - - glxExts = glXQueryExtensionsString( video_x11_display, screen ); - glxServer = glXQueryServerString( video_x11_display, screen, GLX_VENDOR ); - INFO( "GLX version %d.%d, %s. Supported exts: %s", major, minor, - glxServer, glxExts ); - - /* Find ourselves a nice visual */ - visual = glXChooseVisual( video_x11_display, - screen, - visual_attrs ); - if( visual == NULL ) { - ERROR( "Unable to obtain a compatible visual" ); - return FALSE; - } - - /* And a matching gl context */ - glx_context = glXCreateContext( video_x11_display, visual, None, True ); - if( glx_context == NULL ) { - ERROR( "Unable to obtain a GLX Context. Possibly your system is broken in some small, undefineable way" ); - return FALSE; - } - - - /* Ok, all good so far. Unfortunately the visual we need to use will - * almost certainly be different from the one our frame is using. Which - * means we have to jump through the following hoops to create a - * child window with the appropriate settings. - */ - win_attrs.event_mask = 0; - win_attrs.colormap = XCreateColormap( video_x11_display, - RootWindowOfScreen(video_x11_screen), - visual->visual, AllocNone ); - glx_window = XCreateWindow( video_x11_display, video_x11_window, - 0, 0, width, height, 0, visual->depth, - InputOutput, visual->visual, - CWColormap | CWEventMask, - &win_attrs ); - if( glx_window == None ) { - /* Hrm. Aww, no window? */ - ERROR( "Unable to create GLX window" ); - glXDestroyContext( video_x11_display, glx_context ); - if( win_attrs.colormap ) - XFreeColormap( video_x11_display, win_attrs.colormap ); - return FALSE; - } - XMapRaised( video_x11_display, glx_window ); - - /* And finally set the window to be the active drawing area */ - if( glXMakeCurrent( video_x11_display, glx_window, glx_context ) == False ) { - /* Oh you have _GOT_ to be kidding me */ - ERROR( "Unable to prepare GLX window for drawing" ); - XDestroyWindow( video_x11_display, glx_window ); - XFreeColormap( video_x11_display, win_attrs.colormap ); - glXDestroyContext( video_x11_display, glx_context ); - return FALSE; - } - - glx_open = TRUE; - return TRUE; -} - - - -gboolean gl_glx_set_output_format( uint32_t width, uint32_t height, - int colour_format ) -{ - GLXFBConfig config; - int screen = XScreenNumberOfScreen(video_x11_screen); - int buffer_attrs[] = { GLX_PBUFFER_WIDTH, width, - GLX_PBUFFER_HEIGHT, height, - GLX_PRESERVED_CONTENTS, True, - None }; - if( !glx_open ) { - if( !gl_glx_create_window( width, height ) ) - return FALSE; - } - return TRUE; -} - -gboolean gl_glx_swap_frame( ) -{ - return FALSE; -} --- a/src/drivers/video_gtk.c Mon Mar 13 12:38:39 2006 +0000 +++ b/src/drivers/video_gtk.c Mon Mar 13 12:39:07 2006 +0000 @@ -1,5 +1,5 @@ /** - * $Id: video_gtk.c,v 1.1 2006-02-05 04:05:27 nkeynes Exp $ + * $Id: video_gtk.c,v 1.2 2006-03-13 12:39:07 nkeynes Exp $ * * The PC side of the video support (responsible for actually displaying / * rendering frames) @@ -35,9 +35,14 @@ gboolean video_gtk_display_frame( video_buffer_t frame ); gboolean video_gtk_blank( uint32_t rgb ); -struct video_driver video_gtk_driver = { "Gtk", video_gtk_set_output_format, +struct video_driver video_gtk_driver = { "Gtk", + NULL, + NULL, + video_gtk_set_output_format, + NULL, video_gtk_display_frame, - video_gtk_blank }; + video_gtk_blank, + NULL }; gboolean video_gtk_set_output_format( uint32_t width, uint32_t height, int colour_format ) @@ -90,10 +95,10 @@ char *dest = video_img->mem; switch( frame->colour_format ) { - case COLFMT_RGB15: + case COLFMT_ARGB1555: for( y=0; y < frame->vres; y++ ) { uint16_t *p = (uint16_t *)src; - for( x=0; x < frame->vres; x++ ) { + for( x=0; x < frame->hres; x++ ) { uint16_t pixel = *p++; *dest++ = (pixel & 0x1F) << 3; *dest++ = (pixel & 0x3E0) >> 2; @@ -103,10 +108,10 @@ src += frame->rowstride; } break; - case COLFMT_RGB16: + case COLFMT_RGB565: for( y=0; y < frame->vres; y++ ) { uint16_t *p = (uint16_t *)src; - for( x=0; x < frame->vres; x++ ) { + for( x=0; x < frame->hres; x++ ) { uint16_t pixel = *p++; *dest++ = (pixel & 0x1F) << 3; *dest++ = (pixel & 0x7E0) >> 3; @@ -116,7 +121,19 @@ src += frame->rowstride; } break; - case COLFMT_RGB32: + case COLFMT_RGB888: + for( y=0; y< frame->vres; y++ ) { + char *p = src; + for( x=0; x < frame->hres; x++ ) { + *dest++ = *p++; + *dest++ = *p++; + *dest++ = *p++; + *dest++ = 0; + } + src += frame->rowstride; + } + break; + case COLFMT_ARGB8888: bytes_per_line = frame->hres << 2; if( bytes_per_line == frame->rowstride ) { /* A little bit faster */ --- a/src/drivers/video_x11.c Mon Mar 13 12:38:39 2006 +0000 +++ b/src/drivers/video_x11.c Mon Mar 13 12:39:07 2006 +0000 @@ -1,7 +1,7 @@ /** - * $Id: video_x11.c,v 1.1 2006-02-05 04:05:27 nkeynes Exp $ + * $Id: video_x11.c,v 1.2 2006-03-13 12:39:07 nkeynes Exp $ * - * Parent for all X11 display drivers. + * Shared functions for all X11-based display drivers. * * Copyright (c) 2005 Nathan Keynes. * @@ -16,12 +16,27 @@ * GNU General Public License for more details. */ +#include +#include +#include "dream.h" +#include "video.h" #include "drivers/video_x11.h" +/** + * General X11 parameters. The front-end driver is expected to set this up + * by calling video_x11_set_display after initializing itself. + */ Display *video_x11_display = NULL; Screen *video_x11_screen = NULL; Window video_x11_window = 0; +/** + * GLX parameters. + */ +GLXContext glx_context; +Window glx_window; +gboolean glx_open = FALSE; + void video_x11_set_display( Display *display, Screen *screen, Window window ) { video_x11_display = display; @@ -29,3 +44,97 @@ video_x11_window = window; } + +gboolean video_glx_create_window( int x, int y, int width, int height ) +{ + int major, minor; + const char *glxExts, *glxServer; + int visual_attrs[] = { GLX_RGBA, GLX_RED_SIZE, 4, + GLX_GREEN_SIZE, 4, + GLX_BLUE_SIZE, 4, + GLX_ALPHA_SIZE, 4, + GLX_DEPTH_SIZE, 16, + GLX_DOUBLEBUFFER, + None }; + int screen = XScreenNumberOfScreen(video_x11_screen); + XSetWindowAttributes win_attrs; + XVisualInfo *visual; + + if( glXQueryVersion( video_x11_display, &major, &minor ) == False ) { + ERROR( "X Display lacks the GLX nature" ); + return FALSE; + } + if( major < 1 || minor < 2 ) { + ERROR( "X display supports GLX %d.%d, but we need at least 1.2", major, minor ); + return FALSE; + } + + glxExts = glXQueryExtensionsString( video_x11_display, screen ); + glxServer = glXQueryServerString( video_x11_display, screen, GLX_VENDOR ); + INFO( "GLX version %d.%d, %s. Supported exts: %s", major, minor, + glxServer, glxExts ); + + /* Find ourselves a nice visual */ + visual = glXChooseVisual( video_x11_display, + screen, + visual_attrs ); + if( visual == NULL ) { + ERROR( "Unable to obtain a compatible visual" ); + return FALSE; + } + + /* And a matching gl context */ + glx_context = glXCreateContext( video_x11_display, visual, None, True ); + if( glx_context == NULL ) { + ERROR( "Unable to obtain a GLX Context. Possibly your system is broken in some small, undefineable way" ); + return FALSE; + } + + + /* Ok, all good so far. Unfortunately the visual we need to use will + * almost certainly be different from the one our frame is using. Which + * means we have to jump through the following hoops to create a + * child window with the appropriate settings. + */ + win_attrs.event_mask = 0; + win_attrs.colormap = XCreateColormap( video_x11_display, + RootWindowOfScreen(video_x11_screen), + visual->visual, AllocNone ); + glx_window = XCreateWindow( video_x11_display, video_x11_window, + x, y, width, height, 0, visual->depth, + InputOutput, visual->visual, + CWColormap | CWEventMask, + &win_attrs ); + if( glx_window == None ) { + /* Hrm. Aww, no window? */ + ERROR( "Unable to create GLX window" ); + glXDestroyContext( video_x11_display, glx_context ); + if( win_attrs.colormap ) + XFreeColormap( video_x11_display, win_attrs.colormap ); + return FALSE; + } + XMapRaised( video_x11_display, glx_window ); + + /* And finally set the window to be the active drawing area */ + if( glXMakeCurrent( video_x11_display, glx_window, glx_context ) == False ) { + /* Ok you have _GOT_ to be kidding me */ + ERROR( "Unable to prepare GLX window for drawing" ); + XDestroyWindow( video_x11_display, glx_window ); + XFreeColormap( video_x11_display, win_attrs.colormap ); + glXDestroyContext( video_x11_display, glx_context ); + return FALSE; + } + + glx_open = TRUE; + return TRUE; +} + +void video_glx_swap_buffers( void ) +{ + glXSwapBuffers( video_x11_display, glx_window ); +} + +void video_glx_create_pixmap( int width, int height ) +{ + +} --- a/src/pvr2/pvr2.c Mon Mar 13 12:38:39 2006 +0000 +++ b/src/pvr2/pvr2.c Mon Mar 13 12:39:07 2006 +0000 @@ -1,5 +1,5 @@ /** - * $Id: pvr2.c,v 1.16 2006-02-15 13:11:46 nkeynes Exp $ + * $Id: pvr2.c,v 1.17 2006-03-13 12:39:07 nkeynes Exp $ * * PVR2 (Video) Core MMIO registers. * @@ -21,10 +21,10 @@ #include "video.h" #include "mem.h" #include "asic.h" -#include "pvr2.h" +#include "pvr2/pvr2.h" #include "sh4/sh4core.h" #define MMIO_IMPL -#include "pvr2.h" +#include "pvr2/pvr2mmio.h" char *video_base; @@ -32,10 +32,25 @@ uint32_t pvr2_run_slice( uint32_t ); void pvr2_display_frame( void ); +/** + * Current PVR2 ram address of the data (if any) currently held in the + * OpenGL buffers. + */ + video_driver_t video_driver = NULL; struct video_buffer video_buffer[2]; int video_buffer_idx = 0; +struct video_timing { + int fields_per_second; + int total_lines; + int display_lines; + int line_time_ns; +}; + +struct video_timing pal_timing = { 50, 625, 575, 32000 }; +struct video_timing ntsc_timing= { 60, 525, 480, 31746 }; + struct dreamcast_module pvr2_module = { "PVR2", pvr2_init, NULL, NULL, pvr2_run_slice, NULL, NULL, NULL }; @@ -47,19 +62,36 @@ register_io_region( &mmio_region_PVR2TA ); video_base = mem_get_region_by_name( MEM_REGION_VIDEO ); video_driver = &video_gtk_driver; - video_driver->set_output_format( 640, 480, COLFMT_RGB32 ); + video_driver->set_display_format( 640, 480, COLFMT_RGB32 ); } +uint32_t pvr2_line_count = 0; +uint32_t pvr2_line_remainder = 0; +uint32_t pvr2_irq_vpos1 = 0; +uint32_t pvr2_irq_vpos2 = 0; +struct video_timing *pvr2_timing = &ntsc_timing; uint32_t pvr2_time_counter = 0; uint32_t pvr2_frame_counter = 0; uint32_t pvr2_time_per_frame = 20000000; uint32_t pvr2_run_slice( uint32_t nanosecs ) { - pvr2_time_counter += nanosecs; - while( pvr2_time_counter >= pvr2_time_per_frame ) { - pvr2_display_frame(); - pvr2_time_counter -= pvr2_time_per_frame; + pvr2_line_remainder += nanosecs; + while( pvr2_line_remainder >= pvr2_timing->line_time_ns ) { + pvr2_line_remainder -= pvr2_timing->line_time_ns; + pvr2_line_count++; + if( pvr2_line_count == pvr2_irq_vpos1 ) { + asic_event( EVENT_SCANLINE1 ); + } + if( pvr2_line_count == pvr2_irq_vpos2 ) { + asic_event( EVENT_SCANLINE2 ); + } + if( pvr2_line_count == pvr2_timing->display_lines ) { + asic_event( EVENT_RETRACE ); + } else if( pvr2_line_count == pvr2_timing->total_lines ) { + pvr2_display_frame(); + pvr2_line_count = 0; + } } return nanosecs; } @@ -68,48 +100,61 @@ int interlaced, bChanged = 1, bEnabled = 0, vid_size = 0; char *frame_start; /* current video start address (in real memory) */ -/* +/** * Display the next frame, copying the current contents of video ram to * the window. If the video configuration has changed, first recompute the * new frame size/depth. */ void pvr2_display_frame( void ) { + uint32_t display_addr = MMIO_READ( PVR2, DISPADDR1 ); + int dispsize = MMIO_READ( PVR2, DISPSIZE ); int dispmode = MMIO_READ( PVR2, DISPMODE ); - int vidcfg = MMIO_READ( PVR2, VIDCFG ); + int vidcfg = MMIO_READ( PVR2, DISPCFG ); int vid_stride = ((dispsize & DISPSIZE_MODULO) >> 20) - 1; int vid_lpf = ((dispsize & DISPSIZE_LPF) >> 10) + 1; int vid_ppl = ((dispsize & DISPSIZE_PPL)) + 1; - gboolean bEnabled = (dispmode & DISPMODE_DE) && (vidcfg & VIDCFG_VO ) ? TRUE : FALSE; - gboolean interlaced = (vidcfg & VIDCFG_I ? TRUE : FALSE); + gboolean bEnabled = (dispmode & DISPMODE_DE) && (vidcfg & DISPCFG_VO ) ? TRUE : FALSE; + gboolean interlaced = (vidcfg & DISPCFG_I ? TRUE : FALSE); if( bEnabled ) { video_buffer_t buffer = &video_buffer[video_buffer_idx]; video_buffer_idx = !video_buffer_idx; video_buffer_t last = &video_buffer[video_buffer_idx]; - buffer->colour_format = (dispmode & DISPMODE_COL); buffer->rowstride = (vid_ppl + vid_stride) << 2; buffer->data = frame_start = video_base + MMIO_READ( PVR2, DISPADDR1 ); buffer->vres = vid_lpf; if( interlaced ) buffer->vres <<= 1; - switch( buffer->colour_format ) { - case COLFMT_RGB15: - case COLFMT_RGB16: buffer->hres = vid_ppl << 1; break; - case COLFMT_RGB24: buffer->hres = (vid_ppl << 2) / 3; break; - case COLFMT_RGB32: buffer->hres = vid_ppl; break; + switch( (dispmode & DISPMODE_COL) >> 2 ) { + case 0: + buffer->colour_format = COLFMT_ARGB1555; + buffer->hres = vid_ppl << 1; + break; + case 1: + buffer->colour_format = COLFMT_RGB565; + buffer->hres = vid_ppl << 1; + break; + case 2: + buffer->colour_format = COLFMT_RGB888; + buffer->hres = (vid_ppl << 2) / 3; + break; + case 3: + buffer->colour_format = COLFMT_ARGB8888; + buffer->hres = vid_ppl; + break; } if( video_driver != NULL ) { if( buffer->hres != last->hres || buffer->vres != last->vres || buffer->colour_format != last->colour_format) { - video_driver->set_output_format( buffer->hres, buffer->vres, - buffer->colour_format ); + video_driver->set_display_format( buffer->hres, buffer->vres, + buffer->colour_format ); } - if( MMIO_READ( PVR2, VIDCFG2 ) & 0x08 ) { /* Blanked */ + if( MMIO_READ( PVR2, DISPCFG2 ) & 0x08 ) { /* Blanked */ uint32_t colour = MMIO_READ( PVR2, DISPBORDER ); video_driver->display_blank_frame( colour ); - } else { + } else if( !pvr2_render_display_frame( PVR2_RAM_BASE + display_addr ) ) { video_driver->display_frame( buffer ); } } @@ -135,6 +180,10 @@ MMIO_REGID(PVR2,reg), MMIO_REGDESC(PVR2,reg) ); switch(reg) { + case VPOS_IRQ: + pvr2_irq_vpos1 = (val >> 16) & 0x03FF; + pvr2_irq_vpos2 = val & 0x03FF; + break; case TAINIT: if( val & 0x80000000 ) pvr2_ta_init(); @@ -178,4 +227,88 @@ } +void pvr2_vram64_write( sh4addr_t destaddr, char *src, uint32_t length ) +{ + int bank_flag = (destaddr & 0x04) >> 2; + uint32_t *banks[2]; + uint32_t *dwsrc; + int i; + destaddr = destaddr & 0x7FFFFF; + if( destaddr + length > 0x800000 ) { + length = 0x800000 - destaddr; + } + + for( i=destaddr & 0xFFFFF000; i < destaddr + length; i+= PAGE_SIZE ) { + texcache_invalidate_page( i ); + } + + banks[0] = ((uint32_t *)(video_base + (destaddr>>3))); + banks[1] = banks[0] + 0x100000; + + /* Handle non-aligned start of source */ + if( destaddr & 0x03 ) { + char *dest = ((char *)banks[bank_flag]) + (destaddr & 0x03); + for( i= destaddr & 0x03; i < 4 && length > 0; i++, length-- ) { + *dest++ = *src++; + } + bank_flag = !bank_flag; + } + + dwsrc = (uint32_t *)src; + while( length >= 4 ) { + *banks[bank_flag]++ = *dwsrc++; + bank_flag = !bank_flag; + length -= 4; + } + + /* Handle non-aligned end of source */ + if( length ) { + src = (char *)dwsrc; + char *dest = (char *)banks[bank_flag]; + while( length-- > 0 ) { + *dest++ = *src++; + } + } + +} + +void pvr2_vram64_read( char *dest, sh4addr_t srcaddr, uint32_t length ) +{ + int bank_flag = (srcaddr & 0x04) >> 2; + uint32_t *banks[2]; + uint32_t *dwdest; + int i; + + srcaddr = srcaddr & 0x7FFFFF; + if( srcaddr + length > 0x800000 ) + length = 0x800000 - srcaddr; + + banks[0] = ((uint32_t *)(video_base + (srcaddr>>3))); + banks[1] = banks[0] + 0x100000; + + /* Handle non-aligned start of source */ + if( srcaddr & 0x03 ) { + char *src = ((char *)banks[bank_flag]) + (srcaddr & 0x03); + for( i= srcaddr & 0x03; i < 4 && length > 0; i++, length-- ) { + *dest++ = *src++; + } + bank_flag = !bank_flag; + } + + dwdest = (uint32_t *)dest; + while( length >= 4 ) { + *dwdest++ = *banks[bank_flag]++; + bank_flag = !bank_flag; + length -= 4; + } + + /* Handle non-aligned end of source */ + if( length ) { + dest = (char *)dwdest; + char *src = (char *)banks[bank_flag]; + while( length-- > 0 ) { + *dest++ = *src++; + } + } +} --- a/src/pvr2/pvr2.h Mon Mar 13 12:38:39 2006 +0000 +++ b/src/pvr2/pvr2.h Mon Mar 13 12:39:07 2006 +0000 @@ -1,7 +1,7 @@ /** - * $Id: pvr2.h,v 1.8 2006-02-15 13:11:46 nkeynes Exp $ + * $Id: pvr2.h,v 1.9 2006-03-13 12:39:07 nkeynes Exp $ * - * PVR2 (video chip) MMIO registers and functions. + * PVR2 (video chip) functions and macros. * * Copyright (c) 2005 Nathan Keynes. * @@ -16,67 +16,12 @@ * GNU General Public License for more details. */ -#include "mmio.h" +#include "dream.h" +#include "mem.h" +#include "video.h" +#include "pvr2/pvr2mmio.h" +#include -MMIO_REGION_BEGIN( 0x005F8000, PVR2, "Power VR/2" ) - LONG_PORT( 0x000, PVRID, PORT_MR, 0x17FD11DB, "PVR2 Core ID" ) - LONG_PORT( 0x004, PVRVER, PORT_MR, 0x00000011, "PVR2 Core Version" ) - LONG_PORT( 0x008, PVRRST, PORT_MR, 0, "PVR2 Reset" ) - LONG_PORT( 0x014, RENDSTART, PORT_W, 0, "Start render" ) - LONG_PORT( 0x020, OBJBASE, PORT_MRW, 0, "Object buffer base offset" ) - LONG_PORT( 0x02C, TILEBASE, PORT_MRW, 0, "Tile buffer base offset" ) - LONG_PORT( 0x040, DISPBORDER, PORT_MRW, 0, "Border Colour (RGB)" ) - LONG_PORT( 0x044, DISPMODE, PORT_MRW, 0, "Display Mode" ) - LONG_PORT( 0x048, RENDMODE, PORT_MRW, 0, "Rendering Mode" ) - LONG_PORT( 0x04C, RENDSIZE, PORT_MRW, 0, "Rendering width (bytes/2)" ) - LONG_PORT( 0x050, DISPADDR1, PORT_MRW, 0, "Video memory base 1" ) - LONG_PORT( 0x054, DISPADDR2, PORT_MRW, 0, "Video memory base 2" ) - LONG_PORT( 0x05C, DISPSIZE, PORT_MRW, 0, "Display size" ) - LONG_PORT( 0x060, RENDADDR1, PORT_MRW, 0, "Rendering memory base 1" ) - LONG_PORT( 0x064, RENDADDR2, PORT_MRW, 0, "Rendering memory base 2" ) - LONG_PORT( 0x068, HCLIP, PORT_MRW, 0, "Horizontal clipping area" ) - LONG_PORT( 0x06C, VCLIP, PORT_MRW, 0, "Vertical clipping area" ) - LONG_PORT( 0x074, SHADOW, PORT_MRW, 0, "Shadowing" ) - LONG_PORT( 0x078, OBJCLIP, PORT_MRW, 0, "Object clip distance (float32)" ) - LONG_PORT( 0x084, TSPCLIP, PORT_MRW, 0, "Texture clip distance (float32)" ) - LONG_PORT( 0x088, BGPLANEZ, PORT_MRW, 0, "Background plane depth (float32)" ) - LONG_PORT( 0x08C, BGPLANECFG, PORT_MRW, 0, "Background plane config" ) - LONG_PORT( 0x0B0, FGTBLCOL, PORT_MRW, 0, "Fog table colour" ) - LONG_PORT( 0x0B4, FGVRTCOL, PORT_MRW, 0, "Fog vertex colour" ) - LONG_PORT( 0x0B8, FGCOEFF, PORT_MRW, 0, "Fog density coefficient (float16)" ) - LONG_PORT( 0x0BC, CLAMPHI, PORT_MRW, 0, "Clamp high colour" ) - LONG_PORT( 0x0C0, CLAMPLO, PORT_MRW, 0, "Clamp low colour" ) - LONG_PORT( 0x0C4, GUNPOS, PORT_MRW, 0, "Lightgun position" ) - LONG_PORT( 0x0CC, EVTPOS, PORT_MRW, 0, "Raster event position" ) - LONG_PORT( 0x0D0, VIDCFG, PORT_MRW, 0, "Sync configuration & enable" ) - LONG_PORT( 0x0D4, HBORDER, PORT_MRW, 0, "Horizontal border area" ) - LONG_PORT( 0x0D8, REFRESH, PORT_MRW, 0, "Refresh rates?" ) - LONG_PORT( 0x0DC, VBORDER, PORT_MRW, 0, "Vertical border area" ) - LONG_PORT( 0x0E0, SYNCPOS, PORT_MRW, 0, "Sync pulse timing" ) - LONG_PORT( 0x0E4, TSPCFG, PORT_MRW, 0, "Texture modulo width" ) - LONG_PORT( 0x0E8, VIDCFG2, PORT_MRW, 0, "Video configuration 2" ) - LONG_PORT( 0x0F0, VPOS, PORT_MRW, 0, "Vertical display position" ) - LONG_PORT( 0x0F4, SCALERCFG, PORT_MRW, 0, "Scaler configuration (?)" ) - LONG_PORT( 0x10C, BEAMPOS, PORT_R, 0, "Raster beam position" ) - LONG_PORT( 0x124, TAOPBST, PORT_MRW, 0, "TA Object Pointer Buffer start" ) - LONG_PORT( 0x128, TAOBST, PORT_MRW, 0, "TA Object Buffer start" ) - LONG_PORT( 0x12C, TAOPBEN, PORT_MRW, 0, "TA Object Pointer Buffer end" ) - LONG_PORT( 0x130, TAOBEN, PORT_MRW, 0, "TA Object Buffer end" ) - LONG_PORT( 0x134, TAOPBPOS, PORT_MRW, 0, "TA Object Pointer Buffer position" ) - LONG_PORT( 0x138, TAOBPOS, PORT_MRW, 0, "TA Object Buffer position" ) - LONG_PORT( 0x13C, TATBSZ, PORT_MRW, 0, "TA Tile Buffer size" ) - LONG_PORT( 0x140, TAOPBCFG, PORT_MRW, 0, "TA Object Pointer Buffer config" ) - LONG_PORT( 0x144, TAINIT, PORT_MRW, 0, "TA Initialize" ) - LONG_PORT( 0x164, TAOPLST, PORT_MRW, 0, "TA Object Pointer List start" ) -MMIO_REGION_END - -MMIO_REGION_BEGIN( 0x005F9000, PVR2PAL, "Power VR/2 CLUT Palettes" ) - LONG_PORT( 0x000, PAL0_0, PORT_MRW, 0, "Pal0 colour 0" ) -MMIO_REGION_END - -MMIO_REGION_BEGIN( 0x10000000, PVR2TA, "Power VR/2 TA Command port" ) - LONG_PORT( 0x000, TACMD, PORT_MRW, 0, "TA Command port" ) -MMIO_REGION_END #define DISPMODE_DE 0x00000001 /* Display enable */ #define DISPMODE_SD 0x00000002 /* Scan double */ @@ -92,26 +37,136 @@ #define DISPSIZE_LPF 0x000FFC00 /* lines per field */ #define DISPSIZE_PPL 0x000003FF /* pixel words (32 bit) per line */ -#define VIDCFG_VP 0x00000001 /* V-sync polarity */ -#define VIDCFG_HP 0x00000002 /* H-sync polarity */ -#define VIDCFG_I 0x00000010 /* Interlace enable */ -#define VIDCFG_BS 0x000000C0 /* Broadcast standard */ -#define VIDCFG_VO 0x00000100 /* Video output enable */ +#define DISPCFG_VP 0x00000001 /* V-sync polarity */ +#define DISPCFG_HP 0x00000002 /* H-sync polarity */ +#define DISPCFG_I 0x00000010 /* Interlace enable */ +#define DISPCFG_BS 0x000000C0 /* Broadcast standard */ +#define DISPCFG_VO 0x00000100 /* Video output enable */ #define BS_NTSC 0x00000000 #define BS_PAL 0x00000040 #define BS_PALM 0x00000080 /* ? */ #define BS_PALN 0x000000C0 /* ? */ +#define PVR2_RAM_BASE 0x05000000 +#define PVR2_RAM_BASE_INT 0x04000000 +#define PVR2_RAM_SIZE (8 * 1024 * 1024) +#define PVR2_RAM_PAGES (PVR2_RAM_SIZE>>12) + void pvr2_next_frame( void ); void pvr2_set_base_address( uint32_t ); +#define PVR2_CMD_END_OF_LIST 0x00 +#define PVR2_CMD_USER_CLIP 0x20 +#define PVR2_CMD_POLY_OPAQUE 0x80 +#define PVR2_CMD_MOD_OPAQUE 0x81 +#define PVR2_CMD_POLY_TRANS 0x82 +#define PVR2_CMD_MOD_TRANS 0x83 +#define PVR2_CMD_POLY_PUNCHOUT 0x84 +#define PVR2_CMD_VERTEX 0xE0 +#define PVR2_CMD_VERTEX_LAST 0xF0 + +#define PVR2_POLY_TEXTURED 0x00000008 +#define PVR2_POLY_SPECULAR 0x00000004 +#define PVR2_POLY_SHADED 0x00000002 +#define PVR2_POLY_UV_16BIT 0x00000001 + +#define PVR2_TEX_FORMAT_ARGB1555 0x00000000 +#define PVR2_TEX_FORMAT_RGB565 0x08000000 +#define PVR2_TEX_FORMAT_ARGB4444 0x10000000 +#define PVR2_TEX_FORMAT_YUV422 0x18000000 +#define PVR2_TEX_FORMAT_BUMPMAP 0x20000000 +#define PVR2_TEX_FORMAT_IDX4 0x28000000 +#define PVR2_TEX_FORMAT_IDX8 0x30000000 + +#define PVR2_TEX_MIPMAP 0x80000000 +#define PVR2_TEX_COMPRESSED 0x40000000 +#define PVR2_TEX_FORMAT_MASK 0x38000000 +#define PVR2_TEX_UNTWIDDLED 0x04000000 + +#define PVR2_TEX_ADDR(x) ( ((x)&0x1FFFFF)<<3 ); +#define PVR2_TEX_IS_MIPMAPPED(x) ( (x) & PVR2_TEX_MIPMAP ) +#define PVR2_TEX_IS_COMPRESSED(x) ( (x) & PVR2_TEX_COMPRESSED ) +#define PVR2_TEX_IS_TWIDDLED(x) (((x) & PVR2_TEX_UNTWIDDLED) == 0) + +extern video_driver_t video_driver; + +/****************************** Frame Buffer *****************************/ + +/** + * Write to the interleaved memory address space (aka 64-bit address space). + */ +void pvr2_vram64_write( sh4addr_t dest, char *src, uint32_t length ); + +/** + * Read from the interleaved memory address space (aka 64-bit address space) + */ +void pvr2_vram64_read( char *dest, sh4addr_t src, uint32_t length ); + +/**************************** Tile Accelerator ***************************/ /** * Process the data in the supplied buffer as an array of TA command lists. * Any excess bytes are held pending until a complete list is sent */ void pvr2_ta_write( char *buf, uint32_t length ); -void pvr2_init( void ); +/** + * (Re)initialize the tile accelerator in preparation for the next scene. + * Normally called immediately before commencing polygon transmission. + */ +void pvr2_ta_init( void ); + +/********************************* Renderer ******************************/ + +/** + * Initialize the rendering pipeline. + * @return TRUE on success, FALSE on failure. + */ +gboolean pvr2_render_init( void ); + +/** + * Render the current scene stored in PVR ram to the GL back buffer. + */ void pvr2_render_scene( void ); + +/** + * Display the scene rendered to the supplied address. + * @return TRUE if there was an available render that was displayed, + * otherwise FALSE (and no action was taken) + */ +gboolean pvr2_render_display_frame( uint32_t address ); + +/****************************** Texture Cache ****************************/ + +/** + * Initialize the texture cache. Note that the GL context must have been + * initialized before calling this function. + */ +void texcache_init( void ); + + +/** + * Flush all textures and delete. The cache will be non-functional until + * the next call to texcache_init(). This would typically be done if + * switching GL targets. + */ +void texcache_shutdown( void ); + +/** + * Evict all textures contained in the page identified by a texture address. + */ +void texcache_invalidate_page( uint32_t texture_addr ); + +/** + * Return a texture ID for the texture specified at the supplied address + * and given parameters (the same sequence of bytes could in theory have + * multiple interpretations). We use the texture address as the primary + * index, but allow for multiple instances at each address. The texture + * will be bound to the GL_TEXTURE_2D target before being returned. + * + * If the texture has already been bound, return the ID to which it was + * bound. Otherwise obtain an unused texture ID and set it up appropriately. + */ +GLuint texcache_get_texture( uint32_t texture_addr, int width, int height, + int mode ); --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pvr2/pvr2mmio.h Mon Mar 13 12:39:07 2006 +0000 @@ -0,0 +1,80 @@ +/** + * $Id: pvr2mmio.h,v 1.1 2006-03-13 12:39:07 nkeynes Exp $ + * + * PVR2 (video chip) MMIO register definitions. + * + * Copyright (c) 2005 Nathan Keynes. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "mmio.h" + +MMIO_REGION_BEGIN( 0x005F8000, PVR2, "Power VR/2" ) + LONG_PORT( 0x000, PVRID, PORT_MR, 0x17FD11DB, "PVR2 Core ID" ) + LONG_PORT( 0x004, PVRVER, PORT_MR, 0x00000011, "PVR2 Core Version" ) + LONG_PORT( 0x008, PVRRST, PORT_MR, 0, "PVR2 Reset" ) + LONG_PORT( 0x014, RENDSTART, PORT_W, 0, "Start render" ) + LONG_PORT( 0x020, OBJBASE, PORT_MRW, 0, "Object buffer base offset" ) + LONG_PORT( 0x02C, TILEBASE, PORT_MRW, 0, "Tile buffer base offset" ) + LONG_PORT( 0x040, DISPBORDER, PORT_MRW, 0, "Border Colour (RGB)" ) + LONG_PORT( 0x044, DISPMODE, PORT_MRW, 0, "Display Mode" ) + LONG_PORT( 0x048, RENDMODE, PORT_MRW, 0, "Rendering Mode" ) + LONG_PORT( 0x04C, RENDSIZE, PORT_MRW, 0, "Rendering width (bytes/2)" ) + LONG_PORT( 0x050, DISPADDR1, PORT_MRW, 0, "Video memory base 1" ) + LONG_PORT( 0x054, DISPADDR2, PORT_MRW, 0, "Video memory base 2" ) + LONG_PORT( 0x05C, DISPSIZE, PORT_MRW, 0, "Display size" ) + LONG_PORT( 0x060, RENDADDR1, PORT_MRW, 0, "Rendering memory base 1" ) + LONG_PORT( 0x064, RENDADDR2, PORT_MRW, 0, "Rendering memory base 2" ) + LONG_PORT( 0x068, HCLIP, PORT_MRW, 0, "Horizontal clipping area" ) + LONG_PORT( 0x06C, VCLIP, PORT_MRW, 0, "Vertical clipping area" ) + LONG_PORT( 0x074, SHADOW, PORT_MRW, 0, "Shadowing" ) + LONG_PORT( 0x078, OBJCLIP, PORT_MRW, 0, "Object clip distance (float32)" ) + LONG_PORT( 0x07C, OBJCFG, PORT_MRW, 0, "Object config" ) + LONG_PORT( 0x084, TSPCLIP, PORT_MRW, 0, "Texture clip distance (float32)" ) + LONG_PORT( 0x088, BGPLANEZ, PORT_MRW, 0, "Background plane depth (float32)" ) + LONG_PORT( 0x08C, BGPLANECFG, PORT_MRW, 0, "Background plane config" ) + LONG_PORT( 0x0B0, FOGTBLCOL, PORT_MRW, 0, "Fog table colour" ) + LONG_PORT( 0x0B4, FOGVRTCOL, PORT_MRW, 0, "Fog vertex colour" ) + LONG_PORT( 0x0B8, FOGCOEFF, PORT_MRW, 0, "Fog density coefficient (float16)" ) + LONG_PORT( 0x0BC, CLAMPHI, PORT_MRW, 0, "Clamp high colour" ) + LONG_PORT( 0x0C0, CLAMPLO, PORT_MRW, 0, "Clamp low colour" ) + LONG_PORT( 0x0C4, GUNPOS, PORT_MRW, 0, "Lightgun position" ) + LONG_PORT( 0x0CC, VPOS_IRQ, PORT_MRW, 0, "Raster event position" ) + LONG_PORT( 0x0D0, DISPCFG, PORT_MRW, 0, "Sync configuration & enable" ) + LONG_PORT( 0x0D4, HBORDER, PORT_MRW, 0, "Horizontal border area" ) + LONG_PORT( 0x0D8, REFRESH, PORT_MRW, 0, "Refresh rates?" ) + LONG_PORT( 0x0DC, VBORDER, PORT_MRW, 0, "Vertical border area" ) + LONG_PORT( 0x0E0, SYNCPOS, PORT_MRW, 0, "Sync pulse timing" ) + LONG_PORT( 0x0E4, TSPCFG, PORT_MRW, 0, "Texture modulo width" ) + LONG_PORT( 0x0E8, DISPCFG2, PORT_MRW, 0, "Video configuration 2" ) + LONG_PORT( 0x0F0, VPOS, PORT_MRW, 0, "Vertical display position" ) + LONG_PORT( 0x0F4, SCALERCFG, PORT_MRW, 0, "Scaler configuration (?)" ) + LONG_PORT( 0x10C, BEAMPOS, PORT_R, 0, "Raster beam position" ) + LONG_PORT( 0x124, TAOBJPBASE, PORT_MRW, 0, "TA Object Pointer Buffer start" ) + LONG_PORT( 0x128, TAOBJBASE, PORT_MRW, 0, "TA Object Buffer start" ) + LONG_PORT( 0x12C, TAOBJPEND, PORT_MRW, 0, "TA Object Pointer Buffer end" ) + LONG_PORT( 0x130, TAOBJEND, PORT_MRW, 0, "TA Object Buffer end" ) + LONG_PORT( 0x134, TAOBJPPOS, PORT_MRW, 0, "TA Object Pointer Buffer position" ) + LONG_PORT( 0x138, TAOBJPOS, PORT_MRW, 0, "TA Object Buffer position" ) + LONG_PORT( 0x13C, TATBSZ, PORT_MRW, 0, "TA Tile Buffer size" ) + LONG_PORT( 0x140, TAOPBCFG, PORT_MRW, 0, "TA Object Pointer Buffer config" ) + LONG_PORT( 0x144, TAINIT, PORT_MRW, 0, "TA Initialize" ) + LONG_PORT( 0x164, TAOPLST, PORT_MRW, 0, "TA Object Pointer List start" ) +MMIO_REGION_END + +MMIO_REGION_BEGIN( 0x005F9000, PVR2PAL, "Power VR/2 CLUT Palettes" ) + LONG_PORT( 0x000, PAL0_0, PORT_MRW, 0, "Pal0 colour 0" ) +MMIO_REGION_END + +MMIO_REGION_BEGIN( 0x10000000, PVR2TA, "Power VR/2 TA Command port" ) + LONG_PORT( 0x000, TACMD, PORT_MRW, 0, "TA Command port" ) +MMIO_REGION_END --- a/src/pvr2/render.c Mon Mar 13 12:38:39 2006 +0000 +++ b/src/pvr2/render.c Mon Mar 13 12:39:07 2006 +0000 @@ -1,5 +1,5 @@ /** - * $Id: render.c,v 1.1 2006-02-15 13:11:46 nkeynes Exp $ + * $Id: render.c,v 1.2 2006-03-13 12:39:07 nkeynes Exp $ * * PVR2 Renderer support. This is where the real work happens. * @@ -18,20 +18,422 @@ #include "pvr2/pvr2.h" #include "asic.h" -#include "dream.h" + + +#define POLY_COLOUR_ARGB8888 0x00000000 +#define POLY_COLOUR_ARGBFLOAT 0x00000010 + +static int pvr2_poly_vertexes[4] = { 3, 4, 6, 8 }; +static int pvr2_poly_type[4] = { GL_TRIANGLES, GL_QUADS, GL_TRIANGLE_STRIP, GL_TRIANGLE_STRIP }; +static int pvr2_poly_depthmode[8] = { GL_NEVER, GL_LESS, GL_EQUAL, GL_LEQUAL, + GL_GREATER, GL_NOTEQUAL, GL_GEQUAL, + GL_ALWAYS }; +static int pvr2_poly_srcblend[8] = { + GL_ZERO, GL_ONE, GL_DST_COLOR, GL_ONE_MINUS_DST_COLOR, + GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_DST_ALPHA, + GL_ONE_MINUS_DST_ALPHA }; +static int pvr2_poly_dstblend[8] = { + GL_ZERO, GL_ONE, GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR, + GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_DST_ALPHA, + GL_ONE_MINUS_DST_ALPHA }; +static int pvr2_render_colour_format[8] = { + COLFMT_ARGB1555, COLFMT_RGB565, COLFMT_ARGB4444, COLFMT_ARGB1555, + COLFMT_RGB888, COLFMT_ARGB8888, COLFMT_ARGB8888, COLFMT_ARGB4444 }; + +#define POLY_STRIP_TYPE(poly) ( pvr2_poly_type[((poly->command)>>18)&0x03] ) +#define POLY_STRIP_VERTEXES(poly) ( pvr2_poly_vertexes[((poly->command)>>18)&0x03] ) +#define POLY_DEPTH_MODE(poly) ( pvr2_poly_depthmode[poly->poly_cfg>>29] ) +#define POLY_DEPTH_WRITE(poly) (poly->poly_cfg&0x04000000) +#define POLY_TEX_WIDTH(poly) ( 1<< (((poly->poly_mode >> 3) & 0x07 ) + 3) ) +#define POLY_TEX_HEIGHT(poly) ( 1<< (((poly->poly_mode) & 0x07 ) + 3) ) +#define POLY_BLEND_SRC(poly) ( pvr2_poly_srcblend[(poly->poly_mode) >> 29] ) +#define POLY_BLEND_DEST(poly) ( pvr2_poly_dstblend[((poly->poly_mode)>>26)&0x07] ) extern uint32_t pvr2_frame_counter; /** - * Render a complete scene into an OpenGL buffer. - * Note: this may need to be broken up eventually once timings are + * Describes a rendering buffer that's actually held in GL, for when we need + * to fetch the bits back to vram. + */ +typedef struct pvr2_render_buffer { + uint32_t render_addr; /* The actual address rendered to in pvr ram */ + int width, height; + int colour_format; +} *pvr2_render_buffer_t; + +struct pvr2_render_buffer front_buffer; +struct pvr2_render_buffer back_buffer; + +struct tile_descriptor { + uint32_t header[6]; + struct tile_pointers { + uint32_t tile_id; + uint32_t opaque_ptr; + uint32_t opaque_mod_ptr; + uint32_t trans_ptr; + uint32_t trans_mod_ptr; + uint32_t punchout_ptr; + } tile[0]; +}; + +/* Textured polygon */ +struct pvr2_poly { + uint32_t command; + uint32_t poly_cfg; /* Bitmask */ + uint32_t poly_mode; /* texture/blending mask */ + uint32_t texture; /* texture data */ + float alpha; + float red; + float green; + float blue; +}; + +struct pvr2_specular_highlight { + float base_alpha; + float base_red; + float base_green; + float base_blue; + float offset_alpha; + float offset_red; + float offset_green; + float offset_blue; +}; + + +struct pvr2_vertex_basic { + uint32_t command; + float x, y, z; + float s,t; + uint32_t col; + float f; +}; + + +void pvr2_render_copy_to_sh4( pvr2_render_buffer_t buffer, + gboolean backBuffer ); + + +gboolean pvr2_render_init( void ) +{ + front_buffer.render_addr = -1; + back_buffer.render_addr = -1; +} + +/** + * Display a rendered frame if one is available. + * @param address An address in PVR ram (0500000 range). + * @return TRUE if a frame was available to be displayed, otherwise false. + */ +gboolean pvr2_render_display_frame( uint32_t address ) +{ + if( front_buffer.render_addr == address ) { + /* Current front buffer is already displayed, so do nothing + * and tell the caller that all is well. + */ + return TRUE; + } + if( back_buffer.render_addr == address ) { + /* The more useful case - back buffer is to be displayed. Swap + * the buffers + */ + video_driver->display_back_buffer(); + front_buffer = back_buffer; + back_buffer.render_addr = -1; + return TRUE; + } + return FALSE; +} + +/** + * Prepare the OpenGL context to receive instructions for a new frame. + */ +static void pvr2_render_prepare_context( sh4addr_t render_addr, + uint32_t width, uint32_t height, + uint32_t colour_format, + gboolean texture_target ) +{ + /* Select and initialize the render context */ + video_driver->set_render_format( width, height, colour_format, texture_target ); + + if( back_buffer.render_addr != -1 && + back_buffer.render_addr != render_addr ) { + /* There's a current back buffer, and we're rendering somewhere else - + * flush the back buffer back to vram and start a new back buffer + */ + pvr2_render_copy_to_sh4( &back_buffer, TRUE ); + } + + if( front_buffer.render_addr == render_addr ) { + /* In case we've been asked to render to the current front buffer - + * invalidate the front buffer and render to the back buffer, ensuring + * we swap at the next frame display. + */ + front_buffer.render_addr = -1; + } + back_buffer.render_addr = render_addr; + back_buffer.width = width; + back_buffer.height = height; + back_buffer.colour_format = colour_format; + + /* Setup the display model */ + glDrawBuffer(GL_BACK); + glShadeModel(GL_SMOOTH); + glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); + glViewport( 0, 0, width, height ); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho( 0, width, height, 0, 0, 65535 ); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + /* Clear out the buffers */ + glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + glClearDepth(1.0f); + glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); +} + +static void pvr2_render_display_list( uint32_t *display_list, uint32_t length ) +{ + uint32_t *cmd_ptr = display_list; + int expect_vertexes = 0; + gboolean textured = FALSE; + struct pvr2_poly *poly; + while( cmd_ptr < display_list+length ) { + switch( *cmd_ptr >> 24 ) { + case PVR2_CMD_POLY_OPAQUE: + poly = (struct pvr2_poly *)cmd_ptr; + + if( poly->command & PVR2_POLY_TEXTURED ) { + uint32_t addr = PVR2_TEX_ADDR(poly->texture); + int width = POLY_TEX_WIDTH(poly); + int height = POLY_TEX_HEIGHT(poly); + texcache_get_texture( addr, width, height, poly->texture ); + textured = TRUE; + glEnable( GL_TEXTURE_2D ); + } else { + textured = FALSE; + glDisable( GL_TEXTURE_2D ); + } + glBlendFunc( POLY_BLEND_SRC(poly), POLY_BLEND_DEST(poly) ); + if( poly->command & PVR2_POLY_SPECULAR ) { + /* Second block expected */ + } + if( POLY_DEPTH_WRITE(poly) ) { + glEnable( GL_DEPTH_TEST ); + glDepthFunc( POLY_DEPTH_MODE(poly) ); + } else { + glDisable( GL_DEPTH_TEST ); + } + + expect_vertexes = POLY_STRIP_VERTEXES( poly ); + if( expect_vertexes == 3 ) + glBegin( GL_TRIANGLES ); + else if( expect_vertexes == 4 ) + glBegin( GL_QUADS ); + else + glBegin( GL_TRIANGLE_STRIP ); + break; + case PVR2_CMD_VERTEX_LAST: + case PVR2_CMD_VERTEX: + if( expect_vertexes == 0 ) { + ERROR( "Unexpected vertex!" ); + return; + } + expect_vertexes--; + struct pvr2_vertex_basic *vertex = (struct pvr2_vertex_basic *)cmd_ptr; + if( textured ) { + glTexCoord2f( vertex->s, vertex->t ); + } + glVertex3f( vertex->x, vertex->y, vertex->z ); + + if( expect_vertexes == 0 ) + glEnd(); + break; + } + cmd_ptr += 8; /* Next record */ + } +} + +/** + * Render a complete scene into the OpenGL back buffer. + * Note: this will probably need to be broken up eventually once timings are * determined. */ -void pvr2_render_scene( void ) +void pvr2_render_scene( ) { - /* Actual rendering goes here :) */ + struct tile_descriptor *tile_desc = + (struct tile_descriptor *)mem_get_region(PVR2_RAM_BASE + MMIO_READ( PVR2, TILEBASE )); - /* End of render event */ + uint32_t render_addr = MMIO_READ( PVR2, RENDADDR1 ); + gboolean render_to_tex; + if( render_addr & 0x01000000 ) { + render_addr = (render_addr & 0x00FFFFFF) + PVR2_RAM_BASE_INT; + /* Heuristic - if we're rendering to the interlaced region we're + * probably creating a texture rather than rendering actual output. + * We can optimise for this case a little + */ + render_to_tex = TRUE; + } else { + render_addr = (render_addr & 0x00FFFFFF) + PVR2_RAM_BASE; + render_to_tex = FALSE; + } + uint32_t render_mode = MMIO_READ( PVR2, RENDMODE ); + int width = 640; /* FIXME - get this from the tile buffer */ + int height = 480; + int colour_format = pvr2_render_colour_format[render_mode&0x07]; + pvr2_render_prepare_context( render_addr, width, height, colour_format, + render_to_tex ); + + uint32_t *display_list = + (uint32_t *)mem_get_region(PVR2_RAM_BASE + MMIO_READ( PVR2, OBJBASE )); + uint32_t display_length = *display_list++; + + int clip_x = MMIO_READ( PVR2, HCLIP ) & 0x03FF; + int clip_y = MMIO_READ( PVR2, VCLIP ) & 0x03FF; + int clip_width = ((MMIO_READ( PVR2, HCLIP ) >> 16) & 0x03FF) - clip_x + 1; + int clip_height= ((MMIO_READ( PVR2, VCLIP ) >> 16) & 0x03FF) - clip_y + 1; + + if( clip_x == 0 && clip_y == 0 && clip_width == width && clip_height == height ) { + glDisable( GL_SCISSOR_TEST ); + } else { + glEnable( GL_SCISSOR_TEST ); + glScissor( clip_x, clip_y, clip_width, clip_height ); + } + + /* Fog setup goes here */ + + /* Render the display list */ + pvr2_render_display_list( display_list, display_length ); + + /* Post-render cleanup and update */ + + + /* Generate end of render event */ asic_event( EVENT_PVR_RENDER_DONE ); DEBUG( "Rendered frame %d", pvr2_frame_counter ); } + + +/** + * Flush the indicated render buffer back to PVR. Caller is responsible for + * tracking whether there is actually anything in the buffer. + * + * @param buffer A render buffer indicating the address to store to, and the + * format the data needs to be in. + * @param backBuffer TRUE to flush the back buffer, FALSE for + * the front buffer. + */ +void pvr2_render_copy_to_sh4( pvr2_render_buffer_t buffer, + gboolean backBuffer ) +{ + if( buffer->render_addr == -1 ) + return; + GLenum type, format = GL_RGBA; + int size = buffer->width * buffer->height; + + switch( buffer->colour_format ) { + case COLFMT_RGB565: + type = GL_UNSIGNED_SHORT_5_6_5; + format = GL_RGB; + size <<= 1; + break; + case COLFMT_RGB888: + type = GL_UNSIGNED_INT; + format = GL_RGB; + size = (size<<1)+size; + break; + case COLFMT_ARGB1555: + type = GL_UNSIGNED_SHORT_5_5_5_1; + size <<= 1; + break; + case COLFMT_ARGB4444: + type = GL_UNSIGNED_SHORT_4_4_4_4; + size <<= 1; + break; + case COLFMT_ARGB8888: + type = GL_UNSIGNED_INT_8_8_8_8; + size <<= 2; + break; + } + + if( backBuffer ) { + glFinish(); + glReadBuffer( GL_BACK ); + } else { + glReadBuffer( GL_FRONT ); + } + + if( buffer->render_addr & 0xFF000000 == 0x04000000 ) { + /* Interlaced buffer. Go the double copy... :( */ + char target[size]; + glReadPixels( 0, 0, buffer->width, buffer->height, format, type, target ); + pvr2_vram64_write( buffer->render_addr, target, size ); + } else { + /* Regular buffer - go direct */ + char *target = mem_get_region( buffer->render_addr ); + glReadPixels( 0, 0, buffer->width, buffer->height, format, type, target ); + } +} + + +/** + * Copy data from PVR ram into the GL render buffer. + * + * @param buffer A render buffer indicating the address to read from, and the + * format the data is in. + * @param backBuffer TRUE to write the back buffer, FALSE for + * the front buffer. + */ +void pvr2_render_copy_from_sh4( pvr2_render_buffer_t buffer, + gboolean backBuffer ) +{ + if( buffer->render_addr == -1 ) + return; + GLenum type, format = GL_RGBA; + int size = buffer->width * buffer->height; + + switch( buffer->colour_format ) { + case COLFMT_RGB565: + type = GL_UNSIGNED_SHORT_5_6_5; + format = GL_RGB; + size <<= 1; + break; + case COLFMT_RGB888: + type = GL_UNSIGNED_INT; + format = GL_RGB; + size = (size<<1)+size; + break; + case COLFMT_ARGB1555: + type = GL_UNSIGNED_SHORT_5_5_5_1; + size <<= 1; + break; + case COLFMT_ARGB4444: + type = GL_UNSIGNED_SHORT_4_4_4_4; + size <<= 1; + break; + case COLFMT_ARGB8888: + type = GL_UNSIGNED_INT_8_8_8_8; + size <<= 2; + break; + } + + if( backBuffer ) { + glDrawBuffer( GL_BACK ); + } else { + glDrawBuffer( GL_FRONT ); + } + + glRasterPos2i( 0, 0 ); + if( buffer->render_addr & 0xFF000000 == 0x04000000 ) { + /* Interlaced buffer. Go the double copy... :( */ + char target[size]; + pvr2_vram64_read( target, buffer->render_addr, size ); + glDrawPixels( buffer->width, buffer->height, + format, type, target ); + } else { + /* Regular buffer - go direct */ + char *target = mem_get_region( buffer->render_addr ); + glDrawPixels( buffer->width, buffer->height, + format, type, target ); + } +} --- a/src/pvr2/ta.c Mon Mar 13 12:38:39 2006 +0000 +++ b/src/pvr2/ta.c Mon Mar 13 12:39:07 2006 +0000 @@ -1,5 +1,5 @@ /** - * $Id: ta.c,v 1.1 2006-02-15 13:11:46 nkeynes Exp $ + * $Id: ta.c,v 1.2 2006-03-13 12:39:07 nkeynes Exp $ * * PVR2 Tile Accelerator support. In principle this does a lot more work * than is currently implemented - we cheat. A lot. @@ -42,27 +42,48 @@ float f; }; +struct pvr2_ta_status { + uint32_t *length; + unsigned int last_poly_type; +} pvr2_ta_status = {NULL,0}; + /** * (Re)initialize the tile accelerator in preparation for the next scene. * Normally called immediately before commencing polygon transmission. */ void pvr2_ta_init( void ) { - + /* Set the buffer indexes */ + MMIO_WRITE( PVR2, TAOBJPOS, MMIO_READ( PVR2, TAOBJBASE ) ); + MMIO_WRITE( PVR2, TAOBJPPOS, MMIO_READ( PVR2, TAOBJPBASE ) ); + pvr2_ta_status.last_poly_type = 0; + pvr2_ta_status.length = NULL; } -char pvr2ta_remainder[8]; -unsigned int pvr2_last_poly_type = 0; - /** * Write a block of data to the tile accelerator, adding the data to the * current scene. We don't make any particular attempt to interpret the data * at this stage, deferring that until render time. + * + * Currently copies the data verbatim to the vertex buffer, processing only + * far enough to generate the correct end-of-list events. Tile buffer is + * entirely ignored. */ void pvr2_ta_write( char *buf, uint32_t length ) { int i; struct tacmd *cmd_list = (struct tacmd *)buf; + uint32_t obj_addr = MMIO_READ( PVR2, TAOBJPOS ); + if( pvr2_ta_status.length == NULL ) { /* Start */ + pvr2_ta_status.length = (uint32_t *)mem_get_region( PVR2_RAM_BASE + obj_addr ); + obj_addr += 4; + *pvr2_ta_status.length = length; + } else { + *pvr2_ta_status.length = *pvr2_ta_status.length + length; + } + mem_copy_to_sh4( PVR2_RAM_BASE + obj_addr, buf, length ); + MMIO_WRITE( PVR2, TAOBJPOS, obj_addr + length ); + int count = length >> 5; for( i=0; i> 24) & 0xFF; @@ -74,7 +95,7 @@ } if( type == 0 ) { /* End of list */ - switch( pvr2_last_poly_type ) { + switch( pvr2_ta_status.last_poly_type ) { case 0x80: /* Opaque polys */ asic_event( EVENT_PVR_OPAQUE_DONE ); break; @@ -91,9 +112,9 @@ asic_event( EVENT_PVR_PUNCHOUT_DONE ); break; } - pvr2_last_poly_type = 0; + pvr2_ta_status.last_poly_type = 0; } else if( type >= 0x80 && type <= 0x84 ) { - pvr2_last_poly_type = type; + pvr2_ta_status.last_poly_type = type; } } } --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pvr2/texcache.c Mon Mar 13 12:39:07 2006 +0000 @@ -0,0 +1,291 @@ +/** + * $Id: texcache.c,v 1.1 2006-03-13 12:39:07 nkeynes Exp $ + * + * Texture cache. Responsible for maintaining a working set of OpenGL + * textures. + * + * + * Copyright (c) 2005 Nathan Keynes. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include "pvr2/pvr2.h" + +/** Specifies the maximum number of OpenGL + * textures we're willing to have open at a time. If more are + * needed, textures will be evicted in LRU order. + */ +#define MAX_TEXTURES 64 + +/** + * Data structure: + * + * Main operations: + * find entry by texture_addr + * add new entry + * move entry to tail of lru list + * remove entry + */ + +typedef signed short texcache_entry_index; +#define EMPTY_ENTRY -1 + +static texcache_entry_index texcache_free_ptr; +static GLuint texcache_free_list[MAX_TEXTURES]; + +typedef struct texcache_entry { + uint32_t texture_addr; + int width, height, mode; + GLuint texture_id; + texcache_entry_index next; + uint32_t lru_count; +} *texcache_entry_t; + +static uint8_t texcache_page_lookup[PVR2_RAM_PAGES]; +static uint32_t texcache_active_ptr; +static uint32_t texcache_ref_counter; +static struct texcache_entry texcache_active_list[MAX_TEXTURES]; + +/** + * Initialize the texture cache. Note that the GL context must have been + * initialized before calling this function. + */ +void texcache_init( ) +{ + int i; + GLuint texids[MAX_TEXTURES]; + glGenTextures( MAX_TEXTURES, texids ); + for( i=0; i> 12; + texcache_entry_index idx = texcache_page_lookup[texture_page]; + if( idx == EMPTY_ENTRY ) + return; + assert( texcache_free_ptr > 0 ); + do { + texcache_entry_t entry = &texcache_active_list[idx]; + /* release entry */ + texcache_free_ptr--; + texcache_free_list[texcache_free_ptr] = idx; + idx = entry->next; + entry->next = EMPTY_ENTRY; + } while( idx != EMPTY_ENTRY ); + texcache_page_lookup[texture_page] = EMPTY_ENTRY; +} + +/** + * Evict a single texture from the cache. + * @return the slot of the evicted texture. + */ +static texcache_entry_index texcache_evict( void ) +{ + /* Full table scan - take over the entry with the lowest lru value */ + texcache_entry_index slot = 0; + int lru_value = texcache_active_list[0].lru_count; + int i; + for( i=1; i>= 1; + intFormat = GL_INTENSITY4; + format = GL_COLOR_INDEX; + type = GL_UNSIGNED_BYTE; + bpp = 0; + break; + case PVR2_TEX_FORMAT_IDX8: + intFormat = GL_INTENSITY8; + format = GL_COLOR_INDEX; + type = GL_UNSIGNED_BYTE; + bpp = 1; + break; + } + + unsigned char data[bytes]; + /* load data from image, detwiddling/uncompressing as required */ + if( PVR2_TEX_IS_COMPRESSED(mode) ) { + ERROR( "VQ Compression not supported" ); + } else { + pvr2_vram64_read( &data, texture_addr, bytes ); + if( PVR2_TEX_IS_TWIDDLED(mode) ) { + /* Untwiddle */ + } + } + /* Pass to GL */ + glTexImage2D( GL_TEXTURE_2D, 0, intFormat, width, height, 0, format, type, + data ); +} + +/** + * Return a texture ID for the texture specified at the supplied address + * and given parameters (the same sequence of bytes could in theory have + * multiple interpretations). We use the texture address as the primary + * index, but allow for multiple instances at each address. The texture + * will be bound to the GL_TEXTURE_2D target before being returned. + * + * If the texture has already been bound, return the ID to which it was + * bound. Otherwise obtain an unused texture ID and set it up appropriately. + */ +GLuint texcache_get_texture( uint32_t texture_addr, int width, int height, + int mode ) +{ + uint32_t texture_page = texture_addr >> 12; + texcache_entry_index idx = texcache_page_lookup[texture_page]; + while( idx != EMPTY_ENTRY ) { + texcache_entry_t entry = &texcache_active_list[idx]; + if( entry->texture_addr == texture_addr && + entry->mode == mode && + entry->width == width && + entry->height == height ) { + entry->lru_count = texcache_ref_counter++; + glBindTexture( GL_TEXTURE_2D, entry->texture_id ); + return entry->texture_id; + } + idx = entry->next; + } + + /* Not found - check the free list */ + int slot = 0; + + if( texcache_free_ptr < MAX_TEXTURES ) { + slot = texcache_free_list[texcache_free_ptr++]; + } else { + slot = texcache_evict(); + } + + /* Construct new entry */ + texcache_active_list[slot].texture_addr = texture_addr; + texcache_active_list[slot].width = width; + texcache_active_list[slot].height = height; + texcache_active_list[slot].mode = mode; + texcache_active_list[slot].lru_count = texcache_ref_counter++; + + /* Add entry to the lookup table */ + texcache_active_list[slot].next = texcache_page_lookup[texture_page]; + texcache_page_lookup[texture_page] = slot; + + /* Construct the GL texture */ + GLuint texid = texcache_free_list[texcache_free_ptr++]; + glBindTexture( GL_TEXTURE_2D, texid ); + texcache_load_texture( texture_addr, width, height, mode ); + + return texcache_active_list[slot].texture_id; +} --- a/src/sh4/sh4mem.c Mon Mar 13 12:38:39 2006 +0000 +++ b/src/sh4/sh4mem.c Mon Mar 13 12:39:07 2006 +0000 @@ -1,5 +1,5 @@ /** - * $Id: sh4mem.c,v 1.7 2006-02-15 13:11:50 nkeynes Exp $ + * $Id: sh4mem.c,v 1.8 2006-03-13 12:39:07 nkeynes Exp $ * sh4mem.c is responsible for the SH4's access to memory (including memory * mapped I/O), using the page maps created in mem.c * @@ -315,40 +315,29 @@ * into the same memory black */ void mem_copy_from_sh4( char *dest, uint32_t srcaddr, size_t count ) { - char *src = mem_get_region(srcaddr); - memcpy( dest, src, count ); + if( srcaddr >= 0x04000000 && srcaddr < 0x05000000 ) { + pvr2_vram64_read( dest, srcaddr, count ); + } else { + char *src = mem_get_region(srcaddr); + if( src == NULL ) { + ERROR( "Attempted block read from unknown address %08X", srcaddr ); + } else { + memcpy( dest, src, count ); + } + } } void mem_copy_to_sh4( uint32_t destaddr, char *src, size_t count ) { if( destaddr >= 0x10000000 && destaddr < 0x20000000 ) { pvr2_ta_write( src, count ); - } else if( destaddr >= 04000000 && destaddr < 0x5000000 ) { - /* 64-bit video write. Oh. Yuck */ - uint32_t *dest32[2]; - uint32_t *src32 = (uint32_t *)src; - int flag = 0; - if( destaddr & 0x03 != 0 ) { - } - dest32[0] = (uint32_t *)mem_get_region(TRANSLATE_VIDEO_64BIT_ADDRESS(destaddr)); - dest32[1] = (uint32_t *)mem_get_region(TRANSLATE_VIDEO_64BIT_ADDRESS(destaddr+4)); - while( count >= 4 ) { - *dest32[flag]++ = *src32++; - flag = !flag; - count -=4; - } - if( count != 0 ) { - src = (char *)src32; - char *dest = dest32[flag]; - do { - *dest++ = *src++; - count--; - } while( count > 0 ); - } + } else if( destaddr >= 0x04000000 && destaddr < 0x05000000 ) { + pvr2_vram64_write( destaddr, src, count ); } else { char *dest = mem_get_region(destaddr); if( dest == NULL ) - ERROR( "Attempted block write to undefined region %08X", destaddr ); - else + ERROR( "Attempted block write to unknown address %08X", destaddr ); + else { memcpy( dest, src, count ); + } } } --- a/src/video.h Mon Mar 13 12:38:39 2006 +0000 +++ b/src/video.h Mon Mar 13 12:39:07 2006 +0000 @@ -1,5 +1,5 @@ /** - * $Id: video.h,v 1.4 2006-02-05 04:05:27 nkeynes Exp $ + * $Id: video.h,v 1.5 2006-03-13 12:39:03 nkeynes Exp $ * * The PC side of the video support (responsible for actually displaying / * rendering frames) @@ -27,10 +27,18 @@ extern "C" { #endif -#define COLFMT_RGB15 0x00000000 -#define COLFMT_RGB16 0x00000004 -#define COLFMT_RGB24 0x00000008 -#define COLFMT_RGB32 0x0000000C +/** + * Supported colour formats. Note that ARGB4444 is only ever used for texture + * rendering (it's not valid for display purposes). + */ +#define COLFMT_RGB565 1 +#define COLFMT_RGB888 4 +#define COLFMT_ARGB1555 0 +#define COLFMT_ARGB8888 5 +#define COLFMT_ARGB4444 2 +#define COLFMT_YUV422 3 /* 8-bit YUV (texture source only) */ +#define COLFMT_INDEX4 6 /* 4 bit indexed colour (texture source only) */ +#define COLFMT_INDEX8 7 /* 8-bit indexed colour (texture source only) */ typedef struct video_buffer { uint32_t hres; @@ -40,15 +48,69 @@ char *data; } *video_buffer_t; +/** + * Core video driver - expected to directly support an OpenGL context + */ typedef struct video_driver { char *name; - gboolean (*set_output_format)( uint32_t hres, uint32_t vres, - int colour_fmt ); + /** + * Initialize the driver. This is called only once at startup time, and + * is guaranteed to be called before any other methods. + * @return TRUE if the driver was successfully initialized, otherwise + * FALSE. + */ + gboolean (*init_driver)(void); + + /** + * Cleanly shutdown the driver. Normally only called at system shutdown + * time. + */ + void (*shutdown_driver)(void); + + /** + * Set the current display format to the specified values. This is + * called immediately prior to any display frame call where the + * parameters have changed from the previous frame + */ + gboolean (*set_display_format)( uint32_t hres, uint32_t vres, + int colour_fmt ); + + /** + * Set the current rendering format to the specified values. This is + * called immediately prior to starting rendering of a frame where the + * parameters have changed from the previous frame. Note that the driver + * is not required to precisely support the requested colour format. + * + * This method is also responsible for setting up an appropriate GL + * context for the main engine to render into. + * + * @param hres The horizontal resolution (ie 640) + * @param vres The vertical resolution (ie 480) + * @param colour_fmt The colour format of the buffer (ie COLFMT_ARGB4444) + * @param texture Flag indicating that the frame being rendered is a + * texture, rather than a display frame. + */ + gboolean (*set_render_format)( uint32_t hres, uint32_t vres, + int colour_fmt, gboolean texture ); + /** + * Display a single frame using the supplied pixmap data. Is assumed to + * invalidate the current GL front buffer (but not the back buffer). + */ gboolean (*display_frame)( video_buffer_t buffer ); + + /** + * Display a single blanked frame using a fixed colour for the + * entire frame (specified in RGB888 format). Is assumed to invalidate + * the current GL front buffer (but not the back buffer). + */ gboolean (*display_blank_frame)( uint32_t rgb ); + + /** + * Promote the current render back buffer to the front buffer + */ + void (*display_back_buffer)( void ); } *video_driver_t; - void video_open( void ); void video_update_frame( void ); void video_update_size( int, int, int );