The OpenGL ES Emulator allows you to emulate OpenGL ES code on your PC. It's actually very cool. You just need a fairly recent AMD video card on your machine.
The emulator is available at:
http://developer.amd.com/GPU/OpenGL/Pages/default.aspx
Current version is 1.4 (April '09)
Like all products however, there are bugs in this code. Lacking any other place to put them, I'm going to create a new thread for posting them. Hopefully someone at AMD will address them in the near future.
The emulator doesn't support PBuffers (see separate thread on this).
At the very least, it would be nice if this was mentioned in the Caveats section of the Developers Document.
This one is pretty nasty. Calling eglChooseConfig() a second time causes gl to start failing - it returns non-zero errors and even simple calls to glGenTextures() start functioning incorrectly. This is particularly annoying since for the life of me I can't figure out why eglCreateContext() should touch gl until I actually
gl Seems to come back to life after calling eglMakeCurrent(), but it's very iffy.
... Part 1 of 3 .....
#include "EGL/egl.h"
#include "GLES2/gl2.h"
#include "assert.h"
BOOL
InitializeEGL( )
{
EGLint numConfigs;
EGLint majorVersion;
EGLint minorVersion;
EGLDisplay m_eglDsp = EGL_NO_DISPLAY;
EGLConfig m_eglCfg = 0;
EGLContext m_eglCxt = EGL_NO_CONTEXT;
EGLSurface m_eglSurf = EGL_NO_SURFACE;
// Get Display
m_eglDsp = eglGetDisplay( EGL_DEFAULT_DISPLAY );
if ( m_eglDsp == EGL_NO_DISPLAY )
{
assert( 0 && "eglGetDisplay failed" );
return FALSE;
}
// Initialize EGL
if ( ! eglInitialize( m_eglDsp, &majorVersion, &minorVersion) )
{
assert( 0 && "eglInitialize failed" );
return FALSE;
}
// Get configs
if ( ! eglGetConfigs( m_eglDsp, NULL, 0, &numConfigs ) )
{
assert( 0 && "eglGetConfigs failed" );
return FALSE;
}
/// Build up a nice standard attribute list (RGBA8888)
EGLint CfgAttrList[] =
{
EGL_RED_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_BLUE_SIZE, 8,
EGL_ALPHA_SIZE, 0,
EGL_DEPTH_SIZE, 24,
EGL_STENCIL_SIZE, 0,
EGL_SAMPLES, 0,
EGL_NONE
};
// Choose config
if ( !eglChooseConfig(m_eglDsp, CfgAttrList, &m_eglCfg, 1, &numConfigs) )
{
assert( 0 && "eglChooseConfig failed" );
return FALSE;
}
// Create a GL context
EGLint ctxAttribList[] =
{
EGL_CONTEXT_CLIENT_VERSION, 2,
EGL_NONE
};
m_eglCxt = eglCreateContext( m_eglDsp, m_eglCfg, EGL_NO_CONTEXT, ctxAttribList );
if ( m_eglCxt == EGL_NO_CONTEXT )
{
int error = eglGetError();
assert( 0 && "eglCreateContext failed" );
return FALSE;
}
// because we don't hav a surface to draw into yet, and hence can't call eglMakeCurrent()
// even at this point any gl Command will violently assert/throw (including glGetError();
{
HANDLE hWnd = CreateHWnd2(400, 300, "TestWnd"); // CreateHWnd2 code below…
EGLConfig config = m_eglCfg;
int WSAttrList[] =
{
EGL_NONE
};
EGLSurface hSurf;
hSurf = eglCreateWindowSurface(m_eglDsp, m_eglCfg, (EGLNativeWindowType) hWnd, WSAttrList);
// finally, make our framebuffer surface current.
if ( ! eglMakeCurrent( m_eglDsp, hSurf, hSurf, m_eglCxt ) )
{
MessageBox( NULL, "Failed to make win surface current.", "ERROR", MB_OK | MB_ICONSTOP );
return false;
}
// at this point, everything is running ok
GLuint hTexture2;
int err;
err = eglGetError(); // egl Succeeds (returns 0x3000, which is Success)
err = glGetError(); // gl Succeeds (returns 0x0, which is GL_NO_ERROR)
glGenTextures(1, &hTexture2); // and this works (hTexture2 is !0)
// now here comes the error
.... see next article in thread ...
--- Continuation of code from previous message
// now here comes the error
// create a new config in the same thread, and choose it
EGLConfig config2;
const EGLint configAttrs[] =
{
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
EGL_SURFACE_TYPE, EGL_WINDOW_BIT, // | EGL_PIXMAP_BIT | EGL_PBUFFER_BIT, // EGL_MULTISAMPLE_RESOLVE_BOX_BIT | EGL_SWAP_BEHAVIOR_PRESERVED_BIT
EGL_RED_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_BLUE_SIZE, 8,
EGL_ALPHA_SIZE, 8,
EGL_DEPTH_SIZE, 24, // note - changing these to match above config still fails
EGL_STENCIL_SIZE, 8,
EGL_SAMPLES, 0, // BUG: fails in emulator if > 0
EGL_NONE
};
int numConfigs;
if(!eglChooseConfig (m_eglDsp, configAttrs, &config2, 1, &numConfigs))
{
assert(false && "eglChooseConfig Failed");
return false;
err = eglGetError(); // egl Succeeds (returns 0x3000, which is Success)
err = glGetError(); // but gl fails (returns 0x502, which is InvalidValue) <--- BUG ALERT!
glGenTextures(1, &hTexture2); // and hTexture2 is unchanged! <--- SAME BUG
err = glGetError(); // and gl still fails (returns 0x502, which is InvalidValue)
// now lets go create a context about this config
EGLint ctxAttribList[] =
{
EGL_CONTEXT_CLIENT_VERSION, 2,
EGL_NONE
};
EGLContext eglCxt = eglCreateContext( m_eglDsp, config, EGL_NO_CONTEXT, ctxAttribList );
err = eglGetError(); // egl Succeeds (returns 0x3000, which is Success)
err = glGetError(); // but gl fails (returns 0x502, which is InvalidValue) <--- STILL BUGGY
glGenTextures(1, &hTexture2); // and this again fails (hTexture2 still unchanged)
err = glGetError(); // and gl still fails (returns 0x502, which is InvalidValue)
// finally, let's make this context current
if ( ! eglMakeCurrent( m_eglDsp, hSurf, hSurf, eglCxt ) )
{
MessageBox( NULL, "Failed to make framebuffer surface current.", "ERROR", MB_OK | MB_ICONSTOP );
return false;
}
err = eglGetError(); // egl Succeeds (returns 0x3000, which is Success)
err = glGetError(); // this time gl returns 0x501 (GL_INVALID_VALUE).
glGenTextures(1, &hTexture2); // and hTexture stil hasn't changed <---- ANOTHER BUG!
err = glGetError(); // Finally gl returns 0x0 (Success).
glGenTextures(1, &hTexture2); // Finally, we get a new value for hTexture2
err = glGetError(); // this time gl returns 0x501 (GL_INVALID_VALUE).
err = glGetError();
}
return TRUE;
}
.... Part 3, creating the silly hWnd.
LRESULT CALLBACK WndProc2( HWND hWnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam)
{
// switch ( uMsg ) // Check For Windows Messages
// {
// }
// Pass All Unhandled Messages To DefWindowProc
return DefWindowProc( hWnd, uMsg, wParam, lParam );
}
HWND CreateHWnd2( int width, int height, char *name )
{
WNDCLASS wc; // Windows Class Structure
HWND hWnd;
HINSTANCE hInstance;
hInstance = GetModuleHandle( NULL ); // Grab An Instance For Our Window
wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; // Redraw On Size, And Own DC For Window.
wc.lpfnWndProc = WNDPROC( WndProc2 ); // WndProc Handles Messages
wc.cbClsExtra = 0; // No Extra Window Data
wc.cbWndExtra = 0; // No Extra Window Data
wc.hInstance = hInstance; // Set The Instance
wc.hIcon = LoadIcon( NULL, IDI_WINLOGO ); // Load The Default Icon
wc.hCursor = LoadCursor( NULL, IDC_ARROW ); // Load The Arrow Pointer
wc.hbrBackground = NULL; // No Background Required For GL
wc.lpszMenuName = NULL; // We Don't Want A Menu
wc.lpszClassName = "PsuedoGL2"; // Set The Class Name
if ( ! RegisterClass( &wc ) ) // Attempt To Register The Window Class
{
MessageBox( NULL, "Failed To Register The Window Class.", "ERROR", MB_OK | MB_ICONEXCLAMATION );
return 0;
}
if ( ! ( hWnd=CreateWindowEx(
WS_EX_APPWINDOW | WS_EX_WINDOWEDGE, // Extended Style For The Window
"PsuedoGL2", // Class Name
name, // Window Title
WS_OVERLAPPEDWINDOW | // Defined Window Style
WS_CLIPSIBLINGS | // Required Window Style
WS_CLIPCHILDREN, // Required Window Style
0, 0, // Window Position
width, // Window Width
height, // Window Height
NULL, // No Parent Window
NULL, // No Menu
hInstance, // Instance
NULL ) ) ) // Dont Pass Anything To WM_CREATE
{
return 0;
}
return hWnd;
}
According to someone at AMD, the emulator only supports one configuration at any one time
The egl spec (Section 3.7 below) does say an implementation may limit support to just one Context
Contexts aren't the same and Configs, so I think this lack of support is an emulator bug.