/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifdef XP_WIN # include "mozilla/gfx/DeviceManagerDx.h" # include "mozilla/widget/WinCompositorWidget.h" #endif #ifdefined(MOZ_WIDGET_GTK) # include "mozilla/widget/GtkCompositorWidget.h" #endif
class WebRenderBridgeParent::ScheduleSharedSurfaceRelease final
: public wr::NotificationHandler { public: explicit ScheduleSharedSurfaceRelease(WebRenderBridgeParent* aWrBridge)
: mWrBridge(aWrBridge), mSurfaces(20) {}
class MOZ_STACK_CLASS AutoWebRenderBridgeParentAsyncMessageSender final { public: explicit AutoWebRenderBridgeParentAsyncMessageSender(
WebRenderBridgeParent* aWebRenderBridgeParent,
nsTArray<OpDestroy>* aDestroyActors = nullptr)
: mWebRenderBridgeParent(aWebRenderBridgeParent),
mActorsToDestroy(aDestroyActors) {
mWebRenderBridgeParent->SetAboutToSendAsyncMessages();
}
~AutoWebRenderBridgeParentAsyncMessageSender() {
mWebRenderBridgeParent->SendPendingAsyncMessages(); if (mActorsToDestroy) { // Destroy the actors after sending the async messages because the latter // may contain references to some actors. for (constauto& op : *mActorsToDestroy) {
mWebRenderBridgeParent->DestroyActor(op);
}
}
}
mAsyncImageManager->AddPipeline(mPipelineId, this); if (IsRootWebRenderBridgeParent()) {
MOZ_ASSERT(!mCompositorScheduler);
mCompositorScheduler = new CompositorVsyncScheduler(this, mWidget);
UpdateDebugFlags();
UpdateQualitySettings();
UpdateProfilerUI();
UpdateParameters(); // Start with the cached bool parameter bits inverted so that we update them // all.
mBoolParameterBits = ~gfxVars::WebRenderBoolParameters();
UpdateBoolParameters();
}
mRemoteTextureTxnScheduler =
RemoteTextureTxnScheduler::Create(aCompositorBridge);
}
staticbool ReadRawFont(const OpAddRawFont& aOp, wr::ShmSegmentsReader& aReader,
wr::TransactionBuilder& aUpdates) {
wr::Vec<uint8_t> sourceBytes;
Maybe<Range<uint8_t>> ptr =
aReader.GetReadPointerOrCopy(aOp.bytes(), sourceBytes); if (ptr.isNothing()) {
gfxCriticalNote << "No read pointer from reader for sanitizing font "
<< aOp.key().mHandle; returnfalse;
}
Range<uint8_t>& source = ptr.ref(); // Attempt to sanitize the font before passing it along for updating. // Ensure that we're not strict here about font types, since any font that // failed generating a descriptor might end up here as raw font data.
size_t lengthHint = gfxOTSContext::GuessSanitizedFontSize(
source.begin().get(), source.length(), false); if (!lengthHint) {
gfxCriticalNote << "Could not determine font type for sanitizing font "
<< aOp.key().mHandle; returnfalse;
}
gfxOTSExpandingMemoryStream<WROTSAlloc> output(lengthHint);
gfxOTSContext otsContext; if (!otsContext.Process(&output, source.begin().get(), source.length())) {
gfxCriticalNote << "Failed sanitizing font " << aOp.key().mHandle; returnfalse;
}
wr::Vec<uint8_t> bytes = output.forget();
while (GPUParent::MaybeFlushMemory()) { // If the GPU process has memory pressure, preemptively unmap some of our // shared memory images. If we are in the parent process, the expiration // tracker itself will listen for the memory pressure event. if (!SharedSurfacesParent::AgeAndExpireOneGeneration()) { break;
}
}
bool success = true; for (constauto& cmd : aResourceUpdates) { switch (cmd.type()) { case OpUpdateResource::TOpAddImage: { constauto& op = cmd.get_OpAddImage(); if (!MatchesNamespace(op.key())) {
MOZ_ASSERT_UNREACHABLE("Stale image key (add)!"); break;
}
wr::Vec<uint8_t> bytes; if (reader.Read(op.bytes(), bytes)) {
aUpdates.AddImage(op.key(), op.descriptor(), bytes);
} else {
gfxCriticalNote << "TOpAddImage failed";
success = false;
} break;
} case OpUpdateResource::TOpUpdateImage: { constauto& op = cmd.get_OpUpdateImage(); if (!MatchesNamespace(op.key())) {
MOZ_ASSERT_UNREACHABLE("Stale image key (update)!"); break;
}
wr::Vec<uint8_t> bytes; if (reader.Read(op.bytes(), bytes)) {
aUpdates.UpdateImageBuffer(op.key(), op.descriptor(), bytes);
} else {
gfxCriticalNote << "TOpUpdateImage failed";
success = false;
} break;
} case OpUpdateResource::TOpAddBlobImage: { constauto& op = cmd.get_OpAddBlobImage(); if (!MatchesNamespace(op.key())) {
MOZ_ASSERT_UNREACHABLE("Stale blob image key (add)!"); break;
}
break;
} case OpUpdateResource::TOpUpdateBlobImage: { constauto& op = cmd.get_OpUpdateBlobImage(); if (!MatchesNamespace(op.key())) {
MOZ_ASSERT_UNREACHABLE("Stale blob image key (update)!"); break;
}
wr::Vec<uint8_t> bytes; if (reader.Read(op.bytes(), bytes)) {
aUpdates.UpdateBlobImage(op.key(), op.descriptor(), bytes,
wr::ToDeviceIntRect(op.visibleRect()),
wr::ToLayoutIntRect(op.dirtyRect()));
} else {
gfxCriticalNote << "TOpUpdateBlobImage failed";
success = false;
} break;
} case OpUpdateResource::TOpSetBlobImageVisibleArea: { constauto& op = cmd.get_OpSetBlobImageVisibleArea(); if (!MatchesNamespace(op.key())) {
MOZ_ASSERT_UNREACHABLE("Stale blob image key (visible)!"); break;
}
aUpdates.SetBlobImageVisibleArea(op.key(),
wr::ToDeviceIntRect(op.area())); break;
} case OpUpdateResource::TOpAddSharedExternalImage: { constauto& op = cmd.get_OpAddSharedExternalImage(); // gfxCriticalNote is called on error if (!AddSharedExternalImage(op.externalImageId(), op.key(), aUpdates)) {
success = false;
} break;
} case OpUpdateResource::TOpPushExternalImageForTexture: { constauto& op = cmd.get_OpPushExternalImageForTexture();
CompositableTextureHostRef texture;
texture = TextureHost::AsTextureHost(op.texture().AsParent()); // gfxCriticalNote is called on error if (!PushExternalImageForTexture(op.externalImageId(), op.key(),
texture, op.isUpdate(), aUpdates)) {
success = false;
} break;
} case OpUpdateResource::TOpUpdateSharedExternalImage: { constauto& op = cmd.get_OpUpdateSharedExternalImage(); // gfxCriticalNote is called on error if (!UpdateSharedExternalImage(op.externalImageId(), op.key(),
op.dirtyRect(), aUpdates,
scheduleRelease)) {
success = false;
} break;
} case OpUpdateResource::TOpAddRawFont: { if (!ReadRawFont(cmd.get_OpAddRawFont(), reader, aUpdates)) {
success = false;
} break;
} case OpUpdateResource::TOpAddFontDescriptor: { constauto& op = cmd.get_OpAddFontDescriptor(); if (!MatchesNamespace(op.key())) {
MOZ_ASSERT_UNREACHABLE("Stale font key (add descriptor)!"); break;
}
wr::Vec<uint8_t> bytes; if (reader.Read(op.bytes(), bytes)) {
aUpdates.AddFontDescriptor(op.key(), bytes, op.fontIndex());
} else {
gfxCriticalNote << "TOpAddFontDescriptor failed";
success = false;
} break;
} case OpUpdateResource::TOpAddFontInstance: { constauto& op = cmd.get_OpAddFontInstance(); if (!MatchesNamespace(op.instanceKey()) ||
!MatchesNamespace(op.fontKey())) {
MOZ_ASSERT_UNREACHABLE("Stale font key (add instance)!"); break;
}
wr::Vec<uint8_t> variations; if (reader.Read(op.variations(), variations)) {
aUpdates.AddFontInstance(op.instanceKey(), op.fontKey(),
op.glyphSize(), op.options().ptrOr(nullptr),
op.platformOptions().ptrOr(nullptr),
variations);
} else {
gfxCriticalNote << "TOpAddFontInstance failed";
success = false;
} break;
} case OpUpdateResource::TOpDeleteImage: { constauto& op = cmd.get_OpDeleteImage(); if (!MatchesNamespace(op.key())) { // TODO(aosmond): We should also assert here, but the callers are less // careful about checking when cleaning up their old keys. We should // perform an audit on image key usage. break;
}
DeleteImage(op.key(), aUpdates); break;
} case OpUpdateResource::TOpDeleteBlobImage: { constauto& op = cmd.get_OpDeleteBlobImage(); if (!MatchesNamespace(op.key())) {
MOZ_ASSERT_UNREACHABLE("Stale blob image key (delete)!"); break;
}
aUpdates.DeleteBlobImage(op.key()); break;
} case OpUpdateResource::TOpDeleteFont: { constauto& op = cmd.get_OpDeleteFont(); if (!MatchesNamespace(op.key())) {
MOZ_ASSERT_UNREACHABLE("Stale font key (delete)!"); break;
}
aUpdates.DeleteFont(op.key()); break;
} case OpUpdateResource::TOpDeleteFontInstance: { constauto& op = cmd.get_OpDeleteFontInstance(); if (!MatchesNamespace(op.key())) {
MOZ_ASSERT_UNREACHABLE("Stale font instance key (delete)!"); break;
}
aUpdates.DeleteFontInstance(op.key()); break;
} case OpUpdateResource::T__None: break;
}
}
if (scheduleRelease) { // When software WR is enabled, shared surfaces are read during rendering // rather than copied to the texture cache.
wr::Checkpoint when = mApi->GetBackendType() == WebRenderBackend::SOFTWARE
? wr::Checkpoint::FrameRendered
: wr::Checkpoint::FrameTexturesUpdated;
aUpdates.Notify(when, std::move(scheduleRelease));
}
auto key = wr::AsUint64(aKey); auto it = mSharedSurfaceIds.find(key); if (it != mSharedSurfaceIds.end()) {
gfxCriticalNote << "Readding known shared surface: " << key; returnfalse;
}
RefPtr<DataSourceSurface> dSurf = SharedSurfacesParent::Acquire(aExtId); if (!dSurf) {
gfxCriticalNote
<< "DataSourceSurface of SharedSurfaces does not exist for extId:"
<< wr::AsUint64(aExtId); returnfalse;
}
if (!aTexture) {
gfxCriticalNote << "TextureHost does not exist for extId:"
<< wr::AsUint64(aExtId); returnfalse;
}
auto op = aIsUpdate ? TextureHost::UPDATE_IMAGE : TextureHost::ADD_IMAGE;
WebRenderTextureHost* wrTexture = aTexture->AsWebRenderTextureHost(); if (wrTexture) {
Range<wr::ImageKey> keys(&aKey, 1);
wrTexture->PushResourceUpdates(aResources, op, keys,
wrTexture->GetExternalImageKey()); auto it = mTextureHosts.find(wr::AsUint64(aKey));
MOZ_ASSERT((it == mTextureHosts.end() && !aIsUpdate) ||
(it != mTextureHosts.end() && aIsUpdate)); if (it != mTextureHosts.end()) { // Release Texture if it exists.
ReleaseTextureOfImage(aKey);
}
mTextureHosts.emplace(wr::AsUint64(aKey),
CompositableTextureHostRef(aTexture)); returntrue;
}
RefPtr<DataSourceSurface> dSurf = aTexture->GetAsSurface(); if (!dSurf) {
gfxCriticalNote
<< "TextureHost does not return DataSourceSurface for extId:"
<< wr::AsUint64(aExtId); returnfalse;
}
DataSourceSurface::MappedSurface map; if (!dSurf->Map(gfx::DataSourceSurface::MapType::READ, &map)) {
gfxCriticalNote << "DataSourceSurface failed to map for Image for extId:"
<< wr::AsUint64(aExtId); returnfalse;
}
if (!dSurf) {
gfxCriticalNote << "Shared surface does not exist for extId:"
<< wr::AsUint64(aExtId); returnfalse;
}
if (!(it->second == aExtId)) { // We already have a mapping for this image key, so ensure we release the // previous external image ID. This can happen when an image is animated, // and it is changing the external image that the animation points to. if (!aScheduleRelease) {
aScheduleRelease = MakeUnique<ScheduleSharedSurfaceRelease>(this);
}
aScheduleRelease->Add(aKey, it->second);
it->second = aExtId;
}
if (!aFromCheckpoint && mAsyncImageManager) { // We failed to receive a checkpoint notification, so we are releasing these // surfaces blind. Let's wait until the next epoch to complete releasing. for (constauto& pair : aPairs) {
mAsyncImageManager->HoldExternalImage(mPipelineId, mWrEpoch, pair.id);
} return;
}
// We hit the checkpoint, so we know we can safely release the surfaces now. for (constauto& pair : aPairs) {
SharedSurfacesParent::Release(pair.id);
}
}
// Even when txn.IsResourceUpdatesEmpty() is true, there could be resource // updates. It is handled by WebRenderTextureHostWrapper. In this case // txn.IsRenderedFrameInvalidated() becomes true. if (!txn.IsResourceUpdatesEmpty() || txn.IsRenderedFrameInvalidated()) { // There are resource updates, then we update Epoch of transaction.
txn.UpdateEpoch(mPipelineId, mWrEpoch);
mAsyncImageManager->SetWillGenerateFrame();
ScheduleGenerateFrame(wr::RenderReasons::RESOURCE_UPDATE);
} else { // If TransactionBuilder does not have resource updates nor display list, // ScheduleGenerateFrame is not triggered via SceneBuilder and there is no // need to update WrEpoch. // Then we want to rollback WrEpoch. See Bug 1490117.
RollbackWrEpoch();
}
mApi->SendTransaction(txn);
if (!success) { return IPC_FAIL(this, "Invalid WebRender resource data shmem or address.");
}
// Once mWrEpoch has been rendered, we can delete these compositor animations
mCompositorAnimationsToDelete.push(
CompositorAnimationIdsForEpoch(mWrEpoch, std::move(aIds))); return IPC_OK();
}
CompositorBridgeParent* WebRenderBridgeParent::GetRootCompositorBridgeParent() const { if (!mCompositorBridge) { return nullptr;
}
if (IsRootWebRenderBridgeParent()) { // This WebRenderBridgeParent is attached to the root // CompositorBridgeParent. returnstatic_cast<CompositorBridgeParent*>(mCompositorBridge);
}
// Otherwise, this WebRenderBridgeParent is attached to a // ContentCompositorBridgeParent so we have an extra level of // indirection to unravel.
CompositorBridgeParent::LayerTreeState* lts =
CompositorBridgeParent::GetIndirectShadowTree(GetLayersId()); if (!lts) { return nullptr;
} return lts->mParent;
}
void WebRenderBridgeParent::SetAPZSampleTime() {
CompositorBridgeParent* cbp = GetRootCompositorBridgeParent(); if (!cbp) { return;
} if (RefPtr<APZSampler> apz = cbp->GetAPZSampler()) {
SampleTime animationTime; if (Maybe<TimeStamp> testTime = cbp->GetTestingTimeStamp()) {
animationTime = SampleTime::FromTest(*testTime);
} else {
animationTime = mCompositorScheduler->GetLastComposeTime();
}
TimeDuration frameInterval = cbp->GetVsyncInterval(); // As with the non-webrender codepath in AsyncCompositionManager, we want to // use the timestamp for the next vsync when advancing animations. if (frameInterval != TimeDuration::Forever()) {
animationTime = animationTime + frameInterval;
}
apz->SetSampleTime(animationTime);
}
}
if (aDisplayList.mScrollData && !aDisplayList.mScrollData->Validate()) { // If the scroll data is invalid, the entire transaction needs to be dropped // because the scroll data and the display list cross-reference each other.
MOZ_ASSERT( false, "Content sent malformed scroll data (or validation check has a bug)");
aValidTransaction = false;
}
// Note that this needs to happen before the display list transaction is // sent to WebRender, so that the UpdateHitTestingTree call is guaranteed to // be in the updater queue at the time that the scene swap completes. if (aDisplayList.mScrollData) {
UpdateAPZScrollData(aWrEpoch, std::move(aDisplayList.mScrollData.ref()));
}
// This ensures that destroy operations are always processed. It is not safe // to early-return from RecvDPEnd without doing so.
AutoWebRenderBridgeParentAsyncMessageSender autoAsyncMessageSender( this, &aToDestroy);
wr::Epoch wrEpoch = GetNextWrEpoch();
mReceivedDisplayList = true;
if (aDisplayList.mScrollData && aDisplayList.mScrollData->IsFirstPaint()) {
mIsFirstPaint = true;
}
if (!validTransaction) { // Pretend we composited since someone is wating for this event, // though DisplayList was not pushed to webrender. if (CompositorBridgeParent* cbp = GetRootCompositorBridgeParent()) {
TimeStamp now = TimeStamp::Now();
cbp->NotifyPipelineRendered(mPipelineId, wrEpoch, VsyncId(), now, now,
now);
}
}
if (!aData.mScrollUpdates.IsEmpty()) {
UpdateAPZScrollOffsets(std::move(aData.mScrollUpdates),
aData.mPaintSequenceNumber);
}
// Update WrEpoch for UpdateResources() and ProcessWebRenderParentCommands(). // WrEpoch is used to manage ExternalImages lifetimes in // AsyncImagePipelineManager.
Unused << GetNextWrEpoch();
if (validTransaction) {
success = UpdateResources(aData.mResourceUpdates, aData.mSmallShmems,
aData.mLargeShmems, txn); if (!aData.mCommands.IsEmpty()) {
success = ProcessWebRenderParentCommands(aData.mCommands, txn) && success;
}
}
MaybeNotifyOfLayers(txn, true);
// Even when txn.IsResourceUpdatesEmpty() is true, there could be resource // updates. It is handled by WebRenderTextureHostWrapper. In this case // txn.IsRenderedFrameInvalidated() becomes true. if (!txn.IsResourceUpdatesEmpty() || txn.IsRenderedFrameInvalidated()) { // There are resource updates, then we update Epoch of transaction.
txn.UpdateEpoch(mPipelineId, mWrEpoch);
*aScheduleComposite = true;
NeedIncreasedMaxDirtyPageModifier();
} else { // If TransactionBuilder does not have resource updates nor display list, // ScheduleGenerateFrame is not triggered via SceneBuilder and there is no // need to update WrEpoch. // Then we want to rollback WrEpoch. See Bug 1490117.
RollbackWrEpoch();
}
if (!txn.IsEmpty()) {
mApi->SendTransaction(txn);
}
if (*aScheduleComposite) {
mAsyncImageManager->SetWillGenerateFrame();
}
// This ensures that destroy operations are always processed. It is not safe // to early-return without doing so.
AutoWebRenderBridgeParentAsyncMessageSender autoAsyncMessageSender( this, &aToDestroy);
// If we are going to kick off a new composite as a result of this // transaction, or if there are already composite-triggering pending // transactions inflight, then set sendDidComposite to false because we will // send the DidComposite message after the composite occurs. // If there are no pending transactions and we're not going to do a // composite, then we leave sendDidComposite as true so we just send // the DidComposite notification now. bool sendDidComposite =
!scheduleAnyComposite && mPendingTransactionIds.empty();
// Only register a value for CONTENT_FRAME_TIME telemetry if we actually drew // something. It is for consistency with disabling WebRender.
HoldPendingTransactionId(mWrEpoch, aTransactionId, false, aVsyncId,
aVsyncStartTime, aRefreshStartTime, aTxnStartTime,
aTxnURL, aFwdTime, /* aIsFirstPaint */ false, std::move(aPayloads), /* aUseForTelemetry */ scheduleAnyComposite);
if (scheduleAnyComposite) {
ScheduleGenerateFrame(renderReasons);
} elseif (sendDidComposite) { // The only thing in the pending transaction id queue should be the entry // we just added, and now we're going to pretend we rendered it
MOZ_ASSERT(mPendingTransactionIds.size() == 1); if (CompositorBridgeParent* cbp = GetRootCompositorBridgeParent()) {
TimeStamp now = TimeStamp::Now();
cbp->NotifyPipelineRendered(mPipelineId, mWrEpoch, VsyncId(), now, now,
now);
}
}
if (aTransactionData) {
wr::IpcResourceUpdateQueue::ReleaseShmems(this,
aTransactionData->mSmallShmems);
wr::IpcResourceUpdateQueue::ReleaseShmems(this,
aTransactionData->mLargeShmems);
}
if (!success) { return IPC_FAIL(this, "Failed to process empty transaction update.");
}
if (!success) { return IPC_FAIL(this, "Invalid parent command found");
}
return IPC_OK();
}
bool WebRenderBridgeParent::ProcessWebRenderParentCommands( const nsTArray<WebRenderParentCommand>& aCommands,
wr::TransactionBuilder& aTxn) { // Transaction for async image pipeline that uses ImageBridge always need to // be non low priority.
wr::TransactionBuilder txnForImageBridge(mApi->GetRootAPI());
wr::AutoTransactionSender sender(mApi->GetRootAPI(), &txnForImageBridge);
bool success = true; for (nsTArray<WebRenderParentCommand>::index_type i = 0;
i < aCommands.Length(); ++i) { const WebRenderParentCommand& cmd = aCommands[i]; switch (cmd.type()) { case WebRenderParentCommand::TOpAddPipelineIdForCompositable: { const OpAddPipelineIdForCompositable& op =
cmd.get_OpAddPipelineIdForCompositable();
AddPipelineIdForCompositable(op.pipelineId(), op.handle(), op.owner(),
aTxn, txnForImageBridge); break;
} case WebRenderParentCommand::TOpRemovePipelineIdForCompositable: { const OpRemovePipelineIdForCompositable& op =
cmd.get_OpRemovePipelineIdForCompositable(); auto* pendingOps = mApi->GetPendingAsyncImagePipelineOps(aTxn);
RemovePipelineIdForCompositable(op.pipelineId(), pendingOps, aTxn); break;
} case WebRenderParentCommand::TOpReleaseTextureOfImage: { const OpReleaseTextureOfImage& op = cmd.get_OpReleaseTextureOfImage();
ReleaseTextureOfImage(op.key()); break;
} case WebRenderParentCommand::TOpUpdateAsyncImagePipeline: { const OpUpdateAsyncImagePipeline& op =
cmd.get_OpUpdateAsyncImagePipeline();
// Since we are sending transactions through the scene builder thread, we need // to block until all the inflight transactions have been processed. This // flush message blocks until all previously sent scenes have been built // and received by the render backend thread.
mApi->FlushSceneBuilder(); // The post-swap hook for async-scene-building calls the // ScheduleRenderOnCompositorThread function from the scene builder thread, // which then triggers a call to ScheduleGenerateFrame() on the compositor // thread. But since *this* function is running on the compositor thread, // that scheduling will not happen until this call stack unwinds (or we // could spin a nested event loop, but that's more messy). Instead, we // simulate it ourselves by calling ScheduleGenerateFrame() directly. // Note also that the post-swap hook will run and do another // ScheduleGenerateFrame() after we unwind here, so we will end up with an // extra render/composite that is probably avoidable, but in practice we // shouldn't be calling this function all that much in production so this // is probably fine. If it becomes an issue we can add more state tracking // machinery to optimize it away.
ScheduleGenerateFrame(wr::RenderReasons::FLUSH);
}
void WebRenderBridgeParent::FlushFrameGeneration(wr::RenderReasons aReasons) {
MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
MOZ_ASSERT(IsRootWebRenderBridgeParent()); // This function is only useful on // the root WRBP
// This forces a new GenerateFrame transaction to be sent to the render // backend thread, if one is pending. This doesn't block on any other threads. if (mCompositorScheduler->NeedsComposite()) {
mCompositorScheduler->CancelCurrentCompositeTask(); // Update timestamp of scheduler for APZ and animation.
mCompositorScheduler->UpdateLastComposeTime();
MaybeGenerateFrame(VsyncId(), /* aForceGenerateFrame */ true,
aReasons | wr::RenderReasons::FLUSH);
}
}
// This sends a message to the render backend thread to send a message // to the renderer thread, and waits for that message to be processed. So // this effectively blocks on the render backend and renderer threads, // following the same codepath that WebRender takes to render and composite // a frame.
mApi->WaitFlushed();
}
void WebRenderBridgeParent::DisableNativeCompositor() { // Make sure that SceneBuilder thread does not have a task.
mApi->FlushSceneBuilder(); // Disable WebRender's native compositor usage
mApi->EnableNativeCompositor(false); // Ensure we generate and render a frame immediately.
ScheduleForcedGenerateFrame(wr::RenderReasons::CONFIG_CHANGE);
mDisablingNativeCompositor = true;
}
void WebRenderBridgeParent::UpdateQualitySettings() { if (!IsRootWebRenderBridgeParent()) {
MOZ_ASSERT_UNREACHABLE("unexpected to be called"); return;
}
wr::TransactionBuilder txn(mApi);
txn.UpdateQualitySettings(gfxVars::ForceSubpixelAAWherePossible());
mApi->SendTransaction(txn);
}
void WebRenderBridgeParent::UpdateDebugFlags() { if (!IsRootWebRenderBridgeParent()) {
MOZ_ASSERT_UNREACHABLE("unexpected to be called"); return;
}
void WebRenderBridgeParent::UpdateBoolParameters() { if (!IsRootWebRenderBridgeParent()) {
MOZ_ASSERT_UNREACHABLE("unexpected to be called"); return;
}
void WebRenderBridgeParent::MaybeCaptureScreenPixels() { if (!mScreenPixelsTarget) { return;
}
if (mDestroyed) { return;
}
if (auto* cbp = GetRootCompositorBridgeParent()) {
cbp->FlushPendingWrTransactionEventsWithWait();
}
// This function should only get called in the root WRBP.
MOZ_ASSERT(IsRootWebRenderBridgeParent()); # ifdef DEBUG
CompositorBridgeParent* cbp = GetRootCompositorBridgeParent();
MOZ_ASSERT(cbp && !cbp->IsPaused()); # endif
SurfaceFormat format = SurfaceFormat::R8G8B8A8; // On android we use RGBA8 auto client_size = mWidget->GetClientSize();
size_t buffer_size =
client_size.width * client_size.height * BytesPerPixel(format);
ipc::Shmem mem; if (!mScreenPixelsTarget->AllocPixelBuffer(buffer_size, &mem)) { // Failed to alloc shmem, Just bail out. return;
}
// This function should only get called in the root WRBP. If this function // gets called in a non-root WRBP, we will set mForceRendering in this WRBP // but it will have no effect because CompositeToTarget (which reads the // flag) only gets invoked in the root WRBP. So we assert that this is the // root WRBP (i.e. has a non-null mWidget) to catch violations of this rule.
MOZ_ASSERT(IsRootWebRenderBridgeParent());
RefPtr<TextureHost> texture = TextureHost::AsTextureHost(aTexture); if (!texture) { // We kill the content process rather than have it continue with an invalid // snapshot, that may be too harsh and we could decide to return some sort // of error to the child process and let it deal with it... return IPC_FAIL_NO_REASON(this);
}
// XXX Add other TextureHost supports. // Only BufferTextureHost is supported now.
BufferTextureHost* bufferTexture = texture->AsBufferTextureHost(); if (!bufferTexture) { // We kill the content process rather than have it continue with an invalid // snapshot, that may be too harsh and we could decide to return some sort // of error to the child process and let it deal with it... return IPC_FAIL_NO_REASON(this);
}
MOZ_ASSERT(buffer); // For now the only formats we get here are RGBA and BGRA, and code below is // assuming a bpp of 4. If we allow other formats, the code needs adjusting // accordingly.
MOZ_ASSERT(BytesPerPixel(bufferTexture->GetFormat()) == 4);
uint32_t buffer_size = size.width * size.height * 4;
// Assert the stride of the buffer is what webrender expects
MOZ_ASSERT((uint32_t)(size.width * 4) == stride);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.