Bug 1653166 - Add transforms to WebRender Compositor API. r=gw,mstange,sotaro

Differential Revision: https://phabricator.services.mozilla.com/D84328
This commit is contained in:
Matt Woodrow 2020-08-04 01:19:59 +00:00
Родитель 72cda2d18d
Коммит 01b5738a5d
18 изменённых файлов: 268 добавлений и 105 удалений

Просмотреть файл

@ -115,13 +115,20 @@ class NativeLayer {
virtual bool IsOpaque() = 0;
// The location of the layer, in integer device pixels.
// This is applied to the layer, before the transform is applied.
virtual void SetPosition(const gfx::IntPoint& aPosition) = 0;
virtual gfx::IntPoint GetPosition() = 0;
// Sets a transformation to apply to the Layer. This gets applied to
// coordinates with the position applied, but before clipping is
// applied.
virtual void SetTransform(const gfx::Matrix4x4& aTransform) = 0;
virtual gfx::Matrix4x4 GetTransform() = 0;
virtual gfx::IntRect GetRect() = 0;
// Set an optional clip rect on the layer. The clip rect is in the same
// coordinate space as the layer rect.
// Set an optional clip rect on the layer. The clip rect is in post-transform
// coordinate space
virtual void SetClipRect(const Maybe<gfx::IntRect>& aClipRect) = 0;
virtual Maybe<gfx::IntRect> ClipRect() = 0;

Просмотреть файл

@ -185,6 +185,8 @@ class NativeLayerCA : public NativeLayer {
gfx::IntSize GetSize() override;
void SetPosition(const gfx::IntPoint& aPosition) override;
gfx::IntPoint GetPosition() override;
void SetTransform(const gfx::Matrix4x4& aTransform) override;
gfx::Matrix4x4 GetTransform() override;
gfx::IntRect GetRect() override;
RefPtr<gfx::DrawTarget> NextSurfaceAsDrawTarget(
const gfx::IntRect& aDisplayRect, const gfx::IntRegion& aUpdateRegion,
@ -269,6 +271,7 @@ class NativeLayerCA : public NativeLayer {
// before the call.
void ApplyChanges(const gfx::IntSize& aSize, bool aIsOpaque,
const gfx::IntPoint& aPosition,
const gfx::Matrix4x4& aTransform,
const gfx::IntRect& aDisplayRect,
const Maybe<gfx::IntRect>& aClipRect, float aBackingScale,
bool aSurfaceIsFlipped,
@ -284,6 +287,7 @@ class NativeLayerCA : public NativeLayer {
CALayer* mOpaquenessTintLayer = nullptr; // strong
bool mMutatedPosition = true;
bool mMutatedTransform = true;
bool mMutatedDisplayRect = true;
bool mMutatedClipRect = true;
bool mMutatedBackingScale = true;
@ -352,6 +356,7 @@ class NativeLayerCA : public NativeLayer {
Representation mOffscreenRepresentation;
gfx::IntPoint mPosition;
gfx::Matrix4x4 mTransform;
gfx::IntRect mDisplayRect;
const gfx::IntSize mSize;
Maybe<gfx::IntRect> mClipRect;

Просмотреть файл

@ -32,6 +32,7 @@ using gfx::IntPoint;
using gfx::IntSize;
using gfx::IntRect;
using gfx::IntRegion;
using gfx::Matrix4x4;
using gfx::SurfaceFormat;
using gl::GLContext;
using gl::GLContextCGL;
@ -427,6 +428,21 @@ IntPoint NativeLayerCA::GetPosition() {
return mPosition;
}
void NativeLayerCA::SetTransform(const Matrix4x4& aTransform) {
MutexAutoLock lock(mMutex);
MOZ_ASSERT(aTransform.IsRectilinear());
if (aTransform != mTransform) {
mTransform = aTransform;
ForAllRepresentations([&](Representation& r) { r.mMutatedTransform = true; });
}
}
Matrix4x4 NativeLayerCA::GetTransform() {
MutexAutoLock lock(mMutex);
return mTransform;
}
IntRect NativeLayerCA::GetRect() {
MutexAutoLock lock(mMutex);
return IntRect(mPosition, mSize);
@ -671,7 +687,7 @@ void NativeLayerCA::ForAllRepresentations(F aFn) {
void NativeLayerCA::ApplyChanges(WhichRepresentation aRepresentation) {
MutexAutoLock lock(mMutex);
GetRepresentation(aRepresentation)
.ApplyChanges(mSize, mIsOpaque, mPosition, mDisplayRect, mClipRect, mBackingScale,
.ApplyChanges(mSize, mIsOpaque, mPosition, mTransform, mDisplayRect, mClipRect, mBackingScale,
mSurfaceIsFlipped, mFrontSurface ? mFrontSurface->mSurface : nullptr);
}
@ -680,12 +696,10 @@ CALayer* NativeLayerCA::UnderlyingCALayer(WhichRepresentation aRepresentation) {
return GetRepresentation(aRepresentation).UnderlyingCALayer();
}
void NativeLayerCA::Representation::ApplyChanges(const IntSize& aSize, bool aIsOpaque,
const IntPoint& aPosition,
const IntRect& aDisplayRect,
const Maybe<IntRect>& aClipRect,
float aBackingScale, bool aSurfaceIsFlipped,
CFTypeRefPtr<IOSurfaceRef> aFrontSurface) {
void NativeLayerCA::Representation::ApplyChanges(
const IntSize& aSize, bool aIsOpaque, const IntPoint& aPosition, const Matrix4x4& aTransform,
const IntRect& aDisplayRect, const Maybe<IntRect>& aClipRect, float aBackingScale,
bool aSurfaceIsFlipped, CFTypeRefPtr<IOSurfaceRef> aFrontSurface) {
if (!mWrappingCALayer) {
mWrappingCALayer = [[CALayer layer] retain];
mWrappingCALayer.position = NSZeroPoint;
@ -747,17 +761,26 @@ void NativeLayerCA::Representation::ApplyChanges(const IntSize& aSize, bool aIsO
mContentCALayer.contentsScale = aBackingScale;
}
if (mMutatedBackingScale || mMutatedPosition || mMutatedDisplayRect || mMutatedClipRect) {
auto clipFromDisplayRect = aDisplayRect.IsEqualInterior(IntRect({}, aSize))
? Nothing()
: Some(aDisplayRect + aPosition);
if (mMutatedBackingScale || mMutatedPosition || mMutatedDisplayRect || mMutatedClipRect ||
mMutatedTransform || mMutatedSurfaceIsFlipped) {
Maybe<IntRect> clipFromDisplayRect;
if (!aDisplayRect.IsEqualInterior(IntRect({}, aSize))) {
// When the display rect is a subset of the layer, then we want to guarantee that no
// pixels outside that rect are sampled, since they might be uninitialized.
// Transforming the display rect into a post-transform clip only maintains this if
// it's an integer translation, which is all we support for this case currently.
MOZ_ASSERT(aTransform.Is2DIntegerTranslation());
clipFromDisplayRect =
Some(RoundedToInt(aTransform.TransformBounds(IntRectToRect(aDisplayRect + aPosition))));
}
auto effectiveClip = IntersectMaybeRects(aClipRect, clipFromDisplayRect);
auto globalClipOrigin = effectiveClip ? effectiveClip->TopLeft() : aPosition;
auto globalLayerOrigin = aPosition;
auto clipToLayerOffset = globalLayerOrigin - globalClipOrigin;
auto globalClipOrigin = effectiveClip ? effectiveClip->TopLeft() : IntPoint();
auto clipToLayerOffset = -globalClipOrigin;
mWrappingCALayer.position =
CGPointMake(globalClipOrigin.x / aBackingScale, globalClipOrigin.y / aBackingScale);
if (effectiveClip) {
mWrappingCALayer.masksToBounds = YES;
mWrappingCALayer.bounds = CGRectMake(0, 0, effectiveClip->Width() / aBackingScale,
@ -767,18 +790,36 @@ void NativeLayerCA::Representation::ApplyChanges(const IntSize& aSize, bool aIsO
}
mContentCALayer.position =
CGPointMake(clipToLayerOffset.x / aBackingScale, clipToLayerOffset.y / aBackingScale);
mContentCALayer.position = CGPointMake(0, 0);
if (mOpaquenessTintLayer) {
mOpaquenessTintLayer.position = mContentCALayer.position;
}
}
if (mMutatedBackingScale || mMutatedSurfaceIsFlipped) {
Matrix4x4 transform = aTransform;
transform.PreTranslate(aPosition.x, aPosition.y, 0);
transform.PostTranslate(clipToLayerOffset.x, clipToLayerOffset.y, 0);
if (aSurfaceIsFlipped) {
CGFloat height = aSize.height / aBackingScale;
mContentCALayer.affineTransform = CGAffineTransformMake(1.0, 0.0, 0.0, -1.0, 0.0, height);
} else {
mContentCALayer.affineTransform = CGAffineTransformIdentity;
transform.PreTranslate(0, aSize.height, 0).PreScale(1, -1, 1);
}
CATransform3D transformCA{transform._11,
transform._12,
transform._13,
transform._14,
transform._21,
transform._22,
transform._23,
transform._24,
transform._31,
transform._32,
transform._33,
transform._34,
transform._41 / aBackingScale,
transform._42 / aBackingScale,
transform._43,
transform._44};
mContentCALayer.transform = transformCA;
}
if (mMutatedFrontSurface) {
@ -786,6 +827,7 @@ void NativeLayerCA::Representation::ApplyChanges(const IntSize& aSize, bool aIsO
}
mMutatedPosition = false;
mMutatedTransform = false;
mMutatedBackingScale = false;
mMutatedSurfaceIsFlipped = false;
mMutatedDisplayRect = false;

Просмотреть файл

@ -335,8 +335,18 @@ void DCLayerTree::DestroyTile(wr::NativeSurfaceId aId, int aX, int aY) {
surface->DestroyTile(aX, aY);
}
template <typename T>
static inline D2D1_RECT_F D2DRect(const T& aRect) {
return D2D1::RectF(aRect.X(), aRect.Y(), aRect.XMost(), aRect.YMost());
}
static inline D2D1_MATRIX_3X2_F D2DMatrix(const gfx::Matrix& aTransform) {
return D2D1::Matrix3x2F(aTransform._11, aTransform._12, aTransform._21,
aTransform._22, aTransform._31, aTransform._32);
}
void DCLayerTree::AddSurface(wr::NativeSurfaceId aId,
wr::DeviceIntPoint aPosition,
const wr::CompositorSurfaceTransform& aTransform,
wr::DeviceIntRect aClipRect) {
auto it = mDCSurfaces.find(aId);
MOZ_RELEASE_ASSERT(it != mDCSurfaces.end());
@ -344,22 +354,33 @@ void DCLayerTree::AddSurface(wr::NativeSurfaceId aId,
const auto visual = surface->GetVisual();
wr::DeviceIntPoint virtualOffset = surface->GetVirtualOffset();
aPosition.x -= virtualOffset.x;
aPosition.y -= virtualOffset.y;
// Place the visual - this changes frame to frame based on scroll position
// of the slice.
visual->SetOffsetX(aPosition.x);
visual->SetOffsetY(aPosition.y);
gfx::Matrix transform(aTransform.m11, aTransform.m12, aTransform.m21,
aTransform.m22, aTransform.m41, aTransform.m42);
transform.PreTranslate(-virtualOffset.x, -virtualOffset.y);
// The DirectComposition API applies clipping *before* any transforms/offset,
// whereas we want the clip applied after.
// Right now, we only support rectilinear transforms, and then we transform
// our clip into pre-transform coordinate space for it to be applied there.
// DirectComposition does have an option for pre-transform clipping, if you
// create an explicit IDCompositionEffectGroup object and set a 3D transform
// on that. I suspect that will perform worse though, so we should only do
// that for complex transforms (which are never provided right now).
MOZ_ASSERT(transform.IsRectilinear());
gfx::Rect clip = transform.Inverse().TransformBounds(
gfx::Rect(aClipRect.origin.x, aClipRect.origin.y, aClipRect.size.width,
aClipRect.size.height));
clip.Round();
// Set the clip rect - converting from world space to the pre-offset space
// that DC requires for rectangle clips.
D2D_RECT_F clip_rect;
clip_rect.left = aClipRect.origin.x - aPosition.x;
clip_rect.top = aClipRect.origin.y - aPosition.y;
clip_rect.right = clip_rect.left + aClipRect.size.width;
clip_rect.bottom = clip_rect.top + aClipRect.size.height;
visual->SetClip(clip_rect);
visual->SetClip(D2DRect(clip));
// TODO: The input matrix is a 4x4, but we only support a 3x2 at
// the D3D API level (unless we QI to IDCompositionVisual3, which might
// not be available?).
// Should we assert here, or restrict at the WR API level.
visual->SetTransform(D2DMatrix(transform));
mCurrentLayers.push_back(aId);
}

Просмотреть файл

@ -70,7 +70,8 @@ class DCLayerTree {
void DestroySurface(NativeSurfaceId aId);
void CreateTile(wr::NativeSurfaceId aId, int32_t aX, int32_t aY);
void DestroyTile(wr::NativeSurfaceId aId, int32_t aX, int32_t aY);
void AddSurface(wr::NativeSurfaceId aId, wr::DeviceIntPoint aPosition,
void AddSurface(wr::NativeSurfaceId aId,
const wr::CompositorSurfaceTransform& aTransform,
wr::DeviceIntRect aClipRect);
gl::GLContext* GetGLContext() const { return mGL; }

Просмотреть файл

@ -29,10 +29,10 @@ namespace mozilla {
namespace wr {
void wr_compositor_add_surface(void* aCompositor, wr::NativeSurfaceId aId,
wr::DeviceIntPoint aPosition,
const wr::CompositorSurfaceTransform* aTransform,
wr::DeviceIntRect aClipRect) {
RenderCompositor* compositor = static_cast<RenderCompositor*>(aCompositor);
compositor->AddSurface(aId, aPosition, aClipRect);
compositor->AddSurface(aId, *aTransform, aClipRect);
}
void wr_compositor_begin_frame(void* aCompositor) {

Просмотреть файл

@ -108,7 +108,8 @@ class RenderCompositor {
virtual void DestroySurface(NativeSurfaceId aId) {}
virtual void CreateTile(wr::NativeSurfaceId, int32_t aX, int32_t aY) {}
virtual void DestroyTile(wr::NativeSurfaceId, int32_t aX, int32_t aY) {}
virtual void AddSurface(wr::NativeSurfaceId aId, wr::DeviceIntPoint aPosition,
virtual void AddSurface(wr::NativeSurfaceId aId,
const wr::CompositorSurfaceTransform& aTransform,
wr::DeviceIntRect aClipRect) {}
virtual void EnableNativeCompositor(bool aEnable) {}
virtual void DeInit() {}

Просмотреть файл

@ -864,10 +864,10 @@ void RenderCompositorANGLE::DestroyTile(wr::NativeSurfaceId aId, int aX,
mDCLayerTree->DestroyTile(aId, aX, aY);
}
void RenderCompositorANGLE::AddSurface(wr::NativeSurfaceId aId,
wr::DeviceIntPoint aPosition,
wr::DeviceIntRect aClipRect) {
mDCLayerTree->AddSurface(aId, aPosition, aClipRect);
void RenderCompositorANGLE::AddSurface(
wr::NativeSurfaceId aId, const wr::CompositorSurfaceTransform& aTransform,
wr::DeviceIntRect aClipRect) {
mDCLayerTree->AddSurface(aId, aTransform, aClipRect);
}
CompositorCapabilities RenderCompositorANGLE::GetCompositorCapabilities() {

Просмотреть файл

@ -81,7 +81,8 @@ class RenderCompositorANGLE : public RenderCompositor {
void DestroySurface(NativeSurfaceId aId) override;
void CreateTile(wr::NativeSurfaceId aId, int32_t aX, int32_t aY) override;
void DestroyTile(wr::NativeSurfaceId aId, int32_t aX, int32_t aY) override;
void AddSurface(wr::NativeSurfaceId aId, wr::DeviceIntPoint aPosition,
void AddSurface(wr::NativeSurfaceId aId,
const wr::CompositorSurfaceTransform& aTransform,
wr::DeviceIntRect aClipRect) override;
void EnableNativeCompositor(bool aEnable) override;
CompositorCapabilities GetCompositorCapabilities() override;

Просмотреть файл

@ -245,26 +245,32 @@ void RenderCompositorNative::DestroyTile(wr::NativeSurfaceId aId, int aX,
layer->DiscardBackbuffers();
}
void RenderCompositorNative::AddSurface(wr::NativeSurfaceId aId,
wr::DeviceIntPoint aPosition,
wr::DeviceIntRect aClipRect) {
void RenderCompositorNative::AddSurface(
wr::NativeSurfaceId aId, const wr::CompositorSurfaceTransform& aTransform,
wr::DeviceIntRect aClipRect) {
MOZ_RELEASE_ASSERT(!mCurrentlyBoundNativeLayer);
auto surfaceCursor = mSurfaces.find(aId);
MOZ_RELEASE_ASSERT(surfaceCursor != mSurfaces.end());
const Surface& surface = surfaceCursor->second;
Matrix4x4 transform(
aTransform.m11, aTransform.m12, aTransform.m13, aTransform.m14,
aTransform.m21, aTransform.m22, aTransform.m23, aTransform.m24,
aTransform.m31, aTransform.m32, aTransform.m33, aTransform.m34,
aTransform.m41, aTransform.m42, aTransform.m43, aTransform.m44);
for (auto it = surface.mNativeLayers.begin();
it != surface.mNativeLayers.end(); ++it) {
RefPtr<layers::NativeLayer> layer = it->second;
gfx::IntSize layerSize = layer->GetSize();
gfx::IntPoint layerPosition(
aPosition.x + surface.mTileSize.width * it->first.mX,
aPosition.y + surface.mTileSize.height * it->first.mY);
gfx::IntPoint layerPosition(surface.mTileSize.width * it->first.mX,
surface.mTileSize.height * it->first.mY);
layer->SetPosition(layerPosition);
gfx::IntRect clipRect(aClipRect.origin.x, aClipRect.origin.y,
aClipRect.size.width, aClipRect.size.height);
layer->SetClipRect(Some(clipRect));
layer->SetTransform(transform);
mAddedLayers.AppendElement(layer);
mAddedPixelCount += layerSize.width * layerSize.height;

Просмотреть файл

@ -53,7 +53,8 @@ class RenderCompositorNative : public RenderCompositor {
void DestroySurface(NativeSurfaceId aId) override;
void CreateTile(wr::NativeSurfaceId aId, int32_t aX, int32_t aY) override;
void DestroyTile(wr::NativeSurfaceId aId, int32_t aX, int32_t aY) override;
void AddSurface(wr::NativeSurfaceId aId, wr::DeviceIntPoint aPosition,
void AddSurface(wr::NativeSurfaceId aId,
const wr::CompositorSurfaceTransform& aTransform,
wr::DeviceIntRect aClipRect) override;
CompositorCapabilities GetCompositorCapabilities() override;

Просмотреть файл

@ -38,6 +38,7 @@ use webrender::{
CompositorCapabilities, CompositorConfig, DebugFlags, Device, FastHashMap, NativeSurfaceId, NativeSurfaceInfo,
NativeTileId, PipelineInfo, ProfilerHooks, RecordedFrameHandle, Renderer, RendererOptions, RendererStats,
SceneBuilderHooks, ShaderPrecacheFlags, Shaders, ThreadListener, UploadMethod, WrShaders, ONE_TIME_USAGE_HINT,
CompositorSurfaceTransform,
};
use wr_malloc_size_of::MallocSizeOfOps;
@ -1211,7 +1212,7 @@ extern "C" {
fn wr_compositor_add_surface(
compositor: *mut c_void,
id: NativeSurfaceId,
position: DeviceIntPoint,
transform: &CompositorSurfaceTransform,
clip_rect: DeviceIntRect,
);
fn wr_compositor_end_frame(compositor: *mut c_void);
@ -1294,9 +1295,9 @@ impl Compositor for WrCompositor {
}
}
fn add_surface(&mut self, id: NativeSurfaceId, position: DeviceIntPoint, clip_rect: DeviceIntRect) {
fn add_surface(&mut self, id: NativeSurfaceId, transform: CompositorSurfaceTransform, clip_rect: DeviceIntRect) {
unsafe {
wr_compositor_add_surface(self.0, id, position, clip_rect);
wr_compositor_add_surface(self.0, id, &transform, clip_rect);
}
}

Просмотреть файл

@ -12,7 +12,8 @@ use std::rc::Rc;
use std::sync::{mpsc, Arc, Condvar, Mutex};
use std::thread;
use webrender::{
api::units::*, Compositor, CompositorCapabilities, NativeSurfaceId, NativeSurfaceInfo, NativeTileId, ThreadListener,
api::units::*, Compositor, CompositorCapabilities, NativeSurfaceId, NativeSurfaceInfo, NativeTileId,
ThreadListener, CompositorSurfaceTransform
};
#[no_mangle]
@ -62,8 +63,8 @@ pub struct SwTile {
}
impl SwTile {
fn origin(&self, surface: &SwSurface, position: &DeviceIntPoint) -> DeviceIntPoint {
DeviceIntPoint::new(self.x * surface.tile_size.width, self.y * surface.tile_size.height) + position.to_vector()
fn origin(&self, surface: &SwSurface) -> DeviceIntPoint {
DeviceIntPoint::new(self.x * surface.tile_size.width, self.y * surface.tile_size.height)
}
/// Bounds used for determining overlap dependencies. This may either be the
@ -73,10 +74,10 @@ impl SwTile {
fn overlap_rect(
&self,
surface: &SwSurface,
position: &DeviceIntPoint,
transform: &CompositorSurfaceTransform,
clip_rect: &DeviceIntRect,
) -> Option<DeviceIntRect> {
let origin = self.origin(surface, position);
let origin = self.origin(surface);
// If the tile was invalidated this frame, then we don't have precise
// bounds. Instead, just use the default surface tile size.
let bounds = if self.invalid.get() {
@ -84,7 +85,8 @@ impl SwTile {
} else {
self.valid_rect.translate(origin.to_vector())
};
bounds.intersection(clip_rect)
let device_rect = transform.transform_rect(&bounds.to_f32().cast_unit()).unwrap().round_out().to_i32();
device_rect.cast_unit().intersection(clip_rect)
}
/// Determine if the tile's bounds may overlap the dependency rect if it were
@ -92,11 +94,11 @@ impl SwTile {
fn may_overlap(
&self,
surface: &SwSurface,
position: &DeviceIntPoint,
transform: &CompositorSurfaceTransform,
clip_rect: &DeviceIntRect,
dep_rect: &DeviceIntRect,
) -> bool {
self.overlap_rect(surface, position, clip_rect)
self.overlap_rect(surface, transform, clip_rect)
.map_or(false, |r| r.intersects(dep_rect))
}
@ -106,13 +108,12 @@ impl SwTile {
fn composite_rects(
&self,
surface: &SwSurface,
position: &DeviceIntPoint,
transform: &CompositorSurfaceTransform,
clip_rect: &DeviceIntRect,
) -> Option<(DeviceIntRect, DeviceIntRect)> {
let valid = self.valid_rect.translate(self.origin(surface, position).to_vector());
valid
.intersection(clip_rect)
.map(|r| (r.translate(-valid.origin.to_vector()), r))
let valid = self.valid_rect.translate(self.origin(surface).to_vector());
let valid = transform.transform_rect(&valid.to_f32().cast_unit()).unwrap().round_out().to_i32();
valid.cast_unit().intersection(clip_rect).map(|r| (r.translate(-valid.origin.to_vector().cast_unit()), r))
}
}
@ -392,7 +393,7 @@ pub struct SwCompositor {
native_gl: Option<Rc<dyn gl::Gl>>,
compositor: Option<WrCompositor>,
surfaces: HashMap<NativeSurfaceId, SwSurface>,
frame_surfaces: Vec<(NativeSurfaceId, DeviceIntPoint, DeviceIntRect)>,
frame_surfaces: Vec<(NativeSurfaceId, CompositorSurfaceTransform, DeviceIntRect)>,
cur_tile: NativeTileId,
draw_tile: Option<DrawTileHelper>,
/// The maximum tile size required for any of the allocated surfaces.
@ -485,7 +486,7 @@ impl SwCompositor {
/// in composition.
fn get_overlaps(&self, overlap_rect: &DeviceIntRect) -> u32 {
let mut overlaps = 0;
for &(ref id, ref position, ref clip_rect) in &self.frame_surfaces {
for &(ref id, ref transform, ref clip_rect) in &self.frame_surfaces {
// If the surface's clip rect doesn't overlap the tile's rect,
// then there is no need to check any tiles within the surface.
if !overlap_rect.intersects(clip_rect) {
@ -495,7 +496,8 @@ impl SwCompositor {
for tile in &surface.tiles {
// If there is a deferred tile that might overlap the destination rectangle,
// record the overlap.
if tile.overlaps.get() > 0 && tile.may_overlap(surface, position, clip_rect, overlap_rect) {
if tile.overlaps.get() > 0 &&
tile.may_overlap(surface, transform, clip_rect, overlap_rect) {
overlaps += 1;
}
}
@ -508,12 +510,12 @@ impl SwCompositor {
fn queue_composite(
&self,
surface: &SwSurface,
position: &DeviceIntPoint,
transform: &CompositorSurfaceTransform,
clip_rect: &DeviceIntRect,
tile: &SwTile,
) {
if let Some(ref composite_thread) = self.composite_thread {
if let Some((src_rect, dst_rect)) = tile.composite_rects(surface, position, clip_rect) {
if let Some((src_rect, dst_rect)) = tile.composite_rects(surface, transform, clip_rect) {
if let Some(texture) = self.gl.lock_texture(tile.color_id) {
let framebuffer = self.locked_framebuffer.clone().unwrap();
composite_thread.queue_composite(texture, framebuffer, src_rect, dst_rect, surface.is_opaque);
@ -526,14 +528,14 @@ impl SwCompositor {
/// within the surface being queued for composition this frame. If the tile is immediately
/// ready to composite, then queue that now. Otherwise, set its draw order index for later
/// composition.
fn init_composites(&mut self, id: &NativeSurfaceId, position: &DeviceIntPoint, clip_rect: &DeviceIntRect) {
fn init_composites(&mut self, id: &NativeSurfaceId, transform: &CompositorSurfaceTransform, clip_rect: &DeviceIntRect) {
if self.composite_thread.is_none() {
return;
}
if let Some(surface) = self.surfaces.get(&id) {
for tile in &surface.tiles {
if let Some(overlap_rect) = tile.overlap_rect(surface, position, clip_rect) {
if let Some(overlap_rect) = tile.overlap_rect(surface, transform, clip_rect) {
let mut overlaps = self.get_overlaps(&overlap_rect);
// Record an extra overlap for an invalid tile to track the tile's dependency
// on its own future update.
@ -542,7 +544,7 @@ impl SwCompositor {
}
if overlaps == 0 {
// Not dependent on any tiles, so go ahead and composite now.
self.queue_composite(surface, position, clip_rect, tile);
self.queue_composite(surface, transform, clip_rect, tile);
} else {
// Has a dependency on some invalid tiles, so need to defer composition.
tile.overlaps.set(overlaps);
@ -565,7 +567,7 @@ impl SwCompositor {
.iter()
.skip_while(|&(ref id, _, _)| *id != tile_id.surface_id);
let overlap_rect = match frame_surfaces.next() {
Some(&(_, ref position, ref clip_rect)) => {
Some(&(_, ref transform, ref clip_rect)) => {
// Remove invalid tile's update dependency.
if tile.invalid.get() {
tile.overlaps.set(tile.overlaps.get() - 1);
@ -575,9 +577,9 @@ impl SwCompositor {
return;
}
// Otherwise, the tile's dependencies are all resolved, so composite it.
self.queue_composite(surface, position, clip_rect, tile);
self.queue_composite(surface, transform, clip_rect, tile);
// Finally, get the tile's overlap rect used for tracking dependencies
match tile.overlap_rect(surface, position, clip_rect) {
match tile.overlap_rect(surface, transform, clip_rect) {
Some(overlap_rect) => overlap_rect,
None => return,
}
@ -591,7 +593,7 @@ impl SwCompositor {
let mut flushed_rects = vec![overlap_rect];
// Check surfaces following the update in the frame list and see if they would overlap it.
for &(ref id, ref position, ref clip_rect) in frame_surfaces {
for &(ref id, ref transform, ref clip_rect) in frame_surfaces {
// If the clip rect doesn't overlap the conservative bounds, we can skip the whole surface.
if !flushed_bounds.intersects(clip_rect) {
continue;
@ -605,7 +607,7 @@ impl SwCompositor {
continue;
}
// Get this tile's overlap rect for tracking dependencies
let overlap_rect = match tile.overlap_rect(surface, position, clip_rect) {
let overlap_rect = match tile.overlap_rect(surface, transform, clip_rect) {
Some(overlap_rect) => overlap_rect,
None => continue,
};
@ -624,7 +626,7 @@ impl SwCompositor {
// If the count hit zero, it is ready to composite.
tile.overlaps.set(overlaps);
if overlaps == 0 {
self.queue_composite(surface, position, clip_rect, tile);
self.queue_composite(surface, transform, clip_rect, tile);
// Record that the tile got flushed to update any downwind dependencies.
flushed_bounds = flushed_bounds.union(&overlap_rect);
flushed_rects.push(overlap_rect);
@ -946,15 +948,15 @@ impl Compositor for SwCompositor {
}
}
fn add_surface(&mut self, id: NativeSurfaceId, position: DeviceIntPoint, clip_rect: DeviceIntRect) {
fn add_surface(&mut self, id: NativeSurfaceId, transform: CompositorSurfaceTransform, clip_rect: DeviceIntRect) {
if let Some(compositor) = &mut self.compositor {
compositor.add_surface(id, position, clip_rect);
compositor.add_surface(id, transform, clip_rect);
}
// Compute overlap dependencies and issue any initial composite jobs for the SwComposite thread.
self.init_composites(&id, &position, &clip_rect);
self.init_composites(&id, &transform, &clip_rect);
self.frame_surfaces.push((id, position, clip_rect));
self.frame_surfaces.push((id, transform, clip_rect));
}
fn end_frame(&mut self) {
@ -967,7 +969,7 @@ impl Compositor for SwCompositor {
draw_tile.enable(&viewport);
let mut blend = false;
native_gl.blend_func(gl::ONE, gl::ONE_MINUS_SRC_ALPHA);
for &(ref id, ref position, ref clip_rect) in &self.frame_surfaces {
for &(ref id, ref transform, ref clip_rect) in &self.frame_surfaces {
if let Some(surface) = self.surfaces.get(id) {
if surface.is_opaque {
if blend {
@ -979,7 +981,7 @@ impl Compositor for SwCompositor {
blend = true;
}
for tile in &surface.tiles {
if let Some((src_rect, dst_rect)) = tile.composite_rects(surface, position, clip_rect) {
if let Some((src_rect, dst_rect)) = tile.composite_rects(surface, transform, clip_rect) {
draw_tile.draw(&viewport, &dst_rect, &src_rect, surface, tile);
}
}

Просмотреть файл

@ -4,8 +4,9 @@
use api::{ColorF, YuvColorSpace, YuvFormat, ImageRendering};
use api::units::{DeviceRect, DeviceIntSize, DeviceIntRect, DeviceIntPoint, WorldRect};
use api::units::{DevicePixelScale, DevicePoint, PictureRect, TexelRect};
use api::units::{DevicePixelScale, DevicePoint, PictureRect, TexelRect, DevicePixel};
use crate::batch::{resolve_image, get_buffer_kind};
use euclid::Transform3D;
use crate::gpu_cache::GpuCache;
use crate::gpu_types::{ZBufferId, ZBufferIdGenerator};
use crate::internal_types::TextureSource;
@ -106,10 +107,10 @@ pub enum ExternalSurfaceDependency {
/// this will also support RGBA images.
pub struct ExternalSurfaceDescriptor {
pub local_rect: PictureRect,
pub world_rect: WorldRect,
pub device_rect: DeviceRect,
pub local_clip_rect: PictureRect,
pub clip_rect: DeviceRect,
pub transform: CompositorSurfaceTransform,
pub image_rendering: ImageRendering,
pub z_id: ZBufferId,
pub dependency: ExternalSurfaceDependency,
@ -268,6 +269,15 @@ impl CompositorKind {
CompositorKind::Native { virtual_surface_size, .. } => *virtual_surface_size,
}
}
// We currently only support transforms for Native compositors,
// bug 1655639 is filed for adding support to Draw.
pub fn supports_transforms(&self) -> bool {
match self {
CompositorKind::Draw { .. } => false,
CompositorKind::Native { .. } => true,
}
}
}
/// The backing surface kind for a tile. Same as `TileSurface`, minus
@ -311,6 +321,7 @@ pub struct CompositeSurfaceDescriptor {
pub surface_id: Option<NativeSurfaceId>,
pub offset: DevicePoint,
pub clip_rect: DeviceRect,
pub transform: CompositorSurfaceTransform,
// A list of image keys and generations that this compositor surface
// depends on. This avoids composites being skipped when the only
// thing that has changed is the generation of an compositor surface
@ -553,6 +564,9 @@ impl CompositeState {
surface_id: tile_cache.native_surface.as_ref().map(|s| s.opaque),
offset: tile_cache.device_position,
clip_rect: device_clip_rect,
transform: CompositorSurfaceTransform::create_translation(tile_cache.device_position.x,
tile_cache.device_position.y,
0.0),
image_dependencies: [ImageDependency::INVALID; 3],
tile_descriptors: opaque_tile_descriptors,
}
@ -670,11 +684,13 @@ impl CompositeState {
let image_buffer_kind = get_buffer_kind(planes[0].texture);
// Only propagate flip_y if the compositor doesn't support transforms,
// since otherwise it'll be handled as part of the transform.
self.external_surfaces.push(ResolvedExternalSurface {
color_data: ResolvedExternalSurfaceColorData::Rgb {
image_dependency: image_dependencies[0],
plane: planes[0],
flip_y,
flip_y: flip_y && !self.compositor_kind.supports_transforms(),
},
image_buffer_kind,
update_params,
@ -682,12 +698,19 @@ impl CompositeState {
},
}
// Just use the device_rect for the tile's clip, since we'll clip
// in the compositor instead.
let tile_clip = if self.compositor_kind.supports_transforms() {
external_surface.device_rect
} else {
clip_rect
};
let tile = CompositeTile {
surface,
rect: external_surface.device_rect,
valid_rect: external_surface.device_rect.translate(-external_surface.device_rect.origin.to_vector()),
dirty_rect: external_surface.device_rect.translate(-external_surface.device_rect.origin.to_vector()),
clip_rect,
clip_rect: tile_clip,
z_id: external_surface.z_id,
};
@ -698,7 +721,8 @@ impl CompositeState {
CompositeSurfaceDescriptor {
surface_id: external_surface.native_surface_id,
offset: tile.rect.origin,
clip_rect: tile.clip_rect,
clip_rect,
transform: external_surface.transform,
image_dependencies: image_dependencies,
tile_descriptors: Vec::new(),
}
@ -714,6 +738,9 @@ impl CompositeState {
surface_id: tile_cache.native_surface.as_ref().map(|s| s.alpha),
offset: tile_cache.device_position,
clip_rect: device_clip_rect,
transform: CompositorSurfaceTransform::create_translation(tile_cache.device_position.x,
tile_cache.device_position.y,
0.0),
image_dependencies: [ImageDependency::INVALID; 3],
tile_descriptors: alpha_tile_descriptors,
}
@ -810,6 +837,10 @@ pub struct CompositorCapabilities {
pub virtual_surface_size: i32,
}
/// The transform type to apply to Compositor surfaces.
pub struct CompositorSurfacePixel;
pub type CompositorSurfaceTransform = Transform3D<f32, CompositorSurfacePixel, DevicePixel>;
/// Defines an interface to a native (OS level) compositor. If supplied
/// by the client application, then picture cache slices will be
/// composited by the OS compositor, rather than drawn via WR batches.
@ -891,11 +922,10 @@ pub trait Compositor {
// We might need to change the interface to maintain a visual
// tree that can be mutated?
// TODO(gw): We might need to add a concept of a hierachy in future.
// TODO(gw): In future, expand to support a more complete transform matrix.
fn add_surface(
&mut self,
id: NativeSurfaceId,
position: DeviceIntPoint,
transform: CompositorSurfaceTransform,
clip_rect: DeviceIntRect,
);

Просмотреть файл

@ -205,7 +205,7 @@ extern crate webrender_build;
#[doc(hidden)]
pub use crate::composite::{CompositorConfig, Compositor, CompositorCapabilities};
pub use crate::composite::{NativeSurfaceId, NativeTileId, NativeSurfaceInfo};
pub use crate::composite::{NativeSurfaceId, NativeTileId, NativeSurfaceInfo, CompositorSurfaceTransform};
pub use crate::device::{UploadMethod, VertexUsageHint, get_gl_target, get_unoptimized_shader_source};
pub use crate::device::{ProgramBinary, ProgramCache, ProgramCacheObserver, FormatDesc};
pub use crate::device::Device;

Просмотреть файл

@ -107,7 +107,7 @@ use crate::spatial_tree::{ROOT_SPATIAL_NODE_INDEX,
use crate::composite::{CompositorKind, CompositeState, NativeSurfaceId, NativeTileId};
use crate::composite::{ExternalSurfaceDescriptor, ExternalSurfaceDependency};
use crate::debug_colors;
use euclid::{vec2, vec3, Point2D, Scale, Size2D, Vector2D, Rect, Transform3D, SideOffsets2D};
use euclid::{vec2, vec3, Point2D, Scale, Size2D, Vector2D, Vector3D, Rect, Transform3D, SideOffsets2D};
use euclid::approxeq::ApproxEq;
use crate::filterdata::SFilterData;
use crate::intern::ItemUid;
@ -2947,6 +2947,8 @@ impl TileCacheInstance {
&mut self,
prim_info: &mut PrimitiveDependencyInfo,
prim_rect: PictureRect,
local_prim_rect: LayoutRect,
prim_spatial_node_index: SpatialNodeIndex,
frame_context: &FrameVisibilityContext,
image_dependencies: &[ImageDependency;3],
api_keys: &[ImageKey; 3],
@ -2960,6 +2962,8 @@ impl TileCacheInstance {
self.setup_compositor_surfaces_impl(
prim_info,
prim_rect,
local_prim_rect,
prim_spatial_node_index,
frame_context,
ExternalSurfaceDependency::Yuv {
image_dependencies: *image_dependencies,
@ -2978,6 +2982,8 @@ impl TileCacheInstance {
&mut self,
prim_info: &mut PrimitiveDependencyInfo,
prim_rect: PictureRect,
local_prim_rect: LayoutRect,
prim_spatial_node_index: SpatialNodeIndex,
frame_context: &FrameVisibilityContext,
image_dependency: ImageDependency,
api_key: ImageKey,
@ -2991,6 +2997,8 @@ impl TileCacheInstance {
self.setup_compositor_surfaces_impl(
prim_info,
prim_rect,
local_prim_rect,
prim_spatial_node_index,
frame_context,
ExternalSurfaceDependency::Rgb {
image_dependency,
@ -3009,6 +3017,8 @@ impl TileCacheInstance {
&mut self,
prim_info: &mut PrimitiveDependencyInfo,
prim_rect: PictureRect,
local_prim_rect: LayoutRect,
prim_spatial_node_index: SpatialNodeIndex,
frame_context: &FrameVisibilityContext,
dependency: ExternalSurfaceDependency,
api_keys: &[ImageKey; 3],
@ -3025,9 +3035,6 @@ impl TileCacheInstance {
frame_context.spatial_tree,
);
let world_rect = pic_to_world_mapper
.map(&prim_rect)
.expect("bug: unable to map the primitive to world space");
let world_clip_rect = pic_to_world_mapper
.map(&prim_info.prim_clip_box.to_rect())
.expect("bug: unable to map clip to world space");
@ -3040,7 +3047,33 @@ impl TileCacheInstance {
// TODO(gw): Is there any case where if the primitive ends up on a fractional
// boundary we want to _skip_ promoting to a compositor surface and
// draw it as part of the content?
let device_rect = (world_rect * frame_context.global_device_pixel_scale).round();
let (device_rect, transform) = match composite_state.compositor_kind {
CompositorKind::Draw { .. } => {
let world_rect = pic_to_world_mapper
.map(&prim_rect)
.expect("bug: unable to map the primitive to world space");
let device_rect = (world_rect * frame_context.global_device_pixel_scale).round();
(device_rect, Transform3D::identity())
}
CompositorKind::Native { .. } => {
// If we have a Native Compositor, then we can support doing the transformation
// as part of compositing. Use the local prim rect for the external surface, and
// compute the full local to device transform to provide to the compositor.
let surface_to_world_mapper : SpaceMapper<PicturePixel, WorldPixel> = SpaceMapper::new_with_target(
ROOT_SPATIAL_NODE_INDEX,
prim_spatial_node_index,
frame_context.global_screen_world_rect,
frame_context.spatial_tree,
);
let prim_origin = Vector3D::new(local_prim_rect.origin.x, local_prim_rect.origin.y, 0.0);
let world_to_device_scale = Transform3D::from_scale(frame_context.global_device_pixel_scale);
let transform = surface_to_world_mapper.get_transform().pre_translate(prim_origin).post_transform(&world_to_device_scale);
(local_prim_rect.cast_unit(), transform)
}
};
let clip_rect = (world_clip_rect * frame_context.global_device_pixel_scale).round();
if device_rect.size.width >= MAX_COMPOSITOR_SURFACES_SIZE ||
@ -3121,12 +3154,12 @@ impl TileCacheInstance {
// Each compositor surface allocates a unique z-id
self.external_surfaces.push(ExternalSurfaceDescriptor {
local_rect: prim_info.prim_clip_box.to_rect(),
world_rect,
local_clip_rect: prim_info.prim_clip_box.to_rect(),
dependency,
image_rendering,
device_rect,
clip_rect,
transform: transform.cast_unit(),
z_id: composite_state.z_generator.next(),
native_surface_id,
update_params,
@ -3338,6 +3371,8 @@ impl TileCacheInstance {
promote_to_surface = self.setup_compositor_surfaces_rgb(
&mut prim_info,
prim_rect,
local_prim_rect,
prim_spatial_node_index,
frame_context,
ImageDependency {
key: image_data.key,
@ -3402,6 +3437,8 @@ impl TileCacheInstance {
promote_to_surface = self.setup_compositor_surfaces_yuv(
&mut prim_info,
prim_rect,
local_prim_rect,
prim_spatial_node_index,
frame_context,
&image_dependencies,
&prim_data.kind.yuv_key,

Просмотреть файл

@ -49,7 +49,7 @@ use core::time::Duration;
use crate::batch::{AlphaBatchContainer, BatchKind, BatchFeatures, BatchTextures, BrushBatchKind, ClipBatchList};
#[cfg(any(feature = "capture", feature = "replay"))]
use crate::capture::{CaptureConfig, ExternalCaptureImage, PlainExternalImage};
use crate::composite::{CompositeState, CompositeTileSurface, CompositeTile, ResolvedExternalSurface};
use crate::composite::{CompositeState, CompositeTileSurface, CompositeTile, ResolvedExternalSurface, CompositorSurfaceTransform};
use crate::composite::{CompositorKind, Compositor, NativeTileId, CompositeSurfaceFormat, ResolvedExternalSurfaceColorData};
use crate::composite::{CompositorConfig, NativeSurfaceOperationDetails, NativeSurfaceId, NativeSurfaceOperation};
use crate::c_str;
@ -3374,7 +3374,7 @@ impl Renderer {
compositor.add_surface(
NativeSurfaceId::DEBUG_OVERLAY,
DeviceIntPoint::zero(),
CompositorSurfaceTransform::identity(),
DeviceIntRect::new(
DeviceIntPoint::zero(),
self.debug_overlay_state.current_size.unwrap(),
@ -4726,7 +4726,6 @@ impl Renderer {
uv_rect.uv0.y = uv_rect.uv1.y;
uv_rect.uv1.y = y;
}
let instance = CompositeInstance::new_rgb(
surface_rect.to_f32(),
surface_rect.to_f32(),
@ -7737,7 +7736,7 @@ impl CompositeState {
for surface in &self.descriptor.surfaces {
compositor.add_surface(
surface.surface_id.expect("bug: no native surface allocated"),
surface.offset.to_i32(),
surface.transform,
surface.clip_rect.to_i32(),
);
}

Просмотреть файл

@ -333,6 +333,8 @@ pub trait MatrixHelpers<Src, Dst> {
/// Turn Z transformation into identity. This is useful when crossing "flat"
/// transform styled stacking contexts upon traversing the coordinate systems.
fn flatten_z_output(&mut self);
fn cast_unit<NewSrc, NewDst>(&self) -> Transform3D<f32, NewSrc, NewDst>;
}
impl<Src, Dst> MatrixHelpers<Src, Dst> for Transform3D<f32, Src, Dst> {
@ -472,6 +474,13 @@ impl<Src, Dst> MatrixHelpers<Src, Dst> for Transform3D<f32, Src, Dst> {
self.m33 = 1.0;
self.m43 = 0.0;
}
fn cast_unit<NewSrc, NewDst>(&self) -> Transform3D<f32, NewSrc, NewDst> {
Transform3D::row_major(self.m11, self.m12, self.m13, self.m14,
self.m21, self.m22, self.m23, self.m24,
self.m31, self.m32, self.m33, self.m34,
self.m41, self.m42, self.m43, self.m44)
}
}
pub trait PointHelpers<U>