Bug 830881 - Port layerscope GL changes to new layers. r=vlad

This commit is contained in:
Dan Glastonbury 2013-11-29 14:11:49 +10:00
parent a940e05e20
commit 7f73b68e55
11 changed files with 989 additions and 112 deletions

View File

@ -28,6 +28,8 @@
#include "TextureGarbageBin.h" #include "TextureGarbageBin.h"
#include "gfx2DGlue.h" #include "gfx2DGlue.h"
#include "OGLShaderProgram.h" // for ShaderProgramType
#include "mozilla/DebugOnly.h" #include "mozilla/DebugOnly.h"
#include "mozilla/Preferences.h" #include "mozilla/Preferences.h"
@ -41,6 +43,7 @@
#endif #endif
using namespace mozilla::gfx; using namespace mozilla::gfx;
using namespace mozilla::layers;
namespace mozilla { namespace mozilla {
namespace gl { namespace gl {
@ -273,6 +276,11 @@ GLContext::GLContext(const SurfaceCaps& caps,
mWorkAroundDriverBugs(true) mWorkAroundDriverBugs(true)
{ {
mOwningThread = NS_GetCurrentThread(); mOwningThread = NS_GetCurrentThread();
mReadTextureImagePrograms[0] = 0;
mReadTextureImagePrograms[1] = 0;
mReadTextureImagePrograms[2] = 0;
mReadTextureImagePrograms[3] = 0;
} }
GLContext::~GLContext() { GLContext::~GLContext() {
@ -1855,6 +1863,11 @@ GLContext::MarkDestroyed()
mBlitHelper = nullptr; mBlitHelper = nullptr;
mBlitTextureImageHelper = nullptr; mBlitTextureImageHelper = nullptr;
fDeleteProgram(mReadTextureImagePrograms[0]);
fDeleteProgram(mReadTextureImagePrograms[1]);
fDeleteProgram(mReadTextureImagePrograms[2]);
fDeleteProgram(mReadTextureImagePrograms[3]);
mTexGarbageBin->GLContextTeardown(); mTexGarbageBin->GLContextTeardown();
} else { } else {
NS_WARNING("MakeCurrent() failed during MarkDestroyed! Skipping GL object teardown."); NS_WARNING("MakeCurrent() failed during MarkDestroyed! Skipping GL object teardown.");
@ -1938,144 +1951,340 @@ GLContext::GetTexImage(GLuint aTexture, bool aYInvert, SurfaceFormat aFormat)
return surf.forget(); return surf.forget();
} }
already_AddRefed<gfxImageSurface> static float
GLContext::ReadTextureImage(GLuint aTexture, gReadTextureImageVerts[4*4] = {
const gfxIntSize& aSize, -1.0f, -1.0f, 0.0f, 1.0f,
GLenum aTextureFormat, 1.0f, -1.0f, 0.0f, 1.0f,
bool aYInvert) -1.0f, 1.0f, 0.0f, 1.0f,
1.0f, 1.0f, 0.0f, 1.0f
};
static float*
ReadTextureVertexArray()
{ {
MakeCurrent(); return gReadTextureImageVerts;
}
nsRefPtr<gfxImageSurface> isurf; static float
gReadTextureImageTexcoords[2*4] = {
0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f
};
GLint oldrb, oldfb, oldprog, oldPackAlignment; static float*
GLint success; ReadTextureTexCoordArray(float aWidth, float aHeight, bool aFlip)
{
const float u0 = 0.0f;
const float u1 = aWidth;
const float v0 = (aFlip) ? aHeight : 0.0f;
const float v1 = (aFlip) ? 0.0f : aHeight;
GLuint rb = 0, fb = 0; float* uvs = gReadTextureImageTexcoords;
GLuint vs = 0, fs = 0, prog = 0; uvs[0] = u0;
uvs[1] = v0;
uvs[2] = u1;
uvs[3] = v0;
uvs[4] = u0;
uvs[5] = v1;
uvs[6] = u1;
uvs[7] = v1;
const char *vShader = return uvs;
"attribute vec4 aVertex;\n" }
"attribute vec2 aTexCoord;\n"
"varying vec2 vTexCoord;\n"
"void main() { gl_Position = aVertex; vTexCoord = aTexCoord; }";
const char *fShader =
"#ifdef GL_ES\n"
"precision mediump float;\n"
"#endif\n"
"varying vec2 vTexCoord;\n"
"uniform sampler2D uTexture;\n"
"void main() { gl_FragColor = texture2D(uTexture, vTexCoord); }";
float verts[4*4] = { static const char*
-1.0f, -1.0f, 0.0f, 1.0f, gReadTextureImageVS =
1.0f, -1.0f, 0.0f, 1.0f, "attribute vec4 aVertex;\n"
-1.0f, 1.0f, 0.0f, 1.0f, "attribute vec2 aTexCoord;\n"
1.0f, 1.0f, 0.0f, 1.0f "varying vec2 vTexCoord;\n"
}; "void main() { gl_Position = aVertex; vTexCoord = aTexCoord; }";
float texcoords[2*4] = { static const char*
0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f gReadTextureImageFS[] = {
}; /* TEXTURE_2D */
"#ifdef GL_ES\n"
"precision mediump float;\n"
"#endif\n"
"varying vec2 vTexCoord;\n"
"uniform sampler2D uTexture;\n"
"void main() { gl_FragColor = texture2D(uTexture, vTexCoord); }"
,
/* TEXTURE_2D with R/B swizzling */
"#ifdef GL_ES\n"
"precision mediump float;\n"
"#endif\n"
"varying vec2 vTexCoord;\n"
"uniform sampler2D uTexture;\n"
"void main() { gl_FragColor = texture2D(uTexture, vTexCoord).bgra; }"
,
/* TEXTURE_EXTERNAL */
"#extension GL_OES_EGL_image_external : require\n"
"#ifdef GL_ES\n"
"precision mediump float;\n"
"#endif\n"
"varying vec2 vTexCoord;\n"
"uniform samplerExternalOES uTexture;\n"
"void main() { gl_FragColor = texture2D(uTexture, vTexCoord); }"
,
/* TEXTURE_RECTANGLE */
"#extension GL_ARB_texture_rectangle\n"
"#ifdef GL_ES\n"
"precision mediump float;\n"
"#endif\n"
"varying vec2 vTexCoord;\n"
"uniform sampler2DRect uTexture;\n"
"void main() { gl_FragColor = texture2DRect(uTexture, vTexCoord).bgra; }"
};
fGetIntegerv(LOCAL_GL_RENDERBUFFER_BINDING, &oldrb); GLuint
fGetIntegerv(LOCAL_GL_FRAMEBUFFER_BINDING, &oldfb); GLContext::TextureImageProgramFor(GLenum aTextureTarget, int aShader) {
fGetIntegerv(LOCAL_GL_CURRENT_PROGRAM, &oldprog); int variant = 0;
if (aTextureTarget == LOCAL_GL_TEXTURE_2D &&
(aShader == layers::BGRALayerProgramType ||
aShader == layers::BGRXLayerProgramType))
{ // Need to swizzle R/B.
variant = 1;
} else if (aTextureTarget == LOCAL_GL_TEXTURE_EXTERNAL) {
variant = 2;
} else if (aTextureTarget == LOCAL_GL_TEXTURE_RECTANGLE) {
variant = 3;
}
/* This might be overkill, but assure that we don't access out-of-bounds */
MOZ_ASSERT((size_t) variant < ArrayLength(mReadTextureImagePrograms));
if (!mReadTextureImagePrograms[variant]) {
GLuint vs = fCreateShader(LOCAL_GL_VERTEX_SHADER);
fShaderSource(vs, 1, (const GLchar**) &gReadTextureImageVS, NULL);
fCompileShader(vs);
GLuint fs = fCreateShader(LOCAL_GL_FRAGMENT_SHADER);
fShaderSource(fs, 1, (const GLchar**) &gReadTextureImageFS[variant], NULL);
fCompileShader(fs);
GLuint program = fCreateProgram();
fAttachShader(program, vs);
fAttachShader(program, fs);
fBindAttribLocation(program, 0, "aVertex");
fBindAttribLocation(program, 1, "aTexCoord");
fLinkProgram(program);
GLint success;
fGetProgramiv(program, LOCAL_GL_LINK_STATUS, &success);
if (!success) {
fDeleteProgram(program);
program = 0;
}
fDeleteShader(vs);
fDeleteShader(fs);
mReadTextureImagePrograms[variant] = program;
}
return mReadTextureImagePrograms[variant];
}
static bool
DidGLErrorOccur(GLContext* aGL, const char* str)
{
GLenum error = aGL->fGetError();
if (error != LOCAL_GL_NO_ERROR) {
printf_stderr("GL ERROR: %s (0x%04x) %s\n",
aGL->GLErrorToString(error), error, str);
return true;
}
return false;
}
bool
GLContext::ReadBackPixelsIntoSurface(gfxImageSurface* aSurface, const gfxIntSize& aSize) {
GLint oldPackAlignment;
fGetIntegerv(LOCAL_GL_PACK_ALIGNMENT, &oldPackAlignment); fGetIntegerv(LOCAL_GL_PACK_ALIGNMENT, &oldPackAlignment);
PushViewportRect(nsIntRect(0, 0, aSize.width, aSize.height));
fGenRenderbuffers(1, &rb);
fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, rb);
fRenderbufferStorage(LOCAL_GL_RENDERBUFFER, LOCAL_GL_RGBA,
aSize.width, aSize.height);
fGenFramebuffers(1, &fb);
fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, fb);
fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_COLOR_ATTACHMENT0,
LOCAL_GL_RENDERBUFFER, rb);
if (fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER) !=
LOCAL_GL_FRAMEBUFFER_COMPLETE)
{
goto cleanup;
}
vs = fCreateShader(LOCAL_GL_VERTEX_SHADER);
fs = fCreateShader(LOCAL_GL_FRAGMENT_SHADER);
fShaderSource(vs, 1, (const GLchar**) &vShader, nullptr);
fShaderSource(fs, 1, (const GLchar**) &fShader, nullptr);
fCompileShader(vs);
fCompileShader(fs);
prog = fCreateProgram();
fAttachShader(prog, vs);
fAttachShader(prog, fs);
fBindAttribLocation(prog, 0, "aVertex");
fBindAttribLocation(prog, 1, "aTexCoord");
fLinkProgram(prog);
fGetProgramiv(prog, LOCAL_GL_LINK_STATUS, &success);
if (!success) {
goto cleanup;
}
fUseProgram(prog);
fEnableVertexAttribArray(0);
fEnableVertexAttribArray(1);
fVertexAttribPointer(0, 4, LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0, verts);
fVertexAttribPointer(1, 2, LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0, texcoords);
fActiveTexture(LOCAL_GL_TEXTURE0);
fBindTexture(LOCAL_GL_TEXTURE_2D, aTexture);
fUniform1i(fGetUniformLocation(prog, "uTexture"), 0);
fDrawArrays(LOCAL_GL_TRIANGLE_STRIP, 0, 4);
fDisableVertexAttribArray(1);
fDisableVertexAttribArray(0);
isurf = new gfxImageSurface(aSize, gfxImageFormatARGB32);
if (!isurf || isurf->CairoStatus()) {
isurf = nullptr;
goto cleanup;
}
if (oldPackAlignment != 4) if (oldPackAlignment != 4)
fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, 4); fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, 4);
fReadPixels(0, 0, aSize.width, aSize.height, fReadPixels(0, 0, aSize.width, aSize.height,
LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE, LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE,
isurf->Data()); aSurface->Data());
SwapRAndBComponents(isurf); bool result = DidGLErrorOccur(this, "when reading pixels into surface");
if (oldPackAlignment != 4) if (oldPackAlignment != 4)
fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, oldPackAlignment); fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, oldPackAlignment);
if (aYInvert) { return result;
isurf = YInvertImageSurface(isurf); }
#define CLEANUP_IF_GLERROR_OCCURRED(x) \
if (DidGLErrorOccur(this, (x))) { \
isurf = nullptr; \
break; \
} }
cleanup: already_AddRefed<gfxImageSurface>
// note that deleting 0 has no effect in any of these calls GLContext::ReadTextureImage(GLuint aTextureId,
fDeleteRenderbuffers(1, &rb); GLenum aTextureTarget,
fDeleteFramebuffers(1, &fb); const gfxIntSize& aSize,
fDeleteShader(vs); /* ShaderProgramType */ int aShaderProgram,
fDeleteShader(fs); bool aYInvert)
fDeleteProgram(prog); {
// Check aShaderProgram is in bounds for a layers::ShaderProgramType
MOZ_ASSERT(0 <= aShaderProgram && aShaderProgram < NumProgramTypes);
if (aTextureTarget != LOCAL_GL_TEXTURE_2D &&
aTextureTarget != LOCAL_GL_TEXTURE_EXTERNAL &&
aTextureTarget != LOCAL_GL_TEXTURE_RECTANGLE_ARB)
{
printf_stderr("ReadTextureImage target is not TEXTURE_2D || "
"TEXTURE_EXTERNAL || TEXTURE_RECTANGLE\n");
return nullptr;
}
MakeCurrent();
/* Allocate resulting image surface */
nsRefPtr<gfxImageSurface> isurf;
isurf = new gfxImageSurface(aSize, gfxImageFormatARGB32);
if (!isurf || isurf->CairoStatus()) {
isurf = nullptr;
return isurf.forget();
}
realGLboolean oldBlend, oldScissor;
GLint oldrb, oldfb, oldprog, oldTexUnit, oldTex;
GLuint rb, fb;
do {
/* Save current GL state */
oldBlend = fIsEnabled(LOCAL_GL_BLEND);
oldScissor = fIsEnabled(LOCAL_GL_SCISSOR_TEST);
fGetIntegerv(LOCAL_GL_RENDERBUFFER_BINDING, &oldrb);
fGetIntegerv(LOCAL_GL_FRAMEBUFFER_BINDING, &oldfb);
fGetIntegerv(LOCAL_GL_CURRENT_PROGRAM, &oldprog);
fGetIntegerv(LOCAL_GL_ACTIVE_TEXTURE, &oldTexUnit);
fActiveTexture(LOCAL_GL_TEXTURE0);
switch (aTextureTarget) {
case LOCAL_GL_TEXTURE_2D:
fGetIntegerv(LOCAL_GL_TEXTURE_BINDING_2D, &oldTex);
break;
case LOCAL_GL_TEXTURE_EXTERNAL:
fGetIntegerv(LOCAL_GL_TEXTURE_BINDING_EXTERNAL, &oldTex);
break;
case LOCAL_GL_TEXTURE_RECTANGLE:
fGetIntegerv(LOCAL_GL_TEXTURE_BINDING_RECTANGLE, &oldTex);
break;
default: /* Already checked above */
break;
}
/* Set required GL state */
fDisable(LOCAL_GL_BLEND);
fDisable(LOCAL_GL_SCISSOR_TEST);
PushViewportRect(nsIntRect(0, 0, aSize.width, aSize.height));
/* Setup renderbuffer */
fGenRenderbuffers(1, &rb);
fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, rb);
GLenum rbInternalFormat =
IsGLES2()
? (IsExtensionSupported(OES_rgb8_rgba8) ? LOCAL_GL_RGBA8 : LOCAL_GL_RGBA4)
: LOCAL_GL_RGBA;
fRenderbufferStorage(LOCAL_GL_RENDERBUFFER, rbInternalFormat, aSize.width, aSize.height);
CLEANUP_IF_GLERROR_OCCURRED("when binding and creating renderbuffer");
/* Setup framebuffer */
fGenFramebuffers(1, &fb);
fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, fb);
fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_COLOR_ATTACHMENT0,
LOCAL_GL_RENDERBUFFER, rb);
CLEANUP_IF_GLERROR_OCCURRED("when binding and creating framebuffer");
if (fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER) != LOCAL_GL_FRAMEBUFFER_COMPLETE) {
printf_stderr("framebuffer is incomplete\n");
break; //goto cleanup;
}
/* Setup vertex and fragment shader */
layers::ShaderProgramType shaderProgram = (ShaderProgramType) aShaderProgram;
GLuint program = TextureImageProgramFor(aTextureTarget, shaderProgram);
if (!program) {
printf_stderr("failed to compile program for texture target %u and"
" shader program type %d\n",
aTextureTarget, aShaderProgram);
break; // goto cleanup;
}
fUseProgram(program);
CLEANUP_IF_GLERROR_OCCURRED("when using program");
fUniform1i(fGetUniformLocation(program, "uTexture"), 0);
CLEANUP_IF_GLERROR_OCCURRED("when setting uniform location");
/* Setup quad geometry */
fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
fEnableVertexAttribArray(0);
fEnableVertexAttribArray(1);
float w = (aTextureTarget == LOCAL_GL_TEXTURE_RECTANGLE) ? (float) aSize.width : 1.0f;
float h = (aTextureTarget == LOCAL_GL_TEXTURE_RECTANGLE) ? (float) aSize.height : 1.0f;
fVertexAttribPointer(0, 4, LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0, ReadTextureVertexArray());
fVertexAttribPointer(1, 2, LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0, ReadTextureTexCoordArray(w, h, aYInvert));
/* Bind the texture */
if (aTextureId) {
fBindTexture(aTextureTarget, aTextureId);
CLEANUP_IF_GLERROR_OCCURRED("when binding texture");
}
/* Draw quad */
fClearColor(1.0f, 0.0f, 1.0f, 1.0f);
fClear(LOCAL_GL_COLOR_BUFFER_BIT);
CLEANUP_IF_GLERROR_OCCURRED("when clearing color buffer");
fDrawArrays(LOCAL_GL_TRIANGLE_STRIP, 0, 4);
CLEANUP_IF_GLERROR_OCCURRED("when drawing texture");
fDisableVertexAttribArray(1);
fDisableVertexAttribArray(0);
/* Read-back draw results */
ReadBackPixelsIntoSurface(isurf, aSize);
CLEANUP_IF_GLERROR_OCCURRED("when reading pixels into surface");
} while (false);
/* Restore GL state */
//cleanup:
fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, oldrb); fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, oldrb);
fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, oldfb); fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, oldfb);
fUseProgram(oldprog); fUseProgram(oldprog);
// note that deleting 0 has no effect in any of these calls
fDeleteRenderbuffers(1, &rb);
fDeleteFramebuffers(1, &fb);
if (oldBlend)
fEnable(LOCAL_GL_BLEND);
if (oldScissor)
fEnable(LOCAL_GL_SCISSOR_TEST);
if (aTextureId)
fBindTexture(aTextureTarget, oldTex);
if (oldTexUnit != LOCAL_GL_TEXTURE0)
fActiveTexture(oldTexUnit);
PopViewportRect(); PopViewportRect();
return isurf.forget(); return isurf.forget();
} }
#undef CLEANUP_IF_GLERROR_OCCURRED
static bool static bool
GetActualReadFormats(GLContext* gl, GLenum destFormat, GLenum destType, GetActualReadFormats(GLContext* gl, GLenum destFormat, GLenum destType,
GLenum& readFormat, GLenum& readType) GLenum& readFormat, GLenum& readType)

View File

@ -2734,6 +2734,14 @@ public:
return nullptr; return nullptr;
} }
private:
/**
* Helpers for ReadTextureImage
*/
GLuint TextureImageProgramFor(GLenum aTextureTarget, int aShader);
bool ReadBackPixelsIntoSurface(gfxImageSurface* aSurface, const gfxIntSize& aSize);
public:
/** /**
* Read the image data contained in aTexture, and return it as an ImageSurface. * Read the image data contained in aTexture, and return it as an ImageSurface.
* If GL_RGBA is given as the format, a gfxImageFormatARGB32 surface is returned. * If GL_RGBA is given as the format, a gfxImageFormatARGB32 surface is returned.
@ -2744,13 +2752,20 @@ public:
* THIS IS EXPENSIVE. It is ridiculously expensive. Only do this * THIS IS EXPENSIVE. It is ridiculously expensive. Only do this
* if you absolutely positively must, and never in any performance * if you absolutely positively must, and never in any performance
* critical path. * critical path.
*
* NOTE: aShaderProgram is really mozilla::layers::ShaderProgramType. It is
* passed as int to eliminate including LayerManagerOGLProgram.h in this
* hub header.
*/ */
already_AddRefed<gfxImageSurface> ReadTextureImage(GLuint aTexture, already_AddRefed<gfxImageSurface> ReadTextureImage(GLuint aTextureId,
GLenum aTextureTarget,
const gfxIntSize& aSize, const gfxIntSize& aSize,
GLenum aTextureFormat, /* ShaderProgramType */ int aShaderProgram,
bool aYInvert = false); bool aYInvert = false);
already_AddRefed<gfxImageSurface> GetTexImage(GLuint aTexture, bool aYInvert, SurfaceFormat aFormat); already_AddRefed<gfxImageSurface> GetTexImage(GLuint aTexture,
bool aYInvert,
SurfaceFormat aFormat);
/** /**
* Call ReadPixels into an existing gfxImageSurface. * Call ReadPixels into an existing gfxImageSurface.
@ -3111,6 +3126,8 @@ public:
protected: protected:
nsDataHashtable<nsPtrHashKey<void>, void*> mUserData; nsDataHashtable<nsPtrHashKey<void>, void*> mUserData;
GLuint mReadTextureImagePrograms[4];
bool InitWithPrefix(const char *prefix, bool trygl); bool InitWithPrefix(const char *prefix, bool trygl);
void InitExtensions(); void InitExtensions();

View File

@ -17,6 +17,7 @@
// OES_EGL_image_external // OES_EGL_image_external
#define LOCAL_GL_TEXTURE_EXTERNAL 0x8D65 #define LOCAL_GL_TEXTURE_EXTERNAL 0x8D65
#define LOCAL_GL_TEXTURE_BINDING_EXTERNAL 0x8D67
// EGL_KHR_fence_sync // EGL_KHR_fence_sync
#define LOCAL_EGL_SYNC_FENCE 0x30F9 #define LOCAL_EGL_SYNC_FENCE 0x30F9

View File

@ -189,8 +189,12 @@ struct EffectSolidColor : public Effect
struct EffectChain struct EffectChain
{ {
EffectChain() : mLayerRef(NULL) {}
explicit EffectChain(void* aLayerRef) : mLayerRef(aLayerRef) {}
RefPtr<Effect> mPrimaryEffect; RefPtr<Effect> mPrimaryEffect;
RefPtr<Effect> mSecondaryEffects[EFFECT_MAX_SECONDARY]; RefPtr<Effect> mSecondaryEffects[EFFECT_MAX_SECONDARY];
void* mLayerRef; //!< For LayerScope logging
}; };
/** /**

590
gfx/layers/LayerScope.cpp Normal file
View File

@ -0,0 +1,590 @@
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* This must occur *after* layers/PLayers.h to avoid typedefs conflicts. */
#include "LayerScope.h"
#include "mozilla/Util.h"
#include "Composer2D.h"
#include "Effects.h"
#include "mozilla/TimeStamp.h"
#include "mozilla/Preferences.h"
#include "TexturePoolOGL.h"
#include "mozilla/layers/TextureHostOGL.h"
#include "gfxColor.h"
#include "gfxContext.h"
#include "gfxUtils.h"
#include "gfxPlatform.h"
#include "nsIWidget.h"
#include "GLContext.h"
#include "GLContextProvider.h"
#include "nsIServiceManager.h"
#include "nsIConsoleService.h"
#include <memory>
#include "mozilla/Compression.h"
#include "mozilla/LinkedList.h"
#include "nsThreadUtils.h"
#include "nsISocketTransport.h"
#include "nsIServerSocket.h"
#include "nsNetCID.h"
#include "nsIOutputStream.h"
#include "nsIEventTarget.h"
#include "nsProxyRelease.h"
#ifdef __GNUC__
#define PACKED_STRUCT __attribute__((packed))
#else
#define PACKED_STRUCT
#endif
namespace mozilla {
namespace layers {
using namespace mozilla::Compression;
using namespace mozilla::gfx;
using namespace mozilla::gl;
using namespace mozilla;
class DebugDataSender;
static bool gDebugConnected = false;
static nsCOMPtr<nsIServerSocket> gDebugServerSocket;
static nsCOMPtr<nsIThread> gDebugSenderThread;
static nsCOMPtr<nsISocketTransport> gDebugSenderTransport;
static nsCOMPtr<nsIOutputStream> gDebugStream;
static nsCOMPtr<DebugDataSender> gCurrentSender;
class DebugGLData : public LinkedListElement<DebugGLData> {
public:
typedef enum {
FrameStart,
FrameEnd,
TextureData,
ColorData
} DataType;
virtual ~DebugGLData() { }
DataType GetDataType() const { return mDataType; }
intptr_t GetContextAddress() const { return mContextAddress; }
int64_t GetValue() const { return mValue; }
DebugGLData(DataType dataType)
: mDataType(dataType),
mContextAddress(0),
mValue(0)
{ }
DebugGLData(DataType dataType, GLContext* cx)
: mDataType(dataType),
mContextAddress(reinterpret_cast<intptr_t>(cx)),
mValue(0)
{ }
DebugGLData(DataType dataType, GLContext* cx, int64_t value)
: mDataType(dataType),
mContextAddress(reinterpret_cast<intptr_t>(cx)),
mValue(value)
{ }
virtual bool Write() {
if (mDataType != FrameStart &&
mDataType != FrameEnd)
{
NS_WARNING("Unimplemented data type!");
return false;
}
DebugGLData::BasicPacket packet;
packet.type = mDataType;
packet.ptr = static_cast<uint64_t>(mContextAddress);
packet.value = mValue;
return WriteToStream(&packet, sizeof(packet));
}
static bool WriteToStream(void *ptr, uint32_t size) {
uint32_t written = 0;
nsresult rv;
while (written < size) {
uint32_t cnt;
rv = gDebugStream->Write(reinterpret_cast<char*>(ptr) + written,
size - written, &cnt);
if (NS_FAILED(rv))
return false;
written += cnt;
}
return true;
}
protected:
DataType mDataType;
intptr_t mContextAddress;
int64_t mValue;
public:
// the data packet formats; all packed
#ifdef _MSC_VER
#pragma pack(push, 1)
#endif
typedef struct {
uint32_t type;
uint64_t ptr;
uint64_t value;
} PACKED_STRUCT BasicPacket;
typedef struct {
uint32_t type;
uint64_t ptr;
uint64_t layerref;
uint32_t color;
uint32_t width;
uint32_t height;
} PACKED_STRUCT ColorPacket;
typedef struct {
uint32_t type;
uint64_t ptr;
uint64_t layerref;
uint32_t name;
uint32_t width;
uint32_t height;
uint32_t stride;
uint32_t format;
uint32_t target;
uint32_t dataFormat;
uint32_t dataSize;
} PACKED_STRUCT TexturePacket;
#ifdef _MSC_VER
#pragma pack(pop)
#endif
};
class DebugGLTextureData : public DebugGLData {
public:
DebugGLTextureData(GLContext* cx, void* layerRef, GLuint target, GLenum name, gfxImageSurface* img)
: DebugGLData(DebugGLData::TextureData, cx),
mLayerRef(layerRef),
mTarget(target),
mName(name),
mImage(img)
{ }
void *GetLayerRef() const { return mLayerRef; }
GLuint GetName() const { return mName; }
gfxImageSurface* GetImage() const { return mImage; }
GLenum GetTextureTarget() const { return mTarget; }
virtual bool Write() {
DebugGLData::TexturePacket packet;
char* dataptr = nullptr;
uint32_t datasize = 0;
std::auto_ptr<char> compresseddata;
packet.type = mDataType;
packet.ptr = static_cast<uint64_t>(mContextAddress);
packet.layerref = reinterpret_cast<uint64_t>(mLayerRef);
packet.name = mName;
packet.format = 0;
packet.target = mTarget;
packet.dataFormat = LOCAL_GL_RGBA;
if (mImage) {
packet.width = mImage->Width();
packet.height = mImage->Height();
packet.stride = mImage->Stride();
packet.dataSize = mImage->GetDataSize();
dataptr = (char*) mImage->Data();
datasize = mImage->GetDataSize();
compresseddata = std::auto_ptr<char>((char*) moz_malloc(LZ4::maxCompressedSize(datasize)));
if (compresseddata.get()) {
int ndatasize = LZ4::compress(dataptr, datasize, compresseddata.get());
if (ndatasize > 0) {
datasize = ndatasize;
dataptr = compresseddata.get();
packet.dataFormat = (1 << 16) | packet.dataFormat;
packet.dataSize = datasize;
}
}
} else {
packet.width = 0;
packet.height = 0;
packet.stride = 0;
packet.dataSize = 0;
}
// write the packet header data
if (!WriteToStream(&packet, sizeof(packet)))
return false;
// then the image data
if (!WriteToStream(dataptr, datasize))
return false;
// then pad out to 4 bytes
if (datasize % 4 != 0) {
static char buf[] = { 0, 0, 0, 0 };
if (!WriteToStream(buf, 4 - (datasize % 4)))
return false;
}
return true;
}
protected:
void* mLayerRef;
GLenum mTarget;
GLuint mName;
nsRefPtr<gfxImageSurface> mImage;
};
class DebugGLColorData : public DebugGLData {
public:
DebugGLColorData(void* layerRef, const gfxRGBA& color, int width, int height)
: DebugGLData(DebugGLData::ColorData),
mColor(color.Packed()),
mSize(width, height)
{ }
void *GetLayerRef() const { return mLayerRef; }
uint32_t GetColor() const { return mColor; }
const nsIntSize& GetSize() const { return mSize; }
virtual bool Write() {
DebugGLData::ColorPacket packet;
packet.type = mDataType;
packet.ptr = static_cast<uint64_t>(mContextAddress);
packet.layerref = reinterpret_cast<uintptr_t>(mLayerRef);
packet.color = mColor;
packet.width = mSize.width;
packet.height = mSize.height;
return WriteToStream(&packet, sizeof(packet));
}
protected:
void *mLayerRef;
uint32_t mColor;
nsIntSize mSize;
};
static bool
CheckSender()
{
if (!gDebugConnected)
return false;
// At some point we may want to support sending
// data in between frames.
#if 1
if (!gCurrentSender)
return false;
#else
if (!gCurrentSender)
gCurrentSender = new DebugDataSender();
#endif
return true;
}
class DebugListener : public nsIServerSocketListener
{
public:
NS_DECL_THREADSAFE_ISUPPORTS
DebugListener() { }
virtual ~DebugListener() { }
/* nsIServerSocketListener */
NS_IMETHODIMP OnSocketAccepted(nsIServerSocket *aServ,
nsISocketTransport *aTransport)
{
printf_stderr("*** LayerScope: Accepted connection\n");
gDebugConnected = true;
gDebugSenderTransport = aTransport;
aTransport->OpenOutputStream(nsITransport::OPEN_BLOCKING, 0, 0, getter_AddRefs(gDebugStream));
return NS_OK;
}
NS_IMETHODIMP OnStopListening(nsIServerSocket *aServ,
nsresult aStatus)
{
return NS_OK;
}
};
NS_IMPL_ISUPPORTS1(DebugListener, nsIServerSocketListener);
class DebugDataSender : public nsIRunnable
{
public:
NS_DECL_THREADSAFE_ISUPPORTS
DebugDataSender() {
mList = new LinkedList<DebugGLData>();
}
virtual ~DebugDataSender() {
Cleanup();
}
void Append(DebugGLData *d) {
mList->insertBack(d);
}
void Cleanup() {
if (!mList)
return;
DebugGLData *d;
while ((d = mList->popFirst()) != nullptr)
delete d;
delete mList;
mList = nullptr;
}
/* nsIRunnable impl; send the data */
NS_IMETHODIMP Run() {
DebugGLData *d;
nsresult rv = NS_OK;
// If we got closed while trying to write some stuff earlier, just
// throw away everything.
if (!gDebugStream) {
Cleanup();
return NS_OK;
}
while ((d = mList->popFirst()) != nullptr) {
std::auto_ptr<DebugGLData> cleaner(d);
if (!d->Write()) {
rv = NS_ERROR_FAILURE;
break;
}
}
Cleanup();
if (NS_FAILED(rv)) {
gDebugSenderTransport->Close(rv);
gDebugConnected = false;
gDebugStream = nullptr;
gDebugServerSocket = nullptr;
}
return NS_OK;
}
protected:
LinkedList<DebugGLData> *mList;
};
NS_IMPL_ISUPPORTS1(DebugDataSender, nsIRunnable);
void
LayerScope::CreateServerSocket()
{
if (!Preferences::GetBool("gfx.layerscope.enabled", false)) {
return;
}
if (!gDebugSenderThread) {
NS_NewThread(getter_AddRefs(gDebugSenderThread));
}
if (!gDebugServerSocket) {
gDebugServerSocket = do_CreateInstance(NS_SERVERSOCKET_CONTRACTID);
int port = Preferences::GetInt("gfx.layerscope.port", 23456);
gDebugServerSocket->Init(port, false, -1);
gDebugServerSocket->AsyncListen(new DebugListener);
}
}
void
LayerScope::DestroyServerSocket()
{
gDebugConnected = false;
gDebugStream = nullptr;
gDebugServerSocket = nullptr;
}
void
LayerScope::BeginFrame(GLContext* aGLContext, int64_t aFrameStamp)
{
if (!gDebugConnected)
return;
#if 0
// if we're sending data in between frames, flush the list down the socket,
// and start a new one
if (gCurrentSender) {
gDebugSenderThread->Dispatch(gCurrentSender, NS_DISPATCH_NORMAL);
}
#endif
gCurrentSender = new DebugDataSender();
gCurrentSender->Append(new DebugGLData(DebugGLData::FrameStart, aGLContext, aFrameStamp));
}
void
LayerScope::EndFrame(GLContext* aGLContext)
{
if (!CheckSender())
return;
gCurrentSender->Append(new DebugGLData(DebugGLData::FrameEnd, aGLContext));
gDebugSenderThread->Dispatch(gCurrentSender, NS_DISPATCH_NORMAL);
gCurrentSender = nullptr;
}
static void
SendColor(void* aLayerRef, const gfxRGBA& aColor, int aWidth, int aHeight)
{
if (!CheckSender())
return;
gCurrentSender->Append(
new DebugGLColorData(aLayerRef, aColor, aWidth, aHeight));
}
static void
SendTextureSource(GLContext* aGLContext,
void* aLayerRef,
TextureSourceOGL* aSource,
bool aFlipY)
{
GLenum textureTarget = aSource->GetTextureTarget();
int shaderProgram =
(int) ShaderProgramFromTargetAndFormat(textureTarget,
aSource->GetFormat());
aSource->BindTexture(LOCAL_GL_TEXTURE0);
GLuint textureId = 0;
// This is horrid hack. It assumes that aGLContext matches the context
// aSource has bound to.
if (textureTarget == LOCAL_GL_TEXTURE_2D) {
aGLContext->GetUIntegerv(LOCAL_GL_TEXTURE_BINDING_2D, &textureId);
} else if (textureTarget == LOCAL_GL_TEXTURE_EXTERNAL) {
aGLContext->GetUIntegerv(LOCAL_GL_TEXTURE_BINDING_EXTERNAL, &textureId);
} else if (textureTarget == LOCAL_GL_TEXTURE_RECTANGLE) {
aGLContext->GetUIntegerv(LOCAL_GL_TEXTURE_BINDING_RECTANGLE, &textureId);
}
gfx::IntSize size = aSource->GetSize();
// By sending 0 to ReadTextureImage rely upon aSource->BindTexture binding
// texture correctly. textureId is used for tracking in DebugGLTextureData.
nsRefPtr<gfxImageSurface> img =
aGLContext->ReadTextureImage(0, textureTarget,
gfxIntSize(size.width, size.height),
shaderProgram, aFlipY);
gCurrentSender->Append(
new DebugGLTextureData(aGLContext, aLayerRef, textureTarget,
textureId, img));
}
static void
SendTexturedEffect(GLContext* aGLContext,
void* aLayerRef,
const TexturedEffect* aEffect)
{
TextureSourceOGL* source = aEffect->mTexture->AsSourceOGL();
if (!source)
return;
bool flipY = false;
SendTextureSource(aGLContext, aLayerRef, source, flipY);
}
static void
SendYCbCrEffect(GLContext* aGLContext,
void* aLayerRef,
const EffectYCbCr* aEffect)
{
TextureSource* sourceYCbCr = aEffect->mTexture;
if (!sourceYCbCr)
return;
const int Y = 0, Cb = 1, Cr = 2;
TextureSourceOGL* sourceY = sourceYCbCr->GetSubSource(Y)->AsSourceOGL();
TextureSourceOGL* sourceCb = sourceYCbCr->GetSubSource(Cb)->AsSourceOGL();
TextureSourceOGL* sourceCr = sourceYCbCr->GetSubSource(Cr)->AsSourceOGL();
bool flipY = false;
SendTextureSource(aGLContext, aLayerRef, sourceY, flipY);
SendTextureSource(aGLContext, aLayerRef, sourceCb, flipY);
SendTextureSource(aGLContext, aLayerRef, sourceCr, flipY);
}
void
LayerScope::SendEffectChain(GLContext* aGLContext,
const EffectChain& aEffectChain,
int aWidth, int aHeight)
{
if (!CheckSender())
return;
const Effect* primaryEffect = aEffectChain.mPrimaryEffect;
switch (primaryEffect->mType) {
case EFFECT_BGRX:
case EFFECT_RGBX:
case EFFECT_BGRA:
case EFFECT_RGBA:
{
const TexturedEffect* texturedEffect =
static_cast<const TexturedEffect*>(primaryEffect);
SendTexturedEffect(aGLContext, aEffectChain.mLayerRef, texturedEffect);
}
break;
case EFFECT_YCBCR:
{
const EffectYCbCr* yCbCrEffect =
static_cast<const EffectYCbCr*>(primaryEffect);
SendYCbCrEffect(aGLContext, aEffectChain.mLayerRef, yCbCrEffect);
}
case EFFECT_SOLID_COLOR:
{
const EffectSolidColor* solidColorEffect =
static_cast<const EffectSolidColor*>(primaryEffect);
gfxRGBA color(solidColorEffect->mColor.r,
solidColorEffect->mColor.g,
solidColorEffect->mColor.b,
solidColorEffect->mColor.a);
SendColor(aEffectChain.mLayerRef, color, aWidth, aHeight);
}
break;
case EFFECT_COMPONENT_ALPHA:
case EFFECT_RENDER_TARGET:
default:
break;
}
//const Effect* secondaryEffect = aEffectChain.mSecondaryEffects[EFFECT_MASK];
// TODO:
}
} /* layers */
} /* mozilla */

35
gfx/layers/LayerScope.h Normal file
View File

@ -0,0 +1,35 @@
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef GFX_LAYERSCOPE_H
#define GFX_LAYERSCOPE_H
#include <stdint.h>
struct nsIntSize;
namespace mozilla {
namespace gl { class GLContext; }
namespace layers {
struct EffectChain;
class LayerScope {
public:
static void CreateServerSocket();
static void DestroyServerSocket();
static void BeginFrame(gl::GLContext* aGLContext, int64_t aFrameStamp);
static void EndFrame(gl::GLContext* aGLContext);
static void SendEffectChain(gl::GLContext* aGLContext,
const EffectChain& aEffectChain,
int aWidth, int aHeight);
};
} /* layers */
} /* mozilla */
#endif /* GFX_LAYERSCOPE_H */

View File

@ -93,7 +93,8 @@ CanvasLayerComposite::RenderLayer(const nsIntRect& aClipRect)
} }
#endif #endif
EffectChain effectChain; EffectChain effectChain(this);
LayerManagerComposite::AutoAddMaskEffect autoMaskEffect(mMaskLayer, effectChain); LayerManagerComposite::AutoAddMaskEffect autoMaskEffect(mMaskLayer, effectChain);
gfx::Matrix4x4 transform; gfx::Matrix4x4 transform;
ToMatrix4x4(GetEffectiveTransform(), transform); ToMatrix4x4(GetEffectiveTransform(), transform);

View File

@ -28,6 +28,7 @@ EXPORTS += [
'ipc/CompositorParent.h', 'ipc/CompositorParent.h',
'ipc/ShadowLayersManager.h', 'ipc/ShadowLayersManager.h',
'Layers.h', 'Layers.h',
'LayerScope.h',
'LayersLogging.h', 'LayersLogging.h',
'LayerSorter.h', 'LayerSorter.h',
'LayerTreeInvalidation.h', 'LayerTreeInvalidation.h',
@ -251,6 +252,7 @@ UNIFIED_SOURCES += [
'ipc/SharedRGBImage.cpp', 'ipc/SharedRGBImage.cpp',
'ipc/TaskThrottler.cpp', 'ipc/TaskThrottler.cpp',
'Layers.cpp', 'Layers.cpp',
'LayerScope.cpp',
'LayersLogging.cpp', 'LayersLogging.cpp',
'LayerSorter.cpp', 'LayerSorter.cpp',
'LayerTreeInvalidation.cpp', 'LayerTreeInvalidation.cpp',

View File

@ -11,6 +11,7 @@
#include "GLContextProvider.h" // for GLContextProvider #include "GLContextProvider.h" // for GLContextProvider
#include "GLContext.h" // for GLContext #include "GLContext.h" // for GLContext
#include "Layers.h" // for WriteSnapshotToDumpFile #include "Layers.h" // for WriteSnapshotToDumpFile
#include "LayerScope.h" // for LayerScope
#include "gfx2DGlue.h" // for ThebesFilter #include "gfx2DGlue.h" // for ThebesFilter
#include "gfx3DMatrix.h" // for gfx3DMatrix #include "gfx3DMatrix.h" // for gfx3DMatrix
#include "gfxASurface.h" // for gfxASurface, etc #include "gfxASurface.h" // for gfxASurface, etc
@ -767,6 +768,8 @@ CompositorOGL::BeginFrame(const nsIntRegion& aInvalidRegion,
PROFILER_LABEL("CompositorOGL", "BeginFrame"); PROFILER_LABEL("CompositorOGL", "BeginFrame");
MOZ_ASSERT(!mFrameInProgress, "frame still in progress (should have called EndFrame or AbortFrame"); MOZ_ASSERT(!mFrameInProgress, "frame still in progress (should have called EndFrame or AbortFrame");
LayerScope::BeginFrame(mGLContext, PR_Now());
mVBOs.Reset(); mVBOs.Reset();
mFrameInProgress = true; mFrameInProgress = true;
@ -1014,6 +1017,9 @@ CompositorOGL::DrawQuad(const Rect& aRect,
mGLContext->PushScissorRect(nsIntRect(intClipRect.x, intClipRect.y, mGLContext->PushScissorRect(nsIntRect(intClipRect.x, intClipRect.y,
intClipRect.width, intClipRect.height)); intClipRect.width, intClipRect.height));
LayerScope::SendEffectChain(mGLContext, aEffectChain,
aRect.width, aRect.height);
MaskType maskType; MaskType maskType;
EffectMask* effectMask; EffectMask* effectMask;
TextureSourceOGL* sourceMask = nullptr; TextureSourceOGL* sourceMask = nullptr;
@ -1308,6 +1314,8 @@ CompositorOGL::EndFrame()
mFrameInProgress = false; mFrameInProgress = false;
LayerScope::EndFrame(mGLContext);
if (mTarget) { if (mTarget) {
CopyToTarget(mTarget, mCurrentRenderTarget->GetTransform()); CopyToTarget(mTarget, mCurrentRenderTarget->GetTransform());
mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0); mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);

View File

@ -308,6 +308,10 @@ pref("apz.axis_lock_mode", 0);
pref("gfx.hidpi.enabled", 2); pref("gfx.hidpi.enabled", 2);
#endif #endif
// Whether to enable LayerScope tool and default listening port
pref("gfx.layerscope.enabled", false);
pref("gfx.layerscope.port", 23456);
// 0 = Off, 1 = Full, 2 = Tagged Images Only. // 0 = Off, 1 = Full, 2 = Tagged Images Only.
// See eCMSMode in gfx/thebes/gfxPlatform.h // See eCMSMode in gfx/thebes/gfxPlatform.h
pref("gfx.color_management.mode", 2); pref("gfx.color_management.mode", 2);

View File

@ -41,6 +41,7 @@
#include "mozilla/gfx/2D.h" #include "mozilla/gfx/2D.h"
#include "mozilla/MouseEvents.h" #include "mozilla/MouseEvents.h"
#include "GLConsts.h" #include "GLConsts.h"
#include "LayerScope.h"
#ifdef ACCESSIBILITY #ifdef ACCESSIBILITY
#include "nsAccessibilityService.h" #include "nsAccessibilityService.h"
@ -161,6 +162,8 @@ static void DeferredDestroyCompositor(CompositorParent* aCompositorParent,
void nsBaseWidget::DestroyCompositor() void nsBaseWidget::DestroyCompositor()
{ {
LayerScope::DestroyServerSocket();
if (mCompositorChild) { if (mCompositorChild) {
mCompositorChild->SendWillStop(); mCompositorChild->SendWillStop();
mCompositorChild->Destroy(); mCompositorChild->Destroy();
@ -950,6 +953,9 @@ void nsBaseWidget::CreateCompositor(int aWidth, int aHeight)
return; return;
} }
// The server socket has to be created on the main thread.
LayerScope::CreateServerSocket();
mCompositorParent = NewCompositorParent(aWidth, aHeight); mCompositorParent = NewCompositorParent(aWidth, aHeight);
MessageChannel *parentChannel = mCompositorParent->GetIPCChannel(); MessageChannel *parentChannel = mCompositorParent->GetIPCChannel();
ClientLayerManager* lm = new ClientLayerManager(this); ClientLayerManager* lm = new ClientLayerManager(this);