Bug 716859 - Streaming GLContext buffers (doublebuffering, etc) - r=bjacob,jrmuizel,vlad

This commit is contained in:
Jeff Gilbert 2013-02-13 15:26:24 -08:00
parent 381ac3ed45
commit 3375a513c3
51 changed files with 6037 additions and 2671 deletions

View File

@ -50,9 +50,10 @@
#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
@ -109,6 +110,7 @@ WebGLContext::WebGLContext()
mGeneration = 0;
mInvalidated = false;
mShouldPresent = true;
mResetLayer = true;
mOptionsFrozen = false;
@ -156,7 +158,6 @@ WebGLContext::WebGLContext()
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.
@ -193,6 +194,8 @@ WebGLContext::WebGLContext()
mMinInUseAttribArrayLengthCached = false;
mMinInUseAttribArrayLength = 0;
mIsScreenCleared = false;
}
WebGLContext::~WebGLContext()
@ -382,11 +385,13 @@ WebGLContext::SetDimensions(int32_t width, int32_t height)
// 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->OffscreenActualSize().width;
mHeight = gl->OffscreenActualSize().height;
mWidth = gl->OffscreenSize().width;
mHeight = gl->OffscreenSize().height;
mResetLayer = true;
ScopedBindFramebuffer autoFB(gl, 0);
gl->ClearSafely();
mShouldPresent = true;
return NS_OK;
}
@ -436,43 +441,19 @@ WebGLContext::SetDimensions(int32_t width, int32_t height)
if (!(mGeneration + 1).isValid())
return NS_ERROR_FAILURE; // exit without changing the value of mGeneration
gl::ContextFormat format(gl::ContextFormat::BasicRGBA32);
if (mOptions.depth) {
format.depth = 24;
format.minDepth = 16;
}
SurfaceCaps caps;
if (mOptions.stencil) {
format.stencil = 8;
format.minStencil = 8;
}
if (!mOptions.alpha) {
format.alpha = 0;
format.minAlpha = 0;
}
caps.color = true;
caps.alpha = mOptions.alpha;
caps.depth = mOptions.depth;
caps.stencil = mOptions.stencil;
// we should really have this behind a
// |gfxPlatform::GetPlatform()->GetScreenDepth() == 16| check, but
// for now it's just behind a pref for testing/evaluation.
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;
}
}
caps.bpp16 = prefer16bit;
caps.preserve = mOptions.preserveDrawingBuffer;
bool forceMSAA =
Preferences::GetBool("webgl.msaa-force", false);
@ -483,8 +464,7 @@ WebGLContext::SetDimensions(int32_t width, int32_t height)
gfxInfo &&
NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_WEBGL_MSAA, &status))) {
if (status == nsIGfxInfo::FEATURE_NO_INFO || forceMSAA) {
uint32_t msaaLevel = Preferences::GetUint("webgl.msaa-level", 2);
format.samples = msaaLevel*msaaLevel;
caps.antialias = true;
}
}
@ -525,10 +505,12 @@ WebGLContext::SetDimensions(int32_t width, int32_t height)
}
#endif
gfxIntSize size(width, height);
#ifdef XP_WIN
// if we want EGL, try it now
if (!gl && (preferEGL || useANGLE) && !preferOpenGL) {
gl = gl::GLContextProviderEGL::CreateOffscreen(gfxIntSize(width, height), format);
gl = gl::GLContextProviderEGL::CreateOffscreen(size, caps);
if (!gl || !InitAndValidateGL()) {
GenerateWarning("Error during ANGLE OpenGL ES initialization");
return NS_ERROR_FAILURE;
@ -541,8 +523,7 @@ WebGLContext::SetDimensions(int32_t width, int32_t height)
GLContext::ContextFlags flag = useMesaLlvmPipe
? GLContext::ContextFlagsMesaLLVMPipe
: GLContext::ContextFlagsNone;
gl = gl::GLContextProvider::CreateOffscreen(gfxIntSize(width, height),
format, flag);
gl = gl::GLContextProvider::CreateOffscreen(size, caps, flag);
if (gl && !InitAndValidateGL()) {
GenerateWarning("Error during %s initialization",
useMesaLlvmPipe ? "Mesa LLVMpipe" : "OpenGL");
@ -581,7 +562,7 @@ WebGLContext::SetDimensions(int32_t width, int32_t height)
// Make sure that we clear this out, otherwise
// we'll end up displaying random memory
gl->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, gl->GetOffscreenFBO());
gl->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0);
gl->fViewport(0, 0, mWidth, mHeight);
gl->fClearColor(0.0f, 0.0f, 0.0f, 0.0f);
@ -590,6 +571,15 @@ WebGLContext::SetDimensions(int32_t width, int32_t height)
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;
}
@ -803,25 +793,39 @@ namespace mozilla {
class WebGLContextUserData : public LayerUserData {
public:
WebGLContextUserData(HTMLCanvasElement *aContent)
: mContent(aContent) {}
: mContent(aContent)
{}
/** 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));
/* 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));
context->mBackbufferClearingStatus = BackbufferClearingStatus::NotClearedSinceLastPresented;
canvas->MarkContextClean();
// Present our screenbuffer, if needed.
context->PresentScreenBuffer();
}
context->UpdateLastUseIndex();
}
/** 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));
// Mark ourselves as no longer invalidated.
context->MarkContextClean();
context->UpdateLastUseIndex();
}
private:
nsRefPtr<HTMLCanvasElement> mContent;
nsRefPtr<HTMLCanvasElement> mContent;
};
} // end namespace mozilla
@ -862,28 +866,18 @@ WebGLContext::GetCanvasLayer(nsDisplayListBuilder* aBuilder,
userData = new WebGLContextUserData(mCanvasElement);
canvasLayer->SetDidTransactionCallback(
WebGLContextUserData::DidTransactionCallback, userData);
canvasLayer->SetPreTransactionCallback(
WebGLContextUserData::PreTransactionCallback, userData);
}
canvasLayer->SetUserData(&gWebGLLayerUserData, userData);
CanvasLayer::Data data;
// 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.mGLContext = gl;
data.mSize = nsIntSize(mWidth, mHeight);
data.mGLBufferIsPremultiplied = mOptions.premultipliedAlpha ? true : false;
data.mIsGLAlphaPremult = IsPremultAlpha();
canvasLayer->Initialize(data);
uint32_t flags = gl->CreationFormat().alpha == 0 ? Layer::CONTENT_OPAQUE : 0;
uint32_t flags = gl->Caps().alpha ? 0 : Layer::CONTENT_OPAQUE;
canvasLayer->SetContentFlags(flags);
canvasLayer->Updated();
@ -901,11 +895,12 @@ WebGLContext::GetContextAttributes(Nullable<dom::WebGLContextAttributesInitializ
dom::WebGLContextAttributes& result = retval.SetValue();
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;
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;
result.mPremultipliedAlpha = mOptions.premultipliedAlpha;
result.mPreserveDrawingBuffer = mOptions.preserveDrawingBuffer;
}
@ -1109,7 +1104,23 @@ WebGLContext::GetExtension(JSContext *cx, const nsAString& aName, ErrorResult& r
}
void
WebGLContext::ForceClearFramebufferWithDefaultValues(uint32_t mask, const nsIntRect& viewportRect)
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)
{
MakeContextCurrent();
@ -1117,16 +1128,71 @@ WebGLContext::ForceClearFramebufferWithDefaultValues(uint32_t mask, const nsIntR
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
// 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.
// prepare GL state for clearing
#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;
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.
gl->fDisable(LOCAL_GL_SCISSOR_TEST);
gl->fDisable(LOCAL_GL_DITHER);
if (initializeColorBuffer) {
gl->fColorMask(1, 1, 1, 1);
gl->fClearColor(0.f, 0.f, 0.f, 0.f);
gl->fClearColor(0.0f, 0.0f, 0.0f, 0.0f);
}
if (initializeDepthBuffer) {
@ -1135,14 +1201,21 @@ WebGLContext::ForceClearFramebufferWithDefaultValues(uint32_t mask, const nsIntR
}
if (initializeStencilBuffer) {
gl->fStencilMask(0xffffffff);
// "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->fClearStencil(0);
}
// do clear
// Do the clear!
gl->fClear(mask);
// restore GL state after clearing
// And reset!
if (mScissorTestEnabled)
gl->fEnable(LOCAL_GL_SCISSOR_TEST);
// Restore GL state after clearing.
if (initializeColorBuffer) {
gl->fColorMask(mColorWriteMask[0],
mColorWriteMask[1],
@ -1161,41 +1234,33 @@ WebGLContext::ForceClearFramebufferWithDefaultValues(uint32_t mask, const nsIntR
if (initializeStencilBuffer) {
gl->fStencilMaskSeparate(LOCAL_GL_FRONT, mStencilWriteMaskFront);
gl->fStencilMaskSeparate(LOCAL_GL_BACK, mStencilWriteMaskBack);
gl->fStencilMaskSeparate(LOCAL_GL_BACK, mStencilWriteMaskBack);
gl->fClearStencil(mStencilClearValue);
}
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);
}
void
WebGLContext::EnsureBackbufferClearedAsNeeded()
// For an overview of how WebGL compositing works, see:
// https://wiki.mozilla.org/Platform/GFX/WebGL/Compositing
bool
WebGLContext::PresentScreenBuffer()
{
if (mOptions.preserveDrawingBuffer)
return;
if (!mShouldPresent) {
return false;
}
NS_ABORT_IF_FALSE(!mBoundFramebuffer,
"EnsureBackbufferClearedAsNeeded must not be called when a FBO is bound");
gl->MakeCurrent();
if (!gl->PublishFrame()) {
this->ForceLoseContext();
return false;
}
if (mBackbufferClearingStatus != BackbufferClearingStatus::NotClearedSinceLastPresented)
return;
if (!mOptions.preserveDrawingBuffer) {
ClearScreen();
}
mBackbufferClearingStatus = BackbufferClearingStatus::ClearedToDefaultValues;
mShouldPresent = false;
ForceClearFramebufferWithDefaultValues(LOCAL_GL_COLOR_BUFFER_BIT |
LOCAL_GL_DEPTH_BUFFER_BIT |
LOCAL_GL_STENCIL_BUFFER_BIT,
nsIntRect(0, 0, mWidth, mHeight));
Invalidate();
return true;
}
void

View File

@ -86,10 +86,6 @@ struct VertexAttrib0Status {
enum { Default, EmulatedUninitializedArray, EmulatedInitializedArray };
};
struct BackbufferClearingStatus {
enum { NotClearedSinceLastPresented, ClearedToDefaultValues, HasBeenDrawnTo };
};
namespace WebGLTexelConversions {
/*
@ -261,23 +257,35 @@ public:
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 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);
// 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);
// 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();
// Calls ForceClearFramebufferWithDefaultValues() for the Context's 'screen'.
void ClearScreen();
// 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
@ -844,6 +852,8 @@ protected:
bool mIsMesa;
bool mLoseContextOnHeapMinimize;
bool mCanLoseContextInForeground;
bool mShouldPresent;
bool mIsScreenCleared;
template<typename WebGLObjectType>
void DeleteWebGLObjectsArray(nsTArray<WebGLObjectType>& array);
@ -1106,8 +1116,6 @@ protected:
WebGLint mStencilClearValue;
WebGLfloat mDepthClearValue;
int mBackbufferClearingStatus;
nsCOMPtr<nsITimer> mContextRestorer;
bool mAllowRestore;
bool mContextLossTimerRunning;

View File

@ -171,7 +171,7 @@ WebGLContext::BindFramebuffer(WebGLenum target, WebGLFramebuffer *wfb)
MakeContextCurrent();
if (!wfb) {
gl->fBindFramebuffer(target, gl->GetOffscreenFBO());
gl->fBindFramebuffer(target, 0);
} else {
WebGLuint framebuffername = wfb->GLName();
gl->fBindFramebuffer(target, framebuffername);
@ -575,32 +575,52 @@ WebGLContext::Clear(WebGLbitfield mask)
if (mask != m)
return ErrorInvalidValue("clear: invalid mask bits");
bool needClearCallHere = true;
if (mBoundFramebuffer) {
if (!mBoundFramebuffer->CheckAndInitializeRenderbuffers())
return ErrorInvalidFramebufferOperation("clear: incomplete framebuffer");
} 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;
}
gl->fClear(mask);
return;
}
if (needClearCallHere) {
gl->fClear(mask);
mBackbufferClearingStatus = BackbufferClearingStatus::HasBeenDrawnTo;
Invalidate();
// 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;
}
}
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) {
gl->fClear(mask);
mIsScreenCleared = false;
}
Invalidate();
mShouldPresent = true;
}
void
@ -815,7 +835,7 @@ WebGLContext::CopyTexImage2D(WebGLenum target,
internalformat == LOCAL_GL_ALPHA ||
internalformat == LOCAL_GL_LUMINANCE_ALPHA;
bool fboFormatHasAlpha = mBoundFramebuffer ? mBoundFramebuffer->ColorAttachment().HasAlpha()
: bool(gl->ActualFormat().alpha > 0);
: bool(gl->GetPixelFormat().alpha > 0);
if (texFormatRequiresAlpha && !fboFormatHasAlpha)
return ErrorInvalidOperation("copyTexImage2D: texture format requires an alpha channel "
"but the framebuffer doesn't have one");
@ -925,7 +945,7 @@ WebGLContext::CopyTexSubImage2D(WebGLenum target,
format == LOCAL_GL_ALPHA ||
format == LOCAL_GL_LUMINANCE_ALPHA;
bool fboFormatHasAlpha = mBoundFramebuffer ? mBoundFramebuffer->ColorAttachment().HasAlpha()
: bool(gl->ActualFormat().alpha > 0);
: bool(gl->GetPixelFormat().alpha > 0);
if (texFormatRequiresAlpha && !fboFormatHasAlpha)
return ErrorInvalidOperation("copyTexSubImage2D: texture format requires an alpha channel "
@ -1440,8 +1460,6 @@ WebGLContext::DrawArrays(GLenum mode, WebGLint first, WebGLsizei count)
if (mBoundFramebuffer) {
if (!mBoundFramebuffer->CheckAndInitializeRenderbuffers())
return ErrorInvalidFramebufferOperation("drawArrays: incomplete framebuffer");
} else {
EnsureBackbufferClearedAsNeeded();
}
BindFakeBlackTextures();
@ -1454,8 +1472,11 @@ WebGLContext::DrawArrays(GLenum mode, WebGLint first, WebGLsizei count)
UndoFakeVertexAttrib0();
UnbindFakeBlackTextures();
mBackbufferClearingStatus = BackbufferClearingStatus::HasBeenDrawnTo;
Invalidate();
if (!mBoundFramebuffer) {
Invalidate();
mShouldPresent = true;
mIsScreenCleared = false;
}
}
void
@ -1533,8 +1554,6 @@ WebGLContext::DrawElements(WebGLenum mode, WebGLsizei count, WebGLenum type,
if (mBoundFramebuffer) {
if (!mBoundFramebuffer->CheckAndInitializeRenderbuffers())
return ErrorInvalidFramebufferOperation("drawElements: incomplete framebuffer");
} else {
EnsureBackbufferClearedAsNeeded();
}
BindFakeBlackTextures();
@ -1547,8 +1566,11 @@ WebGLContext::DrawElements(WebGLenum mode, WebGLsizei count, WebGLenum type,
UndoFakeVertexAttrib0();
UnbindFakeBlackTextures();
mBackbufferClearingStatus = BackbufferClearingStatus::HasBeenDrawnTo;
Invalidate();
if (!mBoundFramebuffer) {
Invalidate();
mShouldPresent = true;
mIsScreenCleared = false;
}
}
void
@ -3332,7 +3354,7 @@ WebGLContext::ReadPixels(WebGLint x, WebGLint y, WebGLsizei width,
if (mBoundFramebuffer) {
needAlphaFixup = !mBoundFramebuffer->ColorAttachment().HasAlpha();
} else {
needAlphaFixup = gl->ActualFormat().alpha == 0;
needAlphaFixup = gl->GetPixelFormat().alpha == 0;
}
if (needAlphaFixup) {

View File

@ -352,7 +352,7 @@ WebGLFramebuffer::CheckAndInitializeRenderbuffers()
mask |= LOCAL_GL_STENCIL_BUFFER_BIT;
}
mContext->ForceClearFramebufferWithDefaultValues(mask, nsIntRect(0, 0, rect->Width(), rect->Height()));
mContext->ForceClearFramebufferWithDefaultValues(mask);
if (mColorAttachment.HasUninitializedRenderbuffer())
mColorAttachment.Renderbuffer()->SetInitialized(true);

View File

@ -11,175 +11,175 @@ pref(webgl.disabled,true) == webgl-disable-test.html wrapper.html?green.p
# 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
== 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
== 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
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
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
# 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
== 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
== 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
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
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
# 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
== 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?__&_____&_____&_______&________&_______ 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?__&_____&_____&_______&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?__&_____&_____&_______&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?__&_____&_____&_______&________&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?__&_____&_____&_______&________&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
fuzzy-if(B2G,256,83) == 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?__&_____&_____&_______&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
== 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
# Check a smaller selection for readback:
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
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
# Check alpha behavior:
== 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=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=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-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
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
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
# Test premult:
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
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||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(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||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(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||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(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
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||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) 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-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-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
== 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
# Check that our experimental prefs still work:
# 16bpp:
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
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
# Force native GL (Windows):
skip-if(!winWidget) pref(webgl.prefer-native-gl,true) == webgl-clear-test.html?native-gl wrapper.html?green.png
@ -187,6 +187,9 @@ skip-if(!winWidget) pref(webgl.prefer-native-gl,true)
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

View File

@ -82,7 +82,9 @@ static nsRefPtr<GLContext> sPluginContext = nullptr;
static bool EnsureGLContext()
{
if (!sPluginContext) {
sPluginContext = GLContextProvider::CreateOffscreen(gfxIntSize(16, 16));
gfxIntSize dummySize(16, 16);
GLContext::SurfaceCaps dummyCaps;
sPluginContext = GLContextProvider::CreateOffscreen(dummySize, dummyCaps);
}
return sPluginContext != nullptr;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -10,6 +10,7 @@
#include "gfxTypes.h"
#include "gfxPoint.h"
#include "nsAutoPtr.h"
#include "SurfaceTypes.h"
class nsIWidget;
class gfxASurface;

View File

@ -18,6 +18,8 @@
#include "mozilla/Preferences.h"
#include "sampler.h"
using namespace mozilla::gfx;
namespace mozilla {
namespace gl {
@ -84,25 +86,14 @@ class GLContextCGL : public GLContext
friend class GLContextProviderCGL;
public:
GLContextCGL(const ContextFormat& aFormat,
GLContext *aShareContext,
NSOpenGLContext *aContext,
bool aIsOffscreen = false)
: GLContext(aFormat, aIsOffscreen, aShareContext),
mContext(aContext),
mPBuffer(nullptr),
GLContextCGL(const SurfaceCaps& caps,
GLContext *shareContext,
NSOpenGLContext *context,
bool isOffscreen = false)
: GLContext(caps, shareContext, isOffscreen),
mContext(context),
mTempTextureName(0)
{ }
GLContextCGL(const ContextFormat& aFormat,
GLContext *aShareContext,
NSOpenGLContext *aContext,
NSOpenGLPixelBuffer *aPixelBuffer)
: GLContext(aFormat, true, aShareContext),
mContext(aContext),
mPBuffer(aPixelBuffer),
mTempTextureName(0)
{ }
{}
~GLContextCGL()
{
@ -110,9 +101,6 @@ public:
if (mContext)
[mContext release];
if (mPBuffer)
[mPBuffer release];
}
GLContextType GetContextType() {
@ -180,8 +168,6 @@ public:
return true;
}
bool BindTex2DOffscreen(GLContext *aOffscreen);
void UnbindTex2DOffscreen(GLContext *aOffscreen);
bool ResizeOffscreen(const gfxIntSize& aNewSize);
virtual already_AddRefed<TextureImage>
@ -193,99 +179,13 @@ public:
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)
{
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);
return ResizeScreenBuffer(aNewSize);
}
class TextureImageCGL : public BasicTextureImage
@ -431,7 +331,8 @@ GLContextProviderCGL::CreateForWindow(nsIWidget *aWidget)
}
// make the context transparent
nsRefPtr<GLContextCGL> glContext = new GLContextCGL(ContextFormat(ContextFormat::BasicRGB24),
SurfaceCaps caps = SurfaceCaps::ForRGBA();
nsRefPtr<GLContextCGL> glContext = new GLContextCGL(caps,
shareContext,
context);
if (!glContext->Init()) {
@ -442,102 +343,7 @@ GLContextProviderCGL::CreateForWindow(nsIWidget *aWidget)
}
static already_AddRefed<GLContextCGL>
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)
CreateOffscreenFBOContext(bool aShare = true)
{
if (!sCGLLibrary.EnsureInitialized()) {
return nullptr;
@ -556,41 +362,21 @@ CreateOffscreenFBOContext(const ContextFormat& aFormat,
return nullptr;
}
nsRefPtr<GLContextCGL> glContext = new GLContextCGL(aFormat, shareContext, context, true);
SurfaceCaps dummyCaps = SurfaceCaps::Any();
nsRefPtr<GLContextCGL> glContext = new GLContextCGL(dummyCaps, shareContext, context, true);
return glContext.forget();
}
already_AddRefed<GLContext>
GLContextProviderCGL::CreateOffscreen(const gfxIntSize& aSize,
const ContextFormat& aFormat,
GLContextProviderCGL::CreateOffscreen(const gfxIntSize& size,
const SurfaceCaps& caps,
const ContextFlags flags)
{
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);
nsRefPtr<GLContextCGL> glContext = CreateOffscreenFBOContext();
if (glContext &&
glContext->Init() &&
glContext->ResizeOffscreenFBOs(aSize, true))
glContext->InitOffscreen(size, caps))
{
return glContext.forget();
}
@ -613,8 +399,7 @@ GLContextProviderCGL::GetGlobalContext(const ContextFlags)
// 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(ContextFormat(ContextFormat::BasicRGB24),
false);
gGlobalContext = CreateOffscreenFBOContext(false);
if (!gGlobalContext || !static_cast<GLContextCGL*>(gGlobalContext.get())->Init()) {
NS_WARNING("Couldn't init gGlobalContext.");
gGlobalContext = nullptr;

View File

@ -35,6 +35,7 @@
#include "AndroidBridge.h"
#include "nsSurfaceTexture.h"
#endif
#include <android/log.h>
#define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "Gonk" , ## args)
@ -43,9 +44,6 @@
# include <ui/GraphicBuffer.h>
using namespace android;
# define EGL_NATIVE_BUFFER_ANDROID 0x3140
# endif
#endif
@ -132,6 +130,8 @@ static bool gUseBackingSurface = false;
extern nsIntRect gScreenBounds;
#endif
#define EGL_DISPLAY() sEGLLibrary.Display()
namespace mozilla {
namespace gl {
@ -201,37 +201,44 @@ class GLContextEGL : public GLContext
friend class TextureImageEGL;
static already_AddRefed<GLContextEGL>
CreateGLContext(const ContextFormat& format,
EGLSurface surface,
EGLConfig config,
CreateGLContext(const SurfaceCaps& caps,
GLContextEGL *shareContext,
bool aIsOffscreen = false)
bool isOffscreen,
EGLConfig config,
EGLSurface surface)
{
EGLContext context;
if (sEGLLibrary.fBindAPI(LOCAL_EGL_OPENGL_ES_API) == LOCAL_EGL_FALSE) {
NS_WARNING("Failed to bind API to GLES!");
return nullptr;
}
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;
}
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;
}
}
nsRefPtr<GLContextEGL> glContext =
new GLContextEGL(format, shareContext, config,
surface, context, aIsOffscreen);
nsRefPtr<GLContextEGL> glContext = new GLContextEGL(caps,
shareContext,
isOffscreen,
config,
surface,
context);
if (!glContext->Init())
return nullptr;
@ -240,15 +247,17 @@ class GLContextEGL : public GLContext
}
public:
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)
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)
, mPlatformContext(nullptr)
, mThebesSurface(nullptr)
, mBound(false)
@ -265,7 +274,7 @@ public:
printf_stderr("Initializing context %p surface %p on display %p\n", mContext, mSurface, EGL_DISPLAY());
#endif
#ifdef MOZ_WIDGET_GONK
if (!aIsOffscreen) {
if (!mIsOffscreen) {
mHwc = HwcComposer2D::GetInstance();
MOZ_ASSERT(!mHwc->Initialized());
@ -363,6 +372,15 @@ public:
mIsDoubleBuffered = aIsDB;
}
virtual EGLContext GetEGLContext() {
return mContext;
}
virtual GLLibraryEGL* GetLibraryEGL() {
return &sEGLLibrary;
}
bool SupportsRobustness()
{
return sEGLLibrary.HasRobustness();
@ -418,7 +436,7 @@ public:
};
EGLImage image = sEGLLibrary.fCreateImage(EGL_DISPLAY(),
EGL_NO_CONTEXT,
EGL_NATIVE_BUFFER_ANDROID,
LOCAL_EGL_NATIVE_BUFFER_ANDROID,
buffer, attrs);
fBindTexture(LOCAL_GL_TEXTURE_EXTERNAL, texture);
fEGLImageTargetTexture2D(LOCAL_GL_TEXTURE_EXTERNAL, image);
@ -450,6 +468,19 @@ public:
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;
@ -483,7 +514,7 @@ public:
}
#endif
succeeded = sEGLLibrary.fMakeCurrent(EGL_DISPLAY(),
mSurface, mSurface,
mCurSurface, mCurSurface,
mContext);
int eglError = sEGLLibrary.fGetError();
@ -609,41 +640,10 @@ public:
void BindOffscreenFramebuffer();
static already_AddRefed<GLContextEGL>
CreateEGLPixmapOffscreenContext(const gfxIntSize& aSize,
const ContextFormat& aFormat,
bool aShare);
CreateEGLPixmapOffscreenContext(const gfxIntSize& size);
static already_AddRefed<GLContextEGL>
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;
}
CreateEGLPBufferOffscreenContext(const gfxIntSize& size);
virtual bool HasLockSurface() {
return sEGLLibrary.HasKHRLockSurface();
@ -662,11 +662,13 @@ public:
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;
@ -728,6 +730,7 @@ protected:
}
};
typedef enum {
Image
#ifdef MOZ_WIDGET_ANDROID
@ -791,7 +794,8 @@ public:
static const EGLint eglAttributes[] = {
LOCAL_EGL_NONE
};
mEGLImage = sEGLLibrary.fCreateImage(EGL_DISPLAY(), ctx->Context(), LOCAL_EGL_GL_TEXTURE_2D,
EGLContext eglContext = (EGLContext)ctx->GetEGLContext();
mEGLImage = sEGLLibrary.fCreateImage(EGL_DISPLAY(), eglContext, LOCAL_EGL_GL_TEXTURE_2D,
(EGLClientBuffer)texture, eglAttributes);
if (!mEGLImage) {
#ifdef DEBUG
@ -874,22 +878,14 @@ GLContextEGL::UpdateSharedHandle(SharedTextureShareType shareType,
// 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.
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);
ScopedBindTexture autoTex(this, mTemporaryEGLImageTexture);
fEGLImageTargetTexture2D(LOCAL_GL_TEXTURE_2D, wrap->GetEGLImage());
// 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);
// 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);
// 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
@ -907,10 +903,7 @@ GLContextEGL::CreateSharedHandle(SharedTextureShareType shareType)
return 0;
MakeCurrent();
ContextFormat fmt = ActualFormat();
CreateTextureForOffscreen(ChooseGLFormats(fmt, GLContext::ForceRGBA), mOffscreenActualSize,
mTemporaryEGLImageTexture);
mTemporaryEGLImageTexture = CreateTextureForOffscreen(GetGLFormats(), OffscreenSize());
EGLTextureWrapper* tex = new EGLTextureWrapper();
bool ok = tex->CreateEGLImage(this, mTemporaryEGLImageTexture);
@ -930,7 +923,7 @@ GLContextEGL::CreateSharedHandle(SharedTextureShareType shareType,
void* buffer,
SharedTextureBufferType bufferType)
{
// Both EGLImage and SurfaceTexture only support ThreadShared currently, but
// Both EGLImage and SurfaceTexture only support same-process currently, but
// it's possible to make SurfaceTexture work across processes. We should do that.
if (shareType != SameProcess)
return 0;
@ -1075,94 +1068,10 @@ bool GLContextEGL::AttachSharedHandle(SharedTextureShareType shareType,
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)
{
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);
return ResizeScreenBuffer(aNewSize);
}
@ -1834,7 +1743,7 @@ public:
LOCAL_EGL_NONE, LOCAL_EGL_NONE };
mEGLImage = sEGLLibrary.fCreateImage(EGL_DISPLAY(),
EGL_NO_CONTEXT,
EGL_NATIVE_BUFFER_ANDROID,
LOCAL_EGL_NATIVE_BUFFER_ANDROID,
(EGLClientBuffer) mGraphicBuffer->getNativeBuffer(),
eglImageAttributes);
if (!mEGLImage) {
@ -1908,7 +1817,7 @@ public:
mEGLImage = sEGLLibrary.fCreateImage(EGL_DISPLAY(),
EGL_NO_CONTEXT,
EGL_NATIVE_BUFFER_ANDROID,
LOCAL_EGL_NATIVE_BUFFER_ANDROID,
mGraphicBuffer->getNativeBuffer(),
eglImageAttributes);
if (!mEGLImage) {
@ -1977,24 +1886,14 @@ GLContextEGL::TileGenFunc(const nsIntSize& aSize,
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,
@ -2011,6 +1910,7 @@ static const EGLint kEGLConfigAttribsRGB24[] = {
LOCAL_EGL_RED_SIZE, 8,
LOCAL_EGL_GREEN_SIZE, 8,
LOCAL_EGL_BLUE_SIZE, 8,
LOCAL_EGL_ALPHA_SIZE, 0,
LOCAL_EGL_NONE
};
@ -2143,18 +2043,16 @@ CreateSurfaceForWindow(nsIWidget *aWidget, EGLConfig config)
already_AddRefed<GLContext>
GLContextProviderEGL::CreateForWindow(nsIWidget *aWidget)
{
EGLConfig config;
if (!sEGLLibrary.EnsureInitialized()) {
return nullptr;
}
bool doubleBuffered = true;
void* currentContext = sEGLLibrary.fGetCurrentContext();
if (aWidget->HasGLContext() && currentContext) {
int32_t depth = gfxPlatform::GetPlatform()->GetScreenDepth();
void* platformContext = currentContext;
EGLContext eglContext = sEGLLibrary.fGetCurrentContext();
if (aWidget->HasGLContext() && eglContext) {
//int colorDepth = gfxPlatform::GetPlatform()->GetScreenDepth();
void* platformContext = eglContext;
#ifdef MOZ_WIDGET_QT
QGLContext* context = const_cast<QGLContext*>(QGLContext::currentContext());
if (context && context->device()) {
@ -2163,23 +2061,22 @@ GLContextProviderEGL::CreateForWindow(nsIWidget *aWidget)
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(ContextFormat(DepthToGLFormat(depth)),
gGlobalContext,
NULL,
sEGLLibrary.fGetCurrentSurface(LOCAL_EGL_DRAW), // just use same surface for read and draw
currentContext,
false);
new GLContextEGL(caps,
gGlobalContext, false,
config, surface, eglContext);
if (!glContext->Init())
return nullptr;
glContext->MakeCurrent();
sEGLLibrary.LoadConfigSensitiveSymbols();
glContext->SetIsDoubleBuffered(doubleBuffered);
glContext->SetPlatformContext(platformContext);
if (!gGlobalContext) {
gGlobalContext = glContext;
}
@ -2187,6 +2084,7 @@ GLContextProviderEGL::CreateForWindow(nsIWidget *aWidget)
return glContext.forget();
}
EGLConfig config;
if (!CreateConfig(&config)) {
printf_stderr("Failed to create EGL config!\n");
return nullptr;
@ -2200,218 +2098,79 @@ GLContextProviderEGL::CreateForWindow(nsIWidget *aWidget)
#endif
if (!surface) {
printf_stderr("Failed to create EGLSurface!\n");
return nullptr;
}
if (!sEGLLibrary.fBindAPI(LOCAL_EGL_OPENGL_ES_API)) {
GLContextEGL* shareContext = GetGlobalContextEGL();
SurfaceCaps caps = SurfaceCaps::Any();
nsRefPtr<GLContextEGL> glContext =
GLContextEGL::CreateGLContext(caps,
shareContext, false,
config, surface);
if (!glContext) {
sEGLLibrary.fDestroySurface(EGL_DISPLAY(), surface);
return nullptr;
}
GLContextEGL *shareContext = GetGlobalContextEGL();
nsRefPtr<GLContextEGL> glContext =
GLContextEGL::CreateGLContext(ContextFormat(ContextFormat::BasicRGB24),
surface,
config,
shareContext,
false);
if (!glContext) {
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& aSize,
const ContextFormat& aFormat,
bool bufferUnused)
GLContextEGL::CreateEGLPBufferOffscreenContext(const gfxIntSize& size)
{
EGLConfig config;
EGLSurface surface;
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;
}
}
const EGLint numConfigs = 1; // We only need one.
EGLConfig configs[numConfigs];
EGLint foundConfigs = 0;
if (!sEGLLibrary.fChooseConfig(EGL_DISPLAY(),
&attribs[0],
kEGLConfigAttribsOffscreenPBuffer,
configs, numConfigs,
&foundConfigs)
|| foundConfigs == 0)
{
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!");
NS_WARNING("No EGL Config for minimal PBuffer!");
return nullptr;
}
// XXX do some smarter matching here, perhaps instead of the more complex
// minimum overrides above
// We absolutely don't care, so just pick the first one.
config = configs[0];
#ifdef DEBUG
sEGLLibrary.DumpEGLConfig(config);
#endif
if (GLContext::DebugMode())
sEGLLibrary.DumpEGLConfig(config);
gfxIntSize pbsize(aSize);
gfxIntSize pbSize(size);
surface = GLContextEGL::CreatePBufferSurfaceTryingPowerOfTwo(config,
configCanBindToTexture
? (aFormat.minAlpha
? LOCAL_EGL_TEXTURE_RGBA
: LOCAL_EGL_TEXTURE_RGB)
: LOCAL_EGL_NONE,
pbsize);
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();
context = sEGLLibrary.fCreateContext(EGL_DISPLAY(),
config,
shareContext ? shareContext->mContext
: EGL_NO_CONTEXT,
sEGLLibrary.HasRobustness() ? gContextAttribsRobustness
: gContextAttribs);
if (!context) {
SurfaceCaps dummyCaps = SurfaceCaps::Any();
nsRefPtr<GLContextEGL> glContext =
GLContextEGL::CreateGLContext(dummyCaps,
shareContext, true,
config, surface);
if (!glContext) {
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();
}
@ -2505,9 +2264,7 @@ CreateEGLSurfaceForXSurface(gfxASurface* aSurface, EGLConfig* aConfig)
#endif
already_AddRefed<GLContextEGL>
GLContextEGL::CreateEGLPixmapOffscreenContext(const gfxIntSize& aSize,
const ContextFormat& aFormat,
bool aShare)
GLContextEGL::CreateEGLPixmapOffscreenContext(const gfxIntSize& size)
{
gfxASurface *thebesSurface = nullptr;
EGLNativePixmapType pixmap = 0;
@ -2517,7 +2274,7 @@ GLContextEGL::CreateEGLPixmapOffscreenContext(const gfxIntSize& aSize,
gfxXlibSurface::Create(DefaultScreenOfDisplay(DefaultXDisplay()),
gfxXlibSurface::FindRenderFormat(DefaultXDisplay(),
gfxASurface::ImageFormatRGB24),
aSize);
size);
// XSync required after gfxXlibSurface::Create, otherwise EGL will fail with BadDrawable error
XSync(DefaultXDisplay(), False);
@ -2541,15 +2298,25 @@ GLContextEGL::CreateEGLPixmapOffscreenContext(const gfxIntSize& aSize,
if (!config) {
return nullptr;
}
MOZ_ASSERT(surface);
GLContextEGL *shareContext = aShare ? GetGlobalContextEGL() : nullptr;
GLContextEGL* shareContext = GetGlobalContextEGL();
SurfaceCaps dummyCaps = SurfaceCaps::Any();
nsRefPtr<GLContextEGL> glContext =
GLContextEGL::CreateGLContext(aFormat,
surface,
config,
shareContext,
true);
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;
}
glContext->HoldSurface(thebesSurface);
@ -2561,49 +2328,32 @@ GLContextEGL::CreateEGLPixmapOffscreenContext(const gfxIntSize& aSize,
// 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& aSize,
const ContextFormat& aFormat,
const ContextFlags aFlags)
GLContextProviderEGL::CreateOffscreen(const gfxIntSize& size,
const SurfaceCaps& caps,
ContextFlags flags)
{
if (!sEGLLibrary.EnsureInitialized()) {
return nullptr;
}
#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);
gfxIntSize dummySize = gfxIntSize(16, 16);
nsRefPtr<GLContextEGL> glContext;
#if defined(MOZ_X11)
glContext = GLContextEGL::CreateEGLPixmapOffscreenContext(dummySize);
#else
glContext = GLContextEGL::CreateEGLPBufferOffscreenContext(dummySize);
#endif
if (!glContext)
return nullptr;
gfxIntSize fboSize = usePBuffers ? glContext->OffscreenActualSize() : aSize;
if (!(aFlags & GLContext::ContextFlagsGlobal) && !glContext->ResizeOffscreenFBOs(fboSize, !usePBuffers))
if (flags & GLContext::ContextFlagsGlobal)
return glContext.forget();
if (!glContext->InitOffscreen(size, caps))
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)

View File

@ -36,6 +36,8 @@
#include "gfxPlatformGtk.h"
#endif
using namespace mozilla::gfx;
namespace mozilla {
namespace gl {
@ -70,7 +72,7 @@ HasExtension(const char* aExtensions, const char* aRequiredExtension)
}
bool
GLXLibrary::EnsureInitialized(bool aUseMesaLLVMPipe)
GLXLibrary::EnsureInitialized(LibType libType)
{
if (mInitialized) {
return true;
@ -82,19 +84,33 @@ GLXLibrary::EnsureInitialized(bool aUseMesaLLVMPipe)
}
mTriedInitializing = true;
// Force enabling s3 texture compression (http://dri.freedesktop.org/wiki/S3TC)
// Force enabling s3 texture compression. (Bug 774134)
PR_SetEnv("force_s3tc_enable=true");
if (!mOGLLibrary) {
// 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
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
#ifdef __OpenBSD__
const char *libGLfilename = aUseMesaLLVMPipe? "mesallvmpipe.so" : "libGL.so";
libGLfilename = "libGL.so";
#else
const char *libGLfilename = aUseMesaLLVMPipe? "mesallvmpipe.so" : "libGL.so.1";
libGLfilename = "libGL.so.1";
#endif
ScopedGfxFeatureReporter reporter(libGLfilename, aUseMesaLLVMPipe);
break;
default:
MOZ_NOT_REACHED("Invalid GLX library type.");
return false;
}
ScopedGfxFeatureReporter reporter(libGLfilename, forceFeatureReport);
mOGLLibrary = PR_LoadLibrary(libGLfilename);
if (!mOGLLibrary) {
NS_WARNING("Couldn't load OpenGL shared library.");
@ -250,8 +266,7 @@ GLXLibrary::EnsureInitialized(bool aUseMesaLLVMPipe)
mClientIsMesa = clientVendor && DoesStringMatch(clientVendor, "Mesa");
mInitialized = true;
if(aUseMesaLLVMPipe)
mLibType = GLXLibrary::MESA_LLVMPIPE_LIB;
mLibType = libType;
return true;
}
@ -259,7 +274,7 @@ GLXLibrary::EnsureInitialized(bool aUseMesaLLVMPipe)
bool
GLXLibrary::SupportsTextureFromPixmap(gfxASurface* aSurface)
{
if (!EnsureInitialized(mLibType == MESA_LLVMPIPE_LIB)) {
if (!EnsureInitialized(mLibType)) {
return false;
}
@ -726,18 +741,21 @@ class GLContextGLX : public GLContext
{
public:
static already_AddRefed<GLContextGLX>
CreateGLContext(const ContextFormat& format,
Display *display,
CreateGLContext(const SurfaceCaps& caps,
GLContextGLX* shareContext,
bool isOffscreen,
Display* display,
GLXDrawable drawable,
GLXFBConfig cfg,
GLContextGLX *shareContext,
bool deleteDrawable,
LibType lib = GLXLibrary::OPENGL_LIB,
gfxXlibSurface *pixmap = nullptr)
LibType libType = GLXLibrary::OPENGL_LIB,
gfxXlibSurface* pixmap = nullptr)
{
int db = 0, err;
err = sGLXLibrary[lib].xGetFBConfigAttrib(display, cfg,
GLX_DOUBLEBUFFER, &db);
GLXLibrary& glx = sGLXLibrary[libType];
int db = 0;
int err = glx.xGetFBConfigAttrib(display, cfg,
GLX_DOUBLEBUFFER, &db);
if (GLX_BAD_ATTRIBUTE != err) {
#ifdef DEBUG
if (DebugMode()) {
@ -756,36 +774,40 @@ TRY_AGAIN_NO_SHARING:
error = false;
if (sGLXLibrary[lib].HasRobustness()) {
GLXContext glxContext = shareContext ? shareContext->mContext : NULL;
if (glx.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 = sGLXLibrary[lib].xCreateContextAttribs(display,
cfg,
shareContext ? shareContext->mContext : NULL,
True,
attrib_list);
context = glx.xCreateContextAttribs(
display,
cfg,
glxContext,
True,
attrib_list);
} else {
context = sGLXLibrary[lib].xCreateNewContext(display,
cfg,
GLX_RGBA_TYPE,
shareContext ? shareContext->mContext : NULL,
True);
context = glx.xCreateNewContext(
display,
cfg,
GLX_RGBA_TYPE,
glxContext,
True);
}
if (context) {
glContext = new GLContextGLX(format,
shareContext,
display,
drawable,
context,
deleteDrawable,
db,
pixmap,
lib);
glContext = new GLContextGLX(caps,
shareContext,
isOffscreen,
display,
drawable,
context,
deleteDrawable,
db,
pixmap,
libType);
if (!glContext->Init())
error = true;
} else {
@ -816,14 +838,14 @@ TRY_AGAIN_NO_SHARING:
#ifdef DEBUG
bool success =
#endif
sGLXLib.xMakeCurrent(mDisplay, None, nullptr);
mGLX->xMakeCurrent(mDisplay, None, nullptr);
NS_ABORT_IF_FALSE(success,
"glXMakeCurrent failed to release GL context before we call glXDestroyContext!");
sGLXLib.xDestroyContext(mDisplay, mContext);
mGLX->xDestroyContext(mDisplay, mContext);
if (mDeleteDrawable) {
sGLXLib.xDestroyPixmap(mDisplay, mDrawable);
mGLX->xDestroyPixmap(mDisplay, mDrawable);
}
}
@ -857,8 +879,8 @@ TRY_AGAIN_NO_SHARING:
// "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 || sGLXLib.xGetCurrentContext() != mContext) {
succeeded = sGLXLib.xMakeCurrent(mDisplay, mDrawable, mContext);
if (aForce || mGLX->xGetCurrentContext() != mContext) {
succeeded = mGLX->xMakeCurrent(mDisplay, mDrawable, mContext);
NS_ASSERTION(succeeded, "Failed to make GL context current!");
}
@ -866,7 +888,7 @@ TRY_AGAIN_NO_SHARING:
}
virtual bool IsCurrent() {
return sGLXLib.xGetCurrentContext() == mContext;
return mGLX->xGetCurrentContext() == mContext;
}
bool SetupLookupFunction()
@ -896,21 +918,21 @@ TRY_AGAIN_NO_SHARING:
bool SupportsRobustness()
{
return sGLXLib.HasRobustness();
return mGLX->HasRobustness();
}
bool SwapBuffers()
{
if (!mDoubleBuffered)
return false;
sGLXLib.xSwapBuffers(mDisplay, mDrawable);
sGLXLib.xWaitGL();
mGLX->xSwapBuffers(mDisplay, mDrawable);
mGLX->xWaitGL();
return true;
}
bool TextureImageSupportsGetBackingSurface()
{
return sGLXLib.UseTextureFromPixmap();
return mGLX->UseTextureFromPixmap();
}
virtual already_AddRefed<TextureImage>
@ -922,25 +944,27 @@ TRY_AGAIN_NO_SHARING:
private:
friend class GLContextProviderGLX;
GLContextGLX(const ContextFormat& aFormat,
GLContext *aShareContext,
GLContextGLX(const SurfaceCaps& caps,
GLContext* shareContext,
bool isOffscreen,
Display *aDisplay,
GLXDrawable aDrawable,
GLXContext aContext,
bool aDeleteDrawable,
bool aDoubleBuffered,
gfxXlibSurface *aPixmap,
LibType aLibType)
: GLContext(aFormat, aDeleteDrawable ? true : false, aShareContext),
LibType libType)
: GLContext(caps, shareContext, isOffscreen),//aDeleteDrawable ? true : false, aShareContext, ),
mContext(aContext),
mDisplay(aDisplay),
mDrawable(aDrawable),
mDeleteDrawable(aDeleteDrawable),
mDoubleBuffered(aDoubleBuffered),
mLibType(aLibType),
mPixmap(aPixmap),
sGLXLib(sGLXLibrary[aLibType])
mLibType(libType),
mGLX(&sGLXLibrary[libType]),
mPixmap(aPixmap)
{
MOZ_ASSERT(mGLX);
}
GLXContext mContext;
@ -948,10 +972,11 @@ private:
GLXDrawable mDrawable;
bool mDeleteDrawable;
bool mDoubleBuffered;
LibType mLibType;
GLXLibrary* mGLX;
nsRefPtr<gfxXlibSurface> mPixmap;
GLXLibrary& sGLXLib;
};
class TextureImageGLX : public TextureImage
@ -1090,7 +1115,7 @@ GLContextGLX::CreateTextureImage(const nsIntSize& aSize,
}
MakeCurrent();
GLXPixmap pixmap = sGLXLib.CreatePixmap(surface);
GLXPixmap pixmap = mGLX->CreatePixmap(surface);
NS_ASSERTION(pixmap, "Failed to create pixmap!");
GLuint texture;
@ -1141,7 +1166,8 @@ AreCompatibleVisuals(Visual *one, Visual *two)
already_AddRefed<GLContext>
GLContextProviderGLX::CreateForWindow(nsIWidget *aWidget)
{
if (!sDefGLXLib.EnsureInitialized(false)) {
const LibType libType = GLXLibrary::OPENGL_LIB;
if (!sDefGLXLib.EnsureInitialized(libType)) {
return nullptr;
}
@ -1225,24 +1251,24 @@ GLContextProviderGLX::CreateForWindow(nsIWidget *aWidget)
GLContextGLX *shareContext = GetGlobalContextGLX();
nsRefPtr<GLContextGLX> glContext = GLContextGLX::CreateGLContext(ContextFormat(ContextFormat::BasicRGB24),
SurfaceCaps caps = SurfaceCaps::Any();
nsRefPtr<GLContextGLX> glContext = GLContextGLX::CreateGLContext(caps,
shareContext,
false,
display,
window,
cfgs[matchIndex],
shareContext,
false,
GLXLibrary::OPENGL_LIB);
libType);
return glContext.forget();
}
static already_AddRefed<GLContextGLX>
CreateOffscreenPixmapContext(const gfxIntSize& aSize,
const ContextFormat& aFormat,
bool aShare, LibType aLibToUse)
CreateOffscreenPixmapContext(const gfxIntSize& size, LibType libToUse)
{
GLXLibrary& sGLXLib = sGLXLibrary[aLibToUse];
if (!sGLXLib.EnsureInitialized(aLibToUse == GLXLibrary::MESA_LLVMPIPE_LIB)) {
GLXLibrary& glx = sGLXLibrary[libToUse];
if (!glx.EnsureInitialized(libToUse)) {
return nullptr;
}
@ -1250,29 +1276,23 @@ CreateOffscreenPixmapContext(const gfxIntSize& aSize,
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 = sGLXLib.xChooseFBConfig(display,
xscreen,
attribs,
&numConfigs);
cfgs = glx.xChooseFBConfig(display,
xscreen,
attribs,
&numConfigs);
if (!cfgs) {
return nullptr;
}
NS_ASSERTION(numConfigs > 0,
"glXChooseFBConfig() failed to match our requested format and violated its spec (!)");
MOZ_ASSERT(numConfigs > 0,
"glXChooseFBConfig() failed to match our requested format and violated its spec!");
int visid = None;
int chosenIndex = 0;
@ -1280,12 +1300,12 @@ CreateOffscreenPixmapContext(const gfxIntSize& aSize,
for (int i = 0; i < numConfigs; ++i) {
int dtype;
if (sGLXLib.xGetFBConfigAttrib(display, cfgs[i], GLX_DRAWABLE_TYPE, &dtype) != Success
if (glx.xGetFBConfigAttrib(display, cfgs[i], GLX_DRAWABLE_TYPE, &dtype) != Success
|| !(dtype & GLX_PIXMAP_BIT))
{
continue;
}
if (sGLXLib.xGetFBConfigAttrib(display, cfgs[i], GLX_VISUAL_ID, &visid) != Success
if (glx.xGetFBConfigAttrib(display, cfgs[i], GLX_VISUAL_ID, &visid) != Success
|| visid == 0)
{
continue;
@ -1307,9 +1327,10 @@ CreateOffscreenPixmapContext(const gfxIntSize& aSize,
GLXPixmap glxpixmap = 0;
bool error = false;
gfxIntSize dummySize(16, 16);
nsRefPtr<gfxXlibSurface> xsurface = gfxXlibSurface::Create(DefaultScreenOfDisplay(display),
visual,
gfxIntSize(16, 16));
dummySize);
if (xsurface->CairoStatus() != 0) {
error = true;
goto DONE_CREATING_PIXMAP;
@ -1318,13 +1339,13 @@ CreateOffscreenPixmapContext(const gfxIntSize& aSize,
// Handle slightly different signature between glXCreatePixmap and
// its pre-GLX-1.3 extension equivalent (though given the ABI, we
// might not need to).
if (sGLXLib.GLXVersionCheck(1, 3)) {
glxpixmap = sGLXLib.xCreatePixmap(display,
if (glx.GLXVersionCheck(1, 3)) {
glxpixmap = glx.xCreatePixmap(display,
cfgs[chosenIndex],
xsurface->XDrawable(),
NULL);
} else {
glxpixmap = sGLXLib.xCreateGLXPixmapWithConfig(display,
glxpixmap = glx.xCreateGLXPixmapWithConfig(display,
cfgs[chosenIndex],
xsurface->
XDrawable());
@ -1341,68 +1362,65 @@ DONE_CREATING_PIXMAP:
if (!error && // earlier recorded error
!serverError)
{
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);
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);
}
return glContext.forget();
}
already_AddRefed<GLContext>
GLContextProviderGLX::CreateOffscreen(const gfxIntSize& aSize,
const ContextFormat& aFormat,
const ContextFlags aFlag)
GLContextProviderGLX::CreateOffscreen(const gfxIntSize& size,
const SurfaceCaps& caps,
ContextFlags flags)
{
gCurrLib = GLXLibrary::SelectLibrary(aFlag);
LibType libType = GLXLibrary::SelectLibrary(flags);
gCurrLib = libType;
gfxIntSize dummySize = gfxIntSize(16, 16);
nsRefPtr<GLContextGLX> glContext =
CreateOffscreenPixmapContext(aSize, aFormat, true, gCurrLib);
CreateOffscreenPixmapContext(dummySize, libType);
if (!glContext) {
if (!glContext)
return nullptr;
}
if (!glContext->GetSharedContext()) {
// no point in returning anything if sharing failed, we can't
// render from this
if (!glContext->InitOffscreen(size, caps))
return nullptr;
}
if (!glContext->ResizeOffscreenFBOs(aSize, true)) {
// we weren't able to create the initial
// offscreen FBO, so this is dead
return nullptr;
}
return glContext.forget();
}
static nsRefPtr<GLContext> gGlobalContext[GLXLibrary::LIBS_MAX];
GLContext *
GLContext*
GLContextProviderGLX::GetGlobalContext(const ContextFlags aFlag)
{
LibType libToUse = GLXLibrary::SelectLibrary(aFlag);
LibType libType = GLXLibrary::SelectLibrary(aFlag);
static bool triedToCreateContext[GLXLibrary::LIBS_MAX] = {false, false};
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);
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);
}
return gGlobalContext[libToUse];
return gGlobalContext[libType];
}
void

View File

@ -15,6 +15,7 @@ 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,
@ -37,14 +38,13 @@ public:
* @return Context to use for the window
*/
static already_AddRefed<GLContext>
CreateForWindow(nsIWidget *aWidget);
CreateForWindow(nsIWidget* widget);
/**
* 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 not bind framebuffer 0 directly, and instead should bind
* the framebuffer returned by GetOffscreenFBO().
* should bind framebuffer 0 directly to use this offscreen buffer.
*
* The offscreen context returned by this method will always have
* the ability to be rendered into a context created by a window.
@ -59,15 +59,15 @@ public:
* @return Context to use for offscreen rendering
*/
static already_AddRefed<GLContext>
CreateOffscreen(const gfxIntSize& aSize,
const ContextFormat& aFormat = ContextFormat::BasicRGBA32Format,
const ContextFlags aFlags = GLContext::ContextFlagsNone);
CreateOffscreen(const gfxIntSize& size,
const SurfaceCaps& caps,
ContextFlags flags = GLContext::ContextFlagsNone);
/**
* Get a pointer to the global context, creating it if it doesn't exist.
*/
static GLContext *
GetGlobalContext( const ContextFlags aFlags = GLContext::ContextFlagsNone);
static GLContext*
GetGlobalContext(ContextFlags flags = GLContext::ContextFlagsNone);
/**
* Free any resources held by this Context Provider.

View File

@ -16,14 +16,14 @@ GLContextProviderNull::CreateForWindow(nsIWidget*)
already_AddRefed<GLContext>
GLContextProviderNull::CreateOffscreen(const gfxIntSize&,
const ContextFormat&,
const ContextFlags)
const SurfaceCaps&,
ContextFlags)
{
return nullptr;
}
GLContext *
GLContextProviderNull::GetGlobalContext()
GLContext*
GLContextProviderNull::GetGlobalContext(ContextFlags)
{
return nullptr;
}

View File

@ -20,6 +20,8 @@
#include "mozilla/Preferences.h"
using namespace mozilla::gfx;
namespace mozilla {
namespace gl {
@ -252,14 +254,15 @@ WGLLibrary::EnsureInitialized(bool aUseMesaLlvmPipe)
class GLContextWGL : public GLContext
{
public:
GLContextWGL(const ContextFormat& aFormat,
GLContext *aSharedContext,
// From Window: (possibly for offscreen!)
GLContextWGL(const SurfaceCaps& caps,
GLContext* sharedContext,
bool isOffscreen,
HDC aDC,
HGLRC aContext,
LibType aLibUsed,
HWND aWindow = nullptr,
bool aIsOffscreen = false)
: GLContext(aFormat, aIsOffscreen, aSharedContext),
HWND aWindow = nullptr)
: GLContext(caps, sharedContext, isOffscreen),
mDC(aDC),
mContext(aContext),
mWnd(aWindow),
@ -270,14 +273,16 @@ public:
{
}
GLContextWGL(const ContextFormat& aFormat,
GLContext *aSharedContext,
// From PBuffer
GLContextWGL(const SurfaceCaps& caps,
GLContext* sharedContext,
bool isOffscreen,
HANDLE aPbuffer,
HDC aDC,
HGLRC aContext,
int aPixelFormat,
LibType aLibUsed)
: GLContext(aFormat, true, aSharedContext),
: GLContext(caps, sharedContext, isOffscreen),
mDC(aDC),
mContext(aContext),
mWnd(NULL),
@ -374,8 +379,6 @@ public:
}
}
bool BindTex2DOffscreen(GLContext *aOffscreen);
void UnbindTex2DOffscreen(GLContext *aOffscreen);
bool ResizeOffscreen(const gfxIntSize& aNewSize);
HGLRC Context() { return mContext; }
@ -392,63 +395,6 @@ protected:
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)
@ -485,43 +431,7 @@ IsValidSizeForFormat(HDC hDC, int format,
bool
GLContextWGL::ResizeOffscreen(const gfxIntSize& 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);
return ResizeScreenBuffer(aNewSize);
}
static GLContextWGL *
@ -587,8 +497,13 @@ GLContextProviderWGL::CreateForWindow(nsIWidget *aWidget)
return nullptr;
}
nsRefPtr<GLContextWGL> glContext = new GLContextWGL(ContextFormat(ContextFormat::BasicRGB24),
shareContext, dc, context, libToUse);
SurfaceCaps caps = SurfaceCaps::ForRGBA();
nsRefPtr<GLContextWGL> glContext = new GLContextWGL(caps,
shareContext,
false,
dc,
context,
libToUse);
if (!glContext->Init()) {
return nullptr;
}
@ -600,9 +515,10 @@ GLContextProviderWGL::CreateForWindow(nsIWidget *aWidget)
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)
@ -614,83 +530,65 @@ CreatePBufferOffscreenContext(const gfxIntSize& aSize,
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);
UINT numFormats = 256;
int formats[256];
#undef A1
#undef A2
if (!sWGLLib[aLibToUse].fChoosePixelFormat(sWGLLib[aLibToUse].GetWindowDC(),
attrs.Elements(), NULL,
numFormats, formats, &numFormats)
// We only need one!
UINT numFormats = 1;
int formats[1];
HDC windowDC = wgl.GetWindowDC();
if (!wgl.fChoosePixelFormat(windowDC,
attrs.Elements(), NULL,
numFormats, formats, &numFormats)
|| numFormats == 0)
{
return nullptr;
}
// XXX add back the priority choosing code here
// We don't care; just pick the first one.
int chosenFormat = formats[0];
if (!IsValidSizeForFormat(sWGLLib[aLibToUse].GetWindowDC(), chosenFormat, aSize, aLibToUse))
if (!IsValidSizeForFormat(windowDC, chosenFormat, aSize, aLibToUse))
return nullptr;
HANDLE pbuffer = sWGLLib[aLibToUse].fCreatePbuffer(sWGLLib[aLibToUse].GetWindowDC(), chosenFormat,
aSize.width, aSize.height,
pbattrs.Elements());
HANDLE pbuffer = wgl.fCreatePbuffer(windowDC, chosenFormat,
aSize.width, aSize.height,
pbattrs.Elements());
if (!pbuffer) {
return nullptr;
}
HDC pbdc = sWGLLib[aLibToUse].fGetPbufferDC(pbuffer);
HDC pbdc = wgl.fGetPbufferDC(pbuffer);
NS_ASSERTION(pbdc, "expected a dc");
HGLRC context;
if (sWGLLib[aLibToUse].HasRobustness()) {
if (wgl.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 = sWGLLib[aLibToUse].fCreateContextAttribs(pbdc, nullptr, attribs);
context = wgl.fCreateContextAttribs(pbdc, nullptr, attribs);
} else {
context = sWGLLib[aLibToUse].fCreateContext(pbdc);
context = wgl.fCreateContext(pbdc);
}
if (!context) {
sWGLLib[aLibToUse].fDestroyPbuffer(pbuffer);
wgl.fDestroyPbuffer(pbuffer);
return nullptr;
}
nsRefPtr<GLContextWGL> glContext = new GLContextWGL(aFormat,
nullptr,
SurfaceCaps dummyCaps = SurfaceCaps::Any();
nsRefPtr<GLContextWGL> glContext = new GLContextWGL(dummyCaps,
nullptr, true,
pbuffer,
pbdc,
context,
@ -701,8 +599,7 @@ CreatePBufferOffscreenContext(const gfxIntSize& aSize,
}
static already_AddRefed<GLContextWGL>
CreateWindowOffscreenContext(const ContextFormat& aFormat,
const GLContext::ContextFlags aFlags)
CreateWindowOffscreenContext(GLContext::ContextFlags aFlags)
{
// CreateWindowOffscreenContext must return a global-shared context
GLContextWGL *shareContext = GetGlobalContextWGL(aFlags);
@ -743,19 +640,21 @@ CreateWindowOffscreenContext(const ContextFormat& aFormat,
return nullptr;
}
nsRefPtr<GLContextWGL> glContext = new GLContextWGL(aFormat, shareContext,
dc, context, libToUse,
win, true);
SurfaceCaps caps = SurfaceCaps::ForRGBA();
nsRefPtr<GLContextWGL> glContext = new GLContextWGL(caps,
shareContext, true,
dc, context,
libToUse, win);
return glContext.forget();
}
already_AddRefed<GLContext>
GLContextProviderWGL::CreateOffscreen(const gfxIntSize& aSize,
const ContextFormat& aFormat,
const ContextFlags aFlags)
GLContextProviderWGL::CreateOffscreen(const gfxIntSize& size,
const SurfaceCaps& caps,
ContextFlags flags)
{
LibType libToUse = WGLLibrary::SelectLibrary(aFlags);
LibType libToUse = WGLLibrary::SelectLibrary(flags);
if (!sWGLLib[libToUse].EnsureInitialized(libToUse == WGLLibrary::MESA_LLVMPIPE_LIB)) {
return nullptr;
@ -765,18 +664,16 @@ GLContextProviderWGL::CreateOffscreen(const gfxIntSize& aSize,
// Always try to create a pbuffer context first, because we
// want the context isolation.
NS_ENSURE_TRUE(Preferences::GetRootBranch(), nullptr);
const bool preferFBOs = Preferences::GetBool("wgl.prefer-fbo", false);
if (!preferFBOs &&
sWGLLib[libToUse].fCreatePbuffer &&
if (sWGLLib[libToUse].fCreatePbuffer &&
sWGLLib[libToUse].fChoosePixelFormat)
{
glContext = CreatePBufferOffscreenContext(aSize, aFormat,libToUse);
gfxIntSize dummySize = gfxIntSize(16, 16);
glContext = CreatePBufferOffscreenContext(dummySize, libToUse);
}
// If it failed, then create a window context and use a FBO.
if (!glContext) {
glContext = CreateWindowOffscreenContext(aFormat, aFlags);
glContext = CreateWindowOffscreenContext(flags);
}
if (!glContext ||
@ -785,21 +682,18 @@ GLContextProviderWGL::CreateOffscreen(const gfxIntSize& aSize,
return nullptr;
}
if (!glContext->ResizeOffscreenFBOs(aSize, !glContext->mPBuffer))
if (!glContext->InitOffscreen(size, caps))
return nullptr;
glContext->mOffscreenSize = aSize;
glContext->mOffscreenActualSize = aSize;
return glContext.forget();
}
static nsRefPtr<GLContextWGL> gGlobalContext[WGLLibrary::LIBS_MAX];
GLContext *
GLContextProviderWGL::GetGlobalContext(const ContextFlags aFlags)
GLContextProviderWGL::GetGlobalContext(const ContextFlags flags)
{
LibType libToUse = WGLLibrary::SelectLibrary(aFlags);
LibType libToUse = WGLLibrary::SelectLibrary(flags);
if (!sWGLLib[libToUse].EnsureInitialized(libToUse == WGLLibrary::MESA_LLVMPIPE_LIB)) {
return nullptr;
@ -811,11 +705,12 @@ GLContextProviderWGL::GetGlobalContext(const ContextFlags aFlags)
triedToCreateContext[libToUse] = true;
// conveniently, we already have what we need...
gGlobalContext[libToUse] = new GLContextWGL(ContextFormat(ContextFormat::BasicRGB24),
nullptr,
sWGLLib[libToUse].GetWindowDC(),
sWGLLib[libToUse].GetWindowGLContext(),
libToUse);
SurfaceCaps dummyCaps = SurfaceCaps::Any();
gGlobalContext[libToUse] = new GLContextWGL(dummyCaps,
nullptr, true,
sWGLLib[libToUse].GetWindowDC(),
sWGLLib[libToUse].GetWindowGLContext(),
libToUse);
if (!gGlobalContext[libToUse]->Init()) {
NS_WARNING("Global context GLContext initialization failed?");
gGlobalContext[libToUse] = nullptr;

View File

@ -377,6 +377,8 @@ struct GLContextSymbols
// OES_egl_image
typedef void (GLAPIENTRY * PFNGLEGLIMAGETARGETTEXTURE2D)(GLenum target, GLeglImage image);
PFNGLEGLIMAGETARGETTEXTURE2D fEGLImageTargetTexture2D;
typedef void (GLAPIENTRY * PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGE)(GLenum target, GLeglImage image);
PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGE fEGLImageTargetRenderbufferStorage;
};
}

19
gfx/gl/GLContextTypes.cpp Normal file
View File

@ -0,0 +1,19 @@
/* -*- 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));
}

View File

@ -3,13 +3,9 @@
* 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 GLCONTEXTSTUFF_H_
#define GLCONTEXTSTUFF_H_
#ifndef GLCONTEXT_TYPES_H_
#define GLCONTEXT_TYPES_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;
@ -36,7 +32,39 @@ enum ShaderProgramType {
NumProgramTypes
};
} // namespace gl
} // namespace mozilla
struct GLFormats
{
// Constructs a zeroed object:
GLFormats();
#endif /* GLCONTEXTSTUFF_H_ */
GLenum color_texInternalFormat;
GLenum color_texFormat;
GLenum color_texType;
GLenum color_rbFormat;
GLenum depthStencil;
GLenum depth;
GLenum stencil;
GLsizei samples;
};
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_ */

View File

@ -27,6 +27,12 @@ void main(void) { \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\
@ -220,11 +226,11 @@ GLContext::BlitFramebufferToFramebuffer(GLuint srcFB, GLuint destFB,
MOZ_ASSERT(IsExtensionSupported(EXT_framebuffer_blit) ||
IsExtensionSupported(ANGLE_framebuffer_blit));
ScopedFramebufferBinding boundFB(this);
ScopedBindFramebuffer boundFB(this);
ScopedGLState scissor(this, LOCAL_GL_SCISSOR_TEST, false);
BindUserReadFBO(srcFB);
BindUserDrawFBO(destFB);
BindReadFB(srcFB);
BindDrawFB(destFB);
fBlitFramebuffer(0, 0, srcSize.width, srcSize.height,
0, 0, destSize.width, destSize.height,
@ -232,6 +238,32 @@ GLContext::BlitFramebufferToFramebuffer(GLuint srcFB, GLuint destFB,
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,
@ -243,7 +275,7 @@ GLContext::BlitTextureToFramebuffer(GLuint srcTex, GLuint destFB,
if (IsExtensionSupported(EXT_framebuffer_blit) ||
IsExtensionSupported(ANGLE_framebuffer_blit))
{
ScopedFramebufferTexture srcWrapper(this, srcTex);
ScopedFramebufferForTexture srcWrapper(this, srcTex);
MOZ_ASSERT(srcWrapper.IsComplete());
BlitFramebufferToFramebuffer(srcWrapper.FB(), destFB,
@ -252,7 +284,7 @@ GLContext::BlitTextureToFramebuffer(GLuint srcTex, GLuint destFB,
}
ScopedFramebufferBinding boundFB(this, destFB);
ScopedBindFramebuffer boundFB(this, destFB);
GLuint boundTexUnit = 0;
GetUIntegerv(LOCAL_GL_ACTIVE_TEXTURE, &boundTexUnit);
@ -370,27 +402,21 @@ GLContext::BlitFramebufferToTexture(GLuint srcFB, GLuint destTex,
if (IsExtensionSupported(EXT_framebuffer_blit) ||
IsExtensionSupported(ANGLE_framebuffer_blit))
{
ScopedFramebufferTexture destWrapper(this, destTex);
MOZ_ASSERT(destWrapper.IsComplete());
ScopedFramebufferForTexture destWrapper(this, destTex);
BlitFramebufferToFramebuffer(srcFB, destWrapper.FB(),
srcSize, destSize);
return;
}
GLuint boundTex = 0;
GetUIntegerv(LOCAL_GL_TEXTURE_BINDING_2D, &boundTex);
fBindTexture(LOCAL_GL_TEXTURE_2D, destTex);
ScopedFramebufferBinding boundFB(this, srcFB);
ScopedBindTexture autoTex(this, destTex);
ScopedBindFramebuffer 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
@ -403,8 +429,7 @@ GLContext::BlitTextureToTexture(GLuint srcTex, GLuint destTex,
if (mTexBlit_UseDrawNotCopy) {
// Draw is texture->framebuffer
ScopedFramebufferTexture destWrapper(this, destTex);
MOZ_ASSERT(destWrapper.IsComplete());
ScopedFramebufferForTexture destWrapper(this, destTex);
BlitTextureToFramebuffer(srcTex, destWrapper.FB(),
srcSize, destSize);
@ -412,8 +437,7 @@ GLContext::BlitTextureToTexture(GLuint srcTex, GLuint destTex,
}
// Generally, just use the CopyTexSubImage path
ScopedFramebufferTexture srcWrapper(this, srcTex);
MOZ_ASSERT(srcWrapper.IsComplete());
ScopedFramebufferForTexture srcWrapper(this, srcTex);
BlitFramebufferToTexture(srcWrapper.FB(), destTex,
srcSize, destSize);

View File

@ -47,6 +47,27 @@ 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
@ -3275,6 +3296,9 @@ typedef void* GLeglImage;
// 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
@ -3292,4 +3316,10 @@ typedef void* GLeglImage;
#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

View File

@ -10,6 +10,7 @@
#include "nsDirectoryServiceUtils.h"
#include "nsPrintfCString.h"
#include "prenv.h"
#include "GLContext.h"
namespace mozilla {
namespace gl {
@ -256,6 +257,30 @@ GLLibraryEGL::EnsureInitialized()
}
}
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;
@ -289,37 +314,6 @@ GLLibraryEGL::InitExtensions()
#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)
{

View File

@ -14,18 +14,6 @@
#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)
@ -56,6 +44,10 @@ typedef void *EGLNativeWindowType;
// 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
@ -64,12 +56,6 @@ typedef void *EGLNativeWindowType;
#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 {
@ -455,7 +441,6 @@ public:
}
bool EnsureInitialized();
void LoadConfigSensitiveSymbols();
void DumpEGLConfig(EGLConfig cfg);
void DumpEGLConfigs();

619
gfx/gl/GLScreenBuffer.cpp Normal file
View File

@ -0,0 +1,619 @@
/* -*- 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 */

296
gfx/gl/GLScreenBuffer.h Normal file
View File

@ -0,0 +1,296 @@
/* -*- 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_

View File

@ -87,7 +87,7 @@ public:
Bool direct,
const int* attrib_list);
bool EnsureInitialized(bool aUseMesaLLVMPipe);
bool EnsureInitialized(LibraryType libType);
GLXPixmap CreatePixmap(gfxASurface* aSurface);
void DestroyPixmap(GLXPixmap aPixmap);

View File

@ -2,42 +2,50 @@
# 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 = \
GLDefs.h \
GLContext.h \
GLContextTypes.h \
GLContextSymbols.h \
GLContextProvider.h \
GLContextProviderImpl.h \
GLLibraryLoader.h \
ForceDiscreteGPUHelperCGL.h \
GLTextureImage.h \
$(NULL)
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)
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)
@ -45,11 +53,18 @@ endif
endif
CPPSRCS = \
GLContext.cpp \
GLContextUtils.cpp \
GLLibraryLoader.cpp \
GLTextureImage.cpp \
$(NULL)
GLContext.cpp \
GLContextTypes.cpp \
GLContextUtils.cpp \
GLLibraryLoader.cpp \
GLScreenBuffer.cpp \
GLTextureImage.cpp \
SharedSurface.cpp \
SharedSurfaceEGL.cpp \
SharedSurfaceGL.cpp \
SurfaceFactory.cpp \
SurfaceStream.cpp \
$(NULL)
GL_PROVIDER = Null
@ -107,9 +122,15 @@ endif
# Win32 is a special snowflake, for ANGLE
ifeq ($(MOZ_WIDGET_TOOLKIT),windows)
EXPORTS += \
SharedSurfaceANGLE.h \
$(NULL)
CPPSRCS += \
GLContextProviderEGL.cpp \
GLLibraryEGL.cpp
GLContextProviderEGL.cpp \
GLLibraryEGL.cpp \
SharedSurfaceANGLE.cpp \
$(NULL)
endif
ifdef MOZ_ANDROID_OMTC
@ -121,4 +142,4 @@ 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)

29
gfx/gl/SharedSurface.cpp Normal file
View File

@ -0,0 +1,29 @@
/* -*- 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 */

122
gfx/gl/SharedSurface.h Normal file
View File

@ -0,0 +1,122 @@
/* -*- 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_ */

View File

@ -0,0 +1,275 @@
/* -*- 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 */

115
gfx/gl/SharedSurfaceANGLE.h Normal file
View File

@ -0,0 +1,115 @@
/* -*- 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_ */

262
gfx/gl/SharedSurfaceEGL.cpp Normal file
View File

@ -0,0 +1,262 @@
/* -*- 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 */

135
gfx/gl/SharedSurfaceEGL.h Normal file
View File

@ -0,0 +1,135 @@
/* -*- 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_ */

390
gfx/gl/SharedSurfaceGL.cpp Normal file
View File

@ -0,0 +1,390 @@
/* -*- 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,
size,
hasAlpha)
, mTex(tex)
{
mData = new gfxImageSurface(size, format);
}
SharedSurface_Basic::~SharedSurface_Basic()
{
if (!mGL->MakeCurrent())
return;
GLuint tex = mTex;
mGL->fDeleteTextures(1, &tex);
}
void
SharedSurface_Basic::Fence()
{
MOZ_ASSERT(mData->GetSize() == mGL->OffscreenSize());
mGL->MakeCurrent();
mData->Flush();
mGL->ReadScreenIntoImageSurface(mData);
mData->MarkDirty();
}
SharedSurface_GLTexture*
SharedSurface_GLTexture::Create(GLContext* prodGL,
GLContext* consGL,
const GLFormats& formats,
const gfxIntSize& size,
bool hasAlpha)
{
MOZ_ASSERT(prodGL && consGL);
MOZ_ASSERT(prodGL->SharesWith(consGL));
prodGL->MakeCurrent();
GLuint tex = prodGL->CreateTextureForOffscreen(formats, size);
return new SharedSurface_GLTexture(prodGL, consGL, size, hasAlpha, tex);
}
SharedSurface_GLTexture::~SharedSurface_GLTexture()
{
if (!mGL->MakeCurrent())
return;
GLuint tex = mTex;
mGL->fDeleteTextures(1, &tex);
if (mSync) {
mGL->fDeleteSync(mSync);
}
}
void
SharedSurface_GLTexture::Fence()
{
mGL->MakeCurrent();
if (mGL->IsExtensionSupported(GLContext::ARB_sync)) {
if (mSync) {
mGL->fDeleteSync(mSync);
mSync = 0;
}
mSync = mGL->fFenceSync(LOCAL_GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
if (mSync) {
mGL->fFlush();
return;
}
}
MOZ_ASSERT(!mSync);
mGL->fFinish();
}
bool
SharedSurface_GLTexture::WaitSync()
{
if (!mSync) {
// We must have used glFinish instead of glFenceSync.
return true;
}
MOZ_ASSERT(mGL->IsExtensionSupported(GLContext::ARB_sync));
GLuint64 waitMS = 500;
const GLuint64 nsPerMS = 1000 * 1000;
GLuint64 waitNS = waitMS * nsPerMS;
GLenum status = mGL->fClientWaitSync(mSync,
0,
waitNS);
if (status != LOCAL_GL_CONDITION_SATISFIED &&
status != LOCAL_GL_ALREADY_SIGNALED)
{
return false;
}
mGL->fDeleteSync(mSync);
mSync = 0;
return true;
}
} /* namespace gfx */
} /* namespace mozilla */

254
gfx/gl/SharedSurfaceGL.h Normal file
View File

@ -0,0 +1,254 @@
/* -*- 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_GL_H_
#define SHARED_SURFACE_GL_H_
#include "SharedSurface.h"
#include "SurfaceFactory.h"
#include "SurfaceTypes.h"
#include "GLContextTypes.h"
#include "nsAutoPtr.h"
#include "gfxASurface.h"
#include <queue>
// Forwards:
class gfxImageSurface;
namespace mozilla {
namespace gl {
class GLContext;
}
}
namespace mozilla {
namespace gl {
class SurfaceFactory_GL;
class SharedSurface_GL
: public gfx::SharedSurface
{
protected:
typedef class gfx::SharedSurface SharedSurface;
typedef gfx::SharedSurfaceType SharedSurfaceType;
typedef gfx::APITypeT APITypeT;
typedef gfx::AttachmentType AttachmentType;
GLContext* const mGL;
SharedSurface_GL(SharedSurfaceType type,
AttachmentType attachType,
GLContext* gl,
const gfxIntSize& size,
bool hasAlpha)
: SharedSurface(type, APITypeT::OpenGL, attachType, size, hasAlpha)
, mGL(gl)
{}
public:
static void Copy(SharedSurface_GL* src, SharedSurface_GL* dest,
SurfaceFactory_GL* factory);
static SharedSurface_GL* Cast(SharedSurface* surf) {
MOZ_ASSERT(surf->APIType() == APITypeT::OpenGL);
return (SharedSurface_GL*)surf;
}
virtual void LockProd();
virtual void UnlockProd();
GLContext* GL() const {
return mGL;
}
};
class SurfaceFactory_GL
: public gfx::SurfaceFactory
{
protected:
typedef struct gfx::SurfaceCaps SurfaceCaps;
typedef class gfx::SurfaceFactory SurfaceFactory;
typedef class gfx::SharedSurface SharedSurface;
typedef gfx::SharedSurfaceType SharedSurfaceType;
GLContext* const mGL;
const GLFormats mFormats;
SurfaceCaps mDrawCaps;
SurfaceCaps mReadCaps;
// This uses ChooseBufferBits to pick drawBits/readBits.
SurfaceFactory_GL(GLContext* gl,
SharedSurfaceType type,
const SurfaceCaps& caps);
virtual void ChooseBufferBits(const SurfaceCaps& caps,
SurfaceCaps& drawCaps,
SurfaceCaps& readCaps) const;
public:
GLContext* GL() const {
return mGL;
}
const GLFormats& Formats() const {
return mFormats;
}
const SurfaceCaps& DrawCaps() const {
return mDrawCaps;
}
const SurfaceCaps& ReadCaps() const {
return mReadCaps;
}
};
// For readback and bootstrapping:
class SharedSurface_Basic
: public SharedSurface_GL
{
public:
static SharedSurface_Basic* Create(GLContext* gl,
const GLFormats& formats,
const gfxIntSize& size,
bool hasAlpha);
static SharedSurface_Basic* Cast(SharedSurface* surf) {
MOZ_ASSERT(surf->Type() == SharedSurfaceType::Basic);
return (SharedSurface_Basic*)surf;
}
protected:
const GLuint mTex;
nsRefPtr<gfxImageSurface> mData;
SharedSurface_Basic(GLContext* gl,
const gfxIntSize& size,
bool hasAlpha,
gfxASurface::gfxImageFormat format,
GLuint tex);
public:
virtual ~SharedSurface_Basic();
virtual void LockProdImpl() {}
virtual void UnlockProdImpl() {}
virtual void Fence();
virtual bool WaitSync() {
// Since we already store the data in Fence, we're always done already.
return true;
}
virtual GLuint Texture() const {
return mTex;
}
// Implementation-specific functions below:
gfxImageSurface* GetData() {
return mData;
}
};
class SurfaceFactory_Basic
: public SurfaceFactory_GL
{
public:
SurfaceFactory_Basic(GLContext* gl, const SurfaceCaps& caps)
: SurfaceFactory_GL(gl, SharedSurfaceType::Basic, caps)
{}
virtual SharedSurface* CreateShared(const gfxIntSize& size) {
bool hasAlpha = mReadCaps.alpha;
return SharedSurface_Basic::Create(mGL, mFormats, size, hasAlpha);
}
};
// Using shared GL textures:
class SharedSurface_GLTexture
: public SharedSurface_GL
{
public:
static SharedSurface_GLTexture* Create(GLContext* prodGL,
GLContext* consGL,
const GLFormats& formats,
const gfxIntSize& size,
bool hasAlpha);
static SharedSurface_GLTexture* Cast(SharedSurface* surf) {
MOZ_ASSERT(surf->Type() == SharedSurfaceType::GLTextureShare);
return (SharedSurface_GLTexture*)surf;
}
protected:
GLContext* const mConsGL;
const GLuint mTex;
GLsync mSync;
SharedSurface_GLTexture(GLContext* prodGL,
GLContext* consGL,
const gfxIntSize& size,
bool hasAlpha,
GLuint tex)
: SharedSurface_GL(SharedSurfaceType::GLTextureShare,
AttachmentType::GLTexture,
prodGL,
size,
hasAlpha)
, mConsGL(consGL)
, mTex(tex)
, mSync(0)
{
}
public:
virtual ~SharedSurface_GLTexture();
virtual void LockProdImpl() {}
virtual void UnlockProdImpl() {}
virtual void Fence();
virtual bool WaitSync();
virtual GLuint Texture() const {
return mTex;
}
};
class SurfaceFactory_GLTexture
: public SurfaceFactory_GL
{
protected:
GLContext* const mConsGL;
public:
SurfaceFactory_GLTexture(GLContext* prodGL,
GLContext* consGL,
const SurfaceCaps& caps)
: SurfaceFactory_GL(prodGL, SharedSurfaceType::GLTextureShare, caps)
, mConsGL(consGL)
{}
virtual SharedSurface* CreateShared(const gfxIntSize& size) {
bool hasAlpha = mReadCaps.alpha;
return SharedSurface_GLTexture::Create(mGL, mConsGL, mFormats, size, hasAlpha);
}
};
} /* namespace gfx */
} /* namespace mozilla */
#endif /* SHARED_SURFACE_GL_H_ */

59
gfx/gl/SurfaceFactory.cpp Normal file
View File

@ -0,0 +1,59 @@
/* -*- 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 "SurfaceFactory.h"
#include "SharedSurface.h"
namespace mozilla {
namespace gfx {
SurfaceFactory::~SurfaceFactory()
{
while (!mScraps.empty()) {
SharedSurface* cur = mScraps.front();
mScraps.pop();
delete cur;
}
}
SharedSurface*
SurfaceFactory::NewSharedSurface(const gfxIntSize& size)
{
// Attempt to reuse an old surface.
while (!mScraps.empty()) {
SharedSurface* cur = mScraps.front();
mScraps.pop();
if (cur->Size() == size)
return cur;
// Destroy old surfaces of the wrong size.
delete cur;
}
SharedSurface* ret = CreateShared(size);
return ret;
}
// Auto-deletes surfs of the wrong type.
void
SurfaceFactory::Recycle(SharedSurface*& surf)
{
if (!surf)
return;
if (surf->Type() == mType) {
mScraps.push(surf);
} else {
delete surf;
}
surf = nullptr;
}
} /* namespace gfx */
} /* namespace mozilla */

55
gfx/gl/SurfaceFactory.h Normal file
View File

@ -0,0 +1,55 @@
/* -*- 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 SURFACE_FACTORY_H_
#define SURFACE_FACTORY_H_
#include <queue>
#include "SurfaceTypes.h"
#include "gfxPoint.h"
namespace mozilla {
namespace gfx {
// Forward:
class SharedSurface;
class SurfaceFactory
{
protected:
SurfaceCaps mCaps;
SharedSurfaceType mType;
SurfaceFactory(SharedSurfaceType type, const SurfaceCaps& caps)
: mCaps(caps)
, mType(type)
{}
public:
virtual ~SurfaceFactory();
protected:
virtual SharedSurface* CreateShared(const gfxIntSize& size) = 0;
std::queue<SharedSurface*> mScraps;
public:
SharedSurface* NewSharedSurface(const gfxIntSize& size);
// Auto-deletes surfs of the wrong type.
void Recycle(SharedSurface*& surf);
const SurfaceCaps& Caps() const {
return mCaps;
}
SharedSurfaceType Type() const {
return mType;
}
};
} // namespace gfx
} // namespace mozilla
#endif // SURFACE_FACTORY_H_

413
gfx/gl/SurfaceStream.cpp Normal file
View File

@ -0,0 +1,413 @@
/* -*- 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 "SurfaceStream.h"
#include "gfxPoint.h"
#include "SharedSurface.h"
#include "SurfaceFactory.h"
namespace mozilla {
namespace gfx {
SurfaceStreamType
SurfaceStream::ChooseGLStreamType(SurfaceStream::OMTC omtc,
bool preserveBuffer)
{
if (omtc == SurfaceStream::OMTC::OffMainThread) {
if (preserveBuffer)
return SurfaceStreamType::TripleBuffer_Copy;
else
return SurfaceStreamType::TripleBuffer;
} else {
if (preserveBuffer)
return SurfaceStreamType::SingleBuffer;
else
return SurfaceStreamType::TripleBuffer;
}
}
SurfaceStream*
SurfaceStream::CreateForType(SurfaceStreamType type, SurfaceStream* prevStream)
{
switch (type) {
case SurfaceStreamType::SingleBuffer:
return new SurfaceStream_SingleBuffer(prevStream);
case SurfaceStreamType::TripleBuffer_Copy:
return new SurfaceStream_TripleBuffer_Copy(prevStream);
case SurfaceStreamType::TripleBuffer:
return new SurfaceStream_TripleBuffer(prevStream);
default:
MOZ_NOT_REACHED("Invalid Type.");
return nullptr;
}
}
void
SurfaceStream::New(SurfaceFactory* factory, const gfxIntSize& size,
SharedSurface*& surf)
{
MOZ_ASSERT(!surf);
surf = factory->NewSharedSurface(size);
if (surf)
mSurfaces.insert(surf);
}
void
SurfaceStream::Recycle(SurfaceFactory* factory, SharedSurface*& surf)
{
if (surf) {
mSurfaces.erase(surf);
factory->Recycle(surf);
}
MOZ_ASSERT(!surf);
}
void
SurfaceStream::Delete(SharedSurface*& surf)
{
if (surf) {
mSurfaces.erase(surf);
delete surf;
surf = nullptr;
}
MOZ_ASSERT(!surf);
}
SharedSurface*
SurfaceStream::Surrender(SharedSurface*& surf)
{
SharedSurface* ret = surf;
if (surf) {
mSurfaces.erase(surf);
surf = nullptr;
}
MOZ_ASSERT(!surf);
return ret;
}
SharedSurface*
SurfaceStream::Absorb(SharedSurface*& surf)
{
SharedSurface* ret = surf;
if (surf) {
mSurfaces.insert(surf);
surf = nullptr;
}
MOZ_ASSERT(!surf);
return ret;
}
void
SurfaceStream::Scrap(SharedSurface*& scrap)
{
if (scrap) {
mScraps.push(scrap);
scrap = nullptr;
}
MOZ_ASSERT(!scrap);
}
void
SurfaceStream::RecycleScraps(SurfaceFactory* factory)
{
while (!mScraps.empty()) {
SharedSurface* cur = mScraps.top();
mScraps.pop();
Recycle(factory, cur);
}
}
SurfaceStream::~SurfaceStream()
{
Delete(mProducer);
while (!mScraps.empty()) {
SharedSurface* cur = mScraps.top();
mScraps.pop();
Delete(cur);
}
MOZ_ASSERT(mSurfaces.empty());
}
SharedSurface*
SurfaceStream::SwapConsumer()
{
MOZ_ASSERT(mIsAlive);
SharedSurface* ret = SwapConsumer_NoWait();
if (!ret)
return nullptr;
if (!ret->WaitSync()) {
return nullptr;
}
return ret;
}
SurfaceStream_SingleBuffer::SurfaceStream_SingleBuffer(SurfaceStream* prevStream)
: SurfaceStream(SurfaceStreamType::SingleBuffer, prevStream)
, mConsumer(nullptr)
{
if (!prevStream)
return;
SharedSurface* prevProducer = nullptr;
SharedSurface* prevConsumer = nullptr;
prevStream->SurrenderSurfaces(prevProducer, prevConsumer);
if (prevConsumer == prevProducer)
prevConsumer = nullptr;
mProducer = Absorb(prevProducer);
mConsumer = Absorb(prevConsumer);
}
SurfaceStream_SingleBuffer::~SurfaceStream_SingleBuffer()
{
Delete(mConsumer);
}
void
SurfaceStream_SingleBuffer::SurrenderSurfaces(SharedSurface*& producer,
SharedSurface*& consumer)
{
mIsAlive = false;
producer = Surrender(mProducer);
consumer = Surrender(mConsumer);
if (!consumer)
consumer = producer;
}
SharedSurface*
SurfaceStream_SingleBuffer::SwapProducer(SurfaceFactory* factory,
const gfxIntSize& size)
{
MutexAutoLock lock(mMutex);
if (mConsumer) {
Recycle(factory, mConsumer);
}
if (mProducer) {
// Fence now, before we start (maybe) juggling Prod around.
mProducer->Fence();
// Size mismatch means we need to squirrel the current Prod
// into Cons, and leave Prod empty, so it gets a new surface below.
bool needsNewBuffer = mProducer->Size() != size;
// Even if we're the right size, if the type has changed, and we don't
// need to preserve, we should switch out for (presumedly) better perf.
if (mProducer->Type() != factory->Type() &&
!factory->Caps().preserve)
{
needsNewBuffer = true;
}
if (needsNewBuffer) {
Move(mProducer, mConsumer);
}
}
// The old Prod (if there every was one) was invalid,
// so we need a new one.
if (!mProducer) {
New(factory, size, mProducer);
}
return mProducer;
}
SharedSurface*
SurfaceStream_SingleBuffer::SwapConsumer_NoWait()
{
MutexAutoLock lock(mMutex);
// Use Cons, if present.
// Otherwise, just use Prod directly.
SharedSurface* toConsume = mConsumer;
if (!toConsume)
toConsume = mProducer;
return toConsume;
}
SurfaceStream_TripleBuffer_Copy::SurfaceStream_TripleBuffer_Copy(SurfaceStream* prevStream)
: SurfaceStream(SurfaceStreamType::TripleBuffer_Copy, prevStream)
, mStaging(nullptr)
, mConsumer(nullptr)
{
if (!prevStream)
return;
SharedSurface* prevProducer = nullptr;
SharedSurface* prevConsumer = nullptr;
prevStream->SurrenderSurfaces(prevProducer, prevConsumer);
if (prevConsumer == prevProducer)
prevConsumer = nullptr;
mProducer = Absorb(prevProducer);
mConsumer = Absorb(prevConsumer);
}
SurfaceStream_TripleBuffer_Copy::~SurfaceStream_TripleBuffer_Copy()
{
Delete(mStaging);
Delete(mConsumer);
}
void
SurfaceStream_TripleBuffer_Copy::SurrenderSurfaces(SharedSurface*& producer,
SharedSurface*& consumer)
{
mIsAlive = false;
producer = Surrender(mProducer);
consumer = Surrender(mConsumer);
if (!consumer)
consumer = Surrender(mStaging);
}
SharedSurface*
SurfaceStream_TripleBuffer_Copy::SwapProducer(SurfaceFactory* factory,
const gfxIntSize& size)
{
MutexAutoLock lock(mMutex);
RecycleScraps(factory);
if (mProducer) {
if (mStaging && mStaging->Type() != factory->Type())
Recycle(factory, mStaging);
if (!mStaging)
New(factory, mProducer->Size(), mStaging);
if (!mStaging)
return nullptr;
SharedSurface::Copy(mProducer, mStaging, factory);
// Fence now, before we start (maybe) juggling Prod around.
mStaging->Fence();
if (mProducer->Size() != size)
Recycle(factory, mProducer);
}
// The old Prod (if there every was one) was invalid,
// so we need a new one.
if (!mProducer) {
New(factory, size, mProducer);
}
return mProducer;
}
SharedSurface*
SurfaceStream_TripleBuffer_Copy::SwapConsumer_NoWait()
{
MutexAutoLock lock(mMutex);
if (mStaging) {
Scrap(mConsumer);
Move(mStaging, mConsumer);
}
return mConsumer;
}
SurfaceStream_TripleBuffer::SurfaceStream_TripleBuffer(SurfaceStream* prevStream)
: SurfaceStream(SurfaceStreamType::TripleBuffer, prevStream)
, mStaging(nullptr)
, mConsumer(nullptr)
{
if (!prevStream)
return;
SharedSurface* prevProducer = nullptr;
SharedSurface* prevConsumer = nullptr;
prevStream->SurrenderSurfaces(prevProducer, prevConsumer);
if (prevConsumer == prevProducer)
prevConsumer = nullptr;
mProducer = Absorb(prevProducer);
mConsumer = Absorb(prevConsumer);
}
SurfaceStream_TripleBuffer::~SurfaceStream_TripleBuffer()
{
Delete(mStaging);
Delete(mConsumer);
}
void
SurfaceStream_TripleBuffer::SurrenderSurfaces(SharedSurface*& producer,
SharedSurface*& consumer)
{
mIsAlive = false;
producer = Surrender(mProducer);
consumer = Surrender(mConsumer);
if (!consumer)
consumer = Surrender(mStaging);
}
SharedSurface*
SurfaceStream_TripleBuffer::SwapProducer(SurfaceFactory* factory,
const gfxIntSize& size)
{
MutexAutoLock lock(mMutex);
if (mProducer) {
RecycleScraps(factory);
if (mStaging)
Recycle(factory, mStaging);
Move(mProducer, mStaging);
mStaging->Fence();
}
MOZ_ASSERT(!mProducer);
New(factory, size, mProducer);
return mProducer;
}
SharedSurface*
SurfaceStream_TripleBuffer::SwapConsumer_NoWait()
{
MutexAutoLock lock(mMutex);
if (mStaging) {
Scrap(mConsumer);
Move(mStaging, mConsumer);
}
return mConsumer;
}
} /* namespace gfx */
} /* namespace mozilla */

189
gfx/gl/SurfaceStream.h Normal file
View File

@ -0,0 +1,189 @@
/* -*- 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 SURFACESTREAM_H_
#define SURFACESTREAM_H_
#include <stack>
#include <set>
#include "mozilla/Mutex.h"
#include "mozilla/Attributes.h"
#include "gfxPoint.h"
#include "SurfaceTypes.h"
namespace mozilla {
namespace gfx {
class SharedSurface;
class SurfaceFactory;
// Owned by: ScreenBuffer
class SurfaceStream
{
public:
typedef enum {
MainThread,
OffMainThread
} OMTC;
static SurfaceStreamType ChooseGLStreamType(OMTC omtc,
bool preserveBuffer);
static SurfaceStream* CreateForType(SurfaceStreamType type,
SurfaceStream* prevStream = nullptr);
SurfaceStreamHandle GetShareHandle() {
return reinterpret_cast<SurfaceStreamHandle>(this);
}
static SurfaceStream* FromHandle(SurfaceStreamHandle handle) {
return (SurfaceStream*)handle;
}
const SurfaceStreamType mType;
protected:
// |mProd| is owned by us, but can be ripped away when
// creating a new GLStream from this one.
SharedSurface* mProducer;
std::set<SharedSurface*> mSurfaces;
std::stack<SharedSurface*> mScraps;
mutable Mutex mMutex;
bool mIsAlive;
// |previous| can be null, indicating this is the first one.
// Otherwise, we pull in |mProd| from |previous| an our initial surface.
SurfaceStream(SurfaceStreamType type, SurfaceStream* prevStream)
: mType(type)
, mProducer(nullptr)
, mMutex("SurfaceStream mutex")
, mIsAlive(true)
{
MOZ_ASSERT(!prevStream || mType != prevStream->mType,
"We should not need to create a SurfaceStream from another "
"of the same type.");
}
public:
virtual ~SurfaceStream();
protected:
// These functions below are helpers to make trading buffers around easier.
// For instance, using Move(a,b) instead of normal assignment assures that
// we are never leaving anything hanging around, keeping things very safe.
static void Move(SharedSurface*& from, SharedSurface*& to) {
MOZ_ASSERT(!to);
to = from;
from = nullptr;
}
void New(SurfaceFactory* factory, const gfxIntSize& size,
SharedSurface*& surf);
void Delete(SharedSurface*& surf);
void Recycle(SurfaceFactory* factory, SharedSurface*& surf);
// Surrender control of a surface, and return it for use elsewhere.
SharedSurface* Surrender(SharedSurface*& surf);
// Absorb control of a surface from elsewhere, clears its old location.
SharedSurface* Absorb(SharedSurface*& surf);
// For holding on to surfaces we don't need until we can return them to the
// Producer's factory via SurfaceFactory::Recycle.
// Not thread-safe.
void Scrap(SharedSurface*& scrap);
// Not thread-safe.
void RecycleScraps(SurfaceFactory* factory);
public:
/* Note that ownership of the returned surfaces below
* transfers to the caller.
* SwapProd returns null on failure. Returning null doesn't mean nothing
* happened, but rather that a surface allocation failed. After returning
* null, we must be able to call SwapProducer again with better args
* and have everything work again.
* One common failure is asking for a too-large |size|.
*/
virtual SharedSurface* SwapProducer(SurfaceFactory* factory,
const gfxIntSize& size) = 0;
protected:
// SwapCons will return the same surface more than once,
// if nothing new has been published.
virtual SharedSurface* SwapConsumer_NoWait() = 0;
public:
virtual SharedSurface* SwapConsumer();
virtual void SurrenderSurfaces(SharedSurface*& producer, SharedSurface*& consumer) = 0;
};
// Not thread-safe. Don't use cross-threads.
class SurfaceStream_SingleBuffer
: public SurfaceStream
{
protected:
SharedSurface* mConsumer; // Only present after resize-swap.
public:
SurfaceStream_SingleBuffer(SurfaceStream* prevStream);
virtual ~SurfaceStream_SingleBuffer();
/* Since we're non-OMTC, we know the order of execution here:
* SwapProd gets called in UpdateSurface, followed by
* SwapCons being called in Render.
*/
virtual SharedSurface* SwapProducer(SurfaceFactory* factory,
const gfxIntSize& size);
virtual SharedSurface* SwapConsumer_NoWait();
virtual void SurrenderSurfaces(SharedSurface*& producer, SharedSurface*& consumer);
};
// Our hero for preserveDrawingBuffer=true.
class SurfaceStream_TripleBuffer_Copy
: public SurfaceStream
{
protected:
SharedSurface* mStaging;
SharedSurface* mConsumer;
public:
SurfaceStream_TripleBuffer_Copy(SurfaceStream* prevStream);
virtual ~SurfaceStream_TripleBuffer_Copy();
virtual SharedSurface* SwapProducer(SurfaceFactory* factory,
const gfxIntSize& size);
virtual SharedSurface* SwapConsumer_NoWait();
virtual void SurrenderSurfaces(SharedSurface*& producer, SharedSurface*& consumer);
};
class SurfaceStream_TripleBuffer
: public SurfaceStream
{
protected:
SharedSurface* mStaging;
SharedSurface* mConsumer;
public:
SurfaceStream_TripleBuffer(SurfaceStream* prevStream);
virtual ~SurfaceStream_TripleBuffer();
// Done writing to prod, swap prod and staging
virtual SharedSurface* SwapProducer(SurfaceFactory* factory,
const gfxIntSize& size);
virtual SharedSurface* SwapConsumer_NoWait();
virtual void SurrenderSurfaces(SharedSurface*& producer, SharedSurface*& consumer);
};
} /* namespace gfx */
} /* namespace mozilla */
#endif /* SURFACESTREAM_H_ */

107
gfx/gl/SurfaceTypes.h Normal file
View File

@ -0,0 +1,107 @@
/* -*- 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 SURFACE_TYPES_H_
#define SURFACE_TYPES_H_
#include "mozilla/TypedEnum.h"
#include "mozilla/StandardInteger.h"
#include <cstring>
namespace mozilla {
namespace gfx {
typedef uintptr_t SurfaceStreamHandle;
struct SurfaceCaps
{
bool any;
bool color, alpha;
bool bpp16;
bool depth, stencil;
bool antialias;
bool preserve;
SurfaceCaps() {
Clear();
}
void Clear() {
std::memset(this, 0, sizeof(SurfaceCaps));
}
// We can't use just 'RGB' here, since it's an ancient Windows macro.
static SurfaceCaps ForRGB() {
SurfaceCaps caps;
caps.color = true;
return caps;
}
static SurfaceCaps ForRGBA() {
SurfaceCaps caps;
caps.color = true;
caps.alpha = true;
return caps;
}
static SurfaceCaps Any() {
SurfaceCaps caps;
caps.any = true;
return caps;
}
};
MOZ_BEGIN_ENUM_CLASS(SharedSurfaceType, uint8_t)
Unknown = 0,
Basic,
GLTextureShare,
EGLImageShare,
EGLSurfaceANGLE,
DXGLInterop,
DXGLInterop2,
Gralloc,
Max
MOZ_END_ENUM_CLASS(SharedSurfaceType)
MOZ_BEGIN_ENUM_CLASS(SurfaceStreamType, uint8_t)
SingleBuffer,
TripleBuffer_Copy,
TripleBuffer,
Max
MOZ_END_ENUM_CLASS(SurfaceStreamType)
MOZ_BEGIN_ENUM_CLASS(APITypeT, uint8_t)
Generic = 0,
OpenGL,
Max
MOZ_END_ENUM_CLASS(APITypeT)
MOZ_BEGIN_ENUM_CLASS(AttachmentType, uint8_t)
Screen = 0,
GLTexture,
GLRenderbuffer,
Max
MOZ_END_ENUM_CLASS(AttachmentType)
} /* namespace gfx */
} /* namespace mozilla */
#endif /* SURFACE_TYPES_H_ */

View File

@ -47,6 +47,7 @@ extern uint8_t gLayerManagerLayerBuilder;
namespace mozilla {
class FrameLayerBuilder;
class WebGLContext;
namespace gl {
class GLContext;
@ -1540,22 +1541,25 @@ class THEBES_API CanvasLayer : public Layer {
public:
struct Data {
Data()
: mSurface(nullptr), mGLContext(nullptr)
, mDrawTarget(nullptr), mGLBufferIsPremultiplied(false)
: mSurface(nullptr)
, mDrawTarget(nullptr)
, mGLContext(nullptr)
, mSize(0,0)
, mIsGLAlphaPremult(false)
{ }
/* One of these two must be specified, but never both */
// One of these two must be specified for Canvas2D, but never both
gfxASurface* mSurface; // a gfx Surface for the canvas contents
mozilla::gl::GLContext* mGLContext; // a GL PBuffer Context
mozilla::gfx::DrawTarget *mDrawTarget; // a DrawTarget for the canvas contents
/* The size of the canvas content */
// Or this, for GL.
mozilla::gl::GLContext* mGLContext;
// The size of the canvas content
nsIntSize mSize;
/* Whether the GLContext contains premultiplied alpha
* values in the framebuffer or not. Defaults to FALSE.
*/
bool mGLBufferIsPremultiplied;
// Whether mGLContext contains data that is alpha-premultiplied.
bool mIsGLAlphaPremult;
};
/**
@ -1594,14 +1598,33 @@ public:
return mDirty;
}
/**
* Register a callback to be called at the start of each transaction.
*/
typedef void PreTransactionCallback(void* closureData);
void SetPreTransactionCallback(PreTransactionCallback* callback, void* closureData)
{
mPreTransCallback = callback;
mPreTransCallbackData = closureData;
}
protected:
void FirePreTransactionCallback()
{
if (mPreTransCallback) {
mPreTransCallback(mPreTransCallbackData);
}
}
public:
/**
* Register a callback to be called at the end of each transaction.
*/
typedef void (* DidTransactionCallback)(void* aClosureData);
void SetDidTransactionCallback(DidTransactionCallback aCallback, void* aClosureData)
{
mCallback = aCallback;
mCallbackData = aClosureData;
mPostTransCallback = aCallback;
mPostTransCallbackData = aClosureData;
}
/**
@ -1628,16 +1651,21 @@ public:
protected:
CanvasLayer(LayerManager* aManager, void* aImplData)
: Layer(aManager, aImplData),
mCallback(nullptr), mCallbackData(nullptr), mFilter(gfxPattern::FILTER_GOOD),
mDirty(false) {}
: Layer(aManager, aImplData)
, mPreTransCallback(nullptr)
, mPreTransCallbackData(nullptr)
, mPostTransCallback(nullptr)
, mPostTransCallbackData(nullptr)
, mFilter(gfxPattern::FILTER_GOOD)
, mDirty(false)
{}
virtual nsACString& PrintInfo(nsACString& aTo, const char* aPrefix);
void FireDidTransactionCallback()
{
if (mCallback) {
mCallback(mCallbackData);
if (mPostTransCallback) {
mPostTransCallback(mPostTransCallbackData);
}
}
@ -1645,8 +1673,10 @@ protected:
* 0, 0, canvaswidth, canvasheight
*/
nsIntRect mBounds;
DidTransactionCallback mCallback;
void* mCallbackData;
PreTransactionCallback* mPreTransCallback;
void* mPreTransCallbackData;
DidTransactionCallback mPostTransCallback;
void* mPostTransCallbackData;
gfxPattern::GraphicsFilter mFilter;
private:

View File

@ -9,6 +9,9 @@
#include "gfxUtils.h"
#include "gfxPlatform.h"
#include "mozilla/Preferences.h"
#include "SurfaceStream.h"
#include "SharedSurfaceGL.h"
#include "SharedSurfaceEGL.h"
#include "BasicLayersImpl.h"
#include "nsXULAppAPI.h"
@ -56,12 +59,10 @@ protected:
void UpdateSurface(gfxASurface* aDestSurface = nullptr, Layer* aMaskLayer = nullptr);
nsRefPtr<gfxASurface> mSurface;
nsRefPtr<mozilla::gl::GLContext> mGLContext;
mozilla::RefPtr<mozilla::gfx::DrawTarget> mDrawTarget;
nsRefPtr<mozilla::gl::GLContext> mGLContext;
uint32_t mCanvasFramebuffer;
bool mGLBufferIsPremultiplied;
bool mIsGLAlphaPremult;
bool mNeedsYFlip;
bool mForceReadback;
@ -98,15 +99,16 @@ BasicCanvasLayer::Initialize(const Data& aData)
if (aData.mSurface) {
mSurface = aData.mSurface;
NS_ASSERTION(aData.mGLContext == nullptr,
"CanvasLayer can't have both surface and GLContext");
NS_ASSERTION(!aData.mGLContext, "CanvasLayer can't have both surface and GLContext");
mNeedsYFlip = false;
} else if (aData.mGLContext) {
NS_ASSERTION(aData.mGLContext->IsOffscreen(), "canvas gl context isn't offscreen");
mGLContext = aData.mGLContext;
mGLBufferIsPremultiplied = aData.mGLBufferIsPremultiplied;
mCanvasFramebuffer = mGLContext->GetOffscreenFBO();
mIsGLAlphaPremult = aData.mIsGLAlphaPremult;
mNeedsYFlip = true;
MOZ_ASSERT(mGLContext->IsOffscreen(), "canvas gl context isn't offscreen");
// [Basic Layers, non-OMTC] WebGL layer init.
// `GLScreenBuffer::Morph`ing is only needed in BasicShadowableCanvasLayer.
} else if (aData.mDrawTarget) {
mDrawTarget = aData.mDrawTarget;
mSurface = gfxPlatform::GetPlatform()->CreateThebesSurfaceAliasForDrawTarget_hack(mDrawTarget);
@ -146,69 +148,84 @@ BasicCanvasLayer::UpdateSurface(gfxASurface* aDestSurface, Layer* aMaskLayer)
if (mGLContext) {
if (aDestSurface && aDestSurface->GetType() != gfxASurface::SurfaceTypeImage) {
NS_ASSERTION(aDestSurface->GetType() == gfxASurface::SurfaceTypeImage,
"Destination surface must be ImageSurface type");
MOZ_ASSERT(false, "Destination surface must be ImageSurface type.");
return;
}
// We need to read from the GLContext
mGLContext->MakeCurrent();
gfxIntSize readSize(mBounds.width, mBounds.height);
gfxImageFormat format = (GetContentFlags() & CONTENT_OPAQUE)
? gfxASurface::ImageFormatRGB24
: gfxASurface::ImageFormatARGB32;
nsRefPtr<gfxImageSurface> readSurf;
nsRefPtr<gfxImageSurface> resultSurf;
bool usingTempSurface = false;
SharedSurface* sharedSurf = mGLContext->RequestFrame();
if (!sharedSurf) {
NS_WARNING("Null frame received.");
return;
}
gfxIntSize readSize(sharedSurf->Size());
gfxImageFormat format = (GetContentFlags() & CONTENT_OPAQUE)
? gfxASurface::ImageFormatRGB24
: gfxASurface::ImageFormatARGB32;
if (aDestSurface) {
resultSurf = static_cast<gfxImageSurface*>(aDestSurface);
if (resultSurf->GetSize() != readSize ||
resultSurf->Stride() != resultSurf->Width() * 4)
{
readSurf = GetTempSurface(readSize, format);
usingTempSurface = true;
}
} else {
resultSurf = GetTempSurface(readSize, format);
usingTempSurface = true;
}
MOZ_ASSERT(resultSurf);
if (resultSurf->CairoStatus() != 0) {
MOZ_ASSERT(false, "Bad resultSurf->CairoStatus().");
return;
}
if (!usingTempSurface)
DiscardTempSurface();
MOZ_ASSERT(sharedSurf->APIType() == APITypeT::OpenGL);
SharedSurface_GL* surfGL = SharedSurface_GL::Cast(sharedSurf);
if (!readSurf)
readSurf = resultSurf;
if (!resultSurf || resultSurf->CairoStatus() != 0)
return;
if (surfGL->Type() == SharedSurfaceType::Basic) {
SharedSurface_Basic* sharedSurf_Basic = SharedSurface_Basic::Cast(surfGL);
readSurf = sharedSurf_Basic->GetData();
} else {
if (resultSurf->Format() == format &&
resultSurf->GetSize() == readSize)
{
readSurf = resultSurf;
} else {
readSurf = GetTempSurface(readSize, format);
}
// Readback handles Flush/MarkDirty.
mGLContext->Screen()->Readback(surfGL, readSurf);
}
MOZ_ASSERT(readSurf);
MOZ_ASSERT(readSurf->Stride() == mBounds.width * 4, "gfxImageSurface stride isn't what we expect!");
// We need to Flush() the surface before modifying it outside of cairo.
readSurf->Flush();
mGLContext->ReadScreenIntoImageSurface(readSurf);
readSurf->MarkDirty();
bool needsPremult = surfGL->HasAlpha() && !mIsGLAlphaPremult;
if (needsPremult) {
gfxImageSurface* sizedReadSurf = nullptr;
if (readSurf->Format() == resultSurf->Format() &&
readSurf->GetSize() == resultSurf->GetSize())
{
sizedReadSurf = readSurf;
} else {
readSurf->Flush();
nsRefPtr<gfxContext> ctx = new gfxContext(resultSurf);
ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
ctx->SetSource(readSurf);
ctx->Paint();
// If the underlying GLContext doesn't have a framebuffer into which
// premultiplied values were written, we have to do this ourselves here.
// Note that this is a WebGL attribute; GL itself has no knowledge of
// premultiplied or unpremultiplied alpha.
if (!mGLBufferIsPremultiplied)
gfxUtils::PremultiplyImageSurface(readSurf);
if (readSurf != resultSurf) {
MOZ_ASSERT(resultSurf->Width() >= readSurf->Width());
MOZ_ASSERT(resultSurf->Height() >= readSurf->Height());
sizedReadSurf = resultSurf;
}
MOZ_ASSERT(sizedReadSurf);
readSurf->Flush();
resultSurf->Flush();
resultSurf->CopyFrom(readSurf);
gfxUtils::PremultiplyImageSurface(readSurf, resultSurf);
resultSurf->MarkDirty();
} else if (resultSurf != readSurf) {
// Didn't need premult, but we do need to blit to resultSurf
readSurf->Flush();
nsRefPtr<gfxContext> ctx = new gfxContext(resultSurf);
ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
ctx->SetSource(readSurf);
ctx->Paint();
}
// stick our surface into mSurface, so that the Paint() path is the same
@ -223,8 +240,11 @@ BasicCanvasLayer::Paint(gfxContext* aContext, Layer* aMaskLayer)
{
if (IsHidden())
return;
FirePreTransactionCallback();
UpdateSurface();
FireDidTransactionCallback();
PaintWithOpacity(aContext, GetEffectiveOpacity(), aMaskLayer);
}
@ -325,28 +345,14 @@ public:
void DestroyBackBuffer()
{
if (mBackBuffer.type() == SurfaceDescriptor::TSharedTextureDescriptor) {
SharedTextureDescriptor handle = mBackBuffer.get_SharedTextureDescriptor();
if (mGLContext && handle.handle()) {
mGLContext->ReleaseSharedHandle(handle.shareType(), handle.handle());
mBackBuffer = SurfaceDescriptor();
}
} else if (IsSurfaceDescriptorValid(mBackBuffer)) {
MOZ_ASSERT(mBackBuffer.type() != SurfaceDescriptor::TSharedTextureDescriptor);
if (IsSurfaceDescriptorValid(mBackBuffer)) {
BasicManager()->ShadowLayerForwarder::DestroySharedSurface(&mBackBuffer);
mBackBuffer = SurfaceDescriptor();
}
}
private:
typedef mozilla::gl::SharedTextureHandle SharedTextureHandle;
typedef mozilla::gl::TextureImage TextureImage;
SharedTextureHandle GetSharedBackBufferHandle()
{
if (mBackBuffer.type() == SurfaceDescriptor::TSharedTextureDescriptor)
return mBackBuffer.get_SharedTextureDescriptor().handle();
return 0;
}
BasicShadowLayerManager* BasicManager()
{
return static_cast<BasicShadowLayerManager*>(mManager);
@ -363,8 +369,36 @@ BasicShadowableCanvasLayer::Initialize(const Data& aData)
if (!HasShadow())
return;
// XXX won't get here currently; need to figure out what to do on
// canvas resizes
if (mGLContext) {
GLScreenBuffer* screen = mGLContext->Screen();
SurfaceStreamType streamType =
SurfaceStream::ChooseGLStreamType(SurfaceStream::OffMainThread,
screen->PreserveBuffer());
SurfaceFactory_GL* factory = nullptr;
if (!mForceReadback) {
if (BasicManager()->GetParentBackendType() == mozilla::layers::LAYERS_OPENGL) {
if (mGLContext->GetEGLContext()) {
bool isCrossProcess = !(XRE_GetProcessType() == GeckoProcessType_Default);
if (!isCrossProcess) {
// [Basic/OGL Layers, OMTC] WebGL layer init.
factory = SurfaceFactory_EGLImage::Create(mGLContext, screen->Caps());
} else {
// [Basic/OGL Layers, OOPC] WebGL layer init. (Out Of Process Compositing)
// Fall back to readback.
}
} else {
// [Basic Layers, OMTC] WebGL layer init.
// Well, this *should* work...
factory = new SurfaceFactory_GLTexture(mGLContext, mGLContext, screen->Caps());
}
}
}
if (factory) {
screen->Morph(factory, streamType);
}
}
if (IsSurfaceDescriptorValid(mBackBuffer)) {
AutoOpenSurface backSurface(OPEN_READ_ONLY, mBackBuffer);
@ -389,24 +423,17 @@ BasicShadowableCanvasLayer::Paint(gfxContext* aContext, Layer* aMaskLayer)
!mForceReadback &&
BasicManager()->GetParentBackendType() == mozilla::layers::LAYERS_OPENGL)
{
GLContext::SharedTextureShareType shareType;
// if process type is default, then it is single-process (non-e10s)
if (XRE_GetProcessType() == GeckoProcessType_Default)
shareType = GLContext::SameProcess;
else
shareType = GLContext::CrossProcess;
bool isCrossProcess = XRE_GetProcessType() != GeckoProcessType_Default;
// Todo: If isCrossProcess (OMPC), spin off mini-thread to RequestFrame
// and forward Gralloc handle. Signal WaitSync complete with XPC mutex?
if (!isCrossProcess) {
FirePreTransactionCallback();
GLScreenBuffer* screen = mGLContext->Screen();
SurfaceStreamHandle handle = screen->Stream()->GetShareHandle();
SharedTextureHandle handle = GetSharedBackBufferHandle();
if (!handle) {
handle = mGLContext->CreateSharedHandle(shareType);
if (handle) {
mBackBuffer = SharedTextureDescriptor(shareType, handle, mBounds.Size(), false);
}
}
if (handle) {
mGLContext->MakeCurrent();
mGLContext->UpdateSharedHandle(shareType, handle);
// call Painted() to reset our dirty 'bit'
mBackBuffer = SurfaceStreamDescriptor(handle, false);
// Call Painted() to reset our dirty 'bit'.
Painted();
FireDidTransactionCallback();
BasicManager()->PaintedCanvas(BasicManager()->Hold(this),
@ -439,6 +466,7 @@ BasicShadowableCanvasLayer::Paint(gfxContext* aContext, Layer* aMaskLayer)
static_cast<BasicImplData*>(aMaskLayer->ImplData())
->Paint(aContext, nullptr);
}
FirePreTransactionCallback();
UpdateSurface(autoBackSurface.Get(), nullptr);
FireDidTransactionCallback();

View File

@ -9,7 +9,11 @@
#include "gfxImageSurface.h"
#include "gfxWindowsSurface.h"
#include "gfxWindowsPlatform.h"
#include "SurfaceStream.h"
#include "SharedSurfaceANGLE.h"
#include "gfxContext.h"
using namespace mozilla::gl;
using namespace mozilla::gfx;
namespace mozilla {
@ -26,15 +30,31 @@ CanvasLayerD3D10::Initialize(const Data& aData)
if (aData.mSurface) {
mSurface = aData.mSurface;
NS_ASSERTION(aData.mGLContext == nullptr && !aData.mDrawTarget,
"CanvasLayer can't have both surface and GLContext/DrawTarget");
NS_ASSERTION(!aData.mGLContext && !aData.mDrawTarget,
"CanvasLayer can't have both surface and WebGLContext/DrawTarget");
mNeedsYFlip = false;
mDataIsPremultiplied = true;
} else if (aData.mGLContext) {
NS_ASSERTION(aData.mGLContext->IsOffscreen(), "canvas gl context isn't offscreen");
mGLContext = aData.mGLContext;
mDataIsPremultiplied = aData.mGLBufferIsPremultiplied;
NS_ASSERTION(mGLContext->IsOffscreen(), "Canvas GLContext must be offscreen.");
mDataIsPremultiplied = aData.mIsGLAlphaPremult;
mNeedsYFlip = true;
GLScreenBuffer* screen = mGLContext->Screen();
SurfaceStreamType streamType =
SurfaceStream::ChooseGLStreamType(SurfaceStream::MainThread,
screen->PreserveBuffer());
SurfaceFactory_GL* factory = nullptr;
if (!mForceReadback) {
factory = SurfaceFactory_ANGLEShareHandle::Create(mGLContext,
device(),
screen->Caps());
}
if (factory) {
screen->Morph(factory, streamType);
}
} else if (aData.mDrawTarget) {
mDrawTarget = aData.mDrawTarget;
mNeedsYFlip = false;
@ -44,8 +64,8 @@ CanvasLayerD3D10::Initialize(const Data& aData)
if (texture) {
mTexture = static_cast<ID3D10Texture2D*>(texture);
NS_ASSERTION(aData.mGLContext == nullptr && aData.mSurface == nullptr,
"CanvasLayer can't have both surface and GLContext/Surface");
NS_ASSERTION(!aData.mGLContext && !aData.mSurface,
"CanvasLayer can't have both surface and WebGLContext/Surface");
mBounds.SetRect(0, 0, aData.mSize.width, aData.mSize.height);
device()->CreateShaderResourceView(mTexture, NULL, getter_AddRefs(mSRView));
@ -74,30 +94,19 @@ CanvasLayerD3D10::Initialize(const Data& aData)
}
mIsD2DTexture = false;
mUsingSharedTexture = false;
HANDLE shareHandle = mGLContext ? mGLContext->GetD3DShareHandle() : nullptr;
if (shareHandle && !mForceReadback) {
HRESULT hr = device()->OpenSharedResource(shareHandle, __uuidof(ID3D10Texture2D), getter_AddRefs(mTexture));
if (SUCCEEDED(hr))
mUsingSharedTexture = true;
// Create a texture in case we need to readback.
CD3D10_TEXTURE2D_DESC desc(DXGI_FORMAT_B8G8R8A8_UNORM, mBounds.width, mBounds.height, 1, 1);
desc.Usage = D3D10_USAGE_DYNAMIC;
desc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
HRESULT hr = device()->CreateTexture2D(&desc, NULL, getter_AddRefs(mTexture));
if (FAILED(hr)) {
NS_WARNING("Failed to create texture for CanvasLayer!");
return;
}
if (mUsingSharedTexture) {
mNeedsYFlip = true;
} else {
CD3D10_TEXTURE2D_DESC desc(DXGI_FORMAT_B8G8R8A8_UNORM, mBounds.width, mBounds.height, 1, 1);
desc.Usage = D3D10_USAGE_DYNAMIC;
desc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
HRESULT hr = device()->CreateTexture2D(&desc, NULL, getter_AddRefs(mTexture));
if (FAILED(hr)) {
NS_WARNING("Failed to create texture for CanvasLayer!");
return;
}
}
device()->CreateShaderResourceView(mTexture, NULL, getter_AddRefs(mSRView));
device()->CreateShaderResourceView(mTexture, NULL, getter_AddRefs(mUploadSRView));
}
void
@ -112,53 +121,58 @@ CanvasLayerD3D10::UpdateSurface()
} else if (mIsD2DTexture) {
mSurface->Flush();
return;
} else if (mUsingSharedTexture) {
// need to sync on the d3d9 device
if (mGLContext) {
mGLContext->MakeCurrent();
mGLContext->GuaranteeResolve();
}
return;
}
if (mGLContext) {
// WebGL reads entire surface.
D3D10_MAPPED_TEXTURE2D map;
SharedSurface* surf = mGLContext->RequestFrame();
if (!surf)
return;
HRESULT hr = mTexture->Map(0, D3D10_MAP_WRITE_DISCARD, 0, &map);
switch (surf->Type()) {
case SharedSurfaceType::EGLSurfaceANGLE: {
SharedSurface_ANGLEShareHandle* shareSurf = SharedSurface_ANGLEShareHandle::Cast(surf);
if (FAILED(hr)) {
NS_WARNING("Failed to map CanvasLayer texture.");
return;
}
const bool stridesMatch = map.RowPitch == mBounds.width * 4;
uint8_t *destination;
if (!stridesMatch) {
destination = GetTempBlob(mBounds.width * mBounds.height * 4);
} else {
DiscardTempBlob();
destination = (uint8_t*)map.pData;
}
mGLContext->MakeCurrent();
nsRefPtr<gfxImageSurface> tmpSurface =
new gfxImageSurface(destination,
gfxIntSize(mBounds.width, mBounds.height),
mBounds.width * 4,
gfxASurface::ImageFormatARGB32);
mGLContext->ReadScreenIntoImageSurface(tmpSurface);
tmpSurface = nullptr;
if (!stridesMatch) {
for (int y = 0; y < mBounds.height; y++) {
memcpy((uint8_t*)map.pData + map.RowPitch * y,
destination + mBounds.width * 4 * y,
mBounds.width * 4);
mSRView = shareSurf->GetSRV();
return;
}
case SharedSurfaceType::Basic: {
SharedSurface_Basic* shareSurf = SharedSurface_Basic::Cast(surf);
// WebGL reads entire surface.
D3D10_MAPPED_TEXTURE2D map;
HRESULT hr = mTexture->Map(0, D3D10_MAP_WRITE_DISCARD, 0, &map);
if (FAILED(hr)) {
NS_WARNING("Failed to map CanvasLayer texture.");
return;
}
gfxImageSurface* frameData = shareSurf->GetData();
// Scope for gfxContext, so it's destroyed before Unmap.
{
nsRefPtr<gfxImageSurface> mapSurf =
new gfxImageSurface((uint8_t*)map.pData,
shareSurf->Size(),
map.RowPitch,
gfxASurface::ImageFormatARGB32);
nsRefPtr<gfxContext> ctx = new gfxContext(mapSurf);
ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
ctx->SetSource(frameData);
ctx->Paint();
mapSurf->Flush();
}
mTexture->Unmap(0);
mSRView = mUploadSRView;
break;
}
default:
MOZ_NOT_REACHED("Unhandled SharedSurfaceType.");
return;
}
mTexture->Unmap(0);
} else if (mSurface) {
RECT r;
r.left = 0;
@ -186,6 +200,7 @@ CanvasLayerD3D10::UpdateSurface()
ctx->Paint();
mTexture->Unmap(0);
mSRView = mUploadSRView;
}
}
@ -198,6 +213,7 @@ CanvasLayerD3D10::GetLayer()
void
CanvasLayerD3D10::RenderLayer()
{
FirePreTransactionCallback();
UpdateSurface();
FireDidTransactionCallback();

View File

@ -48,12 +48,12 @@ private:
mozilla::RefPtr<mozilla::gfx::DrawTarget> mDrawTarget;
nsRefPtr<GLContext> mGLContext;
nsRefPtr<ID3D10Texture2D> mTexture;
nsRefPtr<ID3D10ShaderResourceView> mUploadSRView;
nsRefPtr<ID3D10ShaderResourceView> mSRView;
bool mDataIsPremultiplied;
bool mNeedsYFlip;
bool mIsD2DTexture;
bool mUsingSharedTexture;
bool mHasAlpha;
bool mForceReadback;
@ -62,17 +62,17 @@ private:
uint8_t* GetTempBlob(const uint32_t aSize)
{
if (!mCachedTempBlob || aSize != mCachedTempBlob_Size) {
mCachedTempBlob = new uint8_t[aSize];
mCachedTempBlob_Size = aSize;
}
if (!mCachedTempBlob || aSize != mCachedTempBlob_Size) {
mCachedTempBlob = new uint8_t[aSize];
mCachedTempBlob_Size = aSize;
}
return mCachedTempBlob;
return mCachedTempBlob;
}
void DiscardTempBlob()
{
mCachedTempBlob = nullptr;
mCachedTempBlob = nullptr;
}
};

View File

@ -12,9 +12,14 @@
#include "gfxImageSurface.h"
#include "gfxWindowsSurface.h"
#include "gfxWindowsPlatform.h"
#include "SurfaceStream.h"
#include "SharedSurfaceGL.h"
#include "CanvasLayerD3D9.h"
using namespace mozilla::gfx;
using namespace mozilla::gl;
namespace mozilla {
namespace layers {
@ -38,13 +43,13 @@ CanvasLayerD3D9::Initialize(const Data& aData)
} else if (aData.mSurface) {
mSurface = aData.mSurface;
NS_ASSERTION(aData.mGLContext == nullptr,
"CanvasLayer can't have both surface and GLContext");
"CanvasLayer can't have both surface and WebGLContext");
mNeedsYFlip = false;
mDataIsPremultiplied = true;
} else if (aData.mGLContext) {
NS_ASSERTION(aData.mGLContext->IsOffscreen(), "canvas gl context isn't offscreen");
mGLContext = aData.mGLContext;
mDataIsPremultiplied = aData.mGLBufferIsPremultiplied;
NS_ASSERTION(mGLContext->IsOffscreen(), "Canvas GLContext must be offscreen.");
mDataIsPremultiplied = aData.mIsGLAlphaPremult;
mNeedsYFlip = true;
} else {
NS_ERROR("CanvasLayer created without mSurface, mGLContext or mDrawTarget?");
@ -72,6 +77,12 @@ CanvasLayerD3D9::UpdateSurface()
}
if (mGLContext) {
SharedSurface* surf = mGLContext->RequestFrame();
if (!surf)
return;
SharedSurface_Basic* shareSurf = SharedSurface_Basic::Cast(surf);
// WebGL reads entire surface.
LockTextureRectD3D9 textureLock(mTexture);
if (!textureLock.HasLock()) {
@ -79,34 +90,23 @@ CanvasLayerD3D9::UpdateSurface()
return;
}
D3DLOCKED_RECT r = textureLock.GetLockRect();
D3DLOCKED_RECT rect = textureLock.GetLockRect();
const bool stridesMatch = r.Pitch == mBounds.width * 4;
gfxImageSurface* frameData = shareSurf->GetData();
// Scope for gfxContext, so it's destroyed early.
{
nsRefPtr<gfxImageSurface> mapSurf =
new gfxImageSurface((uint8_t*)rect.pBits,
shareSurf->Size(),
rect.Pitch,
gfxASurface::ImageFormatARGB32);
uint8_t *destination;
if (!stridesMatch) {
destination = GetTempBlob(mBounds.width * mBounds.height * 4);
} else {
DiscardTempBlob();
destination = (uint8_t*)r.pBits;
}
gfxContext ctx(mapSurf);
ctx.SetOperator(gfxContext::OPERATOR_SOURCE);
ctx.SetSource(frameData);
ctx.Paint();
mGLContext->MakeCurrent();
nsRefPtr<gfxImageSurface> tmpSurface =
new gfxImageSurface(destination,
gfxIntSize(mBounds.width, mBounds.height),
mBounds.width * 4,
gfxASurface::ImageFormatARGB32);
mGLContext->ReadScreenIntoImageSurface(tmpSurface);
tmpSurface = nullptr;
if (!stridesMatch) {
for (int y = 0; y < mBounds.height; y++) {
memcpy((uint8_t*)r.pBits + r.Pitch * y,
destination + mBounds.width * 4 * y,
mBounds.width * 4);
}
mapSurf->Flush();
}
} else {
RECT r;
@ -170,6 +170,7 @@ CanvasLayerD3D9::GetLayer()
void
CanvasLayerD3D9::RenderLayer()
{
FirePreTransactionCallback();
UpdateSurface();
if (mD3DManager->CompositingDisabled()) {
return;

View File

@ -23,6 +23,7 @@ using mozilla::null_t;
using mozilla::WindowsHandle;
using mozilla::gl::SharedTextureHandle;
using mozilla::gl::GLContext::SharedTextureShareType;
using mozilla::gfx::SurfaceStreamHandle;
namespace mozilla {
namespace layers {
@ -60,12 +61,18 @@ struct SharedImageID {
uint64_t id;
};
struct SurfaceStreamDescriptor {
SurfaceStreamHandle handle;
bool yflip;
};
union SurfaceDescriptor {
Shmem;
SurfaceDescriptorD3D10;
SurfaceDescriptorGralloc;
SurfaceDescriptorX11;
SharedTextureDescriptor;
SurfaceStreamDescriptor;
};
struct YCbCrImage {

View File

@ -15,6 +15,10 @@
#include "gfxContext.h"
#include "GLContextProvider.h"
#include "gfxPlatform.h"
#include "SharedSurfaceGL.h"
#include "SharedSurfaceEGL.h"
#include "SurfaceStream.h"
#include "gfxColor.h"
#ifdef XP_MACOSX
#include "mozilla/gfx/MacIOSurface.h"
@ -36,6 +40,7 @@
using namespace mozilla;
using namespace mozilla::layers;
using namespace mozilla::gl;
using namespace mozilla::gfx;
static void
MakeTextureIfNeeded(GLContext* gl, GLuint& aTexture)
@ -102,7 +107,7 @@ CanvasLayerOGL::Initialize(const Data& aData)
if (aData.mGLContext != nullptr &&
aData.mSurface != nullptr)
{
NS_WARNING("CanvasLayerOGL can't have both surface and GLContext");
NS_WARNING("CanvasLayerOGL can't have both surface and WebGLContext");
return;
}
@ -131,20 +136,30 @@ CanvasLayerOGL::Initialize(const Data& aData)
} else {
mLayerProgram = gl::RGBXLayerProgramType;
}
MakeTextureIfNeeded(gl(), mTexture);
MakeTextureIfNeeded(gl(), mUploadTexture);
}
}
#endif
} else if (aData.mGLContext) {
if (!aData.mGLContext->IsOffscreen()) {
NS_WARNING("CanvasLayerOGL with a non-offscreen GL context given");
return;
mGLContext = aData.mGLContext;
NS_ASSERTION(mGLContext->IsOffscreen(), "Canvas GLContext must be offscreen.");
mIsGLAlphaPremult = aData.mIsGLAlphaPremult;
mNeedsYFlip = true;
// [OGL Layers, MTC] WebGL layer init.
GLScreenBuffer* screen = mGLContext->Screen();
SurfaceStreamType streamType =
SurfaceStream::ChooseGLStreamType(SurfaceStream::MainThread,
screen->PreserveBuffer());
SurfaceFactory_GL* factory = nullptr;
if (!mForceReadback) {
factory = new SurfaceFactory_GLTexture(mGLContext, gl(), screen->Caps());
}
mCanvasGLContext = aData.mGLContext;
mGLBufferIsPremultiplied = aData.mGLBufferIsPremultiplied;
mNeedsYFlip = mCanvasGLContext->GetOffscreenTexture() != 0;
if (factory) {
screen->Morph(factory, streamType);
}
} else {
NS_WARNING("CanvasLayerOGL::Initialize called without surface or GL context!");
return;
@ -158,7 +173,7 @@ CanvasLayerOGL::Initialize(const Data& aData)
gl()->fGetIntegerv(LOCAL_GL_MAX_TEXTURE_SIZE, &texSize);
if (mBounds.width > (2 + texSize) || mBounds.height > (2 + texSize)) {
mDelayedUpdates = true;
MakeTextureIfNeeded(gl(), mTexture);
MakeTextureIfNeeded(gl(), mUploadTexture);
// This should only ever occur with 2d canvas, WebGL can't already have a texture
// of this size can it?
NS_ABORT_IF_FALSE(mCanvasSurface || mDrawTarget,
@ -187,72 +202,73 @@ CanvasLayerOGL::UpdateSurface()
}
#endif
if (mCanvasGLContext) {
mCanvasGLContext->MakeCurrent();
}
if (mCanvasGLContext &&
!mForceReadback &&
mCanvasGLContext->GetContextType() == gl()->GetContextType())
{
DiscardTempSurface();
// Can texture share, just make sure it's resolved first
mCanvasGLContext->GuaranteeResolve();
if (gl()->BindOffscreenNeedsTexture(mCanvasGLContext) &&
mTexture == 0)
{
mOGLManager->MakeCurrent();
MakeTextureIfNeeded(gl(), mTexture);
gfxASurface* updatedSurface = nullptr;
gfxImageSurface* temporarySurface = nullptr;
bool nothingToShow = false;
if (mGLContext) {
SharedSurface* surf = mGLContext->RequestFrame();
if (surf) {
mLayerProgram = surf->HasAlpha() ? RGBALayerProgramType
: RGBXLayerProgramType;
switch (surf->Type()) {
case SharedSurfaceType::Basic: {
SharedSurface_Basic* readbackSurf = SharedSurface_Basic::Cast(surf);
updatedSurface = readbackSurf->GetData();
break;
}
case SharedSurfaceType::GLTextureShare: {
SharedSurface_GLTexture* textureSurf = SharedSurface_GLTexture::Cast(surf);
mTexture = textureSurf->Texture();
break;
}
default:
MOZ_NOT_REACHED("Unacceptable SharedSurface type.");
return;
}
} else {
nothingToShow = true;
}
return;
}
#ifdef XP_MACOSX
if (mDrawTarget && mDrawTarget->GetNativeSurface(gfx::NATIVE_SURFACE_CGCONTEXT_ACCELERATED)) {
if (!mTexture) {
mTexture = MakeIOSurfaceTexture((CGContextRef)mDrawTarget->GetNativeSurface(
gfx::NATIVE_SURFACE_CGCONTEXT_ACCELERATED),
gl());
mTextureTarget = LOCAL_GL_TEXTURE_RECTANGLE_ARB;
mLayerProgram = gl::RGBARectLayerProgramType;
}
mDrawTarget->Flush();
return;
}
#endif
nsRefPtr<gfxASurface> updatedAreaSurface;
if (mCanvasGLContext) {
gfxIntSize size(mBounds.width, mBounds.height);
nsRefPtr<gfxImageSurface> updatedAreaImageSurface =
GetTempSurface(size, gfxASurface::ImageFormatARGB32);
updatedAreaImageSurface->Flush();
mCanvasGLContext->ReadScreenIntoImageSurface(updatedAreaImageSurface);
updatedAreaImageSurface->MarkDirty();
updatedAreaSurface = updatedAreaImageSurface;
} else if (mCanvasSurface) {
updatedAreaSurface = mCanvasSurface;
#ifdef XP_MACOSX
if (mDrawTarget && mDrawTarget->GetNativeSurface(gfx::NATIVE_SURFACE_CGCONTEXT_ACCELERATED)) {
if (!mTexture) {
mTexture = MakeIOSurfaceTexture((CGContextRef)mDrawTarget->GetNativeSurface(
gfx::NATIVE_SURFACE_CGCONTEXT_ACCELERATED),
gl());
mTextureTarget = LOCAL_GL_TEXTURE_RECTANGLE_ARB;
mLayerProgram = gl::RGBARectLayerProgramType;
}
mDrawTarget->Flush();
return;
}
#endif
updatedSurface = mCanvasSurface;
} else {
MOZ_NOT_REACHED("Unhandled canvas layer type.");
return;
}
mOGLManager->MakeCurrent();
mLayerProgram = gl()->UploadSurfaceToTexture(updatedAreaSurface,
mBounds,
mTexture,
false,
nsIntPoint(0, 0));
if (updatedSurface) {
mOGLManager->MakeCurrent();
mLayerProgram = gl()->UploadSurfaceToTexture(updatedSurface,
mBounds,
mUploadTexture,
true,//false,
nsIntPoint(0, 0));
mTexture = mUploadTexture;
if (temporarySurface)
delete temporarySurface;
}
MOZ_ASSERT(mTexture || nothingToShow);
}
void
CanvasLayerOGL::RenderLayer(int aPreviousDestination,
const nsIntPoint& aOffset)
{
FirePreTransactionCallback();
UpdateSurface();
if (mOGLManager->CompositingDisabled()) {
return;
@ -273,18 +289,8 @@ CanvasLayerOGL::RenderLayer(int aPreviousDestination,
ShaderProgramOGL *program = nullptr;
bool useGLContext = mCanvasGLContext &&
!mForceReadback &&
mCanvasGLContext->GetContextType() == gl()->GetContextType();
nsIntRect drawRect = mBounds;
if (useGLContext) {
gl()->BindTex2DOffscreen(mCanvasGLContext);
program = mOGLManager->GetBasicLayerProgram(CanUseOpaqueSurface(),
true,
GetMaskLayer() ? Mask2d : MaskNone);
} else if (mDelayedUpdates) {
if (mDelayedUpdates) {
NS_ABORT_IF_FALSE(mCanvasSurface || mDrawTarget, "WebGL canvases should always be using full texture upload");
drawRect.IntersectRect(drawRect, GetEffectiveVisibleRegion().GetBounds());
@ -292,9 +298,10 @@ CanvasLayerOGL::RenderLayer(int aPreviousDestination,
mLayerProgram =
gl()->UploadSurfaceToTexture(mCanvasSurface,
nsIntRect(0, 0, drawRect.width, drawRect.height),
mTexture,
mUploadTexture,
true,
drawRect.TopLeft());
mTexture = mUploadTexture;
}
if (!program) {
@ -332,18 +339,15 @@ CanvasLayerOGL::RenderLayer(int aPreviousDestination,
sDefGLXLib.ReleaseTexImage(mPixmap);
}
#endif
if (useGLContext) {
gl()->UnbindTex2DOffscreen(mCanvasGLContext);
}
}
void
CanvasLayerOGL::CleanupResources()
{
if (mTexture) {
if (mUploadTexture) {
gl()->MakeCurrent();
gl()->fDeleteTextures(1, &mTexture);
gl()->fDeleteTextures(1, &mUploadTexture);
mUploadTexture = 0;
}
}
@ -353,11 +357,20 @@ IsValidSharedTexDescriptor(const SurfaceDescriptor& aDescriptor)
return aDescriptor.type() == SurfaceDescriptor::TSharedTextureDescriptor;
}
static bool
IsValidSurfaceStreamDescriptor(const SurfaceDescriptor& aDescriptor)
{
return aDescriptor.type() == SurfaceDescriptor::TSurfaceStreamDescriptor;
}
ShadowCanvasLayerOGL::ShadowCanvasLayerOGL(LayerManagerOGL* aManager)
: ShadowCanvasLayer(aManager, nullptr)
, LayerOGL(aManager)
, mNeedsYFlip(false)
, mTexture(0)
, mUploadTexture(0)
, mCurTexture(0)
, mGrallocImage(EGL_NO_IMAGE)
, mShaderType(RGBXLayerProgramType)
{
mImplData = static_cast<LayerOGL*>(this);
}
@ -394,13 +407,17 @@ ShadowCanvasLayerOGL::Swap(const CanvasSurface& aNewFront,
return;
}
if (nsRefPtr<TextureImage> texImage =
const SurfaceDescriptor& frontDesc = aNewFront.get_SurfaceDescriptor();
nsRefPtr<TextureImage> texImage =
ShadowLayerManager::OpenDescriptorForDirectTexturing(
gl(), aNewFront.get_SurfaceDescriptor(), LOCAL_GL_CLAMP_TO_EDGE)) {
gl(), frontDesc, LOCAL_GL_CLAMP_TO_EDGE);
if (texImage) {
if (mTexImage &&
(mTexImage->GetSize() != texImage->GetSize() ||
mTexImage->GetContentType() != texImage->GetContentType())) {
mTexImage->GetContentType() != texImage->GetContentType()))
{
mTexImage = nullptr;
DestroyFrontBuffer();
}
@ -411,7 +428,7 @@ ShadowCanvasLayerOGL::Swap(const CanvasSurface& aNewFront,
mFrontBufferDescriptor = aNewFront;
mNeedsYFlip = needYFlip;
} else if (IsValidSharedTexDescriptor(aNewFront)) {
MakeTextureIfNeeded(gl(), mTexture);
MakeTextureIfNeeded(gl(), mUploadTexture);
if (!IsValidSharedTexDescriptor(mFrontBufferDescriptor)) {
mFrontBufferDescriptor = SharedTextureDescriptor(GLContext::SameProcess,
0,
@ -421,14 +438,25 @@ ShadowCanvasLayerOGL::Swap(const CanvasSurface& aNewFront,
*aNewBack = mFrontBufferDescriptor;
mFrontBufferDescriptor = aNewFront;
mNeedsYFlip = needYFlip;
} else if (IsValidSurfaceStreamDescriptor(frontDesc)) {
// Check our previous desc.
if (!IsValidSurfaceStreamDescriptor(mFrontBufferDescriptor)) {
SurfaceStreamHandle handle = (SurfaceStreamHandle)nullptr;
mFrontBufferDescriptor = SurfaceStreamDescriptor(handle, false);
}
*aNewBack = mFrontBufferDescriptor;
mFrontBufferDescriptor = aNewFront;
mNeedsYFlip = needYFlip;
} else {
AutoOpenSurface autoSurf(OPEN_READ_ONLY, aNewFront);
gfxIntSize sz = autoSurf.Size();
if (!mTexImage || mTexImage->GetSize() != sz ||
mTexImage->GetContentType() != autoSurf.ContentType()) {
gfxIntSize autoSurfSize = autoSurf.Size();
if (!mTexImage ||
mTexImage->GetSize() != autoSurfSize ||
mTexImage->GetContentType() != autoSurf.ContentType())
{
Init(aNewFront, needYFlip);
}
nsIntRegion updateRegion(nsIntRect(0, 0, sz.width, sz.height));
nsIntRegion updateRegion(nsIntRect(0, 0, autoSurfSize.width, autoSurfSize.height));
mTexImage->DirectUpdate(autoSurf.Get(), updateRegion);
*aNewBack = aNewFront;
}
@ -438,13 +466,25 @@ void
ShadowCanvasLayerOGL::DestroyFrontBuffer()
{
mTexImage = nullptr;
if (mTexture) {
if (mUploadTexture) {
gl()->MakeCurrent();
gl()->fDeleteTextures(1, &mTexture);
gl()->fDeleteTextures(1, &mUploadTexture);
}
if (IsValidSharedTexDescriptor(mFrontBufferDescriptor)) {
SharedTextureDescriptor texDescriptor = mFrontBufferDescriptor.get_SharedTextureDescriptor();
gl()->ReleaseSharedHandle(texDescriptor.shareType(), texDescriptor.handle());
MOZ_ASSERT(!IsValidSharedTexDescriptor(mFrontBufferDescriptor));
gl()->EmptyTexGarbageBin();
if (mGrallocImage) {
GLLibraryEGL* egl = (GLLibraryEGL*)gl()->GetLibraryEGL();
MOZ_ASSERT(egl);
egl->fDestroyImage(egl->Display(), mGrallocImage);
mGrallocImage = 0;
}
if (IsValidSurfaceStreamDescriptor(mFrontBufferDescriptor)) {
// Nothing needed.
mFrontBufferDescriptor = SurfaceDescriptor();
} else if (IsSurfaceDescriptorValid(mFrontBufferDescriptor)) {
mAllocator->DestroySharedSurface(&mFrontBufferDescriptor);
@ -486,7 +526,10 @@ void
ShadowCanvasLayerOGL::RenderLayer(int aPreviousFrameBuffer,
const nsIntPoint& aOffset)
{
if (!mTexImage && !IsValidSharedTexDescriptor(mFrontBufferDescriptor)) {
if (!mTexImage &&
!IsValidSharedTexDescriptor(mFrontBufferDescriptor) &&
!IsValidSurfaceStreamDescriptor(mFrontBufferDescriptor))
{
return;
}
@ -494,6 +537,8 @@ ShadowCanvasLayerOGL::RenderLayer(int aPreviousFrameBuffer,
return;
}
mOGLManager->MakeCurrent();
gl()->EmptyTexGarbageBin();
//ScopedBindTexture autoTex(gl());
gfx3DMatrix effectiveTransform = GetEffectiveTransform();
gfxPattern::GraphicsFilter filter = mFilter;
@ -507,17 +552,83 @@ ShadowCanvasLayerOGL::RenderLayer(int aPreviousFrameBuffer,
filter = gfxPattern::FILTER_NEAREST;
}
#endif
SurfaceStream* surfStream = nullptr;
SharedSurface* sharedSurf = nullptr;
if (IsValidSurfaceStreamDescriptor(mFrontBufferDescriptor)) {
const SurfaceStreamDescriptor& streamDesc =
mFrontBufferDescriptor.get_SurfaceStreamDescriptor();
ShaderProgramOGL *program;
if (IsValidSharedTexDescriptor(mFrontBufferDescriptor)) {
program = mOGLManager->GetBasicLayerProgram(CanUseOpaqueSurface(),
true,
GetMaskLayer() ? Mask2d : MaskNone);
surfStream = SurfaceStream::FromHandle(streamDesc.handle());
MOZ_ASSERT(surfStream);
sharedSurf = surfStream->SwapConsumer();
if (!sharedSurf) {
// We don't have a valid surf to show yet.
return;
}
gfxImageSurface* toUpload = nullptr;
switch (sharedSurf->Type()) {
case SharedSurfaceType::GLTextureShare: {
mCurTexture = SharedSurface_GLTexture::Cast(sharedSurf)->Texture();
MOZ_ASSERT(mCurTexture);
mShaderType = sharedSurf->HasAlpha() ? RGBALayerProgramType
: RGBXLayerProgramType;
break;
}
case SharedSurfaceType::EGLImageShare: {
SharedSurface_EGLImage* eglImageSurf =
SharedSurface_EGLImage::Cast(sharedSurf);
mCurTexture = eglImageSurf->AcquireConsumerTexture(gl());
if (!mCurTexture) {
toUpload = eglImageSurf->GetPixels();
MOZ_ASSERT(toUpload);
} else {
mShaderType = sharedSurf->HasAlpha() ? RGBALayerProgramType
: RGBXLayerProgramType;
}
break;
}
case SharedSurfaceType::Basic: {
toUpload = SharedSurface_Basic::Cast(sharedSurf)->GetData();
MOZ_ASSERT(toUpload);
break;
}
default:
MOZ_NOT_REACHED("Invalid SharedSurface type.");
return;
}
if (toUpload) {
// mBounds seems to end up as (0,0,0,0) a lot, so don't use it?
nsIntSize size(toUpload->GetSize());
nsIntRect rect(nsIntPoint(0,0), size);
nsIntRegion bounds(rect);
mShaderType = gl()->UploadSurfaceToTexture(toUpload,
bounds,
mUploadTexture,
true);
mCurTexture = mUploadTexture;
}
MOZ_ASSERT(mCurTexture);
gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, mCurTexture);
gl()->fTexParameteri(LOCAL_GL_TEXTURE_2D,
LOCAL_GL_TEXTURE_WRAP_S,
LOCAL_GL_CLAMP_TO_EDGE);
gl()->fTexParameteri(LOCAL_GL_TEXTURE_2D,
LOCAL_GL_TEXTURE_WRAP_T,
LOCAL_GL_CLAMP_TO_EDGE);
} else if (mTexImage) {
mShaderType = mTexImage->GetShaderProgramType();
} else {
program = mOGLManager->GetProgram(mTexImage->GetShaderProgramType(),
GetMaskLayer());
MOZ_NOT_REACHED("What can we do?");
return;
}
ShaderProgramOGL* program = mOGLManager->GetProgram(mShaderType, GetMaskLayer());
program->Activate();
program->SetLayerTransform(effectiveTransform);
program->SetLayerOpacity(GetEffectiveOpacity());
@ -525,19 +636,14 @@ ShadowCanvasLayerOGL::RenderLayer(int aPreviousFrameBuffer,
program->SetTextureUnit(0);
program->LoadMask(GetMaskLayer());
if (IsValidSharedTexDescriptor(mFrontBufferDescriptor)) {
// Shared texture handle rendering path, single texture rendering
SharedTextureDescriptor texDescriptor = mFrontBufferDescriptor.get_SharedTextureDescriptor();
gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture);
if (!gl()->AttachSharedHandle(texDescriptor.shareType(), texDescriptor.handle())) {
NS_ERROR("Failed to attach shared texture handle");
return;
}
if (surfStream) {
MOZ_ASSERT(sharedSurf);
gl()->ApplyFilterToBoundTexture(filter);
program->SetLayerQuadRect(nsIntRect(nsIntPoint(0, 0), texDescriptor.size()));
program->SetLayerQuadRect(nsIntRect(nsIntPoint(0, 0), sharedSurf->Size()));
mOGLManager->BindAndDrawQuad(program, mNeedsYFlip);
gl()->DetachSharedHandle(texDescriptor.shareType(), texDescriptor.handle());
gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, 0);
} else {
// Tiled texture image rendering path

View File

@ -6,15 +6,16 @@
#ifndef GFX_CANVASLAYEROGL_H
#define GFX_CANVASLAYEROGL_H
#include "LayerManagerOGL.h"
#include "gfxASurface.h"
#include "GLDefs.h"
#include "mozilla/Preferences.h"
#if defined(GL_PROVIDER_GLX)
#include "GLXLibrary.h"
#include "mozilla/X11Util.h"
#endif
#include "mozilla/Preferences.h"
namespace mozilla {
namespace layers {
@ -25,20 +26,25 @@ class THEBES_API CanvasLayerOGL :
{
public:
CanvasLayerOGL(LayerManagerOGL *aManager)
: CanvasLayer(aManager, NULL),
LayerOGL(aManager),
mLayerProgram(gl::RGBALayerProgramType),
mTexture(0),
mTextureTarget(LOCAL_GL_TEXTURE_2D),
mDelayedUpdates(false)
: CanvasLayer(aManager, NULL)
, LayerOGL(aManager)
, mLayerProgram(gl::RGBALayerProgramType)
, mTexture(0)
, mTextureTarget(LOCAL_GL_TEXTURE_2D)
, mDelayedUpdates(false)
, mIsGLAlphaPremult(false)
, mUploadTexture(0)
#if defined(GL_PROVIDER_GLX)
,mPixmap(0)
, mPixmap(0)
#endif
{
mImplData = static_cast<LayerOGL*>(this);
mForceReadback = Preferences::GetBool("webgl.force-layers-readback", false);
mImplData = static_cast<LayerOGL*>(this);
mForceReadback = Preferences::GetBool("webgl.force-layers-readback", false);
}
~CanvasLayerOGL() {
Destroy();
}
~CanvasLayerOGL() { Destroy(); }
// CanvasLayer implementation
virtual void Initialize(const Data& aData);
@ -54,7 +60,7 @@ protected:
void UpdateSurface();
nsRefPtr<gfxASurface> mCanvasSurface;
nsRefPtr<GLContext> mCanvasGLContext;
nsRefPtr<GLContext> mGLContext;
gl::ShaderProgramType mLayerProgram;
RefPtr<gfx::DrawTarget> mDrawTarget;
@ -62,9 +68,10 @@ protected:
GLenum mTextureTarget;
bool mDelayedUpdates;
bool mGLBufferIsPremultiplied;
bool mIsGLAlphaPremult;
bool mNeedsYFlip;
bool mForceReadback;
GLuint mUploadTexture;
#if defined(GL_PROVIDER_GLX)
GLXPixmap mPixmap;
#endif
@ -89,8 +96,7 @@ protected:
return mCachedTempSurface;
}
void DiscardTempSurface()
{
void DiscardTempSurface() {
mCachedTempSurface = nullptr;
}
};
@ -136,7 +142,10 @@ private:
bool mNeedsYFlip;
SurfaceDescriptor mFrontBufferDescriptor;
GLuint mTexture;
GLuint mUploadTexture;
GLuint mCurTexture;
EGLImage mGrallocImage;
gl::ShaderProgramType mShaderType;
};
} /* layers */

View File

@ -752,7 +752,6 @@ ShadowImageLayerOGL::Swap(const SharedImage& aNewFront,
SharedImage* aNewBack)
{
if (!mDestroyed) {
if (aNewFront.type() == SharedImage::TSharedImageID) {
// We are using ImageBridge protocol. The image data will be queried at render
// time in the parent side.

View File

@ -64,6 +64,7 @@ int32_t
LayerManagerOGL::GetMaxTextureSize() const
{
int32_t maxSize;
mGLContext->MakeCurrent();
mGLContext->fGetIntegerv(LOCAL_GL_MAX_TEXTURE_SIZE, &maxSize);
return maxSize;
}

View File

@ -37,14 +37,14 @@ gfxUtils::PremultiplyImageSurface(gfxImageSurface *aSourceSurface,
if (!aDestSurface)
aDestSurface = aSourceSurface;
NS_ASSERTION(aSourceSurface->Format() == aDestSurface->Format() &&
aSourceSurface->Width() == aDestSurface->Width() &&
aSourceSurface->Height() == aDestSurface->Height() &&
aSourceSurface->Stride() == aDestSurface->Stride(),
"Source and destination surfaces don't have identical characteristics");
MOZ_ASSERT(aSourceSurface->Format() == aDestSurface->Format() &&
aSourceSurface->Width() == aDestSurface->Width() &&
aSourceSurface->Height() == aDestSurface->Height() &&
aSourceSurface->Stride() == aDestSurface->Stride(),
"Source and destination surfaces don't have identical characteristics");
NS_ASSERTION(aSourceSurface->Stride() == aSourceSurface->Width() * 4,
"Source surface stride isn't tightly packed");
MOZ_ASSERT(aSourceSurface->Stride() == aSourceSurface->Width() * 4,
"Source surface stride isn't tightly packed");
// Only premultiply ARGB32
if (aSourceSurface->Format() != gfxASurface::ImageFormatARGB32) {
@ -91,14 +91,14 @@ gfxUtils::UnpremultiplyImageSurface(gfxImageSurface *aSourceSurface,
if (!aDestSurface)
aDestSurface = aSourceSurface;
NS_ASSERTION(aSourceSurface->Format() == aDestSurface->Format() &&
aSourceSurface->Width() == aDestSurface->Width() &&
aSourceSurface->Height() == aDestSurface->Height() &&
aSourceSurface->Stride() == aDestSurface->Stride(),
"Source and destination surfaces don't have identical characteristics");
MOZ_ASSERT(aSourceSurface->Format() == aDestSurface->Format() &&
aSourceSurface->Width() == aDestSurface->Width() &&
aSourceSurface->Height() == aDestSurface->Height() &&
aSourceSurface->Stride() == aDestSurface->Stride(),
"Source and destination surfaces don't have identical characteristics");
NS_ASSERTION(aSourceSurface->Stride() == aSourceSurface->Width() * 4,
"Source surface stride isn't tightly packed");
MOZ_ASSERT(aSourceSurface->Stride() == aSourceSurface->Width() * 4,
"Source surface stride isn't tightly packed");
// Only premultiply ARGB32
if (aSourceSurface->Format() != gfxASurface::ImageFormatARGB32) {
@ -144,17 +144,17 @@ gfxUtils::ConvertBGRAtoRGBA(gfxImageSurface *aSourceSurface,
if (!aDestSurface)
aDestSurface = aSourceSurface;
NS_ABORT_IF_FALSE(aSourceSurface->Format() == aDestSurface->Format() &&
aSourceSurface->Width() == aDestSurface->Width() &&
aSourceSurface->Height() == aDestSurface->Height() &&
aSourceSurface->Stride() == aDestSurface->Stride(),
"Source and destination surfaces don't have identical characteristics");
MOZ_ASSERT(aSourceSurface->Format() == aDestSurface->Format() &&
aSourceSurface->Width() == aDestSurface->Width() &&
aSourceSurface->Height() == aDestSurface->Height() &&
aSourceSurface->Stride() == aDestSurface->Stride(),
"Source and destination surfaces don't have identical characteristics");
NS_ABORT_IF_FALSE(aSourceSurface->Stride() == aSourceSurface->Width() * 4,
"Source surface stride isn't tightly packed");
MOZ_ASSERT(aSourceSurface->Stride() == aSourceSurface->Width() * 4,
"Source surface stride isn't tightly packed");
NS_ABORT_IF_FALSE(aSourceSurface->Format() == gfxASurface::ImageFormatARGB32,
"Surfaces must be ARGB32");
MOZ_ASSERT(aSourceSurface->Format() == gfxASurface::ImageFormatARGB32,
"Surfaces must be ARGB32");
uint8_t *src = aSourceSurface->Data();
uint8_t *dst = aDestSurface->Data();

View File

@ -3852,13 +3852,13 @@ pref("image.mem.max_ms_before_yield", 5);
pref("image.mem.max_decoded_image_kb", 51200);
// WebGL prefs
pref("gl.msaa-level", 2);
pref("webgl.force-enabled", false);
pref("webgl.disabled", false);
pref("webgl.shader_validator", true);
pref("webgl.prefer-native-gl", false);
pref("webgl.min_capability_mode", false);
pref("webgl.disable-extensions", false);
pref("webgl.msaa-level", 2);
pref("webgl.msaa-force", false);
pref("webgl.prefer-16bpp", false);
pref("webgl.default-no-alpha", false);