mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 05:41:12 +00:00
Bug 830881 - Port layerscope GL changes to new layers. r=vlad
This commit is contained in:
parent
a940e05e20
commit
7f73b68e55
@ -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)
|
||||||
|
@ -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();
|
||||||
|
@ -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
|
||||||
|
@ -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
590
gfx/layers/LayerScope.cpp
Normal 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
35
gfx/layers/LayerScope.h
Normal 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 */
|
@ -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);
|
||||||
|
@ -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',
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
Loading…
Reference in New Issue
Block a user