author | Ryan VanderMeulen <ryanvm@gmail.com> |
Wed, 20 Feb 2013 10:01:20 -0500 | |
changeset 122460 | f04919e7789fc6b7977aec2d3fbd5519dbd9360f |
parent 122459 | 3f2b219950b82780be2c88320ec4a7852b3c4988 |
child 122461 | fa3150c558e0eebbc87d53caa7418330574a78db |
push id | 24342 |
push user | ryanvm@gmail.com |
push date | Thu, 21 Feb 2013 13:05:06 +0000 |
treeherder | mozilla-central@702d2814efbf [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
bugs | 716859, 841836 |
milestone | 22.0a1 |
backs out | b46c006a7696832b2763b13f3934a226510db373 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/b2g/test/emulator.manifest +++ b/b2g/test/emulator.manifest @@ -1,6 +1,6 @@ [{ -"size": 606070399, -"digest": "3d3899e2537bee5e3f969bb6d0e90fed93345512123e3133b1de793d59a8993d8174d9456cb92d86a880f6813d6049933de924cd522a433ef26c4bfa997777a7", +"size": 608318343, +"digest": "9ab6487eccf44b0781cc96c2af9ba497f720a8d289bde40e29417f9db82788d6c8653c7dafa7443069f5898635eef45fa048ee99c03a9d0113c019a2f80f5aa8", "algorithm": "sha512", "filename": "emulator.zip" }]
--- a/content/canvas/src/WebGLContext.cpp +++ b/content/canvas/src/WebGLContext.cpp @@ -45,20 +45,19 @@ #include "mozilla/Services.h" #include "mozilla/dom/WebGLRenderingContextBinding.h" #include "mozilla/dom/BindingUtils.h" #include "mozilla/dom/ipc/ProcessPriorityManager.h" #include "Layers.h" using namespace mozilla; +using namespace mozilla::gl; using namespace mozilla::dom; using namespace mozilla::dom::ipc; -using namespace mozilla::gfx; -using namespace mozilla::gl; using namespace mozilla::layers; NS_IMETHODIMP WebGLMemoryPressureObserver::Observe(nsISupports* aSubject, const char* aTopic, const PRUnichar* aSomeData) { if (strcmp(aTopic, "memory-pressure")) @@ -105,17 +104,16 @@ WebGLContextOptions::WebGLContextOptions WebGLContext::WebGLContext() : gl(nullptr) { SetIsDOMBinding(); mGeneration = 0; mInvalidated = false; - mShouldPresent = true; mResetLayer = true; mOptionsFrozen = false; mActiveTexture = 0; mWebGLError = LOCAL_GL_NO_ERROR; mPixelStoreFlipY = false; mPixelStorePremultiplyAlpha = false; mPixelStoreColorspaceConversion = BROWSER_DEFAULT_WEBGL; @@ -153,16 +151,17 @@ WebGLContext::WebGLContext() mStencilRefBack = 0; mStencilValueMaskFront = 0xffffffff; mStencilValueMaskBack = 0xffffffff; mStencilWriteMaskFront = 0xffffffff; mStencilWriteMaskBack = 0xffffffff; mScissorTestEnabled = 0; mDitherEnabled = 1; + mBackbufferClearingStatus = BackbufferClearingStatus::NotClearedSinceLastPresented; // initialize some GL values: we're going to get them from the GL and use them as the sizes of arrays, // so in case glGetIntegerv leaves them uninitialized because of a GL bug, we would have very weird crashes. mGLMaxVertexAttribs = 0; mGLMaxTextureUnits = 0; mGLMaxTextureSize = 0; mGLMaxCubeMapTextureSize = 0; mGLMaxRenderbufferSize = 0; @@ -189,18 +188,16 @@ WebGLContext::WebGLContext() mAlreadyGeneratedWarnings = 0; mAlreadyWarnedAboutFakeVertexAttrib0 = false; mLastUseIndex = 0; mMinInUseAttribArrayLengthCached = false; mMinInUseAttribArrayLength = 0; - - mIsScreenCleared = false; } WebGLContext::~WebGLContext() { DestroyResourcesAndContext(); WebGLMemoryMultiReporterWrapper::RemoveWebGLContext(this); TerminateContextLossTimer(); mContextRestorer = nullptr; @@ -380,23 +377,21 @@ WebGLContext::SetDimensions(int32_t widt // If we already have a gl context, then we just need to resize it if (gl) { MakeContextCurrent(); gl->ResizeOffscreen(gfxIntSize(width, height)); // Doesn't matter if it succeeds (soft-fail) // It's unlikely that we'll get a proper-sized context if we recreate if we didn't on resize // everything's good, we're done here - mWidth = gl->OffscreenSize().width; - mHeight = gl->OffscreenSize().height; + mWidth = gl->OffscreenActualSize().width; + mHeight = gl->OffscreenActualSize().height; mResetLayer = true; - ScopedBindFramebuffer autoFB(gl, 0); gl->ClearSafely(); - mShouldPresent = true; return NS_OK; } // End of early return cases. // At this point we know that we're not just resizing an existing context, // we are initializing a new context. @@ -436,40 +431,65 @@ WebGLContext::SetDimensions(int32_t widt // event. // If incrementing the generation would cause overflow, // don't allow it. Allowing this would allow us to use // resource handles created from older context generations. if (!(mGeneration + 1).isValid()) return NS_ERROR_FAILURE; // exit without changing the value of mGeneration - SurfaceCaps caps; + gl::ContextFormat format(gl::ContextFormat::BasicRGBA32); + if (mOptions.depth) { + format.depth = 24; + format.minDepth = 16; + } - caps.color = true; - caps.alpha = mOptions.alpha; - caps.depth = mOptions.depth; - caps.stencil = mOptions.stencil; + if (mOptions.stencil) { + format.stencil = 8; + format.minStencil = 8; + } + + if (!mOptions.alpha) { + format.alpha = 0; + format.minAlpha = 0; + } // we should really have this behind a // |gfxPlatform::GetPlatform()->GetScreenDepth() == 16| check, but // for now it's just behind a pref for testing/evaluation. - caps.bpp16 = prefer16bit; - - caps.preserve = mOptions.preserveDrawingBuffer; + if (prefer16bit) { + // Select 4444 or 565 on 16-bit displays; we won't/shouldn't + // hit this on the desktop, but let mobile know we're ok with + // it. Note that we don't just set this to 4440 if no alpha, + // because that might cause us to choose 4444 anyway and we + // don't want that. + if (mOptions.alpha) { + format.red = 4; + format.green = 4; + format.blue = 4; + format.alpha = 4; + } else { + format.red = 5; + format.green = 6; + format.blue = 5; + format.alpha = 0; + } + } bool forceMSAA = Preferences::GetBool("webgl.msaa-force", false); int32_t status; nsCOMPtr<nsIGfxInfo> gfxInfo = do_GetService("@mozilla.org/gfx/info;1"); if (mOptions.antialias && gfxInfo && NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_WEBGL_MSAA, &status))) { if (status == nsIGfxInfo::FEATURE_NO_INFO || forceMSAA) { - caps.antialias = true; + uint32_t msaaLevel = Preferences::GetUint("webgl.msaa-level", 2); + format.samples = msaaLevel*msaaLevel; } } #ifdef XP_WIN if (PR_GetEnv("MOZ_WEBGL_PREFER_EGL")) { preferEGL = true; } #endif @@ -500,35 +520,34 @@ WebGLContext::SetDimensions(int32_t widt // allow forcing GL and not EGL/ANGLE if (useMesaLlvmPipe || PR_GetEnv("MOZ_WEBGL_FORCE_OPENGL")) { preferEGL = false; useANGLE = false; useOpenGL = true; } #endif - gfxIntSize size(width, height); - #ifdef XP_WIN // if we want EGL, try it now if (!gl && (preferEGL || useANGLE) && !preferOpenGL) { - gl = gl::GLContextProviderEGL::CreateOffscreen(size, caps); + gl = gl::GLContextProviderEGL::CreateOffscreen(gfxIntSize(width, height), format); if (!gl || !InitAndValidateGL()) { GenerateWarning("Error during ANGLE OpenGL ES initialization"); return NS_ERROR_FAILURE; } } #endif // try the default provider, whatever that is if (!gl && useOpenGL) { GLContext::ContextFlags flag = useMesaLlvmPipe ? GLContext::ContextFlagsMesaLLVMPipe : GLContext::ContextFlagsNone; - gl = gl::GLContextProvider::CreateOffscreen(size, caps, flag); + gl = gl::GLContextProvider::CreateOffscreen(gfxIntSize(width, height), + format, flag); if (gl && !InitAndValidateGL()) { GenerateWarning("Error during %s initialization", useMesaLlvmPipe ? "Mesa LLVMpipe" : "OpenGL"); return NS_ERROR_FAILURE; } } if (!gl) { @@ -557,34 +576,25 @@ WebGLContext::SetDimensions(int32_t widt // XXX dispatch context lost event } #endif MakeContextCurrent(); // Make sure that we clear this out, otherwise // we'll end up displaying random memory - gl->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0); + gl->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, gl->GetOffscreenFBO()); gl->fViewport(0, 0, mWidth, mHeight); gl->fClearColor(0.0f, 0.0f, 0.0f, 0.0f); gl->fClearDepth(1.0f); gl->fClearStencil(0); gl->ClearSafely(); - mShouldPresent = true; - - MOZ_ASSERT(gl->Caps().color == caps.color); - MOZ_ASSERT(gl->Caps().alpha == caps.alpha); - MOZ_ASSERT(gl->Caps().depth == caps.depth || !gl->Caps().depth); - MOZ_ASSERT(gl->Caps().stencil == caps.stencil || !gl->Caps().stencil); - MOZ_ASSERT(gl->Caps().antialias == caps.antialias || !gl->Caps().antialias); - MOZ_ASSERT(gl->Caps().preserve == caps.preserve); - reporter.SetSuccessful(); return NS_OK; } NS_IMETHODIMP WebGLContext::Render(gfxContext *ctx, gfxPattern::GraphicsFilter f, uint32_t aFlags) { if (!gl) @@ -788,49 +798,35 @@ void WebGLContext::UpdateLastUseIndex() static uint8_t gWebGLLayerUserData; namespace mozilla { class WebGLContextUserData : public LayerUserData { public: WebGLContextUserData(HTMLCanvasElement *aContent) - : mContent(aContent) - {} - - /* PreTransactionCallback gets called by the Layers code every time the - * WebGL canvas is going to be composited. - */ - static void PreTransactionCallback(void* data) - { - WebGLContextUserData* userdata = static_cast<WebGLContextUserData*>(data); - HTMLCanvasElement* canvas = userdata->mContent; - WebGLContext* context = static_cast<WebGLContext*>(canvas->GetContextAtIndex(0)); + : mContent(aContent) {} - // Present our screenbuffer, if needed. - context->PresentScreenBuffer(); - } + /** DidTransactionCallback gets called by the Layers code everytime the WebGL canvas gets composite, + * so it really is the right place to put actions that have to be performed upon compositing + */ + static void DidTransactionCallback(void* aData) + { + WebGLContextUserData *userdata = static_cast<WebGLContextUserData*>(aData); + HTMLCanvasElement *canvas = userdata->mContent; + WebGLContext *context = static_cast<WebGLContext*>(canvas->GetContextAtIndex(0)); - /** DidTransactionCallback gets called by the Layers code everytime the WebGL canvas gets composite, - * so it really is the right place to put actions that have to be performed upon compositing - */ - static void DidTransactionCallback(void* aData) - { - WebGLContextUserData *userdata = static_cast<WebGLContextUserData*>(aData); - HTMLCanvasElement *canvas = userdata->mContent; - WebGLContext *context = static_cast<WebGLContext*>(canvas->GetContextAtIndex(0)); + context->mBackbufferClearingStatus = BackbufferClearingStatus::NotClearedSinceLastPresented; + canvas->MarkContextClean(); - // Mark ourselves as no longer invalidated. - context->MarkContextClean(); - - context->UpdateLastUseIndex(); - } + context->UpdateLastUseIndex(); + } private: - nsRefPtr<HTMLCanvasElement> mContent; + nsRefPtr<HTMLCanvasElement> mContent; }; } // end namespace mozilla already_AddRefed<layers::CanvasLayer> WebGLContext::GetCanvasLayer(nsDisplayListBuilder* aBuilder, CanvasLayer *aOldLayer, LayerManager *aManager) @@ -861,28 +857,38 @@ WebGLContext::GetCanvasLayer(nsDisplayLi // The layer will be destroyed when we tear down the presentation // (at the latest), at which time this userData will be destroyed, // releasing the reference to the element. // The userData will receive DidTransactionCallbacks, which flush the // the invalidation state to indicate that the canvas is up to date. userData = new WebGLContextUserData(mCanvasElement); canvasLayer->SetDidTransactionCallback( WebGLContextUserData::DidTransactionCallback, userData); - canvasLayer->SetPreTransactionCallback( - WebGLContextUserData::PreTransactionCallback, userData); } canvasLayer->SetUserData(&gWebGLLayerUserData, userData); CanvasLayer::Data data; - data.mGLContext = gl; + + // the gl context may either provide a native PBuffer, in which case we want to initialize + // data with the gl context directly, or may provide a surface to which it renders (this is the case + // of OSMesa contexts), in which case we want to initialize data with that surface. + + void* native_surface = gl->GetNativeData(gl::GLContext::NativeImageSurface); + + if (native_surface) { + data.mSurface = static_cast<gfxASurface*>(native_surface); + } else { + data.mGLContext = gl.get(); + } + data.mSize = nsIntSize(mWidth, mHeight); - data.mIsGLAlphaPremult = IsPremultAlpha(); + data.mGLBufferIsPremultiplied = mOptions.premultipliedAlpha ? true : false; canvasLayer->Initialize(data); - uint32_t flags = gl->Caps().alpha ? 0 : Layer::CONTENT_OPAQUE; + uint32_t flags = gl->CreationFormat().alpha == 0 ? Layer::CONTENT_OPAQUE : 0; canvasLayer->SetContentFlags(flags); canvasLayer->Updated(); mResetLayer = false; return canvasLayer.forget().get(); } @@ -890,22 +896,21 @@ void WebGLContext::GetContextAttributes(Nullable<dom::WebGLContextAttributesInitializer> &retval) { retval.SetNull(); if (!IsContextStable()) return; dom::WebGLContextAttributes& result = retval.SetValue(); - const PixelBufferFormat& format = gl->GetPixelFormat(); - - result.mAlpha = format.alpha > 0; - result.mDepth = format.depth > 0; - result.mStencil = format.stencil > 0; - result.mAntialias = format.samples > 1; + gl::ContextFormat cf = gl->ActualFormat(); + result.mAlpha = cf.alpha > 0; + result.mDepth = cf.depth > 0; + result.mStencil = cf.stencil > 0; + result.mAntialias = cf.samples > 1; result.mPremultipliedAlpha = mOptions.premultipliedAlpha; result.mPreserveDrawingBuffer = mOptions.preserveDrawingBuffer; } bool WebGLContext::IsExtensionEnabled(WebGLExtensionID ext) const { return mExtensions.SafeElementAt(ext); } @@ -1099,128 +1104,50 @@ WebGLContext::GetExtension(JSContext *cx mExtensions.EnsureLengthAtLeast(ext + 1); mExtensions[ext] = obj; } return WebGLObjectAsJSObject(cx, mExtensions[ext].get(), rv); } void -WebGLContext::ClearScreen() -{ - MakeContextCurrent(); - ScopedBindFramebuffer autoFB(gl, 0); - - GLbitfield clearMask = LOCAL_GL_COLOR_BUFFER_BIT; - if (mOptions.depth) - clearMask |= LOCAL_GL_DEPTH_BUFFER_BIT; - if (mOptions.stencil) - clearMask |= LOCAL_GL_STENCIL_BUFFER_BIT; - - ForceClearFramebufferWithDefaultValues(clearMask); - mIsScreenCleared = true; -} - -void -WebGLContext::ForceClearFramebufferWithDefaultValues(GLbitfield mask) +WebGLContext::ForceClearFramebufferWithDefaultValues(uint32_t mask, const nsIntRect& viewportRect) { MakeContextCurrent(); bool initializeColorBuffer = 0 != (mask & LOCAL_GL_COLOR_BUFFER_BIT); bool initializeDepthBuffer = 0 != (mask & LOCAL_GL_DEPTH_BUFFER_BIT); bool initializeStencilBuffer = 0 != (mask & LOCAL_GL_STENCIL_BUFFER_BIT); - // Fun GL fact: No need to worry about the viewport here, glViewport is just - // setting up a coordinates transformation, it doesn't affect glClear at all. - -#ifdef DEBUG - // Scope to hide our variables. - { - // Sanity-check that all our state is set properly. Otherwise, when we - // reset out state to what we *think* it is, we'll get it wrong. - - // Dither shouldn't matter when we're clearing to {0,0,0,0}. - MOZ_ASSERT(gl->fIsEnabled(LOCAL_GL_SCISSOR_TEST) == mScissorTestEnabled); - - realGLboolean colorWriteMask[4] = {2, 2, 2, 2}; - GLfloat colorClearValue[4] = {-1.0f, -1.0f, -1.0f, -1.0f}; - - gl->fGetBooleanv(LOCAL_GL_COLOR_WRITEMASK, colorWriteMask); - gl->fGetFloatv(LOCAL_GL_COLOR_CLEAR_VALUE, colorClearValue); - - MOZ_ASSERT(colorWriteMask[0] == mColorWriteMask[0] && - colorWriteMask[1] == mColorWriteMask[1] && - colorWriteMask[2] == mColorWriteMask[2] && - colorWriteMask[3] == mColorWriteMask[3]); - MOZ_ASSERT(colorClearValue[0] == mColorClearValue[0] && - colorClearValue[1] == mColorClearValue[1] && - colorClearValue[2] == mColorClearValue[2] && - colorClearValue[3] == mColorClearValue[3]); - - - realGLboolean depthWriteMask = 2; - GLfloat depthClearValue = -1.0f; + // fun GL fact: no need to worry about the viewport here, glViewport is just setting up a coordinates transformation, + // it doesn't affect glClear at all - gl->fGetBooleanv(LOCAL_GL_DEPTH_WRITEMASK, &depthWriteMask); - gl->fGetFloatv(LOCAL_GL_DEPTH_CLEAR_VALUE, &depthClearValue); - - MOZ_ASSERT(depthWriteMask == mDepthWriteMask); - MOZ_ASSERT(depthClearValue == mDepthClearValue); - - - GLuint stencilWriteMaskFront = 0xdeadbad1; - GLuint stencilWriteMaskBack = 0xdeadbad1; - GLuint stencilClearValue = 0xdeadbad1; - - gl->GetUIntegerv(LOCAL_GL_STENCIL_WRITEMASK, &stencilWriteMaskFront); - gl->GetUIntegerv(LOCAL_GL_STENCIL_BACK_WRITEMASK, &stencilWriteMaskBack); - gl->GetUIntegerv(LOCAL_GL_STENCIL_CLEAR_VALUE, &stencilClearValue); - - GLuint stencilBits = 0; - gl->GetUIntegerv(LOCAL_GL_STENCIL_BITS, &stencilBits); - GLuint stencilMask = (GLuint(1) << stencilBits) - 1; - - MOZ_ASSERT( ( stencilWriteMaskFront & stencilMask) == - (mStencilWriteMaskFront & stencilMask) ); - MOZ_ASSERT( ( stencilWriteMaskBack & stencilMask) == - (mStencilWriteMaskBack & stencilMask) ); - MOZ_ASSERT( ( stencilClearValue & stencilMask) == - (mStencilClearValue & stencilMask) ); - } -#endif - - // Prepare GL state for clearing. + // prepare GL state for clearing gl->fDisable(LOCAL_GL_SCISSOR_TEST); + gl->fDisable(LOCAL_GL_DITHER); if (initializeColorBuffer) { gl->fColorMask(1, 1, 1, 1); - gl->fClearColor(0.0f, 0.0f, 0.0f, 0.0f); + gl->fClearColor(0.f, 0.f, 0.f, 0.f); } if (initializeDepthBuffer) { gl->fDepthMask(1); gl->fClearDepth(1.0f); } if (initializeStencilBuffer) { - // "The clear operation always uses the front stencil write mask - // when clearing the stencil buffer." - gl->fStencilMaskSeparate(LOCAL_GL_FRONT, 0xffffffff); - gl->fStencilMaskSeparate(LOCAL_GL_BACK, 0xffffffff); + gl->fStencilMask(0xffffffff); gl->fClearStencil(0); } - // Do the clear! + // do clear gl->fClear(mask); - // And reset! - if (mScissorTestEnabled) - gl->fEnable(LOCAL_GL_SCISSOR_TEST); - - // Restore GL state after clearing. + // restore GL state after clearing if (initializeColorBuffer) { gl->fColorMask(mColorWriteMask[0], mColorWriteMask[1], mColorWriteMask[2], mColorWriteMask[3]); gl->fClearColor(mColorClearValue[0], mColorClearValue[1], mColorClearValue[2], @@ -1229,43 +1156,51 @@ WebGLContext::ForceClearFramebufferWithD if (initializeDepthBuffer) { gl->fDepthMask(mDepthWriteMask); gl->fClearDepth(mDepthClearValue); } if (initializeStencilBuffer) { gl->fStencilMaskSeparate(LOCAL_GL_FRONT, mStencilWriteMaskFront); - gl->fStencilMaskSeparate(LOCAL_GL_BACK, mStencilWriteMaskBack); + gl->fStencilMaskSeparate(LOCAL_GL_BACK, mStencilWriteMaskBack); gl->fClearStencil(mStencilClearValue); } -} - -// For an overview of how WebGL compositing works, see: -// https://wiki.mozilla.org/Platform/GFX/WebGL/Compositing -bool -WebGLContext::PresentScreenBuffer() -{ - if (!mShouldPresent) { - return false; - } - gl->MakeCurrent(); - if (!gl->PublishFrame()) { - this->ForceLoseContext(); - return false; - } + if (mDitherEnabled) + gl->fEnable(LOCAL_GL_DITHER); + else + gl->fDisable(LOCAL_GL_DITHER); + + if (mScissorTestEnabled) + gl->fEnable(LOCAL_GL_SCISSOR_TEST); + else + gl->fDisable(LOCAL_GL_SCISSOR_TEST); +} - if (!mOptions.preserveDrawingBuffer) { - ClearScreen(); - } +void +WebGLContext::EnsureBackbufferClearedAsNeeded() +{ + if (mOptions.preserveDrawingBuffer) + return; + + NS_ABORT_IF_FALSE(!mBoundFramebuffer, + "EnsureBackbufferClearedAsNeeded must not be called when a FBO is bound"); - mShouldPresent = false; + if (mBackbufferClearingStatus != BackbufferClearingStatus::NotClearedSinceLastPresented) + return; + + mBackbufferClearingStatus = BackbufferClearingStatus::ClearedToDefaultValues; - return true; + ForceClearFramebufferWithDefaultValues(LOCAL_GL_COLOR_BUFFER_BIT | + LOCAL_GL_DEPTH_BUFFER_BIT | + LOCAL_GL_STENCIL_BUFFER_BIT, + nsIntRect(0, 0, mWidth, mHeight)); + + Invalidate(); } void WebGLContext::DummyFramebufferOperation(const char *info) { WebGLenum status = CheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER); if (status == LOCAL_GL_FRAMEBUFFER_COMPLETE) return;
--- a/content/canvas/src/WebGLContext.h +++ b/content/canvas/src/WebGLContext.h @@ -81,16 +81,20 @@ namespace dom { struct WebGLContextAttributes; struct WebGLContextAttributesInitializer; } struct VertexAttrib0Status { enum { Default, EmulatedUninitializedArray, EmulatedInitializedArray }; }; +struct BackbufferClearingStatus { + enum { NotClearedSinceLastPresented, ClearedToDefaultValues, HasBeenDrawnTo }; +}; + namespace WebGLTexelConversions { /* * The formats that may participate, either as source or destination formats, * in WebGL texture conversions. This includes: * - all the formats accepted by WebGL.texImage2D, e.g. RGBA4444 * - additional formats provided by extensions, e.g. RGB32F * - additional source formats, depending on browser details, used when uploading @@ -252,45 +256,33 @@ public: WebGLTexture *activeBoundTextureForTarget(WebGLenum target) { return target == LOCAL_GL_TEXTURE_2D ? mBound2DTextures[mActiveTexture] : mBoundCubeMapTextures[mActiveTexture]; } already_AddRefed<CanvasLayer> GetCanvasLayer(nsDisplayListBuilder* aBuilder, CanvasLayer *aOldLayer, LayerManager *aManager); - - // Note that 'clean' here refers to its invalidation state, not the - // contents of the buffer. void MarkContextClean() { mInvalidated = false; } - gl::GLContext* GL() const { - return gl; - } - - bool IsPremultAlpha() const { - return mOptions.premultipliedAlpha; - } - - bool PresentScreenBuffer(); - // a number that increments every time we have an event that causes // all context resources to be lost. uint32_t Generation() { return mGeneration.value(); } const WebGLRectangleObject *FramebufferRectangleObject() const; - // This is similar to GLContext::ClearSafely, but tries to minimize the - // amount of work it does. - // It only clears the buffers we specify, and can reset its state without - // first having to query anything, as WebGL knows its state at all times. - void ForceClearFramebufferWithDefaultValues(GLbitfield mask); + // this is similar to GLContext::ClearSafely, but is more comprehensive + // (takes care of scissor, stencil write mask, dithering, viewport...) + // WebGL has more complex needs than GLContext as content controls GL state. + void ForceClearFramebufferWithDefaultValues(uint32_t mask, const nsIntRect& viewportRect); - // Calls ForceClearFramebufferWithDefaultValues() for the Context's 'screen'. - void ClearScreen(); + // if the preserveDrawingBuffer context option is false, we need to clear the back buffer + // after it's been presented to the compositor. This function does that if needed. + // See section 2.2 in the WebGL spec. + void EnsureBackbufferClearedAsNeeded(); // checks for GL errors, clears any pending GL error, stores the current GL error in currentGLError, // and copies it into mWebGLError if it doesn't already have an error set void UpdateWebGLErrorAndClearGLError(GLenum *currentGLError) { // get and clear GL error in ALL cases *currentGLError = gl->GetAndClearError(); // only store in mWebGLError if is hasn't already recorded an error if (!mWebGLError) @@ -847,18 +839,16 @@ protected: bool mResetLayer; bool mOptionsFrozen; bool mMinCapability; bool mDisableExtensions; bool mHasRobustness; bool mIsMesa; bool mLoseContextOnHeapMinimize; bool mCanLoseContextInForeground; - bool mShouldPresent; - bool mIsScreenCleared; template<typename WebGLObjectType> void DeleteWebGLObjectsArray(nsTArray<WebGLObjectType>& array); WebGLuint mActiveTexture; WebGLenum mWebGLError; // whether shader validation is supported @@ -1111,16 +1101,18 @@ protected: realGLboolean mColorWriteMask[4]; realGLboolean mDepthWriteMask; realGLboolean mScissorTestEnabled; realGLboolean mDitherEnabled; WebGLfloat mColorClearValue[4]; WebGLint mStencilClearValue; WebGLfloat mDepthClearValue; + int mBackbufferClearingStatus; + nsCOMPtr<nsITimer> mContextRestorer; bool mAllowRestore; bool mContextLossTimerRunning; bool mDrawSinceContextLossTimerSet; ContextStatus mContextStatus; bool mContextLostErrorSet; int mAlreadyGeneratedWarnings;
--- a/content/canvas/src/WebGLContextGL.cpp +++ b/content/canvas/src/WebGLContextGL.cpp @@ -166,17 +166,17 @@ WebGLContext::BindFramebuffer(WebGLenum // silently ignore a deleted frame buffer if (wfb && wfb->IsDeleted()) return; MakeContextCurrent(); if (!wfb) { - gl->fBindFramebuffer(target, 0); + gl->fBindFramebuffer(target, gl->GetOffscreenFBO()); } else { WebGLuint framebuffername = wfb->GLName(); gl->fBindFramebuffer(target, framebuffername); wfb->SetHasEverBeenBound(true); } mBoundFramebuffer = wfb; } @@ -570,62 +570,42 @@ WebGLContext::Clear(WebGLbitfield mask) return; MakeContextCurrent(); uint32_t m = mask & (LOCAL_GL_COLOR_BUFFER_BIT | LOCAL_GL_DEPTH_BUFFER_BIT | LOCAL_GL_STENCIL_BUFFER_BIT); if (mask != m) return ErrorInvalidValue("clear: invalid mask bits"); + bool needClearCallHere = true; + if (mBoundFramebuffer) { if (!mBoundFramebuffer->CheckAndInitializeRenderbuffers()) return ErrorInvalidFramebufferOperation("clear: incomplete framebuffer"); - - gl->fClear(mask); - return; - } - - // Ok, we're clearing the default framebuffer/screen. - - bool needsClear = true; - if (mIsScreenCleared) { - bool isClearRedundant = true; - if (mask & LOCAL_GL_COLOR_BUFFER_BIT) { - if (mColorClearValue[0] != 0.0f || - mColorClearValue[1] != 0.0f || - mColorClearValue[2] != 0.0f || - mColorClearValue[3] != 0.0f) - { - isClearRedundant = false; - } + } else { + // no FBO is bound, so we are clearing the backbuffer here + EnsureBackbufferClearedAsNeeded(); + bool valuesAreDefault = mColorClearValue[0] == 0.0f && + mColorClearValue[1] == 0.0f && + mColorClearValue[2] == 0.0f && + mColorClearValue[3] == 0.0f && + mDepthClearValue == 1.0f && + mStencilClearValue == 0; + if (valuesAreDefault && + mBackbufferClearingStatus == BackbufferClearingStatus::ClearedToDefaultValues) + { + needClearCallHere = false; } - - if (mask & LOCAL_GL_DEPTH_BUFFER_BIT) { - if (mDepthClearValue != 1.0f) { - isClearRedundant = false; - } - } - - if (mask & LOCAL_GL_DEPTH_BUFFER_BIT) { - if (mStencilClearValue != 0) { - isClearRedundant = false; - } - } - - if (isClearRedundant) - needsClear = false; } - if (needsClear) { + if (needClearCallHere) { gl->fClear(mask); - mIsScreenCleared = false; + mBackbufferClearingStatus = BackbufferClearingStatus::HasBeenDrawnTo; + Invalidate(); } - - Invalidate(); - mShouldPresent = true; } void WebGLContext::ClearColor(WebGLclampf r, WebGLclampf g, WebGLclampf b, WebGLclampf a) { if (!IsContextStable()) return; @@ -830,17 +810,17 @@ WebGLContext::CopyTexImage2D(WebGLenum t is_pot_assuming_nonnegative(height))) return ErrorInvalidValue("copyTexImage2D: with level > 0, width and height must be powers of two"); } bool texFormatRequiresAlpha = internalformat == LOCAL_GL_RGBA || internalformat == LOCAL_GL_ALPHA || internalformat == LOCAL_GL_LUMINANCE_ALPHA; bool fboFormatHasAlpha = mBoundFramebuffer ? mBoundFramebuffer->ColorAttachment().HasAlpha() - : bool(gl->GetPixelFormat().alpha > 0); + : bool(gl->ActualFormat().alpha > 0); if (texFormatRequiresAlpha && !fboFormatHasAlpha) return ErrorInvalidOperation("copyTexImage2D: texture format requires an alpha channel " "but the framebuffer doesn't have one"); if (internalformat == LOCAL_GL_DEPTH_COMPONENT || internalformat == LOCAL_GL_DEPTH_STENCIL) return ErrorInvalidOperation("copyTexImage2D: a base internal format of DEPTH_COMPONENT or DEPTH_STENCIL isn't supported"); @@ -940,17 +920,17 @@ WebGLContext::CopyTexSubImage2D(WebGLenu if (yoffset + height > texHeight || yoffset + height < 0) return ErrorInvalidValue("copyTexSubImage2D: yoffset+height is too large"); WebGLenum format = imageInfo.Format(); bool texFormatRequiresAlpha = format == LOCAL_GL_RGBA || format == LOCAL_GL_ALPHA || format == LOCAL_GL_LUMINANCE_ALPHA; bool fboFormatHasAlpha = mBoundFramebuffer ? mBoundFramebuffer->ColorAttachment().HasAlpha() - : bool(gl->GetPixelFormat().alpha > 0); + : bool(gl->ActualFormat().alpha > 0); if (texFormatRequiresAlpha && !fboFormatHasAlpha) return ErrorInvalidOperation("copyTexSubImage2D: texture format requires an alpha channel " "but the framebuffer doesn't have one"); if (format == LOCAL_GL_DEPTH_COMPONENT || format == LOCAL_GL_DEPTH_STENCIL) return ErrorInvalidOperation("copyTexSubImage2D: a base internal format of DEPTH_COMPONENT or DEPTH_STENCIL isn't supported"); @@ -1455,33 +1435,32 @@ WebGLContext::DrawArrays(GLenum mode, We if (checked_firstPlusCount.value() > maxAllowedCount) return ErrorInvalidOperation("drawArrays: bound vertex attribute buffers do not have sufficient size for given first and count"); MakeContextCurrent(); if (mBoundFramebuffer) { if (!mBoundFramebuffer->CheckAndInitializeRenderbuffers()) return ErrorInvalidFramebufferOperation("drawArrays: incomplete framebuffer"); + } else { + EnsureBackbufferClearedAsNeeded(); } BindFakeBlackTextures(); if (!DoFakeVertexAttrib0(checked_firstPlusCount.value())) return; SetupContextLossTimer(); gl->fDrawArrays(mode, first, count); UndoFakeVertexAttrib0(); UnbindFakeBlackTextures(); - if (!mBoundFramebuffer) { - Invalidate(); - mShouldPresent = true; - mIsScreenCleared = false; - } + mBackbufferClearingStatus = BackbufferClearingStatus::HasBeenDrawnTo; + Invalidate(); } void WebGLContext::DrawElements(WebGLenum mode, WebGLsizei count, WebGLenum type, WebGLintptr byteOffset) { if (!IsContextStable()) return; @@ -1549,33 +1528,32 @@ WebGLContext::DrawElements(WebGLenum mod "size for given indices from the bound element array"); } MakeContextCurrent(); if (mBoundFramebuffer) { if (!mBoundFramebuffer->CheckAndInitializeRenderbuffers()) return ErrorInvalidFramebufferOperation("drawElements: incomplete framebuffer"); + } else { + EnsureBackbufferClearedAsNeeded(); } BindFakeBlackTextures(); if (!DoFakeVertexAttrib0(maxAllowedCount)) return; SetupContextLossTimer(); gl->fDrawElements(mode, count, type, reinterpret_cast<GLvoid*>(byteOffset)); UndoFakeVertexAttrib0(); UnbindFakeBlackTextures(); - if (!mBoundFramebuffer) { - Invalidate(); - mShouldPresent = true; - mIsScreenCleared = false; - } + mBackbufferClearingStatus = BackbufferClearingStatus::HasBeenDrawnTo; + Invalidate(); } void WebGLContext::Enable(WebGLenum cap) { if (!IsContextStable()) return; @@ -3349,17 +3327,17 @@ WebGLContext::ReadPixels(WebGLint x, Web // GL_ALPHA to readpixels currently, but we had the code written for it already. if (format == LOCAL_GL_ALPHA || format == LOCAL_GL_RGBA) { bool needAlphaFixup; if (mBoundFramebuffer) { needAlphaFixup = !mBoundFramebuffer->ColorAttachment().HasAlpha(); } else { - needAlphaFixup = gl->GetPixelFormat().alpha == 0; + needAlphaFixup = gl->ActualFormat().alpha == 0; } if (needAlphaFixup) { if (format == LOCAL_GL_ALPHA && type == LOCAL_GL_UNSIGNED_BYTE) { // this is easy; it's an 0xff memset per row uint8_t *row = static_cast<uint8_t*>(data); for (GLint j = 0; j < height; ++j) { memset(row, 0xff, checked_plainRowSize.value());
--- a/content/canvas/src/WebGLFramebuffer.cpp +++ b/content/canvas/src/WebGLFramebuffer.cpp @@ -347,17 +347,17 @@ WebGLFramebuffer::CheckAndInitializeRend } if (mStencilAttachment.HasUninitializedRenderbuffer() || mDepthStencilAttachment.HasUninitializedRenderbuffer()) { mask |= LOCAL_GL_STENCIL_BUFFER_BIT; } - mContext->ForceClearFramebufferWithDefaultValues(mask); + mContext->ForceClearFramebufferWithDefaultValues(mask, nsIntRect(0, 0, rect->Width(), rect->Height())); if (mColorAttachment.HasUninitializedRenderbuffer()) mColorAttachment.Renderbuffer()->SetInitialized(true); if (mDepthAttachment.HasUninitializedRenderbuffer()) mDepthAttachment.Renderbuffer()->SetInitialized(true); if (mStencilAttachment.HasUninitializedRenderbuffer())
--- a/content/canvas/test/reftest/reftest.list +++ b/content/canvas/test/reftest/reftest.list @@ -6,192 +6,189 @@ pref(webgl.disabled,true) == webgl-disable-test.html wrapper.html?green.png # Basic WebGL tests: # Do we get pixels to the screen at all? # Try to just hit the different rendering paths here. # Test: {aa, alpha, preserve, readback} = 16 == webgl-clear-test.html?nogl wrapper.html?green.png - == webgl-clear-test.html?__&_____&________ wrapper.html?green.png - == webgl-clear-test.html?aa&_____&________ wrapper.html?green.png -fuzzy-if(B2G,256,83) == webgl-clear-test.html?__&alpha&________ wrapper.html?green.png -fuzzy-if(B2G,256,83) == webgl-clear-test.html?aa&alpha&________ wrapper.html?green.png - == webgl-clear-test.html?__&_____&preserve wrapper.html?green.png - == webgl-clear-test.html?aa&_____&preserve wrapper.html?green.png -fuzzy-if(B2G,256,83) == webgl-clear-test.html?__&alpha&preserve wrapper.html?green.png -fuzzy-if(B2G,256,83) == webgl-clear-test.html?aa&alpha&preserve wrapper.html?green.png +== webgl-clear-test.html?__&_____&________ wrapper.html?green.png +== webgl-clear-test.html?aa&_____&________ wrapper.html?green.png +== webgl-clear-test.html?__&alpha&________ wrapper.html?green.png +== webgl-clear-test.html?aa&alpha&________ wrapper.html?green.png +== webgl-clear-test.html?__&_____&preserve wrapper.html?green.png +== webgl-clear-test.html?aa&_____&preserve wrapper.html?green.png +== webgl-clear-test.html?__&alpha&preserve wrapper.html?green.png +== webgl-clear-test.html?aa&alpha&preserve wrapper.html?green.png -pref(webgl.force-layers-readback,true) == webgl-clear-test.html?readback&__&_____&________ wrapper.html?green.png -pref(webgl.force-layers-readback,true) == webgl-clear-test.html?readback&aa&_____&________ wrapper.html?green.png -pref(webgl.force-layers-readback,true) fuzzy-if(B2G,256,83) == webgl-clear-test.html?readback&__&alpha&________ wrapper.html?green.png -pref(webgl.force-layers-readback,true) fuzzy-if(B2G,256,83) == webgl-clear-test.html?readback&aa&alpha&________ wrapper.html?green.png -pref(webgl.force-layers-readback,true) == webgl-clear-test.html?readback&__&_____&preserve wrapper.html?green.png -pref(webgl.force-layers-readback,true) == webgl-clear-test.html?readback&aa&_____&preserve wrapper.html?green.png -pref(webgl.force-layers-readback,true) fuzzy-if(B2G,256,83) == webgl-clear-test.html?readback&__&alpha&preserve wrapper.html?green.png -pref(webgl.force-layers-readback,true) fuzzy-if(B2G,256,83) == webgl-clear-test.html?readback&aa&alpha&preserve wrapper.html?green.png +pref(webgl.force-layers-readback,true) fails-if(nativeFennec) == webgl-clear-test.html?readback&__&_____&________ wrapper.html?green.png +pref(webgl.force-layers-readback,true) fails-if(nativeFennec) == webgl-clear-test.html?readback&aa&_____&________ wrapper.html?green.png +pref(webgl.force-layers-readback,true) == webgl-clear-test.html?readback&__&alpha&________ wrapper.html?green.png +pref(webgl.force-layers-readback,true) == webgl-clear-test.html?readback&aa&alpha&________ wrapper.html?green.png +pref(webgl.force-layers-readback,true) fails-if(nativeFennec) == webgl-clear-test.html?readback&__&_____&preserve wrapper.html?green.png +pref(webgl.force-layers-readback,true) fails-if(nativeFennec) == webgl-clear-test.html?readback&aa&_____&preserve wrapper.html?green.png +pref(webgl.force-layers-readback,true) == webgl-clear-test.html?readback&__&alpha&preserve wrapper.html?green.png +pref(webgl.force-layers-readback,true) == webgl-clear-test.html?readback&aa&alpha&preserve wrapper.html?green.png # Check orientation: == webgl-orientation-test.html?nogl wrapper.html?white-top-left.png - == webgl-orientation-test.html?__&_____&________ wrapper.html?white-top-left.png - == webgl-orientation-test.html?aa&_____&________ wrapper.html?white-top-left.png -fuzzy-if(B2G,256,83) == webgl-orientation-test.html?__&alpha&________ wrapper.html?white-top-left.png -fuzzy-if(B2G,256,83) == webgl-orientation-test.html?aa&alpha&________ wrapper.html?white-top-left.png - == webgl-orientation-test.html?__&_____&preserve wrapper.html?white-top-left.png - == webgl-orientation-test.html?aa&_____&preserve wrapper.html?white-top-left.png -fuzzy-if(B2G,256,83) == webgl-orientation-test.html?__&alpha&preserve wrapper.html?white-top-left.png -fuzzy-if(B2G,256,83) == webgl-orientation-test.html?aa&alpha&preserve wrapper.html?white-top-left.png +== webgl-orientation-test.html?__&_____&________ wrapper.html?white-top-left.png +== webgl-orientation-test.html?aa&_____&________ wrapper.html?white-top-left.png +== webgl-orientation-test.html?__&alpha&________ wrapper.html?white-top-left.png +== webgl-orientation-test.html?aa&alpha&________ wrapper.html?white-top-left.png +== webgl-orientation-test.html?__&_____&preserve wrapper.html?white-top-left.png +== webgl-orientation-test.html?aa&_____&preserve wrapper.html?white-top-left.png +== webgl-orientation-test.html?__&alpha&preserve wrapper.html?white-top-left.png +== webgl-orientation-test.html?aa&alpha&preserve wrapper.html?white-top-left.png -pref(webgl.force-layers-readback,true) == webgl-orientation-test.html?readback&__&_____&________ wrapper.html?white-top-left.png -pref(webgl.force-layers-readback,true) == webgl-orientation-test.html?readback&aa&_____&________ wrapper.html?white-top-left.png -pref(webgl.force-layers-readback,true) fuzzy-if(B2G,256,83) == webgl-orientation-test.html?readback&__&alpha&________ wrapper.html?white-top-left.png -pref(webgl.force-layers-readback,true) fuzzy-if(B2G,256,83) == webgl-orientation-test.html?readback&aa&alpha&________ wrapper.html?white-top-left.png -pref(webgl.force-layers-readback,true) == webgl-orientation-test.html?readback&__&_____&preserve wrapper.html?white-top-left.png -pref(webgl.force-layers-readback,true) == webgl-orientation-test.html?readback&aa&_____&preserve wrapper.html?white-top-left.png -pref(webgl.force-layers-readback,true) fuzzy-if(B2G,256,83) == webgl-orientation-test.html?readback&__&alpha&preserve wrapper.html?white-top-left.png -pref(webgl.force-layers-readback,true) fuzzy-if(B2G,256,83) == webgl-orientation-test.html?readback&aa&alpha&preserve wrapper.html?white-top-left.png +pref(webgl.force-layers-readback,true) fails-if(nativeFennec) == webgl-orientation-test.html?readback&__&_____&________ wrapper.html?white-top-left.png +pref(webgl.force-layers-readback,true) fails-if(nativeFennec) == webgl-orientation-test.html?readback&aa&_____&________ wrapper.html?white-top-left.png +pref(webgl.force-layers-readback,true) == webgl-orientation-test.html?readback&__&alpha&________ wrapper.html?white-top-left.png +pref(webgl.force-layers-readback,true) == webgl-orientation-test.html?readback&aa&alpha&________ wrapper.html?white-top-left.png +pref(webgl.force-layers-readback,true) fails-if(nativeFennec) == webgl-orientation-test.html?readback&__&_____&preserve wrapper.html?white-top-left.png +pref(webgl.force-layers-readback,true) fails-if(nativeFennec) == webgl-orientation-test.html?readback&aa&_____&preserve wrapper.html?white-top-left.png +pref(webgl.force-layers-readback,true) == webgl-orientation-test.html?readback&__&alpha&preserve wrapper.html?white-top-left.png +pref(webgl.force-layers-readback,true) == webgl-orientation-test.html?readback&aa&alpha&preserve wrapper.html?white-top-left.png # Does we draw the correct color in the correct places with all context creation options? # (Note that our context creation option matrix is 2^6 = 64) == webgl-color-test.html?nogl wrapper.html?colors.png - == webgl-color-test.html?__&_____&_____&_______&________&_______ wrapper.html?colors.png - == webgl-color-test.html?aa&_____&_____&_______&________&_______ wrapper.html?colors.png -fuzzy-if(B2G,256,83) == webgl-color-test.html?__&alpha&_____&_______&________&_______ wrapper.html?colors.png -fuzzy-if(B2G,256,83) == webgl-color-test.html?aa&alpha&_____&_______&________&_______ wrapper.html?colors.png - == webgl-color-test.html?__&_____&depth&_______&________&_______ wrapper.html?colors.png - == webgl-color-test.html?aa&_____&depth&_______&________&_______ wrapper.html?colors.png -fuzzy-if(B2G,256,83) == webgl-color-test.html?__&alpha&depth&_______&________&_______ wrapper.html?colors.png -fuzzy-if(B2G,256,83) == webgl-color-test.html?aa&alpha&depth&_______&________&_______ wrapper.html?colors.png - == webgl-color-test.html?__&_____&_____&premult&________&_______ wrapper.html?colors.png - == webgl-color-test.html?aa&_____&_____&premult&________&_______ wrapper.html?colors.png -fuzzy-if(B2G,256,83) == webgl-color-test.html?__&alpha&_____&premult&________&_______ wrapper.html?colors.png -fuzzy-if(B2G,256,83) == webgl-color-test.html?aa&alpha&_____&premult&________&_______ wrapper.html?colors.png - == webgl-color-test.html?__&_____&depth&premult&________&_______ wrapper.html?colors.png - == webgl-color-test.html?aa&_____&depth&premult&________&_______ wrapper.html?colors.png -fuzzy-if(B2G,256,83) == webgl-color-test.html?__&alpha&depth&premult&________&_______ wrapper.html?colors.png -fuzzy-if(B2G,256,83) == webgl-color-test.html?aa&alpha&depth&premult&________&_______ wrapper.html?colors.png +== webgl-color-test.html?__&_____&_____&_______&________&_______ wrapper.html?colors.png +== webgl-color-test.html?aa&_____&_____&_______&________&_______ wrapper.html?colors.png +== webgl-color-test.html?__&alpha&_____&_______&________&_______ wrapper.html?colors.png +== webgl-color-test.html?aa&alpha&_____&_______&________&_______ wrapper.html?colors.png +== webgl-color-test.html?__&_____&depth&_______&________&_______ wrapper.html?colors.png +== webgl-color-test.html?aa&_____&depth&_______&________&_______ wrapper.html?colors.png +== webgl-color-test.html?__&alpha&depth&_______&________&_______ wrapper.html?colors.png +== webgl-color-test.html?aa&alpha&depth&_______&________&_______ wrapper.html?colors.png +== webgl-color-test.html?__&_____&_____&premult&________&_______ wrapper.html?colors.png +== webgl-color-test.html?aa&_____&_____&premult&________&_______ wrapper.html?colors.png +== webgl-color-test.html?__&alpha&_____&premult&________&_______ wrapper.html?colors.png +== webgl-color-test.html?aa&alpha&_____&premult&________&_______ wrapper.html?colors.png +== webgl-color-test.html?__&_____&depth&premult&________&_______ wrapper.html?colors.png +== webgl-color-test.html?aa&_____&depth&premult&________&_______ wrapper.html?colors.png +== webgl-color-test.html?__&alpha&depth&premult&________&_______ wrapper.html?colors.png +== webgl-color-test.html?aa&alpha&depth&premult&________&_______ wrapper.html?colors.png - == webgl-color-test.html?__&_____&_____&_______&preserve&_______ wrapper.html?colors.png - == webgl-color-test.html?aa&_____&_____&_______&preserve&_______ wrapper.html?colors.png -fuzzy-if(B2G,256,83) == webgl-color-test.html?__&alpha&_____&_______&preserve&_______ wrapper.html?colors.png -fuzzy-if(B2G,256,83) == webgl-color-test.html?aa&alpha&_____&_______&preserve&_______ wrapper.html?colors.png - == webgl-color-test.html?__&_____&depth&_______&preserve&_______ wrapper.html?colors.png - == webgl-color-test.html?aa&_____&depth&_______&preserve&_______ wrapper.html?colors.png -fuzzy-if(B2G,256,83) == webgl-color-test.html?__&alpha&depth&_______&preserve&_______ wrapper.html?colors.png -fuzzy-if(B2G,256,83) == webgl-color-test.html?aa&alpha&depth&_______&preserve&_______ wrapper.html?colors.png - == webgl-color-test.html?__&_____&_____&premult&preserve&_______ wrapper.html?colors.png - == webgl-color-test.html?aa&_____&_____&premult&preserve&_______ wrapper.html?colors.png -fuzzy-if(B2G,256,83) == webgl-color-test.html?__&alpha&_____&premult&preserve&_______ wrapper.html?colors.png -fuzzy-if(B2G,256,83) == webgl-color-test.html?aa&alpha&_____&premult&preserve&_______ wrapper.html?colors.png - == webgl-color-test.html?__&_____&depth&premult&preserve&_______ wrapper.html?colors.png - == webgl-color-test.html?aa&_____&depth&premult&preserve&_______ wrapper.html?colors.png -fails-if(B2G) == webgl-color-test.html?__&alpha&depth&premult&preserve&_______ wrapper.html?colors.png -fails-if(B2G) == webgl-color-test.html?aa&alpha&depth&premult&preserve&_______ wrapper.html?colors.png +== webgl-color-test.html?__&_____&_____&_______&preserve&_______ wrapper.html?colors.png +== webgl-color-test.html?aa&_____&_____&_______&preserve&_______ wrapper.html?colors.png +== webgl-color-test.html?__&alpha&_____&_______&preserve&_______ wrapper.html?colors.png +== webgl-color-test.html?aa&alpha&_____&_______&preserve&_______ wrapper.html?colors.png +== webgl-color-test.html?__&_____&depth&_______&preserve&_______ wrapper.html?colors.png +== webgl-color-test.html?aa&_____&depth&_______&preserve&_______ wrapper.html?colors.png +== webgl-color-test.html?__&alpha&depth&_______&preserve&_______ wrapper.html?colors.png +== webgl-color-test.html?aa&alpha&depth&_______&preserve&_______ wrapper.html?colors.png +== webgl-color-test.html?__&_____&_____&premult&preserve&_______ wrapper.html?colors.png +== webgl-color-test.html?aa&_____&_____&premult&preserve&_______ wrapper.html?colors.png +== webgl-color-test.html?__&alpha&_____&premult&preserve&_______ wrapper.html?colors.png +== webgl-color-test.html?aa&alpha&_____&premult&preserve&_______ wrapper.html?colors.png +== webgl-color-test.html?__&_____&depth&premult&preserve&_______ wrapper.html?colors.png +== webgl-color-test.html?aa&_____&depth&premult&preserve&_______ wrapper.html?colors.png +== webgl-color-test.html?__&alpha&depth&premult&preserve&_______ wrapper.html?colors.png +== webgl-color-test.html?aa&alpha&depth&premult&preserve&_______ wrapper.html?colors.png - == webgl-color-test.html?__&_____&_____&_______&________&stencil wrapper.html?colors.png - == webgl-color-test.html?aa&_____&_____&_______&________&stencil wrapper.html?colors.png -fuzzy-if(B2G,256,83) == webgl-color-test.html?__&alpha&_____&_______&________&stencil wrapper.html?colors.png -fails-if(B2G) == webgl-color-test.html?aa&alpha&_____&_______&________&stencil wrapper.html?colors.png - == webgl-color-test.html?__&_____&depth&_______&________&stencil wrapper.html?colors.png - == webgl-color-test.html?aa&_____&depth&_______&________&stencil wrapper.html?colors.png -fuzzy-if(B2G,256,83) == webgl-color-test.html?__&alpha&depth&_______&________&stencil wrapper.html?colors.png -fuzzy-if(B2G,256,83) == webgl-color-test.html?aa&alpha&depth&_______&________&stencil wrapper.html?colors.png - == webgl-color-test.html?__&_____&_____&premult&________&stencil wrapper.html?colors.png - == webgl-color-test.html?aa&_____&_____&premult&________&stencil wrapper.html?colors.png -fuzzy-if(B2G,256,83) == webgl-color-test.html?__&alpha&_____&premult&________&stencil wrapper.html?colors.png -fuzzy-if(B2G,256,83) == webgl-color-test.html?aa&alpha&_____&premult&________&stencil wrapper.html?colors.png - == webgl-color-test.html?__&_____&depth&premult&________&stencil wrapper.html?colors.png - == webgl-color-test.html?aa&_____&depth&premult&________&stencil wrapper.html?colors.png -fuzzy-if(B2G,256,83) == webgl-color-test.html?__&alpha&depth&premult&________&stencil wrapper.html?colors.png -fuzzy-if(B2G,256,83) == webgl-color-test.html?aa&alpha&depth&premult&________&stencil wrapper.html?colors.png +== webgl-color-test.html?__&_____&_____&_______&________&stencil wrapper.html?colors.png +== webgl-color-test.html?aa&_____&_____&_______&________&stencil wrapper.html?colors.png +== webgl-color-test.html?__&alpha&_____&_______&________&stencil wrapper.html?colors.png +== webgl-color-test.html?aa&alpha&_____&_______&________&stencil wrapper.html?colors.png +== webgl-color-test.html?__&_____&depth&_______&________&stencil wrapper.html?colors.png +== webgl-color-test.html?aa&_____&depth&_______&________&stencil wrapper.html?colors.png +== webgl-color-test.html?__&alpha&depth&_______&________&stencil wrapper.html?colors.png +== webgl-color-test.html?aa&alpha&depth&_______&________&stencil wrapper.html?colors.png +== webgl-color-test.html?__&_____&_____&premult&________&stencil wrapper.html?colors.png +== webgl-color-test.html?aa&_____&_____&premult&________&stencil wrapper.html?colors.png +== webgl-color-test.html?__&alpha&_____&premult&________&stencil wrapper.html?colors.png +== webgl-color-test.html?aa&alpha&_____&premult&________&stencil wrapper.html?colors.png +== webgl-color-test.html?__&_____&depth&premult&________&stencil wrapper.html?colors.png +== webgl-color-test.html?aa&_____&depth&premult&________&stencil wrapper.html?colors.png +== webgl-color-test.html?__&alpha&depth&premult&________&stencil wrapper.html?colors.png +== webgl-color-test.html?aa&alpha&depth&premult&________&stencil wrapper.html?colors.png - == webgl-color-test.html?__&_____&_____&_______&preserve&stencil wrapper.html?colors.png - == webgl-color-test.html?aa&_____&_____&_______&preserve&stencil wrapper.html?colors.png -fuzzy-if(B2G,256,83) == webgl-color-test.html?__&alpha&_____&_______&preserve&stencil wrapper.html?colors.png -fuzzy-if(B2G,256,83) == webgl-color-test.html?aa&alpha&_____&_______&preserve&stencil wrapper.html?colors.png - == webgl-color-test.html?__&_____&depth&_______&preserve&stencil wrapper.html?colors.png - == webgl-color-test.html?aa&_____&depth&_______&preserve&stencil wrapper.html?colors.png -fuzzy-if(B2G,256,83) == webgl-color-test.html?__&alpha&depth&_______&preserve&stencil wrapper.html?colors.png -fuzzy-if(B2G,256,83) == webgl-color-test.html?aa&alpha&depth&_______&preserve&stencil wrapper.html?colors.png - == webgl-color-test.html?__&_____&_____&premult&preserve&stencil wrapper.html?colors.png - == webgl-color-test.html?aa&_____&_____&premult&preserve&stencil wrapper.html?colors.png -fuzzy-if(B2G,256,83) == webgl-color-test.html?__&alpha&_____&premult&preserve&stencil wrapper.html?colors.png -fuzzy-if(B2G,256,83) == webgl-color-test.html?aa&alpha&_____&premult&preserve&stencil wrapper.html?colors.png - == webgl-color-test.html?__&_____&depth&premult&preserve&stencil wrapper.html?colors.png - == webgl-color-test.html?aa&_____&depth&premult&preserve&stencil wrapper.html?colors.png -fuzzy-if(B2G,256,83) == webgl-color-test.html?__&alpha&depth&premult&preserve&stencil wrapper.html?colors.png -fuzzy-if(B2G,256,83) == webgl-color-test.html?aa&alpha&depth&premult&preserve&stencil wrapper.html?colors.png +== webgl-color-test.html?__&_____&_____&_______&preserve&stencil wrapper.html?colors.png +== webgl-color-test.html?aa&_____&_____&_______&preserve&stencil wrapper.html?colors.png +== webgl-color-test.html?__&alpha&_____&_______&preserve&stencil wrapper.html?colors.png +== webgl-color-test.html?aa&alpha&_____&_______&preserve&stencil wrapper.html?colors.png +== webgl-color-test.html?__&_____&depth&_______&preserve&stencil wrapper.html?colors.png +== webgl-color-test.html?aa&_____&depth&_______&preserve&stencil wrapper.html?colors.png +== webgl-color-test.html?__&alpha&depth&_______&preserve&stencil wrapper.html?colors.png +== webgl-color-test.html?aa&alpha&depth&_______&preserve&stencil wrapper.html?colors.png +== webgl-color-test.html?__&_____&_____&premult&preserve&stencil wrapper.html?colors.png +== webgl-color-test.html?aa&_____&_____&premult&preserve&stencil wrapper.html?colors.png +== webgl-color-test.html?__&alpha&_____&premult&preserve&stencil wrapper.html?colors.png +== webgl-color-test.html?aa&alpha&_____&premult&preserve&stencil wrapper.html?colors.png +== webgl-color-test.html?__&_____&depth&premult&preserve&stencil wrapper.html?colors.png +== webgl-color-test.html?aa&_____&depth&premult&preserve&stencil wrapper.html?colors.png +== webgl-color-test.html?__&alpha&depth&premult&preserve&stencil wrapper.html?colors.png +== webgl-color-test.html?aa&alpha&depth&premult&preserve&stencil wrapper.html?colors.png # Check a smaller selection for readback: -pref(webgl.force-layers-readback,true) == webgl-color-test.html?readback&__&_____&________ wrapper.html?colors.png -pref(webgl.force-layers-readback,true) == webgl-color-test.html?readback&aa&_____&________ wrapper.html?colors.png -pref(webgl.force-layers-readback,true) fuzzy-if(B2G,256,83) == webgl-color-test.html?readback&__&alpha&________ wrapper.html?colors.png -pref(webgl.force-layers-readback,true) fuzzy-if(B2G,256,83) == webgl-color-test.html?readback&aa&alpha&________ wrapper.html?colors.png -pref(webgl.force-layers-readback,true) == webgl-color-test.html?readback&__&_____&preserve wrapper.html?colors.png -pref(webgl.force-layers-readback,true) == webgl-color-test.html?readback&aa&_____&preserve wrapper.html?colors.png -pref(webgl.force-layers-readback,true) fuzzy-if(B2G,256,83) == webgl-color-test.html?readback&__&alpha&preserve wrapper.html?colors.png -pref(webgl.force-layers-readback,true) fuzzy-if(B2G,256,83) == webgl-color-test.html?readback&aa&alpha&preserve wrapper.html?colors.png +pref(webgl.force-layers-readback,true) fails-if(nativeFennec) == webgl-color-test.html?readback&__&_____&________ wrapper.html?colors.png +pref(webgl.force-layers-readback,true) fails-if(nativeFennec) == webgl-color-test.html?readback&aa&_____&________ wrapper.html?colors.png +pref(webgl.force-layers-readback,true) == webgl-color-test.html?readback&__&alpha&________ wrapper.html?colors.png +pref(webgl.force-layers-readback,true) == webgl-color-test.html?readback&aa&alpha&________ wrapper.html?colors.png +pref(webgl.force-layers-readback,true) fails-if(nativeFennec) == webgl-color-test.html?readback&__&_____&preserve wrapper.html?colors.png +pref(webgl.force-layers-readback,true) fails-if(nativeFennec) == webgl-color-test.html?readback&aa&_____&preserve wrapper.html?colors.png +pref(webgl.force-layers-readback,true) == webgl-color-test.html?readback&__&alpha&preserve wrapper.html?colors.png +pref(webgl.force-layers-readback,true) == webgl-color-test.html?readback&aa&alpha&preserve wrapper.html?colors.png # Check alpha behavior: -fuzzy-if(B2G,256,83) == webgl-color-alpha-test.html?colorVal=1.0&alphaVal=1.0&nogl wrapper.html?colors.png -fuzzy-if(B2G,256,83) == webgl-color-alpha-test.html?colorVal=1.0&alphaVal=1.0 wrapper.html?colors.png -fuzzy-if(B2G,256,83) == webgl-color-alpha-test.html?colorVal=0.0&alphaVal=1.0&nogl wrapper.html?black.png -fuzzy-if(B2G,256,83) == webgl-color-alpha-test.html?colorVal=0.0&alphaVal=1.0 wrapper.html?black.png +== webgl-color-alpha-test.html?colorVal=1.0&alphaVal=1.0&nogl wrapper.html?colors.png +== webgl-color-alpha-test.html?colorVal=1.0&alphaVal=1.0 wrapper.html?colors.png +== webgl-color-alpha-test.html?colorVal=0.0&alphaVal=1.0&nogl wrapper.html?black.png +== webgl-color-alpha-test.html?colorVal=0.0&alphaVal=1.0 wrapper.html?black.png -fuzzy-if(B2G,256,83) == webgl-color-alpha-test.html?colorVal=1.0&alphaVal=0.0&nogl wrapper.html?colors.png -fuzzy-if(B2G,256,83) == webgl-color-alpha-test.html?colorVal=1.0&alphaVal=0.0 wrapper.html?colors.png -fuzzy-if(B2G,256,83) == webgl-color-alpha-test.html?colorVal=1.0&alphaVal=0.0&alpha&nogl wrapper.html?white.png -fails-if(B2G) == webgl-color-alpha-test.html?colorVal=1.0&alphaVal=0.0&alpha wrapper.html?white.png +== webgl-color-alpha-test.html?colorVal=1.0&alphaVal=0.0&nogl wrapper.html?colors.png +== webgl-color-alpha-test.html?colorVal=1.0&alphaVal=0.0 wrapper.html?colors.png +== webgl-color-alpha-test.html?colorVal=1.0&alphaVal=0.0&alpha&nogl wrapper.html?white.png +== webgl-color-alpha-test.html?colorVal=1.0&alphaVal=0.0&alpha wrapper.html?white.png -fuzzy(1,65536) fuzzy-if(B2G,256,83) fuzzy-if(Android||B2G,9,65536) == webgl-color-alpha-test.html?colorVal=0.5&alphaVal=1.0&nogl wrapper.html?half-colors.png -fuzzy(1,65536) fuzzy-if(B2G,256,83) fuzzy-if(Android||B2G,9,65536) == webgl-color-alpha-test.html?colorVal=0.5&alphaVal=1.0 wrapper.html?half-colors.png +fuzzy(1,65536) fuzzy-if(Android||B2G,9,65536) == webgl-color-alpha-test.html?colorVal=0.5&alphaVal=1.0&nogl wrapper.html?half-colors.png +fuzzy(1,65536) fuzzy-if(Android||B2G,9,65536) == webgl-color-alpha-test.html?colorVal=0.5&alphaVal=1.0 wrapper.html?half-colors.png # Test premult: -fuzzy(1,65536) fuzzy-if(B2G,256,83) fuzzy-if(Android||B2G,9,65536) == webgl-color-alpha-test.html?colorVal=1.0&alphaVal=0.5&alpha&nogl wrapper.html?colors-half-alpha.png -fuzzy(1,65536) fails-if(B2G) fuzzy-if(Android,9,65536) == webgl-color-alpha-test.html?colorVal=1.0&alphaVal=0.5&alpha wrapper.html?colors-half-alpha.png -fuzzy(1,65536) fuzzy-if(B2G,256,83) fuzzy-if(Android||B2G,9,65536) == webgl-color-alpha-test.html?colorVal=0.5&alphaVal=0.5&alpha&nogl wrapper.html?half-colors-half-alpha.png -fuzzy(1,65536) fails-if(B2G) fuzzy-if(Android,9,65536) fails-if(cocoaWidget||Android) == webgl-color-alpha-test.html?colorVal=0.5&alphaVal=0.5&alpha wrapper.html?half-colors-half-alpha.png -fuzzy(1,65536) fuzzy-if(B2G,256,83) fuzzy-if(Android||B2G,9,65536) == webgl-color-alpha-test.html?colorVal=0.5&alphaVal=0.5&alpha&premult&nogl wrapper.html?colors-half-alpha.png -fuzzy(1,65536) fails-if(B2G) fuzzy-if(Android,9,65536) == webgl-color-alpha-test.html?colorVal=0.5&alphaVal=0.5&alpha&premult wrapper.html?colors-half-alpha.png +fuzzy(1,65536) fuzzy-if(Android||B2G,9,65536) == webgl-color-alpha-test.html?colorVal=1.0&alphaVal=0.5&alpha&nogl wrapper.html?colors-half-alpha.png +fuzzy(1,65536) fuzzy-if(Android||B2G,9,65536) == webgl-color-alpha-test.html?colorVal=1.0&alphaVal=0.5&alpha wrapper.html?colors-half-alpha.png +fuzzy(1,65536) fuzzy-if(Android||B2G,9,65536) == webgl-color-alpha-test.html?colorVal=0.5&alphaVal=0.5&alpha&nogl wrapper.html?half-colors-half-alpha.png +fuzzy(1,65536) fuzzy-if(Android||B2G,9,65536) fails-if(cocoaWidget||Android) == webgl-color-alpha-test.html?colorVal=0.5&alphaVal=0.5&alpha wrapper.html?half-colors-half-alpha.png +fuzzy(1,65536) fuzzy-if(Android||B2G,9,65536) == webgl-color-alpha-test.html?colorVal=0.5&alphaVal=0.5&alpha&premult&nogl wrapper.html?colors-half-alpha.png +fuzzy(1,65536) fuzzy-if(Android||B2G,9,65536) == webgl-color-alpha-test.html?colorVal=0.5&alphaVal=0.5&alpha&premult wrapper.html?colors-half-alpha.png # Test over-bright premult: -fuzzy(1,65536) fuzzy-if(B2G,256,83) fuzzy-if(Android||B2G,9,65536) == webgl-color-alpha-test.html?colorVal=1.0&alphaVal=0.5&alpha&premult&nogl wrapper.html?colors-half-alpha.png -fuzzy(1,65536) fails-if(B2G) fuzzy-if(Android,9,65536) == webgl-color-alpha-test.html?colorVal=1.0&alphaVal=0.5&alpha&premult wrapper.html?colors-half-alpha.png +fuzzy(1,65536) fuzzy-if(Android||B2G,9,65536) == webgl-color-alpha-test.html?colorVal=1.0&alphaVal=0.5&alpha&premult&nogl wrapper.html?colors-half-alpha.png +fuzzy(1,65536) fuzzy-if(Android||B2G,9,65536) == webgl-color-alpha-test.html?colorVal=1.0&alphaVal=0.5&alpha&premult wrapper.html?colors-half-alpha.png # Check for hanging framebuffer bindings: == webgl-hanging-fb-test.html?nogl wrapper.html?green.png - == webgl-hanging-fb-test.html?__&________ wrapper.html?green.png - == webgl-hanging-fb-test.html?aa&________ wrapper.html?green.png -pref(webgl.force-layers-readback,true) == webgl-hanging-fb-test.html?__&readback wrapper.html?green.png -pref(webgl.force-layers-readback,true) == webgl-hanging-fb-test.html?aa&readback wrapper.html?green.png +== webgl-hanging-fb-test.html wrapper.html?green.png +== webgl-hanging-fb-test.html?aa wrapper.html?green.png +pref(webgl.force-layers-readback,true) fails-if(nativeFennec) == webgl-hanging-fb-test.html?readback wrapper.html?green.png +pref(webgl.force-layers-readback,true) fails-if(nativeFennec) == webgl-hanging-fb-test.html?readback&aa wrapper.html?green.png - == webgl-hanging-scissor-test.html?__&________ wrapper.html?green.png - == webgl-hanging-scissor-test.html?aa&________ wrapper.html?green.png -pref(webgl.force-layers-readback,true) == webgl-hanging-scissor-test.html?__&readback wrapper.html?green.png -pref(webgl.force-layers-readback,true) == webgl-hanging-scissor-test.html?aa&readback wrapper.html?green.png +== webgl-hanging-scissor-test.html wrapper.html?green.png +== webgl-hanging-scissor-test.html?aa wrapper.html?green.png +pref(webgl.force-layers-readback,true) fails-if(nativeFennec) == webgl-hanging-scissor-test.html?readback wrapper.html?green.png +pref(webgl.force-layers-readback,true) fails-if(nativeFennec) == webgl-hanging-scissor-test.html?readback&aa wrapper.html?green.png # Check that our experimental prefs still work: # 16bpp: -skip-if(winWidget) pref(webgl.prefer-16bpp,true) == webgl-color-test.html?16bpp wrapper.html?colors.png -skip-if(winWidget) pref(webgl.prefer-16bpp,true) pref(webgl.force-layers-readback,true) == webgl-color-test.html?16bpp&readback wrapper.html?colors.png +pref(webgl.prefer-16bpp,true) == webgl-color-test.html?16bpp wrapper.html?colors.png +pref(webgl.prefer-16bpp,true) pref(webgl.force-layers-readback,true) fails-if(nativeFennec) == webgl-color-test.html?16bpp&readback wrapper.html?colors.png # Force native GL (Windows): skip-if(!winWidget) pref(webgl.prefer-native-gl,true) == webgl-clear-test.html?native-gl wrapper.html?green.png skip-if(!winWidget) pref(webgl.prefer-native-gl,true) == webgl-orientation-test.html?native-gl wrapper.html?white-top-left.png skip-if(!winWidget) pref(webgl.prefer-native-gl,true) == webgl-color-test.html?native-gl wrapper.html?colors.png skip-if(!winWidget) pref(webgl.prefer-native-gl,true) pref(webgl.prefer-16bpp,true) == webgl-color-test.html?native-gl&16bpp wrapper.html?colors.png - -# Non-WebGL Reftests! - # Do we correctly handle multiple clip paths? != clip-multiple-paths.html clip-multiple-paths-badref.html # Bug 815648 == stroketext-shadow.html stroketext-shadow-ref.html
--- a/dom/bindings/test/test_integers.html +++ b/dom/bindings/test/test_integers.html @@ -18,23 +18,17 @@ // ints edge cases. try { var gl = $("c").getContext("experimental-webgl"); } catch (ex) { // No WebGL support on MacOS 10.5. Just skip this test todo(false, "WebGL not supported"); return; } - var error = gl.getError() - - // on the b2g emulator we get GL_INVALID_FRAMEBUFFER_OPERATION - if (error == 0x0506) // GL_INVALID_FRAMEBUFFER_OPERATION - return; - - is(error, 0, "Should not start in an error state"); + is(gl.getError(), 0, "Should not start in an error state"); var b = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, b); var a = new Float32Array(1); gl.bufferData(gl.ARRAY_BUFFER, a, gl.STATIC_DRAW); gl.bufferSubData(gl.ARRAY_BUFFER, arg, a);
--- a/dom/plugins/base/nsNPAPIPluginInstance.cpp +++ b/dom/plugins/base/nsNPAPIPluginInstance.cpp @@ -77,19 +77,17 @@ private: bool mCanceled; }; static nsRefPtr<GLContext> sPluginContext = nullptr; static bool EnsureGLContext() { if (!sPluginContext) { - gfxIntSize dummySize(16, 16); - GLContext::SurfaceCaps dummyCaps; - sPluginContext = GLContextProvider::CreateOffscreen(dummySize, dummyCaps); + sPluginContext = GLContextProvider::CreateOffscreen(gfxIntSize(16, 16)); } return sPluginContext != nullptr; } class SharedPluginTexture { public: NS_INLINE_DECL_REFCOUNTING(SharedPluginTexture)
--- a/gfx/gl/GLContext.cpp +++ b/gfx/gl/GLContext.cpp @@ -2,43 +2,50 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include <algorithm> #include <stdio.h> #include <string.h> +#include "mozilla/DebugOnly.h" + +#include "prlink.h" +#include "prenv.h" + +#include "nsThreadUtils.h" + +#include "gfxPlatform.h" #include "GLContext.h" +#include "GLContextProvider.h" #include "gfxCrashReporterUtils.h" -#include "gfxPlatform.h" #include "gfxUtils.h" -#include "GLContextProvider.h" + +#include "mozilla/Preferences.h" + #include "GLTextureImage.h" + #include "nsIMemoryReporter.h" -#include "nsThreadUtils.h" -#include "prenv.h" -#include "prlink.h" -#include "SurfaceStream.h" - -#include "mozilla/DebugOnly.h" -#include "mozilla/Preferences.h" using namespace mozilla::gfx; namespace mozilla { namespace gl { #ifdef DEBUG unsigned GLContext::sCurrentGLContextTLS = -1; #endif uint32_t GLContext::sDebugMode = 0; +// define this here since it's global to GLContextProvider, not any +// specific implementation +const ContextFormat ContextFormat::BasicRGBA32Format(ContextFormat::BasicRGBA32); #define MAX_SYMBOL_LENGTH 128 #define MAX_SYMBOL_NAMES 5 // should match the order of GLExtensions, and be null-terminated. static const char *sExtensionNames[] = { "GL_EXT_framebuffer_object", "GL_ARB_framebuffer_object", @@ -300,66 +307,58 @@ GLContext::InitWithPrefix(const char *pr if (!LoadSymbols(&symbols_desktop[0], trygl, prefix)) { NS_ERROR("Desktop symbols failed to load."); mInitialized = false; } } } - const char *glVendorString = nullptr; - const char *glRendererString = nullptr; + const char *glVendorString; + const char *glRendererString; if (mInitialized) { // The order of these strings must match up with the order of the enum // defined in GLContext.h for vendor IDs glVendorString = (const char *)fGetString(LOCAL_GL_VENDOR); - if (!glVendorString) - mInitialized = false; - const char *vendorMatchStrings[VendorOther] = { "Intel", "NVIDIA", "ATI", "Qualcomm", "Imagination", "nouveau" }; - mVendor = VendorOther; for (int i = 0; i < VendorOther; ++i) { if (DoesStringMatch(glVendorString, vendorMatchStrings[i])) { mVendor = i; break; } } // The order of these strings must match up with the order of the enum // defined in GLContext.h for renderer IDs glRendererString = (const char *)fGetString(LOCAL_GL_RENDERER); - if (!glRendererString) - mInitialized = false; - const char *rendererMatchStrings[RendererOther] = { "Adreno 200", "Adreno 205", "PowerVR SGX 530", - "PowerVR SGX 540" + "PowerVR SGX 540", + }; - mRenderer = RendererOther; for (int i = 0; i < RendererOther; ++i) { if (DoesStringMatch(glRendererString, rendererMatchStrings[i])) { mRenderer = i; break; } } } - #ifdef DEBUG if (PR_GetEnv("MOZ_GL_DEBUG")) sDebugMode |= DebugEnabled; // enables extra verbose output, informing of the start and finish of every GL call. // useful e.g. to record information to investigate graphics system crashes/lockups if (PR_GetEnv("MOZ_GL_DEBUG_VERBOSE")) sDebugMode |= DebugTrace; @@ -375,17 +374,16 @@ GLContext::InitWithPrefix(const char *pr if (firstRun && DebugMode()) { const char *vendors[VendorOther] = { "Intel", "NVIDIA", "ATI", "Qualcomm" }; - MOZ_ASSERT(glVendorString); if (mVendor < VendorOther) { printf_stderr("OpenGL vendor ('%s') recognized as: %s\n", glVendorString, vendors[mVendor]); } else { printf_stderr("OpenGL vendor ('%s') unrecognized\n", glVendorString); } } firstRun = false; @@ -451,19 +449,20 @@ GLContext::InitWithPrefix(const char *pr NS_ERROR("GL supports framebuffer_blit without supplying glBlitFramebuffer"); MarkExtensionUnsupported(ANGLE_framebuffer_blit); MarkExtensionUnsupported(EXT_framebuffer_blit); mSymbols.fBlitFramebuffer = nullptr; } } - if (SupportsFramebufferMultisample()) + if (SupportsOffscreenSplit() && + ( IsExtensionSupported(GLContext::ANGLE_framebuffer_multisample) || + IsExtensionSupported(GLContext::EXT_framebuffer_multisample) )) { - MOZ_ASSERT(SupportsSplitFramebuffer()); SymLoadStruct auxSymbols[] = { { (PRFuncPtr*) &mSymbols.fRenderbufferStorageMultisample, { "RenderbufferStorageMultisample", "RenderbufferStorageMultisampleEXT", "RenderbufferStorageMultisampleANGLE", nullptr @@ -504,26 +503,24 @@ GLContext::InitWithPrefix(const char *pr mSymbols.fGetInteger64v = nullptr; mSymbols.fGetSynciv = nullptr; } } if (IsExtensionSupported(OES_EGL_image)) { SymLoadStruct imageSymbols[] = { { (PRFuncPtr*) &mSymbols.fEGLImageTargetTexture2D, { "EGLImageTargetTexture2DOES", nullptr } }, - { (PRFuncPtr*) &mSymbols.fEGLImageTargetRenderbufferStorage, { "EGLImageTargetRenderbufferStorageOES", nullptr } }, { nullptr, { nullptr } }, }; if (!LoadSymbols(&imageSymbols[0], trygl, prefix)) { NS_ERROR("GL supports OES_EGL_image without supplying its functions."); MarkExtensionUnsupported(OES_EGL_image); mSymbols.fEGLImageTargetTexture2D = nullptr; - mSymbols.fEGLImageTargetRenderbufferStorage = nullptr; } } // Load developer symbols, don't fail if we can't find them. SymLoadStruct auxSymbols[] = { { (PRFuncPtr*) &mSymbols.fGetTexImage, { "GetTexImage", nullptr } }, { (PRFuncPtr*) &mSymbols.fGetTexLevelParameteriv, { "GetTexLevelParameteriv", nullptr } }, { nullptr, { nullptr } }, @@ -562,33 +559,17 @@ GLContext::InitWithPrefix(const char *pr // see bug 814716. Clamp MaxCubeMapTextureSize at 2K for Nouveau. mMaxCubeMapTextureSize = std::min(mMaxCubeMapTextureSize, 2048); mNeedsTextureSizeChecks = true; } #endif mMaxTextureImageSize = mMaxTextureSize; - mMaxSamples = 0; - if (SupportsFramebufferMultisample()) { - fGetIntegerv(LOCAL_GL_MAX_SAMPLES, (GLint*)&mMaxSamples); - } - - // We're ready for final setup. - InitFramebuffers(); - - if (mCaps.any) - DetermineCaps(); - - UpdatePixelFormat(); - UpdateGLFormats(mCaps); - - mTexGarbageBin = new TextureGarbageBin(this); - - MOZ_ASSERT(IsCurrent()); + UpdateActualFormat(); } if (mInitialized) reporter.SetSuccessful(); else { // if initialization fails, ensure all symbols are zero, to avoid hard-to-understand bugs mSymbols.Zero(); NS_WARNING("InitWithPrefix failed!"); @@ -836,182 +817,148 @@ void GLContext::ApplyFilterToBoundTextur fTexParameteri(aTarget, LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_NEAREST); } else { fTexParameteri(aTarget, LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_LINEAR); fTexParameteri(aTarget, LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_LINEAR); } } -void -GLContext::DetermineCaps() -{ - PixelBufferFormat format = QueryPixelFormat(); - - SurfaceCaps caps; - caps.color = !!format.red && !!format.green && !!format.blue; - caps.bpp16 = caps.color && format.ColorBits() == 16; - caps.alpha = !!format.alpha; - caps.depth = !!format.depth; - caps.stencil = !!format.stencil; - caps.antialias = format.samples > 1; - caps.preserve = true; - - mCaps = caps; -} - -PixelBufferFormat -GLContext::QueryPixelFormat() -{ - PixelBufferFormat format; - - ScopedBindFramebuffer autoFB(this, 0); - - fGetIntegerv(LOCAL_GL_RED_BITS , &format.red ); - fGetIntegerv(LOCAL_GL_GREEN_BITS, &format.green); - fGetIntegerv(LOCAL_GL_BLUE_BITS , &format.blue ); - fGetIntegerv(LOCAL_GL_ALPHA_BITS, &format.alpha); - - fGetIntegerv(LOCAL_GL_DEPTH_BITS, &format.depth); - fGetIntegerv(LOCAL_GL_STENCIL_BITS, &format.stencil); - - fGetIntegerv(LOCAL_GL_SAMPLES, &format.samples); - - return format; -} - -void -GLContext::UpdatePixelFormat() -{ - PixelBufferFormat format = QueryPixelFormat(); -#ifdef DEBUG - const SurfaceCaps& caps = Caps(); - MOZ_ASSERT(caps.color == !!format.red); - MOZ_ASSERT(caps.color == !!format.green); - MOZ_ASSERT(caps.color == !!format.blue); - MOZ_ASSERT(caps.alpha == !!format.alpha); - MOZ_ASSERT(caps.depth == !!format.depth); - MOZ_ASSERT(caps.stencil == !!format.stencil); - MOZ_ASSERT(caps.antialias == (format.samples > 1)); -#endif - mPixelFormat = new PixelBufferFormat(format); -} - -GLFormats -GLContext::ChooseGLFormats(const SurfaceCaps& caps) const +GLContext::GLFormats +GLContext::ChooseGLFormats(ContextFormat& aCF, ColorByteOrder aByteOrder) { GLFormats formats; // If we're on ES2 hardware and we have an explicit request for 16 bits of color or less // OR we don't support full 8-bit color, return a 4444 or 565 format. - bool bpp16 = caps.bpp16; - if (mIsGLES2) { - if (!IsExtensionSupported(OES_rgb8_rgba8)) - bpp16 = true; + if (mIsGLES2 && (aCF.colorBits() <= 16 || !IsExtensionSupported(OES_rgb8_rgba8))) { + if (aCF.alpha) { + formats.texColor = LOCAL_GL_RGBA; + formats.texColorType = LOCAL_GL_UNSIGNED_SHORT_4_4_4_4; + formats.rbColor = LOCAL_GL_RGBA4; + + aCF.red = aCF.green = aCF.blue = aCF.alpha = 4; + } else { + formats.texColor = LOCAL_GL_RGB; + formats.texColorType = LOCAL_GL_UNSIGNED_SHORT_5_6_5; + formats.rbColor = LOCAL_GL_RGB565; + + aCF.red = 5; + aCF.green = 6; + aCF.blue = 5; + aCF.alpha = 0; + } } else { - // RGB565 is uncommon on desktop, requiring ARB_ES2_compatibility. - // Since it's also vanishingly useless there, let's not support it. - bpp16 = false; - } + formats.texColorType = LOCAL_GL_UNSIGNED_BYTE; - if (bpp16) { - MOZ_ASSERT(mIsGLES2); - if (caps.alpha) { - formats.color_texInternalFormat = LOCAL_GL_RGBA; - formats.color_texFormat = LOCAL_GL_RGBA; - formats.color_texType = LOCAL_GL_UNSIGNED_SHORT_4_4_4_4; - formats.color_rbFormat = LOCAL_GL_RGBA4; + if (aCF.alpha) { + // Prefer BGRA8888 on ES2 hardware; if the extension is supported, it + // should be faster. There are some cases where we don't want this -- + // specifically, CopyTex*Image doesn't seem to understand how to deal + // with a BGRA source going to a RGB/RGBA destination on some drivers. + if (mIsGLES2 && + IsExtensionSupported(EXT_texture_format_BGRA8888) && + aByteOrder != ForceRGBA) + { + formats.texColor = LOCAL_GL_BGRA; + } else { + formats.texColor = LOCAL_GL_RGBA; + } + + formats.rbColor = LOCAL_GL_RGBA8; + + aCF.red = aCF.green = aCF.blue = aCF.alpha = 8; } else { - formats.color_texInternalFormat = LOCAL_GL_RGB; - formats.color_texFormat = LOCAL_GL_RGB; - formats.color_texType = LOCAL_GL_UNSIGNED_SHORT_5_6_5; - formats.color_rbFormat = LOCAL_GL_RGB565; - } - } else { - formats.color_texType = LOCAL_GL_UNSIGNED_BYTE; + formats.texColor = LOCAL_GL_RGB; + formats.rbColor = LOCAL_GL_RGB8; - if (caps.alpha) { - formats.color_texInternalFormat = mIsGLES2 ? LOCAL_GL_RGBA : LOCAL_GL_RGBA8; - formats.color_texFormat = LOCAL_GL_RGBA; - formats.color_rbFormat = LOCAL_GL_RGBA8; - } else { - formats.color_texInternalFormat = mIsGLES2 ? LOCAL_GL_RGB : LOCAL_GL_RGB8; - formats.color_texFormat = LOCAL_GL_RGB; - formats.color_rbFormat = LOCAL_GL_RGB8; + aCF.red = aCF.green = aCF.blue = 8; + aCF.alpha = 0; } } - uint32_t msaaLevel = Preferences::GetUint("gl.msaa-level", 2); - GLsizei samples = msaaLevel * msaaLevel; - samples = std::min(samples, mMaxSamples); + GLsizei samples = aCF.samples; - // Bug 778765. + GLsizei maxSamples = 0; + if (SupportsFramebufferMultisample()) + fGetIntegerv(LOCAL_GL_MAX_SAMPLES, (GLint*)&maxSamples); + samples = std::min(samples, maxSamples); + + // bug 778765 if (WorkAroundDriverBugs() && samples == 1) { samples = 0; } + formats.samples = samples; + aCF.samples = samples; - // Be clear that these are 0 if unavailable. + const int depth = aCF.depth; + const int stencil = aCF.stencil; + const bool useDepthStencil = + !mIsGLES2 || IsExtensionSupported(OES_packed_depth_stencil); + formats.depthStencil = 0; - if (!mIsGLES2 || IsExtensionSupported(OES_packed_depth_stencil)) { - formats.depthStencil = LOCAL_GL_DEPTH24_STENCIL8; - } - formats.depth = 0; - if (mIsGLES2) { - if (IsExtensionSupported(OES_depth24)) { - formats.depth = LOCAL_GL_DEPTH_COMPONENT24; - } else { - formats.depth = LOCAL_GL_DEPTH_COMPONENT16; + formats.stencil = 0; + if (depth && stencil && useDepthStencil) { + formats.depthStencil = LOCAL_GL_DEPTH24_STENCIL8; + aCF.depth = 24; + aCF.stencil = 8; + } else { + if (depth) { + if (mIsGLES2) { + if (IsExtensionSupported(OES_depth24)) { + formats.depth = LOCAL_GL_DEPTH_COMPONENT24; + aCF.depth = 24; + } else { + formats.depth = LOCAL_GL_DEPTH_COMPONENT16; + aCF.depth = 16; + } + } else { + formats.depth = LOCAL_GL_DEPTH_COMPONENT24; + aCF.depth = 24; + } } - } else { - formats.depth = LOCAL_GL_DEPTH_COMPONENT24; + + if (stencil) { + formats.stencil = LOCAL_GL_STENCIL_INDEX8; + aCF.stencil = 8; + } } - formats.stencil = LOCAL_GL_STENCIL_INDEX8; - return formats; } -GLuint -GLContext::CreateTextureForOffscreen(const GLFormats& formats, const gfxIntSize& size) +void +GLContext::CreateTextureForOffscreen(const GLFormats& aFormats, const gfxIntSize& aSize, GLuint& texture) { - MOZ_ASSERT(formats.color_texInternalFormat); - MOZ_ASSERT(formats.color_texFormat); - MOZ_ASSERT(formats.color_texType); + GLuint boundTexture = 0; + fGetIntegerv(LOCAL_GL_TEXTURE_BINDING_2D, (GLint*)&boundTexture); - return CreateTexture(formats.color_texInternalFormat, - formats.color_texFormat, - formats.color_texType, - size); -} + if (texture == 0) { + fGenTextures(1, &texture); + } -GLuint -GLContext::CreateTexture(GLenum internalFormat, GLenum format, GLenum type, const gfxIntSize& size) -{ - GLuint tex = 0; - fGenTextures(1, &tex); - ScopedBindTexture autoTex(this, tex); - + fBindTexture(LOCAL_GL_TEXTURE_2D, texture); fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_LINEAR); fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_LINEAR); fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE); fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE); fTexImage2D(LOCAL_GL_TEXTURE_2D, 0, - internalFormat, - size.width, size.height, + aFormats.texColor, + aSize.width, aSize.height, 0, - format, - type, + aFormats.texColor, + aFormats.texColorType, nullptr); - return tex; + fBindTexture(LOCAL_GL_TEXTURE_2D, boundTexture); } static inline void RenderbufferStorageBySamples(GLContext* gl, GLsizei samples, GLenum internalFormat, const gfxIntSize& size) { if (samples) { gl->fRenderbufferStorageMultisample(LOCAL_GL_RENDERBUFFER, samples, @@ -1019,167 +966,100 @@ RenderbufferStorageBySamples(GLContext* size.width, size.height); } else { gl->fRenderbufferStorage(LOCAL_GL_RENDERBUFFER, internalFormat, size.width, size.height); } } -GLuint -GLContext::CreateRenderbuffer(GLenum format, GLsizei samples, const gfxIntSize& size) +void +GLContext::CreateRenderbuffersForOffscreen(const GLContext::GLFormats& aFormats, const gfxIntSize& aSize, + GLuint& colorMSRB, GLuint& depthRB, GLuint& stencilRB) { - GLuint rb = 0; - fGenRenderbuffers(1, &rb); - ScopedBindRenderbuffer autoRB(this, rb); + GLuint boundRB = 0; + fGetIntegerv(LOCAL_GL_RENDERBUFFER_BINDING, (GLint*)&boundRB); - RenderbufferStorageBySamples(this, samples, format, size); - - return rb; -} -void -GLContext::CreateRenderbuffersForOffscreen(const GLFormats& formats, const gfxIntSize& size, - bool multisample, - GLuint* colorMSRB, GLuint* depthRB, GLuint* stencilRB) -{ - GLsizei samples = multisample ? formats.samples : 0; - if (colorMSRB) { - MOZ_ASSERT(formats.samples > 0); - MOZ_ASSERT(formats.color_rbFormat); + colorMSRB = 0; + depthRB = 0; + stencilRB = 0; - *colorMSRB = CreateRenderbuffer(formats.color_rbFormat, samples, size); + if (aFormats.samples > 0) { + fGenRenderbuffers(1, &colorMSRB); + fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, colorMSRB); + RenderbufferStorageBySamples(this, aFormats.samples, aFormats.rbColor, aSize); } - if (depthRB && - stencilRB && - formats.depthStencil) - { - *depthRB = CreateRenderbuffer(formats.depthStencil, samples, size); - *stencilRB = *depthRB; - } else { - if (depthRB) { - MOZ_ASSERT(formats.depth); + // If depthStencil, disallow depth, stencil + MOZ_ASSERT(!aFormats.depthStencil || (!aFormats.depth && !aFormats.stencil)); + + if (aFormats.depthStencil) { + fGenRenderbuffers(1, &depthRB); + stencilRB = depthRB; + fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, depthRB); + RenderbufferStorageBySamples(this, aFormats.samples, aFormats.depthStencil, aSize); + } - *depthRB = CreateRenderbuffer(formats.depth, samples, size); - } + if (aFormats.depth) { + fGenRenderbuffers(1, &depthRB); + fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, depthRB); + RenderbufferStorageBySamples(this, aFormats.samples, aFormats.depth, aSize); + } - if (stencilRB) { - MOZ_ASSERT(formats.stencil); + if (aFormats.stencil) { + fGenRenderbuffers(1, &stencilRB); + fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, stencilRB); + RenderbufferStorageBySamples(this, aFormats.samples, aFormats.stencil, aSize); + } - *stencilRB = CreateRenderbuffer(formats.stencil, samples, size); - } - } + + fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, boundRB); } bool -GLContext::IsFramebufferComplete(GLuint fb, GLenum* pStatus) +GLContext::AssembleOffscreenFBOs(const GLuint colorMSRB, + const GLuint depthRB, + const GLuint stencilRB, + const GLuint texture, + GLuint& drawFBO, + GLuint& readFBO) { - MOZ_ASSERT(fb); - - ScopedBindFramebuffer autoFB(this, fb); - MOZ_ASSERT(fIsFramebuffer(fb)); - - GLenum status = fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER); - if (pStatus) - *pStatus = status; - - return status == LOCAL_GL_FRAMEBUFFER_COMPLETE; -} - -void -GLContext::AttachBuffersToFB(GLuint colorTex, GLuint colorRB, - GLuint depthRB, GLuint stencilRB, - GLuint fb) -{ - MOZ_ASSERT(fb); - MOZ_ASSERT( !(colorTex && colorRB) ); - - ScopedBindFramebuffer autoFB(this, fb); - MOZ_ASSERT(fIsFramebuffer(fb)); // It only counts after being bound. + drawFBO = 0; + readFBO = 0; - if (colorTex) { - MOZ_ASSERT(fIsTexture(colorTex)); - fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, - LOCAL_GL_COLOR_ATTACHMENT0, - LOCAL_GL_TEXTURE_2D, - colorTex, - 0); - } else if (colorRB) { - MOZ_ASSERT(fIsRenderbuffer(colorRB)); - fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, - LOCAL_GL_COLOR_ATTACHMENT0, - LOCAL_GL_RENDERBUFFER, - colorRB); - } - - if (depthRB) { - MOZ_ASSERT(fIsRenderbuffer(depthRB)); - fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, - LOCAL_GL_DEPTH_ATTACHMENT, - LOCAL_GL_RENDERBUFFER, - depthRB); - } - - if (stencilRB) { - MOZ_ASSERT(fIsRenderbuffer(stencilRB)); - fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, - LOCAL_GL_STENCIL_ATTACHMENT, - LOCAL_GL_RENDERBUFFER, - stencilRB); - } -} - -bool -GLContext::AssembleOffscreenFBs(const GLuint colorMSRB, - const GLuint depthRB, - const GLuint stencilRB, - const GLuint texture, - GLuint* drawFB_out, - GLuint* readFB_out) -{ if (!colorMSRB && !texture) { MOZ_ASSERT(!depthRB && !stencilRB); - - if (drawFB_out) - *drawFB_out = 0; - if (readFB_out) - *readFB_out = 0; - return true; } - ScopedBindFramebuffer autoFB(this); - - GLuint drawFB = 0; - GLuint readFB = 0; + GLuint boundDrawFBO = GetUserBoundDrawFBO(); + GLuint boundReadFBO = GetUserBoundReadFBO(); if (texture) { - readFB = 0; - fGenFramebuffers(1, &readFB); - BindFB(readFB); + fGenFramebuffers(1, &readFBO); + BindInternalFBO(readFBO); fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_COLOR_ATTACHMENT0, LOCAL_GL_TEXTURE_2D, texture, 0); } if (colorMSRB) { - drawFB = 0; - fGenFramebuffers(1, &drawFB); - BindFB(drawFB); + fGenFramebuffers(1, &drawFBO); + BindInternalFBO(drawFBO); fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_COLOR_ATTACHMENT0, LOCAL_GL_RENDERBUFFER, colorMSRB); } else { - drawFB = readFB; + drawFBO = readFBO; + // drawFBO==readFBO is already bound from the 'if (texture)' block. } - MOZ_ASSERT(GetFB() == drawFB); if (depthRB) { fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_DEPTH_ATTACHMENT, LOCAL_GL_RENDERBUFFER, depthRB); } @@ -1189,74 +1069,142 @@ GLContext::AssembleOffscreenFBs(const GL LOCAL_GL_RENDERBUFFER, stencilRB); } // We should be all resized. Check for framebuffer completeness. GLenum status; bool isComplete = true; - if (!IsFramebufferComplete(drawFB, &status)) { + BindInternalFBO(drawFBO); + status = fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER); + if (status != LOCAL_GL_FRAMEBUFFER_COMPLETE) { NS_WARNING("DrawFBO: Incomplete"); #ifdef DEBUG if (DebugMode()) { printf_stderr("Framebuffer status: %X\n", status); } #endif isComplete = false; } - if (!IsFramebufferComplete(readFB, &status)) { + BindInternalFBO(readFBO); + status = fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER); + if (status != LOCAL_GL_FRAMEBUFFER_COMPLETE) { NS_WARNING("ReadFBO: Incomplete"); #ifdef DEBUG if (DebugMode()) { printf_stderr("Framebuffer status: %X\n", status); } #endif isComplete = false; } - if (drawFB_out) { - *drawFB_out = drawFB; - } else if (drawFB) { - NS_RUNTIMEABORT("drawFB created when not requested!"); - } - - if (readFB_out) { - *readFB_out = readFB; - } else if (readFB) { - NS_RUNTIMEABORT("readFB created when not requested!"); - } + BindUserDrawFBO(boundDrawFBO); + BindUserReadFBO(boundReadFBO); return isComplete; } - - bool -GLContext::PublishFrame() +GLContext::ResizeOffscreenFBOs(const ContextFormat& aCF, const gfxIntSize& aSize, const bool aNeedsReadBuffer) { - MOZ_ASSERT(mScreen); + // Early out for when we're rendering directly to the context's 'screen'. + if (!aNeedsReadBuffer && !aCF.samples) + return true; + + MakeCurrent(); + ContextFormat cf(aCF); + GLFormats formats = ChooseGLFormats(cf); + + GLuint texture = 0; + if (aNeedsReadBuffer) + CreateTextureForOffscreen(formats, aSize, texture); + + GLuint colorMSRB = 0; + GLuint depthRB = 0; + GLuint stencilRB = 0; + CreateRenderbuffersForOffscreen(formats, aSize, colorMSRB, depthRB, stencilRB); + + GLuint drawFBO = 0; + GLuint readFBO = 0; + if (!AssembleOffscreenFBOs(colorMSRB, depthRB, stencilRB, texture, + drawFBO, readFBO)) + { + fDeleteFramebuffers(1, &drawFBO); + fDeleteFramebuffers(1, &readFBO); + fDeleteRenderbuffers(1, &colorMSRB); + fDeleteRenderbuffers(1, &depthRB); + fDeleteRenderbuffers(1, &stencilRB); + fDeleteTextures(1, &texture); + + return false; + } - if (!mScreen->PublishFrame(OffscreenSize())) - return false; + // Success, so switch everything out. + // Store current user FBO bindings. + GLuint boundDrawFBO = GetUserBoundDrawFBO(); + GLuint boundReadFBO = GetUserBoundReadFBO(); + + // Replace with the new hotness + std::swap(mOffscreenDrawFBO, drawFBO); + std::swap(mOffscreenReadFBO, readFBO); + std::swap(mOffscreenColorRB, colorMSRB); + std::swap(mOffscreenDepthRB, depthRB); + std::swap(mOffscreenStencilRB, stencilRB); + std::swap(mOffscreenTexture, texture); + + // Delete the old and busted + fDeleteFramebuffers(1, &drawFBO); + fDeleteFramebuffers(1, &readFBO); + fDeleteRenderbuffers(1, &colorMSRB); + fDeleteRenderbuffers(1, &depthRB); + fDeleteRenderbuffers(1, &stencilRB); + fDeleteTextures(1, &texture); + + // Rebind user FBOs, in case anything changed internally. + BindUserDrawFBO(boundDrawFBO); + BindUserReadFBO(boundReadFBO); + + // Newly-created buffers are...unlikely to match. + ForceDirtyFBOs(); + + // Finish up. + mOffscreenSize = aSize; + mOffscreenActualSize = aSize; + mActualFormat = cf; + + if (DebugMode()) { + printf_stderr("Resized %dx%d offscreen FBO: r: %d g: %d b: %d a: %d depth: %d stencil: %d samples: %d\n", + mOffscreenActualSize.width, mOffscreenActualSize.height, + mActualFormat.red, mActualFormat.green, mActualFormat.blue, mActualFormat.alpha, + mActualFormat.depth, mActualFormat.stencil, mActualFormat.samples); + } return true; } -SharedSurface* -GLContext::RequestFrame() +void +GLContext::DeleteOffscreenFBOs() { - MOZ_ASSERT(mScreen); + fDeleteFramebuffers(1, &mOffscreenDrawFBO); + fDeleteFramebuffers(1, &mOffscreenReadFBO); + fDeleteTextures(1, &mOffscreenTexture); + fDeleteRenderbuffers(1, &mOffscreenColorRB); + fDeleteRenderbuffers(1, &mOffscreenDepthRB); + fDeleteRenderbuffers(1, &mOffscreenStencilRB); - return mScreen->Stream()->SwapConsumer(); + mOffscreenDrawFBO = 0; + mOffscreenReadFBO = 0; + mOffscreenTexture = 0; + mOffscreenColorRB = 0; + mOffscreenDepthRB = 0; + mOffscreenStencilRB = 0; } - - void GLContext::ClearSafely() { // bug 659349 --- we must be very careful here: clearing a GL framebuffer is nontrivial, relies on a lot of state, // and in the case of the backbuffer of a WebGL context, state is exposed to scripts. // // The code here is taken from WebGLContext::ForceClearFramebufferWithDefaultValues, but I didn't find a good way of // sharing code with it. WebGL's code is somewhat performance-critical as it is typically called on every frame, so @@ -1282,17 +1230,17 @@ GLContext::ClearSafely() fGetIntegerv(LOCAL_GL_STENCIL_BACK_WRITEMASK, &stencilWriteMaskBack); fGetFloatv(LOCAL_GL_COLOR_CLEAR_VALUE, colorClearValue); fGetFloatv(LOCAL_GL_DEPTH_CLEAR_VALUE, &depthClearValue); fGetIntegerv(LOCAL_GL_STENCIL_CLEAR_VALUE, &stencilClearValue); // prepare GL state for clearing fDisable(LOCAL_GL_SCISSOR_TEST); fDisable(LOCAL_GL_DITHER); - PushViewportRect(nsIntRect(0, 0, OffscreenSize().width, OffscreenSize().height)); + PushViewportRect(nsIntRect(0, 0, mOffscreenSize.width, mOffscreenSize.height)); fColorMask(1, 1, 1, 1); fClearColor(0.f, 0.f, 0.f, 0.f); fDepthMask(1); fClearDepth(1.0f); fStencilMask(0xffffffff); @@ -1330,34 +1278,44 @@ GLContext::ClearSafely() if (scissorTestEnabled) fEnable(LOCAL_GL_SCISSOR_TEST); else fDisable(LOCAL_GL_SCISSOR_TEST); } void +GLContext::UpdateActualFormat() +{ + ContextFormat nf; + + fGetIntegerv(LOCAL_GL_RED_BITS, (GLint*) &nf.red); + fGetIntegerv(LOCAL_GL_GREEN_BITS, (GLint*) &nf.green); + fGetIntegerv(LOCAL_GL_BLUE_BITS, (GLint*) &nf.blue); + fGetIntegerv(LOCAL_GL_ALPHA_BITS, (GLint*) &nf.alpha); + fGetIntegerv(LOCAL_GL_DEPTH_BITS, (GLint*) &nf.depth); + fGetIntegerv(LOCAL_GL_STENCIL_BITS, (GLint*) &nf.stencil); + + mActualFormat = nf; +} + +void GLContext::MarkDestroyed() { if (IsDestroyed()) return; if (MakeCurrent()) { - DestroyScreenBuffer(); - - // This is for Blit{Tex,FB}To{TexFB}. + DeleteOffscreenFBOs(); DeleteTexBlitProgram(); - // Likely used by OGL Layers. fDeleteProgram(mBlitProgram); mBlitProgram = 0; fDeleteFramebuffers(1, &mBlitFramebuffer); mBlitFramebuffer = 0; - - mTexGarbageBin->GLContextTeardown(); } else { NS_WARNING("MakeCurrent() failed during MarkDestroyed! Skipping GL object teardown."); } mSymbols.Zero(); } static void SwapRAndBComponents(gfxImageSurface* surf) @@ -1554,243 +1512,123 @@ GLContext::ReadTextureImage(GLuint aText fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, oldfb); fUseProgram(oldprog); PopViewportRect(); return isurf.forget(); } -static bool -GetActualReadFormats(GLContext* gl, GLenum destFormat, GLenum destType, - GLenum& readFormat, GLenum& readType) -{ - if (destFormat == LOCAL_GL_RGBA && - destType == LOCAL_GL_UNSIGNED_BYTE) - { - readFormat = destFormat; - readType = destType; - return true; - } - - bool fallback = true; +static void +GetOptimalReadFormats(GLContext* gl, GLenum& format, GLenum& type) { if (gl->IsGLES2()) { - GLenum auxFormat = 0; - GLenum auxType = 0; - - gl->fGetIntegerv(LOCAL_GL_IMPLEMENTATION_COLOR_READ_FORMAT, (GLint*)&auxFormat); - gl->fGetIntegerv(LOCAL_GL_IMPLEMENTATION_COLOR_READ_TYPE, (GLint*)&auxType); + bool has_BGRA_UByte = false; + if (gl->IsExtensionSupported(gl::GLContext::EXT_bgra)) { + has_BGRA_UByte = true; + } else if (gl->IsExtensionSupported(gl::GLContext::EXT_read_format_bgra) || + gl->IsExtensionSupported(gl::GLContext::IMG_read_format)) { + // Note that these extensions are not required to query this value. + // However, we should never get back BGRA unless one of these is supported. + GLint auxFormat = 0; + GLint auxType = 0; - if (destFormat == auxFormat && - destType == auxType) - { - fallback = false; + gl->fGetIntegerv(LOCAL_GL_IMPLEMENTATION_COLOR_READ_FORMAT, &auxFormat); + gl->fGetIntegerv(LOCAL_GL_IMPLEMENTATION_COLOR_READ_TYPE, &auxType); + + if (auxFormat == LOCAL_GL_BGRA && auxType == LOCAL_GL_UNSIGNED_BYTE) + has_BGRA_UByte = true; } + + format = has_BGRA_UByte ? LOCAL_GL_BGRA : LOCAL_GL_RGBA; + type = LOCAL_GL_UNSIGNED_BYTE; } else { - switch (destFormat) { - case LOCAL_GL_RGB: { - if (destType == LOCAL_GL_UNSIGNED_SHORT_5_6_5_REV) - fallback = false; - break; - } - case LOCAL_GL_BGRA: { - if (destType == LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV) - fallback = false; - break; - } - } - } - - if (fallback) { - readFormat = LOCAL_GL_RGBA; - readType = LOCAL_GL_UNSIGNED_BYTE; - return false; - } else { - readFormat = destFormat; - readType = destType; - return true; + // defaults for desktop + format = LOCAL_GL_BGRA; + type = LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV; } } void GLContext::ReadScreenIntoImageSurface(gfxImageSurface* dest) { - ScopedBindFramebuffer autoFB(this, 0); + GLuint boundFB = 0; + fGetIntegerv(LOCAL_GL_FRAMEBUFFER_BINDING, (GLint*)&boundFB); + fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0); ReadPixelsIntoImageSurface(dest); + + fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, boundFB); } void GLContext::ReadPixelsIntoImageSurface(gfxImageSurface* dest) { - MakeCurrent(); - MOZ_ASSERT(dest->GetSize() != gfxIntSize(0, 0)); - - /* ImageFormatARGB32: - * RGBA+UByte: be[RGBA], le[ABGR] - * RGBA+UInt: le[RGBA] - * BGRA+UInt: le[BGRA] - * BGRA+UIntRev: le[ARGB] - * - * ImageFormatRGB16_565: - * RGB+UShort: le[rrrrrggg,gggbbbbb] - */ - bool hasAlpha = dest->Format() == gfxASurface::ImageFormatARGB32; - - int destPixelSize; - GLenum destFormat; - GLenum destType; - - switch (dest->Format()) { - case gfxASurface::ImageFormatRGB24: // XRGB - case gfxASurface::ImageFormatARGB32: - destPixelSize = 4; - // Needs host (little) endian ARGB. - destFormat = LOCAL_GL_BGRA; - destType = LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV; - break; - - case gfxASurface::ImageFormatRGB16_565: - destPixelSize = 2; - destFormat = LOCAL_GL_RGB; - destType = LOCAL_GL_UNSIGNED_SHORT_5_6_5_REV; - break; - - default: - MOZ_NOT_REACHED("Bad format."); - return; - } - MOZ_ASSERT(dest->Stride() == dest->Width() * destPixelSize); - - GLenum readFormat = destFormat; - GLenum readType = destType; - bool needsTempSurf = !GetActualReadFormats(this, - destFormat, destType, - readFormat, readType); + MOZ_ASSERT(dest->Format() == gfxASurface::ImageFormatARGB32 || + dest->Format() == gfxASurface::ImageFormatRGB24); - nsAutoPtr<gfxImageSurface> tempSurf; - gfxImageSurface* readSurf = nullptr; - int readPixelSize = 0; - if (needsTempSurf) { - if (DebugMode()) { - NS_WARNING("Needing intermediary surface for ReadPixels. This will be slow!"); - } - gfxASurface::gfxImageFormat readFormatGFX; - - switch (readFormat) { - case LOCAL_GL_RGBA: - case LOCAL_GL_BGRA: { - readFormatGFX = hasAlpha ? gfxASurface::ImageFormatARGB32 - : gfxASurface::ImageFormatRGB24; - break; - } - case LOCAL_GL_RGB: { - MOZ_ASSERT(readPixelSize == 2); - MOZ_ASSERT(readType == LOCAL_GL_UNSIGNED_SHORT_5_6_5_REV); - readFormatGFX = gfxASurface::ImageFormatRGB16_565; - break; - } - default: { - MOZ_NOT_REACHED("Bad read format."); - return; - } - } + MOZ_ASSERT(dest->Stride() == dest->Width() * 4); + MOZ_ASSERT(dest->Format() == gfxASurface::ImageFormatARGB32 || + dest->Format() == gfxASurface::ImageFormatRGB24); - switch (readType) { - case LOCAL_GL_UNSIGNED_BYTE: { - MOZ_ASSERT(readFormat == LOCAL_GL_RGBA); - readPixelSize = 4; - break; - } - case LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV: { - MOZ_ASSERT(readFormat == LOCAL_GL_BGRA); - readPixelSize = 4; - break; - } - case LOCAL_GL_UNSIGNED_SHORT_5_6_5_REV: { - MOZ_ASSERT(readFormat == LOCAL_GL_RGB); - readPixelSize = 2; - break; - } - default: { - MOZ_NOT_REACHED("Bad read type."); - return; - } - } + MOZ_ASSERT(dest->Stride() == dest->Width() * 4); - tempSurf = new gfxImageSurface(dest->GetSize(), readFormatGFX, false); - readSurf = tempSurf; - } else { - readPixelSize = destPixelSize; - readSurf = dest; - } - MOZ_ASSERT(readPixelSize); + MakeCurrent(); GLint currentPackAlignment = 0; fGetIntegerv(LOCAL_GL_PACK_ALIGNMENT, ¤tPackAlignment); - if (currentPackAlignment != readPixelSize) - fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, readPixelSize); + if (currentPackAlignment != 4) + fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, 4); + + GLenum format; + GLenum datatype; + GetOptimalReadFormats(this, format, datatype); GLsizei width = dest->Width(); GLsizei height = dest->Height(); - readSurf->Flush(); fReadPixels(0, 0, width, height, - readFormat, readType, - readSurf->Data()); - readSurf->MarkDirty(); - - if (currentPackAlignment != readPixelSize) - fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, currentPackAlignment); - - if (readSurf != dest) { - MOZ_ASSERT(readFormat == LOCAL_GL_RGBA); - MOZ_ASSERT(readType == LOCAL_GL_UNSIGNED_BYTE); - // So we just copied in RGBA in big endian, or le: 0xAABBGGRR. - // We want 0xAARRGGBB, so swap R and B: - dest->Flush(); - SwapRAndBComponents(readSurf); - dest->MarkDirty(); - - gfxContext ctx(dest); - ctx.SetOperator(gfxContext::OPERATOR_SOURCE); - ctx.SetSource(readSurf); - ctx.Paint(); - } + format, datatype, + dest->Data()); // Check if GL is giving back 1.0 alpha for // RGBA reads to RGBA images from no-alpha buffers. #ifdef XP_MACOSX if (WorkAroundDriverBugs() && mVendor == VendorNVIDIA && dest->Format() == gfxASurface::ImageFormatARGB32 && width && height) { GLint alphaBits = 0; fGetIntegerv(LOCAL_GL_ALPHA_BITS, &alphaBits); if (!alphaBits) { const uint32_t alphaMask = gfxPackedPixelNoPreMultiply(0xff,0,0,0); - dest->Flush(); uint32_t* itr = (uint32_t*)dest->Data(); uint32_t testPixel = *itr; if ((testPixel & alphaMask) != alphaMask) { // We need to set the alpha channel to 1.0 manually. uint32_t* itrEnd = itr + width*height; // Stride is guaranteed to be width*4. for (; itr != itrEnd; itr++) { *itr |= alphaMask; } } - dest->MarkDirty(); } } #endif + + // Output should be in BGRA, so swap if RGBA. + if (format == LOCAL_GL_RGBA) { + SwapRAndBComponents(dest); + } + + if (currentPackAlignment != 4) + fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, currentPackAlignment); } void GLContext::BlitTextureImage(TextureImage *aSrc, const nsIntRect& aSrcRect, TextureImage *aDst, const nsIntRect& aDstRect) { NS_ASSERTION(!aSrc->InUpdate(), "Source texture is in update!"); NS_ASSERTION(!aDst->InUpdate(), "Destination texture is in update!"); @@ -2021,19 +1859,16 @@ GLContext::UploadSurfaceToTexture(gfxASu // If a pixel buffer is bound the data pointer parameter is relative // to the start of the data block. if (!aPixelBuffer) { data = imageSurface->Data(); } data += DataOffset(imageSurface, aSrcPoint); } - MOZ_ASSERT(imageSurface); - imageSurface->Flush(); - GLenum format; GLenum type; int32_t pixelSize = gfxASurface::BytePerPixelFromFormat(imageSurface->Format()); ShaderProgramType shader; switch (imageSurface->Format()) { case gfxASurface::ImageFormatARGB32: format = LOCAL_GL_RGBA; @@ -2818,125 +2653,10 @@ GLContext::ReportOutstandingNames() ReportArrayContents("Outstanding Programs", mTrackedPrograms); ReportArrayContents("Outstanding Shaders", mTrackedShaders); ReportArrayContents("Outstanding Framebuffers", mTrackedFramebuffers); ReportArrayContents("Outstanding Renderbuffers", mTrackedRenderbuffers); } #endif /* DEBUG */ - -void -GLContext::GuaranteeResolve() -{ - mScreen->AssureBlitted(); - fFinish(); -} - -const gfxIntSize& -GLContext::OffscreenSize() const -{ - MOZ_ASSERT(IsOffscreen()); - return mScreen->Size(); -} - -bool -GLContext::CreateScreenBufferImpl(const gfxIntSize& size, const SurfaceCaps& caps) -{ - GLScreenBuffer* newScreen = GLScreenBuffer::Create(this, size, caps); - if (!newScreen) - return false; - - if (!newScreen->PublishFrame(size)) { - delete newScreen; - return false; - } - - DestroyScreenBuffer(); - - // This will rebind to 0 (Screen) if needed when - // it falls out of scope. - ScopedBindFramebuffer autoFB(this); - - mScreen = newScreen; - - return true; -} - -bool -GLContext::ResizeScreenBuffer(const gfxIntSize& size) -{ - if (!IsOffscreenSizeAllowed(size)) - return false; - - return mScreen->PublishFrame(size); -} - - -void -GLContext::DestroyScreenBuffer() -{ - delete mScreen; - mScreen = nullptr; -} - -void -GLContext::ForceDirtyScreen() -{ - ScopedBindFramebuffer autoFB(0); - - BeforeGLDrawCall(); - // no-op; just pretend we did something - AfterGLDrawCall(); -} - -void -GLContext::CleanDirtyScreen() -{ - ScopedBindFramebuffer autoFB(0); - - BeforeGLReadCall(); - // no-op; we just want to make sure the Read FBO is updated if it needs to be - AfterGLReadCall(); -} - -void -GLContext::EmptyTexGarbageBin() -{ - TexGarbageBin()->EmptyGarbage(); -} - - -void -TextureGarbageBin::GLContextTeardown() -{ - EmptyGarbage(); - - MutexAutoLock lock(mMutex); - mGL = nullptr; -} - -void -TextureGarbageBin::Trash(GLuint tex) -{ - MutexAutoLock lock(mMutex); - if (!mGL) - return; - - mGarbageTextures.push(tex); -} - -void -TextureGarbageBin::EmptyGarbage() -{ - MutexAutoLock lock(mMutex); - if (!mGL) - return; - - while (!mGarbageTextures.empty()) { - GLuint tex = mGarbageTextures.top(); - mGarbageTextures.pop(); - mGL->fDeleteTextures(1, &tex); - } -} - } /* namespace gl */ } /* namespace mozilla */
--- a/gfx/gl/GLContext.h +++ b/gfx/gl/GLContext.h @@ -8,18 +8,16 @@ #include <stdio.h> #include <algorithm> #if defined(XP_UNIX) #include <stdint.h> #endif #include <string.h> #include <ctype.h> -#include <set> -#include <stack> #ifdef WIN32 #include <windows.h> #endif #include "GLDefs.h" #include "GLLibraryLoader.h" #include "gfxASurface.h" @@ -33,90 +31,143 @@ #include "nsDataHashtable.h" #include "nsHashKeys.h" #include "nsRegion.h" #include "nsAutoPtr.h" #include "nsThreadUtils.h" #include "GLContextTypes.h" #include "GLTextureImage.h" -#include "SurfaceTypes.h" -#include "GLScreenBuffer.h" typedef char realGLboolean; #include "GLContextSymbols.h" #include "mozilla/mozalloc.h" #include "mozilla/Preferences.h" -#include "mozilla/StandardInteger.h" -#include "mozilla/Mutex.h" namespace android { - class GraphicBuffer; +class GraphicBuffer; } namespace mozilla { - namespace gfx { - class SharedSurface; - struct SurfaceCaps; - } - - namespace gl { - class GLContext; - class GLLibraryEGL; - class GLScreenBuffer; - class TextureGarbageBin; + namespace layers { + class LayerManagerOGL; + class ColorTextureLayerProgram; + } + +namespace gl { +class GLContext; + +typedef uintptr_t SharedTextureHandle; + +struct THEBES_API ContextFormat +{ + static const ContextFormat BasicRGBA32Format; + + enum StandardContextFormat { + Empty, + BasicRGBA32, + StrictBasicRGBA32, + BasicRGB24, + StrictBasicRGB24, + BasicRGB16_565, + StrictBasicRGB16_565 + }; + + ContextFormat() { + memset(this, 0, sizeof(ContextFormat)); } - namespace layers { - class ColorTextureLayerProgram; - class LayerManagerOGL; + ContextFormat(const StandardContextFormat cf) { + memset(this, 0, sizeof(ContextFormat)); + switch (cf) { + case BasicRGBA32: + red = green = blue = alpha = 8; + minRed = minGreen = minBlue = minAlpha = 1; + break; + + case StrictBasicRGBA32: + red = green = blue = alpha = 8; + minRed = minGreen = minBlue = minAlpha = 8; + break; + + case BasicRGB24: + red = green = blue = 8; + minRed = minGreen = minBlue = 1; + break; + + case StrictBasicRGB24: + red = green = blue = 8; + minRed = minGreen = minBlue = 8; + break; + + case StrictBasicRGB16_565: + red = minRed = 5; + green = minGreen = 6; + blue = minBlue = 5; + break; + + default: + break; + } } -} - -namespace mozilla { -namespace gl { -typedef uintptr_t SharedTextureHandle; + + int depth, minDepth; + int stencil, minStencil; + int red, minRed; + int green, minGreen; + int blue, minBlue; + int alpha, minAlpha; + int samples; + + int colorBits() const { return red + green + blue; } +}; class GLContext : public GLLibraryLoader { NS_INLINE_DECL_THREADSAFE_REFCOUNTING(GLContext) - -protected: - typedef class gfx::SharedSurface SharedSurface; - typedef gfx::SharedSurfaceType SharedSurfaceType; - public: - typedef struct gfx::SurfaceCaps SurfaceCaps; - - GLContext(const SurfaceCaps& caps, - GLContext* sharedContext = nullptr, - bool isOffscreen = false) + GLContext(const ContextFormat& aFormat, + bool aIsOffscreen = false, + GLContext *aSharedContext = nullptr) : mTexBlit_Buffer(0), mTexBlit_VertShader(0), mTexBlit_FragShader(0), mTexBlit_Program(0), mTexBlit_UseDrawNotCopy(false), + mUserBoundDrawFBO(0), + mUserBoundReadFBO(0), + mInternalBoundDrawFBO(0), + mInternalBoundReadFBO(0), +#ifdef DEBUG + mInInternalBindingMode_DrawFBO(true), + mInInternalBindingMode_ReadFBO(true), +#endif + mOffscreenFBOsDirty(false), mInitialized(false), - mIsOffscreen(isOffscreen), + mIsOffscreen(aIsOffscreen), mIsGLES2(false), mIsGlobalSharedContext(false), mHasRobustness(false), mContextLost(false), mVendor(-1), mRenderer(-1), - mSharedContext(sharedContext), + mCreationFormat(aFormat), + mSharedContext(aSharedContext), + mOffscreenTexture(0), mFlipped(false), mBlitProgram(0), mBlitFramebuffer(0), - mCaps(caps), - mScreen(nullptr), - mLockedSurface(nullptr), + mOffscreenDrawFBO(0), + mOffscreenReadFBO(0), + mOffscreenColorRB(0), + mOffscreenDepthRB(0), + mOffscreenStencilRB(0), mMaxTextureSize(0), mMaxCubeMapTextureSize(0), mMaxTextureImageSize(0), mMaxRenderbufferSize(0), mNeedsTextureSizeChecks(false), mWorkAroundDriverBugs(true) #ifdef DEBUG , mGLError(LOCAL_GL_NO_ERROR) @@ -237,22 +288,23 @@ public: // (that is, when the main thread is no longer get-able) can cause them // to leak. See Bug 741319, and Bug 744115. nsCOMPtr<nsIThread> mainThread; if (NS_SUCCEEDED(NS_GetMainThread(getter_AddRefs(mainThread)))) { mOwningThread->Dispatch(event, NS_DISPATCH_NORMAL); } } - virtual EGLContext GetEGLContext() { return nullptr; } - virtual GLLibraryEGL* GetLibraryEGL() { return nullptr; } - - virtual void MakeCurrent_EGLSurface(void* surf) { - MOZ_NOT_REACHED("Must be called against a GLContextEGL."); - } + 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 nullptr; } /** * If this context is double-buffered, returns TRUE. */ virtual bool IsDoubleBuffered() { return false; } /** * If this context is the GLES2 API, returns TRUE. @@ -354,41 +406,86 @@ public: virtual bool BindExternalBuffer(GLuint texture, void* buffer) { return false; } virtual bool UnbindExternalBuffer(GLuint texture) { return false; } virtual already_AddRefed<TextureImage> CreateDirectTextureImage(android::GraphicBuffer* aBuffer, GLenum aWrapMode) { return nullptr; } + /* + * Offscreen support API + */ + + /* + * Bind aOffscreen's color buffer as a texture to the TEXTURE_2D + * target. Returns TRUE on success, otherwise FALSE. If + * aOffscreen is not an offscreen context, returns FALSE. If + * BindOffscreenNeedsTexture() returns TRUE, then you should have + * a 2D texture name bound whose image will be replaced by the + * contents of the offscreen context. If it returns FALSE, + * the current 2D texture binding will be replaced. + * + * After a successul call to BindTex2DOffscreen, UnbindTex2DOffscreen + * *must* be called once rendering is complete. + * + * The same texture unit must be active for Bind/Unbind of a given + * context. + */ + virtual bool BindOffscreenNeedsTexture(GLContext *aOffscreen) { + return aOffscreen->mOffscreenTexture == 0; + } + + virtual bool BindTex2DOffscreen(GLContext *aOffscreen) { + if (aOffscreen->GetContextType() != GetContextType()) { + return false; + } + + if (!aOffscreen->mSharedContext || + aOffscreen->mSharedContext != mSharedContext) + { + return false; + } + + if (!aOffscreen->mOffscreenTexture) { + return false; + } + + fBindTexture(LOCAL_GL_TEXTURE_2D, aOffscreen->mOffscreenTexture); + + return true; + } + + virtual void UnbindTex2DOffscreen(GLContext *aOffscreen) { } + + bool IsOffscreen() { + return mIsOffscreen; + } + // Before reads from offscreen texture - void GuaranteeResolve(); + void GuaranteeResolve() { + BlitDirtyFBOs(); + fFinish(); + } protected: GLuint mTexBlit_Buffer; GLuint mTexBlit_VertShader; GLuint mTexBlit_FragShader; GLuint mTexBlit_Program; bool mTexBlit_UseDrawNotCopy; bool UseTexQuadProgram(); void DeleteTexBlitProgram(); public: - // If you don't have |srcFormats| for the 2nd definition, - // then you'll need the framebuffer_blit extensions to use - // the first BlitFramebufferToFramebuffer. void BlitFramebufferToFramebuffer(GLuint srcFB, GLuint destFB, const gfxIntSize& srcSize, const gfxIntSize& destSize); - void BlitFramebufferToFramebuffer(GLuint srcFB, GLuint destFB, - const gfxIntSize& srcSize, - const gfxIntSize& destSize, - const GLFormats& srcFormats); void BlitTextureToFramebuffer(GLuint srcTex, GLuint destFB, const gfxIntSize& srcSize, const gfxIntSize& destSize); void BlitFramebufferToTexture(GLuint srcFB, GLuint destTex, const gfxIntSize& srcSize, const gfxIntSize& destSize); void BlitTextureToTexture(GLuint srcTex, GLuint destTex, const gfxIntSize& srcSize, @@ -397,35 +494,63 @@ public: /* * Resize the current offscreen buffer. Returns true on success. * If it returns false, the context should be treated as unusable * and should be recreated. After the resize, the viewport is not * changed; glViewport should be called as appropriate. * * Only valid if IsOffscreen() returns true. */ - virtual bool ResizeOffscreen(const gfxIntSize& size) { - return ResizeScreenBuffer(size); + virtual bool ResizeOffscreen(const gfxIntSize& aNewSize) { + if (mOffscreenDrawFBO || mOffscreenReadFBO) + return ResizeOffscreenFBOs(aNewSize, mOffscreenReadFBO != 0); + return false; } /* * Return size of this offscreen context. * * Only valid if IsOffscreen() returns true. */ - const gfxIntSize& OffscreenSize() const; - - virtual bool SupportsFramebufferMultisample() const { - return IsExtensionSupported(EXT_framebuffer_multisample) || - IsExtensionSupported(ANGLE_framebuffer_multisample); + gfxIntSize OffscreenSize() { + return mOffscreenSize; + } + + /* + * In some cases, we have to allocate a bigger offscreen buffer + * than what's requested. This is the bigger size. + * + * Only valid if IsOffscreen() returns true. + */ + gfxIntSize OffscreenActualSize() { + return mOffscreenActualSize; } - virtual bool SupportsSplitFramebuffer() { - return IsExtensionSupported(EXT_framebuffer_blit) || - IsExtensionSupported(ANGLE_framebuffer_blit); + /* + * If this context is FBO-backed, return the FBO or the color + * buffer texture. If the context is not FBO-backed, 0 is + * returned (which is also a valid FBO binding). + * + * Only valid if IsOffscreen() returns true. + */ + GLuint GetOffscreenFBO() { + // 0 is interpreted as (off)screen, whether for read or draw operations + return 0; + } + + GLuint GetOffscreenTexture() { + return mOffscreenTexture; + } + + virtual bool SupportsFramebufferMultisample() { + return IsExtensionSupported(EXT_framebuffer_multisample) || IsExtensionSupported(ANGLE_framebuffer_multisample); + } + + virtual bool SupportsOffscreenSplit() { + return IsExtensionSupported(EXT_framebuffer_blit) || IsExtensionSupported(ANGLE_framebuffer_blit); } enum SharedTextureShareType { SameProcess = 0, CrossProcess }; @@ -501,121 +626,269 @@ public: /** * Detach Shared GL Handle from GL_TEXTURE_2D target */ virtual void DetachSharedHandle(SharedTextureShareType shareType, SharedTextureHandle sharedHandle) { } +private: + GLuint mUserBoundDrawFBO; + GLuint mUserBoundReadFBO; + GLuint mInternalBoundDrawFBO; + GLuint mInternalBoundReadFBO; + +public: void fBindFramebuffer(GLenum target, GLuint framebuffer) { - if (!mScreen) { - raw_fBindFramebuffer(target, framebuffer); - return; - } - switch (target) { - case LOCAL_GL_DRAW_FRAMEBUFFER_EXT: - mScreen->BindDrawFB(framebuffer); - return; - - case LOCAL_GL_READ_FRAMEBUFFER_EXT: - mScreen->BindReadFB(framebuffer); - return; - - case LOCAL_GL_FRAMEBUFFER: - mScreen->BindFB(framebuffer); - return; - - default: - // Nothing we care about, likely an error. - break; - } - - raw_fBindFramebuffer(target, framebuffer); - } - - void BindFB(GLuint fb) { - fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, fb); - MOZ_ASSERT(!fb || fIsFramebuffer(fb)); - } - - void BindDrawFB(GLuint fb) { - fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER_EXT, fb); - } - - void BindReadFB(GLuint fb) { - fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER_EXT, fb); + case LOCAL_GL_DRAW_FRAMEBUFFER_EXT: + mUserBoundDrawFBO = framebuffer; + + if (framebuffer == 0) { + mInternalBoundDrawFBO = mOffscreenDrawFBO; + } else { + mInternalBoundDrawFBO = mUserBoundDrawFBO; + } + + raw_fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER_EXT, + mInternalBoundDrawFBO); + break; + + case LOCAL_GL_READ_FRAMEBUFFER_EXT: + mUserBoundReadFBO = framebuffer; + + if (framebuffer == 0) { + mInternalBoundReadFBO = mOffscreenReadFBO; + } else { + mInternalBoundReadFBO = mUserBoundReadFBO; + } + + raw_fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER_EXT, + mInternalBoundReadFBO); + break; + + case LOCAL_GL_FRAMEBUFFER: + mUserBoundDrawFBO = mUserBoundReadFBO = framebuffer; + + if (framebuffer == 0) { + mInternalBoundDrawFBO = mOffscreenDrawFBO; + mInternalBoundReadFBO = mOffscreenReadFBO; + } else { + mInternalBoundDrawFBO = mUserBoundDrawFBO; + mInternalBoundReadFBO = mUserBoundReadFBO; + } + + if (SupportsOffscreenSplit()) { + raw_fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER_EXT, + mInternalBoundDrawFBO); + raw_fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER_EXT, + mInternalBoundReadFBO); + } else { + raw_fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, + mInternalBoundDrawFBO); + } + + break; + + default: + raw_fBindFramebuffer(target, framebuffer); + break; + } } void fGetIntegerv(GLenum pname, GLint *params) { - if (!mScreen) { - raw_fGetIntegerv(pname, params); - return; - } - switch (pname) { // LOCAL_GL_FRAMEBUFFER_BINDING is equal to - // LOCAL_GL_DRAW_FRAMEBUFFER_BINDING_EXT, - // so we don't need two cases. - case LOCAL_GL_DRAW_FRAMEBUFFER_BINDING_EXT: - *params = mScreen->GetDrawFB(); + // LOCAL_GL_DRAW_FRAMEBUFFER_BINDING_EXT, so we don't need two + // cases. + case LOCAL_GL_FRAMEBUFFER_BINDING: + *params = GetUserBoundDrawFBO(); break; case LOCAL_GL_READ_FRAMEBUFFER_BINDING_EXT: - *params = mScreen->GetReadFB(); + *params = GetUserBoundReadFBO(); + break; + + case LOCAL_GL_MAX_TEXTURE_SIZE: + *params = mMaxTextureSize; + break; + + case LOCAL_GL_MAX_CUBE_MAP_TEXTURE_SIZE: + *params = mMaxCubeMapTextureSize; + break; + + case LOCAL_GL_MAX_RENDERBUFFER_SIZE: + *params = mMaxRenderbufferSize; break; default: raw_fGetIntegerv(pname, params); break; } } - GLuint GetDrawFB() { - if (mScreen) - return mScreen->GetDrawFB(); - - GLuint ret = 0; - GetUIntegerv(LOCAL_GL_DRAW_FRAMEBUFFER_BINDING_EXT, &ret); - return ret; +#ifdef DEBUG + // See comment near BindInternalDrawFBO() + bool mInInternalBindingMode_DrawFBO; + bool mInInternalBindingMode_ReadFBO; +#endif + + GLuint GetUserBoundDrawFBO() { +#ifdef DEBUG + MOZ_ASSERT(IsCurrent()); + + GLint ret = 0; + // Don't need a branch here, because: + // LOCAL_GL_DRAW_FRAMEBUFFER_BINDING_EXT == LOCAL_GL_FRAMEBUFFER_BINDING == 0x8CA6 + // We use raw_ here because this is debug code and we need to see what + // the driver thinks. + raw_fGetIntegerv(LOCAL_GL_DRAW_FRAMEBUFFER_BINDING_EXT, &ret); + + bool abort = false; + + if (mInInternalBindingMode_DrawFBO) { + NS_ERROR("Draw FBO still bound internally!"); + printf_stderr("Current internal draw FBO: %d, user: %d)\n", ret, mUserBoundDrawFBO); + abort = true; + } + + if (mInternalBoundDrawFBO != (GLuint)ret) { + NS_ERROR("Draw FBO binding misprediction!"); + printf_stderr("Bound draw FBO was: %d, Expected: %d\n", ret, mInternalBoundDrawFBO); + abort = true; + } + + if (abort) + NS_ABORT(); +#endif + + // We only ever expose the user's bound FBOs + return mUserBoundDrawFBO; } - GLuint GetReadFB() { - if (mScreen) - return mScreen->GetReadFB(); - - GLenum bindEnum = SupportsSplitFramebuffer() ? LOCAL_GL_READ_FRAMEBUFFER_BINDING_EXT - : LOCAL_GL_FRAMEBUFFER_BINDING; - - GLuint ret = 0; - GetUIntegerv(bindEnum, &ret); - return ret; + GLuint GetUserBoundReadFBO() { +#ifdef DEBUG + MOZ_ASSERT(IsCurrent()); + + GLint ret = 0; + // We use raw_ here because this is debug code and we need to see what + // the driver thinks. + if (SupportsOffscreenSplit()) + raw_fGetIntegerv(LOCAL_GL_READ_FRAMEBUFFER_BINDING_EXT, &ret); + else + raw_fGetIntegerv(LOCAL_GL_FRAMEBUFFER_BINDING, &ret); + + bool abort = false; + + if (mInInternalBindingMode_ReadFBO) { + NS_ERROR("Read FBO still bound internally!"); + printf_stderr("Current internal read FBO: %d, user: %d)\n", ret, mUserBoundReadFBO); + abort = true; + } + + if (mInternalBoundReadFBO != (GLuint)ret) { + NS_ERROR("Read FBO binding misprediction!"); + printf_stderr("Bound read FBO was: %d, Expected: %d\n", ret, mInternalBoundReadFBO); + abort = true; + } + + if (abort) + NS_ABORT(); +#endif + + // We only ever expose the user's bound FBOs + return mUserBoundReadFBO; + } + + void BindUserDrawFBO(GLuint name) { + if (SupportsOffscreenSplit()) + fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER_EXT, name); + else + fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, name); +#ifdef DEBUG + mInInternalBindingMode_DrawFBO = false; +#endif } - GLuint GetFB() { - if (mScreen) { - // This has a very important extra assert that checks that we're - // not accidentally ignoring a situation where the draw and read - // FBs differ. - return mScreen->GetFB(); - } - - GLuint ret = 0; - GetUIntegerv(LOCAL_GL_FRAMEBUFFER_BINDING, &ret); - return ret; + void BindUserReadFBO(GLuint name) { + if (SupportsOffscreenSplit()) + fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER_EXT, name); + else + fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, name); +#ifdef DEBUG + mInInternalBindingMode_ReadFBO = false; +#endif + } + + GLuint GetUserBoundFBO() { + MOZ_ASSERT(GetUserBoundDrawFBO() == GetUserBoundReadFBO()); + return GetUserBoundReadFBO(); + } + + void BindUserFBO(GLuint name) { + fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, name); + } + + // BindInternalDraw/ReadFBO() switch us over into 'internal binding mode' + // for the corresponding Draw or Read binding. + // To exit internal binding mode, use BindUserDraw/ReadFBO(). + // While in internal binding mode for Draw/Read, the corresponding + // GetBoundUserDraw/ReadFBO() is undefined, and will trigger ABORT in DEBUG builds. + void BindInternalDrawFBO(GLuint name) { +#ifdef DEBUG + mInInternalBindingMode_DrawFBO = true; +#endif + if (SupportsOffscreenSplit()) + raw_fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER_EXT, name); + else + raw_fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, name); + + mInternalBoundDrawFBO = name; + } + + void BindInternalReadFBO(GLuint name) { +#ifdef DEBUG + mInInternalBindingMode_ReadFBO = true; +#endif + if (SupportsOffscreenSplit()) + raw_fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER_EXT, name); + else + raw_fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, name); + + mInternalBoundReadFBO = name; + } + + void BindInternalFBO(GLuint name) { + BindInternalDrawFBO(name); + BindInternalReadFBO(name); } void InitFramebuffers() { MakeCurrent(); - BindFB(0); + BindUserDrawFBO(0); + BindUserReadFBO(0); + } + + GLuint SwapUserDrawFBO(GLuint name) { + GLuint prev = GetUserBoundDrawFBO(); + BindUserDrawFBO(name); + return prev; + } + + GLuint SwapUserReadFBO(GLuint name) { + GLuint prev = GetUserBoundReadFBO(); + BindUserReadFBO(name); + return prev; } private: + bool mOffscreenFBOsDirty; + void GetShaderPrecisionFormatNonES2(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision) { switch (precisiontype) { case LOCAL_GL_LOW_FLOAT: case LOCAL_GL_MEDIUM_FLOAT: case LOCAL_GL_HIGH_FLOAT: // Assume IEEE 754 precision range[0] = 127; range[1] = 127; @@ -631,30 +904,73 @@ private: *precision = 0; break; } } // Do whatever setup is necessary to draw to our offscreen FBO, if it's // bound. void BeforeGLDrawCall() { + if (mInternalBoundDrawFBO != mOffscreenDrawFBO) + return; + + if (mOffscreenDrawFBO == mOffscreenReadFBO) + return; + + mOffscreenFBOsDirty = true; } // Do whatever tear-down is necessary after drawing to our offscreen FBO, // if it's bound. void AfterGLDrawCall() { - if (mScreen) - mScreen->AfterDrawCall(); } // Do whatever setup is necessary to read from our offscreen FBO, if it's // bound. void BeforeGLReadCall() { - if (mScreen) - mScreen->BeforeReadCall(); + if (mInternalBoundReadFBO != mOffscreenReadFBO) + return; + + if (mOffscreenDrawFBO == mOffscreenReadFBO) + return; + + // If we're not dirty, there's no need to blit + if (!mOffscreenFBOsDirty) + return; + + const bool scissor = fIsEnabled(LOCAL_GL_SCISSOR_TEST); + if (scissor) + fDisable(LOCAL_GL_SCISSOR_TEST); + + // Store current bindings for restoring later + GLuint prevDraw = GetUserBoundDrawFBO(); + GLuint prevRead = GetUserBoundReadFBO(); + + NS_ABORT_IF_FALSE(SupportsOffscreenSplit(), "Doesn't support offscreen split?"); + + // Manually setting internal bindings, entering internal mode + // Flip read/draw for blitting + BindInternalDrawFBO(mOffscreenReadFBO); + BindInternalReadFBO(mOffscreenDrawFBO); + + GLint width = mOffscreenActualSize.width; + GLint height = mOffscreenActualSize.height; + raw_fBlitFramebuffer(0, 0, width, height, + 0, 0, width, height, + LOCAL_GL_COLOR_BUFFER_BIT, + LOCAL_GL_NEAREST); + + // Reset to emulated user binding, exiting internal mode + BindUserDrawFBO(prevDraw); + BindUserReadFBO(prevRead); + + if (scissor) + fEnable(LOCAL_GL_SCISSOR_TEST); + + mOffscreenFBOsDirty = false; } // Do whatever tear-down is necessary after reading from our offscreen FBO, // if it's bound. void AfterGLReadCall() { } public: @@ -708,18 +1024,35 @@ public: y = FixYValue(y, height); BeforeGLReadCall(); raw_fCopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height); AfterGLReadCall(); } - void ForceDirtyScreen(); - void CleanDirtyScreen(); + void ForceDirtyFBOs() { + GLuint draw = SwapUserDrawFBO(0); + + BeforeGLDrawCall(); + // no-op; just pretend we did something + AfterGLDrawCall(); + + BindUserDrawFBO(draw); + } + + void BlitDirtyFBOs() { + GLuint read = SwapUserReadFBO(0); + + BeforeGLReadCall(); + // no-op; we just want to make sure the Read FBO is updated if it needs to be + AfterGLReadCall(); + + BindUserReadFBO(read); + } // Draw/Read void fBlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) { BeforeGLDrawCall(); BeforeGLReadCall(); raw_fBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter); AfterGLReadCall(); AfterGLDrawCall(); @@ -1086,21 +1419,16 @@ public: CONTEXT_INNOCENT_CONTEXT_RESET_ARB = 0x8254, CONTEXT_UNKNOWN_CONTEXT_RESET_ARB = 0x8255 }; bool HasRobustness() { return mHasRobustness; } - bool HasExt_FramebufferBlit() { - return IsExtensionSupported(EXT_framebuffer_blit) || - IsExtensionSupported(ANGLE_framebuffer_blit); - } - protected: bool mInitialized; bool mIsOffscreen; bool mIsGLES2; bool mIsGlobalSharedContext; bool mHasRobustness; bool mContextLost; @@ -1120,214 +1448,128 @@ public: #ifdef DEBUG return sDebugMode; #else return 0; #endif } protected: + + ContextFormat mCreationFormat; nsRefPtr<GLContext> mSharedContext; // The thread on which this context was created. nsCOMPtr<nsIThread> mOwningThread; GLContextSymbols mSymbols; #ifdef DEBUG // GLDebugMode will check that we don't send call // to a GLContext that isn't current on the current // thread. // Store the current context when binding to thread local // storage to support DebugMode on an arbitrary thread. static unsigned sCurrentGLContextTLS; #endif + + void UpdateActualFormat(); + ContextFormat mActualFormat; + + gfxIntSize mOffscreenSize; + gfxIntSize mOffscreenActualSize; + GLuint mOffscreenTexture; bool mFlipped; // lazy-initialized things GLuint mBlitProgram, mBlitFramebuffer; void UseBlitProgram(); void SetBlitFramebufferForDestTexture(GLuint aTexture); -public: - // Assumes shares are created by all sharing with the same global context. - bool SharesWith(const GLContext* other) const { - MOZ_ASSERT(!this->mSharedContext || !this->mSharedContext->mSharedContext); - MOZ_ASSERT(!other->mSharedContext || !other->mSharedContext->mSharedContext); - MOZ_ASSERT(!this->mSharedContext || - !other->mSharedContext || - this->mSharedContext == other->mSharedContext); - - const GLContext* thisShared = this->mSharedContext ? this->mSharedContext - : this; - const GLContext* otherShared = other->mSharedContext ? other->mSharedContext - : other; - - return thisShared == otherShared; - } - - bool InitOffscreen(const gfxIntSize& size, const SurfaceCaps& caps) { - if (!CreateScreenBuffer(size, caps)) + // Helper to create/resize an offscreen FBO, + // for offscreen implementations that use FBOs. + // Note that it does -not- clear the resized buffers. + bool ResizeOffscreenFBOs(const ContextFormat& aCF, const gfxIntSize& aSize, const bool aNeedsReadBuffer); + bool ResizeOffscreenFBOs(const gfxIntSize& aSize, const bool aNeedsReadBuffer) { + if (!IsOffscreenSizeAllowed(aSize)) return false; - InitFramebuffers(); - - mCaps = mScreen->Caps(); - UpdateGLFormats(caps); - UpdatePixelFormat(); - - return true; - } - -protected: - // Note that it does -not- clear the resized buffers. - bool CreateScreenBuffer(const gfxIntSize& size, const SurfaceCaps& caps) { - if (!IsOffscreenSizeAllowed(size)) - return false; - - SurfaceCaps tryCaps = caps; - if (tryCaps.antialias) { + ContextFormat format(mCreationFormat); + + if (format.samples) { // AA path - if (CreateScreenBufferImpl(size, tryCaps)) + if (ResizeOffscreenFBOs(format, aSize, aNeedsReadBuffer)) return true; - NS_WARNING("CreateScreenBuffer failed to initialize an AA context! Falling back to no AA..."); - tryCaps.antialias = false; + NS_WARNING("ResizeOffscreenFBOs failed to resize an AA context! Falling back to no AA..."); + format.samples = 0; } - MOZ_ASSERT(!tryCaps.antialias); - - if (CreateScreenBufferImpl(size, tryCaps)) + + if (ResizeOffscreenFBOs(format, aSize, aNeedsReadBuffer)) return true; - NS_WARNING("CreateScreenBuffer failed to initialize non-AA context!"); + NS_WARNING("ResizeOffscreenFBOs failed to resize non-AA context!"); return false; } - bool CreateScreenBufferImpl(const gfxIntSize& size, - const SurfaceCaps& caps); - -public: - bool ResizeScreenBuffer(const gfxIntSize& size); - -protected: - SurfaceCaps mCaps; - nsAutoPtr<GLFormats> mGLFormats; - nsAutoPtr<PixelBufferFormat> mPixelFormat; - + struct GLFormats { + GLFormats() + : texColor(0) + , texColorType(0) + , rbColor(0) + , depthStencil(0) + , depth(0) + , stencil(0) + , samples(0) + {} + + GLenum texColor; + GLenum texColorType; + GLenum rbColor; + GLenum depthStencil; + GLenum depth; + GLenum stencil; + GLsizei samples; + }; + + enum ColorByteOrder { + ForceRGBA, + DefaultByteOrder + }; + + GLFormats ChooseGLFormats(ContextFormat& aCF, GLContext::ColorByteOrder aByteOrder = GLContext::DefaultByteOrder); + void CreateTextureForOffscreen(const GLFormats& aFormats, const gfxIntSize& aSize, + GLuint& texture); + void CreateRenderbuffersForOffscreen(const GLContext::GLFormats& aFormats, const gfxIntSize& aSize, + GLuint& colorMSRB, GLuint& depthRB, GLuint& stencilRB); + bool AssembleOffscreenFBOs(const GLuint colorMSRB, + const GLuint depthRB, + const GLuint stencilRB, + const GLuint texture, + GLuint& drawFBO, + GLuint& readFBO); + + void DeleteOffscreenFBOs(); + + GLuint mOffscreenDrawFBO; + GLuint mOffscreenReadFBO; + GLuint mOffscreenColorRB; + GLuint mOffscreenDepthRB; + GLuint mOffscreenStencilRB; + + // Clear to transparent black, with 0 depth and stencil, + // while preserving current ClearColor etc. values. + // Useful for resizing offscreen buffers. public: - void DetermineCaps(); - const SurfaceCaps& Caps() const { - return mCaps; - } - - // Only varies based on bpp16 and alpha. - GLFormats ChooseGLFormats(const SurfaceCaps& caps) const; - void UpdateGLFormats(const SurfaceCaps& caps) { - mGLFormats = new GLFormats(ChooseGLFormats(caps)); - } - - const GLFormats& GetGLFormats() const { - MOZ_ASSERT(mGLFormats); - return *mGLFormats; - } - - PixelBufferFormat QueryPixelFormat(); - void UpdatePixelFormat(); - - const PixelBufferFormat& GetPixelFormat() const { - MOZ_ASSERT(mPixelFormat); - return *mPixelFormat; - } - - - GLuint CreateTextureForOffscreen(const GLFormats& formats, - const gfxIntSize& size); - GLuint CreateTexture(GLenum internalFormat, - GLenum format, GLenum type, - const gfxIntSize& size); - GLuint CreateRenderbuffer(GLenum format, - GLsizei samples, - const gfxIntSize& size); - bool IsFramebufferComplete(GLuint fb, GLenum* status = nullptr); - - // Pass null to an RB arg to disable its creation. - void CreateRenderbuffersForOffscreen(const GLFormats& formats, - const gfxIntSize& size, - bool multisample, - GLuint* colorMSRB, - GLuint* depthRB, - GLuint* stencilRB); - - // Does not check completeness. - void AttachBuffersToFB(GLuint colorTex, GLuint colorRB, - GLuint depthRB, GLuint stencilRB, - GLuint fb); - - // Passing null is fine if the value you'd get is 0. - bool AssembleOffscreenFBs(const GLuint colorMSRB, - const GLuint depthRB, - const GLuint stencilRB, - const GLuint texture, - GLuint* drawFB, - GLuint* readFB); - -protected: - friend class GLScreenBuffer; - GLScreenBuffer* mScreen; - - void DestroyScreenBuffer(); - - SharedSurface* mLockedSurface; - -public: - void LockSurface(SharedSurface* surf) { - MOZ_ASSERT(!mLockedSurface); - mLockedSurface = surf; - } - - void UnlockSurface(SharedSurface* surf) { - MOZ_ASSERT(mLockedSurface == surf); - mLockedSurface = nullptr; - } - - SharedSurface* GetLockedSurface() const { - return mLockedSurface; - } - - bool IsOffscreen() const { - return mScreen; - } - - GLScreenBuffer* Screen() const { - return mScreen; - } - - bool PublishFrame(); - SharedSurface* RequestFrame(); - - /* Clear to transparent black, with 0 depth and stencil, - * while preserving current ClearColor etc. values. - * Useful for resizing offscreen buffers. - */ void ClearSafely(); bool WorkAroundDriverBugs() const { return mWorkAroundDriverBugs; } protected: - nsRefPtr<TextureGarbageBin> mTexGarbageBin; - -public: - TextureGarbageBin* TexGarbageBin() { - MOZ_ASSERT(mTexGarbageBin); - return mTexGarbageBin; - } - - void EmptyTexGarbageBin(); - -protected: + nsDataHashtable<nsPtrHashKey<void>, void*> mUserData; void SetIsGLES2(bool aIsGLES2) { NS_ASSERTION(!mInitialized, "SetIsGLES2 can only be called before initialization!"); mIsGLES2 = aIsGLES2; } bool InitWithPrefix(const char *prefix, bool trygl); @@ -1350,17 +1592,16 @@ protected: nsTArray<nsIntRect> mViewportStack; nsTArray<nsIntRect> mScissorStack; GLint mMaxTextureSize; GLint mMaxCubeMapTextureSize; GLint mMaxTextureImageSize; GLint mMaxRenderbufferSize; - GLsizei mMaxSamples; bool mNeedsTextureSizeChecks; bool mWorkAroundDriverBugs; bool IsTextureSizeSafeToPassToDriver(GLenum target, GLsizei width, GLsizei height) const { if (mNeedsTextureSizeChecks) { // some drivers incorrectly handle some large texture sizes that are below the // max texture size that they report. So we check ourselves against our own values // (mMax[CubeMap]TextureSize). @@ -1407,17 +1648,16 @@ public: #endif protected: GLenum mGLError; public: void BeforeGLCall(const char* glFunction) { - MOZ_ASSERT(IsCurrent()); if (DebugMode()) { GLContext *currentGLContext = NULL; currentGLContext = (GLContext*)PR_GetThreadPrivate(sCurrentGLContextTLS); if (DebugMode() & DebugTrace) printf_stderr("[gl:%p] > %s\n", this, glFunction); if (this != currentGLContext) { @@ -2387,17 +2627,17 @@ private: public: void fBindRenderbuffer(GLenum target, GLuint renderbuffer) { BEFORE_GL_CALL; mSymbols.fBindRenderbuffer(target, renderbuffer); AFTER_GL_CALL; } - GLenum fCheckFramebufferStatus(GLenum target) { + GLenum fCheckFramebufferStatus (GLenum target) { BEFORE_GL_CALL; GLenum retval = mSymbols.fCheckFramebufferStatus(target); AFTER_GL_CALL; return retval; } void fFramebufferRenderbuffer(GLenum target, GLenum attachmentPoint, GLenum renderbufferTarget, GLuint renderbuffer) { BEFORE_GL_CALL; @@ -2664,24 +2904,16 @@ public: } void fDeleteBuffers(GLsizei n, GLuint *names) { raw_fDeleteBuffers(n, names); TRACKING_CONTEXT(DeletedBuffers(this, n, names)); } void fDeleteFramebuffers(GLsizei n, GLuint *names) { - if (mScreen) { - // Notify mScreen which framebuffers we're deleting. - // Otherwise, we will get framebuffer binding mispredictions. - for (int i = 0; i < n; i++) { - mScreen->DeletingFB(names[i]); - } - } - if (n == 1 && *names == 0) { // Deleting framebuffer 0 causes hangs on the DROID. See bug 623228. } else { raw_fDeleteFramebuffers(n, names); } TRACKING_CONTEXT(DeletedFramebuffers(this, n, names)); } @@ -2761,24 +2993,16 @@ public: // OES_EGL_image (GLES) void fEGLImageTargetTexture2D(GLenum target, GLeglImage image) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fEGLImageTargetTexture2D); mSymbols.fEGLImageTargetTexture2D(target, image); AFTER_GL_CALL; } - void fEGLImageTargetRenderbufferStorage(GLenum target, GLeglImage image) - { - BEFORE_GL_CALL; - ASSERT_SYMBOL_PRESENT(fEGLImageTargetRenderbufferStorage); - mSymbols.fEGLImageTargetRenderbufferStorage(target, image); - AFTER_GL_CALL; - } - #undef ASSERT_SYMBOL_PRESENT #ifdef DEBUG void THEBES_API CreatedProgram(GLContext *aOrigin, GLuint aName); void THEBES_API CreatedShader(GLContext *aOrigin, GLuint aName); void THEBES_API CreatedBuffers(GLContext *aOrigin, GLsizei aCount, GLuint *aNames); void THEBES_API CreatedTextures(GLContext *aOrigin, GLsizei aCount, GLuint *aNames); void THEBES_API CreatedFramebuffers(GLContext *aOrigin, GLsizei aCount, GLuint *aNames); @@ -2899,288 +3123,147 @@ public: Derived* derived = static_cast<Derived*>(this); derived->UnwrapImpl(); mIsUnwrapped = true; } }; +struct ScopedFramebufferTexture + : public ScopedGLWrapper<ScopedFramebufferTexture> +{ + friend struct ScopedGLWrapper<ScopedFramebufferTexture>; + +protected: + bool mComplete; // True if the framebuffer we create is complete. + GLuint mFB; + +public: + ScopedFramebufferTexture(GLContext* gl, GLuint texture) + : ScopedGLWrapper<ScopedFramebufferTexture>(gl) + , mComplete(false) + , mFB(0) + { + MOZ_ASSERT(mGL->IsCurrent()); + GLuint boundFB = mGL->GetUserBoundFBO(); + + mGL->fGenFramebuffers(1, &mFB); + mGL->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, mFB); + mGL->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, + LOCAL_GL_COLOR_ATTACHMENT0, + LOCAL_GL_TEXTURE_2D, + texture, + 0); + + GLenum status = mGL->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER); + if (status == LOCAL_GL_FRAMEBUFFER_COMPLETE) { + mComplete = true; + } else { + mGL->fDeleteFramebuffers(1, &mFB); + mFB = 0; + } + + mGL->BindUserFBO(boundFB); + } + +protected: + void UnwrapImpl() { + if (!mFB) + return; + + MOZ_ASSERT(mGL->IsCurrent()); + mGL->fDeleteFramebuffers(1, &mFB); + mFB = 0; + } + +public: + GLuint FB() const { + return mFB; + } + + bool IsComplete() const { + return mComplete; + } +}; + // Wraps glEnable/Disable. struct ScopedGLState : public ScopedGLWrapper<ScopedGLState> { friend struct ScopedGLWrapper<ScopedGLState>; protected: const GLenum mCapability; bool mOldState; public: // Use |newState = true| to enable, |false| to disable. ScopedGLState(GLContext* gl, GLenum capability, bool newState) : ScopedGLWrapper<ScopedGLState>(gl) , mCapability(capability) { + MOZ_ASSERT(mGL->IsCurrent()); mOldState = mGL->fIsEnabled(mCapability); // Early out if we're already in the right state. if (newState == mOldState) return; if (newState) mGL->fEnable(mCapability); else mGL->fDisable(mCapability); } protected: void UnwrapImpl() { + MOZ_ASSERT(mGL->IsCurrent()); + if (mOldState) mGL->fEnable(mCapability); else mGL->fDisable(mCapability); } }; -// Saves and restores with GetUserBoundFB and BindUserFB. -struct ScopedBindFramebuffer - : public ScopedGLWrapper<ScopedBindFramebuffer> +// Saves and restores with GetUserBoundFBO and BindUserFBO. +struct ScopedFramebufferBinding + : public ScopedGLWrapper<ScopedFramebufferBinding> { - friend struct ScopedGLWrapper<ScopedBindFramebuffer>; + friend struct ScopedGLWrapper<ScopedFramebufferBinding>; protected: - GLuint mOldFB; - -private: - void Init() { - mOldFB = mGL->GetFB(); - } - -public: - explicit ScopedBindFramebuffer(GLContext* gl) - : ScopedGLWrapper<ScopedBindFramebuffer>(gl) - { - Init(); - } - - ScopedBindFramebuffer(GLContext* gl, GLuint newFB) - : ScopedGLWrapper<ScopedBindFramebuffer>(gl) - { - Init(); - mGL->BindFB(newFB); - } - -protected: - void UnwrapImpl() { - // Check that we're not falling out of scope after - // the current context changed. - MOZ_ASSERT(mGL->IsCurrent()); - - mGL->BindFB(mOldFB); - } -}; - -struct ScopedBindTexture - : public ScopedGLWrapper<ScopedBindTexture> -{ - friend struct ScopedGLWrapper<ScopedBindTexture>; - -protected: - GLuint mOldTex; + GLuint mOldState; private: void Init() { - mOldTex = 0; - mGL->GetUIntegerv(LOCAL_GL_TEXTURE_BINDING_2D, &mOldTex); + MOZ_ASSERT(mGL->IsCurrent()); + mOldState = mGL->GetUserBoundFBO(); } public: - explicit ScopedBindTexture(GLContext* gl) - : ScopedGLWrapper<ScopedBindTexture>(gl) + ScopedFramebufferBinding(GLContext* gl) + : ScopedGLWrapper<ScopedFramebufferBinding>(gl) { Init(); } - ScopedBindTexture(GLContext* gl, GLuint newTex) - : ScopedGLWrapper<ScopedBindTexture>(gl) + ScopedFramebufferBinding(GLContext* gl, GLuint newFB) + : ScopedGLWrapper<ScopedFramebufferBinding>(gl) { Init(); - mGL->fBindTexture(LOCAL_GL_TEXTURE_2D, newTex); - } - -protected: - void UnwrapImpl() { - // Check that we're not falling out of scope after - // the current context changed. - MOZ_ASSERT(mGL->IsCurrent()); - - mGL->fBindTexture(LOCAL_GL_TEXTURE_2D, mOldTex); - } -}; - - -struct ScopedBindRenderbuffer - : public ScopedGLWrapper<ScopedBindRenderbuffer> -{ - friend struct ScopedGLWrapper<ScopedBindRenderbuffer>; - -protected: - GLuint mOldRB; - -private: - void Init() { - mOldRB = 0; - mGL->GetUIntegerv(LOCAL_GL_RENDERBUFFER_BINDING, &mOldRB); - } - -public: - explicit ScopedBindRenderbuffer(GLContext* gl) - : ScopedGLWrapper<ScopedBindRenderbuffer>(gl) - { - Init(); - } - - ScopedBindRenderbuffer(GLContext* gl, GLuint newRB) - : ScopedGLWrapper<ScopedBindRenderbuffer>(gl) - { - Init(); - mGL->fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, newRB); + mGL->BindUserFBO(newFB); } protected: void UnwrapImpl() { - // Check that we're not falling out of scope after - // the current context changed. MOZ_ASSERT(mGL->IsCurrent()); - - mGL->fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, mOldRB); - } -}; - -struct ScopedFramebufferForTexture - : public ScopedGLWrapper<ScopedFramebufferForTexture> -{ - friend struct ScopedGLWrapper<ScopedFramebufferForTexture>; - -protected: - bool mComplete; // True if the framebuffer we create is complete. - GLuint mFB; - -public: - ScopedFramebufferForTexture(GLContext* gl, GLuint texture) - : ScopedGLWrapper<ScopedFramebufferForTexture>(gl) - , mComplete(false) - , mFB(0) - { - mGL->fGenFramebuffers(1, &mFB); - ScopedBindFramebuffer autoFB(gl, mFB); - mGL->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, - LOCAL_GL_COLOR_ATTACHMENT0, - LOCAL_GL_TEXTURE_2D, - texture, - 0); - - GLenum status = mGL->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER); - if (status == LOCAL_GL_FRAMEBUFFER_COMPLETE) { - mComplete = true; - } else { - mGL->fDeleteFramebuffers(1, &mFB); - mFB = 0; - } - } - -protected: - void UnwrapImpl() { - if (!mFB) - return; - - mGL->fDeleteFramebuffers(1, &mFB); - mFB = 0; - } - -public: - GLuint FB() const { - MOZ_ASSERT(IsComplete()); - return mFB; - } - - bool IsComplete() const { - return mComplete; + mGL->BindUserFBO(mOldState); } }; -struct ScopedFramebufferForRenderbuffer - : public ScopedGLWrapper<ScopedFramebufferForRenderbuffer> -{ - friend struct ScopedGLWrapper<ScopedFramebufferForRenderbuffer>; - -protected: - bool mComplete; // True if the framebuffer we create is complete. - GLuint mFB; - -public: - ScopedFramebufferForRenderbuffer(GLContext* gl, GLuint rb) - : ScopedGLWrapper<ScopedFramebufferForRenderbuffer>(gl) - , mComplete(false) - , mFB(0) - { - mGL->fGenFramebuffers(1, &mFB); - ScopedBindFramebuffer autoFB(gl, mFB); - mGL->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, - LOCAL_GL_COLOR_ATTACHMENT0, - LOCAL_GL_RENDERBUFFER, - rb); - - GLenum status = mGL->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER); - if (status == LOCAL_GL_FRAMEBUFFER_COMPLETE) { - mComplete = true; - } else { - mGL->fDeleteFramebuffers(1, &mFB); - mFB = 0; - } - } - -protected: - void UnwrapImpl() { - if (!mFB) - return; - - mGL->fDeleteFramebuffers(1, &mFB); - mFB = 0; - } - -public: - GLuint FB() const { - return mFB; - } - - bool IsComplete() const { - return mComplete; - } -}; - - -class TextureGarbageBin { - NS_INLINE_DECL_THREADSAFE_REFCOUNTING(TextureGarbageBin) - -protected: - GLContext* mGL; - Mutex mMutex; - std::stack<GLuint> mGarbageTextures; - -public: - TextureGarbageBin(GLContext* gl) - : mGL(gl) - , mMutex("TextureGarbageBin mutex") - {} - - void GLContextTeardown(); - void Trash(GLuint tex); - void EmptyGarbage(); -}; - uint32_t GetBitsPerTexel(GLenum format, GLenum type); } /* namespace gl */ } /* namespace mozilla */ #endif /* GLCONTEXT_H_ */
--- a/gfx/gl/GLContextProvider.h +++ b/gfx/gl/GLContextProvider.h @@ -5,17 +5,16 @@ #ifndef GLCONTEXTPROVIDER_H_ #define GLCONTEXTPROVIDER_H_ #include "GLContext.h" #include "gfxTypes.h" #include "gfxPoint.h" #include "nsAutoPtr.h" -#include "SurfaceTypes.h" class nsIWidget; class gfxASurface; namespace mozilla { namespace gl { #define IN_GL_CONTEXT_PROVIDER_H
--- a/gfx/gl/GLContextProviderCGL.mm +++ b/gfx/gl/GLContextProviderCGL.mm @@ -13,18 +13,16 @@ #include "gfxImageSurface.h" #include "gfxQuartzSurface.h" #include "gfxPlatform.h" #include "gfxFailure.h" #include "prenv.h" #include "mozilla/Preferences.h" #include "sampler.h" -using namespace mozilla::gfx; - namespace mozilla { namespace gl { static bool gUseDoubleBufferedWindows = true; class CGLLibrary { public: @@ -81,31 +79,45 @@ private: CGLLibrary sCGLLibrary; class GLContextCGL : public GLContext { friend class GLContextProviderCGL; public: - GLContextCGL(const SurfaceCaps& caps, - GLContext *shareContext, - NSOpenGLContext *context, - bool isOffscreen = false) - : GLContext(caps, shareContext, isOffscreen), - mContext(context), + GLContextCGL(const ContextFormat& aFormat, + GLContext *aShareContext, + NSOpenGLContext *aContext, + bool aIsOffscreen = false) + : GLContext(aFormat, aIsOffscreen, aShareContext), + mContext(aContext), + mPBuffer(nullptr), mTempTextureName(0) - {} + { } + + GLContextCGL(const ContextFormat& aFormat, + GLContext *aShareContext, + NSOpenGLContext *aContext, + NSOpenGLPixelBuffer *aPixelBuffer) + : GLContext(aFormat, true, aShareContext), + mContext(aContext), + mPBuffer(aPixelBuffer), + mTempTextureName(0) + { } ~GLContextCGL() { MarkDestroyed(); if (mContext) [mContext release]; + + if (mPBuffer) + [mPBuffer release]; } GLContextType GetContextType() { return ContextTypeCGL; } bool Init() { @@ -163,34 +175,122 @@ public: bool SwapBuffers() { SAMPLE_LABEL("GLContext", "SwapBuffers"); [mContext flushBuffer]; return true; } + bool BindTex2DOffscreen(GLContext *aOffscreen); + void UnbindTex2DOffscreen(GLContext *aOffscreen); bool ResizeOffscreen(const gfxIntSize& aNewSize); virtual already_AddRefed<TextureImage> CreateBasicTextureImage(GLuint aTexture, const nsIntSize& aSize, GLenum aWrapMode, TextureImage::ContentType aContentType, GLContext* aContext, TextureImage::Flags aFlags = TextureImage::NoFlags); NSOpenGLContext *mContext; + NSOpenGLPixelBuffer *mPBuffer; GLuint mTempTextureName; }; bool +GLContextCGL::BindTex2DOffscreen(GLContext *aOffscreen) +{ + if (aOffscreen->GetContextType() != ContextTypeCGL) { + NS_WARNING("non-CGL context"); + return false; + } + + if (!aOffscreen->IsOffscreen()) { + NS_WARNING("non-offscreen context"); + return false; + } + + GLContextCGL *offs = static_cast<GLContextCGL*>(aOffscreen); + + if (offs->mPBuffer) { + fGenTextures(1, &mTempTextureName); + fBindTexture(LOCAL_GL_TEXTURE_2D, mTempTextureName); + + [mContext + setTextureImageToPixelBuffer:offs->mPBuffer + colorBuffer:LOCAL_GL_FRONT]; + } else if (offs->mOffscreenTexture) { + if (offs->GetSharedContext() != GLContextProviderCGL::GetGlobalContext()) + { + NS_WARNING("offscreen FBO context can only be bound with context sharing!"); + return false; + } + + fBindTexture(LOCAL_GL_TEXTURE_2D, offs->mOffscreenTexture); + } else { + NS_WARNING("don't know how to bind this!"); + return false; + } + + return true; +} + +void +GLContextCGL::UnbindTex2DOffscreen(GLContext *aOffscreen) +{ + NS_ASSERTION(aOffscreen->GetContextType() == ContextTypeCGL, "wrong type"); + + GLContextCGL *offs = static_cast<GLContextCGL*>(aOffscreen); + if (offs->mPBuffer) { + NS_ASSERTION(mTempTextureName, "We didn't have an offscreen texture name?"); + fDeleteTextures(1, &mTempTextureName); + mTempTextureName = 0; + } +} + +bool GLContextCGL::ResizeOffscreen(const gfxIntSize& aNewSize) { - return ResizeScreenBuffer(aNewSize); + if (!IsOffscreenSizeAllowed(aNewSize)) + return false; + + if (mPBuffer) { + NSOpenGLPixelBuffer *pb = [[NSOpenGLPixelBuffer alloc] + initWithTextureTarget:LOCAL_GL_TEXTURE_2D + textureInternalFormat:(mCreationFormat.alpha ? LOCAL_GL_RGBA : LOCAL_GL_RGB) + textureMaxMipMapLevel:0 + pixelsWide:aNewSize.width + pixelsHigh:aNewSize.height]; + if (!pb) { + return false; + } + + if (!ResizeOffscreenFBOs(aNewSize, false)) { + [pb release]; + return false; + } + + [mPBuffer release]; + mPBuffer = pb; + + mOffscreenSize = aNewSize; + mOffscreenActualSize = aNewSize; + + [mContext setPixelBuffer:pb cubeMapFace:0 mipMapLevel:0 + currentVirtualScreen:[mContext currentVirtualScreen]]; + + MakeCurrent(); + ClearSafely(); + + return true; + } + + return ResizeOffscreenFBOs(aNewSize, true); } class TextureImageCGL : public BasicTextureImage { friend already_AddRefed<TextureImage> GLContextCGL::CreateBasicTextureImage(GLuint, const nsIntSize&, GLenum, @@ -326,29 +426,123 @@ GLContextProviderCGL::CreateForWindow(ns NSOpenGLContext *context = [[NSOpenGLContext alloc] initWithFormat:sCGLLibrary.PixelFormat() shareContext:(shareContext ? shareContext->mContext : NULL)]; if (!context) { return nullptr; } // make the context transparent - SurfaceCaps caps = SurfaceCaps::ForRGBA(); - nsRefPtr<GLContextCGL> glContext = new GLContextCGL(caps, + nsRefPtr<GLContextCGL> glContext = new GLContextCGL(ContextFormat(ContextFormat::BasicRGB24), shareContext, context); if (!glContext->Init()) { return nullptr; } return glContext.forget(); } static already_AddRefed<GLContextCGL> -CreateOffscreenFBOContext(bool aShare = true) +CreateOffscreenPBufferContext(const gfxIntSize& aSize, + const ContextFormat& aFormat, + bool aShare = false) +{ + if (!sCGLLibrary.EnsureInitialized()) { + return nullptr; + } + + GLContextCGL *shareContext = aShare ? GetGlobalContextCGL() : nullptr; + if (aShare && !shareContext) { + return nullptr; + } + + nsTArray<NSOpenGLPixelFormatAttribute> attribs; + +#define A_(_x) attribs.AppendElement(NSOpenGLPixelFormatAttribute(_x)) + A_(NSOpenGLPFAAccelerated); + A_(NSOpenGLPFAPixelBuffer); + A_(NSOpenGLPFAMinimumPolicy); + + A_(NSOpenGLPFAColorSize); + A_(aFormat.colorBits()); + + A_(NSOpenGLPFAAlphaSize); + A_(aFormat.alpha); + + A_(NSOpenGLPFADepthSize); + A_(aFormat.depth); + + A_(NSOpenGLPFAStencilSize); + A_(aFormat.stencil); + + A_(0); +#undef A_ + + NSOpenGLPixelFormat *pbFormat = [[NSOpenGLPixelFormat alloc] + initWithAttributes:attribs.Elements()]; + if (!pbFormat) { + return nullptr; + } + + // If we ask for any of these to be on/off and we get the opposite, we stop + // creating a pbuffer and instead create an FBO. + GLint alphaBits, depthBits, stencilBits; + [pbFormat getValues: &alphaBits forAttribute: NSOpenGLPFAAlphaSize forVirtualScreen: 0]; + [pbFormat getValues: &depthBits forAttribute: NSOpenGLPFADepthSize forVirtualScreen: 0]; + [pbFormat getValues: &stencilBits forAttribute: NSOpenGLPFAStencilSize forVirtualScreen: 0]; + if ((alphaBits && !aFormat.alpha) || (!alphaBits && aFormat.alpha) || + (depthBits && !aFormat.alpha) || (!depthBits && aFormat.depth) || + (stencilBits && !aFormat.stencil) || (!stencilBits && aFormat.stencil)) + { + [pbFormat release]; + return nullptr; + } + + NSOpenGLPixelBuffer *pb = [[NSOpenGLPixelBuffer alloc] + initWithTextureTarget:LOCAL_GL_TEXTURE_2D + textureInternalFormat:(aFormat.alpha ? LOCAL_GL_RGBA : LOCAL_GL_RGB) + textureMaxMipMapLevel:0 + pixelsWide:aSize.width + pixelsHigh:aSize.height]; + if (!pb) { + [pbFormat release]; + return nullptr; + } + + NSOpenGLContext *context = [[NSOpenGLContext alloc] + initWithFormat:pbFormat + shareContext:shareContext ? shareContext->mContext : NULL]; + if (!context) { + [pbFormat release]; + [pb release]; + return nullptr; + } + + [context + setPixelBuffer:pb + cubeMapFace:0 + mipMapLevel:0 + currentVirtualScreen:[context currentVirtualScreen]]; + + { + GLint l; + [pbFormat getValues:&l forAttribute:NSOpenGLPFADepthSize forVirtualScreen:[context currentVirtualScreen]]; + } + + [pbFormat release]; + + nsRefPtr<GLContextCGL> glContext = new GLContextCGL(aFormat, shareContext, context, pb); + + return glContext.forget(); +} + +static already_AddRefed<GLContextCGL> +CreateOffscreenFBOContext(const ContextFormat& aFormat, + bool aShare = true) { if (!sCGLLibrary.EnsureInitialized()) { return nullptr; } GLContextCGL *shareContext = aShare ? GetGlobalContextCGL() : nullptr; if (aShare && !shareContext) { // if there is no share context, then we can't use FBOs. @@ -357,31 +551,51 @@ CreateOffscreenFBOContext(bool aShare = NSOpenGLContext *context = [[NSOpenGLContext alloc] initWithFormat:sCGLLibrary.PixelFormat() shareContext:shareContext ? shareContext->mContext : NULL]; if (!context) { return nullptr; } - SurfaceCaps dummyCaps = SurfaceCaps::Any(); - nsRefPtr<GLContextCGL> glContext = new GLContextCGL(dummyCaps, shareContext, context, true); + nsRefPtr<GLContextCGL> glContext = new GLContextCGL(aFormat, shareContext, context, true); return glContext.forget(); } already_AddRefed<GLContext> -GLContextProviderCGL::CreateOffscreen(const gfxIntSize& size, - const SurfaceCaps& caps, +GLContextProviderCGL::CreateOffscreen(const gfxIntSize& aSize, + const ContextFormat& aFormat, const ContextFlags flags) { - nsRefPtr<GLContextCGL> glContext = CreateOffscreenFBOContext(); + ContextFormat actualFormat(aFormat); + + nsRefPtr<GLContextCGL> glContext; + + NS_ENSURE_TRUE(Preferences::GetRootBranch(), nullptr); + const bool preferFBOs = Preferences::GetBool("cgl.prefer-fbo", true); + if (!preferFBOs) + { + glContext = CreateOffscreenPBufferContext(aSize, actualFormat); + if (glContext && + glContext->Init() && + glContext->ResizeOffscreenFBOs(aSize, false)) + { + glContext->mOffscreenSize = aSize; + glContext->mOffscreenActualSize = aSize; + + return glContext.forget(); + } + } + + // try a FBO as second choice + glContext = CreateOffscreenFBOContext(actualFormat); if (glContext && glContext->Init() && - glContext->InitOffscreen(size, caps)) + glContext->ResizeOffscreenFBOs(aSize, true)) { return glContext.forget(); } // everything failed return nullptr; } @@ -394,17 +608,18 @@ GLContextProviderCGL::GetGlobalContext(c return nullptr; } if (!gGlobalContext) { // There are bugs in some older drivers with pbuffers less // than 16x16 in size; also 16x16 is POT so that we can do // a FBO with it on older video cards. A FBO context for // sharing is preferred since it has no associated target. - gGlobalContext = CreateOffscreenFBOContext(false); + gGlobalContext = CreateOffscreenFBOContext(ContextFormat(ContextFormat::BasicRGB24), + false); if (!gGlobalContext || !static_cast<GLContextCGL*>(gGlobalContext.get())->Init()) { NS_WARNING("Couldn't init gGlobalContext."); gGlobalContext = nullptr; return nullptr; } gGlobalContext->SetIsGlobalSharedContext(true); }
--- a/gfx/gl/GLContextProviderEGL.cpp +++ b/gfx/gl/GLContextProviderEGL.cpp @@ -30,25 +30,27 @@ #endif #if defined(ANDROID) /* from widget */ #if defined(MOZ_WIDGET_ANDROID) #include "AndroidBridge.h" #include "nsSurfaceTexture.h" #endif - #include <android/log.h> #define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "Gonk" , ## args) # if defined(MOZ_WIDGET_GONK) # include "cutils/properties.h" # include <ui/GraphicBuffer.h> using namespace android; + +# define EGL_NATIVE_BUFFER_ANDROID 0x3140 + # endif #endif #define GLES2_LIB "libGLESv2.so" #define GLES2_LIB2 "libGLESv2.so.2" #elif defined(XP_WIN) @@ -125,18 +127,16 @@ static bool gUseBackingSurface = true; #else static bool gUseBackingSurface = false; #endif #ifdef MOZ_WIDGET_GONK extern nsIntRect gScreenBounds; #endif -#define EGL_DISPLAY() sEGLLibrary.Display() - namespace mozilla { namespace gl { static GLLibraryEGL sEGLLibrary; #define ADD_ATTR_2(_array, _k, _v) do { \ (_array).AppendElement(_k); \ (_array).AppendElement(_v); \ @@ -196,90 +196,81 @@ is_power_of_two(int v) return (v & (v-1)) == 0; } class GLContextEGL : public GLContext { friend class TextureImageEGL; static already_AddRefed<GLContextEGL> - CreateGLContext(const SurfaceCaps& caps, + CreateGLContext(const ContextFormat& format, + EGLSurface surface, + EGLConfig config, GLContextEGL *shareContext, - bool isOffscreen, - EGLConfig config, - EGLSurface surface) + bool aIsOffscreen = false) { - if (sEGLLibrary.fBindAPI(LOCAL_EGL_OPENGL_ES_API) == LOCAL_EGL_FALSE) { - NS_WARNING("Failed to bind API to GLES!"); - return nullptr; - } - - EGLContext eglShareContext = shareContext ? shareContext->mContext - : EGL_NO_CONTEXT; - EGLint* attribs = sEGLLibrary.HasRobustness() ? gContextAttribsRobustness - : gContextAttribs; - - EGLContext context = sEGLLibrary.fCreateContext(EGL_DISPLAY(), - config, - eglShareContext, - attribs); - if (!context && shareContext) { - shareContext = nullptr; - context = sEGLLibrary.fCreateContext(EGL_DISPLAY(), - config, - EGL_NO_CONTEXT, - attribs); - if (!context) { - NS_WARNING("Failed to create EGLContext!"); - return nullptr; + EGLContext context; + + context = sEGLLibrary.fCreateContext(EGL_DISPLAY(), + config, + shareContext ? shareContext->mContext : EGL_NO_CONTEXT, + sEGLLibrary.HasRobustness() ? gContextAttribsRobustness + : gContextAttribs); + if (!context) { + if (shareContext) { + shareContext = nullptr; + context = sEGLLibrary.fCreateContext(EGL_DISPLAY(), + config, + EGL_NO_CONTEXT, + sEGLLibrary.HasRobustness() ? gContextAttribsRobustness + : gContextAttribs); + if (!context) { + NS_WARNING("Failed to create EGLContext!"); + return nullptr; + } } } - nsRefPtr<GLContextEGL> glContext = new GLContextEGL(caps, - shareContext, - isOffscreen, - config, - surface, - context); + nsRefPtr<GLContextEGL> glContext = + new GLContextEGL(format, shareContext, config, + surface, context, aIsOffscreen); if (!glContext->Init()) return nullptr; return glContext.forget(); } public: - GLContextEGL(const SurfaceCaps& caps, - GLContext* shareContext, - bool isOffscreen, - EGLConfig config, - EGLSurface surface, - EGLContext context) - : GLContext(caps, shareContext, isOffscreen) - , mConfig(config) - , mSurface(surface) - , mCurSurface(surface) - , mContext(context) + GLContextEGL(const ContextFormat& aFormat, + GLContext *aShareContext, + EGLConfig aConfig, + EGLSurface aSurface, + EGLContext aContext, + bool aIsOffscreen = false) + : GLContext(aFormat, aIsOffscreen, aShareContext) + , mConfig(aConfig) + , mSurface(aSurface), mContext(aContext) , mPlatformContext(nullptr) , mThebesSurface(nullptr) , mBound(false) , mIsPBuffer(false) , mIsDoubleBuffered(false) , mCanBindToTexture(false) , mShareWithEGLImage(false) , mTemporaryEGLImageTexture(0) { // any EGL contexts will always be GLESv2 SetIsGLES2(true); #ifdef DEBUG printf_stderr("Initializing context %p surface %p on display %p\n", mContext, mSurface, EGL_DISPLAY()); #endif #ifdef MOZ_WIDGET_GONK - if (!mIsOffscreen) { + if (!aIsOffscreen) { mHwc = HwcComposer2D::GetInstance(); MOZ_ASSERT(!mHwc->Initialized()); if (mHwc->Init(EGL_DISPLAY(), mSurface)) { NS_WARNING("HWComposer initialization failed!"); mHwc = nullptr; } } @@ -367,25 +358,16 @@ public: bool IsDoubleBuffered() { return mIsDoubleBuffered; } void SetIsDoubleBuffered(bool aIsDB) { mIsDoubleBuffered = aIsDB; } - virtual EGLContext GetEGLContext() { - return mContext; - } - - virtual GLLibraryEGL* GetLibraryEGL() { - return &sEGLLibrary; - } - - bool SupportsRobustness() { return sEGLLibrary.HasRobustness(); } virtual bool IsANGLE() { return sEGLLibrary.IsANGLE(); @@ -431,17 +413,17 @@ public: { #if defined(MOZ_WIDGET_GONK) EGLint attrs[] = { LOCAL_EGL_IMAGE_PRESERVED, LOCAL_EGL_TRUE, LOCAL_EGL_NONE, LOCAL_EGL_NONE }; EGLImage image = sEGLLibrary.fCreateImage(EGL_DISPLAY(), EGL_NO_CONTEXT, - LOCAL_EGL_NATIVE_BUFFER_ANDROID, + EGL_NATIVE_BUFFER_ANDROID, buffer, attrs); fBindTexture(LOCAL_GL_TEXTURE_EXTERNAL, texture); fEGLImageTargetTexture2D(LOCAL_GL_TEXTURE_EXTERNAL, image); sEGLLibrary.fDestroyImage(EGL_DISPLAY(), image); return true; #else return false; #endif @@ -463,29 +445,16 @@ public: #endif } #ifdef MOZ_WIDGET_GONK virtual already_AddRefed<TextureImage> CreateDirectTextureImage(GraphicBuffer* aBuffer, GLenum aWrapMode) MOZ_OVERRIDE; #endif - virtual void MakeCurrent_EGLSurface(void* surf) { - EGLSurface eglSurface = (EGLSurface)surf; - if (!eglSurface) - eglSurface = mSurface; - - if (eglSurface == mCurSurface) - return; - - // Else, surface changed... - mCurSurface = eglSurface; - MakeCurrent(true); - } - bool MakeCurrentImpl(bool aForce = false) { bool succeeded = true; // Assume that EGL has the same problem as WGL does, // where MakeCurrent with an already-current context is // still expensive. #ifndef MOZ_WIDGET_QT if (!mSurface) { @@ -509,17 +478,17 @@ public: if (mSharedContext) { QGLContext* qglCtx = static_cast<QGLContext*>(static_cast<GLContextEGL*>(mSharedContext.get())->mPlatformContext); if (qglCtx) { qglCtx->doneCurrent(); } } #endif succeeded = sEGLLibrary.fMakeCurrent(EGL_DISPLAY(), - mCurSurface, mCurSurface, + mSurface, mSurface, mContext); int eglError = sEGLLibrary.fGetError(); if (!succeeded) { if (eglError == LOCAL_EGL_CONTEXT_LOST) { mContextLost = true; NS_WARNING("EGL context has been lost."); } else { @@ -635,20 +604,51 @@ public: } bool BindTex2DOffscreen(GLContext *aOffscreen); void UnbindTex2DOffscreen(GLContext *aOffscreen); bool ResizeOffscreen(const gfxIntSize& aNewSize); void BindOffscreenFramebuffer(); static already_AddRefed<GLContextEGL> - CreateEGLPixmapOffscreenContext(const gfxIntSize& size); + CreateEGLPixmapOffscreenContext(const gfxIntSize& aSize, + const ContextFormat& aFormat, + bool aShare); static already_AddRefed<GLContextEGL> - CreateEGLPBufferOffscreenContext(const gfxIntSize& size); + CreateEGLPBufferOffscreenContext(const gfxIntSize& aSize, + const ContextFormat& aFormat, + bool bufferUnused = false); + + void SetOffscreenSize(const gfxIntSize &aRequestedSize, + const gfxIntSize &aActualSize) + { + mOffscreenSize = aRequestedSize; + mOffscreenActualSize = aActualSize; + } + + void *GetD3DShareHandle() { + if (!sEGLLibrary.HasANGLESurfaceD3DTexture2DShareHandle()) { + return nullptr; + } + + void *h = nullptr; + +#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 nullptr; + } + + return h; + } virtual bool HasLockSurface() { return sEGLLibrary.HasKHRLockSurface(); } virtual SharedTextureHandle CreateSharedHandle(SharedTextureShareType shareType); virtual SharedTextureHandle CreateSharedHandle(SharedTextureShareType shareType, void* buffer, @@ -657,23 +657,21 @@ public: SharedTextureHandle sharedHandle); virtual void ReleaseSharedHandle(SharedTextureShareType shareType, SharedTextureHandle sharedHandle); virtual bool GetSharedHandleDetails(SharedTextureShareType shareType, SharedTextureHandle sharedHandle, SharedHandleDetails& details); virtual bool AttachSharedHandle(SharedTextureShareType shareType, SharedTextureHandle sharedHandle); - protected: friend class GLContextProviderEGL; EGLConfig mConfig; EGLSurface mSurface; - EGLSurface mCurSurface; EGLContext mContext; void *mPlatformContext; nsRefPtr<gfxASurface> mThebesSurface; bool mBound; bool mIsPBuffer; bool mIsDoubleBuffered; bool mCanBindToTexture; @@ -725,17 +723,16 @@ protected: NS_WARNING("Failed to create pbuffer surface"); return nullptr; } return surface; } }; - typedef enum { Image #ifdef MOZ_WIDGET_ANDROID , SurfaceTexture #endif } SharedHandleType; class SharedTextureHandleWrapper @@ -789,18 +786,17 @@ public: // Args are the active GL context, and a texture in that GL // context for which to create an EGLImage. After the EGLImage // is created, the texture is unused by EGLTextureWrapper. bool CreateEGLImage(GLContextEGL *ctx, GLuint texture) { MOZ_ASSERT(!mEGLImage && texture && sEGLLibrary.HasKHRImageBase()); static const EGLint eglAttributes[] = { LOCAL_EGL_NONE }; - EGLContext eglContext = (EGLContext)ctx->GetEGLContext(); - mEGLImage = sEGLLibrary.fCreateImage(EGL_DISPLAY(), eglContext, LOCAL_EGL_GL_TEXTURE_2D, + mEGLImage = sEGLLibrary.fCreateImage(EGL_DISPLAY(), ctx->Context(), LOCAL_EGL_GL_TEXTURE_2D, (EGLClientBuffer)texture, eglAttributes); if (!mEGLImage) { #ifdef DEBUG printf_stderr("Could not create EGL images: ERROR (0x%04x)\n", sEGLLibrary.fGetError()); #endif return false; } return true; @@ -873,24 +869,32 @@ GLContextEGL::UpdateSharedHandle(SharedT NS_ASSERTION(wrapper->Type() == SharedHandleType::Image, "Expected EGLImage shared handle"); NS_ASSERTION(mShareWithEGLImage, "EGLImage not supported or disabled in runtime"); EGLTextureWrapper* wrap = reinterpret_cast<EGLTextureWrapper*>(wrapper); // We need to copy the current GLContext drawing buffer to the texture // exported by the EGLImage. Need to save both the read FBO and the texture // binding, because we're going to munge them to do this. - ScopedBindTexture autoTex(this, mTemporaryEGLImageTexture); + GLuint prevRead = GetUserBoundReadFBO(); + GLint oldtex = -1; + BindUserReadFBO(0); + fGetIntegerv(LOCAL_GL_TEXTURE_BINDING_2D, &oldtex); + MOZ_ASSERT(oldtex != -1); + fBindTexture(LOCAL_GL_TEXTURE_2D, mTemporaryEGLImageTexture); fEGLImageTargetTexture2D(LOCAL_GL_TEXTURE_2D, wrap->GetEGLImage()); - // CopyTexSubImage2D, is ~2x slower than simple FBO render to texture with - // draw quads, but if we want that, we need to assure that our default - // framebuffer is texture-backed. - gfxIntSize size = OffscreenSize(); - BlitFramebufferToTexture(0, mTemporaryEGLImageTexture, size, size); + // CopyTexSubImage2D, is ~2x slower than simple FBO render to texture with draw quads, + // but render with draw quads require complex and hard to maintain context save/restore code + fCopyTexSubImage2D(LOCAL_GL_TEXTURE_2D, 0, 0, 0, + 0, 0, mOffscreenActualSize.width, + mOffscreenActualSize.height); + + fBindTexture(LOCAL_GL_TEXTURE_2D, oldtex); + BindUserReadFBO(prevRead); // Make sure our copy is finished, so that we can be ready to draw // in different thread GLContext. If we have KHR_fence_sync, then // we insert a sync object, otherwise we have to do a GuaranteeResolve. wrap->MakeSync(this); } SharedTextureHandle @@ -898,17 +902,20 @@ GLContextEGL::CreateSharedHandle(SharedT { if (shareType != SameProcess) return 0; if (!mShareWithEGLImage) return 0; MakeCurrent(); - mTemporaryEGLImageTexture = CreateTextureForOffscreen(GetGLFormats(), OffscreenSize()); + ContextFormat fmt = ActualFormat(); + + CreateTextureForOffscreen(ChooseGLFormats(fmt, GLContext::ForceRGBA), mOffscreenActualSize, + mTemporaryEGLImageTexture); EGLTextureWrapper* tex = new EGLTextureWrapper(); bool ok = tex->CreateEGLImage(this, mTemporaryEGLImageTexture); if (!ok) { NS_ERROR("EGLImage creation for EGLTextureWrapper failed"); ReleaseSharedHandle(shareType, (SharedTextureHandle)tex); return 0; @@ -918,17 +925,17 @@ GLContextEGL::CreateSharedHandle(SharedT return (SharedTextureHandle)tex; } SharedTextureHandle GLContextEGL::CreateSharedHandle(SharedTextureShareType shareType, void* buffer, SharedTextureBufferType bufferType) { - // Both EGLImage and SurfaceTexture only support same-process currently, but + // Both EGLImage and SurfaceTexture only support ThreadShared currently, but // it's possible to make SurfaceTexture work across processes. We should do that. if (shareType != SameProcess) return 0; switch (bufferType) { #ifdef MOZ_WIDGET_ANDROID case SharedTextureBufferType::SurfaceTexture: if (!IsExtensionSupported(GLContext::OES_EGL_image_external)) { @@ -1045,17 +1052,17 @@ bool GLContextEGL::AttachSharedHandle(Sh // FIXME: SurfaceTexture provides a transform matrix which is supposed to // be applied to the texture coordinates. We should return that here // so we can render correctly. Bug 775083 surfaceTextureWrapper->SurfaceTexture()->UpdateTexImage(); break; } #endif // MOZ_WIDGET_ANDROID - + case SharedHandleType::Image: { NS_ASSERTION(mShareWithEGLImage, "EGLImage not supported or disabled in runtime"); EGLTextureWrapper* wrap = (EGLTextureWrapper*)sharedHandle; wrap->WaitSync(); fEGLImageTargetTexture2D(LOCAL_GL_TEXTURE_2D, wrap->GetEGLImage()); break; } @@ -1063,20 +1070,104 @@ bool GLContextEGL::AttachSharedHandle(Sh default: NS_ERROR("Unknown shared handle type"); return false; } return true; } + +bool +GLContextEGL::BindTex2DOffscreen(GLContext *aOffscreen) +{ + if (aOffscreen->GetContextType() != ContextTypeEGL) { + NS_WARNING("non-EGL context"); + return false; + } + + GLContextEGL *offs = static_cast<GLContextEGL*>(aOffscreen); + + if (offs->mCanBindToTexture) { + bool ok = sEGLLibrary.fBindTexImage(EGL_DISPLAY(), + offs->mSurface, + LOCAL_EGL_BACK_BUFFER); + return ok; + } + + if (offs->mOffscreenTexture) { + if (offs->GetSharedContext() != GLContextProviderEGL::GetGlobalContext()) + { + NS_WARNING("offscreen FBO context can only be bound with context sharing!"); + return false; + } + + fBindTexture(LOCAL_GL_TEXTURE_2D, offs->mOffscreenTexture); + return true; + } + + NS_WARNING("don't know how to bind this!"); + + return false; +} + +void +GLContextEGL::UnbindTex2DOffscreen(GLContext *aOffscreen) +{ + NS_ASSERTION(aOffscreen->GetContextType() == ContextTypeEGL, "wrong type"); + + GLContextEGL *offs = static_cast<GLContextEGL*>(aOffscreen); + + if (offs->mCanBindToTexture) { + sEGLLibrary.fReleaseTexImage(EGL_DISPLAY(), + offs->mSurface, + LOCAL_EGL_BACK_BUFFER); + } +} + bool GLContextEGL::ResizeOffscreen(const gfxIntSize& aNewSize) { - return ResizeScreenBuffer(aNewSize); + if (!IsOffscreenSizeAllowed(aNewSize)) + return false; + + if (mIsPBuffer) { + gfxIntSize pbsize(aNewSize); + + EGLSurface surface = + CreatePBufferSurfaceTryingPowerOfTwo(mConfig, + mCanBindToTexture + ? (mCreationFormat.minAlpha + ? LOCAL_EGL_TEXTURE_RGBA + : LOCAL_EGL_TEXTURE_RGB) + : LOCAL_EGL_NONE, + pbsize); + if (!surface) { + NS_WARNING("Failed to resize pbuffer"); + return false; + } + + if (!ResizeOffscreenFBOs(pbsize, false)) + return false; + + SetOffscreenSize(aNewSize, pbsize); + + if (mSurface && !mPlatformContext) { + sEGLLibrary.fDestroySurface(EGL_DISPLAY(), mSurface); + } + + mSurface = surface; + + MakeCurrent(true); + ClearSafely(); + + return true; + } + + return ResizeOffscreenFBOs(aNewSize, true); } static GLContextEGL * GetGlobalContextEGL() { return static_cast<GLContextEGL*>(GLContextProviderEGL::GetGlobalContext()); } @@ -1738,17 +1829,17 @@ public: GraphicBuffer::USAGE_SW_READ_OFTEN | GraphicBuffer::USAGE_SW_WRITE_OFTEN; mGraphicBuffer = new GraphicBuffer(aSize.width, aSize.height, format, usage); if (mGraphicBuffer->initCheck() == OK) { const int eglImageAttributes[] = { LOCAL_EGL_IMAGE_PRESERVED, LOCAL_EGL_TRUE, LOCAL_EGL_NONE, LOCAL_EGL_NONE }; mEGLImage = sEGLLibrary.fCreateImage(EGL_DISPLAY(), EGL_NO_CONTEXT, - LOCAL_EGL_NATIVE_BUFFER_ANDROID, + EGL_NATIVE_BUFFER_ANDROID, (EGLClientBuffer) mGraphicBuffer->getNativeBuffer(), eglImageAttributes); if (!mEGLImage) { mGraphicBuffer = nullptr; LOG("Could not create EGL images: ERROR (0x%04x)", sEGLLibrary.fGetError()); return false; } @@ -1812,17 +1903,17 @@ public: mGraphicBuffer = aGraphicBuffer; const int eglImageAttributes[] = { LOCAL_EGL_IMAGE_PRESERVED, LOCAL_EGL_TRUE, LOCAL_EGL_NONE, LOCAL_EGL_NONE }; mEGLImage = sEGLLibrary.fCreateImage(EGL_DISPLAY(), EGL_NO_CONTEXT, - LOCAL_EGL_NATIVE_BUFFER_ANDROID, + EGL_NATIVE_BUFFER_ANDROID, mGraphicBuffer->getNativeBuffer(), eglImageAttributes); if (!mEGLImage) { LOG("Could not create EGL images: ERROR (0x%04x)", sEGLLibrary.fGetError()); } } }; @@ -1881,41 +1972,50 @@ GLContextEGL::TileGenFunc(const nsIntSiz fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER, texfilter); fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER, texfilter); fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE); fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE); return teximage.forget(); } +inline static ContextFormat +DepthToGLFormat(int aDepth) +{ + switch (aDepth) { + case 32: + return ContextFormat::BasicRGBA32; + case 24: + return ContextFormat::BasicRGB24; + case 16: + return ContextFormat::BasicRGB16_565; + default: + break; + } + return ContextFormat::BasicRGBA32; +} + static nsRefPtr<GLContext> gGlobalContext; -static const EGLint kEGLConfigAttribsOffscreenPBuffer[] = { - LOCAL_EGL_SURFACE_TYPE, LOCAL_EGL_PBUFFER_BIT, - LOCAL_EGL_RENDERABLE_TYPE, LOCAL_EGL_OPENGL_ES2_BIT, - LOCAL_EGL_NONE -}; - static const EGLint kEGLConfigAttribsRGB16[] = { LOCAL_EGL_SURFACE_TYPE, LOCAL_EGL_WINDOW_BIT, LOCAL_EGL_RENDERABLE_TYPE, LOCAL_EGL_OPENGL_ES2_BIT, LOCAL_EGL_RED_SIZE, 5, LOCAL_EGL_GREEN_SIZE, 6, LOCAL_EGL_BLUE_SIZE, 5, LOCAL_EGL_ALPHA_SIZE, 0, LOCAL_EGL_NONE }; static const EGLint kEGLConfigAttribsRGB24[] = { LOCAL_EGL_SURFACE_TYPE, LOCAL_EGL_WINDOW_BIT, LOCAL_EGL_RENDERABLE_TYPE, LOCAL_EGL_OPENGL_ES2_BIT, LOCAL_EGL_RED_SIZE, 8, LOCAL_EGL_GREEN_SIZE, 8, LOCAL_EGL_BLUE_SIZE, 8, - LOCAL_EGL_ALPHA_SIZE, 0, LOCAL_EGL_NONE }; static const EGLint kEGLConfigAttribsRGBA32[] = { LOCAL_EGL_SURFACE_TYPE, LOCAL_EGL_WINDOW_BIT, LOCAL_EGL_RENDERABLE_TYPE, LOCAL_EGL_OPENGL_ES2_BIT, LOCAL_EGL_RED_SIZE, 8, LOCAL_EGL_GREEN_SIZE, 8, @@ -2023,144 +2123,285 @@ CreateSurfaceForWindow(nsIWidget *aWidge return surface; } #endif already_AddRefed<GLContext> GLContextProviderEGL::CreateForWindow(nsIWidget *aWidget) { + EGLConfig config; + if (!sEGLLibrary.EnsureInitialized()) { return nullptr; } bool doubleBuffered = true; - EGLContext eglContext = sEGLLibrary.fGetCurrentContext(); - if (aWidget->HasGLContext() && eglContext) { - //int colorDepth = gfxPlatform::GetPlatform()->GetScreenDepth(); - void* platformContext = eglContext; + void* currentContext = sEGLLibrary.fGetCurrentContext(); + if (aWidget->HasGLContext() && currentContext) { + int32_t depth = gfxPlatform::GetPlatform()->GetScreenDepth(); + void* platformContext = currentContext; #ifdef MOZ_WIDGET_QT QGLContext* context = const_cast<QGLContext*>(QGLContext::currentContext()); if (context && context->device()) { depth = context->device()->depth(); } doubleBuffered = context->format().doubleBuffer(); platformContext = context; #endif - - SurfaceCaps caps = SurfaceCaps::Any(); - EGLConfig config = EGL_NO_CONFIG; - EGLSurface surface = sEGLLibrary.fGetCurrentSurface(LOCAL_EGL_DRAW); nsRefPtr<GLContextEGL> glContext = - new GLContextEGL(caps, - gGlobalContext, false, - config, surface, eglContext); + new GLContextEGL(ContextFormat(DepthToGLFormat(depth)), + gGlobalContext, + NULL, + sEGLLibrary.fGetCurrentSurface(LOCAL_EGL_DRAW), // just use same surface for read and draw + currentContext, + false); if (!glContext->Init()) return nullptr; glContext->MakeCurrent(); + sEGLLibrary.LoadConfigSensitiveSymbols(); + glContext->SetIsDoubleBuffered(doubleBuffered); + glContext->SetPlatformContext(platformContext); - if (!gGlobalContext) { gGlobalContext = glContext; } return glContext.forget(); } - EGLConfig config; if (!CreateConfig(&config)) { printf_stderr("Failed to create EGL config!\n"); return nullptr; } #ifdef MOZ_ANDROID_OMTC mozilla::AndroidBridge::Bridge()->RegisterCompositor(); EGLSurface surface = mozilla::AndroidBridge::Bridge()->ProvideEGLSurface(true); #else EGLSurface surface = CreateSurfaceForWindow(aWidget, config); #endif if (!surface) { - printf_stderr("Failed to create EGLSurface!\n"); + return nullptr; + } + + if (!sEGLLibrary.fBindAPI(LOCAL_EGL_OPENGL_ES_API)) { + sEGLLibrary.fDestroySurface(EGL_DISPLAY(), surface); return nullptr; } - GLContextEGL* shareContext = GetGlobalContextEGL(); - SurfaceCaps caps = SurfaceCaps::Any(); + GLContextEGL *shareContext = GetGlobalContextEGL(); + nsRefPtr<GLContextEGL> glContext = - GLContextEGL::CreateGLContext(caps, - shareContext, false, - config, surface); + GLContextEGL::CreateGLContext(ContextFormat(ContextFormat::BasicRGB24), + surface, + config, + shareContext, + false); if (!glContext) { - sEGLLibrary.fDestroySurface(EGL_DISPLAY(), surface); return nullptr; } glContext->MakeCurrent(); + sEGLLibrary.LoadConfigSensitiveSymbols(); glContext->SetIsDoubleBuffered(doubleBuffered); return glContext.forget(); } +static void +FillPBufferAttribs_Minimal(nsTArray<EGLint>& aAttrs) +{ + aAttrs.Clear(); + +#define A1(_x) do { aAttrs.AppendElement(_x); } while (0) +#define A2(_x,_y) do { A1(_x); A1(_y); } while (0) + + A2(LOCAL_EGL_RENDERABLE_TYPE, LOCAL_EGL_OPENGL_ES2_BIT); + + A2(LOCAL_EGL_SURFACE_TYPE, LOCAL_EGL_PBUFFER_BIT); + + A1(LOCAL_EGL_NONE); +#undef A1 +#undef A2 +} + +static void +FillPBufferAttribs(nsTArray<EGLint>& aAttrs, + const ContextFormat& aFormat, + bool aCanBindToTexture, + int aColorBitsOverride, + int aDepthBitsOverride) +{ + aAttrs.Clear(); + +#define A1(_x) do { aAttrs.AppendElement(_x); } while (0) +#define A2(_x,_y) do { A1(_x); A1(_y); } while (0) + + A2(LOCAL_EGL_RENDERABLE_TYPE, LOCAL_EGL_OPENGL_ES2_BIT); + + A2(LOCAL_EGL_SURFACE_TYPE, LOCAL_EGL_PBUFFER_BIT); + + if (aColorBitsOverride == -1) { + A2(LOCAL_EGL_RED_SIZE, aFormat.red); + A2(LOCAL_EGL_GREEN_SIZE, aFormat.green); + A2(LOCAL_EGL_BLUE_SIZE, aFormat.blue); + } else { + A2(LOCAL_EGL_RED_SIZE, aColorBitsOverride); + A2(LOCAL_EGL_GREEN_SIZE, aColorBitsOverride); + A2(LOCAL_EGL_BLUE_SIZE, aColorBitsOverride); + } + + A2(LOCAL_EGL_ALPHA_SIZE, aFormat.alpha); + + if (aDepthBitsOverride == -1) { + A2(LOCAL_EGL_DEPTH_SIZE, aFormat.minDepth); + } else { + A2(LOCAL_EGL_DEPTH_SIZE, aDepthBitsOverride); + } + + A2(LOCAL_EGL_STENCIL_SIZE, aFormat.minStencil); + + if (aCanBindToTexture) { + A2(aFormat.minAlpha ? LOCAL_EGL_BIND_TO_TEXTURE_RGBA : LOCAL_EGL_BIND_TO_TEXTURE_RGB, + LOCAL_EGL_TRUE); + } + + A1(LOCAL_EGL_NONE); +#undef A1 +#undef A2 +} + already_AddRefed<GLContextEGL> -GLContextEGL::CreateEGLPBufferOffscreenContext(const gfxIntSize& size) +GLContextEGL::CreateEGLPBufferOffscreenContext(const gfxIntSize& aSize, + const ContextFormat& aFormat, + bool bufferUnused) { EGLConfig config; EGLSurface surface; - - const EGLint numConfigs = 1; // We only need one. - EGLConfig configs[numConfigs]; - EGLint foundConfigs = 0; + EGLContext context; + + bool configCanBindToTexture = true; + + EGLConfig configs[64]; + int numConfigs = sizeof(configs)/sizeof(EGLConfig); + int foundConfigs = 0; + + // if we're running under ANGLE, we can't set BIND_TO_TEXTURE -- + // it's not supported, and we have dx interop pbuffers anyway + if (sEGLLibrary.IsANGLE() || bufferUnused) + configCanBindToTexture = false; + + nsTArray<EGLint> attribs(32); + int attribAttempt = 0; + + int tryDepthSize = (aFormat.depth > 0) ? 24 : 0; + +TRY_ATTRIBS_AGAIN: + if (bufferUnused) { + FillPBufferAttribs_Minimal(attribs); + } else { + switch (attribAttempt) { + case 0: + FillPBufferAttribs(attribs, aFormat, configCanBindToTexture, 8, tryDepthSize); + break; + case 1: + FillPBufferAttribs(attribs, aFormat, configCanBindToTexture, -1, tryDepthSize); + break; + case 2: + FillPBufferAttribs(attribs, aFormat, configCanBindToTexture, -1, -1); + break; + } + } + if (!sEGLLibrary.fChooseConfig(EGL_DISPLAY(), - kEGLConfigAttribsOffscreenPBuffer, + &attribs[0], configs, numConfigs, &foundConfigs) || foundConfigs == 0) { - NS_WARNING("No EGL Config for minimal PBuffer!"); + if (bufferUnused) { + NS_WARNING("No EGL Config for minimal PBuffer!"); + return nullptr; + } + + if (attribAttempt < 3) { + attribAttempt++; + goto TRY_ATTRIBS_AGAIN; + } + + if (configCanBindToTexture) { + NS_WARNING("No pbuffer EGL configs that can bind to texture, trying without"); + configCanBindToTexture = false; + attribAttempt = 0; + goto TRY_ATTRIBS_AGAIN; + } + + // no configs? no pbuffers! + NS_WARNING("Failed to select acceptable config for PBuffer creation!"); return nullptr; } - // We absolutely don't care, so just pick the first one. + // XXX do some smarter matching here, perhaps instead of the more complex + // minimum overrides above config = configs[0]; - if (GLContext::DebugMode()) - sEGLLibrary.DumpEGLConfig(config); - - gfxIntSize pbSize(size); +#ifdef DEBUG + sEGLLibrary.DumpEGLConfig(config); +#endif + + gfxIntSize pbsize(aSize); surface = GLContextEGL::CreatePBufferSurfaceTryingPowerOfTwo(config, - LOCAL_EGL_NONE, - pbSize); + configCanBindToTexture + ? (aFormat.minAlpha + ? LOCAL_EGL_TEXTURE_RGBA + : LOCAL_EGL_TEXTURE_RGB) + : LOCAL_EGL_NONE, + pbsize); if (!surface) { NS_WARNING("Failed to create PBuffer for context!"); return nullptr; } + sEGLLibrary.fBindAPI(LOCAL_EGL_OPENGL_ES_API); + GLContextEGL* shareContext = GetGlobalContextEGL(); - SurfaceCaps dummyCaps = SurfaceCaps::Any(); - nsRefPtr<GLContextEGL> glContext = - GLContextEGL::CreateGLContext(dummyCaps, - shareContext, true, - config, surface); - if (!glContext) { + context = sEGLLibrary.fCreateContext(EGL_DISPLAY(), + config, + shareContext ? shareContext->mContext + : EGL_NO_CONTEXT, + sEGLLibrary.HasRobustness() ? gContextAttribsRobustness + : gContextAttribs); + if (!context) { NS_WARNING("Failed to create GLContext from PBuffer"); sEGLLibrary.fDestroySurface(EGL_DISPLAY(), surface); return nullptr; } + nsRefPtr<GLContextEGL> glContext = new GLContextEGL(aFormat, shareContext, + config, surface, context, + true); + if (!glContext->Init()) { NS_WARNING("Failed to initialize GLContext!"); - // GLContextEGL::dtor will destroy |surface| for us. return nullptr; } + glContext->mCanBindToTexture = configCanBindToTexture; + + if (!bufferUnused) { // We *are* using the buffer + glContext->SetOffscreenSize(aSize, pbsize); + glContext->mIsPBuffer = true; + } + return glContext.forget(); } #ifdef MOZ_X11 EGLSurface CreateEGLSurfaceForXSurface(gfxASurface* aSurface, EGLConfig* aConfig) { gfxXlibSurface* xsurface = static_cast<gfxXlibSurface*>(aSurface); @@ -2244,27 +2485,29 @@ CreateEGLSurfaceForXSurface(gfxASurface* if (aConfig) *aConfig = configs[i]; return surface; } #endif already_AddRefed<GLContextEGL> -GLContextEGL::CreateEGLPixmapOffscreenContext(const gfxIntSize& size) +GLContextEGL::CreateEGLPixmapOffscreenContext(const gfxIntSize& aSize, + const ContextFormat& aFormat, + bool aShare) { gfxASurface *thebesSurface = nullptr; EGLNativePixmapType pixmap = 0; #ifdef MOZ_X11 nsRefPtr<gfxXlibSurface> xsurface = gfxXlibSurface::Create(DefaultScreenOfDisplay(DefaultXDisplay()), gfxXlibSurface::FindRenderFormat(DefaultXDisplay(), gfxASurface::ImageFormatRGB24), - size); + aSize); // XSync required after gfxXlibSurface::Create, otherwise EGL will fail with BadDrawable error XSync(DefaultXDisplay(), False); if (xsurface->CairoStatus() != 0) return nullptr; thebesSurface = xsurface; pixmap = (EGLNativePixmapType)xsurface->XDrawable(); @@ -2278,72 +2521,79 @@ GLContextEGL::CreateEGLPixmapOffscreenCo EGLConfig config = 0; #ifdef MOZ_X11 surface = CreateEGLSurfaceForXSurface(thebesSurface, &config); #endif if (!config) { return nullptr; } - MOZ_ASSERT(surface); - - GLContextEGL* shareContext = GetGlobalContextEGL(); - SurfaceCaps dummyCaps = SurfaceCaps::Any(); + + GLContextEGL *shareContext = aShare ? GetGlobalContextEGL() : nullptr; + nsRefPtr<GLContextEGL> glContext = - GLContextEGL::CreateGLContext(dummyCaps, - shareContext, true, - surface, config); - if (!glContext) { - NS_WARNING("Failed to create GLContext from XSurface"); - sEGLLibrary.fDestroySurface(EGL_DISPLAY(), surface); - return nullptr; - } - - if (!glContext->Init()) { - NS_WARNING("Failed to initialize GLContext!"); - // GLContextEGL::dtor will destroy |surface| for us. - return nullptr; - } + GLContextEGL::CreateGLContext(aFormat, + surface, + config, + shareContext, + true); glContext->HoldSurface(thebesSurface); return glContext.forget(); } // 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 // often without the ability to texture from them directly. already_AddRefed<GLContext> -GLContextProviderEGL::CreateOffscreen(const gfxIntSize& size, - const SurfaceCaps& caps, - ContextFlags flags) +GLContextProviderEGL::CreateOffscreen(const gfxIntSize& aSize, + const ContextFormat& aFormat, + const ContextFlags aFlags) { if (!sEGLLibrary.EnsureInitialized()) { return nullptr; } - gfxIntSize dummySize = gfxIntSize(16, 16); - nsRefPtr<GLContextEGL> glContext; -#if defined(MOZ_X11) - glContext = GLContextEGL::CreateEGLPixmapOffscreenContext(dummySize); -#else - glContext = GLContextEGL::CreateEGLPBufferOffscreenContext(dummySize); -#endif +#if !defined(MOZ_X11) + bool usePBuffers = false; // Generally, prefer FBOs to PBuffers + + if (sEGLLibrary.IsANGLE()) + usePBuffers = true; // For d3d share handle, we need an EGL surface + + gfxIntSize pbufferSize = usePBuffers ? aSize : gfxIntSize(16, 16); + nsRefPtr<GLContextEGL> glContext = + GLContextEGL::CreateEGLPBufferOffscreenContext(pbufferSize, aFormat, !usePBuffers); if (!glContext) return nullptr; - if (flags & GLContext::ContextFlagsGlobal) - return glContext.forget(); - - if (!glContext->InitOffscreen(size, caps)) + gfxIntSize fboSize = usePBuffers ? glContext->OffscreenActualSize() : aSize; + if (!(aFlags & GLContext::ContextFlagsGlobal) && !glContext->ResizeOffscreenFBOs(fboSize, !usePBuffers)) return nullptr; return glContext.forget(); +#elif defined(MOZ_X11) + nsRefPtr<GLContextEGL> glContext = + GLContextEGL::CreateEGLPixmapOffscreenContext(gfxIntSize(16, 16), aFormat, true); + + if (!glContext) { + return nullptr; + } + + if (!(aFlags & GLContext::ContextFlagsGlobal) && !glContext->ResizeOffscreenFBOs(aSize, true)) { + // we weren't able to create the initial + // offscreen FBO, so this is dead + return nullptr; + } + return glContext.forget(); +#else + return nullptr; +#endif } // Don't want a global context on Android as 1) share groups across 2 threads fail on many Tegra drivers (bug 759225) // and 2) some mobile devices have a very strict limit on global number of GL contexts (bug 754257) // and 3) each EGL context eats 750k on B2G (bug 813783) GLContext * GLContextProviderEGL::GetGlobalContext(const ContextFlags) {
--- a/gfx/gl/GLContextProviderGLX.cpp +++ b/gfx/gl/GLContextProviderGLX.cpp @@ -31,18 +31,16 @@ #include "gfxUtils.h" #include "gfxCrashReporterUtils.h" #ifdef MOZ_WIDGET_GTK #include "gfxPlatformGtk.h" #endif -using namespace mozilla::gfx; - namespace mozilla { namespace gl { GLXLibrary sGLXLibrary[GLXLibrary::LIBS_MAX]; GLXLibrary& sDefGLXLib = sGLXLibrary[GLXLibrary::OPENGL_LIB]; typedef GLXLibrary::LibraryType LibType; @@ -67,55 +65,41 @@ GLXLibrary::GLXVersionCheck(int aMajor, static inline bool HasExtension(const char* aExtensions, const char* aRequiredExtension) { return GLContext::ListHasExtension( reinterpret_cast<const GLubyte*>(aExtensions), aRequiredExtension); } bool -GLXLibrary::EnsureInitialized(LibType libType) +GLXLibrary::EnsureInitialized(bool aUseMesaLLVMPipe) { if (mInitialized) { return true; } // Don't repeatedly try to initialize. if (mTriedInitializing) { return false; } mTriedInitializing = true; - // Force enabling s3 texture compression. (Bug 774134) + // Force enabling s3 texture compression (http://dri.freedesktop.org/wiki/S3TC) PR_SetEnv("force_s3tc_enable=true"); if (!mOGLLibrary) { - const char* libGLfilename = nullptr; - bool forceFeatureReport = false; - switch (libType) { - case MESA_LLVMPIPE_LIB: - libGLfilename = "mesallvmpipe.so"; - forceFeatureReport = true; - break; - case OPENGL_LIB: - // see e.g. bug 608526: it is intrinsically interesting to know whether we have dynamically linked to libGL.so.1 - // because at least the NVIDIA implementation requires an executable stack, which causes mprotect calls, - // which trigger glibc bug http://sourceware.org/bugzilla/show_bug.cgi?id=12225 + // see e.g. bug 608526: it is intrinsically interesting to know whether we have dynamically linked to libGL.so.1 + // because at least the NVIDIA implementation requires an executable stack, which causes mprotect calls, + // which trigger glibc bug http://sourceware.org/bugzilla/show_bug.cgi?id=12225 #ifdef __OpenBSD__ - libGLfilename = "libGL.so"; + const char *libGLfilename = aUseMesaLLVMPipe? "mesallvmpipe.so" : "libGL.so"; #else - libGLfilename = "libGL.so.1"; + const char *libGLfilename = aUseMesaLLVMPipe? "mesallvmpipe.so" : "libGL.so.1"; #endif - break; - default: - MOZ_NOT_REACHED("Invalid GLX library type."); - return false; - } - - ScopedGfxFeatureReporter reporter(libGLfilename, forceFeatureReport); + ScopedGfxFeatureReporter reporter(libGLfilename, aUseMesaLLVMPipe); mOGLLibrary = PR_LoadLibrary(libGLfilename); if (!mOGLLibrary) { NS_WARNING("Couldn't load OpenGL shared library."); return false; } reporter.SetSuccessful(); } @@ -261,25 +245,26 @@ GLXLibrary::EnsureInitialized(LibType li GLLibraryLoader::LoadSymbols(mOGLLibrary, symbols_robustness)) { mHasRobustness = true; } mIsATI = serverVendor && DoesStringMatch(serverVendor, "ATI"); mClientIsMesa = clientVendor && DoesStringMatch(clientVendor, "Mesa"); mInitialized = true; - mLibType = libType; + if(aUseMesaLLVMPipe) + mLibType = GLXLibrary::MESA_LLVMPIPE_LIB; return true; } bool GLXLibrary::SupportsTextureFromPixmap(gfxASurface* aSurface) { - if (!EnsureInitialized(mLibType)) { + if (!EnsureInitialized(mLibType == MESA_LLVMPIPE_LIB)) { return false; } if (aSurface->GetType() != gfxASurface::SurfaceTypeXlib || !mUseTextureFromPixmap) { return false; } return true; @@ -736,31 +721,28 @@ GLXLibrary::xCreateContextAttribs(Displa AFTER_GLX_CALL; return result; } class GLContextGLX : public GLContext { public: static already_AddRefed<GLContextGLX> - CreateGLContext(const SurfaceCaps& caps, - GLContextGLX* shareContext, - bool isOffscreen, - Display* display, + CreateGLContext(const ContextFormat& format, + Display *display, GLXDrawable drawable, GLXFBConfig cfg, + GLContextGLX *shareContext, bool deleteDrawable, - LibType libType = GLXLibrary::OPENGL_LIB, - gfxXlibSurface* pixmap = nullptr) + LibType lib = GLXLibrary::OPENGL_LIB, + gfxXlibSurface *pixmap = nullptr) { - GLXLibrary& glx = sGLXLibrary[libType]; - - int db = 0; - int err = glx.xGetFBConfigAttrib(display, cfg, - GLX_DOUBLEBUFFER, &db); + int db = 0, err; + err = sGLXLibrary[lib].xGetFBConfigAttrib(display, cfg, + GLX_DOUBLEBUFFER, &db); if (GLX_BAD_ATTRIBUTE != err) { #ifdef DEBUG if (DebugMode()) { printf("[GLX] FBConfig is %sdouble-buffered\n", db ? "" : "not "); } #endif } @@ -769,50 +751,46 @@ public: bool error; ScopedXErrorHandler xErrorHandler; TRY_AGAIN_NO_SHARING: error = false; - GLXContext glxContext = shareContext ? shareContext->mContext : NULL; - if (glx.HasRobustness()) { + if (sGLXLibrary[lib].HasRobustness()) { int attrib_list[] = { LOCAL_GL_CONTEXT_FLAGS_ARB, LOCAL_GL_CONTEXT_ROBUST_ACCESS_BIT_ARB, LOCAL_GL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, LOCAL_GL_LOSE_CONTEXT_ON_RESET_ARB, 0, }; - context = glx.xCreateContextAttribs( - display, - cfg, - glxContext, - True, - attrib_list); + context = sGLXLibrary[lib].xCreateContextAttribs(display, + cfg, + shareContext ? shareContext->mContext : NULL, + True, + attrib_list); } else { - context = glx.xCreateNewContext( - display, - cfg, - GLX_RGBA_TYPE, - glxContext, - True); + context = sGLXLibrary[lib].xCreateNewContext(display, + cfg, + GLX_RGBA_TYPE, + shareContext ? shareContext->mContext : NULL, + True); } if (context) { - glContext = new GLContextGLX(caps, - shareContext, - isOffscreen, - display, - drawable, - context, - deleteDrawable, - db, - pixmap, - libType); + glContext = new GLContextGLX(format, + shareContext, + display, + drawable, + context, + deleteDrawable, + db, + pixmap, + lib); if (!glContext->Init()) error = true; } else { error = true; } error |= xErrorHandler.SyncAndGetError(display); @@ -833,24 +811,24 @@ TRY_AGAIN_NO_SHARING: ~GLContextGLX() { MarkDestroyed(); // see bug 659842 comment 76 #ifdef DEBUG bool success = #endif - mGLX->xMakeCurrent(mDisplay, None, nullptr); + sGLXLib.xMakeCurrent(mDisplay, None, nullptr); NS_ABORT_IF_FALSE(success, "glXMakeCurrent failed to release GL context before we call glXDestroyContext!"); - mGLX->xDestroyContext(mDisplay, mContext); + sGLXLib.xDestroyContext(mDisplay, mContext); if (mDeleteDrawable) { - mGLX->xDestroyPixmap(mDisplay, mDrawable); + sGLXLib.xDestroyPixmap(mDisplay, mDrawable); } } GLContextType GetContextType() { return ContextTypeGLX; } bool Init() @@ -874,26 +852,26 @@ TRY_AGAIN_NO_SHARING: bool succeeded = true; // With the ATI FGLRX driver, glxMakeCurrent is very slow even when the context doesn't change. // (This is not the case with other drivers such as NVIDIA). // So avoid calling it more than necessary. Since GLX documentation says that: // "glXGetCurrentContext returns client-side information. // It does not make a round trip to the server." // I assume that it's not worth using our own TLS slot here. - if (aForce || mGLX->xGetCurrentContext() != mContext) { - succeeded = mGLX->xMakeCurrent(mDisplay, mDrawable, mContext); + if (aForce || sGLXLib.xGetCurrentContext() != mContext) { + succeeded = sGLXLib.xMakeCurrent(mDisplay, mDrawable, mContext); NS_ASSERTION(succeeded, "Failed to make GL context current!"); } return succeeded; } virtual bool IsCurrent() { - return mGLX->xGetCurrentContext() == mContext; + return sGLXLib.xGetCurrentContext() == mContext; } bool SetupLookupFunction() { mLookupFunc = (PlatformLookupFunction)&GLXLibrary::xGetProcAddress; return true; } @@ -913,75 +891,72 @@ TRY_AGAIN_NO_SHARING: bool IsDoubleBuffered() { return mDoubleBuffered; } bool SupportsRobustness() { - return mGLX->HasRobustness(); + return sGLXLib.HasRobustness(); } bool SwapBuffers() { if (!mDoubleBuffered) return false; - mGLX->xSwapBuffers(mDisplay, mDrawable); - mGLX->xWaitGL(); + sGLXLib.xSwapBuffers(mDisplay, mDrawable); + sGLXLib.xWaitGL(); return true; } bool TextureImageSupportsGetBackingSurface() { - return mGLX->UseTextureFromPixmap(); + return sGLXLib.UseTextureFromPixmap(); } virtual already_AddRefed<TextureImage> CreateTextureImage(const nsIntSize& aSize, TextureImage::ContentType aContentType, GLenum aWrapMode, TextureImage::Flags aFlags = TextureImage::NoFlags); private: friend class GLContextProviderGLX; - GLContextGLX(const SurfaceCaps& caps, - GLContext* shareContext, - bool isOffscreen, + GLContextGLX(const ContextFormat& aFormat, + GLContext *aShareContext, Display *aDisplay, GLXDrawable aDrawable, GLXContext aContext, bool aDeleteDrawable, bool aDoubleBuffered, gfxXlibSurface *aPixmap, - LibType libType) - : GLContext(caps, shareContext, isOffscreen),//aDeleteDrawable ? true : false, aShareContext, ), + LibType aLibType) + : GLContext(aFormat, aDeleteDrawable ? true : false, aShareContext), mContext(aContext), mDisplay(aDisplay), mDrawable(aDrawable), mDeleteDrawable(aDeleteDrawable), mDoubleBuffered(aDoubleBuffered), - mLibType(libType), - mGLX(&sGLXLibrary[libType]), - mPixmap(aPixmap) + mLibType(aLibType), + mPixmap(aPixmap), + sGLXLib(sGLXLibrary[aLibType]) { - MOZ_ASSERT(mGLX); } GLXContext mContext; Display *mDisplay; GLXDrawable mDrawable; bool mDeleteDrawable; bool mDoubleBuffered; - LibType mLibType; - GLXLibrary* mGLX; nsRefPtr<gfxXlibSurface> mPixmap; + GLXLibrary& sGLXLib; }; class TextureImageGLX : public TextureImage { friend already_AddRefed<TextureImage> GLContextGLX::CreateTextureImage(const nsIntSize&, ContentType, GLenum, @@ -1110,17 +1085,17 @@ GLContextGLX::CreateTextureImage(const n if (aContentType == gfxASurface::CONTENT_COLOR_ALPHA) { nsRefPtr<gfxContext> ctx = new gfxContext(surface); ctx->SetOperator(gfxContext::OPERATOR_CLEAR); ctx->Paint(); } MakeCurrent(); - GLXPixmap pixmap = mGLX->CreatePixmap(surface); + GLXPixmap pixmap = sGLXLib.CreatePixmap(surface); NS_ASSERTION(pixmap, "Failed to create pixmap!"); GLuint texture; fGenTextures(1, &texture); fActiveTexture(LOCAL_GL_TEXTURE0); fBindTexture(LOCAL_GL_TEXTURE_2D, texture); @@ -1161,18 +1136,17 @@ AreCompatibleVisuals(Visual *one, Visual } return true; } already_AddRefed<GLContext> GLContextProviderGLX::CreateForWindow(nsIWidget *aWidget) { - const LibType libType = GLXLibrary::OPENGL_LIB; - if (!sDefGLXLib.EnsureInitialized(libType)) { + if (!sDefGLXLib.EnsureInitialized(false)) { return nullptr; } // Currently, we take whatever Visual the window already has, and // try to create an fbconfig for that visual. This isn't // necessarily what we want in the long run; an fbconfig may not // be available for the existing visual, or if it is, the GL // performance might be suboptimal. But using the existing visual @@ -1246,71 +1220,77 @@ GLContextProviderGLX::CreateForWindow(ns if (matchIndex == -1) { NS_WARNING("[GLX] Couldn't find a FBConfig matching widget visual"); return nullptr; } GLContextGLX *shareContext = GetGlobalContextGLX(); - SurfaceCaps caps = SurfaceCaps::Any(); - nsRefPtr<GLContextGLX> glContext = GLContextGLX::CreateGLContext(caps, - shareContext, - false, + nsRefPtr<GLContextGLX> glContext = GLContextGLX::CreateGLContext(ContextFormat(ContextFormat::BasicRGB24), display, window, cfgs[matchIndex], + shareContext, false, - libType); + GLXLibrary::OPENGL_LIB); return glContext.forget(); } static already_AddRefed<GLContextGLX> -CreateOffscreenPixmapContext(const gfxIntSize& size, LibType libToUse) +CreateOffscreenPixmapContext(const gfxIntSize& aSize, + const ContextFormat& aFormat, + bool aShare, LibType aLibToUse) { - GLXLibrary& glx = sGLXLibrary[libToUse]; - if (!glx.EnsureInitialized(libToUse)) { + GLXLibrary& sGLXLib = sGLXLibrary[aLibToUse]; + if (!sGLXLib.EnsureInitialized(aLibToUse == GLXLibrary::MESA_LLVMPIPE_LIB)) { return nullptr; } Display *display = DefaultXDisplay(); int xscreen = DefaultScreen(display); int attribs[] = { + GLX_DOUBLEBUFFER, False, GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT, GLX_X_RENDERABLE, True, + GLX_RED_SIZE, 1, + GLX_GREEN_SIZE, 1, + GLX_BLUE_SIZE, 1, + GLX_ALPHA_SIZE, 0, + GLX_DEPTH_SIZE, 0, 0 }; int numConfigs = 0; ScopedXFree<GLXFBConfig> cfgs; - cfgs = glx.xChooseFBConfig(display, - xscreen, - attribs, - &numConfigs); + cfgs = sGLXLib.xChooseFBConfig(display, + xscreen, + attribs, + &numConfigs); if (!cfgs) { return nullptr; } - MOZ_ASSERT(numConfigs > 0, - "glXChooseFBConfig() failed to match our requested format and violated its spec!"); + NS_ASSERTION(numConfigs > 0, + "glXChooseFBConfig() failed to match our requested format and violated its spec (!)"); int visid = None; int chosenIndex = 0; for (int i = 0; i < numConfigs; ++i) { int dtype; - if (glx.xGetFBConfigAttrib(display, cfgs[i], GLX_DRAWABLE_TYPE, &dtype) != Success + if (sGLXLib.xGetFBConfigAttrib(display, cfgs[i], GLX_DRAWABLE_TYPE, &dtype) != Success || !(dtype & GLX_PIXMAP_BIT)) { continue; } - if (glx.xGetFBConfigAttrib(display, cfgs[i], GLX_VISUAL_ID, &visid) != Success + if (sGLXLib.xGetFBConfigAttrib(display, cfgs[i], GLX_VISUAL_ID, &visid) != Success || visid == 0) { continue; } chosenIndex = i; break; } @@ -1322,110 +1302,112 @@ CreateOffscreenPixmapContext(const gfxIn Visual *visual; int depth; FindVisualAndDepth(display, visid, &visual, &depth); ScopedXErrorHandler xErrorHandler; GLXPixmap glxpixmap = 0; bool error = false; - gfxIntSize dummySize(16, 16); nsRefPtr<gfxXlibSurface> xsurface = gfxXlibSurface::Create(DefaultScreenOfDisplay(display), visual, - dummySize); + gfxIntSize(16, 16)); if (xsurface->CairoStatus() != 0) { error = true; goto DONE_CREATING_PIXMAP; } // Handle slightly different signature between glXCreatePixmap and // its pre-GLX-1.3 extension equivalent (though given the ABI, we // might not need to). - if (glx.GLXVersionCheck(1, 3)) { - glxpixmap = glx.xCreatePixmap(display, + if (sGLXLib.GLXVersionCheck(1, 3)) { + glxpixmap = sGLXLib.xCreatePixmap(display, cfgs[chosenIndex], xsurface->XDrawable(), NULL); } else { - glxpixmap = glx.xCreateGLXPixmapWithConfig(display, + glxpixmap = sGLXLib.xCreateGLXPixmapWithConfig(display, cfgs[chosenIndex], xsurface-> XDrawable()); } if (glxpixmap == 0) { error = true; } DONE_CREATING_PIXMAP: nsRefPtr<GLContextGLX> glContext; bool serverError = xErrorHandler.SyncAndGetError(display); if (!error && // earlier recorded error !serverError) { - GLContext::ContextFlags flag = libToUse == GLXLibrary::MESA_LLVMPIPE_LIB - ? GLContext::ContextFlagsMesaLLVMPipe - : GLContext::ContextFlagsNone; - // We might have an alpha channel, but it doesn't matter. - SurfaceCaps dummyCaps = SurfaceCaps::Any(); - GLContextGLX* shareContext = GetGlobalContextGLX(flag); - - glContext = GLContextGLX::CreateGLContext(dummyCaps, - shareContext, - true, - display, - glxpixmap, - cfgs[chosenIndex], - false, - libToUse, - xsurface); + GLContext::ContextFlags flag = aLibToUse == GLXLibrary::OPENGL_LIB + ? GLContext::ContextFlagsNone + : GLContext::ContextFlagsMesaLLVMPipe; + glContext = GLContextGLX::CreateGLContext( + aFormat, + display, + glxpixmap, + cfgs[chosenIndex], + aShare ? GetGlobalContextGLX(flag) : nullptr, + true, + aLibToUse, + xsurface); } return glContext.forget(); } already_AddRefed<GLContext> -GLContextProviderGLX::CreateOffscreen(const gfxIntSize& size, - const SurfaceCaps& caps, - ContextFlags flags) +GLContextProviderGLX::CreateOffscreen(const gfxIntSize& aSize, + const ContextFormat& aFormat, + const ContextFlags aFlag) { - LibType libType = GLXLibrary::SelectLibrary(flags); - gCurrLib = libType; + gCurrLib = GLXLibrary::SelectLibrary(aFlag); + nsRefPtr<GLContextGLX> glContext = + CreateOffscreenPixmapContext(aSize, aFormat, true, gCurrLib); + + if (!glContext) { + return nullptr; + } - gfxIntSize dummySize = gfxIntSize(16, 16); - nsRefPtr<GLContextGLX> glContext = - CreateOffscreenPixmapContext(dummySize, libType); + if (!glContext->GetSharedContext()) { + // no point in returning anything if sharing failed, we can't + // render from this + return nullptr; + } - if (!glContext) + if (!glContext->ResizeOffscreenFBOs(aSize, true)) { + // we weren't able to create the initial + // offscreen FBO, so this is dead return nullptr; - - if (!glContext->InitOffscreen(size, caps)) - return nullptr; + } return glContext.forget(); } static nsRefPtr<GLContext> gGlobalContext[GLXLibrary::LIBS_MAX]; -GLContext* +GLContext * GLContextProviderGLX::GetGlobalContext(const ContextFlags aFlag) { - LibType libType = GLXLibrary::SelectLibrary(aFlag); + LibType libToUse = GLXLibrary::SelectLibrary(aFlag); static bool triedToCreateContext[GLXLibrary::LIBS_MAX] = {false, false}; - if (!triedToCreateContext[libType] && !gGlobalContext[libType]) { - triedToCreateContext[libType] = true; - - gfxIntSize dummySize = gfxIntSize(16, 16); - gGlobalContext[libType] = CreateOffscreenPixmapContext(dummySize, libType); - if (gGlobalContext[libType]) - gGlobalContext[libType]->SetIsGlobalSharedContext(true); + if (!triedToCreateContext[libToUse] && !gGlobalContext[libToUse]) { + triedToCreateContext[libToUse] = true; + gGlobalContext[libToUse] = CreateOffscreenPixmapContext(gfxIntSize(1, 1), + ContextFormat(ContextFormat::BasicRGB24), + false, libToUse); + if (gGlobalContext[libToUse]) + gGlobalContext[libToUse]->SetIsGlobalSharedContext(true); } - return gGlobalContext[libType]; + return gGlobalContext[libToUse]; } void GLContextProviderGLX::Shutdown() { for (int i = 0; i < GLXLibrary::LIBS_MAX; ++i) gGlobalContext[i] = nullptr; }
--- a/gfx/gl/GLContextProviderImpl.h +++ b/gfx/gl/GLContextProviderImpl.h @@ -10,17 +10,16 @@ #ifndef GL_CONTEXT_PROVIDER_NAME #error GL_CONTEXT_PROVIDER_NAME not defined #endif class THEBES_API GL_CONTEXT_PROVIDER_NAME { public: typedef GLContext::ContextFlags ContextFlags; - typedef gfx::SurfaceCaps SurfaceCaps; /** * Create a context that renders to the surface of the widget that is * passed in. The context is always created with an RGB pixel format, * with no alpha, depth or stencil. If any of those features are needed, * either use a framebuffer, or use CreateOffscreen. * * This context will attempt to share resources with all other window * contexts. As such, it's critical that resources allocated that are not @@ -33,45 +32,46 @@ public: * reference to the widget; otherwise a cycle can be created through * a GL layer manager. * * @param aWidget Widget whose surface to create a context for * * @return Context to use for the window */ static already_AddRefed<GLContext> - CreateForWindow(nsIWidget* widget); + CreateForWindow(nsIWidget *aWidget); /** * Create a context for offscreen rendering. The target of this * context should be treated as opaque -- it might be a FBO, or a * pbuffer, or some other construct. Users of this GLContext - * should bind framebuffer 0 directly to use this offscreen buffer. + * should not bind framebuffer 0 directly, and instead should bind + * the framebuffer returned by GetOffscreenFBO(). * * The offscreen context returned by this method will always have * the ability to be rendered into a context created by a window. * It might or might not share resources with the global context; * query GetSharedContext() for a non-null result to check. If * resource sharing can be avoided on the target platform, it will * be, in order to isolate the offscreen context. * * @param aSize The initial size of this offscreen context. * @param aFormat The ContextFormat for this offscreen context. * * @return Context to use for offscreen rendering */ static already_AddRefed<GLContext> - CreateOffscreen(const gfxIntSize& size, - const SurfaceCaps& caps, - ContextFlags flags = GLContext::ContextFlagsNone); + CreateOffscreen(const gfxIntSize& aSize, + const ContextFormat& aFormat = ContextFormat::BasicRGBA32Format, + const ContextFlags aFlags = GLContext::ContextFlagsNone); /** * Get a pointer to the global context, creating it if it doesn't exist. */ - static GLContext* - GetGlobalContext(ContextFlags flags = GLContext::ContextFlagsNone); + static GLContext * + GetGlobalContext( const ContextFlags aFlags = GLContext::ContextFlagsNone); /** * Free any resources held by this Context Provider. */ static void Shutdown(); };
--- a/gfx/gl/GLContextProviderNull.cpp +++ b/gfx/gl/GLContextProviderNull.cpp @@ -11,24 +11,24 @@ namespace gl { already_AddRefed<GLContext> GLContextProviderNull::CreateForWindow(nsIWidget*) { return nullptr; } already_AddRefed<GLContext> GLContextProviderNull::CreateOffscreen(const gfxIntSize&, - const SurfaceCaps&, - ContextFlags) + const ContextFormat&, + const ContextFlags) { return nullptr; } -GLContext* -GLContextProviderNull::GetGlobalContext(ContextFlags) +GLContext * +GLContextProviderNull::GetGlobalContext() { return nullptr; } void GLContextProviderNull::Shutdown() { }
--- a/gfx/gl/GLContextProviderWGL.cpp +++ b/gfx/gl/GLContextProviderWGL.cpp @@ -15,18 +15,16 @@ #include "gfxWindowsSurface.h" #include "gfxCrashReporterUtils.h" #include "prenv.h" #include "mozilla/Preferences.h" -using namespace mozilla::gfx; - namespace mozilla { namespace gl { typedef WGLLibrary::LibraryType LibType; WGLLibrary sWGLLib[WGLLibrary::LIBS_MAX]; LibType @@ -249,45 +247,42 @@ WGLLibrary::EnsureInitialized(bool aUseM reporter.SetSuccessful(); return true; } class GLContextWGL : public GLContext { public: - // From Window: (possibly for offscreen!) - GLContextWGL(const SurfaceCaps& caps, - GLContext* sharedContext, - bool isOffscreen, + GLContextWGL(const ContextFormat& aFormat, + GLContext *aSharedContext, HDC aDC, HGLRC aContext, LibType aLibUsed, - HWND aWindow = nullptr) - : GLContext(caps, sharedContext, isOffscreen), + HWND aWindow = nullptr, + bool aIsOffscreen = false) + : GLContext(aFormat, aIsOffscreen, aSharedContext), mDC(aDC), mContext(aContext), mWnd(aWindow), mPBuffer(NULL), mPixelFormat(0), mLibType(aLibUsed), mIsDoubleBuffered(false) { } - // From PBuffer - GLContextWGL(const SurfaceCaps& caps, - GLContext* sharedContext, - bool isOffscreen, + GLContextWGL(const ContextFormat& aFormat, + GLContext *aSharedContext, HANDLE aPbuffer, HDC aDC, HGLRC aContext, int aPixelFormat, LibType aLibUsed) - : GLContext(caps, sharedContext, isOffscreen), + : GLContext(aFormat, true, aSharedContext), mDC(aDC), mContext(aContext), mWnd(NULL), mPBuffer(aPbuffer), mPixelFormat(aPixelFormat), mLibType(aLibUsed), mIsDoubleBuffered(false) { @@ -374,32 +369,91 @@ public: case NativeGLContext: return mContext; default: return nullptr; } } + bool BindTex2DOffscreen(GLContext *aOffscreen); + void UnbindTex2DOffscreen(GLContext *aOffscreen); bool ResizeOffscreen(const gfxIntSize& aNewSize); HGLRC Context() { return mContext; } protected: friend class GLContextProviderWGL; HDC mDC; HGLRC mContext; HWND mWnd; HANDLE mPBuffer; int mPixelFormat; LibType mLibType; bool mIsDoubleBuffered; }; +bool +GLContextWGL::BindTex2DOffscreen(GLContext *aOffscreen) +{ + if (aOffscreen->GetContextType() != ContextTypeWGL) { + NS_WARNING("non-WGL context"); + return false; + } + + if (!aOffscreen->IsOffscreen()) { + NS_WARNING("non-offscreen context"); + return false; + } + + GLContextWGL *offs = static_cast<GLContextWGL*>(aOffscreen); + + if (offs->mPBuffer) { + BOOL ok = sWGLLib[mLibType].fBindTexImage(offs->mPBuffer, + LOCAL_WGL_FRONT_LEFT_ARB); + if (!ok) { + NS_WARNING("CanvasLayerOGL::Updated wglBindTexImageARB failed"); + return false; + } + } else if (offs->mOffscreenTexture) { + GLContext::ContextFlags flag = + sWGLLib[mLibType].GetLibraryType() == WGLLibrary::MESA_LLVMPIPE_LIB + ? GLContext::ContextFlagsMesaLLVMPipe + : GLContext::ContextFlagsNone; + + if (offs->GetSharedContext() != GLContextProviderWGL::GetGlobalContext(flag)) + { + NS_WARNING("offscreen FBO context can only be bound with context sharing!"); + return false; + } + + fBindTexture(LOCAL_GL_TEXTURE_2D, offs->mOffscreenTexture); + } else { + NS_WARNING("don't know how to bind this!"); + return false; + } + + return true; +} + +void +GLContextWGL::UnbindTex2DOffscreen(GLContext *aOffscreen) +{ + NS_ASSERTION(aOffscreen->GetContextType() == ContextTypeWGL, "wrong type"); + + GLContextWGL *offs = static_cast<GLContextWGL*>(aOffscreen); + if (offs->mPBuffer) { + // XXX so, according to the extension, ReleaseTexImage is not required to + // preserve color buffer contents. This sucks, but everywhere that I've + // tried it the color buffer is preserved. So let's cross our fingers.. + sWGLLib[mLibType].fReleaseTexImage(offs->mPBuffer, LOCAL_WGL_FRONT_LEFT_ARB); + } +} + static bool GetMaxSize(HDC hDC, int format, gfxIntSize& size, LibType aLibToUse) { int query[] = {LOCAL_WGL_MAX_PBUFFER_WIDTH_ARB, LOCAL_WGL_MAX_PBUFFER_HEIGHT_ARB}; int result[2]; // (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, int* piAttributes, int *piValues) @@ -426,17 +480,53 @@ IsValidSizeForFormat(HDC hDC, int format return false; return true; } bool GLContextWGL::ResizeOffscreen(const gfxIntSize& aNewSize) { - return ResizeScreenBuffer(aNewSize); + if (mPBuffer) { + if (!IsValidSizeForFormat(sWGLLib[mLibType].GetWindowDC(), mPixelFormat, aNewSize, mLibType)) + return false; + + int pbattrs[] = { + LOCAL_WGL_TEXTURE_FORMAT_ARB, + mCreationFormat.alpha > 0 ? LOCAL_WGL_TEXTURE_RGBA_ARB + : LOCAL_WGL_TEXTURE_RGB_ARB, + LOCAL_WGL_TEXTURE_TARGET_ARB, LOCAL_WGL_TEXTURE_2D_ARB, + 0 + }; + + HANDLE newbuf = sWGLLib[mLibType].fCreatePbuffer(sWGLLib[mLibType].GetWindowDC(), mPixelFormat, + aNewSize.width, aNewSize.height, + pbattrs); + if (!newbuf) + return false; + + if (sWGLLib[mLibType].fGetCurrentContext() == mContext) { + sWGLLib[mLibType].fMakeCurrent(NULL, NULL); + } + + sWGLLib[mLibType].fDestroyPbuffer(mPBuffer); + + mPBuffer = newbuf; + mDC = sWGLLib[mLibType].fGetPbufferDC(mPBuffer); + + mOffscreenSize = aNewSize; + mOffscreenActualSize = aNewSize; + + MakeCurrent(); + ClearSafely(); + + return ResizeOffscreenFBOs(aNewSize, false); + } + + return ResizeOffscreenFBOs(aNewSize, true); } static GLContextWGL * GetGlobalContextWGL(const GLContext::ContextFlags aFlags = GLContext::ContextFlagsNone) { return static_cast<GLContextWGL*>(GLContextProviderWGL::GetGlobalContext(aFlags)); } @@ -492,119 +582,132 @@ GLContextProviderWGL::CreateForWindow(ns shareContext = nullptr; } } if (!context) { return nullptr; } - SurfaceCaps caps = SurfaceCaps::ForRGBA(); - nsRefPtr<GLContextWGL> glContext = new GLContextWGL(caps, - shareContext, - false, - dc, - context, - libToUse); + nsRefPtr<GLContextWGL> glContext = new GLContextWGL(ContextFormat(ContextFormat::BasicRGB24), + shareContext, dc, context, libToUse); if (!glContext->Init()) { return nullptr; } glContext->SetIsDoubleBuffered(sWGLLib[libToUse].UseDoubleBufferedWindows()); return glContext.forget(); } static already_AddRefed<GLContextWGL> CreatePBufferOffscreenContext(const gfxIntSize& aSize, + const ContextFormat& aFormat, LibType aLibToUse) { - WGLLibrary& wgl = sWGLLib[aLibToUse]; - #define A1(_a,_x) do { _a.AppendElement(_x); } while(0) #define A2(_a,_x,_y) do { _a.AppendElement(_x); _a.AppendElement(_y); } while(0) nsTArray<int> attrs; A2(attrs, LOCAL_WGL_SUPPORT_OPENGL_ARB, LOCAL_GL_TRUE); A2(attrs, LOCAL_WGL_DRAW_TO_PBUFFER_ARB, LOCAL_GL_TRUE); A2(attrs, LOCAL_WGL_DOUBLE_BUFFER_ARB, LOCAL_GL_FALSE); A2(attrs, LOCAL_WGL_ACCELERATION_ARB, LOCAL_WGL_FULL_ACCELERATION_ARB); + A2(attrs, LOCAL_WGL_COLOR_BITS_ARB, aFormat.colorBits()); + A2(attrs, LOCAL_WGL_RED_BITS_ARB, aFormat.red); + A2(attrs, LOCAL_WGL_GREEN_BITS_ARB, aFormat.green); + A2(attrs, LOCAL_WGL_BLUE_BITS_ARB, aFormat.blue); + A2(attrs, LOCAL_WGL_ALPHA_BITS_ARB, aFormat.alpha); + + A2(attrs, LOCAL_WGL_DEPTH_BITS_ARB, aFormat.depth); + A2(attrs, LOCAL_WGL_STENCIL_BITS_ARB, aFormat.stencil); + + if (aFormat.alpha > 0) { + A2(attrs, LOCAL_WGL_BIND_TO_TEXTURE_RGBA_ARB, LOCAL_GL_TRUE); + } else { + A2(attrs, LOCAL_WGL_BIND_TO_TEXTURE_RGB_ARB, LOCAL_GL_TRUE); + } + A2(attrs, LOCAL_WGL_DOUBLE_BUFFER_ARB, LOCAL_GL_FALSE); A2(attrs, LOCAL_WGL_STEREO_ARB, LOCAL_GL_FALSE); A1(attrs, 0); nsTArray<int> pbattrs; + A2(pbattrs, LOCAL_WGL_TEXTURE_TARGET_ARB, LOCAL_WGL_TEXTURE_2D_ARB); + + if (aFormat.alpha > 0) { + A2(pbattrs, LOCAL_WGL_TEXTURE_FORMAT_ARB, LOCAL_WGL_TEXTURE_RGBA_ARB); + } else { + A2(pbattrs, LOCAL_WGL_TEXTURE_FORMAT_ARB, LOCAL_WGL_TEXTURE_RGB_ARB); + } A1(pbattrs, 0); -#undef A1 -#undef A2 + UINT numFormats = 256; + int formats[256]; - // We only need one! - UINT numFormats = 1; - int formats[1]; - HDC windowDC = wgl.GetWindowDC(); - if (!wgl.fChoosePixelFormat(windowDC, - attrs.Elements(), NULL, - numFormats, formats, &numFormats) + if (!sWGLLib[aLibToUse].fChoosePixelFormat(sWGLLib[aLibToUse].GetWindowDC(), + attrs.Elements(), NULL, + numFormats, formats, &numFormats) || numFormats == 0) { return nullptr; } - // We don't care; just pick the first one. + // XXX add back the priority choosing code here int chosenFormat = formats[0]; - if (!IsValidSizeForFormat(windowDC, chosenFormat, aSize, aLibToUse)) + + if (!IsValidSizeForFormat(sWGLLib[aLibToUse].GetWindowDC(), chosenFormat, aSize, aLibToUse)) return nullptr; - HANDLE pbuffer = wgl.fCreatePbuffer(windowDC, chosenFormat, - aSize.width, aSize.height, - pbattrs.Elements()); + HANDLE pbuffer = sWGLLib[aLibToUse].fCreatePbuffer(sWGLLib[aLibToUse].GetWindowDC(), chosenFormat, + aSize.width, aSize.height, + pbattrs.Elements()); if (!pbuffer) { return nullptr; } - HDC pbdc = wgl.fGetPbufferDC(pbuffer); + HDC pbdc = sWGLLib[aLibToUse].fGetPbufferDC(pbuffer); NS_ASSERTION(pbdc, "expected a dc"); HGLRC context; - if (wgl.HasRobustness()) { + if (sWGLLib[aLibToUse].HasRobustness()) { int attribs[] = { LOCAL_WGL_CONTEXT_FLAGS_ARB, LOCAL_WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB, LOCAL_WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, LOCAL_WGL_LOSE_CONTEXT_ON_RESET_ARB, 0 }; - context = wgl.fCreateContextAttribs(pbdc, nullptr, attribs); + context = sWGLLib[aLibToUse].fCreateContextAttribs(pbdc, nullptr, attribs); } else { - context = wgl.fCreateContext(pbdc); + context = sWGLLib[aLibToUse].fCreateContext(pbdc); } if (!context) { - wgl.fDestroyPbuffer(pbuffer); + sWGLLib[aLibToUse].fDestroyPbuffer(pbuffer); return nullptr; } - SurfaceCaps dummyCaps = SurfaceCaps::Any(); - nsRefPtr<GLContextWGL> glContext = new GLContextWGL(dummyCaps, - nullptr, true, + nsRefPtr<GLContextWGL> glContext = new GLContextWGL(aFormat, + nullptr, pbuffer, pbdc, context, chosenFormat, aLibToUse); return glContext.forget(); } static already_AddRefed<GLContextWGL> -CreateWindowOffscreenContext(GLContext::ContextFlags aFlags) +CreateWindowOffscreenContext(const ContextFormat& aFormat, + const GLContext::ContextFlags aFlags) { // CreateWindowOffscreenContext must return a global-shared context GLContextWGL *shareContext = GetGlobalContextWGL(aFlags); if (!shareContext) { return nullptr; } LibType libToUse = WGLLibrary::SelectLibrary(aFlags); @@ -635,87 +738,89 @@ CreateWindowOffscreenContext(GLContext:: return nullptr; } } if (!context) { return nullptr; } - SurfaceCaps caps = SurfaceCaps::ForRGBA(); - nsRefPtr<GLContextWGL> glContext = new GLContextWGL(caps, - shareContext, true, - dc, context, - libToUse, win); + nsRefPtr<GLContextWGL> glContext = new GLContextWGL(aFormat, shareContext, + dc, context, libToUse, + win, true); return glContext.forget(); } already_AddRefed<GLContext> -GLContextProviderWGL::CreateOffscreen(const gfxIntSize& size, - const SurfaceCaps& caps, - ContextFlags flags) +GLContextProviderWGL::CreateOffscreen(const gfxIntSize& aSize, + const ContextFormat& aFormat, + const ContextFlags aFlags) { - LibType libToUse = WGLLibrary::SelectLibrary(flags); + LibType libToUse = WGLLibrary::SelectLibrary(aFlags); if (!sWGLLib[libToUse].EnsureInitialized(libToUse == WGLLibrary::MESA_LLVMPIPE_LIB)) { return nullptr; } nsRefPtr<GLContextWGL> glContext; // Always try to create a pbuffer context first, because we // want the context isolation. - if (sWGLLib[libToUse].fCreatePbuffer && + NS_ENSURE_TRUE(Preferences::GetRootBranch(), nullptr); + const bool preferFBOs = Preferences::GetBool("wgl.prefer-fbo", false); + if (!preferFBOs && + sWGLLib[libToUse].fCreatePbuffer && sWGLLib[libToUse].fChoosePixelFormat) { - gfxIntSize dummySize = gfxIntSize(16, 16); - glContext = CreatePBufferOffscreenContext(dummySize, libToUse); + glContext = CreatePBufferOffscreenContext(aSize, aFormat,libToUse); } // If it failed, then create a window context and use a FBO. if (!glContext) { - glContext = CreateWindowOffscreenContext(flags); + glContext = CreateWindowOffscreenContext(aFormat, aFlags); } if (!glContext || !glContext->Init()) { return nullptr; } - if (!glContext->InitOffscreen(size, caps)) + if (!glContext->ResizeOffscreenFBOs(aSize, !glContext->mPBuffer)) return nullptr; + glContext->mOffscreenSize = aSize; + glContext->mOffscreenActualSize = aSize; + return glContext.forget(); } static nsRefPtr<GLContextWGL> gGlobalContext[WGLLibrary::LIBS_MAX]; GLContext * -GLContextProviderWGL::GetGlobalContext(const ContextFlags flags) +GLContextProviderWGL::GetGlobalContext(const ContextFlags aFlags) { - LibType libToUse = WGLLibrary::SelectLibrary(flags); + LibType libToUse = WGLLibrary::SelectLibrary(aFlags); if (!sWGLLib[libToUse].EnsureInitialized(libToUse == WGLLibrary::MESA_LLVMPIPE_LIB)) { return nullptr; } static bool triedToCreateContext[WGLLibrary::LIBS_MAX] = {false, false}; if (!triedToCreateContext[libToUse] && !gGlobalContext[libToUse]) { triedToCreateContext[libToUse] = true; // conveniently, we already have what we need... - SurfaceCaps dummyCaps = SurfaceCaps::Any(); - gGlobalContext[libToUse] = new GLContextWGL(dummyCaps, - nullptr, true, - sWGLLib[libToUse].GetWindowDC(), - sWGLLib[libToUse].GetWindowGLContext(), - libToUse); + gGlobalContext[libToUse] = new GLContextWGL(ContextFormat(ContextFormat::BasicRGB24), + nullptr, + sWGLLib[libToUse].GetWindowDC(), + sWGLLib[libToUse].GetWindowGLContext(), + libToUse); if (!gGlobalContext[libToUse]->Init()) { NS_WARNING("Global context GLContext initialization failed?"); gGlobalContext[libToUse] = nullptr; return nullptr; } gGlobalContext[libToUse]->SetIsGlobalSharedContext(true); }
--- a/gfx/gl/GLContextSymbols.h +++ b/gfx/gl/GLContextSymbols.h @@ -372,16 +372,14 @@ struct GLContextSymbols typedef void (GLAPIENTRY * PFNGLGETINTEGER64V) (GLenum pname, GLint64 *params); PFNGLGETINTEGER64V fGetInteger64v; typedef void (GLAPIENTRY * PFNGLGETSYNCIV) (GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values); PFNGLGETSYNCIV fGetSynciv; // OES_egl_image typedef void (GLAPIENTRY * PFNGLEGLIMAGETARGETTEXTURE2D)(GLenum target, GLeglImage image); PFNGLEGLIMAGETARGETTEXTURE2D fEGLImageTargetTexture2D; - typedef void (GLAPIENTRY * PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGE)(GLenum target, GLeglImage image); - PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGE fEGLImageTargetRenderbufferStorage; }; } } #endif /* GLCONTEXTSYMBOLS_H_ */
deleted file mode 100644 --- a/gfx/gl/GLContextTypes.cpp +++ /dev/null @@ -1,19 +0,0 @@ -/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40; -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "GLContextTypes.h" -#include <cstring> - -using namespace mozilla::gl; - -GLFormats::GLFormats() -{ - std::memset(this, 0, sizeof(GLFormats)); -} - -PixelBufferFormat::PixelBufferFormat() -{ - std::memset(this, 0, sizeof(PixelBufferFormat)); -}
--- a/gfx/gl/GLContextTypes.h +++ b/gfx/gl/GLContextTypes.h @@ -1,16 +1,20 @@ /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#ifndef GLCONTEXT_TYPES_H_ -#define GLCONTEXT_TYPES_H_ +#ifndef GLCONTEXTSTUFF_H_ +#define GLCONTEXTSTUFF_H_ +/** + * We don't include GLDefs.h here since we don't want to drag in all defines + * in for all our users. + */ typedef unsigned int GLenum; typedef unsigned int GLbitfield; typedef unsigned int GLuint; typedef int GLint; typedef int GLsizei; namespace mozilla { namespace gl { @@ -27,44 +31,12 @@ enum ShaderProgramType { YCbCrLayerProgramType, ComponentAlphaPass1ProgramType, ComponentAlphaPass2ProgramType, Copy2DProgramType, Copy2DRectProgramType, NumProgramTypes }; -struct GLFormats -{ - // Constructs a zeroed object: - GLFormats(); - - GLenum color_texInternalFormat; - GLenum color_texFormat; - GLenum color_texType; - GLenum color_rbFormat; - - GLenum depthStencil; - GLenum depth; - GLenum stencil; - - GLsizei samples; -}; - +} // namespace gl +} // namespace mozilla -struct PixelBufferFormat -{ - // Constructs a zeroed object: - PixelBufferFormat(); - - int red, green, blue; - int alpha; - int depth, stencil; - int samples; - - int ColorBits() const { return red + green + blue; } -}; - - -} /* namespace gl */ -} /* namespace mozilla */ - -#endif /* GLCONTEXT_TYPES_H_ */ +#endif /* GLCONTEXTSTUFF_H_ */
--- a/gfx/gl/GLContextUtils.cpp +++ b/gfx/gl/GLContextUtils.cpp @@ -22,22 +22,16 @@ varying vec2 vTexCoord; void main(void) { \n\ vTexCoord = aPosition; \n\ vec2 vertPos = aPosition * 2.0 - 1.0; \n\ gl_Position = vec4(vertPos, 0.0, 1.0); \n\ } \n\ "; static const char kTexBlit_FragShaderSource[] = "\ -#ifdef GL_FRAGMENT_PRECISION_HIGH \n\ - precision highp float; \n\ -#else \n\ - precision mediump float; \n\ -#endif \n\ - \n\ uniform sampler2D uTexUnit; \n\ \n\ varying vec2 vTexCoord; \n\ \n\ void main(void) { \n\ gl_FragColor = texture2D(uTexUnit, vTexCoord); \n\ } \n\ "; @@ -221,75 +215,49 @@ GLContext::BlitFramebufferToFramebuffer( const gfxIntSize& destSize) { MOZ_ASSERT(!srcFB || fIsFramebuffer(srcFB)); MOZ_ASSERT(!destFB || fIsFramebuffer(destFB)); MOZ_ASSERT(IsExtensionSupported(EXT_framebuffer_blit) || IsExtensionSupported(ANGLE_framebuffer_blit)); - ScopedBindFramebuffer boundFB(this); + ScopedFramebufferBinding boundFB(this); ScopedGLState scissor(this, LOCAL_GL_SCISSOR_TEST, false); - BindReadFB(srcFB); - BindDrawFB(destFB); + BindUserReadFBO(srcFB); + BindUserDrawFBO(destFB); fBlitFramebuffer(0, 0, srcSize.width, srcSize.height, 0, 0, destSize.width, destSize.height, LOCAL_GL_COLOR_BUFFER_BIT, LOCAL_GL_NEAREST); } void -GLContext::BlitFramebufferToFramebuffer(GLuint srcFB, GLuint destFB, - const gfxIntSize& srcSize, - const gfxIntSize& destSize, - const GLFormats& srcFormats) -{ - MOZ_ASSERT(!srcFB || fIsFramebuffer(srcFB)); - MOZ_ASSERT(!destFB || fIsFramebuffer(destFB)); - - if (IsExtensionSupported(EXT_framebuffer_blit) || - IsExtensionSupported(ANGLE_framebuffer_blit)) - { - BlitFramebufferToFramebuffer(srcFB, destFB, - srcSize, destSize); - return; - } - - GLuint tex = CreateTextureForOffscreen(srcFormats, srcSize); - MOZ_ASSERT(tex); - - BlitFramebufferToTexture(srcFB, tex, srcSize, srcSize); - BlitTextureToFramebuffer(tex, destFB, srcSize, destSize); - - fDeleteTextures(1, &tex); -} - -void GLContext::BlitTextureToFramebuffer(GLuint srcTex, GLuint destFB, const gfxIntSize& srcSize, const gfxIntSize& destSize) { MOZ_ASSERT(fIsTexture(srcTex)); MOZ_ASSERT(!destFB || fIsFramebuffer(destFB)); if (IsExtensionSupported(EXT_framebuffer_blit) || IsExtensionSupported(ANGLE_framebuffer_blit)) { - ScopedFramebufferForTexture srcWrapper(this, srcTex); + ScopedFramebufferTexture srcWrapper(this, srcTex); MOZ_ASSERT(srcWrapper.IsComplete()); BlitFramebufferToFramebuffer(srcWrapper.FB(), destFB, srcSize, destSize); return; } - ScopedBindFramebuffer boundFB(this, destFB); + ScopedFramebufferBinding boundFB(this, destFB); GLuint boundTexUnit = 0; GetUIntegerv(LOCAL_GL_ACTIVE_TEXTURE, &boundTexUnit); fActiveTexture(LOCAL_GL_TEXTURE0); GLuint boundTex = 0; GetUIntegerv(LOCAL_GL_TEXTURE_BINDING_2D, &boundTex); fBindTexture(LOCAL_GL_TEXTURE_2D, srcTex); @@ -397,52 +365,60 @@ GLContext::BlitFramebufferToTexture(GLui const gfxIntSize& destSize) { MOZ_ASSERT(!srcFB || fIsFramebuffer(srcFB)); MOZ_ASSERT(fIsTexture(destTex)); if (IsExtensionSupported(EXT_framebuffer_blit) || IsExtensionSupported(ANGLE_framebuffer_blit)) { - ScopedFramebufferForTexture destWrapper(this, destTex); + ScopedFramebufferTexture destWrapper(this, destTex); + MOZ_ASSERT(destWrapper.IsComplete()); BlitFramebufferToFramebuffer(srcFB, destWrapper.FB(), srcSize, destSize); return; } - ScopedBindTexture autoTex(this, destTex); - ScopedBindFramebuffer boundFB(this, srcFB); + GLuint boundTex = 0; + GetUIntegerv(LOCAL_GL_TEXTURE_BINDING_2D, &boundTex); + fBindTexture(LOCAL_GL_TEXTURE_2D, destTex); + + ScopedFramebufferBinding boundFB(this, srcFB); ScopedGLState scissor(this, LOCAL_GL_SCISSOR_TEST, false); fCopyTexSubImage2D(LOCAL_GL_TEXTURE_2D, 0, 0, 0, 0, 0, srcSize.width, srcSize.height); + + fBindTexture(LOCAL_GL_TEXTURE_2D, boundTex); } void GLContext::BlitTextureToTexture(GLuint srcTex, GLuint destTex, const gfxIntSize& srcSize, const gfxIntSize& destSize) { MOZ_ASSERT(fIsTexture(srcTex)); MOZ_ASSERT(fIsTexture(destTex)); if (mTexBlit_UseDrawNotCopy) { // Draw is texture->framebuffer - ScopedFramebufferForTexture destWrapper(this, destTex); + ScopedFramebufferTexture destWrapper(this, destTex); + MOZ_ASSERT(destWrapper.IsComplete()); BlitTextureToFramebuffer(srcTex, destWrapper.FB(), srcSize, destSize); return; } // Generally, just use the CopyTexSubImage path - ScopedFramebufferForTexture srcWrapper(this, srcTex); + ScopedFramebufferTexture srcWrapper(this, srcTex); + MOZ_ASSERT(srcWrapper.IsComplete()); BlitFramebufferToTexture(srcWrapper.FB(), destTex, srcSize, destSize); } uint32_t GetBitsPerTexel(GLenum format, GLenum type) { // If there is no defined format or type, we're not taking up any memory
--- a/gfx/gl/GLDefs.h +++ b/gfx/gl/GLDefs.h @@ -42,37 +42,16 @@ typedef ptrdiff_t GLintptr; // ARB_sync typedef struct __GLsync* GLsync; typedef int64_t GLint64; typedef uint64_t GLuint64; // OES_EGL_image (GLES) typedef void* GLeglImage; -// EGL types -typedef int EGLint; -typedef unsigned int EGLBoolean; -typedef unsigned int EGLenum; -typedef void *EGLConfig; -typedef void *EGLContext; -typedef void *EGLDisplay; -typedef void *EGLSurface; -typedef void *EGLClientBuffer; -typedef void *EGLCastToRelevantPtr; -typedef void *EGLImage; -typedef void *EGLSync; -typedef uint64_t EGLTime; - -#define EGL_NO_CONTEXT ((EGLContext)0) -#define EGL_NO_DISPLAY ((EGLDisplay)0) -#define EGL_NO_SURFACE ((EGLSurface)0) -#define EGL_NO_CONFIG ((EGLConfig)nullptr) -#define EGL_NO_SYNC ((EGLSync)0) -#define EGL_NO_IMAGE ((EGLImage)0) - #ifndef GLAPIENTRY # ifdef WIN32 # define GLAPIENTRY APIENTRY # define GLAPI # else # define GLAPIENTRY # define GLAPI # endif @@ -3291,19 +3270,16 @@ typedef uint64_t EGLTime; #define LOCAL_EGL_IMAGE_PRESERVED 0x30D2 // EGL_KHR_image_pixmap #define LOCAL_EGL_NATIVE_PIXMAP 0x30B0 // EGL_KHR_gl_texture_2D_image #define LOCAL_EGL_GL_TEXTURE_2D 0x30B1 -// EGL_KHR_gl_renderbuffer_image -#define LOCAL_EGL_GL_RENDERBUFFER 0x30B9 - // OES_EGL_image_external #define LOCAL_GL_TEXTURE_EXTERNAL 0x8D65 // EGL_KHR_fence_sync #define LOCAL_EGL_SYNC_FENCE 0x30F9 #define LOCAL_EGL_SYNC_TYPE 0x30F7 #define LOCAL_EGL_SYNC_STATUS 0x30F1 #define LOCAL_EGL_SYNC_CONDITION 0x30F8 @@ -3311,15 +3287,9 @@ typedef uint64_t EGLTime; #define LOCAL_EGL_UNSIGNALED 0x30F3 #define LOCAL_EGL_SYNC_PRIOR_COMMANDS_COMPLETE 0x30F0 #define LOCAL_EGL_SYNC_FLUSH_COMMANDS_BIT 0x0001 #define LOCAL_EGL_FOREVER 0xFFFFFFFFFFFFFFFFull #define LOCAL_EGL_TIMEOUT_EXPIRED 0x30F5 #define LOCAL_EGL_CONDITION_SATISFIED 0x30F6 #define LOCAL_EGL_SUCCESS 0x3000 -// EGL_ANGLE_surface_d3d_texture_2d_share_handle -#define LOCAL_EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE 0x3200 - -// FAKE_EGL_image_android -#define LOCAL_EGL_NATIVE_BUFFER_ANDROID 0x3140 - #endif
--- a/gfx/gl/GLLibraryEGL.cpp +++ b/gfx/gl/GLLibraryEGL.cpp @@ -5,17 +5,16 @@ #include "GLLibraryEGL.h" #include "gfxCrashReporterUtils.h" #include "mozilla/Preferences.h" #include "nsDirectoryServiceDefs.h" #include "nsDirectoryServiceUtils.h" #include "nsPrintfCString.h" #include "prenv.h" -#include "GLContext.h" namespace mozilla { namespace gl { // should match the order of EGLExtensions, and be null-terminated. static const char *sExtensionNames[] = { "EGL_KHR_image_base", "EGL_KHR_image_pixmap", @@ -252,40 +251,16 @@ GLLibraryEGL::EnsureInitialized() mSymbols.fCreateSync = nullptr; mSymbols.fDestroySync = nullptr; mSymbols.fClientWaitSync = nullptr; mSymbols.fGetSyncAttrib = nullptr; } } - if (IsExtensionSupported(KHR_image) || IsExtensionSupported(KHR_image_base)) { - GLLibraryLoader::SymLoadStruct imageSymbols[] = { - { (PRFuncPtr*) &mSymbols.fCreateImage, { "eglCreateImageKHR", nullptr } }, - { (PRFuncPtr*) &mSymbols.fDestroyImage, { "eglDestroyImageKHR", nullptr } }, - { nullptr, { nullptr } } - }; - - bool success = GLLibraryLoader::LoadSymbols(mEGLLibrary, - &imageSymbols[0], - lookupFunction); - if (!success) { - NS_ERROR("EGL supports KHR_image(_base) without exposing its functions!"); - - MarkExtensionUnsupported(KHR_image); - MarkExtensionUnsupported(KHR_image_base); - MarkExtensionUnsupported(KHR_image_pixmap); - - mSymbols.fCreateImage = nullptr; - mSymbols.fDestroyImage = nullptr; - } - } else { - MarkExtensionUnsupported(KHR_image_pixmap); - } - mInitialized = true; reporter.SetSuccessful(); return true; } void GLLibraryEGL::InitExtensions() { @@ -310,16 +285,47 @@ GLLibraryEGL::InitExtensions() mAvailableExtensions.Load(extensions, sExtensionNames, firstRun && debugMode); #ifdef DEBUG firstRun = false; #endif } void +GLLibraryEGL::LoadConfigSensitiveSymbols() +{ + GLLibraryLoader::PlatformLookupFunction lookupFunction = + (GLLibraryLoader::PlatformLookupFunction)mSymbols.fGetProcAddress; + + if (IsExtensionSupported(KHR_image) || IsExtensionSupported(KHR_image_base)) { + GLLibraryLoader::SymLoadStruct imageSymbols[] = { + { (PRFuncPtr*) &mSymbols.fCreateImage, { "eglCreateImageKHR", nullptr } }, + { (PRFuncPtr*) &mSymbols.fDestroyImage, { "eglDestroyImageKHR", nullptr } }, + { nullptr, { nullptr } } + }; + + bool success = GLLibraryLoader::LoadSymbols(mEGLLibrary, + &imageSymbols[0], + lookupFunction); + if (!success) { + NS_ERROR("EGL supports KHR_image(_base) without exposing its functions!"); + + MarkExtensionUnsupported(KHR_image); + MarkExtensionUnsupported(KHR_image_base); + MarkExtensionUnsupported(KHR_image_pixmap); + + mSymbols.fCreateImage = nullptr; + mSymbols.fDestroyImage = nullptr; + } + } else { + MarkExtensionUnsupported(KHR_image_pixmap); + } +} + +void GLLibraryEGL::DumpEGLConfig(EGLConfig cfg) { int attrval; int err; #define ATTR(_x) do { \ fGetConfigAttrib(mEGLDisplay, cfg, LOCAL_EGL_##_x, &attrval); \ if ((err = fGetError()) != 0x3000) { \
--- a/gfx/gl/GLLibraryEGL.h +++ b/gfx/gl/GLLibraryEGL.h @@ -9,16 +9,28 @@ #include "mozilla/X11Util.h" #endif #include "GLContext.h" #include "GLLibraryLoader.h" #include "nsIFile.h" +typedef int EGLint; +typedef unsigned int EGLBoolean; +typedef unsigned int EGLenum; +typedef void *EGLConfig; +typedef void *EGLContext; +typedef void *EGLDisplay; +typedef void *EGLSurface; +typedef void *EGLClientBuffer; +typedef void *EGLCastToRelevantPtr; +typedef void *EGLImage; +typedef void *EGLSync; +typedef uint64_t EGLTime; #if defined(XP_WIN) #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN 1 #endif #include <windows.h> @@ -39,28 +51,30 @@ typedef void *EGLNativeWindowType; // on android as we can use LD_PRELOAD or other tricks // on other platforms. We look for it in /data/local // as that's writeable by all users // // This should really go in GLLibraryEGL.cpp but we currently reference // APITRACE_LIB in GLContextProviderEGL.cpp. Further refactoring // will come in subsequent patches on Bug 732865 #define APITRACE_LIB "/data/local/egltrace.so" - -#ifdef MOZ_WIDGET_ANDROID - -#endif // MOZ_WIDGET_ANDROID #endif // ANDROID #endif #if defined(MOZ_X11) #define EGL_DEFAULT_DISPLAY ((EGLNativeDisplayType)mozilla::DefaultXDisplay()) #else #define EGL_DEFAULT_DISPLAY ((EGLNativeDisplayType)0) #endif +#define EGL_NO_CONTEXT ((EGLContext)0) +#define EGL_NO_DISPLAY ((EGLDisplay)0) +#define EGL_NO_SURFACE ((EGLSurface)0) +#define EGL_NO_SYNC ((EGLSync)0) + +#define EGL_DISPLAY() sEGLLibrary.Display() namespace mozilla { namespace gl { #ifdef DEBUG #undef BEFORE_GL_CALL #undef AFTER_GL_CALL @@ -436,16 +450,17 @@ public: return IsExtensionSupported(ANGLE_surface_d3d_texture_2d_share_handle); } bool HasRobustness() { return IsExtensionSupported(EXT_create_context_robustness); } bool EnsureInitialized(); + void LoadConfigSensitiveSymbols(); void DumpEGLConfig(EGLConfig cfg); void DumpEGLConfigs(); struct { typedef EGLDisplay (GLAPIENTRY * pfnGetDisplay)(void *display_id); pfnGetDisplay fGetDisplay; typedef EGLSurface (GLAPIENTRY * pfnGetCurrentSurface)(EGLint);
deleted file mode 100644 --- a/gfx/gl/GLScreenBuffer.cpp +++ /dev/null @@ -1,619 +0,0 @@ -/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40; -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "GLScreenBuffer.h" - -#include <cstring> -#include "gfxImageSurface.h" -#include "GLContext.h" -#include "SharedSurfaceGL.h" -#include "SurfaceStream.h" - -using namespace mozilla::gfx; - -namespace mozilla { -namespace gl { - -GLScreenBuffer* -GLScreenBuffer::Create(GLContext* gl, - const gfxIntSize& size, - const SurfaceCaps& caps) -{ - if (caps.antialias && - !gl->SupportsFramebufferMultisample()) - { - return nullptr; - } - - SurfaceFactory_GL* factory = new SurfaceFactory_Basic(gl, caps); - SurfaceStream* stream = SurfaceStream::CreateForType( - SurfaceStream::ChooseGLStreamType(SurfaceStream::MainThread, - caps.preserve), - nullptr); - - return new GLScreenBuffer(gl, caps, factory, stream); -} - -GLScreenBuffer::~GLScreenBuffer() -{ - delete mFactory; - delete mStream; - delete mDraw; - delete mRead; -} - - -void -GLScreenBuffer::BindAsFramebuffer(GLContext* const gl, GLenum target) const -{ - GLuint drawFB = DrawFB(); - GLuint readFB = ReadFB(); - - if (!gl->HasExt_FramebufferBlit()) { - MOZ_ASSERT(drawFB == readFB); - gl->raw_fBindFramebuffer(target, readFB); - return; - } - - switch (target) { - case LOCAL_GL_FRAMEBUFFER: - gl->raw_fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER_EXT, drawFB); - gl->raw_fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER_EXT, readFB); - break; - - case LOCAL_GL_DRAW_FRAMEBUFFER_EXT: - if (!gl->HasExt_FramebufferBlit()) - NS_WARNING("DRAW_FRAMEBUFFER requested but unavailable."); - - gl->raw_fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER_EXT, drawFB); - break; - - case LOCAL_GL_READ_FRAMEBUFFER_EXT: - if (!gl->HasExt_FramebufferBlit()) - NS_WARNING("READ_FRAMEBUFFER requested but unavailable."); - - gl->raw_fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER_EXT, readFB); - break; - - default: - // In case we got a bad target. - MOZ_NOT_REACHED("Bad `target` for BindFramebuffer."); - gl->raw_fBindFramebuffer(target, 0); - break; - } -} - -void -GLScreenBuffer::BindFB(GLuint fb) -{ - GLuint drawFB = DrawFB(); - GLuint readFB = ReadFB(); - - mUserDrawFB = fb; - mUserReadFB = fb; - mInternalDrawFB = (fb == 0) ? drawFB : fb; - mInternalReadFB = (fb == 0) ? readFB : fb; - - if (mInternalDrawFB == mInternalReadFB) { - mGL->raw_fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, mInternalDrawFB); - } else { - MOZ_ASSERT(mGL->SupportsSplitFramebuffer()); - mGL->raw_fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER_EXT, mInternalDrawFB); - mGL->raw_fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER_EXT, mInternalReadFB); - } - -#ifdef DEBUG - mInInternalMode_DrawFB = false; - mInInternalMode_ReadFB = false; -#endif -} - -void -GLScreenBuffer::BindDrawFB(GLuint fb) -{ - if (!mGL->SupportsSplitFramebuffer()) { - NS_WARNING("DRAW_FRAMEBUFFER requested, but unsupported."); - - mGL->raw_fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER_EXT, fb); - } else { - GLuint drawFB = DrawFB(); - mUserDrawFB = fb; - mInternalDrawFB = (fb == 0) ? drawFB : fb; - - mGL->raw_fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER_EXT, mInternalDrawFB); - } - -#ifdef DEBUG - mInInternalMode_DrawFB = false; -#endif -} - -void -GLScreenBuffer::BindReadFB(GLuint fb) -{ - if (!mGL->SupportsSplitFramebuffer()) { - NS_WARNING("READ_FRAMEBUFFER requested, but unsupported."); - - mGL->raw_fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER_EXT, fb); - } else { - GLuint readFB = ReadFB(); - mUserReadFB = fb; - mInternalReadFB = (fb == 0) ? readFB : fb; - - mGL->raw_fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER_EXT, mInternalReadFB); - } - -#ifdef DEBUG - mInInternalMode_ReadFB = false; -#endif -} - -void -GLScreenBuffer::BindDrawFB_Internal(GLuint fb) -{ - mInternalDrawFB = mUserDrawFB = fb; - mGL->raw_fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER_EXT, mInternalDrawFB); - -#ifdef DEBUG - mInInternalMode_DrawFB = true; -#endif -} - -void -GLScreenBuffer::BindReadFB_Internal(GLuint fb) -{ - mInternalReadFB = mUserReadFB = fb; - mGL->raw_fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER_EXT, mInternalReadFB); - -#ifdef DEBUG - mInInternalMode_ReadFB = true; -#endif -} - - -GLuint -GLScreenBuffer::GetDrawFB() const -{ -#ifdef DEBUG - MOZ_ASSERT(mGL->IsCurrent()); - MOZ_ASSERT(!mInInternalMode_DrawFB); - - // Don't need a branch here, because: - // LOCAL_GL_DRAW_FRAMEBUFFER_BINDING_EXT == LOCAL_GL_FRAMEBUFFER_BINDING == 0x8CA6 - // We use raw_ here because this is debug code and we need to see what - // the driver thinks. - GLuint actual = 0; - mGL->raw_fGetIntegerv(LOCAL_GL_DRAW_FRAMEBUFFER_BINDING_EXT, (GLint*)&actual); - - GLuint predicted = mInternalDrawFB; - if (predicted != actual) { - printf_stderr("Misprediction: Bound draw FB predicted: %d. Was: %d.\n", - predicted, actual); - MOZ_ASSERT(false, "Draw FB binding misprediction!"); - } -#endif - - return mUserDrawFB; -} - -GLuint -GLScreenBuffer::GetReadFB() const -{ -#ifdef DEBUG - MOZ_ASSERT(mGL->IsCurrent()); - MOZ_ASSERT(!mInInternalMode_ReadFB); - - // We use raw_ here because this is debug code and we need to see what - // the driver thinks. - GLuint actual = 0; - if (mGL->SupportsSplitFramebuffer()) - mGL->raw_fGetIntegerv(LOCAL_GL_READ_FRAMEBUFFER_BINDING_EXT, (GLint*)&actual); - else - mGL->raw_fGetIntegerv(LOCAL_GL_FRAMEBUFFER_BINDING, (GLint*)&actual); - - GLuint predicted = mInternalReadFB; - if (predicted != actual) { - printf_stderr("Misprediction: Bound read FB predicted: %d. Was: %d.\n", - predicted, actual); - MOZ_ASSERT(false, "Read FB binding misprediction!"); - } -#endif - - return mUserReadFB; -} - -GLuint -GLScreenBuffer::GetFB() const -{ - MOZ_ASSERT(GetDrawFB() == GetReadFB()); - return GetDrawFB(); -} - - -void -GLScreenBuffer::DeletingFB(GLuint fb) -{ - if (fb == mInternalDrawFB) { - mInternalDrawFB = 0; - mUserDrawFB = 0; - } - if (fb == mInternalReadFB) { - mInternalReadFB = 0; - mUserReadFB = 0; - } -} - - -void -GLScreenBuffer::AfterDrawCall() -{ - if (mUserDrawFB != 0) - return; - - RequireBlit(); -} - -void -GLScreenBuffer::BeforeReadCall() -{ - if (mUserReadFB != 0) - return; - - AssureBlitted(); -} - -void -GLScreenBuffer::RequireBlit() -{ - mNeedsBlit = true; -} - -void -GLScreenBuffer::AssureBlitted() -{ - if (!mNeedsBlit) - return; - - if (mDraw) { - GLuint drawFB = DrawFB(); - GLuint readFB = ReadFB(); - - MOZ_ASSERT(drawFB != 0); - MOZ_ASSERT(drawFB != readFB); - MOZ_ASSERT(mGL->IsExtensionSupported(GLContext::EXT_framebuffer_blit) || - mGL->IsExtensionSupported(GLContext::ANGLE_framebuffer_blit)); - MOZ_ASSERT(mDraw->Size() == mRead->Size()); - - ScopedBindFramebuffer boundFB(mGL); - ScopedGLState scissor(mGL, LOCAL_GL_SCISSOR_TEST, false); - - BindReadFB_Internal(drawFB); - BindDrawFB_Internal(readFB); - - const gfxIntSize& srcSize = mDraw->Size(); - const gfxIntSize& destSize = mRead->Size(); - - mGL->raw_fBlitFramebuffer(0, 0, srcSize.width, srcSize.height, - 0, 0, destSize.width, destSize.height, - LOCAL_GL_COLOR_BUFFER_BIT, - LOCAL_GL_NEAREST); - // Done! - } - - mNeedsBlit = false; -} - -void -GLScreenBuffer::Morph(SurfaceFactory_GL* newFactory, SurfaceStreamType streamType) -{ - MOZ_ASSERT(mStream); - - if (newFactory) { - delete mFactory; - mFactory = newFactory; - } - - if (mStream->mType == streamType) - return; - - SurfaceStream* newStream = SurfaceStream::CreateForType(streamType, mStream); - MOZ_ASSERT(newStream); - - delete mStream; - mStream = newStream; -} - -bool -GLScreenBuffer::Swap(const gfxIntSize& size) -{ - ScopedBindFramebuffer autoFB(mGL); - - SharedSurface* nextSurf = mStream->SwapProducer(mFactory, size); - if (!nextSurf) { - SurfaceFactory_GL* basicFactory = - new SurfaceFactory_Basic(mGL, mFactory->Caps()); - nextSurf = mStream->SwapProducer(basicFactory, size); - if (!nextSurf) { - delete basicFactory; - return false; - } - - // Swap out the apparently defective old factory. - delete mFactory; - mFactory = basicFactory; - } - - SharedSurface_GL* surf = SharedSurface_GL::Cast(nextSurf); - if (mRead && SharedSurf()) - SharedSurf()->UnlockProd(); - - surf->LockProd(); - - if (mRead && - surf->AttachType() == SharedSurf()->AttachType() && - size == Size()) - { - // Same size, same type, ready for reuse! - mRead->Attach(surf); - } else { - // Else something changed, so resize: - DrawBuffer* draw = CreateDraw(size); // Can be null. - ReadBuffer* read = CreateRead(surf); - MOZ_ASSERT(read); // Should never fail if SwapProd succeeded. - - delete mDraw; - delete mRead; - - mDraw = draw; - mRead = read; - } - - // Check that we're all set up. - MOZ_ASSERT(SharedSurf() == surf); - - if (!PreserveBuffer()) { - // DiscardFramebuffer here could help perf on some mobile platforms. - } - - return true; -} - -bool -GLScreenBuffer::PublishFrame(const gfxIntSize& size) -{ - AssureBlitted(); - - bool good = Swap(size); - return good; -} - - -DrawBuffer* -GLScreenBuffer::CreateDraw(const gfxIntSize& size) -{ - GLContext* gl = mFactory->GL(); - const GLFormats& formats = mFactory->Formats(); - const SurfaceCaps& caps = mFactory->DrawCaps(); - - return DrawBuffer::Create(gl, caps, formats, size); -} - -ReadBuffer* -GLScreenBuffer::CreateRead(SharedSurface_GL* surf) -{ - GLContext* gl = mFactory->GL(); - const GLFormats& formats = mFactory->Formats(); - const SurfaceCaps& caps = mFactory->ReadCaps(); - - return ReadBuffer::Create(gl, caps, formats, surf); -} - - -void -GLScreenBuffer::Readback(SharedSurface_GL* src, gfxImageSurface* dest) -{ - MOZ_ASSERT(src && dest); - MOZ_ASSERT(dest->GetSize() == src->Size()); - MOZ_ASSERT(dest->Format() == (src->HasAlpha() ? gfxImageSurface::ImageFormatARGB32 - : gfxImageSurface::ImageFormatRGB24)); - - mGL->MakeCurrent(); - - bool needsSwap = src != SharedSurf(); - if (needsSwap) { - SharedSurf()->UnlockProd(); - src->LockProd(); - } - - ReadBuffer* buffer = CreateRead(src); - MOZ_ASSERT(buffer); - - ScopedBindFramebuffer autoFB(mGL, buffer->FB()); - mGL->ReadPixelsIntoImageSurface(dest); - - delete buffer; - - if (needsSwap) { - src->UnlockProd(); - SharedSurf()->LockProd(); - } -} - - - -DrawBuffer* -DrawBuffer::Create(GLContext* const gl, - const SurfaceCaps& caps, - const GLFormats& formats, - const gfxIntSize& size) -{ - if (!caps.color) { - MOZ_ASSERT(!caps.alpha && !caps.depth && !caps.stencil); - - // Nothing is needed. - return nullptr; - } - - GLuint colorMSRB = 0; - GLuint depthRB = 0; - GLuint stencilRB = 0; - - GLuint* pColorMSRB = caps.antialias ? &colorMSRB : nullptr; - GLuint* pDepthRB = caps.depth ? &depthRB : nullptr; - GLuint* pStencilRB = caps.stencil ? &stencilRB : nullptr; - - if (!formats.color_rbFormat) - pColorMSRB = nullptr; - - if (pDepthRB && pStencilRB) { - if (!formats.depth && !formats.depthStencil) - pDepthRB = nullptr; - - if (!formats.stencil && !formats.depthStencil) - pStencilRB = nullptr; - } else { - if (!formats.depth) - pDepthRB = nullptr; - - if (!formats.stencil) - pStencilRB = nullptr; - } - - gl->CreateRenderbuffersForOffscreen(formats, size, caps.antialias, - pColorMSRB, pDepthRB, pStencilRB); - - GLuint fb = 0; - gl->fGenFramebuffers(1, &fb); - gl->AttachBuffersToFB(0, colorMSRB, depthRB, stencilRB, fb); - MOZ_ASSERT(gl->IsFramebufferComplete(fb)); - - return new DrawBuffer(gl, size, fb, colorMSRB, depthRB, stencilRB); -} - -DrawBuffer::~DrawBuffer() -{ - mGL->MakeCurrent(); - - GLuint fb = mFB; - GLuint rbs[] = { - mColorMSRB, - mDepthRB, - mStencilRB - }; - - mGL->fDeleteFramebuffers(1, &fb); - mGL->fDeleteRenderbuffers(3, rbs); -} - - - - - - -ReadBuffer* -ReadBuffer::Create(GLContext* gl, - const SurfaceCaps& caps, - const GLFormats& formats, - SharedSurface_GL* surf) -{ - MOZ_ASSERT(surf); - - if (surf->AttachType() == AttachmentType::Screen) { - // Don't need anything. Our read buffer will be the 'screen'. - - return new ReadBuffer(gl, - 0, 0, 0, - surf); - } - - GLuint depthRB = 0; - GLuint stencilRB = 0; - - GLuint* pDepthRB = caps.depth ? &depthRB : nullptr; - GLuint* pStencilRB = caps.stencil ? &stencilRB : nullptr; - - gl->CreateRenderbuffersForOffscreen(formats, surf->Size(), caps.antialias, - nullptr, pDepthRB, pStencilRB); - - GLuint colorTex = 0; - GLuint colorRB = 0; - - switch (surf->AttachType()) { - case AttachmentType::GLTexture: - colorTex = surf->Texture(); - break; - case AttachmentType::GLRenderbuffer: - colorRB = surf->Renderbuffer(); - break; - default: - MOZ_NOT_REACHED("Unknown attachment type?"); - return nullptr; - } - MOZ_ASSERT(colorTex || colorRB); - - GLuint fb = 0; - gl->fGenFramebuffers(1, &fb); - gl->AttachBuffersToFB(colorTex, colorRB, depthRB, stencilRB, fb); - - MOZ_ASSERT(gl->IsFramebufferComplete(fb)); - - return new ReadBuffer(gl, - fb, depthRB, stencilRB, - surf); -} - -ReadBuffer::~ReadBuffer() -{ - mGL->MakeCurrent(); - - GLuint fb = mFB; - GLuint rbs[] = { - mDepthRB, - mStencilRB - }; - - mGL->fDeleteFramebuffers(1, &fb); - mGL->fDeleteRenderbuffers(2, rbs); -} - -void -ReadBuffer::Attach(SharedSurface_GL* surf) -{ - MOZ_ASSERT(surf && mSurf); - MOZ_ASSERT(surf->AttachType() == mSurf->AttachType()); - MOZ_ASSERT(surf->Size() == mSurf->Size()); - - // Nothing else is needed for AttachType Screen. - if (surf->AttachType() != AttachmentType::Screen) { - GLuint colorTex = 0; - GLuint colorRB = 0; - - switch (surf->AttachType()) { - case AttachmentType::GLTexture: - colorTex = surf->Texture(); - break; - case AttachmentType::GLRenderbuffer: - colorRB = surf->Renderbuffer(); - break; - default: - MOZ_NOT_REACHED("Unknown attachment type?"); - return; - } - - mGL->AttachBuffersToFB(colorTex, colorRB, 0, 0, mFB); - MOZ_ASSERT(mGL->IsFramebufferComplete(mFB)); - } - - mSurf = surf; -} - -const gfxIntSize& -ReadBuffer::Size() const -{ - return mSurf->Size(); -} - -} /* namespace gl */ -} /* namespace mozilla */
deleted file mode 100644 --- a/gfx/gl/GLScreenBuffer.h +++ /dev/null @@ -1,296 +0,0 @@ -/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40; -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/* GLScreenBuffer is the abstraction for the "default framebuffer" used - * by an offscreen GLContext. Since it's only for offscreen GLContext's, - * it's only useful for things like WebGL, and is NOT used by the - * compositor's GLContext. Remember that GLContext provides an abstraction - * so that even if you want to draw to the 'screen', even if that's not - * actually the screen, just draw to 0. This GLScreenBuffer class takes the - * logic handling out of GLContext. -*/ - -#ifndef SCREEN_BUFFER_H_ -#define SCREEN_BUFFER_H_ - -#include "SurfaceTypes.h" -#include "GLContextTypes.h" -#include "GLDefs.h" -#include "gfxPoint.h" - -// Forwards: -class gfxImageSurface; - -namespace mozilla { - namespace gfx { - class SurfaceStream; - class SharedSurface; - } - namespace gl { - class GLContext; - class SharedSurface_GL; - class SurfaceFactory_GL; - } -} - -namespace mozilla { -namespace gl { - -class DrawBuffer -{ -protected: - typedef struct gfx::SurfaceCaps SurfaceCaps; - -public: - // Infallible, may return null if unneeded. - static DrawBuffer* Create(GLContext* const gl, - const SurfaceCaps& caps, - const GLFormats& formats, - const gfxIntSize& size); - -protected: - GLContext* const mGL; - const gfxIntSize mSize; - const GLuint mFB; - const GLuint mColorMSRB; - const GLuint mDepthRB; - const GLuint mStencilRB; - - DrawBuffer(GLContext* gl, - const gfxIntSize& size, - GLuint fb, - GLuint colorMSRB, - GLuint depthRB, - GLuint stencilRB) - : mGL(gl) - , mSize(size) - , mFB(fb) - , mColorMSRB(colorMSRB) - , mDepthRB(depthRB) - , mStencilRB(stencilRB) - {} - -public: - virtual ~DrawBuffer(); - - const gfxIntSize& Size() const { - return mSize; - } - - GLuint FB() const { - return mFB; - } -}; - -class ReadBuffer -{ -protected: - typedef struct gfx::SurfaceCaps SurfaceCaps; - -public: - // Infallible, always non-null. - static ReadBuffer* Create(GLContext* gl, - const SurfaceCaps& caps, - const GLFormats& formats, - SharedSurface_GL* surf); - -protected: - GLContext* const mGL; - - const GLuint mFB; - // mFB has the following attachments: - const GLuint mDepthRB; - const GLuint mStencilRB; - // note no mColorRB here: this is provided by mSurf. - SharedSurface_GL* mSurf; // Owned by GLScreenBuffer's SurfaceStream. - - ReadBuffer(GLContext* gl, - GLuint fb, - GLuint depthRB, - GLuint stencilRB, - SharedSurface_GL* surf) - : mGL(gl) - , mFB(fb) - , mDepthRB(depthRB) - , mStencilRB(stencilRB) - , mSurf(surf) - {} - -public: - virtual ~ReadBuffer(); - - // Cannot attach a surf of a different AttachType or Size than before. - void Attach(SharedSurface_GL* surf); - - const gfxIntSize& Size() const; - - GLuint FB() const { - return mFB; - } - - SharedSurface_GL* SharedSurf() const { - return mSurf; - } -}; - - -class GLScreenBuffer -{ -protected: - typedef class gfx::SurfaceStream SurfaceStream; - typedef class gfx::SharedSurface SharedSurface; - typedef gfx::SurfaceStreamType SurfaceStreamType; - typedef gfx::SharedSurfaceType SharedSurfaceType; - typedef struct gfx::SurfaceCaps SurfaceCaps; - -public: - // Infallible. - static GLScreenBuffer* Create(GLContext* gl, - const gfxIntSize& size, - const SurfaceCaps& caps); - -protected: - GLContext* const mGL; // Owns us. - SurfaceCaps mCaps; - SurfaceFactory_GL* mFactory; // Owned by us. - SurfaceStream* mStream; // Owned by us. - - DrawBuffer* mDraw; // Owned by us. - ReadBuffer* mRead; // Owned by us. - - bool mNeedsBlit; - - // Below are the parts that help us pretend to be framebuffer 0: - GLuint mUserDrawFB; - GLuint mUserReadFB; - GLuint mInternalDrawFB; - GLuint mInternalReadFB; - -#ifdef DEBUG - bool mInInternalMode_DrawFB; - bool mInInternalMode_ReadFB; -#endif - - GLScreenBuffer(GLContext* gl, - const SurfaceCaps& caps, - SurfaceFactory_GL* factory, - SurfaceStream* stream) - : mGL(gl) - , mCaps(caps) - , mFactory(factory) - , mStream(stream) - , mDraw(nullptr) - , mRead(nullptr) - , mNeedsBlit(true) - , mUserDrawFB(0) - , mUserReadFB(0) - , mInternalDrawFB(0) - , mInternalReadFB(0) -#ifdef DEBUG - , mInInternalMode_DrawFB(true) - , mInInternalMode_ReadFB(true) -#endif - {} - -public: - virtual ~GLScreenBuffer(); - - SurfaceStream* Stream() const { - return mStream; - } - - SurfaceFactory_GL* Factory() const { - return mFactory; - } - - SharedSurface_GL* SharedSurf() const { - MOZ_ASSERT(mRead); - return mRead->SharedSurf(); - } - - bool PreserveBuffer() const { - return mCaps.preserve; - } - - const SurfaceCaps& Caps() const { - return mCaps; - } - - GLuint DrawFB() const { - if (!mDraw) - return ReadFB(); - - return mDraw->FB(); - } - - GLuint ReadFB() const { - return mRead->FB(); - } - - void DeletingFB(GLuint fb); - - const gfxIntSize& Size() const { - MOZ_ASSERT(mRead); - MOZ_ASSERT(!mDraw || mDraw->Size() == mRead->Size()); - return mRead->Size(); - } - - void BindAsFramebuffer(GLContext* const gl, GLenum target) const; - - void RequireBlit(); - void AssureBlitted(); - void AfterDrawCall(); - void BeforeReadCall(); - - /* Morph swaps out our SurfaceStream mechanism and replaces it with - * one best suited to our platform and compositor configuration. - * - * Must be called on the producing thread. - * We haven't made any guarantee that rendering is actually - * done when Morph is run, just that it can't run concurrently - * with rendering. This means that we can't just drop the contents - * of the buffer, since we may only be partially done rendering. - * - * Once you pass newFactory into Morph, newFactory will be owned by - * GLScreenBuffer, so `forget` any references to it that still exist. - */ - void Morph(SurfaceFactory_GL* newFactory, SurfaceStreamType streamType); - -protected: - // Returns false on error or inability to resize. - bool Swap(const gfxIntSize& size); - -public: - bool PublishFrame(const gfxIntSize& size); - - void Readback(SharedSurface_GL* src, gfxImageSurface* dest); - -protected: - DrawBuffer* CreateDraw(const gfxIntSize& size); - ReadBuffer* CreateRead(SharedSurface_GL* surf); - -public: - /* `fb` in these functions is the framebuffer the GLContext is hoping to - * bind. When this is 0, we intercept the call and bind our own - * framebuffers. As a client of these functions, just bind 0 when you want - * to draw to the default framebuffer/'screen'. - */ - void BindFB(GLuint fb); - void BindDrawFB(GLuint fb); - void BindReadFB(GLuint fb); - GLuint GetFB() const; - GLuint GetDrawFB() const; - GLuint GetReadFB() const; - - // Here `fb` is the actual framebuffer you want bound. Binding 0 will - // bind the (generally useless) default framebuffer. - void BindDrawFB_Internal(GLuint fb); - void BindReadFB_Internal(GLuint fb); -}; - -} // namespace gl -} // namespace mozilla - -#endif // SCREEN_BUFFER_H_
--- a/gfx/gl/GLXLibrary.h +++ b/gfx/gl/GLXLibrary.h @@ -82,17 +82,17 @@ public: void xWaitX(); GLXContext xCreateContextAttribs(Display* display, GLXFBConfig config, GLXContext share_list, Bool direct, const int* attrib_list); - bool EnsureInitialized(LibraryType libType); + bool EnsureInitialized(bool aUseMesaLLVMPipe); GLXPixmap CreatePixmap(gfxASurface* aSurface); void DestroyPixmap(GLXPixmap aPixmap); void BindTexImage(GLXPixmap aPixmap); void ReleaseTexImage(GLXPixmap aPixmap); bool UseTextureFromPixmap() { return mUseTextureFromPixmap; } bool HasRobustness() { return mHasRobustness; }
--- a/gfx/gl/Makefile.in +++ b/gfx/gl/Makefile.in @@ -1,75 +1,60 @@ # This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. -DEPTH = @DEPTH@ -topsrcdir = @top_srcdir@ -srcdir = @srcdir@ -VPATH = @srcdir@ +DEPTH = @DEPTH@ +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ include $(DEPTH)/config/autoconf.mk -MODULE = gl -LIBRARY_NAME = gl -LIBXUL_LIBRARY = 1 -EXPORT_LIBRARY = 1 +MODULE = gl +LIBRARY_NAME = gl +LIBXUL_LIBRARY = 1 +EXPORT_LIBRARY = 1 FAIL_ON_WARNINGS = 1 EXPORTS = \ - ForceDiscreteGPUHelperCGL.h \ - GLContext.h \ - GLContextProvider.h \ - GLContextProviderImpl.h \ - GLContextSymbols.h \ - GLContextTypes.h \ - GLDefs.h \ - GLLibraryLoader.h \ - GLLibraryEGL.h \ - GLScreenBuffer.h \ - GLTextureImage.h \ - SharedSurface.h \ - SharedSurfaceEGL.h \ - SharedSurfaceGL.h \ - SurfaceFactory.h \ - SurfaceStream.h \ - SurfaceTypes.h \ - $(NULL) + GLDefs.h \ + GLContext.h \ + GLContextTypes.h \ + GLContextSymbols.h \ + GLContextProvider.h \ + GLContextProviderImpl.h \ + GLLibraryLoader.h \ + ForceDiscreteGPUHelperCGL.h \ + GLTextureImage.h \ + $(NULL) ifdef MOZ_X11 EXPORTS += \ - GLXLibrary.h \ - $(NULL) + GLXLibrary.h \ + $(NULL) endif ifeq ($(MOZ_WIDGET_TOOLKIT),windows) EXPORTS += \ - WGLLibrary.h \ - $(NULL) + WGLLibrary.h \ + $(NULL) ifdef MOZ_WEBGL DEFINES += -DMOZ_WEBGL DEFINES += -DMOZ_D3DCOMPILER_DLL=$(MOZ_D3DCOMPILER_DLL) endif endif CPPSRCS = \ - GLContext.cpp \ - GLContextTypes.cpp \ - GLContextUtils.cpp \ - GLLibraryLoader.cpp \ - GLScreenBuffer.cpp \ - GLTextureImage.cpp \ - SharedSurface.cpp \ - SharedSurfaceEGL.cpp \ - SharedSurfaceGL.cpp \ - SurfaceFactory.cpp \ - SurfaceStream.cpp \ - $(NULL) + GLContext.cpp \ + GLContextUtils.cpp \ + GLLibraryLoader.cpp \ + GLTextureImage.cpp \ + $(NULL) GL_PROVIDER = Null ifeq ($(MOZ_WIDGET_TOOLKIT),windows) GL_PROVIDER = WGL endif ifeq ($(MOZ_WIDGET_TOOLKIT),cocoa) @@ -117,29 +102,23 @@ CPPSRCS += GLContextProvider$(GL_PROVIDE endif ifeq ($(GL_PROVIDER),EGL) CPPSRCS += GLLibraryEGL.cpp endif # Win32 is a special snowflake, for ANGLE ifeq ($(MOZ_WIDGET_TOOLKIT),windows) -EXPORTS += \ - SharedSurfaceANGLE.h \ - $(NULL) - CPPSRCS += \ - GLContextProviderEGL.cpp \ - GLLibraryEGL.cpp \ - SharedSurfaceANGLE.cpp \ - $(NULL) + GLContextProviderEGL.cpp \ + GLLibraryEGL.cpp endif ifdef MOZ_ANDROID_OMTC DEFINES += -DMOZ_ANDROID_OMTC endif include $(topsrcdir)/config/rules.mk DEFINES := $(filter-out -DUNICODE,$(DEFINES)) CXXFLAGS += $(MOZ_CAIRO_CFLAGS) $(MOZ_PIXMAN_CFLAGS) $(TK_CFLAGS) -CFLAGS += $(MOZ_CAIRO_CFLAGS) $(MOZ_PIXMAN_CFLAGS) $(TK_CFLAGS) +CFLAGS += $(MOZ_CAIRO_CFLAGS) $(MOZ_PIXMAN_CFLAGS) $(TK_CFLAGS)
deleted file mode 100644 --- a/gfx/gl/SharedSurface.cpp +++ /dev/null @@ -1,29 +0,0 @@ -/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40; -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "SharedSurface.h" -#include "SharedSurfaceGL.h" - -using namespace mozilla::gl; - -namespace mozilla { -namespace gfx { - -// |src| must begin and end locked, though it -// can be temporarily unlocked if needed. -void -SharedSurface::Copy(SharedSurface* src, SharedSurface* dest, SurfaceFactory* factory) -{ - MOZ_ASSERT( src->APIType() == APITypeT::OpenGL); - MOZ_ASSERT(dest->APIType() == APITypeT::OpenGL); - - SharedSurface_GL* srcGL = (SharedSurface_GL*)src; - SharedSurface_GL* destGL = (SharedSurface_GL*)dest; - - SharedSurface_GL::Copy(srcGL, destGL, (SurfaceFactory_GL*)factory); -} - -} /* namespace gfx */ -} /* namespace mozilla */
deleted file mode 100644 --- a/gfx/gl/SharedSurface.h +++ /dev/null @@ -1,122 +0,0 @@ -/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40; -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/* SharedSurface abstracts an actual surface (can be a GL texture, but - * not necessarily) that handles sharing. - * Its specializations are: - * SharedSurface_Basic (client-side bitmap, does readback) - * SharedSurface_GLTexture - * SharedSurface_EGLImage - * SharedSurface_ANGLEShareHandle - */ - -#ifndef SHARED_SURFACE_H_ -#define SHARED_SURFACE_H_ - -#include "mozilla/StandardInteger.h" -#include "mozilla/Attributes.h" -#include "GLDefs.h" -#include "gfxPoint.h" -#include "SurfaceTypes.h" - -namespace mozilla { -namespace gfx { - -class SurfaceFactory; - -class SharedSurface -{ -protected: - const SharedSurfaceType mType; - const APITypeT mAPI; - const AttachmentType mAttachType; - const gfxIntSize mSize; - const bool mHasAlpha; - bool mIsLocked; - - SharedSurface(SharedSurfaceType type, - APITypeT api, - AttachmentType attachType, - const gfxIntSize& size, - bool hasAlpha) - : mType(type) - , mAPI(api) - , mAttachType(attachType) - , mSize(size) - , mHasAlpha(hasAlpha) - , mIsLocked(false) - { - } - -public: - virtual ~SharedSurface() { - } - - static void Copy(SharedSurface* src, SharedSurface* dest, - SurfaceFactory* factory); - - // This locks the SharedSurface as the production buffer for the context. - // This is needed by backends which use PBuffers and/or EGLSurfaces. - virtual void LockProd() { - MOZ_ASSERT(!mIsLocked); - LockProdImpl(); - mIsLocked = true; - } - - // Unlocking is harmless if we're already unlocked. - virtual void UnlockProd() { - if (!mIsLocked) - return; - - UnlockProdImpl(); - mIsLocked = false; - } - - virtual void LockProdImpl() = 0; - virtual void UnlockProdImpl() = 0; - - virtual void Fence() = 0; - virtual bool WaitSync() = 0; - - - SharedSurfaceType Type() const { - return mType; - } - - APITypeT APIType() const { - return mAPI; - } - - AttachmentType AttachType() const { - return mAttachType; - } - - const gfxIntSize& Size() const { - return mSize; - } - - bool HasAlpha() const { - return mHasAlpha; - } - - - // For use when AttachType is correct. - virtual GLuint Texture() const { - MOZ_ASSERT(AttachType() == AttachmentType::GLTexture); - MOZ_NOT_REACHED("Did you forget to override this function?"); - return 0; - } - - virtual GLuint Renderbuffer() const { - MOZ_ASSERT(AttachType() == AttachmentType::GLRenderbuffer); - MOZ_NOT_REACHED("Did you forget to override this function?"); - return 0; - } -}; - -} /* namespace gfx */ -} /* namespace mozilla */ - -#endif /* SHARED_SURFACE_H_ */
deleted file mode 100644 --- a/gfx/gl/SharedSurfaceANGLE.cpp +++ /dev/null @@ -1,275 +0,0 @@ -/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40; -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "SharedSurfaceANGLE.h" - -#include "GLContext.h" - -using namespace mozilla::gfx; - -namespace mozilla { -namespace gl { - -SurfaceFactory_ANGLEShareHandle* -SurfaceFactory_ANGLEShareHandle::Create(GLContext* gl, - ID3D10Device1* d3d, - const SurfaceCaps& caps) -{ - GLLibraryEGL* egl = gl->GetLibraryEGL(); - if (!egl) - return nullptr; - - if (!egl->IsExtensionSupported( - GLLibraryEGL::ANGLE_surface_d3d_texture_2d_share_handle)) - { - return nullptr; - } - - return new SurfaceFactory_ANGLEShareHandle(gl, egl, d3d, caps); -} - -EGLDisplay -SharedSurface_ANGLEShareHandle::Display() -{ - return mEGL->Display(); -} - - -SharedSurface_ANGLEShareHandle::~SharedSurface_ANGLEShareHandle() -{ - mEGL->fDestroySurface(Display(), mPBuffer); -} - -void -SharedSurface_ANGLEShareHandle::LockProdImpl() -{ - mGL->MakeCurrent_EGLSurface(mPBuffer); -} - -void -SharedSurface_ANGLEShareHandle::UnlockProdImpl() -{ -} - - -void -SharedSurface_ANGLEShareHandle::Fence() -{ - mGL->fFinish(); -} - -bool -SharedSurface_ANGLEShareHandle::WaitSync() -{ - // Since we glFinish in Fence(), we're always going to be resolved here. - return true; -} - -static void -FillPBufferAttribs_ByBits(nsTArray<EGLint>& aAttrs, - int redBits, int greenBits, - int blueBits, int alphaBits, - int depthBits, int stencilBits) -{ - aAttrs.Clear(); - -#if defined(A1) || defined(A2) -#error The temp-macro names we want are already defined. -#endif - -#define A1(_x) do { aAttrs.AppendElement(_x); } while (0) -#define A2(_x,_y) do { A1(_x); A1(_y); } while (0) - - A2(LOCAL_EGL_RENDERABLE_TYPE, LOCAL_EGL_OPENGL_ES2_BIT); - A2(LOCAL_EGL_SURFACE_TYPE, LOCAL_EGL_PBUFFER_BIT); - - A2(LOCAL_EGL_RED_SIZE, redBits); - A2(LOCAL_EGL_GREEN_SIZE, greenBits); - A2(LOCAL_EGL_BLUE_SIZE, blueBits); - A2(LOCAL_EGL_ALPHA_SIZE, alphaBits); - - A2(LOCAL_EGL_DEPTH_SIZE, depthBits); - A2(LOCAL_EGL_STENCIL_SIZE, stencilBits); - - A1(LOCAL_EGL_NONE); -#undef A1 -#undef A2 -} - -static void -FillPBufferAttribs_BySizes(nsTArray<EGLint>& attribs, - bool bpp16, bool hasAlpha, - int depthBits, int stencilBits) -{ - int red = 0; - int green = 0; - int blue = 0; - int alpha = 0; - - if (bpp16) { - if (hasAlpha) { - red = green = blue = alpha = 4; - } else { - red = 5; - green = 6; - blue = 5; - } - } else { - red = green = blue = 8; - if (hasAlpha) - alpha = 8; - } - - FillPBufferAttribs_ByBits(attribs, - red, green, blue, alpha, - depthBits, stencilBits); -} - -static EGLConfig -ChooseConfig(GLContext* gl, - GLLibraryEGL* egl, - const SurfaceCaps& caps) -{ - MOZ_ASSERT(egl); - MOZ_ASSERT(caps.color); - - // We might want 24-bit depth, but we're only (fairly) sure to get 16-bit. - int depthBits = caps.depth ? 16 : 0; - int stencilBits = caps.stencil ? 8 : 0; - - // Ok, now we have everything. - nsTArray<EGLint> attribs(32); - FillPBufferAttribs_BySizes(attribs, - caps.bpp16, caps.alpha, - depthBits, stencilBits); - - // Time to try to get this config: - EGLConfig configs[64]; - int numConfigs = sizeof(configs)/sizeof(EGLConfig); - int foundConfigs = 0; - - if (!egl->fChooseConfig(egl->Display(), - attribs.Elements(), - configs, numConfigs, - &foundConfigs) || - !foundConfigs) - { - NS_WARNING("No configs found for the requested formats."); - return EGL_NO_CONFIG; - } - - // TODO: Pick a config progamatically instead of hoping that - // the first config will be minimally matching our request. - EGLConfig config = configs[0]; - - if (gl->DebugMode()) { - egl->DumpEGLConfig(config); - } - - return config; -} - - -// Returns EGL_NO_SURFACE on error. -static EGLSurface CreatePBufferSurface(GLLibraryEGL* egl, - EGLDisplay display, - EGLConfig config, - const gfxIntSize& size) -{ - EGLint attribs[] = { - LOCAL_EGL_WIDTH, size.width, - LOCAL_EGL_HEIGHT, size.height, - LOCAL_EGL_NONE - }; - - EGLSurface surface = egl->fCreatePbufferSurface(display, config, attribs); - - return surface; -} - -SharedSurface_ANGLEShareHandle* -SharedSurface_ANGLEShareHandle::Create(GLContext* gl, ID3D10Device1* d3d, - EGLContext context, EGLConfig config, - const gfxIntSize& size, bool hasAlpha) -{ - GLLibraryEGL* egl = gl->GetLibraryEGL(); - MOZ_ASSERT(egl); - MOZ_ASSERT(egl->IsExtensionSupported( - GLLibraryEGL::ANGLE_surface_d3d_texture_2d_share_handle)); - - if (!context || !config) - return nullptr; - - EGLDisplay display = egl->Display(); - EGLSurface pbuffer = CreatePBufferSurface(egl, display, config, size); - if (!pbuffer) - return nullptr; - - - // Declare everything before 'goto's. - HANDLE shareHandle = nullptr; - nsRefPtr<ID3D10Texture2D> texture; - nsRefPtr<ID3D10ShaderResourceView> srv; - - // On failure, goto CleanUpIfFailed. - // If |failed|, CleanUpIfFailed will clean up and return null. - bool failed = true; - - // Off to the races! - if (!egl->fQuerySurfacePointerANGLE( - display, - pbuffer, - LOCAL_EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE, - &shareHandle)) - { - NS_ERROR("Failed to grab ShareHandle for PBuffer!"); - goto CleanUpIfFailed; - } - - // Ok, we have a valid PBuffer with ShareHandle. - // Let's attach it to D3D. - HRESULT hr = d3d->OpenSharedResource(shareHandle, - __uuidof(ID3D10Texture2D), - getter_AddRefs(texture)); - if (FAILED(hr)) - goto CleanUpIfFailed; - - hr = d3d->CreateShaderResourceView(texture, nullptr, getter_AddRefs(srv)); - if (FAILED(hr)) - goto CleanUpIfFailed; - - failed = false; - -CleanUpIfFailed: - if (failed) { - NS_WARNING("CleanUpIfFailed"); - egl->fDestroySurface(egl->Display(), pbuffer); - MOZ_CRASH(); - return nullptr; - } - - return new SharedSurface_ANGLEShareHandle(gl, egl, - size, hasAlpha, - context, pbuffer, - texture, srv); -} - - -SurfaceFactory_ANGLEShareHandle::SurfaceFactory_ANGLEShareHandle(GLContext* gl, - GLLibraryEGL* egl, - ID3D10Device1* d3d, - const SurfaceCaps& caps) - : SurfaceFactory_GL(gl, SharedSurfaceType::EGLSurfaceANGLE, caps) - , mProdGL(gl) - , mEGL(egl) - , mConsD3D(d3d) -{ - mConfig = ChooseConfig(mProdGL, mEGL, mReadCaps); - mContext = mProdGL->GetEGLContext(); - MOZ_ASSERT(mConfig && mContext); -} - -} /* namespace gl */ -} /* namespace mozilla */
deleted file mode 100644 --- a/gfx/gl/SharedSurfaceANGLE.h +++ /dev/null @@ -1,115 +0,0 @@ -/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40; -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef SHARED_SURFACE_ANGLE_H_ -#define SHARED_SURFACE_ANGLE_H_ - -#include "SharedSurfaceGL.h" -#include "SurfaceFactory.h" -#include "GLLibraryEGL.h" -#include "SurfaceTypes.h" - -#include <windows.h> -#include <d3d10_1.h> - -namespace mozilla { -namespace gl { - -class GLContext; - -class SharedSurface_ANGLEShareHandle - : public SharedSurface_GL -{ -public: - static SharedSurface_ANGLEShareHandle* Create(GLContext* gl, ID3D10Device1* d3d, - EGLContext context, EGLConfig config, - const gfxIntSize& size, - bool hasAlpha); - - static SharedSurface_ANGLEShareHandle* Cast(SharedSurface* surf) { - MOZ_ASSERT(surf->Type() == SharedSurfaceType::EGLSurfaceANGLE); - - return (SharedSurface_ANGLEShareHandle*)surf; - } - -protected: - GLLibraryEGL* const mEGL; - const EGLContext mContext; - const EGLSurface mPBuffer; - nsRefPtr<ID3D10Texture2D> mTexture; - nsRefPtr<ID3D10ShaderResourceView> mSRV; - - SharedSurface_ANGLEShareHandle(GLContext* gl, - GLLibraryEGL* egl, - const gfxIntSize& size, - bool hasAlpha, - EGLContext context, - EGLSurface pbuffer, - ID3D10Texture2D* texture, - ID3D10ShaderResourceView* srv) - : SharedSurface_GL(SharedSurfaceType::EGLSurfaceANGLE, - AttachmentType::Screen, - gl, - size, - hasAlpha) - , mEGL(egl) - , mContext(context) - , mPBuffer(pbuffer) - , mTexture(texture) - , mSRV(srv) - {} - - EGLDisplay Display(); - -public: - virtual ~SharedSurface_ANGLEShareHandle(); - - virtual void LockProdImpl(); - virtual void UnlockProdImpl(); - - virtual void Fence(); - virtual bool WaitSync(); - - // Implementation-specific functions below: - ID3D10ShaderResourceView* GetSRV() { - return mSRV; - } -}; - - - -class SurfaceFactory_ANGLEShareHandle - : public SurfaceFactory_GL -{ -protected: - GLContext* const mProdGL; - GLLibraryEGL* const mEGL; - nsRefPtr<ID3D10Device1> mConsD3D; - EGLContext mContext; - EGLConfig mConfig; - -public: - static SurfaceFactory_ANGLEShareHandle* Create(GLContext* gl, - ID3D10Device1* d3d, - const SurfaceCaps& caps); - -protected: - SurfaceFactory_ANGLEShareHandle(GLContext* gl, - GLLibraryEGL* egl, - ID3D10Device1* d3d, - const SurfaceCaps& caps); - - virtual SharedSurface* CreateShared(const gfxIntSize& size) { - bool hasAlpha = mReadCaps.alpha; - return SharedSurface_ANGLEShareHandle::Create(mProdGL, mConsD3D, - mContext, mConfig, - size, hasAlpha); - } -}; - -} /* namespace gfx */ -} /* namespace mozilla */ - -#endif /* SHARED_SURFACE_ANGLE_H_ */
deleted file mode 100644 --- a/gfx/gl/SharedSurfaceEGL.cpp +++ /dev/null @@ -1,262 +0,0 @@ -/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40; -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "SharedSurfaceEGL.h" - -#include "GLContext.h" -#include "SharedSurfaceGL.h" -#include "SurfaceFactory.h" -#include "GLLibraryEGL.h" - -using namespace mozilla::gfx; - -namespace mozilla { -namespace gl { - -SharedSurface_EGLImage* -SharedSurface_EGLImage::Create(GLContext* prodGL, - const GLFormats& formats, - const gfxIntSize& size, - bool hasAlpha, - EGLContext context) -{ - GLLibraryEGL* egl = prodGL->GetLibraryEGL(); - MOZ_ASSERT(egl); - - if (!HasExtensions(egl, prodGL)) - return nullptr; - - MOZ_ALWAYS_TRUE(prodGL->MakeCurrent()); - GLuint prodTex = prodGL->CreateTextureForOffscreen(formats, size); - if (!prodTex) - return nullptr; - - return new SharedSurface_EGLImage(prodGL, egl, - size, hasAlpha, - formats, prodTex); -} - - -bool -SharedSurface_EGLImage::HasExtensions(GLLibraryEGL* egl, GLContext* gl) -{ - return egl->HasKHRImageBase() && - egl->IsExtensionSupported(GLLibraryEGL::KHR_gl_texture_2D_image) && - gl->IsExtensionSupported(GLContext::OES_EGL_image); -} - -SharedSurface_EGLImage::~SharedSurface_EGLImage() -{ - mEGL->fDestroyImage(Display(), mImage); - mImage = 0; - - mGL->MakeCurrent(); - mGL->fDeleteTextures(1, &mProdTex); - mProdTex = 0; - - if (mProdTexForPipe) { - mGL->fDeleteTextures(1, &mProdTexForPipe); - mProdTexForPipe = 0; - } - - if (mConsTex) { - MOZ_ASSERT(mGarbageBin); - mGarbageBin->Trash(mConsTex); - mConsTex = 0; - } - - if (mSync) { - // We can't call this unless we have the ext, but we will always have - // the ext if we have something to destroy. - mEGL->fDestroySync(Display(), mSync); - mSync = 0; - } -} - -void -SharedSurface_EGLImage::LockProdImpl() -{ - MutexAutoLock lock(mMutex); - - if (!mPipeComplete) - return; - - if (mPipeActive) - return; - - mGL->BlitTextureToTexture(mProdTex, mProdTexForPipe, Size(), Size()); - mGL->fDeleteTextures(1, &mProdTex); - mProdTex = mProdTexForPipe; - mProdTexForPipe = 0; - mPipeActive = true; -} - -static bool -CreateTexturePipe(GLLibraryEGL* const egl, GLContext* const gl, - const GLFormats& formats, const gfxIntSize& size, - GLuint* const out_tex, EGLImage* const out_image) -{ - MOZ_ASSERT(out_tex && out_image); - *out_tex = 0; - *out_image = 0; - - GLuint tex = gl->CreateTextureForOffscreen(formats, size); - if (!tex) - return false; - - EGLContext context = gl->GetEGLContext(); - MOZ_ASSERT(context); - EGLClientBuffer buffer = reinterpret_cast<EGLClientBuffer>(tex); - EGLImage image = egl->fCreateImage(egl->Display(), context, - LOCAL_EGL_GL_TEXTURE_2D, buffer, - nullptr); - if (!image) { - gl->fDeleteTextures(1, &tex); - return false; - } - - // Success. - *out_tex = tex; - *out_image = image; - return true; -} - -void -SharedSurface_EGLImage::Fence() -{ - MutexAutoLock lock(mMutex); - mGL->MakeCurrent(); - - if (!mPipeActive) { - MOZ_ASSERT(!mSync); - MOZ_ASSERT(!mPipeComplete); - - if (!mPipeFailed) { - if (!CreateTexturePipe(mEGL, mGL, mFormats, Size(), - &mProdTexForPipe, &mImage)) - { - mPipeFailed = true; - } - } - - if (!mPixels) { - gfxASurface::gfxImageFormat format = - HasAlpha() ? gfxASurface::ImageFormatARGB32 - : gfxASurface::ImageFormatRGB24; - mPixels = new gfxImageSurface(Size(), format); - } - - mPixels->Flush(); - mGL->ReadScreenIntoImageSurface(mPixels); - mPixels->MarkDirty(); - return; - } - MOZ_ASSERT(mPipeActive); - MOZ_ASSERT(mCurConsGL); - - if (mEGL->IsExtensionSupported(GLLibraryEGL::KHR_fence_sync) && - mGL->IsExtensionSupported(GLContext::OES_EGL_sync)) - { - if (mSync) { - MOZ_ALWAYS_TRUE( mEGL->fDestroySync(Display(), mSync) ); - mSync = 0; - } - - mSync = mEGL->fCreateSync(Display(), - LOCAL_EGL_SYNC_FENCE, - nullptr); - if (mSync) { - mGL->fFlush(); - return; - } - } - - MOZ_ASSERT(!mSync); - mGL->fFinish(); -} - -bool -SharedSurface_EGLImage::WaitSync() -{ - MutexAutoLock lock(mMutex); - if (!mSync) { - // We must not be needed. - return true; - } - MOZ_ASSERT(mEGL->IsExtensionSupported(GLLibraryEGL::KHR_fence_sync)); - - EGLTime waitMS = 500; - const EGLTime nsPerMS = 1000 * 1000; - EGLTime waitNS = waitMS * nsPerMS; - EGLint status = mEGL->fClientWaitSync(Display(), - mSync, - 0, - waitNS); - - if (status != LOCAL_EGL_CONDITION_SATISFIED) { - return false; - } - - MOZ_ALWAYS_TRUE( mEGL->fDestroySync(Display(), mSync) ); - mSync = 0; - - return true; -} - - -EGLDisplay -SharedSurface_EGLImage::Display() const -{ - return mEGL->Display(); -} - -GLuint -SharedSurface_EGLImage::AcquireConsumerTexture(GLContext* consGL) -{ - MutexAutoLock lock(mMutex); - MOZ_ASSERT(!mCurConsGL || consGL == mCurConsGL); - if (mPipeFailed) - return 0; - - if (mPipeActive) { - MOZ_ASSERT(mConsTex); - - return mConsTex; - } - - if (!mConsTex) { - consGL->fGenTextures(1, &mConsTex); - ScopedBindTexture autoTex(consGL, mConsTex); - consGL->fEGLImageTargetTexture2D(LOCAL_GL_TEXTURE_2D, mImage); - - mPipeComplete = true; - mCurConsGL = consGL; - mGarbageBin = consGL->TexGarbageBin(); - } - - MOZ_ASSERT(consGL == mCurConsGL); - return 0; -} - -gfxImageSurface* -SharedSurface_EGLImage::GetPixels() const -{ - MutexAutoLock lock(mMutex); - return mPixels; -} - - - -SurfaceFactory_EGLImage* -SurfaceFactory_EGLImage::Create(GLContext* prodGL, - const SurfaceCaps& caps) -{ - EGLContext context = prodGL->GetEGLContext(); - - return new SurfaceFactory_EGLImage(prodGL, context, caps); -} - -} /* namespace gfx */ -} /* namespace mozilla */
deleted file mode 100644 --- a/gfx/gl/SharedSurfaceEGL.h +++ /dev/null @@ -1,135 +0,0 @@ -/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40; -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef SHARED_SURFACE_EGL_H_ -#define SHARED_SURFACE_EGL_H_ - -#include "SharedSurfaceGL.h" -#include "SurfaceFactory.h" -#include "GLLibraryEGL.h" -#include "SurfaceTypes.h" -#include "mozilla/Attributes.h" -#include "mozilla/Mutex.h" - -namespace mozilla { -namespace gl { - -class GLContext; - -class SharedSurface_EGLImage - : public SharedSurface_GL -{ -public: - static SharedSurface_EGLImage* Create(GLContext* prodGL, - const GLFormats& formats, - const gfxIntSize& size, - bool hasAlpha, - EGLContext context); - - static SharedSurface_EGLImage* Cast(SharedSurface* surf) { - MOZ_ASSERT(surf->Type() == SharedSurfaceType::EGLImageShare); - - return (SharedSurface_EGLImage*)surf; - } - -protected: - mutable Mutex mMutex; - GLLibraryEGL* const mEGL; - const GLFormats mFormats; - GLuint mProdTex; - nsRefPtr<gfxImageSurface> mPixels; - GLuint mProdTexForPipe; // Moves to mProdTex when mPipeActive becomes true. - EGLImage mImage; - GLContext* mCurConsGL; - GLuint mConsTex; - nsRefPtr<TextureGarbageBin> mGarbageBin; - EGLSync mSync; - bool mPipeFailed; // Pipe creation failed, and has been abandoned. - bool mPipeComplete; // Pipe connects (mPipeActive ? mProdTex : mProdTexForPipe) to mConsTex. - bool mPipeActive; // Pipe is complete and in use for production. - - SharedSurface_EGLImage(GLContext* gl, - GLLibraryEGL* egl, - const gfxIntSize& size, - bool hasAlpha, - const GLFormats& formats, - GLuint prodTex) - : SharedSurface_GL(SharedSurfaceType::EGLImageShare, - AttachmentType::GLTexture, - gl, - size, - hasAlpha) - , mMutex("SharedSurface_EGLImage mutex") - , mEGL(egl) - , mFormats(formats) - , mProdTex(prodTex) - , mProdTexForPipe(0) - , mImage(0) - , mCurConsGL(nullptr) - , mConsTex(0) - , mSync(0) - , mPipeFailed(false) - , mPipeComplete(false) - , mPipeActive(false) - {} - - EGLDisplay Display() const; - - static bool HasExtensions(GLLibraryEGL* egl, GLContext* gl); - -public: - virtual ~SharedSurface_EGLImage(); - - virtual void LockProdImpl(); - virtual void UnlockProdImpl() {} - - - virtual void Fence(); - virtual bool WaitSync(); - - - virtual GLuint Texture() const { - return mProdTex; - } - - // Implementation-specific functions below: - // Returns 0 if the pipe isn't ready. If 0, use GetPixels below. - GLuint AcquireConsumerTexture(GLContext* consGL); - - // Will be void if AcquireConsumerTexture returns non-zero. - gfxImageSurface* GetPixels() const; -}; - - - -class SurfaceFactory_EGLImage - : public SurfaceFactory_GL -{ -public: - // Infallible: - static SurfaceFactory_EGLImage* Create(GLContext* prodGL, - const SurfaceCaps& caps); - -protected: - const EGLContext mContext; - - SurfaceFactory_EGLImage(GLContext* prodGL, - EGLContext context, - const SurfaceCaps& caps) - : SurfaceFactory_GL(prodGL, SharedSurfaceType::EGLImageShare, caps) - , mContext(context) - {} - -public: - virtual SharedSurface* CreateShared(const gfxIntSize& size) { - bool hasAlpha = mReadCaps.alpha; - return SharedSurface_EGLImage::Create(mGL, mFormats, size, hasAlpha, mContext); - } -}; - -} /* namespace gfx */ -} /* namespace mozilla */ - -#endif /* SHARED_SURFACE_EGL_H_ */
deleted file mode 100644 --- a/gfx/gl/SharedSurfaceGL.cpp +++ /dev/null @@ -1,390 +0,0 @@ -/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40; -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "SharedSurfaceGL.h" - -#include "GLContext.h" -#include "gfxImageSurface.h" - -using namespace mozilla::gfx; - -namespace mozilla { -namespace gl { - -// |src| must begin and end locked, though we may -// temporarily unlock it if we need to. -void -SharedSurface_GL::Copy(SharedSurface_GL* src, SharedSurface_GL* dest, - SurfaceFactory_GL* factory) -{ - GLContext* gl = src->GL(); - - if (src->AttachType() == AttachmentType::Screen && - dest->AttachType() == AttachmentType::Screen) - { - // Here, we actually need to blit through a temp surface, so let's make one. - nsAutoPtr<SharedSurface_GLTexture> tempSurf( - SharedSurface_GLTexture::Create(gl, gl, - factory->Formats(), - src->Size(), - factory->Caps().alpha)); - - Copy(src, tempSurf, factory); - Copy(tempSurf, dest, factory); - return; - } - - if (src->AttachType() == AttachmentType::Screen) { - SharedSurface* origLocked = gl->GetLockedSurface(); - bool srcNeedsUnlock = false; - bool origNeedsRelock = false; - if (origLocked != src) { - if (origLocked) { - origLocked->UnlockProd(); - origNeedsRelock = true; - } - - src->LockProd(); - srcNeedsUnlock = true; - } - - if (dest->AttachType() == AttachmentType::GLTexture) { - GLuint destTex = dest->Texture(); - - gl->BlitFramebufferToTexture(0, destTex, src->Size(), dest->Size()); - } else if (dest->AttachType() == AttachmentType::GLRenderbuffer) { - GLuint destRB = dest->Renderbuffer(); - ScopedFramebufferForRenderbuffer destWrapper(gl, destRB); - - gl->BlitFramebufferToFramebuffer(0, destWrapper.FB(), - src->Size(), dest->Size()); - } else { - MOZ_NOT_REACHED("Unhandled dest->AttachType()."); - return; - } - - if (srcNeedsUnlock) - src->UnlockProd(); - - if (origNeedsRelock) - origLocked->LockProd(); - - return; - } - - if (dest->AttachType() == AttachmentType::Screen) { - SharedSurface* origLocked = gl->GetLockedSurface(); - bool destNeedsUnlock = false; - bool origNeedsRelock = false; - if (origLocked != dest) { - if (origLocked) { - origLocked->UnlockProd(); - origNeedsRelock = true; - } - - dest->LockProd(); - destNeedsUnlock = true; - } - - if (src->AttachType() == AttachmentType::GLTexture) { - GLuint srcTex = src->Texture(); - - gl->BlitTextureToFramebuffer(srcTex, 0, src->Size(), dest->Size()); - } else if (src->AttachType() == AttachmentType::GLRenderbuffer) { - GLuint srcRB = src->Renderbuffer(); - ScopedFramebufferForRenderbuffer srcWrapper(gl, srcRB); - - gl->BlitFramebufferToFramebuffer(srcWrapper.FB(), 0, - src->Size(), dest->Size()); - } else { - MOZ_NOT_REACHED("Unhandled src->AttachType()."); - return; - } - - if (destNeedsUnlock) - dest->UnlockProd(); - - if (origNeedsRelock) - origLocked->LockProd(); - - return; - } - - // Alright, done with cases involving Screen types. - // Only {src,dest}x{texture,renderbuffer} left. - - if (src->AttachType() == AttachmentType::GLTexture) { - GLuint srcTex = src->Texture(); - - if (dest->AttachType() == AttachmentType::GLTexture) { - GLuint destTex = dest->Texture(); - - gl->BlitTextureToTexture(srcTex, destTex, - src->Size(), dest->Size()); - - return; - } - - if (dest->AttachType() == AttachmentType::GLRenderbuffer) { - GLuint destRB = dest->Renderbuffer(); - ScopedFramebufferForRenderbuffer destWrapper(gl, destRB); - - gl->BlitTextureToFramebuffer(srcTex, destWrapper.FB(), - src->Size(), dest->Size()); - - return; - } - - MOZ_NOT_REACHED("Unhandled dest->AttachType()."); - return; - } - - if (src->AttachType() == AttachmentType::GLRenderbuffer) { - GLuint srcRB = src->Renderbuffer(); - ScopedFramebufferForRenderbuffer srcWrapper(gl, srcRB); - - if (dest->AttachType() == AttachmentType::GLTexture) { - GLuint destTex = dest->Texture(); - - gl->BlitFramebufferToTexture(srcWrapper.FB(), destTex, - src->Size(), dest->Size()); - - return; - } - - if (dest->AttachType() == AttachmentType::GLRenderbuffer) { - GLuint destRB = dest->Renderbuffer(); - ScopedFramebufferForRenderbuffer destWrapper(gl, destRB); - - gl->BlitFramebufferToFramebuffer(srcWrapper.FB(), destWrapper.FB(), - src->Size(), dest->Size()); - - return; - } - - MOZ_NOT_REACHED("Unhandled dest->AttachType()."); - return; - } - - MOZ_NOT_REACHED("Unhandled src->AttachType()."); - return; -} - -void -SharedSurface_GL::LockProd() -{ - MOZ_ASSERT(!mIsLocked); - - LockProdImpl(); - - mGL->LockSurface(this); - mIsLocked = true; -} - -void -SharedSurface_GL::UnlockProd() -{ - if (!mIsLocked) - return; - - UnlockProdImpl(); - - mGL->UnlockSurface(this); - mIsLocked = false; -} - - -SurfaceFactory_GL::SurfaceFactory_GL(GLContext* gl, - SharedSurfaceType type, - const SurfaceCaps& caps) - : SurfaceFactory(type, caps) - , mGL(gl) - , mFormats(gl->ChooseGLFormats(caps)) -{ - ChooseBufferBits(caps, mDrawCaps, mReadCaps); -} - -void -SurfaceFactory_GL::ChooseBufferBits(const SurfaceCaps& caps, - SurfaceCaps& drawCaps, - SurfaceCaps& readCaps) const -{ - SurfaceCaps screenCaps; - - screenCaps.color = caps.color; - screenCaps.alpha = caps.alpha; - screenCaps.bpp16 = caps.bpp16; - - screenCaps.depth = caps.depth; - screenCaps.stencil = caps.stencil; - - screenCaps.antialias = caps.antialias; - screenCaps.preserve = caps.preserve; - - if (caps.antialias) { - drawCaps = screenCaps; - readCaps.Clear(); - - // Color caps need to be duplicated in readCaps. - readCaps.color = caps.color; - readCaps.alpha = caps.alpha; - readCaps.bpp16 = caps.bpp16; - } else { - drawCaps.Clear(); - readCaps = screenCaps; - } -} - - -SharedSurface_Basic* -SharedSurface_Basic::Create(GLContext* gl, - const GLFormats& formats, - const gfxIntSize& size, - bool hasAlpha) -{ - gl->MakeCurrent(); - GLuint tex = gl->CreateTexture(formats.color_texInternalFormat, - formats.color_texFormat, - formats.color_texType, - size); - - gfxASurface::gfxImageFormat format = gfxASurface::ImageFormatRGB24; - switch (formats.color_texInternalFormat) { - case LOCAL_GL_RGB: - case LOCAL_GL_RGB8: - if (formats.color_texType == LOCAL_GL_UNSIGNED_SHORT_5_6_5) - format = gfxASurface::ImageFormatRGB16_565; - else - format = gfxASurface::ImageFormatRGB24; - break; - case LOCAL_GL_RGBA: - case LOCAL_GL_RGBA8: - format = gfxASurface::ImageFormatARGB32; - break; - default: - MOZ_NOT_REACHED("Unhandled Tex format."); - return nullptr; - } - return new SharedSurface_Basic(gl, size, hasAlpha, format, tex); -} - -SharedSurface_Basic::SharedSurface_Basic(GLContext* gl, - const gfxIntSize& size, - bool hasAlpha, - gfxASurface::gfxImageFormat format, - GLuint tex) - : SharedSurface_GL(SharedSurfaceType::Basic, - AttachmentType::GLTexture, - gl, -