author | Jeff Gilbert <jgilbert@mozilla.com> |
Thu, 16 Jun 2016 07:30:47 -0700 | |
changeset 305276 | 40e9d24fd8eab4cd9d9e434ca3d5e815148a7b3f |
parent 305275 | c70eb1338bf4621388b0187510dd288ca2be6591 |
child 305277 | 0a20a55213d28e92a78f8f483aa27c38818732c7 |
push id | 79535 |
push user | jgilbert@mozilla.com |
push date | Mon, 18 Jul 2016 04:46:14 +0000 |
treeherder | mozilla-inbound@b658098634b8 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | jrmuizel |
bugs | 1250710 |
milestone | 50.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
dom/canvas/WebGLContext.h | file | annotate | diff | comparison | revisions | |
dom/canvas/WebGLContextGL.cpp | file | annotate | diff | comparison | revisions |
--- a/dom/canvas/WebGLContext.h +++ b/dom/canvas/WebGLContext.h @@ -539,17 +539,18 @@ public: void PixelStorei(GLenum pname, GLint param); void PolygonOffset(GLfloat factor, GLfloat units); protected: bool ReadPixels_SharedPrecheck(ErrorResult* const out_error); void ReadPixelsImpl(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* data, uint32_t dataLen); bool DoReadPixelsAndConvert(const webgl::FormatInfo* srcFormat, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, - GLenum destType, void* dest); + GLenum destType, void* dest, uint32_t dataLen, + uint32_t rowStride); public: void ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, const dom::Nullable<dom::ArrayBufferView>& pixels, ErrorResult& rv); void RenderbufferStorage(GLenum target, GLenum internalFormat, GLsizei width, GLsizei height); protected:
--- a/dom/canvas/WebGLContextGL.cpp +++ b/dom/canvas/WebGLContextGL.cpp @@ -1226,17 +1226,18 @@ IsNeedsANGLEWorkAround(const webgl::Form default: return false; } } bool WebGLContext::DoReadPixelsAndConvert(const webgl::FormatInfo* srcFormat, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, - GLenum destType, void* dest) + GLenum destType, void* dest, uint32_t destSize, + uint32_t rowStride) { if (gl->WorkAroundDriverBugs() && gl->IsANGLE() && gl->Version() < 300 && // ANGLE ES2 doesn't support HALF_FLOAT reads properly. IsNeedsANGLEWorkAround(srcFormat)) { MOZ_RELEASE_ASSERT(!IsWebGL2()); // No SKIP_PIXELS, etc. MOZ_ASSERT(!mBoundPixelPackBuffer); // Let's be real clear. @@ -1300,17 +1301,46 @@ WebGLContext::DoReadPixelsAndConvert(con srcRow += readStride; dstRow += destStride; } return true; } - gl->fReadPixels(x, y, width, height, format, destType, dest); + // On at least Win+NV, we'll get PBO errors if we don't have at least + // `rowStride * height` bytes available to read into. + const auto naiveBytesNeeded = CheckedUint32(rowStride) * height; + const bool isDangerCloseToEdge = (!naiveBytesNeeded.isValid() || + naiveBytesNeeded.value() > destSize); + const bool useParanoidHandling = (gl->WorkAroundDriverBugs() && + isDangerCloseToEdge && + mBoundPixelPackBuffer); + if (!useParanoidHandling) { + gl->fReadPixels(x, y, width, height, format, destType, dest); + return true; + } + + // Read everything but the last row. + const auto bodyHeight = height - 1; + if (bodyHeight) { + gl->fReadPixels(x, y, width, bodyHeight, format, destType, dest); + } + + // Now read the last row. + gl->fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, 1); + gl->fPixelStorei(LOCAL_GL_PACK_ROW_LENGTH, 0); + gl->fPixelStorei(LOCAL_GL_PACK_SKIP_ROWS, 0); + + const auto tailRowOffset = (char*)dest + rowStride * bodyHeight; + gl->fReadPixels(x, y+bodyHeight, width, 1, format, destType, tailRowOffset); + + gl->fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, mPixelStore_PackAlignment); + gl->fPixelStorei(LOCAL_GL_PACK_ROW_LENGTH, mPixelStore_PackRowLength); + gl->fPixelStorei(LOCAL_GL_PACK_SKIP_ROWS, mPixelStore_PackSkipRows); return true; } static bool IsFormatAndTypeUnpackable(GLenum format, GLenum type, bool isWebGL2) { switch (type) { case LOCAL_GL_UNSIGNED_BYTE: @@ -1759,17 +1789,17 @@ WebGLContext::ReadPixelsImpl(GLint x, GL uint32_t readX, readY; uint32_t writeX, writeY; uint32_t rwWidth, rwHeight; Intersect(srcWidth, x, width, &readX, &writeX, &rwWidth); Intersect(srcHeight, y, height, &readY, &writeY, &rwHeight); if (rwWidth == uint32_t(width) && rwHeight == uint32_t(height)) { DoReadPixelsAndConvert(srcFormat->format, x, y, width, height, packFormat, - packType, dest); + packType, dest, dataLen, rowStride); return; } // Read request contains out-of-bounds pixels. Unfortunately: // GLES 3.0.4 p194 "Obtaining Pixels from the Framebuffer": // "If any of these pixels lies outside of the window allocated to the current GL // context, or outside of the image attached to the currently bound framebuffer // object, then the values obtained for those pixels are undefined." @@ -1791,29 +1821,29 @@ WebGLContext::ReadPixelsImpl(GLint x, GL if (!mPixelStore_PackRowLength) { gl->fPixelStorei(LOCAL_GL_PACK_ROW_LENGTH, mPixelStore_PackSkipPixels + width); } gl->fPixelStorei(LOCAL_GL_PACK_SKIP_PIXELS, mPixelStore_PackSkipPixels + writeX); gl->fPixelStorei(LOCAL_GL_PACK_SKIP_ROWS, mPixelStore_PackSkipRows + writeY); DoReadPixelsAndConvert(srcFormat->format, readX, readY, rwWidth, rwHeight, - packFormat, packType, dest); + packFormat, packType, dest, dataLen, rowStride); gl->fPixelStorei(LOCAL_GL_PACK_ROW_LENGTH, mPixelStore_PackRowLength); gl->fPixelStorei(LOCAL_GL_PACK_SKIP_PIXELS, mPixelStore_PackSkipPixels); gl->fPixelStorei(LOCAL_GL_PACK_SKIP_ROWS, mPixelStore_PackSkipRows); } else { // I *did* say "hilariously slow". uint8_t* row = (uint8_t*)dest + writeX * bytesPerPixel; row += writeY * rowStride; for (uint32_t j = 0; j < rwHeight; j++) { DoReadPixelsAndConvert(srcFormat->format, readX, readY+j, rwWidth, 1, - packFormat, packType, row); + packFormat, packType, row, dataLen, rowStride); row += rowStride; } } } void WebGLContext::RenderbufferStorage_base(const char* funcName, GLenum target, GLsizei samples, GLenum internalFormat,