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
GetActualReadFormats(GLContext* gl, GLenum destFormat, GLenum destType,
GetActualReadFormats(GLContext* gl,
GLenum destFormat, GLenum destType,
GLenum& readFormat, GLenum& readType)
{
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
ReadPixelsIntoImageSurface(GLContext* gl, gfxImageSurface* dest) {
gl->MakeCurrent();
MOZ_ASSERT(dest->GetSize() != gfxIntSize(0, 0));
/* gfxImageFormat::ARGB32:
* RGBA+UByte: be[RGBA], le[ABGR]
* RGBA+UInt: le[RGBA]
* BGRA+UInt: le[BGRA]
* BGRA+UIntRev: le[ARGB]
* 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]
@ -269,7 +297,7 @@ ReadPixelsIntoImageSurface(GLContext* gl, gfxImageSurface* dest) {
default:
MOZ_CRASH("Bad format.");
}
MOZ_ASSERT(dest->Stride() == dest->Width() * destPixelSize);
MOZ_ASSERT(dest->Width() * destPixelSize <= dest->Stride());
GLenum readFormat = destFormat;
GLenum readType = destType;
@ -279,7 +307,7 @@ ReadPixelsIntoImageSurface(GLContext* gl, gfxImageSurface* dest) {
nsAutoPtr<gfxImageSurface> tempSurf;
gfxImageSurface* readSurf = nullptr;
int readPixelSize = 0;
int readAlignment = 0;
if (needsTempSurf) {
if (gl->DebugMode()) {
NS_WARNING("Needing intermediary surface for ReadPixels. This will be slow!");
@ -294,7 +322,7 @@ ReadPixelsIntoImageSurface(GLContext* gl, gfxImageSurface* dest) {
break;
}
case LOCAL_GL_RGB: {
MOZ_ASSERT(readPixelSize == 2);
MOZ_ASSERT(destPixelSize == 2);
MOZ_ASSERT(readType == LOCAL_GL_UNSIGNED_SHORT_5_6_5_REV);
readFormatGFX = SurfaceFormat::R5G6B5;
break;
@ -307,17 +335,17 @@ ReadPixelsIntoImageSurface(GLContext* gl, gfxImageSurface* dest) {
switch (readType) {
case LOCAL_GL_UNSIGNED_BYTE: {
MOZ_ASSERT(readFormat == LOCAL_GL_RGBA);
readPixelSize = 4;
readAlignment = 1;
break;
}
case LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV: {
MOZ_ASSERT(readFormat == LOCAL_GL_BGRA);
readPixelSize = 4;
readAlignment = 4;
break;
}
case LOCAL_GL_UNSIGNED_SHORT_5_6_5_REV: {
MOZ_ASSERT(readFormat == LOCAL_GL_RGB);
readPixelSize = 2;
readAlignment = 2;
break;
}
default: {
@ -330,16 +358,20 @@ ReadPixelsIntoImageSurface(GLContext* gl, gfxImageSurface* dest) {
false);
readSurf = tempSurf;
} 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;
}
MOZ_ASSERT(readPixelSize);
MOZ_ASSERT(readAlignment);
GLint currentPackAlignment = 0;
gl->fGetIntegerv(LOCAL_GL_PACK_ALIGNMENT, &currentPackAlignment);
if (currentPackAlignment != readPixelSize)
gl->fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, readPixelSize);
if (currentPackAlignment != readAlignment)
gl->fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, readAlignment);
GLsizei width = dest->Width();
GLsizei height = dest->Height();
@ -351,7 +383,7 @@ ReadPixelsIntoImageSurface(GLContext* gl, gfxImageSurface* dest) {
readSurf->Data());
readSurf->MarkDirty();
if (currentPackAlignment != readPixelSize)
if (currentPackAlignment != readAlignment)
gl->fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, currentPackAlignment);
if (readSurf != dest) {
@ -387,6 +419,8 @@ ReadPixelsIntoImageSurface(GLContext* gl, gfxImageSurface* dest) {
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;