mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 716859 - Streaming GLContext buffers (doublebuffering, etc) - r=bjacob,jrmuizel,vlad
This commit is contained in:
parent
381ac3ed45
commit
3375a513c3
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
1151
gfx/gl/GLContext.h
1151
gfx/gl/GLContext.h
File diff suppressed because it is too large
Load Diff
@ -10,6 +10,7 @@
|
||||
#include "gfxTypes.h"
|
||||
#include "gfxPoint.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "SurfaceTypes.h"
|
||||
|
||||
class nsIWidget;
|
||||
class gfxASurface;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
@ -1057,7 +1050,7 @@ bool GLContextEGL::AttachSharedHandle(SharedTextureShareType shareType,
|
||||
break;
|
||||
}
|
||||
#endif // MOZ_WIDGET_ANDROID
|
||||
|
||||
|
||||
case SharedHandleType::Image: {
|
||||
NS_ASSERTION(mShareWithEGLImage, "EGLImage not supported or disabled in runtime");
|
||||
|
||||
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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
19
gfx/gl/GLContextTypes.cpp
Normal 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));
|
||||
}
|
@ -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_ */
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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
619
gfx/gl/GLScreenBuffer.cpp
Normal 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
296
gfx/gl/GLScreenBuffer.h
Normal 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_
|
@ -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);
|
||||
|
@ -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
29
gfx/gl/SharedSurface.cpp
Normal 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
122
gfx/gl/SharedSurface.h
Normal 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_ */
|
275
gfx/gl/SharedSurfaceANGLE.cpp
Normal file
275
gfx/gl/SharedSurfaceANGLE.cpp
Normal 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
115
gfx/gl/SharedSurfaceANGLE.h
Normal 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
262
gfx/gl/SharedSurfaceEGL.cpp
Normal 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
135
gfx/gl/SharedSurfaceEGL.h
Normal 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
390
gfx/gl/SharedSurfaceGL.cpp
Normal 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
254
gfx/gl/SharedSurfaceGL.h
Normal 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
59
gfx/gl/SurfaceFactory.cpp
Normal 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
55
gfx/gl/SurfaceFactory.h
Normal 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
413
gfx/gl/SurfaceStream.cpp
Normal 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
189
gfx/gl/SurfaceStream.h
Normal 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
107
gfx/gl/SurfaceTypes.h
Normal 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_ */
|
@ -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:
|
||||
|
@ -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;
|
||||
|
||||
uint32_t mCanvasFramebuffer;
|
||||
nsRefPtr<mozilla::gl::GLContext> mGLContext;
|
||||
|
||||
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();
|
||||
|
||||
|
@ -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;
|
||||
|
||||
HRESULT hr = mTexture->Map(0, D3D10_MAP_WRITE_DISCARD, 0, &map);
|
||||
SharedSurface* surf = mGLContext->RequestFrame();
|
||||
if (!surf)
|
||||
return;
|
||||
|
||||
if (FAILED(hr)) {
|
||||
NS_WARNING("Failed to map CanvasLayer texture.");
|
||||
return;
|
||||
}
|
||||
switch (surf->Type()) {
|
||||
case SharedSurfaceType::EGLSurfaceANGLE: {
|
||||
SharedSurface_ANGLEShareHandle* shareSurf = SharedSurface_ANGLEShareHandle::Cast(surf);
|
||||
|
||||
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();
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
|
@ -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.
|
||||
|
@ -64,6 +64,7 @@ int32_t
|
||||
LayerManagerOGL::GetMaxTextureSize() const
|
||||
{
|
||||
int32_t maxSize;
|
||||
mGLContext->MakeCurrent();
|
||||
mGLContext->fGetIntegerv(LOCAL_GL_MAX_TEXTURE_SIZE, &maxSize);
|
||||
return maxSize;
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user