b=618892; [webgl] use ANGLE pbuffers to speed up webgl with d3d10 layers; r=bas

This commit is contained in:
Vladimir Vukicevic 2011-01-06 14:07:12 -08:00
Родитель 9765b7449a
Коммит 1f95129bca
5 изменённых файлов: 111 добавлений и 124 удалений

Просмотреть файл

@ -76,23 +76,34 @@ CanvasLayerD3D10::Initialize(const Data& aData)
void *data = mSurface->GetData(&gKeyD3D10Texture);
if (data) {
mTexture = static_cast<ID3D10Texture2D*>(data);
mIsD2DTexture = true;
mIsD2DTexture = PR_TRUE;
device()->CreateShaderResourceView(mTexture, NULL, getter_AddRefs(mSRView));
return;
}
}
mIsD2DTexture = false;
mIsD2DTexture = PR_FALSE;
mUsingSharedTexture = PR_FALSE;
CD3D10_TEXTURE2D_DESC desc(DXGI_FORMAT_B8G8R8A8_UNORM, mBounds.width, mBounds.height, 1, 1);
desc.Usage = D3D10_USAGE_DYNAMIC;
desc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
HRESULT hr = device()->CreateTexture2D(&desc, NULL, getter_AddRefs(mTexture));
if (FAILED(hr)) {
NS_WARNING("Failed to create texture for CanvasLayer!");
return;
HANDLE shareHandle = mGLContext ? mGLContext->GetD3DShareHandle() : nsnull;
if (shareHandle) {
HRESULT hr = device()->OpenSharedResource(shareHandle, __uuidof(ID3D10Texture2D), getter_AddRefs(mTexture));
if (SUCCEEDED(hr))
mUsingSharedTexture = PR_TRUE;
}
if (!mUsingSharedTexture) {
CD3D10_TEXTURE2D_DESC desc(DXGI_FORMAT_B8G8R8A8_UNORM, mBounds.width, mBounds.height, 1, 1);
desc.Usage = D3D10_USAGE_DYNAMIC;
desc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
HRESULT hr = device()->CreateTexture2D(&desc, NULL, getter_AddRefs(mTexture));
if (FAILED(hr)) {
NS_WARNING("Failed to create texture for CanvasLayer!");
return;
}
}
device()->CreateShaderResourceView(mTexture, NULL, getter_AddRefs(mSRView));
}
@ -104,6 +115,15 @@ CanvasLayerD3D10::Updated(const nsIntRect& aRect)
return;
}
if (mUsingSharedTexture) {
// need to sync on the d3d9 device
if (mGLContext) {
mGLContext->MakeCurrent();
mGLContext->fFinish();
}
return;
}
if (mGLContext) {
// WebGL reads entire surface.
D3D10_MAPPED_TEXTURE2D map;

Просмотреть файл

@ -82,6 +82,7 @@ private:
PRPackedBool mDataIsPremultiplied;
PRPackedBool mNeedsYFlip;
PRPackedBool mIsD2DTexture;
PRPackedBool mUsingSharedTexture;
};
} /* layers */

Просмотреть файл

@ -92,13 +92,11 @@ LayerManagerD3D10::Initialize()
{
HRESULT hr;
cairo_device_t *device = gfxWindowsPlatform::GetPlatform()->GetD2DDevice();
if (!device) {
return false;
mDevice = gfxWindowsPlatform::GetPlatform()->GetD3D10Device();
if (!mDevice) {
return false;
}
mDevice = cairo_d2d_device_get_device(device);
UINT size = sizeof(ID3D10Effect*);
if (FAILED(mDevice->GetPrivateData(sEffect, &size, mEffect.StartAssignment()))) {
D3D10CreateEffectFromMemoryFunc createEffect = (D3D10CreateEffectFromMemoryFunc)

Просмотреть файл

@ -495,6 +495,11 @@ public:
const ContextFormat& CreationFormat() { return mCreationFormat; }
const ContextFormat& ActualFormat() { return mActualFormat; }
/**
* If this GL context has a D3D texture share handle, returns non-null.
*/
virtual void *GetD3DShareHandle() { return nsnull; }
/**
* If this context is double-buffered, returns TRUE.
*/

Просмотреть файл

@ -209,10 +209,12 @@ public:
: mInitialized(PR_FALSE),
mEGLLibrary(nsnull)
{
mIsANGLE = PR_FALSE;
mHave_EGL_KHR_image_base = PR_FALSE;
mHave_EGL_KHR_image_pixmap = PR_FALSE;
mHave_EGL_KHR_gl_texture_2D_image = PR_FALSE;
mHave_EGL_KHR_lock_surface = PR_FALSE;
mHave_EGL_ANGLE_surface_d3d_share_handle = PR_FALSE;
}
typedef EGLDisplay (GLAPIENTRY * pfnGetDisplay)(void *display_id);
@ -276,6 +278,9 @@ public:
typedef EGLBoolean (GLAPIENTRY * pfnQuerySurface)(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint *value);
pfnQuerySurface fQuerySurface;
typedef EGLBoolean (GLAPIENTRY * pfnQuerySurfacePointerANGLE)(EGLDisplay dpy, EGLSurface surface, EGLint attribute, void **value);
pfnQuerySurfacePointerANGLE fQuerySurfacePointerANGLE;
// This is EGL specific GL ext symbol "glEGLImageTargetTexture2DOES"
// Lets keep it here for now.
typedef void (GLAPIENTRY * pfnImageTargetTexture2DOES)(GLenum target, GLeglImageOES image);
@ -372,6 +377,11 @@ public:
mEGLDisplay = fGetDisplay(EGL_DEFAULT_DISPLAY);
if (!fInitialize(mEGLDisplay, NULL, NULL))
return PR_FALSE;
const char *vendor = (const char*) fQueryString(mEGLDisplay, LOCAL_EGL_VENDOR);
if (vendor && strstr(vendor, "TransGaming") != 0) {
mIsANGLE = PR_TRUE;
}
const char *extensions = (const char*) fQueryString(mEGLDisplay, LOCAL_EGL_EXTENSIONS);
if (!extensions)
@ -448,6 +458,19 @@ public:
mHave_EGL_KHR_gl_texture_2D_image = PR_FALSE;
}
if (strstr(extensions, "EGL_ANGLE_surface_d3d_share_handle")) {
LibrarySymbolLoader::SymLoadStruct d3dSymbols[] = {
{ (PRFuncPtr*) &fQuerySurfacePointerANGLE, { "eglQuerySurfacePointerANGLE", NULL } },
{ NULL, { NULL } }
};
LibrarySymbolLoader::LoadSymbols(mEGLLibrary, &d3dSymbols[0],
(LibrarySymbolLoader::PlatformLookupFunction)fGetProcAddress);
if (fQuerySurfacePointerANGLE) {
mHave_EGL_ANGLE_surface_d3d_share_handle = PR_TRUE;
}
}
mInitialized = PR_TRUE;
return PR_TRUE;
}
@ -456,6 +479,10 @@ public:
return mEGLDisplay;
}
PRBool IsANGLE() {
return mIsANGLE;
}
PRBool HasKHRImageBase() {
return mHave_EGL_KHR_image_base;
}
@ -472,6 +499,10 @@ public:
return mHave_EGL_KHR_lock_surface;
}
PRBool HasANGLESurfaceD3DShareHandle() {
return mHave_EGL_ANGLE_surface_d3d_share_handle;
}
void
DumpEGLConfig(EGLConfig cfg)
{
@ -531,10 +562,13 @@ private:
PRLibrary *mEGLLibrary;
EGLDisplay mEGLDisplay;
PRPackedBool mIsANGLE;
PRPackedBool mHave_EGL_KHR_image_base;
PRPackedBool mHave_EGL_KHR_image_pixmap;
PRPackedBool mHave_EGL_KHR_gl_texture_2D_image;
PRPackedBool mHave_EGL_KHR_lock_surface;
PRPackedBool mHave_EGL_ANGLE_surface_d3d_share_handle;
} sEGLLibrary;
class GLContextEGL : public GLContext
@ -556,9 +590,6 @@ public:
, mBound(PR_FALSE)
, mIsPBuffer(PR_FALSE)
, mIsDoubleBuffered(PR_FALSE)
#ifdef XP_WIN
, mWnd(0)
#endif
{
// any EGL contexts will always be GLESv2
SetIsGLES2(PR_TRUE);
@ -757,15 +788,6 @@ 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)
{
@ -773,6 +795,26 @@ public:
mOffscreenActualSize = aActualSize;
}
void *GetD3DShareHandle() {
if (!sEGLLibrary.HasANGLESurfaceD3DShareHandle()) {
return nsnull;
}
void *h = nsnull;
#ifndef EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE
#define EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE 0x3200
#endif
if (!sEGLLibrary.fQuerySurfacePointerANGLE(EGL_DISPLAY(), mSurface,
EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE, (void**) &h))
{
return nsnull;
}
return h;
}
protected:
friend class GLContextProviderEGL;
@ -785,10 +827,6 @@ protected:
PRPackedBool mIsPBuffer;
PRPackedBool mIsDoubleBuffered;
#ifdef XP_WIN
AutoDestroyHWND mWnd;
#endif
};
PRBool
@ -1659,6 +1697,7 @@ GLContextEGL::CreateEGLPBufferOffscreenContext(const gfxIntSize& aSize,
LOCAL_EGL_DEPTH_SIZE, aFormat.minDepth,
LOCAL_EGL_STENCIL_SIZE, aFormat.minStencil,
// these get overwritten below; if you add anything above
aFormat.minAlpha ?
LOCAL_EGL_BIND_TO_TEXTURE_RGBA :
LOCAL_EGL_BIND_TO_TEXTURE_RGB,
@ -1667,6 +1706,14 @@ GLContextEGL::CreateEGLPBufferOffscreenContext(const gfxIntSize& aSize,
LOCAL_EGL_NONE
};
// if we're running under ANGLE, we can't set
// BIND_TO_TEXTURE since we're probably doing d3d interop
if (sEGLLibrary.IsANGLE()) {
int k = sizeof(attribs)/sizeof(EGLint) - 3;
attribs[k] = LOCAL_EGL_NONE;
attribs[k+1] = LOCAL_EGL_NONE;
}
EGLConfig configs[64];
int numConfigs = 64;
@ -1694,7 +1741,6 @@ GLContextEGL::CreateEGLPBufferOffscreenContext(const gfxIntSize& aSize,
LOCAL_EGL_HEIGHT, 0,
LOCAL_EGL_TEXTURE_TARGET, LOCAL_EGL_TEXTURE_2D,
LOCAL_EGL_TEXTURE_FORMAT,
aFormat.minAlpha ?
LOCAL_EGL_TEXTURE_RGBA :
@ -1703,6 +1749,14 @@ GLContextEGL::CreateEGLPBufferOffscreenContext(const gfxIntSize& aSize,
LOCAL_EGL_NONE
};
// if under ANGLE, then TEXTURE_TARGET/TEXTURE_FORMAT
// need to be stripped out (we don't support bind-to-texture,
// and just do d3d interop)
if (sEGLLibrary.IsANGLE()) {
pbattrs[4] = LOCAL_EGL_NONE;
pbattrs[5] = LOCAL_EGL_NONE;
}
TRY_AGAIN_POWER_OF_TWO:
pbattrs[1] = pbsize.width;
pbattrs[3] = pbsize.height;
@ -1902,95 +1956,6 @@ 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
@ -2003,12 +1968,10 @@ GLContextProviderEGL::CreateOffscreen(const gfxIntSize& aSize,
return nsnull;
}
#if defined(ANDROID)
#if defined(ANDROID) || defined(XP_WIN)
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