static bool ClearDepthTexture(const WebGLContext& webgl, const GLuint tex, const TexImageTarget imageTarget, const uint32_t level, const webgl::FormatUsageInfo* const usage, const uint32_t depth) { // Depth resources actually clear to 1.0f, not 0.0f! // They are also always renderable. MOZ_ASSERT(usage->IsRenderable()); const auto& gl = webgl.gl; const auto& format = usage->format; GLenum attachPoint = LOCAL_GL_DEPTH_ATTACHMENT; GLbitfield clearBits = LOCAL_GL_DEPTH_BUFFER_BIT; if (format->s) { attachPoint = LOCAL_GL_DEPTH_STENCIL_ATTACHMENT; clearBits |= LOCAL_GL_STENCIL_BUFFER_BIT; } // - gl::ScopedFramebuffer scopedFB(gl); const gl::ScopedBindFramebuffer scopedBindFB(gl, scopedFB.FB()); const webgl::ScopedPrepForResourceClear scopedPrep(webgl); const auto fnAttach = [&](const uint32_t z) { switch (imageTarget.get()) { case LOCAL_GL_TEXTURE_3D: case LOCAL_GL_TEXTURE_2D_ARRAY: gl->fFramebufferTextureLayer(LOCAL_GL_FRAMEBUFFER, attachPoint, tex, level, z); break; default: if (attachPoint == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) { gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_DEPTH_ATTACHMENT, imageTarget.get(), tex, level); gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_STENCIL_ATTACHMENT, imageTarget.get(), tex, level); } else { gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, attachPoint, imageTarget.get(), tex, level); } break; } }; for (uint32_t z = 0; z < depth; ++z) { fnAttach(z); gl->fClear(clearBits); } const auto& status = gl->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER); const bool isComplete = (status == LOCAL_GL_FRAMEBUFFER_COMPLETE); MOZ_ASSERT(isComplete); return isComplete; }
static void ZeroANGLEDepthTexture(WebGLContext* webgl, GLuint tex, const webgl::FormatUsageInfo* usage, uint32_t width, uint32_t height) { const auto& format = usage->format; GLenum attachPoint = 0; GLbitfield clearBits = 0; if (format->d) { attachPoint = LOCAL_GL_DEPTH_ATTACHMENT; clearBits |= LOCAL_GL_DEPTH_BUFFER_BIT; } if (format->s) { attachPoint = (format->d ? LOCAL_GL_DEPTH_STENCIL_ATTACHMENT : LOCAL_GL_STENCIL_ATTACHMENT); clearBits |= LOCAL_GL_STENCIL_BUFFER_BIT; } MOZ_RELEASE_ASSERT(attachPoint && clearBits, "GFX: No bits cleared."); //// const auto& gl = webgl->gl; MOZ_ASSERT(gl->IsCurrent()); gl::ScopedFramebuffer scopedFB(gl); const gl::ScopedBindFramebuffer scopedBindFB(gl, scopedFB.FB()); gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, attachPoint, LOCAL_GL_TEXTURE_2D, tex, 0); const auto& status = gl->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER); MOZ_RELEASE_ASSERT(status == LOCAL_GL_FRAMEBUFFER_COMPLETE); //// const bool fakeNoAlpha = false; webgl->ForceClearFramebufferWithDefaultValues(clearBits, fakeNoAlpha); }
bool TexUnpackImage::TexOrSubImage(bool isSubImage, bool needsRespec, const char* funcName, WebGLTexture* tex, TexImageTarget target, GLint level, const webgl::DriverUnpackInfo* dui, GLint xOffset, GLint yOffset, GLint zOffset, const webgl::PackingInfo& pi, GLenum* const out_error) const { MOZ_ASSERT_IF(needsRespec, !isSubImage); WebGLContext* webgl = tex->mContext; gl::GLContext* gl = webgl->GL(); gl->MakeCurrent(); if (needsRespec) { *out_error = DoTexOrSubImage(isSubImage, gl, target.get(), level, dui, xOffset, yOffset, zOffset, mWidth, mHeight, mDepth, nullptr); if (*out_error) return true; } const char* fallbackReason; do { if (mDepth != 1) { fallbackReason = "depth is not 1"; break; } if (webgl->mPixelStore_UnpackSkipPixels || webgl->mPixelStore_UnpackSkipRows || webgl->mPixelStore_UnpackSkipImages) { fallbackReason = "non-zero UNPACK_SKIP_* not yet supported"; break; } const auto fnHasPremultMismatch = [&]() { if (mSrcAlphaType == gfxAlphaType::Opaque) return false; const bool srcIsPremult = (mSrcAlphaType == gfxAlphaType::Premult); const auto& dstIsPremult = webgl->mPixelStore_PremultiplyAlpha; if (srcIsPremult == dstIsPremult) return false; if (dstIsPremult) { fallbackReason = "UNPACK_PREMULTIPLY_ALPHA_WEBGL is not true"; } else { fallbackReason = "UNPACK_PREMULTIPLY_ALPHA_WEBGL is not false"; } return true; }; if (fnHasPremultMismatch()) break; if (dui->unpackFormat != LOCAL_GL_RGB && dui->unpackFormat != LOCAL_GL_RGBA) { fallbackReason = "`format` is not RGB or RGBA"; break; } if (dui->unpackType != LOCAL_GL_UNSIGNED_BYTE) { fallbackReason = "`type` is not UNSIGNED_BYTE"; break; } gl::ScopedFramebuffer scopedFB(gl); gl::ScopedBindFramebuffer bindFB(gl, scopedFB.FB()); { gl::GLContext::LocalErrorScope errorScope(*gl); gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_COLOR_ATTACHMENT0, target.get(), tex->mGLName, level); if (errorScope.GetError()) { fallbackReason = "bug: failed to attach to FB for blit"; break; } } const GLenum status = gl->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER); if (status != LOCAL_GL_FRAMEBUFFER_COMPLETE) { fallbackReason = "bug: failed to confirm FB for blit"; break; } const gfx::IntSize destSize(mWidth, mHeight); const auto dstOrigin = (webgl->mPixelStore_FlipY ? gl::OriginPos::TopLeft : gl::OriginPos::BottomLeft); if (!gl->BlitHelper()->BlitImageToFramebuffer(mImage, destSize, scopedFB.FB(), dstOrigin)) { fallbackReason = "likely bug: failed to blit"; break; } // Blitting was successful, so we're done! *out_error = 0; return true; } while (false); const nsPrintfCString perfMsg("%s: Failed to hit GPU-copy fast-path: %s (src type %u)", funcName, fallbackReason, uint32_t(mImage->GetFormat())); if (webgl->mPixelStore_RequireFastPath) { webgl->ErrorInvalidOperation("%s", perfMsg.BeginReading()); return false; } webgl->GeneratePerfWarning("%s Falling back to CPU upload.", perfMsg.BeginReading()); const RefPtr<gfx::SourceSurface> surf = mImage->GetAsSourceSurface(); RefPtr<gfx::DataSourceSurface> dataSurf; if (surf) { // WARNING: OSX can lose our MakeCurrent here. dataSurf = surf->GetDataSurface(); } if (!dataSurf) { webgl->ErrorOutOfMemory("%s: GetAsSourceSurface or GetDataSurface failed after" " blit failed for TexUnpackImage.", funcName); return false; } const TexUnpackSurface surfBlob(webgl, target, mWidth, mHeight, mDepth, dataSurf, mSrcAlphaType); return surfBlob.TexOrSubImage(isSubImage, needsRespec, funcName, tex, target, level, dui, xOffset, yOffset, zOffset, pi, out_error); }
bool TexUnpackImage::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 { MOZ_ASSERT_IF(needsRespec, !isSubImage); WebGLContext* webgl = tex->mContext; gl::GLContext* gl = webgl->GL(); gl->MakeCurrent(); if (needsRespec) { *out_error = DoTexOrSubImage(isSubImage, gl, target.get(), level, dui, xOffset, yOffset, zOffset, mWidth, mHeight, mDepth, nullptr); if (*out_error) return false; } do { if (mDepth != 1) break; const bool isDstPremult = webgl->mPixelStore_PremultiplyAlpha; if (mIsSrcPremult != isDstPremult) break; if (dui->unpackFormat != LOCAL_GL_RGB && dui->unpackFormat != LOCAL_GL_RGBA) break; if (dui->unpackType != LOCAL_GL_UNSIGNED_BYTE) break; gl::ScopedFramebuffer scopedFB(gl); gl::ScopedBindFramebuffer bindFB(gl, scopedFB.FB()); { gl::GLContext::LocalErrorScope errorScope(*gl); gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_COLOR_ATTACHMENT0, target.get(), tex->mGLName, level); if (errorScope.GetError()) break; } const GLenum status = gl->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER); if (status != LOCAL_GL_FRAMEBUFFER_COMPLETE) break; const gfx::IntSize destSize(mWidth, mHeight); const auto dstOrigin = (webgl->mPixelStore_FlipY ? gl::OriginPos::TopLeft : gl::OriginPos::BottomLeft); if (!gl->BlitHelper()->BlitImageToFramebuffer(mImage, destSize, scopedFB.FB(), dstOrigin)) { break; } // Blitting was successful, so we're done! *out_error = 0; return true; } while (false); webgl->GenerateWarning("%s: Failed to hit GPU-copy fast-path. Falling back to CPU" " upload.", funcName); const RefPtr<gfx::SourceSurface> surf = mImage->GetAsSourceSurface(); RefPtr<gfx::DataSourceSurface> dataSurf; if (surf) { // WARNING: OSX can lose our MakeCurrent here. dataSurf = surf->GetDataSurface(); } if (!dataSurf) { webgl->ErrorOutOfMemory("%s: GetAsSourceSurface or GetDataSurface failed after" " blit failed for TexUnpackImage.", funcName); return false; } const TexUnpackSurface surfBlob(webgl, target, mWidth, mHeight, mDepth, dataSurf, mIsSrcPremult); return surfBlob.TexOrSubImage(isSubImage, needsRespec, funcName, tex, target, level, dui, xOffset, yOffset, zOffset, out_error); }
void TexUnpackImage::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_glError) { MOZ_ASSERT_IF(needsRespec, !isSubImage); *out_glError = 0; WebGLContext* webgl = tex->mContext; gl::GLContext* gl = webgl->GL(); gl->MakeCurrent(); if (needsRespec) { GLenum error = DoTexOrSubImage(isSubImage, gl, target.get(), level, dui, xOffset, yOffset, zOffset, mWidth, mHeight, mDepth, nullptr); if (error) { MOZ_ASSERT(!error); *out_glError = LOCAL_GL_OUT_OF_MEMORY; return; } } do { if (dui->unpackFormat != LOCAL_GL_RGB && dui->unpackFormat != LOCAL_GL_RGBA) break; if (dui->unpackType != LOCAL_GL_UNSIGNED_BYTE) break; gl::ScopedFramebuffer scopedFB(gl); gl::ScopedBindFramebuffer bindFB(gl, scopedFB.FB()); { gl::GLContext::LocalErrorScope errorScope(*gl); gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_COLOR_ATTACHMENT0, target.get(), tex->mGLName, level); if (errorScope.GetError()) break; } const GLenum status = gl->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER); if (status != LOCAL_GL_FRAMEBUFFER_COMPLETE) break; gl::OriginPos srcOrigin, dstOrigin; OriginsForDOM(webgl, &srcOrigin, &dstOrigin); const gfx::IntSize destSize(mWidth, mHeight); if (!gl->BlitHelper()->BlitImageToFramebuffer(mImage, destSize, scopedFB.FB(), dstOrigin)) { break; } return; // Blitting was successful, so we're done! } while (false); TexUnpackSurface surfBlob(mImage->GetAsSourceSurface(), mIsAlphaPremult); surfBlob.TexOrSubImage(isSubImage, needsRespec, funcName, tex, target, level, dui, xOffset, yOffset, zOffset, out_glError); }