b=583838; add ANGLE/D3D WebGL support - part 2 - build EGL on windows and try to use it; r=bjacob

This commit is contained in:
Vladimir Vukicevic 2010-08-06 22:09:18 -07:00
parent 30c2b7b82c
commit c44e0d0074
8 changed files with 492 additions and 63 deletions

View File

@ -56,6 +56,8 @@
#include "GLContextProvider.h"
#include "prenv.h"
using namespace mozilla;
using namespace mozilla::gl;
@ -275,29 +277,77 @@ WebGLContext::SetDimensions(PRInt32 width, PRInt32 height)
format.depth = 16;
format.minDepth = 1;
gl = gl::GLContextProvider::CreateOffscreen(gfxIntSize(width, height), format);
#ifdef XP_WIN
// On Windows, we may have a choice of backends, including straight
// OpenGL, D3D through ANGLE via EGL, or straight EGL/GLES2.
// We don't differentiate the latter two yet, but we allow for
// a env var to try EGL first, instead of last.
bool preferEGL = PR_GetEnv("MOZ_WEBGL_PREFER_EGL") != nsnull;
// if we want EGL, try it first
if (!gl && preferEGL) {
gl = gl::GLContextProviderEGL::CreateOffscreen(gfxIntSize(width, height), format);
if (gl && !InitAndValidateGL()) {
gl = nsnull;
}
}
// if it failed, then try the default provider, whatever that is
if (!gl) {
gl = gl::GLContextProvider::CreateOffscreen(gfxIntSize(width, height), format);
if (gl && !InitAndValidateGL()) {
gl = nsnull;
}
}
// if that failed, and we weren't already preferring EGL, try it now.
if (!gl && !preferEGL) {
gl = gl::GLContextProviderEGL::CreateOffscreen(gfxIntSize(width, height), format);
if (gl && !InitAndValidateGL()) {
gl = nsnull;
}
}
#else
// other platforms just use whatever the default is
if (!gl) {
gl = gl::GLContextProvider::CreateOffscreen(gfxIntSize(width, height), format);
if (gl && !InitAndValidateGL()) {
gl = nsnull;
}
}
#endif
// last chance, try OSMesa
if (!gl) {
gl = gl::GLContextProviderOSMesa::CreateOffscreen(gfxIntSize(width, height), format);
if (gl) {
if (!InitAndValidateGL()) {
gl = nsnull;
} else {
// make sure we notify always in this case, because it's likely going to be
// painfully slow
LogMessage("WebGL: Using software rendering via OSMesa");
}
}
}
if (!gl) {
LogMessage("WebGL: Can't get a usable OpenGL context.");
return NS_ERROR_FAILURE;
}
printf_stderr ("--- WebGL context created: %p\n", gl.get());
#ifdef USE_GLES2
// On native GLES2, no need to validate, the compiler will do it
mShaderValidation = PR_FALSE;
#else
// Check the shader validator pref
nsCOMPtr<nsIPrefBranch> prefService = do_GetService(NS_PREFSERVICE_CONTRACTID);
NS_ENSURE_TRUE(prefService != nsnull, NS_ERROR_FAILURE);
if (gl->IsGLES2()) {
// On native GLES2, no need to validate, the compiler will do it
mShaderValidation = PR_FALSE;
} else {
// Otherwise, check the shader validator pref
nsCOMPtr<nsIPrefBranch> prefService = do_GetService(NS_PREFSERVICE_CONTRACTID);
NS_ENSURE_TRUE(prefService != nsnull, NS_ERROR_FAILURE);
prefService->GetBoolPref("webgl.shader_validator", &mShaderValidation);
#endif
if (!InitAndValidateGL()) {
gl = gl::GLContextProviderOSMesa::CreateOffscreen(gfxIntSize(width, height), format);
if (!InitAndValidateGL()) {
LogMessage("WebGL: Can't get a usable OpenGL context.");
return NS_ERROR_FAILURE;
}
LogMessage("WebGL: Using software rendering via OSMesa");
prefService->GetBoolPref("webgl.shader_validator", &mShaderValidation);
}
mWidth = width;

View File

@ -701,15 +701,9 @@ BasicCanvasLayer::Updated(const nsIntRect& aRect)
// For simplicity, we read the entire framebuffer for now -- in
// the future we should use mUpdatedRect, though with WebGL we don't
// have an easy way to generate one.
if (mGLContext->IsGLES2()) {
mGLContext->fReadPixels(0, 0, mBounds.width, mBounds.height,
LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE,
isurf->Data());
} else {
mGLContext->fReadPixels(0, 0, mBounds.width, mBounds.height,
LOCAL_GL_BGRA, LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV,
isurf->Data());
}
mGLContext->ReadPixelsIntoImageSurface(0, 0,
mBounds.width, mBounds.height,
isurf);
// Put back the previous framebuffer binding.
if (currentFramebuffer != mCanvasFramebuffer)

View File

@ -111,9 +111,15 @@ CanvasLayerD3D9::Updated(const nsIntRect& aRect)
// For simplicity, we read the entire framebuffer for now -- in
// the future we should use aRect, though with WebGL we don't
// have an easy way to generate one.
mGLContext->fReadPixels(0, 0, mBounds.width, mBounds.height,
LOCAL_GL_BGRA, LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV,
destination);
nsRefPtr<gfxImageSurface> tmpSurface =
new gfxImageSurface(destination,
gfxIntSize(mBounds.width, mBounds.height),
mBounds.width * 4,
gfxASurface::ImageFormatARGB32);
mGLContext->ReadPixelsIntoImageSurface(0, 0,
mBounds.width, mBounds.height,
tmpSurface);
tmpSurface = nsnull;
// Put back the previous framebuffer binding.
if (currentFramebuffer != mCanvasFramebuffer)

View File

@ -309,9 +309,63 @@ GLContext::InitWithPrefix(const char *prefix, PRBool trygl)
};
mInitialized = LoadSymbols(&symbols[0], trygl, prefix);
if (mInitialized) {
InitExtensions();
}
return mInitialized;
}
// should match the order of GLExtensions
static const char *sExtensionNames[] = {
"GL_EXT_framebuffer_object",
"GL_ARB_framebuffer_object",
"GL_EXT_bgra",
"GL_EXT_texture_format_BGRA8888",
"GL_OES_depth24",
"GL_OES_depth32",
"GL_OES_stencil8",
"GL_OES_texture_npot",
"GL_OES_depth_texture",
"GL_OES_packed_depth_stencil",
"GL_IMG_read_format",
"GL_EXT_read_format_bgra",
NULL
};
void
GLContext::InitExtensions()
{
MakeCurrent();
const GLubyte *extensions = fGetString(LOCAL_GL_EXTENSIONS);
char *exts = strdup((char *)extensions);
printf_stderr("GL extensions: %s\n", exts);
char *s = exts;
bool done = false;
while (!done) {
char *space = strchr(s, ' ');
if (space) {
*space = '\0';
} else {
done = true;
}
for (int i = 0; sExtensionNames[i]; ++i) {
if (strcmp(s, sExtensionNames[i]) == 0) {
printf_stderr("Found extension %s\n", s);
mAvailableExtensions[i] = 1;
}
}
s = space+1;
}
free(exts);
}
PRBool
GLContext::IsExtensionSupported(const char *extension)
{
@ -479,6 +533,9 @@ GLContext::ResizeOffscreenFBO(const gfxIntSize& aSize)
GLint viewport[4];
bool useDepthStencil =
!mIsGLES2 || IsExtensionSupported(OES_packed_depth_stencil);
// save a few things for later restoring
fGetIntegerv(LOCAL_GL_TEXTURE_BINDING_2D, (GLint*) &curBoundTexture);
fGetIntegerv(LOCAL_GL_FRAMEBUFFER_BINDING, (GLint*) &curBoundFramebuffer);
@ -496,7 +553,7 @@ GLContext::ResizeOffscreenFBO(const gfxIntSize& aSize)
fGenFramebuffers(1, &mOffscreenFBO);
fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, mOffscreenFBO);
if (depth && stencil && !mIsGLES2) {
if (depth && stencil && useDepthStencil) {
fGenRenderbuffers(1, &mOffscreenDepthRB);
} else {
if (depth) {
@ -529,18 +586,35 @@ GLContext::ResizeOffscreenFBO(const gfxIntSize& aSize)
aSize.width, aSize.height,
0,
LOCAL_GL_RGB,
#ifdef XP_WIN
LOCAL_GL_UNSIGNED_BYTE,
#else
mIsGLES2 ? LOCAL_GL_UNSIGNED_SHORT_5_6_5
: LOCAL_GL_UNSIGNED_BYTE,
#endif
NULL);
}
if (depth && stencil && !mIsGLES2) {
if (depth && stencil && useDepthStencil) {
fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, mOffscreenDepthRB);
fRenderbufferStorage(LOCAL_GL_RENDERBUFFER,
LOCAL_GL_DEPTH24_STENCIL8,
aSize.width, aSize.height);
} else {
if (depth) {
GLenum depthType;
if (mIsGLES2) {
if (IsExtensionSupported(OES_depth32)) {
depthType = LOCAL_GL_DEPTH_COMPONENT32;
} else if (IsExtensionSupported(OES_depth24)) {
depthType = LOCAL_GL_DEPTH_COMPONENT24;
} else {
depthType = LOCAL_GL_DEPTH_COMPONENT16;
}
} else {
depthType = LOCAL_GL_DEPTH_COMPONENT24;
}
fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, mOffscreenDepthRB);
fRenderbufferStorage(LOCAL_GL_RENDERBUFFER,
mIsGLES2 ? LOCAL_GL_DEPTH_COMPONENT16
@ -565,7 +639,7 @@ GLContext::ResizeOffscreenFBO(const gfxIntSize& aSize)
mOffscreenTexture,
0);
if (depth && stencil && !mIsGLES2) {
if (depth && stencil && useDepthStencil) {
fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER,
LOCAL_GL_DEPTH_ATTACHMENT,
LOCAL_GL_RENDERBUFFER,
@ -603,6 +677,10 @@ GLContext::ResizeOffscreenFBO(const gfxIntSize& aSize)
if (firstTime) {
UpdateActualFormat();
printf_stderr("Created offscreen FBO: r: %d g: %d b: %d a: %d depth: %d stencil: %d\n",
mActualFormat.red, mActualFormat.green, mActualFormat.blue, mActualFormat.alpha,
mActualFormat.depth, mActualFormat.stencil);
}
// We're good, and the framebuffer is already attached, so let's
@ -665,7 +743,16 @@ GLContext::ClearSafely()
void
GLContext::UpdateActualFormat()
{
// TODO
ContextFormat nf;
fGetIntegerv(LOCAL_GL_RED_BITS, (GLint*) &nf.alpha);
fGetIntegerv(LOCAL_GL_GREEN_BITS, (GLint*) &nf.alpha);
fGetIntegerv(LOCAL_GL_BLUE_BITS, (GLint*) &nf.alpha);
fGetIntegerv(LOCAL_GL_ALPHA_BITS, (GLint*) &nf.alpha);
fGetIntegerv(LOCAL_GL_DEPTH_BITS, (GLint*) &nf.depth);
fGetIntegerv(LOCAL_GL_STENCIL_BITS, (GLint*) &nf.depth);
mActualFormat = nf;
}
void
@ -805,6 +892,69 @@ GLContext::ReadTextureImage(GLuint aTexture,
return isurf.forget();
}
void
GLContext::ReadPixelsIntoImageSurface(GLint aX, GLint aY,
GLsizei aWidth, GLsizei aHeight,
gfxImageSurface *aDest)
{
MakeCurrent();
if (aDest->Format() != gfxASurface::ImageFormatARGB32 &&
aDest->Format() != gfxASurface::ImageFormatRGB24)
{
NS_WARNING("ReadPixelsIntoImageSurface called with invalid image format");
return;
}
if (aDest->Width() != aWidth ||
aDest->Height() != aHeight ||
aDest->Stride() != aWidth * 4)
{
NS_WARNING("ReadPixelsIntoImageSurface called with wrong size or stride surface");
return;
}
GLint currentPackAlignment = 0;
fGetIntegerv(LOCAL_GL_PACK_ALIGNMENT, &currentPackAlignment);
fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, 4);
// defaults for desktop
GLenum format = LOCAL_GL_BGRA;
GLenum datatype = LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV;
bool swap = false;
if (IsGLES2()) {
datatype = LOCAL_GL_UNSIGNED_BYTE;
if (IsExtensionSupported(gl::GLContext::EXT_read_format_bgra) ||
IsExtensionSupported(gl::GLContext::IMG_read_format) ||
IsExtensionSupported(gl::GLContext::EXT_bgra))
{
format = LOCAL_GL_BGRA;
} else {
format = LOCAL_GL_RGBA;
swap = true;
}
}
fReadPixels(0, 0, aWidth, aHeight,
format, datatype,
aDest->Data());
if (swap) {
// swap B and R bytes
for (int j = 0; j < aHeight; ++j) {
PRUint32 *row = (PRUint32*) (aDest->Data() + aDest->Stride() * j);
for (int i = 0; i < aWidth; ++i) {
*row = (*row & 0xff00ff00) | ((*row & 0xff) << 16) | ((*row & 0xff0000) >> 16);
row++;
}
}
}
fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, currentPackAlignment);
}
#ifdef DEBUG
void

View File

@ -562,6 +562,40 @@ public:
const gfxIntSize& aSize,
GLenum aTextureFormat);
/**
* Call ReadPixels into an existing gfxImageSurface for the given bounds.
* The image surface must be using image format RGBA32 or RGB24.
*/
void ReadPixelsIntoImageSurface(GLint aX, GLint aY, GLsizei aWidth, GLsizei aHeight,
gfxImageSurface *aDest);
/**
* Known GL extensions that can be queried by
* IsExtensionSupported. The results of this are cached, and as
* such it's safe to use this even in performance critical code.
* If you add to this array, remember to add to the string names
* in GLContext.cpp.
*/
enum GLExtensions {
EXT_framebuffer_object,
ARB_framebuffer_object,
EXT_bgra,
EXT_texture_format_BGRA8888,
OES_depth24,
OES_depth32,
OES_stencil8,
OES_texture_npot,
OES_depth_texture,
OES_packed_depth_stencil,
IMG_read_format,
EXT_read_format_bgra,
Extensions_Max
};
PRBool IsExtensionSupported(GLExtensions aKnownExtension) {
return mAvailableExtensions[aKnownExtension];
}
protected:
PRPackedBool mInitialized;
PRPackedBool mIsOffscreen;
@ -585,6 +619,25 @@ protected:
GLuint mOffscreenDepthRB;
GLuint mOffscreenStencilRB;
// this should just be a std::bitset, but that ended up breaking
// MacOS X builds; see bug 584919. We can replace this with one
// later on.
template<size_t setlen>
struct ExtensionBitset {
ExtensionBitset() {
for (int i = 0; i < setlen; ++i)
values[i] = false;
}
bool& operator[](const int index) {
NS_ASSERTION(index >= 0 && index < setlen, "out of range");
return values[index];
}
bool values[setlen];
};
ExtensionBitset<Extensions_Max> mAvailableExtensions;
// Clear to transparent black, with 0 depth and stencil,
// while preserving current ClearColor etc. values.
// Useful for resizing offscreen buffers.
@ -599,6 +652,7 @@ protected:
PRBool InitWithPrefix(const char *prefix, PRBool trygl);
void InitExtensions();
PRBool IsExtensionSupported(const char *extension);
virtual already_AddRefed<TextureImage>

View File

@ -74,12 +74,15 @@ namespace gl {
#define GL_CONTEXT_PROVIDER_DEFAULT GLContextProviderCGL
#endif
#if defined(ANDROID) || defined(MOZ_PLATFORM_MAEMO)
#if defined(ANDROID) || defined(MOZ_PLATFORM_MAEMO) || defined(XP_WIN)
#define GL_CONTEXT_PROVIDER_NAME GLContextProviderEGL
#include "GLContextProviderImpl.h"
#undef GL_CONTEXT_PROVIDER_NAME
#ifndef GL_CONTEXT_PROVIDER_DEFAULT
#define GL_CONTEXT_PROVIDER_DEFAULT GLContextProviderEGL
#endif
#endif
// X11, but only if we didn't use EGL above
#if defined(MOZ_X11) && !defined(GL_CONTEXT_PROVIDER_DEFAULT)

View File

@ -76,6 +76,58 @@ typedef void *EGLNativeWindowType;
#define EGL_LIB "/system/lib/libEGL.so"
#define GLES2_LIB "/system/lib/libGLESv2.so"
#elif defined(XP_WIN)
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN 1
#endif
#include <windows.h>
typedef HDC EGLNativeDisplayType;
typedef HBITMAP EGLNativePixmapType;
typedef HWND EGLNativeWindowType;
#define GET_NATIVE_WINDOW(aWidget) ((EGLNativeWindowType)aWidget->GetNativeData(NS_NATIVE_WINDOW))
#define EGL_LIB "libEGL.dll"
#define GLES2_LIB "libGLESv2.dll"
// a little helper
class AutoDestroyHWND {
public:
AutoDestroyHWND(HWND aWnd = NULL)
: mWnd(aWnd)
{
}
~AutoDestroyHWND() {
if (mWnd) {
::DestroyWindow(mWnd);
}
}
operator HWND() {
return mWnd;
}
HWND forget() {
HWND w = mWnd;
mWnd = NULL;
return w;
}
HWND operator=(HWND aWnd) {
if (mWnd && mWnd != aWnd) {
::DestroyWindow(mWnd);
}
mWnd = aWnd;
return mWnd;
}
HWND mWnd;
};
#else
#error "Platform not recognized"
@ -147,58 +199,58 @@ public:
mHave_EGL_KHR_gl_texture_2D_image = PR_FALSE;
}
typedef EGLDisplay (*pfnGetDisplay)(void *display_id);
typedef EGLDisplay (GLAPIENTRY * pfnGetDisplay)(void *display_id);
pfnGetDisplay fGetDisplay;
typedef EGLContext (*pfnGetCurrentContext)(void);
typedef EGLContext (GLAPIENTRY * pfnGetCurrentContext)(void);
pfnGetCurrentContext fGetCurrentContext;
typedef EGLBoolean (*pfnMakeCurrent)(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx);
typedef EGLBoolean (GLAPIENTRY * pfnMakeCurrent)(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx);
pfnMakeCurrent fMakeCurrent;
typedef EGLBoolean (*pfnDestroyContext)(EGLDisplay dpy, EGLContext ctx);
typedef EGLBoolean (GLAPIENTRY * pfnDestroyContext)(EGLDisplay dpy, EGLContext ctx);
pfnDestroyContext fDestroyContext;
typedef EGLContext (*pfnCreateContext)(EGLDisplay dpy, EGLConfig config, EGLContext share_context, const EGLint *attrib_list);
typedef EGLContext (GLAPIENTRY * pfnCreateContext)(EGLDisplay dpy, EGLConfig config, EGLContext share_context, const EGLint *attrib_list);
pfnCreateContext fCreateContext;
typedef EGLBoolean (*pfnDestroySurface)(EGLDisplay dpy, EGLSurface surface);
typedef EGLBoolean (GLAPIENTRY * pfnDestroySurface)(EGLDisplay dpy, EGLSurface surface);
pfnDestroySurface fDestroySurface;
typedef EGLSurface (*pfnCreateWindowSurface)(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const EGLint *attrib_list);
typedef EGLSurface (GLAPIENTRY * pfnCreateWindowSurface)(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const EGLint *attrib_list);
pfnCreateWindowSurface fCreateWindowSurface;
typedef EGLSurface (*pfnCreatePbufferSurface)(EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list);
typedef EGLSurface (GLAPIENTRY * pfnCreatePbufferSurface)(EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list);
pfnCreatePbufferSurface fCreatePbufferSurface;
typedef EGLSurface (*pfnCreatePixmapSurface)(EGLDisplay dpy, EGLConfig config, EGLNativePixmapType pixmap, const EGLint *attrib_list);
typedef EGLSurface (GLAPIENTRY * pfnCreatePixmapSurface)(EGLDisplay dpy, EGLConfig config, EGLNativePixmapType pixmap, const EGLint *attrib_list);
pfnCreatePixmapSurface fCreatePixmapSurface;
typedef EGLBoolean (*pfnBindAPI)(EGLenum api);
typedef EGLBoolean (GLAPIENTRY * pfnBindAPI)(EGLenum api);
pfnBindAPI fBindAPI;
typedef EGLBoolean (*pfnInitialize)(EGLDisplay dpy, EGLint *major, EGLint *minor);
typedef EGLBoolean (GLAPIENTRY * pfnInitialize)(EGLDisplay dpy, EGLint *major, EGLint *minor);
pfnInitialize fInitialize;
typedef EGLBoolean (*pfnChooseConfig)(EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config);
typedef EGLBoolean (GLAPIENTRY * pfnChooseConfig)(EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config);
pfnChooseConfig fChooseConfig;
typedef EGLint (*pfnGetError)(void);
typedef EGLint (GLAPIENTRY * pfnGetError)(void);
pfnGetError fGetError;
typedef EGLBoolean (*pfnGetConfigAttrib)(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value);
typedef EGLBoolean (GLAPIENTRY * pfnGetConfigAttrib)(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value);
pfnGetConfigAttrib fGetConfigAttrib;
typedef EGLBoolean (*pfnGetConfigs)(EGLDisplay dpy, EGLConfig *configs, EGLint config_size, EGLint *num_config);
typedef EGLBoolean (GLAPIENTRY * pfnGetConfigs)(EGLDisplay dpy, EGLConfig *configs, EGLint config_size, EGLint *num_config);
pfnGetConfigs fGetConfigs;
typedef EGLBoolean (*pfnWaitNative)(EGLint engine);
typedef EGLBoolean (GLAPIENTRY * pfnWaitNative)(EGLint engine);
pfnWaitNative fWaitNative;
typedef EGLCastToRelevantPtr (*pfnGetProcAddress)(const char *procname);
typedef EGLCastToRelevantPtr (GLAPIENTRY * pfnGetProcAddress)(const char *procname);
pfnGetProcAddress fGetProcAddress;
typedef EGLBoolean (*pfnSwapBuffers)(EGLDisplay dpy, EGLSurface surface);
typedef EGLBoolean (GLAPIENTRY * pfnSwapBuffers)(EGLDisplay dpy, EGLSurface surface);
pfnSwapBuffers fSwapBuffers;
typedef EGLBoolean (*pfnCopyBuffers)(EGLDisplay dpy, EGLSurface surface,
EGLNativePixmapType target);
typedef EGLBoolean (GLAPIENTRY * pfnCopyBuffers)(EGLDisplay dpy, EGLSurface surface,
EGLNativePixmapType target);
pfnCopyBuffers fCopyBuffers;
typedef const GLubyte* (*pfnQueryString)(EGLDisplay, EGLint name);
typedef const GLubyte* (GLAPIENTRY * pfnQueryString)(EGLDisplay, EGLint name);
pfnQueryString fQueryString;
typedef EGLBoolean (*pfnBindTexImage)(EGLDisplay, EGLSurface surface, EGLint buffer);
typedef EGLBoolean (GLAPIENTRY * pfnBindTexImage)(EGLDisplay, EGLSurface surface, EGLint buffer);
pfnBindTexImage fBindTexImage;
typedef EGLBoolean (*pfnReleaseTexImage)(EGLDisplay, EGLSurface surface, EGLint buffer);
typedef EGLBoolean (GLAPIENTRY * pfnReleaseTexImage)(EGLDisplay, EGLSurface surface, EGLint buffer);
pfnReleaseTexImage fReleaseTexImage;
typedef EGLImageKHR (*pfnCreateImageKHR)(EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list);
typedef EGLImageKHR (GLAPIENTRY * pfnCreateImageKHR)(EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list);
pfnCreateImageKHR fCreateImageKHR;
typedef EGLBoolean (*pfnDestroyImageKHR)(EGLDisplay dpy, EGLImageKHR image);
typedef EGLBoolean (GLAPIENTRY * pfnDestroyImageKHR)(EGLDisplay dpy, EGLImageKHR image);
pfnDestroyImageKHR fDestroyImageKHR;
// This is EGL specific GL ext symbol "glEGLImageTargetTexture2DOES"
// Lets keep it here for now.
typedef void (*pfnImageTargetTexture2DOES)(GLenum target, GLeglImageOES image);
typedef void (GLAPIENTRY * pfnImageTargetTexture2DOES)(GLenum target, GLeglImageOES image);
pfnImageTargetTexture2DOES fImageTargetTexture2DOES;
PRBool EnsureInitialized()
@ -253,6 +305,11 @@ public:
return PR_FALSE;
const char *extensions = (const char*) fQueryString(mEGLDisplay, LOCAL_EGL_EXTENSIONS);
if (!extensions)
extensions = "";
printf_stderr("Extensions: %s 0x%02x\n", extensions, extensions[0]);
printf_stderr("Extensions length: %d\n", strlen(extensions));
// note the extra space -- this ugliness tries to match
// EGL_KHR_image in the middle of the string, or right at the
@ -406,7 +463,13 @@ public:
, mThebesSurface(nsnull)
, mBound(PR_FALSE)
, mIsPBuffer(PR_FALSE)
{}
#ifdef XP_WIN
, mWnd(0)
#endif
{
// any EGL contexts will always be GLESv2
SetIsGLES2(PR_TRUE);
}
~GLContextEGL()
{
@ -564,6 +627,15 @@ public:
CreateEGLPBufferOffscreenContext(const gfxIntSize& aSize,
const ContextFormat& aFormat);
#ifdef XP_WIN
static already_AddRefed<GLContextEGL>
CreateEGLWin32OffscreenContext(const gfxIntSize& aSize,
const ContextFormat& aFormat);
void HoldWin32Window(HWND aWnd) { mWnd = aWnd; }
HWND GetWin32Window() { return mWnd; }
#endif
void SetOffscreenSize(const gfxIntSize &aRequestedSize,
const gfxIntSize &aActualSize)
{
@ -582,6 +654,10 @@ protected:
PRBool mBound;
PRPackedBool mIsPBuffer;
#ifdef XP_WIN
AutoDestroyHWND mWnd;
#endif
};
PRBool
@ -1172,6 +1248,95 @@ GLContextEGL::CreateEGLPixmapOffscreenContext(const gfxIntSize& aSize,
return glContext.forget();
}
#ifdef XP_WIN
already_AddRefed<GLContextEGL>
GLContextEGL::CreateEGLWin32OffscreenContext(const gfxIntSize& aSize,
const ContextFormat& aFormat)
{
if (!sEGLLibrary.EnsureInitialized()) {
return nsnull;
}
WNDCLASSW wc;
if (!GetClassInfoW(GetModuleHandle(NULL), L"ANGLEContextClass", &wc)) {
ZeroMemory(&wc, sizeof(WNDCLASSW));
wc.style = CS_OWNDC;
wc.hInstance = GetModuleHandle(NULL);
wc.lpfnWndProc = DefWindowProc;
wc.lpszClassName = L"ANGLEContextClass";
if (!RegisterClassW(&wc)) {
NS_WARNING("Failed to register ANGLEContextClass?!");
return NULL;
}
}
AutoDestroyHWND wnd = CreateWindowW(L"ANGLEContextClass", L"ANGLEContext", 0,
0, 0, 16, 16,
NULL, NULL, GetModuleHandle(NULL), NULL);
NS_ENSURE_TRUE(HWND(wnd), NULL);
EGLConfig config;
EGLSurface surface;
EGLContext context;
// We don't really care, we're going to use a FBO anyway
EGLint attribs[] = {
LOCAL_EGL_SURFACE_TYPE, LOCAL_EGL_WINDOW_BIT,
LOCAL_EGL_RENDERABLE_TYPE, LOCAL_EGL_OPENGL_ES2_BIT,
LOCAL_EGL_NONE
};
EGLint ncfg = 1;
if (!sEGLLibrary.fChooseConfig(sEGLLibrary.Display(), attribs, &config, ncfg, &ncfg) ||
ncfg < 1)
{
return nsnull;
}
surface = sEGLLibrary.fCreateWindowSurface(sEGLLibrary.Display(),
config,
HWND(wnd),
0);
if (!surface) {
return nsnull;
}
if (!sEGLLibrary.fBindAPI(LOCAL_EGL_OPENGL_ES_API)) {
sEGLLibrary.fDestroySurface(sEGLLibrary.Display(), surface);
return nsnull;
}
EGLint cxattribs[] = {
LOCAL_EGL_CONTEXT_CLIENT_VERSION, 2,
LOCAL_EGL_NONE
};
context = sEGLLibrary.fCreateContext(sEGLLibrary.Display(),
config,
EGL_NO_CONTEXT,
cxattribs);
if (!context) {
sEGLLibrary.fDestroySurface(sEGLLibrary.Display(), surface);
return nsnull;
}
nsRefPtr<GLContextEGL> glContext = new GLContextEGL(aFormat, nsnull,
config, surface, context,
PR_TRUE);
// hold this even before we initialize, because we need to make
// sure it gets destroyed after the surface etc. in case of error.
glContext->HoldWin32Window(wnd.forget());
if (!glContext->Init() ||
!glContext->ResizeOffscreenFBO(aSize))
{
return nsnull;
}
return glContext.forget();
}
#endif
// Under EGL, if we're under X11, then we have to create a Pixmap
// because Maemo's EGL implementation doesn't support pbuffers at all
// for some reason. On Android, pbuffers are supported fine, though
@ -1188,6 +1353,8 @@ GLContextProviderEGL::CreateOffscreen(const gfxIntSize& aSize,
return GLContextEGL::CreateEGLPBufferOffscreenContext(aSize, aFormat);
#elif defined(MOZ_X11)
return GLContextEGL::CreateEGLPixmapOffscreenContext(aSize, aFormat);
#elif defined(XP_WIN)
return GLContextEGL::CreateEGLWin32OffscreenContext(aSize, aFormat);
#else
return nsnull;
#endif

View File

@ -414,6 +414,11 @@ else
CPPSRCS += GLContextProvider$(GL_PROVIDER).cpp
endif
# Win32 is a special snowflake, for ANGLE
ifeq ($(MOZ_WIDGET_TOOLKIT),windows)
CPPSRCS += GLContextProviderEGL.cpp
endif
DEFINES += -DIMPL_THEBES -DWOFF_MOZILLA_CLIENT
include $(topsrcdir)/config/rules.mk