mirror of
https://github.com/bsnes-emu/bsnes.git
synced 2025-08-21 03:01:24 +02:00
Update to v095r03 release and icarus 20151107.
byuu says: Note: you will need the new icarus (and please use the "no manifest" system) to run GBA games with this WIP. Changelog: - fixed caching of r(d) to pass armwrestler tests [Jonas Quinn] - DMA to/from GBA BIOS should fail [Cydrak] - fixed sign-extend and rotate on ldrs instructions [Cydrak] - fixed 8-bit SRAM reading/writing [byuu] - refactored GBA/cartridge - cartridge/rom,ram.type is now cartridge/mrom,sram,eeprom,flash - things won't crash horribly if you specify a RAM size larger than the largest legal size in the manifest - specialized MROM / SRAM classes replace all the shared read/write functions that didn't work right anyway - there's a new ruby/video.glx2 driver, which is not enabled by default - use this if you are running Linux/BSD, but don't have OpenGL 3.2 yet - I'm not going to support OpenGL2 on Windows/OS X, because these OSes don't ship ancient video card drivers - probably more. What am I, clairvoyant? :P For endrift's tests, this gets us to 1348/1552 memory and 1016/1260 timing. Overall, this puts us back in second place. Only no$ is ahead on memory, but bgba is even more ahead on timing.
This commit is contained in:
@@ -43,6 +43,10 @@ using namespace ruby;
|
||||
#include <ruby/video/glx.cpp>
|
||||
#endif
|
||||
|
||||
#if defined(VIDEO_GLX2)
|
||||
#include <ruby/video/glx2.cpp>
|
||||
#endif
|
||||
|
||||
#if defined(VIDEO_SDL)
|
||||
#include <ruby/video/sdl.cpp>
|
||||
#endif
|
||||
@@ -93,6 +97,10 @@ auto Video::create(const string& driver) -> Video* {
|
||||
if(driver == "OpenGL") return new VideoGLX;
|
||||
#endif
|
||||
|
||||
#if defined(VIDEO_GLX2)
|
||||
if(driver == "OpenGL2") return new VideoGLX2;
|
||||
#endif
|
||||
|
||||
#if defined(VIDEO_SDL)
|
||||
if(driver == "SDL") return new VideoSDL;
|
||||
#endif
|
||||
@@ -125,6 +133,8 @@ auto Video::optimalDriver() -> string {
|
||||
return "OpenGL";
|
||||
#elif defined(VIDEO_GLX)
|
||||
return "OpenGL";
|
||||
#elif defined(VIDEO_GLX2)
|
||||
return "OpenGL2";
|
||||
#elif defined(VIDEO_XV)
|
||||
return "X-Video";
|
||||
#elif defined(VIDEO_XSHM)
|
||||
@@ -153,6 +163,8 @@ auto Video::safestDriver() -> string {
|
||||
return "SDL";
|
||||
#elif defined(VIDEO_XV)
|
||||
return "X-Video";
|
||||
#elif defined(VIDEO_GLX2)
|
||||
return "OpenGL2";
|
||||
#elif defined(VIDEO_GLX)
|
||||
return "OpenGL";
|
||||
#else
|
||||
@@ -187,6 +199,10 @@ auto Video::availableDrivers() -> lstring {
|
||||
"OpenGL",
|
||||
#endif
|
||||
|
||||
#if defined(VIDEO_GLX2)
|
||||
"OpenGL2",
|
||||
#endif
|
||||
|
||||
#if defined(VIDEO_XV)
|
||||
"X-Video",
|
||||
#endif
|
||||
|
245
ruby/video/glx2.cpp
Normal file
245
ruby/video/glx2.cpp
Normal file
@@ -0,0 +1,245 @@
|
||||
//Xorg/GLX OpenGL 2.0 driver
|
||||
|
||||
//note: this is a fallback driver for use when OpenGL 3.2 is not available.
|
||||
//see glx.cpp for comments on how this driver operates (they are very similar.)
|
||||
|
||||
struct VideoGLX2 : Video {
|
||||
~VideoGLX2() { term(); }
|
||||
|
||||
auto (*glXSwapInterval)(signed) -> signed = nullptr;
|
||||
Display* display = nullptr;
|
||||
signed screen = 0;
|
||||
Window xwindow = 0;
|
||||
Colormap colormap = 0;
|
||||
GLXContext glxcontext = nullptr;
|
||||
GLXWindow glxwindow = 0;
|
||||
|
||||
struct {
|
||||
Window handle = 0;
|
||||
bool synchronize = false;
|
||||
unsigned filter = 1; //linear
|
||||
|
||||
unsigned width = 256;
|
||||
unsigned height = 256;
|
||||
|
||||
bool isDoubleBuffered = false;
|
||||
bool isDirect = false;
|
||||
} settings;
|
||||
|
||||
auto cap(const string& name) -> bool {
|
||||
if(name == Video::Handle) return true;
|
||||
if(name == Video::Synchronize) return true;
|
||||
if(name == Video::Filter) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
auto get(const string& name) -> any {
|
||||
if(name == Video::Handle) return (uintptr_t)settings.handle;
|
||||
if(name == Video::Synchronize) return settings.synchronize;
|
||||
if(name == Video::Filter) return settings.filter;
|
||||
return {};
|
||||
}
|
||||
|
||||
auto set(const string& name, const any& value) -> bool {
|
||||
if(name == Video::Handle && value.is<uintptr_t>()) {
|
||||
settings.handle = value.get<uintptr_t>();
|
||||
return true;
|
||||
}
|
||||
|
||||
if(name == Video::Synchronize && value.is<bool>()) {
|
||||
if(settings.synchronize != value.get<bool>()) {
|
||||
settings.synchronize = value.get<bool>();
|
||||
if(glXSwapInterval) glXSwapInterval(settings.synchronize);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if(name == Video::Filter && value.is<unsigned>()) {
|
||||
settings.filter = value.get<unsigned>();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
auto lock(uint32_t*& data, unsigned& pitch, unsigned width, unsigned height) -> bool {
|
||||
if(width != settings.width || height != settings.height) resize(width, height);
|
||||
pitch = glwidth * sizeof(uint32_t);
|
||||
return data = glbuffer;
|
||||
}
|
||||
|
||||
auto unlock() -> void {
|
||||
}
|
||||
|
||||
auto clear() -> void {
|
||||
memory::fill(glbuffer, glwidth * glheight * sizeof(uint32_t));
|
||||
glClearColor(0.0, 0.0, 0.0, 1.0);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
glFlush();
|
||||
if(settings.isDoubleBuffered) glXSwapBuffers(display, glxwindow);
|
||||
}
|
||||
|
||||
auto refresh() -> void {
|
||||
XWindowAttributes parent, child;
|
||||
XGetWindowAttributes(display, settings.handle, &parent);
|
||||
XGetWindowAttributes(display, xwindow, &child);
|
||||
if(child.width != parent.width || child.height != parent.height) {
|
||||
XResizeWindow(display, xwindow, parent.width, parent.height);
|
||||
}
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, settings.filter ? GL_LINEAR : GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, settings.filter ? GL_LINEAR : GL_NEAREST);
|
||||
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
glOrtho(0, parent.width, 0, parent.height, -1.0, 1.0);
|
||||
glViewport(0, 0, parent.width, parent.height);
|
||||
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, glwidth);
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, settings.width, settings.height,
|
||||
GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, glbuffer);
|
||||
|
||||
double w = (double)settings.width / (double)glwidth;
|
||||
double h = (double)settings.height / (double)glheight;
|
||||
signed u = parent.width;
|
||||
signed v = parent.height;
|
||||
|
||||
glBegin(GL_TRIANGLE_STRIP);
|
||||
glTexCoord2f(0, 0); glVertex3i(0, v, 0);
|
||||
glTexCoord2f(w, 0); glVertex3i(u, v, 0);
|
||||
glTexCoord2f(0, h); glVertex3i(0, 0, 0);
|
||||
glTexCoord2f(w, h); glVertex3i(u, 0, 0);
|
||||
glEnd();
|
||||
glFlush();
|
||||
|
||||
if(settings.isDoubleBuffered) glXSwapBuffers(display, glxwindow);
|
||||
}
|
||||
|
||||
auto init() -> bool {
|
||||
display = XOpenDisplay(0);
|
||||
screen = DefaultScreen(display);
|
||||
|
||||
signed versionMajor = 0, versionMinor = 0;
|
||||
glXQueryVersion(display, &versionMajor, &versionMinor);
|
||||
if(versionMajor < 1 || (versionMajor == 1 && versionMinor < 2)) return false;
|
||||
|
||||
XWindowAttributes windowAttributes;
|
||||
XGetWindowAttributes(display, settings.handle, &windowAttributes);
|
||||
|
||||
signed attributeList[] = {
|
||||
GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
|
||||
GLX_RENDER_TYPE, GLX_RGBA_BIT,
|
||||
GLX_DOUBLEBUFFER, True,
|
||||
GLX_RED_SIZE, 8,
|
||||
GLX_GREEN_SIZE, 8,
|
||||
GLX_BLUE_SIZE, 8,
|
||||
None
|
||||
};
|
||||
|
||||
signed fbCount = 0;
|
||||
auto fbConfig = glXChooseFBConfig(display, screen, attributeList, &fbCount);
|
||||
if(fbCount == 0) return false;
|
||||
|
||||
auto vi = glXGetVisualFromFBConfig(display, fbConfig[0]);
|
||||
colormap = XCreateColormap(display, RootWindow(display, vi->screen), vi->visual, AllocNone);
|
||||
XSetWindowAttributes attributes;
|
||||
attributes.colormap = colormap;
|
||||
attributes.border_pixel = 0;
|
||||
xwindow = XCreateWindow(display, settings.handle, 0, 0, windowAttributes.width, windowAttributes.height,
|
||||
0, vi->depth, InputOutput, vi->visual, CWColormap | CWBorderPixel, &attributes);
|
||||
XSetWindowBackground(display, xwindow, 0);
|
||||
XMapWindow(display, xwindow);
|
||||
XFlush(display);
|
||||
|
||||
while(XPending(display)) {
|
||||
XEvent event;
|
||||
XNextEvent(display, &event);
|
||||
}
|
||||
|
||||
glxcontext = glXCreateContext(display, vi, 0, GL_TRUE);
|
||||
glXMakeCurrent(display, glxwindow = xwindow, glxcontext);
|
||||
|
||||
glXSwapInterval = (signed (*)(signed))glGetProcAddress("glXSwapIntervalEXT");
|
||||
if(!glXSwapInterval) glXSwapInterval = (signed (*)(signed))glGetProcAddress("glXSwapIntervalMESA");
|
||||
if(!glXSwapInterval) glXSwapInterval = (signed (*)(signed))glGetProcAddress("glXSwapIntervalSGI");
|
||||
|
||||
if(glXSwapInterval) glXSwapInterval(settings.synchronize);
|
||||
|
||||
signed value = 0;
|
||||
glXGetConfig(display, vi, GLX_DOUBLEBUFFER, &value);
|
||||
settings.isDoubleBuffered = value;
|
||||
settings.isDirect = glXIsDirect(display, glxcontext);
|
||||
|
||||
glDisable(GL_ALPHA_TEST);
|
||||
glDisable(GL_BLEND);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glDisable(GL_POLYGON_SMOOTH);
|
||||
glDisable(GL_STENCIL_TEST);
|
||||
|
||||
glEnable(GL_DITHER);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
|
||||
resize(256, 256);
|
||||
return true;
|
||||
}
|
||||
|
||||
auto term() -> void {
|
||||
if(gltexture) {
|
||||
glDeleteTextures(1, &gltexture);
|
||||
gltexture = 0;
|
||||
}
|
||||
|
||||
if(glbuffer) {
|
||||
delete[] glbuffer;
|
||||
glbuffer = 0;
|
||||
}
|
||||
|
||||
glwidth = 0;
|
||||
glheight = 0;
|
||||
|
||||
if(glxcontext) {
|
||||
glXDestroyContext(display, glxcontext);
|
||||
glxcontext = nullptr;
|
||||
}
|
||||
|
||||
if(xwindow) {
|
||||
XUnmapWindow(display, xwindow);
|
||||
xwindow = 0;
|
||||
}
|
||||
|
||||
if(colormap) {
|
||||
XFreeColormap(display, colormap);
|
||||
colormap = 0;
|
||||
}
|
||||
|
||||
if(display) {
|
||||
XCloseDisplay(display);
|
||||
display = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
GLuint gltexture = 0;
|
||||
uint32_t* glbuffer = nullptr;
|
||||
unsigned glwidth = 0;
|
||||
unsigned glheight = 0;
|
||||
|
||||
auto resize(unsigned width, unsigned height) -> void {
|
||||
settings.width = width;
|
||||
settings.height = height;
|
||||
|
||||
if(gltexture == 0) glGenTextures(1, &gltexture);
|
||||
glwidth = max(glwidth, width);
|
||||
glheight = max(glheight, height);
|
||||
if(glbuffer) delete[] glbuffer;
|
||||
glbuffer = new uint32_t[glwidth * glheight]();
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, gltexture);
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, glwidth);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, glwidth, glheight, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, glbuffer);
|
||||
}
|
||||
};
|
Reference in New Issue
Block a user