Bug 1677929 - Add a way to specify an ID for a generated frame, and propagate the ID to the APZSampler. r=gw,kats

This ID allows the compositor to track per-frame information from frame
generation, through APZ sampling, to the NotifyDidRender notification.

Differential Revision: https://phabricator.services.mozilla.com/D97535
This commit is contained in:
Markus Stange
2020-12-09 03:35:50 +00:00
parent a867907ff8
commit 46ea354af1
24 changed files with 113 additions and 55 deletions

View File

@@ -57,11 +57,13 @@ class APZSampler {
*/ */
static void SetSamplerThread(const wr::WrWindowId& aWindowId); static void SetSamplerThread(const wr::WrWindowId& aWindowId);
static void SampleForWebRender( static void SampleForWebRender(
const wr::WrWindowId& aWindowId, wr::Transaction* aTxn, const wr::WrWindowId& aWindowId, const uint64_t* aGeneratedFrameId,
wr::Transaction* aTransaction,
const wr::WrPipelineIdEpochs* aEpochsBeingRendered); const wr::WrPipelineIdEpochs* aEpochsBeingRendered);
void SetSampleTime(const SampleTime& aSampleTime); void SetSampleTime(const SampleTime& aSampleTime);
void SampleForWebRender(wr::TransactionWrapper& aTxn, void SampleForWebRender(const Maybe<VsyncId>& aGeneratedFrameId,
wr::TransactionWrapper& aTxn,
const wr::WrPipelineIdEpochs* aEpochsBeingRendered); const wr::WrPipelineIdEpochs* aEpochsBeingRendered);
bool AdvanceAnimations(const SampleTime& aSampleTime); bool AdvanceAnimations(const SampleTime& aSampleTime);

View File

@@ -706,7 +706,8 @@ void APZCTreeManager::UpdateHitTestingTree(
} }
void APZCTreeManager::SampleForWebRender( void APZCTreeManager::SampleForWebRender(
wr::TransactionWrapper& aTxn, const SampleTime& aSampleTime, const Maybe<VsyncId>& aVsyncId, wr::TransactionWrapper& aTxn,
const SampleTime& aSampleTime,
const wr::WrPipelineIdEpochs* aEpochsBeingRendered) { const wr::WrPipelineIdEpochs* aEpochsBeingRendered) {
AssertOnSamplerThread(); AssertOnSamplerThread();
MutexAutoLock lock(mMapLock); MutexAutoLock lock(mMapLock);

View File

@@ -196,7 +196,8 @@ class APZCTreeManager : public IAPZCTreeManager, public APZInputBridge {
* In effect it is the webrender equivalent of (part of) the code in * In effect it is the webrender equivalent of (part of) the code in
* AsyncCompositionManager. * AsyncCompositionManager.
*/ */
void SampleForWebRender(wr::TransactionWrapper& aTxn, void SampleForWebRender(const Maybe<VsyncId>& aVsyncId,
wr::TransactionWrapper& aTxn,
const SampleTime& aSampleTime, const SampleTime& aSampleTime,
const wr::WrPipelineIdEpochs* aEpochsBeingRendered); const wr::WrPipelineIdEpochs* aEpochsBeingRendered);

View File

@@ -66,11 +66,14 @@ void APZSampler::SetSamplerThread(const wr::WrWindowId& aWindowId) {
/*static*/ /*static*/
void APZSampler::SampleForWebRender( void APZSampler::SampleForWebRender(
const wr::WrWindowId& aWindowId, wr::Transaction* aTransaction, const wr::WrWindowId& aWindowId, const uint64_t* aGeneratedFrameId,
wr::Transaction* aTransaction,
const wr::WrPipelineIdEpochs* aEpochsBeingRendered) { const wr::WrPipelineIdEpochs* aEpochsBeingRendered) {
if (RefPtr<APZSampler> sampler = GetSampler(aWindowId)) { if (RefPtr<APZSampler> sampler = GetSampler(aWindowId)) {
wr::TransactionWrapper txn(aTransaction); wr::TransactionWrapper txn(aTransaction);
sampler->SampleForWebRender(txn, aEpochsBeingRendered); Maybe<VsyncId> vsyncId =
aGeneratedFrameId ? Some(VsyncId{*aGeneratedFrameId}) : Nothing();
sampler->SampleForWebRender(vsyncId, txn, aEpochsBeingRendered);
} }
} }
@@ -84,7 +87,7 @@ void APZSampler::SetSampleTime(const SampleTime& aSampleTime) {
} }
void APZSampler::SampleForWebRender( void APZSampler::SampleForWebRender(
wr::TransactionWrapper& aTxn, const Maybe<VsyncId>& aVsyncId, wr::TransactionWrapper& aTxn,
const wr::WrPipelineIdEpochs* aEpochsBeingRendered) { const wr::WrPipelineIdEpochs* aEpochsBeingRendered) {
AssertOnSamplerThread(); AssertOnSamplerThread();
SampleTime sampleTime; SampleTime sampleTime;
@@ -121,7 +124,7 @@ void APZSampler::SampleForWebRender(
? now ? now
: mSampleTime; : mSampleTime;
} }
mApz->SampleForWebRender(aTxn, sampleTime, aEpochsBeingRendered); mApz->SampleForWebRender(aVsyncId, aTxn, sampleTime, aEpochsBeingRendered);
} }
bool APZSampler::AdvanceAnimations(const SampleTime& aSampleTime) { bool APZSampler::AdvanceAnimations(const SampleTime& aSampleTime) {
@@ -331,10 +334,11 @@ void apz_register_sampler(mozilla::wr::WrWindowId aWindowId) {
} }
void apz_sample_transforms( void apz_sample_transforms(
mozilla::wr::WrWindowId aWindowId, mozilla::wr::Transaction* aTransaction, mozilla::wr::WrWindowId aWindowId, const uint64_t* aGeneratedFrameId,
mozilla::wr::Transaction* aTransaction,
const mozilla::wr::WrPipelineIdEpochs* aEpochsBeingRendered) { const mozilla::wr::WrPipelineIdEpochs* aEpochsBeingRendered) {
mozilla::layers::APZSampler::SampleForWebRender(aWindowId, aTransaction, mozilla::layers::APZSampler::SampleForWebRender(
aEpochsBeingRendered); aWindowId, aGeneratedFrameId, aTransaction, aEpochsBeingRendered);
} }
void apz_deregister_sampler(mozilla::wr::WrWindowId aWindowId) {} void apz_deregister_sampler(mozilla::wr::WrWindowId aWindowId) {}

View File

@@ -2091,7 +2091,7 @@ void WebRenderBridgeParent::MaybeGenerateFrame(VsyncId aId,
#endif #endif
MOZ_ASSERT(generateFrame); MOZ_ASSERT(generateFrame);
fastTxn.GenerateFrame(); fastTxn.GenerateFrame(aId);
mApi->SendTransaction(fastTxn); mApi->SendTransaction(fastTxn);
#if defined(MOZ_WIDGET_ANDROID) #if defined(MOZ_WIDGET_ANDROID)

View File

@@ -252,8 +252,8 @@ void TransactionBuilder::ClearDisplayList(Epoch aEpoch,
wr_transaction_clear_display_list(mTxn, aEpoch, aPipelineId); wr_transaction_clear_display_list(mTxn, aEpoch, aPipelineId);
} }
void TransactionBuilder::GenerateFrame() { void TransactionBuilder::GenerateFrame(const VsyncId& aVsyncId) {
wr_transaction_generate_frame(mTxn); wr_transaction_generate_frame(mTxn, aVsyncId.mId);
} }
void TransactionBuilder::InvalidateRenderedFrame() { void TransactionBuilder::InvalidateRenderedFrame() {

View File

@@ -111,7 +111,7 @@ class TransactionBuilder final {
void ClearDisplayList(Epoch aEpoch, wr::WrPipelineId aPipeline); void ClearDisplayList(Epoch aEpoch, wr::WrPipelineId aPipeline);
void GenerateFrame(); void GenerateFrame(const VsyncId& aVsyncId);
void InvalidateRenderedFrame(); void InvalidateRenderedFrame();

View File

@@ -917,6 +917,7 @@ extern "C" {
fn apz_register_sampler(window_id: WrWindowId); fn apz_register_sampler(window_id: WrWindowId);
fn apz_sample_transforms( fn apz_sample_transforms(
window_id: WrWindowId, window_id: WrWindowId,
generated_frame_id: *const u64,
transaction: &mut Transaction, transaction: &mut Transaction,
epochs_being_rendered: &WrPipelineIdEpochs, epochs_being_rendered: &WrPipelineIdEpochs,
); );
@@ -1014,8 +1015,17 @@ impl AsyncPropertySampler for SamplerCallback {
fn sample( fn sample(
&self, &self,
_document_id: DocumentId, _document_id: DocumentId,
generated_frame_id: Option<u64>,
epochs_being_rendered: &FastHashMap<PipelineId, Epoch>, epochs_being_rendered: &FastHashMap<PipelineId, Epoch>,
) -> Vec<FrameMsg> { ) -> Vec<FrameMsg> {
let generated_frame_id_value;
let generated_frame_id: *const u64 = match generated_frame_id {
Some(id) => {
generated_frame_id_value = id;
&generated_frame_id_value
}
None => ptr::null_mut(),
};
let mut transaction = Transaction::new(); let mut transaction = Transaction::new();
unsafe { unsafe {
// XXX: When we implement scroll-linked animations, we will probably // XXX: When we implement scroll-linked animations, we will probably
@@ -1023,6 +1033,7 @@ impl AsyncPropertySampler for SamplerCallback {
omta_sample(self.window_id, &mut transaction); omta_sample(self.window_id, &mut transaction);
apz_sample_transforms( apz_sample_transforms(
self.window_id, self.window_id,
generated_frame_id,
&mut transaction, &mut transaction,
&epochs_being_rendered.iter().map(WrPipelineIdAndEpoch::from).collect(), &epochs_being_rendered.iter().map(WrPipelineIdAndEpoch::from).collect(),
) )
@@ -1823,8 +1834,8 @@ pub extern "C" fn wr_transaction_set_document_view(txn: &mut Transaction, doc_re
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn wr_transaction_generate_frame(txn: &mut Transaction) { pub extern "C" fn wr_transaction_generate_frame(txn: &mut Transaction, id: u64) {
txn.generate_frame(); txn.generate_frame(id);
} }
#[no_mangle] #[no_mangle]

View File

@@ -92,7 +92,8 @@ void apz_deregister_updater(mozilla::wr::WrWindowId aWindowId);
void apz_register_sampler(mozilla::wr::WrWindowId aWindowId); void apz_register_sampler(mozilla::wr::WrWindowId aWindowId);
void apz_sample_transforms( void apz_sample_transforms(
mozilla::wr::WrWindowId aWindowId, mozilla::wr::Transaction* aTransaction, mozilla::wr::WrWindowId aWindowId, const uint64_t* aGeneratedFrameId,
mozilla::wr::Transaction* aTransaction,
const mozilla::wr::WrPipelineIdEpochs* aPipelineEpochs); const mozilla::wr::WrPipelineIdEpochs* aPipelineEpochs);
void apz_deregister_sampler(mozilla::wr::WrWindowId aWindowId); void apz_deregister_sampler(mozilla::wr::WrWindowId aWindowId);

View File

@@ -169,7 +169,7 @@ impl Rectangle {
true, true,
); );
transaction.set_root_pipeline(pipeline_id); transaction.set_root_pipeline(pipeline_id);
transaction.generate_frame(); transaction.generate_frame(0);
self.api.send_transaction(self.document_id, transaction); self.api.send_transaction(self.document_id, transaction);
rx.recv().unwrap(); rx.recv().unwrap();
let renderer = self.renderer.as_mut().unwrap(); let renderer = self.renderer.as_mut().unwrap();

View File

@@ -417,7 +417,7 @@ fn main() {
); );
} }
txn.generate_frame(); txn.generate_frame(0);
api.send_transaction(document_id, txn); api.send_transaction(document_id, txn);
// Tick the compositor (in this sample, we don't block on UI events) // Tick the compositor (in this sample, we don't block on UI events)
@@ -464,7 +464,7 @@ fn main() {
} }
} }
txn.generate_frame(); txn.generate_frame(0);
api.send_transaction(document_id, txn); api.send_transaction(document_id, txn);
current_epoch.0 += 1; current_epoch.0 += 1;
time += 0.001; time += 0.001;

View File

@@ -195,7 +195,7 @@ impl Example for App {
colors: vec![], colors: vec![],
}, },
); );
txn.generate_frame(); txn.generate_frame(0);
api.send_transaction(document_id, txn); api.send_transaction(document_id, txn);
} }
_ => (), _ => (),

View File

@@ -313,7 +313,7 @@ impl Example for App {
} }
if !txn.is_empty() { if !txn.is_empty() {
txn.generate_frame(); txn.generate_frame(0);
api.send_transaction(document_id, txn); api.send_transaction(document_id, txn);
} }

View File

@@ -215,7 +215,7 @@ pub fn main_wrapper<E: Example>(
true, true,
); );
txn.set_root_pipeline(pipeline_id); txn.set_root_pipeline(pipeline_id);
txn.generate_frame(); txn.generate_frame(0);
api.send_transaction(document_id, txn); api.send_transaction(document_id, txn);
println!("Entering event loop"); println!("Entering event loop");
@@ -312,7 +312,7 @@ pub fn main_wrapper<E: Example>(
builder.finalize(), builder.finalize(),
true, true,
); );
txn.generate_frame(); txn.generate_frame(0);
} }
api.send_transaction(document_id, txn); api.send_transaction(document_id, txn);

View File

@@ -129,7 +129,7 @@ impl Example for App {
builder.finalize(), builder.finalize(),
true, true,
); );
txn.generate_frame(); txn.generate_frame(0);
api.send_transaction(doc.id, txn); api.send_transaction(doc.id, txn);
} }
} }

View File

@@ -104,7 +104,7 @@ impl Example for App {
&DirtyRect::All, &DirtyRect::All,
); );
let mut txn = Transaction::new(); let mut txn = Transaction::new();
txn.generate_frame(); txn.generate_frame(0);
api.send_transaction(document_id, txn); api.send_transaction(document_id, txn);
} }
_ => {} _ => {}

View File

@@ -285,7 +285,7 @@ impl Window {
true, true,
); );
txn.set_root_pipeline(self.pipeline_id); txn.set_root_pipeline(self.pipeline_id);
txn.generate_frame(); txn.generate_frame(0);
api.send_transaction(self.document_id, txn); api.send_transaction(self.document_id, txn);
renderer.update(); renderer.update();

View File

@@ -182,11 +182,11 @@ impl Example for App {
ExternalScrollId(0, PipelineId::dummy()), ExternalScrollId(0, PipelineId::dummy()),
ScrollClamping::ToContentBounds, ScrollClamping::ToContentBounds,
); );
txn.generate_frame(); txn.generate_frame(0);
} }
if let Some(zoom) = zoom { if let Some(zoom) = zoom {
txn.set_pinch_zoom(ZoomFactor::new(zoom)); txn.set_pinch_zoom(ZoomFactor::new(zoom));
txn.generate_frame(); txn.generate_frame(0);
} }
} }
winit::WindowEvent::CursorMoved { position: LogicalPosition { x, y }, .. } => { winit::WindowEvent::CursorMoved { position: LogicalPosition { x, y }, .. } => {
@@ -207,7 +207,7 @@ impl Example for App {
ScrollClamping::ToContentBounds, ScrollClamping::ToContentBounds,
); );
txn.generate_frame(); txn.generate_frame(0);
} }
winit::WindowEvent::MouseInput { .. } => { winit::WindowEvent::MouseInput { .. } => {
let results = api.hit_test( let results = api.hit_test(

View File

@@ -106,6 +106,38 @@ impl fmt::Debug for ResourceUpdate {
} }
} }
/// Whether to generate a frame, and if so, an id that allows tracking this
/// transaction through the various frame stages.
#[derive(Clone, Debug)]
pub enum GenerateFrame {
/// Generate a frame if something changed.
Yes {
/// An id that allows tracking the frame transaction through the various
/// frame stages. Specified by the caller of generate_frame().
id: u64,
},
/// Don't generate a frame even if something has changed.
No,
}
impl GenerateFrame {
///
pub fn as_bool(&self) -> bool {
match self {
GenerateFrame::Yes { .. } => true,
GenerateFrame::No => false,
}
}
/// Return the frame ID, if a frame is generated.
pub fn id(&self) -> Option<u64> {
match self {
GenerateFrame::Yes { id } => Some(*id),
GenerateFrame::No => None,
}
}
}
/// A Transaction is a group of commands to apply atomically to a document. /// A Transaction is a group of commands to apply atomically to a document.
/// ///
/// This mechanism ensures that: /// This mechanism ensures that:
@@ -127,8 +159,10 @@ pub struct Transaction {
/// it will be applied directly on the render backend. /// it will be applied directly on the render backend.
use_scene_builder_thread: bool, use_scene_builder_thread: bool,
/// /// Whether to generate a frame, and if so, an id that allows tracking this
generate_frame: bool, /// transaction through the various frame stages. Specified by the caller of
/// generate_frame().
generate_frame: GenerateFrame,
/// Set to true in order to force re-rendering even if WebRender can't internally /// Set to true in order to force re-rendering even if WebRender can't internally
/// detect that something has changed. /// detect that something has changed.
@@ -146,7 +180,7 @@ impl Transaction {
resource_updates: Vec::new(), resource_updates: Vec::new(),
notifications: Vec::new(), notifications: Vec::new(),
use_scene_builder_thread: true, use_scene_builder_thread: true,
generate_frame: false, generate_frame: GenerateFrame::No,
invalidate_rendered_frame: false, invalidate_rendered_frame: false,
low_priority: false, low_priority: false,
} }
@@ -171,7 +205,7 @@ impl Transaction {
/// Returns true if the transaction has no effect. /// Returns true if the transaction has no effect.
pub fn is_empty(&self) -> bool { pub fn is_empty(&self) -> bool {
!self.generate_frame && !self.generate_frame.as_bool() &&
!self.invalidate_rendered_frame && !self.invalidate_rendered_frame &&
self.scene_ops.is_empty() && self.scene_ops.is_empty() &&
self.frame_ops.is_empty() && self.frame_ops.is_empty() &&
@@ -342,8 +376,8 @@ impl Transaction {
/// as to when happened. /// as to when happened.
/// ///
/// [notifier]: trait.RenderNotifier.html#tymethod.new_frame_ready /// [notifier]: trait.RenderNotifier.html#tymethod.new_frame_ready
pub fn generate_frame(&mut self) { pub fn generate_frame(&mut self, id: u64) {
self.generate_frame = true; self.generate_frame = GenerateFrame::Yes{ id };
} }
/// Invalidate rendered frame. It ensure that frame will be rendered during /// Invalidate rendered frame. It ensure that frame will be rendered during
@@ -556,7 +590,7 @@ pub struct TransactionMsg {
/// Updates to resources that persist across display lists. /// Updates to resources that persist across display lists.
pub resource_updates: Vec<ResourceUpdate>, pub resource_updates: Vec<ResourceUpdate>,
/// Whether to trigger frame building and rendering if something has changed. /// Whether to trigger frame building and rendering if something has changed.
pub generate_frame: bool, pub generate_frame: GenerateFrame,
/// Whether to force frame building and rendering even if no changes are internally /// Whether to force frame building and rendering even if no changes are internally
/// observed. /// observed.
pub invalidate_rendered_frame: bool, pub invalidate_rendered_frame: bool,
@@ -579,7 +613,7 @@ pub struct TransactionMsg {
impl fmt::Debug for TransactionMsg { impl fmt::Debug for TransactionMsg {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln!(f, "threaded={}, genframe={}, invalidate={}, low_priority={}", writeln!(f, "threaded={}, genframe={:?}, invalidate={}, low_priority={}",
self.use_scene_builder_thread, self.use_scene_builder_thread,
self.generate_frame, self.generate_frame,
self.invalidate_rendered_frame, self.invalidate_rendered_frame,
@@ -603,7 +637,7 @@ impl fmt::Debug for TransactionMsg {
impl TransactionMsg { impl TransactionMsg {
/// Returns true if this transaction has no effect. /// Returns true if this transaction has no effect.
pub fn is_empty(&self) -> bool { pub fn is_empty(&self) -> bool {
!self.generate_frame && !self.generate_frame.as_bool() &&
!self.invalidate_rendered_frame && !self.invalidate_rendered_frame &&
self.scene_ops.is_empty() && self.scene_ops.is_empty() &&
self.frame_ops.is_empty() && self.frame_ops.is_empty() &&
@@ -1230,7 +1264,7 @@ impl RenderApi {
frame_ops: vec![msg], frame_ops: vec![msg],
resource_updates: Vec::new(), resource_updates: Vec::new(),
notifications: Vec::new(), notifications: Vec::new(),
generate_frame: false, generate_frame: GenerateFrame::No,
invalidate_rendered_frame: false, invalidate_rendered_frame: false,
use_scene_builder_thread: false, use_scene_builder_thread: false,
low_priority: false, low_priority: false,
@@ -1249,7 +1283,7 @@ impl RenderApi {
frame_ops: Vec::new(), frame_ops: Vec::new(),
resource_updates: Vec::new(), resource_updates: Vec::new(),
notifications: Vec::new(), notifications: Vec::new(),
generate_frame: false, generate_frame: GenerateFrame::No,
invalidate_rendered_frame: false, invalidate_rendered_frame: false,
use_scene_builder_thread: false, use_scene_builder_thread: false,
low_priority: false, low_priority: false,
@@ -1287,7 +1321,7 @@ impl RenderApi {
self.resources.update(&mut transaction); self.resources.update(&mut transaction);
transaction.use_scene_builder_thread |= !transaction.scene_ops.is_empty(); transaction.use_scene_builder_thread |= !transaction.scene_ops.is_empty();
if transaction.generate_frame { if transaction.generate_frame.as_bool() {
transaction.profile.start_time(profiler::API_SEND_TIME); transaction.profile.start_time(profiler::API_SEND_TIME);
transaction.profile.start_time(profiler::TOTAL_FRAME_CPU_TIME); transaction.profile.start_time(profiler::TOTAL_FRAME_CPU_TIME);
} }
@@ -1312,7 +1346,7 @@ impl RenderApi {
.map(|(txn, id)| { .map(|(txn, id)| {
let mut txn = txn.finalize(id); let mut txn = txn.finalize(id);
self.resources.update(&mut txn); self.resources.update(&mut txn);
if txn.generate_frame { if txn.generate_frame.as_bool() {
txn.profile.start_time(profiler::API_SEND_TIME); txn.profile.start_time(profiler::API_SEND_TIME);
txn.profile.start_time(profiler::TOTAL_FRAME_CPU_TIME); txn.profile.start_time(profiler::TOTAL_FRAME_CPU_TIME);
} }

View File

@@ -1010,6 +1010,7 @@ impl RenderBackend {
txn.frame_ops.take(), txn.frame_ops.take(),
txn.notifications.take(), txn.notifications.take(),
txn.render_frame, txn.render_frame,
None,
txn.invalidate_rendered_frame, txn.invalidate_rendered_frame,
frame_counter, frame_counter,
has_built_scene, has_built_scene,
@@ -1347,7 +1348,7 @@ impl RenderBackend {
let mut built_frame = false; let mut built_frame = false;
for mut txn in txns { for mut txn in txns {
if txn.generate_frame { if txn.generate_frame.as_bool() {
txn.profile.end_time(profiler::API_SEND_TIME); txn.profile.end_time(profiler::API_SEND_TIME);
} }
@@ -1358,7 +1359,8 @@ impl RenderBackend {
txn.resource_updates.take(), txn.resource_updates.take(),
txn.frame_ops.take(), txn.frame_ops.take(),
txn.notifications.take(), txn.notifications.take(),
txn.generate_frame, txn.generate_frame.as_bool(),
txn.generate_frame.id(),
txn.invalidate_rendered_frame, txn.invalidate_rendered_frame,
frame_counter, frame_counter,
false false
@@ -1395,6 +1397,7 @@ impl RenderBackend {
Vec::default(), Vec::default(),
Vec::default(), Vec::default(),
false, false,
None,
false, false,
frame_counter, frame_counter,
false); false);
@@ -1414,6 +1417,7 @@ impl RenderBackend {
mut frame_ops: Vec<FrameMsg>, mut frame_ops: Vec<FrameMsg>,
mut notifications: Vec<NotificationRequest>, mut notifications: Vec<NotificationRequest>,
mut render_frame: bool, mut render_frame: bool,
generated_frame_id: Option<u64>,
invalidate_rendered_frame: bool, invalidate_rendered_frame: bool,
frame_counter: &mut u32, frame_counter: &mut u32,
has_built_scene: bool, has_built_scene: bool,
@@ -1430,7 +1434,7 @@ impl RenderBackend {
// async transforms. // async transforms.
if requested_frame || has_built_scene { if requested_frame || has_built_scene {
if let Some(ref sampler) = self.sampler { if let Some(ref sampler) = self.sampler {
frame_ops.append(&mut sampler.sample(document_id, frame_ops.append(&mut sampler.sample(document_id, generated_frame_id,
&doc.scene.pipeline_epochs)); &doc.scene.pipeline_epochs));
} }
} }

View File

@@ -6907,7 +6907,7 @@ pub trait AsyncPropertySampler {
/// This is called for each transaction with the generate_frame flag set /// This is called for each transaction with the generate_frame flag set
/// (i.e. that will trigger a render). The list of frame messages returned /// (i.e. that will trigger a render). The list of frame messages returned
/// are processed as though they were part of the original transaction. /// are processed as though they were part of the original transaction.
fn sample(&self, document_id: DocumentId, fn sample(&self, document_id: DocumentId, generated_frame_id: Option<u64>,
doc: &FastHashMap<PipelineId, Epoch>) -> Vec<FrameMsg>; doc: &FastHashMap<PipelineId, Epoch>) -> Vec<FrameMsg>;
/// This is called exactly once, when the render backend thread is about to /// This is called exactly once, when the render backend thread is about to
/// terminate. /// terminate.

View File

@@ -687,7 +687,7 @@ impl SceneBuilderThread {
Box::new(BuiltTransaction { Box::new(BuiltTransaction {
document_id: txn.document_id, document_id: txn.document_id,
render_frame: txn.generate_frame, render_frame: txn.generate_frame.as_bool(),
invalidate_rendered_frame: txn.invalidate_rendered_frame, invalidate_rendered_frame: txn.invalidate_rendered_frame,
built_scene, built_scene,
view: doc.view, view: doc.view,

View File

@@ -107,7 +107,7 @@ impl<'a> RawtestHarness<'a> {
); );
epoch.0 += 1; epoch.0 += 1;
txn.generate_frame(); txn.generate_frame(0);
self.wrench.api.send_transaction(self.wrench.document_id, txn); self.wrench.api.send_transaction(self.wrench.document_id, txn);
} }
@@ -1239,7 +1239,7 @@ impl<'a> RawtestHarness<'a> {
builder.finalize(), builder.finalize(),
false, false,
); );
txn.generate_frame(); txn.generate_frame(0);
self.wrench.api.send_transaction(self.wrench.document_id, txn); self.wrench.api.send_transaction(self.wrench.document_id, txn);
@@ -1274,7 +1274,7 @@ impl<'a> RawtestHarness<'a> {
// 6. rebuild the scene and compare again // 6. rebuild the scene and compare again
let mut txn = Transaction::new(); let mut txn = Transaction::new();
txn.set_root_pipeline(captured.root_pipeline_id.unwrap()); txn.set_root_pipeline(captured.root_pipeline_id.unwrap());
txn.generate_frame(); txn.generate_frame(0);
self.wrench.api.send_transaction(captured.document_id, txn); self.wrench.api.send_transaction(captured.document_id, txn);
let pixels2 = self.render_and_get_pixels(window_rect); let pixels2 = self.render_and_get_pixels(window_rect);
self.compare_pixels(pixels0, pixels2, window_rect.size); self.compare_pixels(pixels0, pixels2, window_rect.size);
@@ -1305,7 +1305,7 @@ impl<'a> RawtestHarness<'a> {
builder.finalize(), builder.finalize(),
false, false,
); );
txn.generate_frame(); txn.generate_frame(0);
self.wrench.api.send_transaction(doc_id, txn); self.wrench.api.send_transaction(doc_id, txn);
// Ensure we get a notification from rendering the above, even though // Ensure we get a notification from rendering the above, even though

View File

@@ -606,7 +606,7 @@ impl Wrench {
txn.scroll_node_with_id(*offset, *id, ScrollClamping::NoClamping); txn.scroll_node_with_id(*offset, *id, ScrollClamping::NoClamping);
} }
txn.generate_frame(); txn.generate_frame(0);
self.api.send_transaction(self.document_id, txn); self.api.send_transaction(self.document_id, txn);
} }
@@ -627,7 +627,7 @@ impl Wrench {
pub fn refresh(&mut self) { pub fn refresh(&mut self) {
self.begin_frame(); self.begin_frame();
let mut txn = Transaction::new(); let mut txn = Transaction::new();
txn.generate_frame(); txn.generate_frame(0);
self.api.send_transaction(self.document_id, txn); self.api.send_transaction(self.document_id, txn);
} }