JayFoxRox
Active Member
This is a POC (Proof of concept) only, don't expect anything too cool for now. A download will be made available once I cleaned up the source
Hey, I just wanted to tell you about one of my current side projects, called pandora-emulate.
Basicly, its a wrapper around qemu including:
- A launcher (called "pandora-emulate")
- A host library (called "preload_host.so")
- A guest library (called "preload_guest.so")
- and tons of libraries for any API that is supposed to be forwarded to the host ("host_libX11.so" / "libX11.so", ...)
It works by creating a local pipe in the launcher, then forwarding the pipe descriptors to the guest which then forwards any call to the host system. Additionally realtime dynamic linking was improved (but not fully working yet) by hooking all calls to dlopen and replacing the mode with RTLD_GLOBAL (as its the only one which works in qemu).
I tried to make forwarding as easy as possible and its done using macros. Following is the forwarder for GLES2 for example:
Features include:
- Doesn't touch qemu source-code at all (only library preloading is done)
- GLES2 should be fully supported, some bugs fixed
- Can work with applications depending X
- Can work with applications which are not using X, by creating an extra output when EGL doesn't specify an X window
- Its quite fast for a first version. It runs all GLES samples with at least 30FPS on my machine (ok... its an i7, GTX265 )
- Most smaller things I tried, including my PSP Emulator (the version I send to Pickle in October which ran on a real Pandora before!), work fine
- Input is working by re-creating the original Pandora kernel interface (button mapping is outdated tho, that stuff is changing way too often)
Known problems (Highest priority first):
- Unstable, I still can't getmupen64 gles2n64 to work. Outputs garbage right now
- Probably not working with threads
- Callbacks and variable number of arguments don't work yet (This could be a huge problem for SDL)
- dlmopen is used to fix dlopen (as dlopen is commonly used), which means dlmopen itself doesn't work anymore
- exec() will start on the host system (just like in qemu), making it impossible to use launchers
- Depends heavily on your system and linux installation
- Only 32 bit version was tested and developed because it depends on the PVR GLES wrapper (tho, adding 64 bit support without GLES should be easy)
- Still too slow to be really useful
- No audio libraries yet
- Missing support for lots of other libraries including GTK etc.
- No Win32 support yet (Planned using cygwin, but I haven't used Windows/cygwin in ages)
- Depends on qemu-arm which might have bugs, or not enough compatibility to port it to Win32
And last but not least some screens I took while testing (People on IRC saw them before, don't expect anything new )
(I think its worth to note that the Pandora-PSP output above is wrong and it worked fine on PC when I send Pickle the test version (who reported the problem so I could fix it) - I could have fixed the bug before already if I would have had this emulator)
Using the "emulator" is really simple:
(I'd like to thank rapidpoobear for making a small script to make it easier to wrap EGL and GLES2 (even tho I only used it for EGL))
Hey, I just wanted to tell you about one of my current side projects, called pandora-emulate.
Basicly, its a wrapper around qemu including:
- A launcher (called "pandora-emulate")
- A host library (called "preload_host.so")
- A guest library (called "preload_guest.so")
- and tons of libraries for any API that is supposed to be forwarded to the host ("host_libX11.so" / "libX11.so", ...)
It works by creating a local pipe in the launcher, then forwarding the pipe descriptors to the guest which then forwards any call to the host system. Additionally realtime dynamic linking was improved (but not fully working yet) by hooking all calls to dlopen and replacing the mode with RTLD_GLOBAL (as its the only one which works in qemu).
I tried to make forwarding as easy as possible and its done using macros. Following is the forwarder for GLES2 for example:
Code:
#include <GLES2/gl2.h>
#include "../breakout.h"
BREAKOUT_HOST_SUB(1,glActiveTexture,GLenum)
BREAKOUT_HOST_SUB(2,glAttachShader,GLuint,GLuint)
BREAKOUT_HOST_SUB(3,glBindAttribLocation,GLuint,GLuint,const char*)
BREAKOUT_HOST_SUB(2,glBindBuffer,GLenum,GLuint)
BREAKOUT_HOST_SUB(2,glBindFramebuffer,GLenum,GLuint)
BREAKOUT_HOST_SUB(2,glBindRenderbuffer,GLenum,GLuint)
BREAKOUT_HOST_SUB(2,glBindTexture,GLenum,GLuint)
BREAKOUT_HOST_SUB(4,glBlendColor,GLclampf,GLclampf,GLclampf,GLclampf)
BREAKOUT_HOST_SUB(1,glBlendEquation,GLenum )
BREAKOUT_HOST_SUB(2,glBlendEquationSeparate,GLenum,GLenum)
BREAKOUT_HOST_SUB(2,glBlendFunc,GLenum,GLenum)
BREAKOUT_HOST_SUB(4,glBlendFuncSeparate,GLenum,GLenum,GLenum,GLenum)
BREAKOUT_HOST_SUB(4,glBufferData,GLenum,GLsizei,const void*,GLenum)
BREAKOUT_HOST_SUB(4,glBufferSubData,GLenum,GLint,GLsizei,const void*)
BREAKOUT_HOST_FUNCTION(1,GLenum,glCheckFramebufferStatus,GLenum)
BREAKOUT_HOST_SUB(1,glClear,GLbitfield)
BREAKOUT_HOST_SUB(4,glClearColor,GLclampf,GLclampf,GLclampf,GLclampf)
BREAKOUT_HOST_SUB(1,glClearDepthf,GLclampf)
BREAKOUT_HOST_SUB(1,glClearStencil,GLint)
BREAKOUT_HOST_SUB(4,glColorMask,GLboolean,GLboolean,GLboolean,GLboolean)
BREAKOUT_HOST_SUB(1,glCompileShader,GLuint)
BREAKOUT_HOST_SUB(8,glCompressedTexImage2D,GLenum,GLint,GLenum,GLsizei,GLsizei,GLint,GLsizei,const void*)
BREAKOUT_HOST_SUB(9,glCompressedTexSubImage2D,GLenum,GLint,GLint,GLint,GLsizei,GLsizei,GLenum,GLsizei,const void*)
BREAKOUT_HOST_SUB(8,glCopyTexImage2D,GLenum,GLint,GLenum,GLint,GLint,GLsizei,GLsizei,GLint)
BREAKOUT_HOST_SUB(8,glCopyTexSubImage2D,GLenum,GLint,GLint,GLint,GLint,GLint,GLsizei,GLsizei)
BREAKOUT_HOST_FUNCTION(0,GLuint,glCreateProgram)
BREAKOUT_HOST_FUNCTION(1,GLuint,glCreateShader,GLenum)
BREAKOUT_HOST_SUB(1,glCullFace,GLenum)
BREAKOUT_HOST_SUB(2,glDeleteBuffers,GLsizei,const GLuint*)
BREAKOUT_HOST_SUB(2,glDeleteFramebuffers,GLsizei,const GLuint*)
BREAKOUT_HOST_SUB(2,glDeleteTextures,GLsizei,const GLuint*)
BREAKOUT_HOST_SUB(1,glDeleteProgram,GLuint)
BREAKOUT_HOST_SUB(2,glDeleteRenderbuffers,GLsizei,const GLuint*)
BREAKOUT_HOST_SUB(1,glDeleteShader,GLuint)
BREAKOUT_HOST_SUB(2,glDetachShader,GLuint,GLuint)
BREAKOUT_HOST_SUB(1,glDepthFunc,GLenum)
BREAKOUT_HOST_SUB(1,glDepthMask,GLboolean)
BREAKOUT_HOST_SUB(2,glDepthRangef,GLclampf,GLclampf)
BREAKOUT_HOST_SUB(1,glDisable,GLenum)
BREAKOUT_HOST_SUB(1,glDisableVertexAttribArray,GLuint)
BREAKOUT_HOST_SUB(3,glDrawArrays,GLenum,GLint,GLsizei)
BREAKOUT_HOST_SUB(4,glDrawElements,GLenum,GLsizei,GLenum,const void*)
BREAKOUT_HOST_SUB(1,glEnable,GLenum)
BREAKOUT_HOST_SUB(1,glEnableVertexAttribArray,GLuint)
BREAKOUT_HOST_SUB(0,glFinish)
BREAKOUT_HOST_SUB(0,glFlush)
BREAKOUT_HOST_SUB(4,glFramebufferRenderbuffer,GLenum,GLenum,GLenum,GLuint)
BREAKOUT_HOST_SUB(5,glFramebufferTexture2D,GLenum,GLenum,GLenum,GLuint,GLint)
BREAKOUT_HOST_SUB(1,glFrontFace,GLenum)
BREAKOUT_HOST_SUB(2,glGenBuffers,GLsizei,GLuint*)
BREAKOUT_HOST_SUB(1,glGenerateMipmap,GLenum)
BREAKOUT_HOST_SUB(2,glGenFramebuffers,GLsizei,GLuint*)
BREAKOUT_HOST_SUB(2,glGenRenderbuffers,GLsizei,GLuint*)
BREAKOUT_HOST_SUB(2,glGenTextures,GLsizei,GLuint*)
BREAKOUT_HOST_SUB(7,glGetActiveAttrib,GLuint,GLuint,GLsizei,GLsizei*,GLint*,GLenum*,char*)
BREAKOUT_HOST_SUB(7,glGetActiveUniform,GLuint,GLuint,GLsizei,GLsizei*,GLint*,GLenum*,char*)
BREAKOUT_HOST_SUB(4,glGetAttachedShaders,GLuint,GLsizei,GLsizei*,GLuint*)
BREAKOUT_HOST_FUNCTION(2,int,glGetAttribLocation,GLuint,const char*)
BREAKOUT_HOST_SUB(2,glGetBooleanv,GLenum,GLboolean*)
BREAKOUT_HOST_SUB(3,glGetBufferParameteriv,GLenum,GLenum,GLint*)
BREAKOUT_HOST_FUNCTION(0,GLenum,glGetError)
BREAKOUT_HOST_SUB(2,glGetFloatv,GLenum,GLfloat*)
BREAKOUT_HOST_SUB(4,glGetFramebufferAttachmentParameteriv,GLenum,GLenum,GLenum,GLint*)
BREAKOUT_HOST_SUB(2,glGetIntegerv,GLenum,GLint*)
BREAKOUT_HOST_SUB(3,glGetProgramiv,GLuint,GLenum,GLint*)
BREAKOUT_HOST_SUB(4,glGetProgramInfoLog,GLuint,GLsizei,GLsizei*,char* )
BREAKOUT_HOST_SUB(3,glGetRenderbufferParameteriv,GLenum,GLenum,GLint*)
BREAKOUT_HOST_SUB(3,glGetShaderiv,GLuint,GLenum,GLint*)
BREAKOUT_HOST_SUB(4,glGetShaderInfoLog,GLuint,GLsizei,GLsizei*,char* )
BREAKOUT_HOST_SUB(4,glGetShaderPrecisionFormat,GLenum,GLenum,GLint*,GLint*)
BREAKOUT_HOST_SUB(4,glGetShaderSource,GLuint,GLsizei,GLsizei*,char* )
BREAKOUT_HOST_FUNCTION(1,const GLubyte*,glGetString,GLenum)
BREAKOUT_HOST_SUB(3,glGetTexParameterfv,GLenum,GLenum,GLfloat*)
BREAKOUT_HOST_SUB(3,glGetTexParameteriv,GLenum,GLenum,GLint*)
BREAKOUT_HOST_SUB(3,glGetUniformfv,GLuint,GLint,GLfloat*)
BREAKOUT_HOST_SUB(3,glGetUniformiv,GLuint,GLint,GLint*)
BREAKOUT_HOST_FUNCTION(2,int,glGetUniformLocation,GLuint,const char*)
BREAKOUT_HOST_SUB(3,glGetVertexAttribfv,GLuint,GLenum,GLfloat*)
BREAKOUT_HOST_SUB(3,glGetVertexAttribiv,GLuint,GLenum,GLint*)
BREAKOUT_HOST_SUB(3,glGetVertexAttribPointerv,GLuint,GLenum,void**)
BREAKOUT_HOST_SUB(2,glHint,GLenum,GLenum)
BREAKOUT_HOST_FUNCTION(1,GLboolean,glIsBuffer,GLuint)
BREAKOUT_HOST_FUNCTION(1,GLboolean,glIsEnabled,GLenum)
BREAKOUT_HOST_FUNCTION(1,GLboolean,glIsFramebuffer,GLuint)
BREAKOUT_HOST_FUNCTION(1,GLboolean,glIsProgram,GLuint)
BREAKOUT_HOST_FUNCTION(1,GLboolean,glIsRenderbuffer,GLuint)
BREAKOUT_HOST_FUNCTION(1,GLboolean,glIsShader,GLuint)
BREAKOUT_HOST_FUNCTION(1,GLboolean,glIsTexture,GLuint)
BREAKOUT_HOST_SUB(1,glLineWidth,GLfloat)
BREAKOUT_HOST_SUB(1,glLinkProgram,GLuint)
BREAKOUT_HOST_SUB(2,glPixelStorei,GLenum,GLint)
BREAKOUT_HOST_SUB(2,glPolygonOffset,GLfloat,GLfloat)
BREAKOUT_HOST_SUB(7,glReadPixels,GLint,GLint,GLsizei,GLsizei,GLenum,GLenum,void*)
BREAKOUT_HOST_SUB(0,glReleaseShaderCompiler)
BREAKOUT_HOST_SUB(4,glRenderbufferStorage,GLenum,GLenum,GLsizei,GLsizei)
BREAKOUT_HOST_SUB(2,glSampleCoverage,GLclampf,GLboolean)
BREAKOUT_HOST_SUB(4,glScissor,GLint,GLint,GLsizei,GLsizei)
BREAKOUT_HOST_SUB(5,glShaderBinary,GLint,const GLuint*,GLenum,const void*,GLint)
BREAKOUT_HOST_SUB(4,glShaderSource,GLuint,GLsizei,const char**,const GLint*)
BREAKOUT_HOST_SUB(3,glStencilFunc,GLenum,GLint,GLuint)
BREAKOUT_HOST_SUB(4,glStencilFuncSeparate,GLenum,GLenum,GLint,GLuint)
BREAKOUT_HOST_SUB(1,glStencilMask,GLuint)
BREAKOUT_HOST_SUB(2,glStencilMaskSeparate,GLenum,GLuint)
BREAKOUT_HOST_SUB(3,glStencilOp,GLenum,GLenum,GLenum)
BREAKOUT_HOST_SUB(4,glStencilOpSeparate,GLenum,GLenum,GLenum,GLenum)
BREAKOUT_HOST_SUB(9,glTexImage2D,GLenum,GLint,GLenum,GLsizei,GLsizei,GLint,GLenum,GLenum,const void*)
BREAKOUT_HOST_SUB(3,glTexParameterf,GLenum,GLenum,GLfloat)
BREAKOUT_HOST_SUB(3,glTexParameterfv,GLenum,GLenum,const GLfloat*)
BREAKOUT_HOST_SUB(3,glTexParameteri,GLenum,GLenum,GLint)
BREAKOUT_HOST_SUB(3,glTexParameteriv,GLenum,GLenum,const GLint*)
BREAKOUT_HOST_SUB(9,glTexSubImage2D,GLenum,GLint,GLint,GLint,GLsizei,GLsizei,GLenum,GLenum,const void*)
BREAKOUT_HOST_SUB(2,glUniform1f,GLint,GLfloat)
BREAKOUT_HOST_SUB(3,glUniform1fv,GLint,GLsizei,const GLfloat*)
BREAKOUT_HOST_SUB(2,glUniform1i,GLint,GLint)
BREAKOUT_HOST_SUB(3,glUniform1iv,GLint,GLsizei,const GLint*)
BREAKOUT_HOST_SUB(3,glUniform2f,GLint,GLfloat,GLfloat)
BREAKOUT_HOST_SUB(3,glUniform2fv,GLint,GLsizei,const GLfloat*)
BREAKOUT_HOST_SUB(3,glUniform2i,GLint,GLint,GLint)
BREAKOUT_HOST_SUB(3,glUniform2iv,GLint,GLsizei,const GLint*)
BREAKOUT_HOST_SUB(4,glUniform3f,GLint,GLfloat,GLfloat,GLfloat)
BREAKOUT_HOST_SUB(3,glUniform3fv,GLint,GLsizei,const GLfloat*)
BREAKOUT_HOST_SUB(4,glUniform3i,GLint,GLint,GLint,GLint)
BREAKOUT_HOST_SUB(3,glUniform3iv,GLint,GLsizei,const GLint*)
BREAKOUT_HOST_SUB(5,glUniform4f,GLint,GLfloat,GLfloat,GLfloat,GLfloat)
BREAKOUT_HOST_SUB(3,glUniform4fv,GLint,GLsizei,const GLfloat*)
BREAKOUT_HOST_SUB(5,glUniform4i,GLint,GLint,GLint,GLint,GLint)
BREAKOUT_HOST_SUB(3,glUniform4iv,GLint,GLsizei,const GLint*)
BREAKOUT_HOST_SUB(4,glUniformMatrix2fv,GLint,GLsizei,GLboolean,const GLfloat*)
BREAKOUT_HOST_SUB(4,glUniformMatrix3fv,GLint,GLsizei,GLboolean,const GLfloat*)
BREAKOUT_HOST_SUB(4,glUniformMatrix4fv,GLint,GLsizei,GLboolean,const GLfloat*)
BREAKOUT_HOST_SUB(1,glUseProgram,GLuint)
BREAKOUT_HOST_SUB(1,glValidateProgram,GLuint)
BREAKOUT_HOST_SUB(2,glVertexAttrib1f,GLuint,GLfloat)
BREAKOUT_HOST_SUB(2,glVertexAttrib1fv,GLuint,const GLfloat*)
BREAKOUT_HOST_SUB(3,glVertexAttrib2f,GLuint,GLfloat,GLfloat)
BREAKOUT_HOST_SUB(2,glVertexAttrib2fv,GLuint,const GLfloat*)
BREAKOUT_HOST_SUB(4,glVertexAttrib3f,GLuint,GLfloat,GLfloat,GLfloat)
BREAKOUT_HOST_SUB(2,glVertexAttrib3fv,GLuint,const GLfloat*)
BREAKOUT_HOST_SUB(5,glVertexAttrib4f,GLuint,GLfloat,GLfloat,GLfloat,GLfloat)
BREAKOUT_HOST_SUB(2,glVertexAttrib4fv,GLuint,const GLfloat*)
BREAKOUT_HOST_SUB(6,glVertexAttribPointer,GLuint,GLint,GLenum,GLboolean,GLsizei,const void*)
BREAKOUT_HOST_SUB(4,glViewport,GLint,GLint,GLsizei,GLsizei)
Features include:
- Doesn't touch qemu source-code at all (only library preloading is done)
- GLES2 should be fully supported, some bugs fixed
- Can work with applications depending X
- Can work with applications which are not using X, by creating an extra output when EGL doesn't specify an X window
- Its quite fast for a first version. It runs all GLES samples with at least 30FPS on my machine (ok... its an i7, GTX265 )
- Most smaller things I tried, including my PSP Emulator (the version I send to Pickle in October which ran on a real Pandora before!), work fine
- Input is working by re-creating the original Pandora kernel interface (button mapping is outdated tho, that stuff is changing way too often)
Known problems (Highest priority first):
- Unstable, I still can't get
- Probably not working with threads
- Callbacks and variable number of arguments don't work yet (This could be a huge problem for SDL)
- dlmopen is used to fix dlopen (as dlopen is commonly used), which means dlmopen itself doesn't work anymore
- exec() will start on the host system (just like in qemu), making it impossible to use launchers
- Depends heavily on your system and linux installation
- Only 32 bit version was tested and developed because it depends on the PVR GLES wrapper (tho, adding 64 bit support without GLES should be easy)
- Still too slow to be really useful
- No audio libraries yet
- Missing support for lots of other libraries including GTK etc.
- No Win32 support yet (Planned using cygwin, but I haven't used Windows/cygwin in ages)
- Depends on qemu-arm which might have bugs, or not enough compatibility to port it to Win32
And last but not least some screens I took while testing (People on IRC saw them before, don't expect anything new )
(I think its worth to note that the Pandora-PSP output above is wrong and it worked fine on PC when I send Pickle the test version (who reported the problem so I could fix it) - I could have fixed the bug before already if I would have had this emulator)
Using the "emulator" is really simple:
Code:
pandora-emulate ./application.elf *parameters*
(I'd like to thank rapidpoobear for making a small script to make it easier to wrap EGL and GLES2 (even tho I only used it for EGL))