Bug 960378 - Allow Reading into non-tightly-packed surfaces. - r=bjacob

This commit is contained in:
Jeff Gilbert 2014-02-13 15:38:53 -08:00
parent 62bc24f9b3
commit f68d00bf9a

View File

@ -156,7 +156,8 @@ GLReadTexImageHelper::DidGLErrorOccur(const char* str)
} }
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)
{ {
if (destFormat == LOCAL_GL_RGBA && if (destFormat == LOCAL_GL_RGBA &&
@ -231,16 +232,43 @@ static void SwapRAndBComponents(DataSourceSurface* surf)
} }
} }
static int
CalcStride(int width, int pixelSize, int alignment)
{
MOZ_ASSERT(alignment);
int stride = width * pixelSize;
if (stride % alignment) { // Extra at the end of the line?
int alignmentCount = stride / alignment;
stride = (alignmentCount+1) * alignment;
}
return stride;
}
static int
GuessAlignment(int width, int pixelSize, int stride)
{
int alignment = 8; // Max GLES allows.
while (CalcStride(width, pixelSize, alignment) != stride) {
alignment /= 2;
if (!alignment) {
MOZ_ASSERT(alignment);
return 1;
}
}
return alignment;
}
void void
ReadPixelsIntoImageSurface(GLContext* gl, gfxImageSurface* dest) { ReadPixelsIntoImageSurface(GLContext* gl, gfxImageSurface* dest) {
gl->MakeCurrent(); gl->MakeCurrent();
MOZ_ASSERT(dest->GetSize() != gfxIntSize(0, 0)); MOZ_ASSERT(dest->GetSize() != gfxIntSize(0, 0));
/* gfxImageFormat::ARGB32: /* gfxImageFormat::ARGB32:
* RGBA+UByte: be[RGBA], le[ABGR] * RGBA+UByte: be[RGBA], le[ABGR]
* RGBA+UInt: le[RGBA] * RGBA+UInt: be[ABGR], le[RGBA]
* BGRA+UInt: le[BGRA] * BGRA+UInt: be[ARGB], le[BGRA]
* BGRA+UIntRev: le[ARGB] * BGRA+UIntRev: be[BGRA], le[ARGB]
* *
* gfxImageFormat::RGB16_565: * gfxImageFormat::RGB16_565:
* RGB+UShort: le[rrrrrggg,gggbbbbb] * RGB+UShort: le[rrrrrggg,gggbbbbb]
@ -269,7 +297,7 @@ ReadPixelsIntoImageSurface(GLContext* gl, gfxImageSurface* dest) {
default: default:
MOZ_CRASH("Bad format."); MOZ_CRASH("Bad format.");
} }
MOZ_ASSERT(dest->Stride() == dest->Width() * destPixelSize); MOZ_ASSERT(dest->Width() * destPixelSize <= dest->Stride());
GLenum readFormat = destFormat; GLenum readFormat = destFormat;
GLenum readType = destType; GLenum readType = destType;
@ -279,7 +307,7 @@ ReadPixelsIntoImageSurface(GLContext* gl, gfxImageSurface* dest) {
nsAutoPtr<gfxImageSurface> tempSurf; nsAutoPtr<gfxImageSurface> tempSurf;
gfxImageSurface* readSurf = nullptr; gfxImageSurface* readSurf = nullptr;
int readPixelSize = 0; int readAlignment = 0;
if (needsTempSurf) { if (needsTempSurf) {
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!");
@ -294,7 +322,7 @@ ReadPixelsIntoImageSurface(GLContext* gl, gfxImageSurface* dest) {
break; break;
} }
case LOCAL_GL_RGB: { case LOCAL_GL_RGB: {
MOZ_ASSERT(readPixelSize == 2); MOZ_ASSERT(destPixelSize == 2);
MOZ_ASSERT(readType == LOCAL_GL_UNSIGNED_SHORT_5_6_5_REV); MOZ_ASSERT(readType == LOCAL_GL_UNSIGNED_SHORT_5_6_5_REV);
readFormatGFX = SurfaceFormat::R5G6B5; readFormatGFX = SurfaceFormat::R5G6B5;
break; break;
@ -307,17 +335,17 @@ ReadPixelsIntoImageSurface(GLContext* gl, gfxImageSurface* dest) {
switch (readType) { switch (readType) {
case LOCAL_GL_UNSIGNED_BYTE: { case LOCAL_GL_UNSIGNED_BYTE: {
MOZ_ASSERT(readFormat == LOCAL_GL_RGBA); MOZ_ASSERT(readFormat == LOCAL_GL_RGBA);
readPixelSize = 4; readAlignment = 1;
break; break;
} }
case LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV: { case LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV: {
MOZ_ASSERT(readFormat == LOCAL_GL_BGRA); MOZ_ASSERT(readFormat == LOCAL_GL_BGRA);
readPixelSize = 4; readAlignment = 4;
break; break;
} }
case LOCAL_GL_UNSIGNED_SHORT_5_6_5_REV: { case LOCAL_GL_UNSIGNED_SHORT_5_6_5_REV: {
MOZ_ASSERT(readFormat == LOCAL_GL_RGB); MOZ_ASSERT(readFormat == LOCAL_GL_RGB);
readPixelSize = 2; readAlignment = 2;
break; break;
} }
default: { default: {
@ -330,16 +358,20 @@ ReadPixelsIntoImageSurface(GLContext* gl, gfxImageSurface* dest) {
false); false);
readSurf = tempSurf; readSurf = tempSurf;
} else { } else {
readPixelSize = destPixelSize; // Figure out alignment. We don't need to know why, we just need it
// to be valid.
readAlignment = GuessAlignment(dest->Width(),
destPixelSize,
dest->Stride());
readSurf = dest; readSurf = dest;
} }
MOZ_ASSERT(readPixelSize); MOZ_ASSERT(readAlignment);
GLint currentPackAlignment = 0; GLint currentPackAlignment = 0;
gl->fGetIntegerv(LOCAL_GL_PACK_ALIGNMENT, &currentPackAlignment); gl->fGetIntegerv(LOCAL_GL_PACK_ALIGNMENT, &currentPackAlignment);
if (currentPackAlignment != readPixelSize) if (currentPackAlignment != readAlignment)
gl->fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, readPixelSize); gl->fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, readAlignment);
GLsizei width = dest->Width(); GLsizei width = dest->Width();
GLsizei height = dest->Height(); GLsizei height = dest->Height();
@ -351,7 +383,7 @@ ReadPixelsIntoImageSurface(GLContext* gl, gfxImageSurface* dest) {
readSurf->Data()); readSurf->Data());
readSurf->MarkDirty(); readSurf->MarkDirty();
if (currentPackAlignment != readPixelSize) if (currentPackAlignment != readAlignment)
gl->fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, currentPackAlignment); gl->fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, currentPackAlignment);
if (readSurf != dest) { if (readSurf != dest) {
@ -387,6 +419,8 @@ ReadPixelsIntoImageSurface(GLContext* gl, gfxImageSurface* dest) {
if (!alphaBits) { if (!alphaBits) {
const uint32_t alphaMask = gfxPackedPixelNoPreMultiply(0xff,0,0,0); const uint32_t alphaMask = gfxPackedPixelNoPreMultiply(0xff,0,0,0);
MOZ_ASSERT(dest->Width() * destPixelSize == dest->Stride());
dest->Flush(); dest->Flush();
uint32_t* itr = (uint32_t*)dest->Data(); uint32_t* itr = (uint32_t*)dest->Data();
uint32_t testPixel = *itr; uint32_t testPixel = *itr;