From 41c0b57871e86c5a16a6bd4eee4a2f10e3d4418b Mon Sep 17 00:00:00 2001 From: Jeff Gilbert Date: Thu, 21 Jul 2016 19:20:21 -0700 Subject: [PATCH] Bug 1280499 - Implement PBOs for textures. - r=jrmuizel MozReview-Commit-ID: 3FCinT9hS8j --- dom/canvas/TexUnpackBlob.cpp | 10 +- dom/canvas/TexUnpackBlob.h | 15 +-- dom/canvas/WebGLContext.h | 4 +- dom/canvas/WebGLTexture.h | 6 + dom/canvas/WebGLTextureUpload.cpp | 175 +++++++++++++++++++----------- 5 files changed, 136 insertions(+), 74 deletions(-) diff --git a/dom/canvas/TexUnpackBlob.cpp b/dom/canvas/TexUnpackBlob.cpp index f382c7c06412..d84eaf36e431 100644 --- a/dom/canvas/TexUnpackBlob.cpp +++ b/dom/canvas/TexUnpackBlob.cpp @@ -319,11 +319,12 @@ DoTexOrSubImage(bool isSubImage, gl::GLContext* gl, TexImageTarget target, GLint TexUnpackBytes::TexUnpackBytes(const WebGLContext* webgl, TexImageTarget target, uint32_t width, uint32_t height, uint32_t depth, - const void* bytes) + bool isClientData, const void* ptr) : TexUnpackBlob(webgl, target, FallbackOnZero(webgl->mPixelStore_UnpackRowLength, width), width, height, depth, false) - , mBytes(bytes) + , mIsClientData(isClientData) + , mPtr(ptr) { } bool @@ -347,8 +348,9 @@ TexUnpackBytes::TexOrSubImage(bool isSubImage, bool needsRespec, const char* fun const void* uploadBytes; UniqueBuffer tempBuffer; - if (!ConvertIfNeeded(webgl, funcName, mBytes, rowStride.value(), bytesPerPixel, - format, dui, &uploadBytes, &tempBuffer)) + if (mIsClientData && + !ConvertIfNeeded(webgl, funcName, mPtr, rowStride.value(), bytesPerPixel, format, + dui, &uploadBytes, &tempBuffer)) { return false; } diff --git a/dom/canvas/TexUnpackBlob.h b/dom/canvas/TexUnpackBlob.h index a20e718df317..eb1736bb71c4 100644 --- a/dom/canvas/TexUnpackBlob.h +++ b/dom/canvas/TexUnpackBlob.h @@ -86,12 +86,13 @@ public: class TexUnpackBytes final : public TexUnpackBlob { public: - const void* const mBytes; + const bool mIsClientData; + const void* const mPtr; TexUnpackBytes(const WebGLContext* webgl, TexImageTarget target, uint32_t width, - uint32_t height, uint32_t depth, const void* bytes); + uint32_t height, uint32_t depth, bool isClientData, const void* ptr); - virtual bool HasData() const override { return bool(mBytes); } + virtual bool HasData() const override { return !mIsClientData || bool(mPtr); } virtual bool TexOrSubImage(bool isSubImage, bool needsRespec, const char* funcName, WebGLTexture* tex, TexImageTarget target, GLint level, @@ -126,10 +127,10 @@ public: bool isAlphaPremult); virtual bool TexOrSubImage(bool isSubImage, bool needsRespec, const char* funcName, - WebGLTexture* tex, TexImageTarget target, GLint level, - const webgl::DriverUnpackInfo* dui, GLint xOffset, - GLint yOffset, GLint zOffset, - GLenum* const out_error) const override; + WebGLTexture* tex, TexImageTarget target, GLint level, + const webgl::DriverUnpackInfo* dui, GLint xOffset, + GLint yOffset, GLint zOffset, + GLenum* const out_error) const override; }; } // namespace webgl diff --git a/dom/canvas/WebGLContext.h b/dom/canvas/WebGLContext.h index 46521f9a8f0b..2aa8b7266275 100644 --- a/dom/canvas/WebGLContext.h +++ b/dom/canvas/WebGLContext.h @@ -914,8 +914,8 @@ protected: WebGLTexture** const out_texture, WebGLTexture::ImageInfo** const out_imageInfo); - bool ValidateUnpackInfo(const char* funcName, GLenum format, GLenum type, - webgl::PackingInfo* const out); + bool ValidateUnpackInfo(const char* funcName, bool usePBOs, GLenum format, + GLenum type, webgl::PackingInfo* const out); // ----------------------------------------------------------------------------- // Vertices Feature (WebGLContextVertices.cpp) diff --git a/dom/canvas/WebGLTexture.h b/dom/canvas/WebGLTexture.h index 204e373c1d14..b4d128e33606 100644 --- a/dom/canvas/WebGLTexture.h +++ b/dom/canvas/WebGLTexture.h @@ -237,6 +237,12 @@ public: GLint zOffset, GLenum unpackFormat, GLenum unpackType, dom::Element* elem, ErrorResult* const out_error); + void TexOrSubImage(bool isSubImage, const char* funcName, TexImageTarget target, + GLint level, GLenum internalFormat, GLint xOffset, GLint yOffset, + GLint zOffset, GLsizei width, GLsizei height, GLsizei depth, + GLint border, GLenum unpackFormat, GLenum unpackType, + WebGLsizeiptr offset); + protected: void TexOrSubImageBlob(bool isSubImage, const char* funcName, TexImageTarget target, GLint level, GLenum internalFormat, GLint xOffset, diff --git a/dom/canvas/WebGLTextureUpload.cpp b/dom/canvas/WebGLTextureUpload.cpp index 105ad8953334..55dbc5bee5a7 100644 --- a/dom/canvas/WebGLTextureUpload.cpp +++ b/dom/canvas/WebGLTextureUpload.cpp @@ -177,68 +177,37 @@ WebGLContext::ValidateUnpackPixels(const char* funcName, uint32_t fullRows, return false; } -static UniquePtr -BlobFromView(WebGLContext* webgl, const char* funcName, TexImageTarget target, - uint32_t width, uint32_t height, uint32_t depth, - const webgl::PackingInfo& pi, - const dom::Nullable& maybeView) +static bool +ValidateUnpackBytes(WebGLContext* webgl, const char* funcName, uint32_t width, + uint32_t height, uint32_t depth, const webgl::PackingInfo& pi, + uint32_t byteCount, const webgl::TexUnpackBlob* blob) { - const uint8_t* bytes = nullptr; - uint32_t byteCount = 0; + const auto bytesPerPixel = webgl::BytesPerPixel(pi); + const auto bytesPerRow = CheckedUint32(blob->mRowLength) * bytesPerPixel; + const auto rowStride = RoundUpToMultipleOf(bytesPerRow, blob->mAlignment); - if (!maybeView.IsNull()) { - const auto& view = maybeView.Value(); - - const auto jsType = JS_GetArrayBufferViewType(view.Obj()); - if (!DoesJSTypeMatchUnpackType(pi.type, jsType)) { - webgl->ErrorInvalidOperation("%s: `pixels` must be compatible with `type`.", - funcName); - return nullptr; - } - - if (width && height && depth) { - view.ComputeLengthAndData(); - - bytes = view.DataAllowShared(); - byteCount = view.LengthAllowShared(); - } + const auto fullRows = byteCount / rowStride; + if (!fullRows.isValid()) { + webgl->ErrorOutOfMemory("%s: Unacceptable upload size calculated."); + return false; } - UniquePtr blob(new webgl::TexUnpackBytes(webgl, target, width, - height, depth, bytes)); + const auto bodyBytes = fullRows.value() * rowStride.value(); + const auto tailPixels = (byteCount - bodyBytes) / bytesPerPixel; - ////// - - if (bytes) { - const auto bytesPerPixel = webgl::BytesPerPixel(pi); - const auto bytesPerRow = CheckedUint32(blob->mRowLength) * bytesPerPixel; - const auto rowStride = RoundUpToMultipleOf(bytesPerRow, blob->mAlignment); - - const auto fullRows = byteCount / rowStride; - if (!fullRows.isValid()) { - webgl->ErrorOutOfMemory("%s: Unacceptable upload size calculated."); - return nullptr; - } - - const auto bodyBytes = fullRows.value() * rowStride.value(); - const auto tailPixels = (byteCount - bodyBytes) / bytesPerPixel; - - if (!webgl->ValidateUnpackPixels(funcName, fullRows.value(), tailPixels, - blob.get())) - { - return nullptr; - } - } - - ////// - - return Move(blob); + return webgl->ValidateUnpackPixels(funcName, fullRows.value(), tailPixels, blob); } bool -WebGLContext::ValidateUnpackInfo(const char* funcName, GLenum format, GLenum type, - webgl::PackingInfo* const out) +WebGLContext::ValidateUnpackInfo(const char* funcName, bool usePBOs, GLenum format, + GLenum type, webgl::PackingInfo* const out) { + if (usePBOs != bool(mBoundPixelUnpackBuffer)) { + ErrorInvalidOperation("%s: PACK_BUFFER must be %s.", funcName, + (usePBOs ? "non-null" : "null")); + return false; + } + if (!mFormatUsage->AreUnpackEnumsValid(format, type)) { ErrorInvalidEnum("%s: Invalid unpack format/type: 0x%04x/0x%04x", funcName, format, type); @@ -265,17 +234,97 @@ WebGLTexture::TexOrSubImage(bool isSubImage, const char* funcName, TexImageTarge return; } + const bool usePBOs = false; webgl::PackingInfo pi; - if (!mContext->ValidateUnpackInfo(funcName, unpackFormat, unpackType, &pi)) + if (!mContext->ValidateUnpackInfo(funcName, usePBOs, unpackFormat, unpackType, &pi)) return; - const auto blob = BlobFromView(mContext, funcName, target, width, height, depth, pi, - maybeView); - if (!blob) + //// + + const void* bytes = nullptr; + uint32_t byteCount = 0; + + if (!maybeView.IsNull()) { + const auto& view = maybeView.Value(); + + const auto jsType = JS_GetArrayBufferViewType(view.Obj()); + if (!DoesJSTypeMatchUnpackType(pi.type, jsType)) { + mContext->ErrorInvalidOperation("%s: `pixels` not compatible with `type`.", + funcName); + return; + } + + if (width && height && depth) { + view.ComputeLengthAndData(); + + bytes = view.DataAllowShared(); + byteCount = view.LengthAllowShared(); + } + } + + const bool isClientData = true; + const webgl::TexUnpackBytes blob(mContext, target, width, height, depth, isClientData, + bytes); + + if (bytes && + !ValidateUnpackBytes(mContext, funcName, width, height, depth, pi, byteCount, + &blob)) + { return; + } TexOrSubImageBlob(isSubImage, funcName, target, level, internalFormat, xOffset, - yOffset, zOffset, pi, blob.get()); + yOffset, zOffset, pi, &blob); +} + +void +WebGLTexture::TexOrSubImage(bool isSubImage, const char* funcName, TexImageTarget target, + GLint level, GLenum internalFormat, GLint xOffset, + GLint yOffset, GLint zOffset, GLsizei rawWidth, + GLsizei rawHeight, GLsizei rawDepth, GLint border, + GLenum unpackFormat, GLenum unpackType, + WebGLsizeiptr offset) +{ + uint32_t width, height, depth; + if (!ValidateExtents(mContext, funcName, rawWidth, rawHeight, rawDepth, border, + &width, &height, &depth)) + { + return; + } + + const bool usePBOs = true; + webgl::PackingInfo pi; + if (!mContext->ValidateUnpackInfo(funcName, usePBOs, unpackFormat, unpackType, &pi)) + return; + + //// + + if (offset < 0) { + mContext->ErrorInvalidValue("%s: offset cannot be negative.", funcName); + return; + } + + const bool isClientData = false; + const auto ptr = (const void*)offset; + const webgl::TexUnpackBytes blob(mContext, target, width, height, depth, isClientData, + ptr); + + const auto& packBuffer = mContext->mBoundPixelUnpackBuffer; + const auto bufferByteCount = packBuffer->ByteLength(); + + uint32_t byteCount = 0; + if (bufferByteCount >= offset) { + byteCount = bufferByteCount - offset; + } + + if (!ValidateUnpackBytes(mContext, funcName, width, height, depth, pi, byteCount, + &blob)) + { + return; + } + + TexOrSubImageBlob(isSubImage, funcName, target, level, internalFormat, xOffset, + yOffset, zOffset, pi, &blob); } //////////////////////////////////////// @@ -319,8 +368,9 @@ WebGLTexture::TexOrSubImage(bool isSubImage, const char* funcName, TexImageTarge GLint yOffset, GLint zOffset, GLenum unpackFormat, GLenum unpackType, dom::ImageData* imageData) { + const bool usePBOs = false; webgl::PackingInfo pi; - if (!mContext->ValidateUnpackInfo(funcName, unpackFormat, unpackType, &pi)) + if (!mContext->ValidateUnpackInfo(funcName, usePBOs, unpackFormat, unpackType, &pi)) return; if (!imageData) { @@ -368,8 +418,9 @@ WebGLTexture::TexOrSubImage(bool isSubImage, const char* funcName, TexImageTarge GLenum unpackType, dom::Element* elem, ErrorResult* const out_error) { + const bool usePBOs = false; webgl::PackingInfo pi; - if (!mContext->ValidateUnpackInfo(funcName, unpackFormat, unpackType, &pi)) + if (!mContext->ValidateUnpackInfo(funcName, usePBOs, unpackFormat, unpackType, &pi)) return; ////// @@ -415,7 +466,9 @@ WebGLTexture::TexOrSubImage(bool isSubImage, const char* funcName, TexImageTarge const uint32_t depth = 1; if (!layersImage && !dataSurf) { - const webgl::TexUnpackBytes blob(mContext, target, width, height, depth, nullptr); + const bool isClientData = true; + const webgl::TexUnpackBytes blob(mContext, target, width, height, depth, + isClientData, nullptr); TexOrSubImageBlob(isSubImage, funcName, target, level, internalFormat, xOffset, yOffset, zOffset, pi, &blob); return;