зеркало из https://github.com/mozilla/gecko-dev.git
Backed out 6 changesets (bug 1006198) for webgl assertions on a CLOSED TREE
Backed out changeset 5be3c8c44eed (bug 1006198) Backed out changeset 4b15abd14f28 (bug 1006198) Backed out changeset bd11a10e7028 (bug 1006198) Backed out changeset e1044a8ab189 (bug 1006198) Backed out changeset 558abe22ab30 (bug 1006198) Backed out changeset 5462b9babaed (bug 1006198)
This commit is contained in:
Родитель
6b859b8e96
Коммит
a30e4e7afc
|
@ -1337,10 +1337,10 @@ WebGLContext::GetSurfaceSnapshot(bool* aPremultAlpha)
|
||||||
if (!gl)
|
if (!gl)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
RefPtr<DataSourceSurface> surf = Factory::CreateDataSourceSurfaceWithStride(IntSize(mWidth, mHeight),
|
nsRefPtr<gfxImageSurface> surf = new gfxImageSurface(gfxIntSize(mWidth, mHeight),
|
||||||
SurfaceFormat::B8G8R8A8,
|
gfxImageFormat::ARGB32,
|
||||||
mWidth * 4);
|
mWidth * 4, 0, false);
|
||||||
if (!surf) {
|
if (surf->CairoStatus() != 0) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1348,7 +1348,7 @@ WebGLContext::GetSurfaceSnapshot(bool* aPremultAlpha)
|
||||||
{
|
{
|
||||||
ScopedBindFramebuffer autoFB(gl, 0);
|
ScopedBindFramebuffer autoFB(gl, 0);
|
||||||
ClearBackbufferIfNeeded();
|
ClearBackbufferIfNeeded();
|
||||||
ReadPixelsIntoDataSurface(gl, surf);
|
ReadPixelsIntoImageSurface(gl, surf);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (aPremultAlpha) {
|
if (aPremultAlpha) {
|
||||||
|
@ -1359,7 +1359,8 @@ WebGLContext::GetSurfaceSnapshot(bool* aPremultAlpha)
|
||||||
if (aPremultAlpha) {
|
if (aPremultAlpha) {
|
||||||
*aPremultAlpha = false;
|
*aPremultAlpha = false;
|
||||||
} else {
|
} else {
|
||||||
gfxUtils::PremultiplyDataSurface(surf);
|
gfxUtils::PremultiplyImageSurface(surf);
|
||||||
|
surf->MarkDirty();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1372,12 +1373,14 @@ WebGLContext::GetSurfaceSnapshot(bool* aPremultAlpha)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RefPtr<SourceSurface> source = gfxPlatform::GetPlatform()->GetSourceSurfaceForSurface(dt, surf);
|
||||||
|
|
||||||
Matrix m;
|
Matrix m;
|
||||||
m.Translate(0.0, mHeight);
|
m.Translate(0.0, mHeight);
|
||||||
m.Scale(1.0, -1.0);
|
m.Scale(1.0, -1.0);
|
||||||
dt->SetTransform(m);
|
dt->SetTransform(m);
|
||||||
|
|
||||||
dt->DrawSurface(surf,
|
dt->DrawSurface(source,
|
||||||
Rect(0, 0, mWidth, mHeight),
|
Rect(0, 0, mWidth, mHeight),
|
||||||
Rect(0, 0, mWidth, mHeight),
|
Rect(0, 0, mWidth, mHeight),
|
||||||
DrawSurfaceOptions(),
|
DrawSurfaceOptions(),
|
||||||
|
|
|
@ -328,40 +328,44 @@ GuessAlignment(int width, int pixelSize, int rowStride)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ReadPixelsIntoDataSurface(GLContext* gl, DataSourceSurface* dest) {
|
ReadPixelsIntoImageSurface(GLContext* gl, gfxImageSurface* dest) {
|
||||||
gl->MakeCurrent();
|
gl->MakeCurrent();
|
||||||
MOZ_ASSERT(dest->GetSize().width != 0);
|
MOZ_ASSERT(dest->GetSize() != gfxIntSize(0, 0));
|
||||||
MOZ_ASSERT(dest->GetSize().height != 0);
|
|
||||||
|
|
||||||
bool hasAlpha = dest->GetFormat() == SurfaceFormat::B8G8R8A8 ||
|
/* gfxImageFormat::ARGB32:
|
||||||
dest->GetFormat() == SurfaceFormat::R8G8B8A8;
|
* RGBA+UByte: be[RGBA], le[ABGR]
|
||||||
|
* RGBA+UInt: be[ABGR], le[RGBA]
|
||||||
|
* BGRA+UInt: be[ARGB], le[BGRA]
|
||||||
|
* BGRA+UIntRev: be[BGRA], le[ARGB]
|
||||||
|
*
|
||||||
|
* gfxImageFormat::RGB16_565:
|
||||||
|
* RGB+UShort: le[rrrrrggg,gggbbbbb]
|
||||||
|
*/
|
||||||
|
bool hasAlpha = dest->Format() == gfxImageFormat::ARGB32;
|
||||||
|
|
||||||
int destPixelSize;
|
int destPixelSize;
|
||||||
GLenum destFormat;
|
GLenum destFormat;
|
||||||
GLenum destType;
|
GLenum destType;
|
||||||
|
|
||||||
switch (dest->GetFormat()) {
|
switch (dest->Format()) {
|
||||||
case SurfaceFormat::B8G8R8A8:
|
case gfxImageFormat::RGB24: // XRGB
|
||||||
case SurfaceFormat::B8G8R8X8:
|
case gfxImageFormat::ARGB32:
|
||||||
|
destPixelSize = 4;
|
||||||
// Needs host (little) endian ARGB.
|
// Needs host (little) endian ARGB.
|
||||||
destFormat = LOCAL_GL_BGRA;
|
destFormat = LOCAL_GL_BGRA;
|
||||||
destType = LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV;
|
destType = LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV;
|
||||||
break;
|
break;
|
||||||
case SurfaceFormat::R8G8B8A8:
|
|
||||||
case SurfaceFormat::R8G8B8X8:
|
case gfxImageFormat::RGB16_565:
|
||||||
// Needs host (little) endian ABGR.
|
destPixelSize = 2;
|
||||||
destFormat = LOCAL_GL_RGBA;
|
|
||||||
destType = LOCAL_GL_UNSIGNED_BYTE;
|
|
||||||
break;
|
|
||||||
case SurfaceFormat::R5G6B5:
|
|
||||||
destFormat = LOCAL_GL_RGB;
|
destFormat = LOCAL_GL_RGB;
|
||||||
destType = LOCAL_GL_UNSIGNED_SHORT_5_6_5_REV;
|
destType = LOCAL_GL_UNSIGNED_SHORT_5_6_5_REV;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
MOZ_CRASH("Bad format.");
|
MOZ_CRASH("Bad format.");
|
||||||
}
|
}
|
||||||
destPixelSize = BytesPerPixel(dest->GetFormat());
|
MOZ_ASSERT(dest->Width() * destPixelSize <= dest->Stride());
|
||||||
MOZ_ASSERT(dest->GetSize().width * destPixelSize <= dest->Stride());
|
|
||||||
|
|
||||||
GLenum readFormat = destFormat;
|
GLenum readFormat = destFormat;
|
||||||
GLenum readType = destType;
|
GLenum readType = destType;
|
||||||
|
@ -369,15 +373,20 @@ ReadPixelsIntoDataSurface(GLContext* gl, DataSourceSurface* dest) {
|
||||||
destFormat, destType,
|
destFormat, destType,
|
||||||
readFormat, readType);
|
readFormat, readType);
|
||||||
|
|
||||||
RefPtr<DataSourceSurface> tempSurf;
|
nsAutoPtr<gfxImageSurface> tempSurf;
|
||||||
DataSourceSurface* readSurf = dest;
|
gfxImageSurface* readSurf = nullptr;
|
||||||
int readAlignment = GuessAlignment(dest->GetSize().width,
|
|
||||||
|
// Figure out alignment. We don't need to know why, we just need it
|
||||||
|
// to be valid.
|
||||||
|
int readAlignment = GuessAlignment(dest->Width(),
|
||||||
destPixelSize,
|
destPixelSize,
|
||||||
dest->Stride());
|
dest->Stride());
|
||||||
if (!readAlignment) {
|
if (!readAlignment) // Couldn't calculate a valid alignment.
|
||||||
needsTempSurf = true;
|
needsTempSurf = true;
|
||||||
}
|
|
||||||
if (needsTempSurf) {
|
if (!needsTempSurf) {
|
||||||
|
readSurf = dest;
|
||||||
|
} else {
|
||||||
if (gl->DebugMode()) {
|
if (gl->DebugMode()) {
|
||||||
NS_WARNING("Needing intermediary surface for ReadPixels. This will be slow!");
|
NS_WARNING("Needing intermediary surface for ReadPixels. This will be slow!");
|
||||||
}
|
}
|
||||||
|
@ -422,11 +431,154 @@ ReadPixelsIntoDataSurface(GLContext* gl, DataSourceSurface* dest) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tempSurf = new gfxImageSurface(dest->GetSize(),
|
||||||
|
SurfaceFormatToImageFormat(readFormatGFX),
|
||||||
|
false);
|
||||||
|
readSurf = tempSurf;
|
||||||
|
}
|
||||||
|
MOZ_ASSERT(readAlignment);
|
||||||
|
|
||||||
|
GLint currentPackAlignment = 0;
|
||||||
|
gl->fGetIntegerv(LOCAL_GL_PACK_ALIGNMENT, ¤tPackAlignment);
|
||||||
|
|
||||||
|
if (currentPackAlignment != readAlignment)
|
||||||
|
gl->fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, readAlignment);
|
||||||
|
|
||||||
|
GLsizei width = dest->Width();
|
||||||
|
GLsizei height = dest->Height();
|
||||||
|
|
||||||
|
readSurf->Flush();
|
||||||
|
gl->fReadPixels(0, 0,
|
||||||
|
width, height,
|
||||||
|
readFormat, readType,
|
||||||
|
readSurf->Data());
|
||||||
|
readSurf->MarkDirty();
|
||||||
|
|
||||||
|
if (currentPackAlignment != readAlignment)
|
||||||
|
gl->fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, currentPackAlignment);
|
||||||
|
|
||||||
|
if (readSurf != dest) {
|
||||||
|
MOZ_ASSERT(readFormat == LOCAL_GL_RGBA);
|
||||||
|
MOZ_ASSERT(readType == LOCAL_GL_UNSIGNED_BYTE);
|
||||||
|
// So we just copied in RGBA in big endian, or le: 0xAABBGGRR.
|
||||||
|
// We want 0xAARRGGBB, so swap R and B:
|
||||||
|
dest->Flush();
|
||||||
|
RefPtr<DataSourceSurface> readDSurf =
|
||||||
|
Factory::CreateWrappingDataSourceSurface(readSurf->Data(),
|
||||||
|
readSurf->Stride(),
|
||||||
|
ToIntSize(readSurf->GetSize()),
|
||||||
|
ImageFormatToSurfaceFormat(readSurf->Format()));
|
||||||
|
SwapRAndBComponents(readDSurf);
|
||||||
|
dest->MarkDirty();
|
||||||
|
|
||||||
|
gfxContext ctx(dest);
|
||||||
|
ctx.SetOperator(gfxContext::OPERATOR_SOURCE);
|
||||||
|
ctx.SetSource(readSurf);
|
||||||
|
ctx.Paint();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if GL is giving back 1.0 alpha for
|
||||||
|
// RGBA reads to RGBA images from no-alpha buffers.
|
||||||
|
#ifdef XP_MACOSX
|
||||||
|
if (gl->WorkAroundDriverBugs() &&
|
||||||
|
gl->Vendor() == gl::GLVendor::NVIDIA &&
|
||||||
|
dest->Format() == gfxImageFormat::ARGB32 &&
|
||||||
|
width && height)
|
||||||
|
{
|
||||||
|
GLint alphaBits = 0;
|
||||||
|
gl->fGetIntegerv(LOCAL_GL_ALPHA_BITS, &alphaBits);
|
||||||
|
if (!alphaBits) {
|
||||||
|
const uint32_t alphaMask = gfxPackedPixelNoPreMultiply(0xff,0,0,0);
|
||||||
|
|
||||||
|
MOZ_ASSERT(dest->Width() * destPixelSize == dest->Stride());
|
||||||
|
|
||||||
|
dest->Flush();
|
||||||
|
uint32_t* itr = (uint32_t*)dest->Data();
|
||||||
|
uint32_t testPixel = *itr;
|
||||||
|
if ((testPixel & alphaMask) != alphaMask) {
|
||||||
|
// We need to set the alpha channel to 1.0 manually.
|
||||||
|
uint32_t* itrEnd = itr + width*height; // Stride is guaranteed to be width*4.
|
||||||
|
|
||||||
|
for (; itr != itrEnd; itr++) {
|
||||||
|
*itr |= alphaMask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dest->MarkDirty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ReadPixelsIntoDataSurface(GLContext* gl, DataSourceSurface* dest) {
|
||||||
|
gl->MakeCurrent();
|
||||||
|
MOZ_ASSERT(dest->GetSize().width != 0);
|
||||||
|
MOZ_ASSERT(dest->GetSize().height != 0);
|
||||||
|
|
||||||
|
bool hasAlpha = dest->GetFormat() == SurfaceFormat::B8G8R8A8 ||
|
||||||
|
dest->GetFormat() == SurfaceFormat::R8G8B8A8;
|
||||||
|
|
||||||
|
int destPixelSize;
|
||||||
|
GLenum destFormat;
|
||||||
|
GLenum destType;
|
||||||
|
|
||||||
|
switch (dest->GetFormat()) {
|
||||||
|
case SurfaceFormat::B8G8R8A8:
|
||||||
|
case SurfaceFormat::B8G8R8X8:
|
||||||
|
// Needs host (little) endian ARGB.
|
||||||
|
destFormat = LOCAL_GL_BGRA;
|
||||||
|
destType = LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV;
|
||||||
|
break;
|
||||||
|
case SurfaceFormat::R8G8B8A8:
|
||||||
|
case SurfaceFormat::R8G8B8X8:
|
||||||
|
// Needs host (little) endian ABGR.
|
||||||
|
destFormat = LOCAL_GL_RGBA;
|
||||||
|
destType = LOCAL_GL_UNSIGNED_BYTE;
|
||||||
|
break;
|
||||||
|
case SurfaceFormat::R5G6B5:
|
||||||
|
destFormat = LOCAL_GL_RGB;
|
||||||
|
destType = LOCAL_GL_UNSIGNED_SHORT_5_6_5_REV;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
MOZ_CRASH("Bad format.");
|
||||||
|
}
|
||||||
|
destPixelSize = BytesPerPixel(dest->GetFormat());
|
||||||
|
MOZ_ASSERT(dest->GetSize().width * destPixelSize <= dest->Stride());
|
||||||
|
|
||||||
|
GLenum readFormat = destFormat;
|
||||||
|
GLenum readType = destType;
|
||||||
|
bool needsTempSurf = !GetActualReadFormats(gl,
|
||||||
|
destFormat, destType,
|
||||||
|
readFormat, readType);
|
||||||
|
|
||||||
|
RefPtr<DataSourceSurface> tempSurf;
|
||||||
|
DataSourceSurface* readSurf = nullptr;
|
||||||
|
int readAlignment = 0;
|
||||||
|
if (needsTempSurf) {
|
||||||
|
if (gl->DebugMode()) {
|
||||||
|
NS_WARNING("Needing intermediary surface for ReadPixels. This will be slow!");
|
||||||
|
}
|
||||||
|
SurfaceFormat readFormatGFX;
|
||||||
|
|
||||||
|
// If needs temp surface, readFormat is always LOCAL_GL_RGBA
|
||||||
|
// and readType is always LOCAL_GL_UNSIGNED_BYTE
|
||||||
|
MOZ_ASSERT(readFormat == LOCAL_GL_RGBA);
|
||||||
|
MOZ_ASSERT(readType == LOCAL_GL_UNSIGNED_BYTE);
|
||||||
|
readFormatGFX = hasAlpha ? SurfaceFormat::R8G8B8A8
|
||||||
|
: SurfaceFormat::R8G8B8X8;
|
||||||
|
readAlignment = 1;
|
||||||
int32_t stride = dest->GetSize().width * BytesPerPixel(readFormatGFX);
|
int32_t stride = dest->GetSize().width * BytesPerPixel(readFormatGFX);
|
||||||
tempSurf = Factory::CreateDataSourceSurfaceWithStride(dest->GetSize(),
|
tempSurf = Factory::CreateDataSourceSurfaceWithStride(dest->GetSize(),
|
||||||
readFormatGFX,
|
readFormatGFX,
|
||||||
stride);
|
stride);
|
||||||
readSurf = tempSurf;
|
readSurf = tempSurf;
|
||||||
|
} else {
|
||||||
|
// Figure out alignment. We don't need to know why, we just need it
|
||||||
|
// to be valid.
|
||||||
|
readAlignment = GuessAlignment(dest->GetSize().width,
|
||||||
|
destPixelSize,
|
||||||
|
dest->Stride());
|
||||||
|
readSurf = dest;
|
||||||
}
|
}
|
||||||
MOZ_ASSERT(readAlignment);
|
MOZ_ASSERT(readAlignment);
|
||||||
MOZ_ASSERT(reinterpret_cast<uintptr_t>(readSurf->GetData()) % readAlignment == 0);
|
MOZ_ASSERT(reinterpret_cast<uintptr_t>(readSurf->GetData()) % readAlignment == 0);
|
||||||
|
@ -553,6 +705,14 @@ ReadBackSurface(GLContext* gl, GLuint aTexture, bool aYInvert, SurfaceFormat aFo
|
||||||
return surf.forget();
|
return surf.forget();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ReadScreenIntoImageSurface(GLContext* gl, gfxImageSurface* dest)
|
||||||
|
{
|
||||||
|
ScopedBindFramebuffer autoFB(gl, 0);
|
||||||
|
ReadPixelsIntoImageSurface(gl, dest);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#define CLEANUP_IF_GLERROR_OCCURRED(x) \
|
#define CLEANUP_IF_GLERROR_OCCURRED(x) \
|
||||||
if (DidGLErrorOccur(x)) { \
|
if (DidGLErrorOccur(x)) { \
|
||||||
isurf = nullptr; \
|
isurf = nullptr; \
|
||||||
|
|
|
@ -26,6 +26,8 @@ namespace gl {
|
||||||
|
|
||||||
void ReadPixelsIntoDataSurface(GLContext* aGL,
|
void ReadPixelsIntoDataSurface(GLContext* aGL,
|
||||||
gfx::DataSourceSurface* aSurface);
|
gfx::DataSourceSurface* aSurface);
|
||||||
|
void ReadPixelsIntoImageSurface(GLContext* aGL, gfxImageSurface* aSurface);
|
||||||
|
void ReadScreenIntoImageSurface(GLContext* aGL, gfxImageSurface* aSurface);
|
||||||
|
|
||||||
TemporaryRef<gfx::DataSourceSurface>
|
TemporaryRef<gfx::DataSourceSurface>
|
||||||
ReadBackSurface(GLContext* gl, GLuint aTexture, bool aYInvert, gfx::SurfaceFormat aFormat);
|
ReadBackSurface(GLContext* gl, GLuint aTexture, bool aYInvert, gfx::SurfaceFormat aFormat);
|
||||||
|
|
|
@ -17,12 +17,11 @@
|
||||||
#include "gfxUtils.h" // for gfxUtils
|
#include "gfxUtils.h" // for gfxUtils
|
||||||
#include "gfx2DGlue.h" // for thebes --> moz2d transition
|
#include "gfx2DGlue.h" // for thebes --> moz2d transition
|
||||||
#include "mozilla/gfx/BaseSize.h" // for BaseSize
|
#include "mozilla/gfx/BaseSize.h" // for BaseSize
|
||||||
#include "mozilla/gfx/Tools.h"
|
|
||||||
#include "nsDebug.h" // for NS_ASSERTION, NS_WARNING, etc
|
#include "nsDebug.h" // for NS_ASSERTION, NS_WARNING, etc
|
||||||
#include "nsISupportsImpl.h" // for gfxContext::AddRef, etc
|
#include "nsISupportsImpl.h" // for gfxContext::AddRef, etc
|
||||||
#include "nsRect.h" // for nsIntRect
|
#include "nsRect.h" // for nsIntRect
|
||||||
#include "nsSize.h" // for nsIntSize
|
#include "nsSize.h" // for nsIntSize
|
||||||
#include "gfxUtils.h"
|
#include "LayerUtils.h"
|
||||||
|
|
||||||
using namespace mozilla::gfx;
|
using namespace mozilla::gfx;
|
||||||
using namespace mozilla::gl;
|
using namespace mozilla::gl;
|
||||||
|
@ -127,7 +126,7 @@ CopyableCanvasLayer::UpdateTarget(DrawTarget* aDestTarget)
|
||||||
Factory::CreateWrappingDataSourceSurface(destData, destStride, destSize, destFormat);
|
Factory::CreateWrappingDataSourceSurface(destData, destStride, destSize, destFormat);
|
||||||
mGLContext->Screen()->Readback(sharedSurf, data);
|
mGLContext->Screen()->Readback(sharedSurf, data);
|
||||||
if (needsPremult) {
|
if (needsPremult) {
|
||||||
gfxUtils::PremultiplyDataSurface(data);
|
PremultiplySurface(data);
|
||||||
}
|
}
|
||||||
aDestTarget->ReleaseBits(destData);
|
aDestTarget->ReleaseBits(destData);
|
||||||
return;
|
return;
|
||||||
|
@ -145,7 +144,7 @@ CopyableCanvasLayer::UpdateTarget(DrawTarget* aDestTarget)
|
||||||
// Readback handles Flush/MarkDirty.
|
// Readback handles Flush/MarkDirty.
|
||||||
mGLContext->Screen()->Readback(sharedSurf, data);
|
mGLContext->Screen()->Readback(sharedSurf, data);
|
||||||
if (needsPremult) {
|
if (needsPremult) {
|
||||||
gfxUtils::PremultiplyDataSurface(data);
|
PremultiplySurface(data);
|
||||||
}
|
}
|
||||||
resultSurf = data;
|
resultSurf = data;
|
||||||
}
|
}
|
||||||
|
@ -171,9 +170,7 @@ CopyableCanvasLayer::GetTempSurface(const IntSize& aSize,
|
||||||
aSize != mCachedTempSurface->GetSize() ||
|
aSize != mCachedTempSurface->GetSize() ||
|
||||||
aFormat != mCachedTempSurface->GetFormat())
|
aFormat != mCachedTempSurface->GetFormat())
|
||||||
{
|
{
|
||||||
// Create a surface aligned to 8 bytes since that's the highest alignment WebGL can handle.
|
mCachedTempSurface = Factory::CreateDataSourceSurface(aSize, aFormat);
|
||||||
uint32_t stride = GetAlignedStride<8>(aSize.width * BytesPerPixel(aFormat));
|
|
||||||
mCachedTempSurface = Factory::CreateDataSourceSurfaceWithStride(aSize, aFormat, stride);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return mCachedTempSurface;
|
return mCachedTempSurface;
|
||||||
|
|
|
@ -0,0 +1,101 @@
|
||||||
|
/* -*- Mode: c++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* 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 "LayerUtils.h"
|
||||||
|
#include "PremultiplyTables.h"
|
||||||
|
#include "mozilla/Endian.h"
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
namespace layers {
|
||||||
|
|
||||||
|
using namespace mozilla::gfx;
|
||||||
|
|
||||||
|
static inline const uint8_t PremultiplyValue(uint8_t a, uint8_t v) {
|
||||||
|
return PremultiplyTable[a*256+v];
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline const uint8_t UnpremultiplyValue(uint8_t a, uint8_t v) {
|
||||||
|
return UnpremultiplyTable[a*256+v];
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
static bool IsLittleEndian()
|
||||||
|
{
|
||||||
|
// Violate strict aliasing, because violating strict aliasing is how
|
||||||
|
// we always pack and unpack between uint32_t and uint8_t[].
|
||||||
|
uint16_t testShort;
|
||||||
|
static const uint8_t testBytes[2] = { 0xAA, 0xBB };
|
||||||
|
memcpy(&testShort, testBytes, sizeof(testBytes));
|
||||||
|
return testShort == 0xBBAA;
|
||||||
|
}
|
||||||
|
#endif // DEBUG
|
||||||
|
|
||||||
|
#ifdef MOZ_LITTLE_ENDIAN
|
||||||
|
#define ASSERT_ENDIAN() MOZ_ASSERT(IsLittleEndian(), "Defined as little endian, but actually big!")
|
||||||
|
#else
|
||||||
|
#define ASSERT_ENDIAN() MOZ_ASSERT(!IsLittleEndian(), "Defined as big endian, but actually little!")
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void
|
||||||
|
PremultiplySurface(DataSourceSurface* srcSurface,
|
||||||
|
DataSourceSurface* destSurface)
|
||||||
|
{
|
||||||
|
if (!destSurface)
|
||||||
|
destSurface = srcSurface;
|
||||||
|
|
||||||
|
IntSize srcSize = srcSurface->GetSize();
|
||||||
|
MOZ_ASSERT(srcSurface->GetFormat() == destSurface->GetFormat() &&
|
||||||
|
srcSize.width == destSurface->GetSize().width &&
|
||||||
|
srcSize.height == destSurface->GetSize().height &&
|
||||||
|
srcSurface->Stride() == destSurface->Stride(),
|
||||||
|
"Source and destination surfaces don't have identical characteristics");
|
||||||
|
|
||||||
|
MOZ_ASSERT(srcSurface->Stride() == srcSize.width * 4,
|
||||||
|
"Source surface stride isn't tightly packed");
|
||||||
|
|
||||||
|
// Only premultiply ARGB32
|
||||||
|
if (srcSurface->GetFormat() != SurfaceFormat::B8G8R8A8) {
|
||||||
|
if (destSurface != srcSurface) {
|
||||||
|
memcpy(destSurface->GetData(), srcSurface->GetData(),
|
||||||
|
srcSurface->Stride() * srcSize.height);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t *src = srcSurface->GetData();
|
||||||
|
uint8_t *dst = destSurface->GetData();
|
||||||
|
|
||||||
|
// Assert that our endian define is correct.
|
||||||
|
ASSERT_ENDIAN();
|
||||||
|
|
||||||
|
uint32_t dim = srcSize.width * srcSize.height;
|
||||||
|
for (uint32_t i = 0; i < dim; ++i) {
|
||||||
|
#ifdef MOZ_LITTLE_ENDIAN
|
||||||
|
uint8_t b = *src++;
|
||||||
|
uint8_t g = *src++;
|
||||||
|
uint8_t r = *src++;
|
||||||
|
uint8_t a = *src++;
|
||||||
|
|
||||||
|
*dst++ = PremultiplyValue(a, b);
|
||||||
|
*dst++ = PremultiplyValue(a, g);
|
||||||
|
*dst++ = PremultiplyValue(a, r);
|
||||||
|
*dst++ = a;
|
||||||
|
#else
|
||||||
|
uint8_t a = *src++;
|
||||||
|
uint8_t r = *src++;
|
||||||
|
uint8_t g = *src++;
|
||||||
|
uint8_t b = *src++;
|
||||||
|
|
||||||
|
*dst++ = a;
|
||||||
|
*dst++ = PremultiplyValue(a, r);
|
||||||
|
*dst++ = PremultiplyValue(a, g);
|
||||||
|
*dst++ = PremultiplyValue(a, b);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
/* -*- Mode: c++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* 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 MOZILLA_LAYERS_LAYERUTILS_H_
|
||||||
|
#define MOZILLA_LAYERS_LAYERUTILS_H_
|
||||||
|
|
||||||
|
#include "mozilla/gfx/2D.h"
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
namespace layers {
|
||||||
|
|
||||||
|
void
|
||||||
|
PremultiplySurface(gfx::DataSourceSurface* srcSurface,
|
||||||
|
gfx::DataSourceSurface* destSurface = nullptr);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* MOZILLA_LAYERS_LAYERUTILS_H_ */
|
|
@ -124,10 +124,6 @@ ImageHost::Composite(EffectChain& aEffectChain,
|
||||||
} else {
|
} else {
|
||||||
effect->mTextureCoords = Rect(0, 0, 1, 1);
|
effect->mTextureCoords = Rect(0, 0, 1, 1);
|
||||||
}
|
}
|
||||||
if (mFrontBuffer->GetFlags() & TextureFlags::NEEDS_Y_FLIP) {
|
|
||||||
effect->mTextureCoords.y = effect->mTextureCoords.YMost();
|
|
||||||
effect->mTextureCoords.height = -effect->mTextureCoords.height;
|
|
||||||
}
|
|
||||||
GetCompositor()->DrawQuad(rect, aClipRect, aEffectChain,
|
GetCompositor()->DrawQuad(rect, aClipRect, aEffectChain,
|
||||||
aOpacity, aTransform);
|
aOpacity, aTransform);
|
||||||
GetCompositor()->DrawDiagnostics(DiagnosticFlags::IMAGE | DiagnosticFlags::BIGIMAGE,
|
GetCompositor()->DrawDiagnostics(DiagnosticFlags::IMAGE | DiagnosticFlags::BIGIMAGE,
|
||||||
|
|
|
@ -294,6 +294,7 @@ UNIFIED_SOURCES += [
|
||||||
'LayerScope.cpp',
|
'LayerScope.cpp',
|
||||||
'LayersLogging.cpp',
|
'LayersLogging.cpp',
|
||||||
'LayerSorter.cpp',
|
'LayerSorter.cpp',
|
||||||
|
'LayerUtils.cpp',
|
||||||
'opengl/CompositingRenderTargetOGL.cpp',
|
'opengl/CompositingRenderTargetOGL.cpp',
|
||||||
'opengl/CompositorOGL.cpp',
|
'opengl/CompositorOGL.cpp',
|
||||||
'opengl/OGLShaderProgram.cpp',
|
'opengl/OGLShaderProgram.cpp',
|
||||||
|
|
|
@ -36,24 +36,34 @@ static const uint8_t UnpremultiplyValue(uint8_t a, uint8_t v) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
gfxUtils::PremultiplyDataSurface(DataSourceSurface *aSurface)
|
gfxUtils::PremultiplyImageSurface(gfxImageSurface *aSourceSurface,
|
||||||
|
gfxImageSurface *aDestSurface)
|
||||||
{
|
{
|
||||||
// Only premultiply ARGB32
|
if (!aDestSurface)
|
||||||
if (aSurface->GetFormat() != SurfaceFormat::B8G8R8A8) {
|
aDestSurface = aSourceSurface;
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
DataSourceSurface::MappedSurface map;
|
MOZ_ASSERT(aSourceSurface->Format() == aDestSurface->Format() &&
|
||||||
if (!aSurface->Map(DataSourceSurface::MapType::READ_WRITE, &map)) {
|
aSourceSurface->Width() == aDestSurface->Width() &&
|
||||||
return;
|
aSourceSurface->Height() == aDestSurface->Height() &&
|
||||||
}
|
aSourceSurface->Stride() == aDestSurface->Stride(),
|
||||||
MOZ_ASSERT(map.mStride == aSurface->GetSize().width * 4,
|
"Source and destination surfaces don't have identical characteristics");
|
||||||
|
|
||||||
|
MOZ_ASSERT(aSourceSurface->Stride() == aSourceSurface->Width() * 4,
|
||||||
"Source surface stride isn't tightly packed");
|
"Source surface stride isn't tightly packed");
|
||||||
|
|
||||||
uint8_t *src = map.mData;
|
// Only premultiply ARGB32
|
||||||
uint8_t *dst = map.mData;
|
if (aSourceSurface->Format() != gfxImageFormat::ARGB32) {
|
||||||
|
if (aDestSurface != aSourceSurface) {
|
||||||
|
memcpy(aDestSurface->Data(), aSourceSurface->Data(),
|
||||||
|
aSourceSurface->Stride() * aSourceSurface->Height());
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t dim = aSurface->GetSize().width * aSurface->GetSize().height;
|
uint8_t *src = aSourceSurface->Data();
|
||||||
|
uint8_t *dst = aDestSurface->Data();
|
||||||
|
|
||||||
|
uint32_t dim = aSourceSurface->Width() * aSourceSurface->Height();
|
||||||
for (uint32_t i = 0; i < dim; ++i) {
|
for (uint32_t i = 0; i < dim; ++i) {
|
||||||
#ifdef IS_LITTLE_ENDIAN
|
#ifdef IS_LITTLE_ENDIAN
|
||||||
uint8_t b = *src++;
|
uint8_t b = *src++;
|
||||||
|
@ -77,8 +87,59 @@ gfxUtils::PremultiplyDataSurface(DataSourceSurface *aSurface)
|
||||||
*dst++ = PremultiplyValue(a, b);
|
*dst++ = PremultiplyValue(a, b);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
aSurface->Unmap();
|
void
|
||||||
|
gfxUtils::UnpremultiplyImageSurface(gfxImageSurface *aSourceSurface,
|
||||||
|
gfxImageSurface *aDestSurface)
|
||||||
|
{
|
||||||
|
if (!aDestSurface)
|
||||||
|
aDestSurface = aSourceSurface;
|
||||||
|
|
||||||
|
MOZ_ASSERT(aSourceSurface->Format() == aDestSurface->Format() &&
|
||||||
|
aSourceSurface->Width() == aDestSurface->Width() &&
|
||||||
|
aSourceSurface->Height() == aDestSurface->Height(),
|
||||||
|
"Source and destination surfaces don't have identical characteristics");
|
||||||
|
|
||||||
|
// Only premultiply ARGB32
|
||||||
|
if (aSourceSurface->Format() != gfxImageFormat::ARGB32) {
|
||||||
|
if (aDestSurface != aSourceSurface) {
|
||||||
|
aDestSurface->CopyFrom(aSourceSurface);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t *src = aSourceSurface->Data();
|
||||||
|
uint8_t *dst = aDestSurface->Data();
|
||||||
|
|
||||||
|
for (int32_t i = 0; i < aSourceSurface->Height(); ++i) {
|
||||||
|
uint8_t *srcRow = src + (i * aSourceSurface->Stride());
|
||||||
|
uint8_t *dstRow = dst + (i * aDestSurface->Stride());
|
||||||
|
|
||||||
|
for (int32_t j = 0; j < aSourceSurface->Width(); ++j) {
|
||||||
|
#ifdef IS_LITTLE_ENDIAN
|
||||||
|
uint8_t b = *srcRow++;
|
||||||
|
uint8_t g = *srcRow++;
|
||||||
|
uint8_t r = *srcRow++;
|
||||||
|
uint8_t a = *srcRow++;
|
||||||
|
|
||||||
|
*dstRow++ = UnpremultiplyValue(a, b);
|
||||||
|
*dstRow++ = UnpremultiplyValue(a, g);
|
||||||
|
*dstRow++ = UnpremultiplyValue(a, r);
|
||||||
|
*dstRow++ = a;
|
||||||
|
#else
|
||||||
|
uint8_t a = *srcRow++;
|
||||||
|
uint8_t r = *srcRow++;
|
||||||
|
uint8_t g = *srcRow++;
|
||||||
|
uint8_t b = *srcRow++;
|
||||||
|
|
||||||
|
*dstRow++ = a;
|
||||||
|
*dstRow++ = UnpremultiplyValue(a, r);
|
||||||
|
*dstRow++ = UnpremultiplyValue(a, g);
|
||||||
|
*dstRow++ = UnpremultiplyValue(a, b);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TemporaryRef<DataSourceSurface>
|
TemporaryRef<DataSourceSurface>
|
||||||
|
|
|
@ -40,7 +40,10 @@ public:
|
||||||
* If the source is not gfxImageFormat::ARGB32, no operation is performed. If
|
* If the source is not gfxImageFormat::ARGB32, no operation is performed. If
|
||||||
* aDestSurface is given, the data is copied over.
|
* aDestSurface is given, the data is copied over.
|
||||||
*/
|
*/
|
||||||
static void PremultiplyDataSurface(DataSourceSurface *aSurface);
|
static void PremultiplyImageSurface(gfxImageSurface *aSourceSurface,
|
||||||
|
gfxImageSurface *aDestSurface = nullptr);
|
||||||
|
static void UnpremultiplyImageSurface(gfxImageSurface *aSurface,
|
||||||
|
gfxImageSurface *aDestSurface = nullptr);
|
||||||
static mozilla::TemporaryRef<DataSourceSurface> UnpremultiplyDataSurface(DataSourceSurface* aSurface);
|
static mozilla::TemporaryRef<DataSourceSurface> UnpremultiplyDataSurface(DataSourceSurface* aSurface);
|
||||||
|
|
||||||
static void ConvertBGRAtoRGBA(gfxImageSurface *aSourceSurface,
|
static void ConvertBGRAtoRGBA(gfxImageSurface *aSourceSurface,
|
||||||
|
|
Загрузка…
Ссылка в новой задаче