From 8dd16259287f58f9273002717ec4d27e97127719 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 12 Jun 2024 07:43:14 +0200 Subject: Merging upstream version 127.0. Signed-off-by: Daniel Baumann --- gfx/webrender_bindings/DCLayerTree.cpp | 47 ++++++++++-- gfx/webrender_bindings/DCLayerTree.h | 8 +- gfx/webrender_bindings/RenderCompositorANGLE.cpp | 19 ++--- gfx/webrender_bindings/RenderThread.cpp | 15 ++++ gfx/webrender_bindings/RenderThread.h | 5 ++ gfx/webrender_bindings/WebRenderAPI.cpp | 38 +++++---- gfx/webrender_bindings/WebRenderAPI.h | 3 +- gfx/webrender_bindings/WebRenderTypes.h | 7 ++ gfx/webrender_bindings/src/bindings.rs | 98 +++++++++++++++++++----- 9 files changed, 178 insertions(+), 62 deletions(-) (limited to 'gfx/webrender_bindings') diff --git a/gfx/webrender_bindings/DCLayerTree.cpp b/gfx/webrender_bindings/DCLayerTree.cpp index 49ca8ee77b..c867740ba5 100644 --- a/gfx/webrender_bindings/DCLayerTree.cpp +++ b/gfx/webrender_bindings/DCLayerTree.cpp @@ -751,9 +751,9 @@ DCSurface* DCExternalSurfaceWrapper::EnsureSurfaceForExternalImage( auto cprofileOut = mDCLayerTree->OutputColorProfile(); bool pretendSrgb = true; if (pretendSrgb) { - cprofileOut = color::ColorProfileDesc::From({ - color::Chromaticities::Srgb(), - color::PiecewiseGammaDesc::Srgb(), + cprofileOut = color::ColorProfileDesc::From(color::ColorspaceDesc{ + .chrom = color::Chromaticities::Srgb(), + .tf = color::PiecewiseGammaDesc::Srgb(), }); } const auto conversion = color::ColorProfileConversionDesc::From({ @@ -1355,7 +1355,7 @@ bool DCSurfaceVideo::CalculateSwapChainSize(gfx::Matrix& aTransform) { MOZ_ASSERT(mDCLayerTree->GetVideoProcessor()); const UINT vendorId = GetVendorId(mDCLayerTree->GetVideoDevice()); - const bool driverSupportsTrueHDR = + const bool driverSupportsAutoHDR = GetVpAutoHDRSupported(vendorId, mDCLayerTree->GetVideoContext(), mDCLayerTree->GetVideoProcessor()); const bool contentIsHDR = false; // XXX for now, only non-HDR is supported. @@ -1364,9 +1364,18 @@ bool DCSurfaceVideo::CalculateSwapChainSize(gfx::Matrix& aTransform) { const bool powerIsCharging = RenderThread::Get()->GetPowerIsCharging(); bool useVpAutoHDR = gfx::gfxVars::WebRenderOverlayVpAutoHDR() && - !contentIsHDR && monitorIsHDR && driverSupportsTrueHDR && + !contentIsHDR && monitorIsHDR && driverSupportsAutoHDR && powerIsCharging && !mVpAutoHDRFailed; + if (profiler_thread_is_being_profiled_for_markers()) { + nsPrintfCString str( + "useVpAutoHDR %d gfxVars %d contentIsHDR %d monitor %d driver %d " + "charging %d failed %d", + useVpAutoHDR, gfx::gfxVars::WebRenderOverlayVpAutoHDR(), contentIsHDR, + monitorIsHDR, driverSupportsAutoHDR, powerIsCharging, mVpAutoHDRFailed); + PROFILER_MARKER_TEXT("DCSurfaceVideo", GRAPHICS, {}, str); + } + if (!mVideoSwapChain || mSwapChainSize != swapChainSize || mIsDRM != isDRM || mUseVpAutoHDR != useVpAutoHDR) { needsToPresent = true; @@ -1791,8 +1800,22 @@ bool DCSurfaceVideo::CallVideoProcessorBlt() { const UINT vendorId = GetVendorId(videoDevice); const auto powerIsCharging = RenderThread::Get()->GetPowerIsCharging(); - if (gfx::gfxVars::WebRenderOverlayVpSuperResolution() && - !mVpSuperResolutionFailed && powerIsCharging) { + const bool useSuperResolution = + gfx::gfxVars::WebRenderOverlayVpSuperResolution() && powerIsCharging && + !mVpSuperResolutionFailed; + + if (profiler_thread_is_being_profiled_for_markers()) { + nsPrintfCString str( + "useSuperResolution %d gfxVars %d charging %d failed %d", + useSuperResolution, gfx::gfxVars::WebRenderOverlayVpSuperResolution(), + powerIsCharging, mVpSuperResolutionFailed); + PROFILER_MARKER_TEXT("DCSurfaceVideo", GRAPHICS, {}, str); + } + + if (useSuperResolution) { + PROFILER_MARKER_TEXT("DCSurfaceVideo", GRAPHICS, {}, + "SetVpSuperResolution"_ns); + hr = SetVpSuperResolution(vendorId, videoContext, videoProcessor, true); if (FAILED(hr)) { if (hr != E_NOTIMPL) { @@ -1803,6 +1826,8 @@ bool DCSurfaceVideo::CallVideoProcessorBlt() { } if (mUseVpAutoHDR) { + PROFILER_MARKER_TEXT("DCSurfaceVideo", GRAPHICS, {}, "SetVpAutoHDR"_ns); + hr = SetVpAutoHDR(vendorId, videoContext, videoProcessor, true); if (FAILED(hr)) { gfxCriticalNoteOnce << "SetVpAutoHDR failed: " << gfx::hexa(hr); @@ -2072,7 +2097,10 @@ void DCLayerTree::DestroyEGLSurface() { // - -color::ColorProfileDesc DCLayerTree::QueryOutputColorProfile() { +} // namespace wr +namespace gfx { + +color::ColorProfileDesc QueryOutputColorProfile() { // GPU process can't simply init gfxPlatform, (and we don't need most of it) // but we do need gfxPlatform::GetCMSOutputProfile(). // So we steal what we need through the window: @@ -2126,6 +2154,9 @@ color::ColorProfileDesc DCLayerTree::QueryOutputColorProfile() { return ret; } +} // namespace gfx +namespace wr { + inline D2D1_MATRIX_5X4_F to_D2D1_MATRIX_5X4_F(const color::mat4& m) { return D2D1_MATRIX_5X4_F{{{ m.rows[0][0], diff --git a/gfx/webrender_bindings/DCLayerTree.h b/gfx/webrender_bindings/DCLayerTree.h index d5ade5781e..8289eaf50d 100644 --- a/gfx/webrender_bindings/DCLayerTree.h +++ b/gfx/webrender_bindings/DCLayerTree.h @@ -44,6 +44,10 @@ struct IDCompositionVirtualSurface; namespace mozilla { +namespace gfx { +color::ColorProfileDesc QueryOutputColorProfile(); +} + namespace gl { class GLContext; } @@ -248,8 +252,6 @@ class DCLayerTree { bool mPendingCommit; - static color::ColorProfileDesc QueryOutputColorProfile(); - mutable Maybe mOutputColorProfile; DCompOverlayTypes mUsedOverlayTypesInFrame = DCompOverlayTypes::NO_OVERLAY; @@ -258,7 +260,7 @@ class DCLayerTree { public: const color::ColorProfileDesc& OutputColorProfile() const { if (!mOutputColorProfile) { - mOutputColorProfile = Some(QueryOutputColorProfile()); + mOutputColorProfile = Some(gfx::QueryOutputColorProfile()); } return *mOutputColorProfile; } diff --git a/gfx/webrender_bindings/RenderCompositorANGLE.cpp b/gfx/webrender_bindings/RenderCompositorANGLE.cpp index e01ac6a187..ec102074cb 100644 --- a/gfx/webrender_bindings/RenderCompositorANGLE.cpp +++ b/gfx/webrender_bindings/RenderCompositorANGLE.cpp @@ -36,8 +36,7 @@ #undef PW_RENDERFULLCONTENT #define PW_RENDERFULLCONTENT 0x00000002 -namespace mozilla { -namespace wr { +namespace mozilla::wr { extern LazyLogModule gRenderThreadLog; #define LOG(...) MOZ_LOG(gRenderThreadLog, LogLevel::Debug, (__VA_ARGS__)) @@ -440,11 +439,9 @@ RenderedFrameId RenderCompositorANGLE::EndFrame( if (!UseCompositor()) { auto start = TimeStamp::Now(); - if (mWidget->AsWindows()->HasFxrOutputHandler()) { + if (auto* fxrHandler = mWidget->AsWindows()->GetFxrOutputHandler()) { // There is a Firefox Reality handler for this swapchain. Update this // window's contents to the VR window. - FxROutputHandler* fxrHandler = - mWidget->AsWindows()->GetFxrOutputHandler(); if (fxrHandler->TryInitialize(mSwapChain, mDevice)) { fxrHandler->UpdateOutput(mCtx); } @@ -926,12 +923,9 @@ void RenderCompositorANGLE::InitializeUsePartialPresent() { // Even when mSwapChain1 is null, we could enable WR partial present, since // when mSwapChain1 is null, SwapChain is blit model swap chain with one // buffer. - if (UseCompositor() || mWidget->AsWindows()->HasFxrOutputHandler() || - gfx::gfxVars::WebRenderMaxPartialPresentRects() <= 0) { - mUsePartialPresent = false; - } else { - mUsePartialPresent = true; - } + mUsePartialPresent = !UseCompositor() && + !mWidget->AsWindows()->HasFxrOutputHandler() && + gfx::gfxVars::WebRenderMaxPartialPresentRects() > 0; } bool RenderCompositorANGLE::UsePartialPresent() { return mUsePartialPresent; } @@ -1021,5 +1015,4 @@ bool RenderCompositorANGLE::MaybeReadback( return true; } -} // namespace wr -} // namespace mozilla +} // namespace mozilla::wr diff --git a/gfx/webrender_bindings/RenderThread.cpp b/gfx/webrender_bindings/RenderThread.cpp index e1a41ee225..cb496c8fc5 100644 --- a/gfx/webrender_bindings/RenderThread.cpp +++ b/gfx/webrender_bindings/RenderThread.cpp @@ -979,6 +979,21 @@ void RenderThread::RegisterExternalImage( mSyncObjectNeededRenderTextures.emplace(aExternalImageId, texture); } mRenderTextures.emplace(aExternalImageId, texture); + +#ifdef DEBUG + int32_t maxAllowedIncrease = + StaticPrefs::gfx_testing_assert_render_textures_increase(); + + if (maxAllowedIncrease <= 0) { + mRenderTexturesLastTime = -1; + } else { + if (mRenderTexturesLastTime < 0) { + mRenderTexturesLastTime = static_cast(mRenderTextures.size()); + } + MOZ_ASSERT((static_cast(mRenderTextures.size()) - + mRenderTexturesLastTime) < maxAllowedIncrease); + } +#endif } void RenderThread::UnregisterExternalImage( diff --git a/gfx/webrender_bindings/RenderThread.h b/gfx/webrender_bindings/RenderThread.h index f9ab1e742e..6191a28bcd 100644 --- a/gfx/webrender_bindings/RenderThread.h +++ b/gfx/webrender_bindings/RenderThread.h @@ -489,6 +489,11 @@ class RenderThread final { RefPtr mRenderTextureOpsRunnable MOZ_GUARDED_BY(mRenderTextureMapLock); +#ifdef DEBUG + // used for tests only to ensure render textures don't increase + int32_t mRenderTexturesLastTime MOZ_GUARDED_BY(mRenderTextureMapLock) = -1; +#endif + // Set from MainThread, read from either MainThread or RenderThread bool mHasShutdown; diff --git a/gfx/webrender_bindings/WebRenderAPI.cpp b/gfx/webrender_bindings/WebRenderAPI.cpp index 09a024a897..105c2dff98 100644 --- a/gfx/webrender_bindings/WebRenderAPI.cpp +++ b/gfx/webrender_bindings/WebRenderAPI.cpp @@ -537,7 +537,25 @@ bool WebRenderAPI::CheckIsRemoteTextureReady( layers::CompositorThread()->Dispatch(runnable.forget()); }; + bool isReady = true; + while (!aList->mList.empty() && isReady) { + auto& front = aList->mList.front(); + isReady &= layers::RemoteTextureMap::Get()->CheckRemoteTextureReady( + front, callback); + if (isReady) { + aList->mList.pop(); + } + } + + if (isReady) { + return true; + } + +#ifndef DEBUG const auto maxWaitDurationMs = 10000; +#else + const auto maxWaitDurationMs = 30000; +#endif const auto now = TimeStamp::Now(); const auto waitDurationMs = static_cast((now - aTimeStamp).ToMilliseconds()); @@ -548,20 +566,7 @@ bool WebRenderAPI::CheckIsRemoteTextureReady( gfxCriticalNote << "RemoteTexture ready timeout"; } - bool isReady = true; - while (!aList->mList.empty() && isReady) { - auto& front = aList->mList.front(); - isReady &= layers::RemoteTextureMap::Get()->CheckRemoteTextureReady( - front, callback); - if (isTimeout) { - isReady = true; - } - if (isReady) { - aList->mList.pop(); - } - } - - return isReady; + return false; } void WebRenderAPI::WaitRemoteTextureReady( @@ -1256,11 +1261,12 @@ wr::WrSpatialId DisplayListBuilder::DefineStickyFrame( const float* aRightMargin, const float* aBottomMargin, const float* aLeftMargin, const StickyOffsetBounds& aVerticalBounds, const StickyOffsetBounds& aHorizontalBounds, - const wr::LayoutVector2D& aAppliedOffset, wr::SpatialTreeItemKey aKey) { + const wr::LayoutVector2D& aAppliedOffset, wr::SpatialTreeItemKey aKey, + const WrAnimationProperty* aAnimation) { auto spatialId = wr_dp_define_sticky_frame( mWrState, mCurrentSpaceAndClipChain.space, aContentRect, aTopMargin, aRightMargin, aBottomMargin, aLeftMargin, aVerticalBounds, - aHorizontalBounds, aAppliedOffset, aKey); + aHorizontalBounds, aAppliedOffset, aKey, aAnimation); WRDL_LOG("DefineSticky id=%zu c=%s t=%s r=%s b=%s l=%s v=%s h=%s a=%s\n", mWrState, spatialId.id, ToString(aContentRect).c_str(), diff --git a/gfx/webrender_bindings/WebRenderAPI.h b/gfx/webrender_bindings/WebRenderAPI.h index 16a9acc0ab..eff7b3039a 100644 --- a/gfx/webrender_bindings/WebRenderAPI.h +++ b/gfx/webrender_bindings/WebRenderAPI.h @@ -600,7 +600,8 @@ class DisplayListBuilder final { const float* aRightMargin, const float* aBottomMargin, const float* aLeftMargin, const StickyOffsetBounds& aVerticalBounds, const StickyOffsetBounds& aHorizontalBounds, - const wr::LayoutVector2D& aAppliedOffset, wr::SpatialTreeItemKey aKey); + const wr::LayoutVector2D& aAppliedOffset, wr::SpatialTreeItemKey aKey, + const WrAnimationProperty* aAnimation); Maybe GetScrollIdForDefinedScrollLayer( layers::ScrollableLayerGuid::ViewID aViewId) const; diff --git a/gfx/webrender_bindings/WebRenderTypes.h b/gfx/webrender_bindings/WebRenderTypes.h index 3216a0afd6..84c9d5cf63 100644 --- a/gfx/webrender_bindings/WebRenderTypes.h +++ b/gfx/webrender_bindings/WebRenderTypes.h @@ -667,6 +667,13 @@ struct Vec final { } void SetEmpty() { + // We need to ensure that (data, capacity, length) always remain valid + // to be passed to Vec::from_raw_parts. In particular, this requires that + // inner.data is always non-null, even for zero-capacity Vecs. + + // Set inner.data to the equivalent of ptr::NonNull::dangling().as_ptr(), + // i.e. a non-null value that is aligned with T's alignment, T being u8 + // here. inner.data = (uint8_t*)1; inner.capacity = 0; inner.length = 0; diff --git a/gfx/webrender_bindings/src/bindings.rs b/gfx/webrender_bindings/src/bindings.rs index 3fc93fdf13..579453a165 100644 --- a/gfx/webrender_bindings/src/bindings.rs +++ b/gfx/webrender_bindings/src/bindings.rs @@ -36,11 +36,11 @@ use tracy_rs::register_thread_with_profiler; use webrender::sw_compositor::SwCompositor; use webrender::{ api::units::*, api::*, create_webrender_instance, render_api::*, set_profiler_hooks, AsyncPropertySampler, - AsyncScreenshotHandle, Compositor, CompositorCapabilities, CompositorConfig, CompositorSurfaceTransform, - Device, MappableCompositor, MappedTileInfo, NativeSurfaceId, NativeSurfaceInfo, NativeTileId, - PartialPresentCompositor, PipelineInfo, ProfilerHooks, RecordedFrameHandle, Renderer, RendererStats, - SWGLCompositeSurfaceInfo, SceneBuilderHooks, ShaderPrecacheFlags, Shaders, SharedShaders, TextureCacheConfig, - UploadMethod, WebRenderOptions, WindowVisibility, ONE_TIME_USAGE_HINT, + AsyncScreenshotHandle, Compositor, CompositorCapabilities, CompositorConfig, CompositorSurfaceTransform, Device, + MappableCompositor, MappedTileInfo, NativeSurfaceId, NativeSurfaceInfo, NativeTileId, PartialPresentCompositor, + PipelineInfo, ProfilerHooks, RecordedFrameHandle, Renderer, RendererStats, SWGLCompositeSurfaceInfo, + SceneBuilderHooks, ShaderPrecacheFlags, Shaders, SharedShaders, TextureCacheConfig, UploadMethod, WebRenderOptions, + WindowVisibility, ONE_TIME_USAGE_HINT, }; use wr_malloc_size_of::MallocSizeOfOps; @@ -212,36 +212,68 @@ impl DocumentHandle { #[repr(C)] pub struct WrVecU8 { + /// `data` must always be valid for passing to Vec::from_raw_parts. + /// In particular, it must be non-null even if capacity is zero. data: *mut u8, length: usize, capacity: usize, } impl WrVecU8 { - fn into_vec(self) -> Vec { - unsafe { Vec::from_raw_parts(self.data, self.length, self.capacity) } + fn into_vec(mut self) -> Vec { + // Clear self and then drop self. + self.flush_into_vec() } - // Equivalent to `into_vec` but clears self instead of consuming the value. + // Clears self without consuming self. fn flush_into_vec(&mut self) -> Vec { - self.convert_into_vec::() - } - - // Like flush_into_vec, but also does an unsafe conversion to the desired type. - fn convert_into_vec(&mut self) -> Vec { + // Create a Vec using Vec::from_raw_parts. + // + // Here are the safety requirements, verbatim from the documentation of `from_raw_parts`: + // + // > * `ptr` must have been allocated using the global allocator, such as via + // > the [`alloc::alloc`] function. + // > * `T` needs to have the same alignment as what `ptr` was allocated with. + // > (`T` having a less strict alignment is not sufficient, the alignment really + // > needs to be equal to satisfy the [`dealloc`] requirement that memory must be + // > allocated and deallocated with the same layout.) + // > * The size of `T` times the `capacity` (ie. the allocated size in bytes) needs + // > to be the same size as the pointer was allocated with. (Because similar to + // > alignment, [`dealloc`] must be called with the same layout `size`.) + // > * `length` needs to be less than or equal to `capacity`. + // > * The first `length` values must be properly initialized values of type `T`. + // > * `capacity` needs to be the capacity that the pointer was allocated with. + // > * The allocated size in bytes must be no larger than `isize::MAX`. + // > See the safety documentation of [`pointer::offset`]. + // + // These comments don't say what to do for zero-capacity vecs which don't have + // an allocation. In particular, the requirement "`ptr` must have been allocated" + // is not met for such vecs. + // + // However, the safety requirements of `slice::from_raw_parts` are more explicit + // about the empty case: + // + // > * `data` must be non-null and aligned even for zero-length slices. One + // > reason for this is that enum layout optimizations may rely on references + // > (including slices of any length) being aligned and non-null to distinguish + // > them from other data. You can obtain a pointer that is usable as `data` + // > for zero-length slices using [`NonNull::dangling()`]. + // + // For the empty case we follow this requirement rather than the more stringent + // requirement from the `Vec::from_raw_parts` docs. let vec = unsafe { - Vec::from_raw_parts( - self.data as *mut T, - self.length / mem::size_of::(), - self.capacity / mem::size_of::(), - ) + Vec::from_raw_parts(self.data, self.length, self.capacity) }; - self.data = ptr::null_mut(); + self.data = ptr::NonNull::dangling().as_ptr(); self.length = 0; self.capacity = 0; vec } + pub fn as_slice(&self) -> &[u8] { + unsafe { core::slice::from_raw_parts(self.data, self.length) } + } + fn from_vec(mut v: Vec) -> WrVecU8 { let w = WrVecU8 { data: v.as_mut_ptr(), @@ -2317,7 +2349,8 @@ pub extern "C" fn wr_api_stop_capture_sequence(dh: &mut DocumentHandle) { #[cfg(target_os = "windows")] fn read_font_descriptor(bytes: &mut WrVecU8, index: u32) -> NativeFontHandle { - let wchars = bytes.convert_into_vec::(); + let wchars: Vec = + bytes.as_slice().chunks_exact(2).map(|c| u16::from_ne_bytes([c[0], c[1]])).collect(); NativeFontHandle { path: PathBuf::from(OsString::from_wide(&wchars)), index, @@ -2373,13 +2406,24 @@ pub extern "C" fn wr_resource_updates_add_font_instance( platform_options: *const FontInstancePlatformOptions, variations: &mut WrVecU8, ) { + // Deserialize a sequence of FontVariation objects from the raw bytes. + // Every FontVariation is 8 bytes: one u32 and one f32. + // The code below would look better with slice::chunk_arrays: + // https://github.com/rust-lang/rust/issues/74985 + let variations: Vec = + variations.as_slice().chunks_exact(8).map(|c| { + assert_eq!(c.len(), 8); + let tag = u32::from_ne_bytes([c[0], c[1], c[2], c[3]]); + let value = f32::from_ne_bytes([c[4], c[5], c[6], c[7]]); + FontVariation { tag, value } + }).collect(); txn.add_font_instance( key, font_key, glyph_size, unsafe { options.as_ref().cloned() }, unsafe { platform_options.as_ref().cloned() }, - variations.convert_into_vec::(), + variations, ); } @@ -2756,8 +2800,19 @@ pub extern "C" fn wr_dp_define_sticky_frame( horizontal_bounds: StickyOffsetBounds, applied_offset: LayoutVector2D, key: SpatialTreeItemKey, + animation: *const WrAnimationProperty ) -> WrSpatialId { assert!(unsafe { is_in_main_thread() }); + let anim = unsafe { animation.as_ref() }; + let transform = anim.map(|anim| { + debug_assert!(anim.id > 0); + match anim.effect_type { + WrAnimationType::Transform => { + PropertyBinding::Binding(PropertyBindingKey::new(anim.id), LayoutTransform::identity()) + }, + _ => unreachable!("sticky elements can only have a transform animated") + } + }); let spatial_id = state.frame_builder.dl_builder.define_sticky_frame( parent_spatial_id.to_webrender(state.pipeline_id), content_rect, @@ -2771,6 +2826,7 @@ pub extern "C" fn wr_dp_define_sticky_frame( horizontal_bounds, applied_offset, key, + transform ); WrSpatialId { id: spatial_id.0 } -- cgit v1.2.3