diff options
Diffstat (limited to '')
-rw-r--r-- | dom/canvas/CanvasRenderingContext2D.cpp | 95 |
1 files changed, 84 insertions, 11 deletions
diff --git a/dom/canvas/CanvasRenderingContext2D.cpp b/dom/canvas/CanvasRenderingContext2D.cpp index 62f6e6443d..1a79a9f734 100644 --- a/dom/canvas/CanvasRenderingContext2D.cpp +++ b/dom/canvas/CanvasRenderingContext2D.cpp @@ -682,6 +682,8 @@ class AdjustedTarget { CompositionOp UsedOperation() const { return mUsedOperation; } + bool UseOptimizeShadow() const { return mOptimizeShadow; } + ShadowOptions ShadowParams() const { const ContextState& state = mCtx->CurrentState(); return ShadowOptions(ToDeviceColor(state.shadowColor), state.shadowOffset, @@ -5359,6 +5361,40 @@ static Matrix ComputeRotationMatrix(gfxFloat aRotatedWidth, .PostTranslate(shiftLeftTopToOrigin); } +static Maybe<layers::SurfaceDescriptor> +MaybeGetSurfaceDescriptorForRemoteCanvas( + const SurfaceFromElementResult& aResult) { + if (!StaticPrefs::gfx_canvas_remote_use_draw_image_fast_path()) { + return Nothing(); + } + + if (!aResult.mLayersImage) { + return Nothing(); + } + + Maybe<layers::SurfaceDescriptor> sd; + sd = aResult.mLayersImage->GetDesc(); + if (sd.isNothing() || + sd.ref().type() != + layers::SurfaceDescriptor::TSurfaceDescriptorGPUVideo) { + return Nothing(); + } + + const auto& sdv = sd.ref().get_SurfaceDescriptorGPUVideo(); + const auto& sdvType = sdv.type(); + if (sdvType == + layers::SurfaceDescriptorGPUVideo::TSurfaceDescriptorRemoteDecoder) { + const auto& sdrd = sdv.get_SurfaceDescriptorRemoteDecoder(); + const auto& subdesc = sdrd.subdesc(); + const auto& subdescType = subdesc.type(); + if (subdescType == layers::RemoteDecoderVideoSubDescriptor::Tnull_t) { + return sd; + } + } + + return Nothing(); +} + // drawImage(in HTMLImageElement image, in float dx, in float dy); // -- render image from 0,0 at dx,dy top-left coords // drawImage(in HTMLImageElement image, in float dx, in float dy, in float dw, @@ -5470,6 +5506,8 @@ void CanvasRenderingContext2D::DrawImage(const CanvasImageSource& aImage, } DirectDrawInfo drawInfo; + Maybe<layers::SurfaceDescriptor> surfaceDescriptor; + SurfaceFromElementResult res; if (!srcSurf) { // The canvas spec says that drawImage should draw the first frame @@ -5478,7 +5516,6 @@ void CanvasRenderingContext2D::DrawImage(const CanvasImageSource& aImage, nsLayoutUtils::SFE_NO_RASTERIZING_VECTORS | nsLayoutUtils::SFE_ALLOW_UNCROPPED_UNSCALED; - SurfaceFromElementResult res; if (offscreenCanvas) { res = nsLayoutUtils::SurfaceFromOffscreenCanvas(offscreenCanvas, sfeFlags, mTarget); @@ -5487,12 +5524,34 @@ void CanvasRenderingContext2D::DrawImage(const CanvasImageSource& aImage, } else { res = CanvasRenderingContext2D::CachedSurfaceFromElement(element); if (!res.mSourceSurface) { - res = nsLayoutUtils::SurfaceFromElement(element, sfeFlags, mTarget); + HTMLVideoElement* video = HTMLVideoElement::FromNodeOrNull(element); + if (video && mBufferProvider->IsAccelerated() && + mTarget->IsRecording() && + !(!NeedToApplyFilter() && NeedToDrawShadow())) { + res = nsLayoutUtils::SurfaceFromElement( + video, sfeFlags, mTarget, /* aOptimizeSourceSurface */ false); + surfaceDescriptor = MaybeGetSurfaceDescriptorForRemoteCanvas(res); + if (surfaceDescriptor.isNothing() && res.mLayersImage) { + if ((res.mSourceSurface = res.mLayersImage->GetAsSourceSurface())) { + RefPtr<SourceSurface> opt = + mTarget->OptimizeSourceSurface(res.mSourceSurface); + if (opt) { + res.mSourceSurface = opt; + } + } + } + } else { + res = nsLayoutUtils::SurfaceFromElement(element, sfeFlags, mTarget); + } } } - srcSurf = res.GetSourceSurface(); - if (!srcSurf && !res.mDrawInfo.mImgContainer) { + if (surfaceDescriptor.isNothing()) { + srcSurf = res.GetSourceSurface(); + } + + if (!srcSurf && surfaceDescriptor.isNothing() && + !res.mDrawInfo.mImgContainer) { // https://html.spec.whatwg.org/#check-the-usability-of-the-image-argument: // // Only throw if the request is broken and the element is an @@ -5612,10 +5671,10 @@ void CanvasRenderingContext2D::DrawImage(const CanvasImageSource& aImage, return; } - if (srcSurf) { + if (srcSurf || surfaceDescriptor.isSome()) { gfx::Rect sourceRect(aSx, aSy, aSw, aSh); - if ((element && element == mCanvasElement) || - (offscreenCanvas && offscreenCanvas == mOffscreenCanvas)) { + if (srcSurf && ((element && element == mCanvasElement) || + (offscreenCanvas && offscreenCanvas == mOffscreenCanvas))) { // srcSurf is a snapshot of mTarget. If we draw to mTarget now, we'll // trigger a COW copy of the whole canvas into srcSurf. That's a huge // waste if sourceRect doesn't cover the whole canvas. @@ -5656,10 +5715,24 @@ void CanvasRenderingContext2D::DrawImage(const CanvasImageSource& aImage, destRect.y = 0; } - tempTarget.DrawSurface( - srcSurf, destRect, sourceRect, - DrawSurfaceOptions(samplingFilter, SamplingBounds::UNBOUNDED), - DrawOptions(CurrentState().globalAlpha, op, antialiasMode)); + if (srcSurf) { + MOZ_ASSERT(surfaceDescriptor.isNothing()); + + tempTarget.DrawSurface( + srcSurf, destRect, sourceRect, + DrawSurfaceOptions(samplingFilter, SamplingBounds::UNBOUNDED), + DrawOptions(CurrentState().globalAlpha, op, antialiasMode)); + } else if (surfaceDescriptor.isSome()) { + MOZ_ASSERT(!tempTarget.UseOptimizeShadow()); + MOZ_ASSERT(res.mLayersImage); + + mTarget->DrawSurfaceDescriptor( + surfaceDescriptor.ref(), res.mLayersImage, destRect, sourceRect, + DrawSurfaceOptions(samplingFilter, SamplingBounds::UNBOUNDED), + DrawOptions(CurrentState().globalAlpha, op, antialiasMode)); + } else { + MOZ_ASSERT_UNREACHABLE("unexpected to be called"); + } if (rotationDeg != VideoRotation::kDegree_0) { tempTarget->SetTransform(currentTransform); |