зеркало из https://github.com/mozilla/gecko-dev.git
1686 строки
63 KiB
C++
1686 строки
63 KiB
C++
/* -*- 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/. */
|
|
|
|
#include "WebRenderAPI.h"
|
|
|
|
#include "mozilla/StaticPrefs_gfx.h"
|
|
#include "mozilla/ipc/ByteBuf.h"
|
|
#include "mozilla/webrender/RendererOGL.h"
|
|
#include "mozilla/gfx/gfxVars.h"
|
|
#include "mozilla/layers/CompositorThread.h"
|
|
#include "mozilla/ToString.h"
|
|
#include "mozilla/webrender/RenderCompositor.h"
|
|
#include "mozilla/widget/CompositorWidget.h"
|
|
#include "mozilla/layers/SynchronousTask.h"
|
|
#include "TextDrawTarget.h"
|
|
#include "malloc_decls.h"
|
|
#include "GLContext.h"
|
|
|
|
// clang-format off
|
|
#define WRDL_LOG(...)
|
|
//#define WRDL_LOG(...) printf_stderr("WRDL(%p): " __VA_ARGS__)
|
|
//#define WRDL_LOG(...) if (XRE_IsContentProcess()) printf_stderr("WRDL(%p): " __VA_ARGS__)
|
|
// clang-format on
|
|
|
|
namespace mozilla {
|
|
using namespace layers;
|
|
|
|
namespace wr {
|
|
|
|
MOZ_DEFINE_MALLOC_SIZE_OF(WebRenderMallocSizeOf)
|
|
MOZ_DEFINE_MALLOC_ENCLOSING_SIZE_OF(WebRenderMallocEnclosingSizeOf)
|
|
|
|
class NewRenderer : public RendererEvent {
|
|
public:
|
|
NewRenderer(wr::DocumentHandle** aDocHandle,
|
|
layers::CompositorBridgeParent* aBridge,
|
|
WebRenderBackend* aBackend, WebRenderCompositor* aCompositor,
|
|
int32_t* aMaxTextureSize, bool* aUseANGLE, bool* aUseDComp,
|
|
bool* aUseTripleBuffering, bool* aSupportsExternalBufferTextures,
|
|
RefPtr<widget::CompositorWidget>&& aWidget,
|
|
layers::SynchronousTask* aTask, LayoutDeviceIntSize aSize,
|
|
layers::WindowKind aWindowKind, layers::SyncHandle* aHandle,
|
|
nsACString* aError)
|
|
: mDocHandle(aDocHandle),
|
|
mBackend(aBackend),
|
|
mCompositor(aCompositor),
|
|
mMaxTextureSize(aMaxTextureSize),
|
|
mUseANGLE(aUseANGLE),
|
|
mUseDComp(aUseDComp),
|
|
mUseTripleBuffering(aUseTripleBuffering),
|
|
mSupportsExternalBufferTextures(aSupportsExternalBufferTextures),
|
|
mBridge(aBridge),
|
|
mCompositorWidget(std::move(aWidget)),
|
|
mTask(aTask),
|
|
mSize(aSize),
|
|
mWindowKind(aWindowKind),
|
|
mSyncHandle(aHandle),
|
|
mError(aError) {
|
|
MOZ_COUNT_CTOR(NewRenderer);
|
|
}
|
|
|
|
MOZ_COUNTED_DTOR(NewRenderer)
|
|
|
|
void Run(RenderThread& aRenderThread, WindowId aWindowId) override {
|
|
layers::AutoCompleteTask complete(mTask);
|
|
|
|
UniquePtr<RenderCompositor> compositor =
|
|
RenderCompositor::Create(std::move(mCompositorWidget), *mError);
|
|
if (!compositor) {
|
|
if (!mError->IsEmpty()) {
|
|
gfxCriticalNote << mError->BeginReading();
|
|
}
|
|
return;
|
|
}
|
|
|
|
compositor->MakeCurrent();
|
|
|
|
*mBackend = compositor->BackendType();
|
|
*mCompositor = compositor->CompositorType();
|
|
*mUseANGLE = compositor->UseANGLE();
|
|
*mUseDComp = compositor->UseDComp();
|
|
*mUseTripleBuffering = compositor->UseTripleBuffering();
|
|
*mSupportsExternalBufferTextures =
|
|
compositor->SupportsExternalBufferTextures();
|
|
|
|
// Only allow the panic on GL error functionality in nightly builds,
|
|
// since it (deliberately) crashes the GPU process if any GL call
|
|
// returns an error code.
|
|
bool panic_on_gl_error = false;
|
|
#ifdef NIGHTLY_BUILD
|
|
panic_on_gl_error =
|
|
StaticPrefs::gfx_webrender_panic_on_gl_error_AtStartup();
|
|
#endif
|
|
|
|
bool isMainWindow = true; // TODO!
|
|
bool supportLowPriorityTransactions = isMainWindow;
|
|
bool supportLowPriorityThreadpool =
|
|
supportLowPriorityTransactions &&
|
|
StaticPrefs::gfx_webrender_enable_low_priority_pool();
|
|
wr::Renderer* wrRenderer = nullptr;
|
|
char* errorMessage = nullptr;
|
|
int picTileWidth = StaticPrefs::gfx_webrender_picture_tile_width();
|
|
int picTileHeight = StaticPrefs::gfx_webrender_picture_tile_height();
|
|
auto* swgl = compositor->swgl();
|
|
auto* gl = (compositor->gl() && !swgl) ? compositor->gl() : nullptr;
|
|
auto* progCache = (aRenderThread.GetProgramCache() && !swgl)
|
|
? aRenderThread.GetProgramCache()->Raw()
|
|
: nullptr;
|
|
auto* shaders = (aRenderThread.GetShaders() && !swgl)
|
|
? aRenderThread.GetShaders()->RawShaders()
|
|
: nullptr;
|
|
|
|
// Check That if we are not using SWGL, we have at least a GL or GLES 3.0
|
|
// context.
|
|
if (gl && !swgl) {
|
|
bool versionCheck =
|
|
gl->IsAtLeast(gl::ContextProfile::OpenGLCore, 300) ||
|
|
gl->IsAtLeast(gl::ContextProfile::OpenGLCompatibility, 300) ||
|
|
gl->IsAtLeast(gl::ContextProfile::OpenGLES, 300);
|
|
|
|
if (!versionCheck) {
|
|
gfxCriticalNote << "GL context version (" << gl->Version()
|
|
<< ") insufficent for hardware WebRender";
|
|
|
|
mError->AssignASCII("GL context version insufficient");
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (!wr_window_new(
|
|
aWindowId, mSize.width, mSize.height,
|
|
mWindowKind == WindowKind::MAIN, supportLowPriorityTransactions,
|
|
supportLowPriorityThreadpool, gfx::gfxVars::UseGLSwizzle(),
|
|
gfx::gfxVars::UseWebRenderScissoredCacheClears(), swgl, gl,
|
|
compositor->SurfaceOriginIsTopLeft(), progCache, shaders,
|
|
aRenderThread.ThreadPool().Raw(),
|
|
aRenderThread.ThreadPoolLP().Raw(), &WebRenderMallocSizeOf,
|
|
&WebRenderMallocEnclosingSizeOf, 0, compositor.get(),
|
|
compositor->ShouldUseNativeCompositor(),
|
|
compositor->UsePartialPresent(),
|
|
compositor->GetMaxPartialPresentRects(),
|
|
compositor->ShouldDrawPreviousPartialPresentRegions(), mDocHandle,
|
|
&wrRenderer, mMaxTextureSize, &errorMessage,
|
|
StaticPrefs::gfx_webrender_enable_gpu_markers_AtStartup(),
|
|
panic_on_gl_error, picTileWidth, picTileHeight,
|
|
gfx::gfxVars::WebRenderRequiresHardwareDriver(),
|
|
StaticPrefs::gfx_webrender_low_quality_pinch_zoom_AtStartup())) {
|
|
// wr_window_new puts a message into gfxCriticalNote if it returns false
|
|
MOZ_ASSERT(errorMessage);
|
|
mError->AssignASCII(errorMessage);
|
|
wr_api_free_error_msg(errorMessage);
|
|
return;
|
|
}
|
|
MOZ_ASSERT(wrRenderer);
|
|
|
|
RefPtr<RenderThread> thread = &aRenderThread;
|
|
auto renderer =
|
|
MakeUnique<RendererOGL>(std::move(thread), std::move(compositor),
|
|
aWindowId, wrRenderer, mBridge);
|
|
if (wrRenderer && renderer) {
|
|
wr::WrExternalImageHandler handler = renderer->GetExternalImageHandler();
|
|
wr_renderer_set_external_image_handler(wrRenderer, &handler);
|
|
}
|
|
|
|
if (renderer) {
|
|
layers::SyncObjectHost* syncObj = renderer->GetSyncObject();
|
|
if (syncObj) {
|
|
*mSyncHandle = syncObj->GetSyncHandle();
|
|
}
|
|
}
|
|
|
|
aRenderThread.AddRenderer(aWindowId, std::move(renderer));
|
|
}
|
|
|
|
private:
|
|
wr::DocumentHandle** mDocHandle;
|
|
WebRenderBackend* mBackend;
|
|
WebRenderCompositor* mCompositor;
|
|
int32_t* mMaxTextureSize;
|
|
bool* mUseANGLE;
|
|
bool* mUseDComp;
|
|
bool* mUseTripleBuffering;
|
|
bool* mSupportsExternalBufferTextures;
|
|
layers::CompositorBridgeParent* mBridge;
|
|
RefPtr<widget::CompositorWidget> mCompositorWidget;
|
|
layers::SynchronousTask* mTask;
|
|
LayoutDeviceIntSize mSize;
|
|
layers::WindowKind mWindowKind;
|
|
layers::SyncHandle* mSyncHandle;
|
|
nsACString* mError;
|
|
};
|
|
|
|
class RemoveRenderer : public RendererEvent {
|
|
public:
|
|
explicit RemoveRenderer(layers::SynchronousTask* aTask) : mTask(aTask) {
|
|
MOZ_COUNT_CTOR(RemoveRenderer);
|
|
}
|
|
|
|
MOZ_COUNTED_DTOR_OVERRIDE(RemoveRenderer)
|
|
|
|
void Run(RenderThread& aRenderThread, WindowId aWindowId) override {
|
|
aRenderThread.RemoveRenderer(aWindowId);
|
|
layers::AutoCompleteTask complete(mTask);
|
|
}
|
|
|
|
private:
|
|
layers::SynchronousTask* mTask;
|
|
};
|
|
|
|
TransactionBuilder::TransactionBuilder(WebRenderAPI* aApi,
|
|
bool aUseSceneBuilderThread)
|
|
: mUseSceneBuilderThread(aUseSceneBuilderThread),
|
|
mApiBackend(aApi->GetBackendType()) {
|
|
mTxn = wr_transaction_new(mUseSceneBuilderThread);
|
|
}
|
|
|
|
TransactionBuilder::~TransactionBuilder() { wr_transaction_delete(mTxn); }
|
|
|
|
void TransactionBuilder::SetLowPriority(bool aIsLowPriority) {
|
|
wr_transaction_set_low_priority(mTxn, aIsLowPriority);
|
|
}
|
|
|
|
void TransactionBuilder::UpdateEpoch(PipelineId aPipelineId, Epoch aEpoch) {
|
|
wr_transaction_update_epoch(mTxn, aPipelineId, aEpoch);
|
|
}
|
|
|
|
void TransactionBuilder::SetRootPipeline(PipelineId aPipelineId) {
|
|
wr_transaction_set_root_pipeline(mTxn, aPipelineId);
|
|
}
|
|
|
|
void TransactionBuilder::RemovePipeline(PipelineId aPipelineId) {
|
|
wr_transaction_remove_pipeline(mTxn, aPipelineId);
|
|
}
|
|
|
|
void TransactionBuilder::SetDisplayList(
|
|
const gfx::DeviceColor& aBgColor, Epoch aEpoch,
|
|
const wr::LayoutSize& aViewportSize, wr::WrPipelineId pipeline_id,
|
|
wr::BuiltDisplayListDescriptor dl_descriptor,
|
|
wr::Vec<uint8_t>& dl_items_data, wr::Vec<uint8_t>& dl_cache_data,
|
|
wr::Vec<uint8_t>& dl_spatial_tree) {
|
|
wr_transaction_set_display_list(mTxn, aEpoch, ToColorF(aBgColor),
|
|
aViewportSize, pipeline_id, dl_descriptor,
|
|
&dl_items_data.inner, &dl_cache_data.inner,
|
|
&dl_spatial_tree.inner);
|
|
}
|
|
|
|
void TransactionBuilder::ClearDisplayList(Epoch aEpoch,
|
|
wr::WrPipelineId aPipelineId) {
|
|
wr_transaction_clear_display_list(mTxn, aEpoch, aPipelineId);
|
|
}
|
|
|
|
void TransactionBuilder::GenerateFrame(const VsyncId& aVsyncId,
|
|
wr::RenderReasons aReasons) {
|
|
wr_transaction_generate_frame(mTxn, aVsyncId.mId, aReasons);
|
|
}
|
|
|
|
void TransactionBuilder::InvalidateRenderedFrame(wr::RenderReasons aReasons) {
|
|
wr_transaction_invalidate_rendered_frame(mTxn, aReasons);
|
|
}
|
|
|
|
bool TransactionBuilder::IsEmpty() const {
|
|
return wr_transaction_is_empty(mTxn);
|
|
}
|
|
|
|
bool TransactionBuilder::IsResourceUpdatesEmpty() const {
|
|
return wr_transaction_resource_updates_is_empty(mTxn);
|
|
}
|
|
|
|
bool TransactionBuilder::IsRenderedFrameInvalidated() const {
|
|
return wr_transaction_is_rendered_frame_invalidated(mTxn);
|
|
}
|
|
|
|
void TransactionBuilder::SetDocumentView(
|
|
const LayoutDeviceIntRect& aDocumentRect) {
|
|
wr::DeviceIntRect wrDocRect;
|
|
wrDocRect.min.x = aDocumentRect.x;
|
|
wrDocRect.min.y = aDocumentRect.y;
|
|
wrDocRect.max.x = aDocumentRect.x + aDocumentRect.width;
|
|
wrDocRect.max.y = aDocumentRect.y + aDocumentRect.height;
|
|
wr_transaction_set_document_view(mTxn, &wrDocRect);
|
|
}
|
|
|
|
TransactionWrapper::TransactionWrapper(Transaction* aTxn) : mTxn(aTxn) {}
|
|
|
|
void TransactionWrapper::AppendDynamicProperties(
|
|
const nsTArray<wr::WrOpacityProperty>& aOpacityArray,
|
|
const nsTArray<wr::WrTransformProperty>& aTransformArray,
|
|
const nsTArray<wr::WrColorProperty>& aColorArray) {
|
|
wr_transaction_append_dynamic_properties(
|
|
mTxn, aOpacityArray.IsEmpty() ? nullptr : aOpacityArray.Elements(),
|
|
aOpacityArray.Length(),
|
|
aTransformArray.IsEmpty() ? nullptr : aTransformArray.Elements(),
|
|
aTransformArray.Length(),
|
|
aColorArray.IsEmpty() ? nullptr : aColorArray.Elements(),
|
|
aColorArray.Length());
|
|
}
|
|
|
|
void TransactionWrapper::AppendTransformProperties(
|
|
const nsTArray<wr::WrTransformProperty>& aTransformArray) {
|
|
wr_transaction_append_transform_properties(
|
|
mTxn, aTransformArray.IsEmpty() ? nullptr : aTransformArray.Elements(),
|
|
aTransformArray.Length());
|
|
}
|
|
|
|
void TransactionWrapper::UpdateScrollPosition(
|
|
const wr::WrPipelineId& aPipelineId,
|
|
const layers::ScrollableLayerGuid::ViewID& aScrollId,
|
|
const nsTArray<wr::SampledScrollOffset>& aSampledOffsets) {
|
|
wr_transaction_scroll_layer(mTxn, aPipelineId, aScrollId, &aSampledOffsets);
|
|
}
|
|
|
|
void TransactionWrapper::UpdateIsTransformAsyncZooming(uint64_t aAnimationId,
|
|
bool aIsZooming) {
|
|
wr_transaction_set_is_transform_async_zooming(mTxn, aAnimationId, aIsZooming);
|
|
}
|
|
|
|
/*static*/
|
|
already_AddRefed<WebRenderAPI> WebRenderAPI::Create(
|
|
layers::CompositorBridgeParent* aBridge,
|
|
RefPtr<widget::CompositorWidget>&& aWidget, const wr::WrWindowId& aWindowId,
|
|
LayoutDeviceIntSize aSize, layers::WindowKind aWindowKind,
|
|
nsACString& aError) {
|
|
MOZ_ASSERT(aBridge);
|
|
MOZ_ASSERT(aWidget);
|
|
static_assert(
|
|
sizeof(size_t) == sizeof(uintptr_t),
|
|
"The FFI bindings assume size_t is the same size as uintptr_t!");
|
|
|
|
wr::DocumentHandle* docHandle = nullptr;
|
|
WebRenderBackend backend = WebRenderBackend::HARDWARE;
|
|
WebRenderCompositor compositor = WebRenderCompositor::DRAW;
|
|
int32_t maxTextureSize = 0;
|
|
bool useANGLE = false;
|
|
bool useDComp = false;
|
|
bool useTripleBuffering = false;
|
|
bool supportsExternalBufferTextures = false;
|
|
layers::SyncHandle syncHandle = 0;
|
|
|
|
// Dispatch a synchronous task because the DocumentHandle object needs to be
|
|
// created on the render thread. If need be we could delay waiting on this
|
|
// task until the next time we need to access the DocumentHandle object.
|
|
layers::SynchronousTask task("Create Renderer");
|
|
auto event = MakeUnique<NewRenderer>(
|
|
&docHandle, aBridge, &backend, &compositor, &maxTextureSize, &useANGLE,
|
|
&useDComp, &useTripleBuffering, &supportsExternalBufferTextures,
|
|
std::move(aWidget), &task, aSize, aWindowKind, &syncHandle, &aError);
|
|
RenderThread::Get()->RunEvent(aWindowId, std::move(event));
|
|
|
|
task.Wait();
|
|
|
|
if (!docHandle) {
|
|
return nullptr;
|
|
}
|
|
|
|
return RefPtr<WebRenderAPI>(
|
|
new WebRenderAPI(docHandle, aWindowId, backend, compositor,
|
|
maxTextureSize, useANGLE, useDComp,
|
|
useTripleBuffering,
|
|
supportsExternalBufferTextures, syncHandle))
|
|
.forget();
|
|
}
|
|
|
|
already_AddRefed<WebRenderAPI> WebRenderAPI::Clone() {
|
|
wr::DocumentHandle* docHandle = nullptr;
|
|
wr_api_clone(mDocHandle, &docHandle);
|
|
|
|
RefPtr<WebRenderAPI> renderApi =
|
|
new WebRenderAPI(docHandle, mId, mBackend, mCompositor, mMaxTextureSize,
|
|
mUseANGLE, mUseDComp, mUseTripleBuffering,
|
|
mSupportsExternalBufferTextures, mSyncHandle);
|
|
renderApi->mRootApi = this; // Hold root api
|
|
renderApi->mRootDocumentApi = this;
|
|
|
|
return renderApi.forget();
|
|
}
|
|
|
|
wr::WrIdNamespace WebRenderAPI::GetNamespace() {
|
|
return wr_api_get_namespace(mDocHandle);
|
|
}
|
|
|
|
WebRenderAPI::WebRenderAPI(wr::DocumentHandle* aHandle, wr::WindowId aId,
|
|
WebRenderBackend aBackend,
|
|
WebRenderCompositor aCompositor,
|
|
uint32_t aMaxTextureSize, bool aUseANGLE,
|
|
bool aUseDComp, bool aUseTripleBuffering,
|
|
bool aSupportsExternalBufferTextures,
|
|
layers::SyncHandle aSyncHandle)
|
|
: mDocHandle(aHandle),
|
|
mId(aId),
|
|
mBackend(aBackend),
|
|
mCompositor(aCompositor),
|
|
mMaxTextureSize(aMaxTextureSize),
|
|
mUseANGLE(aUseANGLE),
|
|
mUseDComp(aUseDComp),
|
|
mUseTripleBuffering(aUseTripleBuffering),
|
|
mSupportsExternalBufferTextures(aSupportsExternalBufferTextures),
|
|
mCaptureSequence(false),
|
|
mSyncHandle(aSyncHandle),
|
|
mRendererDestroyed(false) {}
|
|
|
|
WebRenderAPI::~WebRenderAPI() {
|
|
if (!mRootDocumentApi) {
|
|
wr_api_delete_document(mDocHandle);
|
|
}
|
|
|
|
if (!mRootApi) {
|
|
MOZ_RELEASE_ASSERT(mRendererDestroyed);
|
|
wr_api_shut_down(mDocHandle);
|
|
}
|
|
|
|
wr_api_delete(mDocHandle);
|
|
}
|
|
|
|
void WebRenderAPI::DestroyRenderer() {
|
|
MOZ_RELEASE_ASSERT(!mRootApi);
|
|
|
|
RenderThread::Get()->SetDestroyed(GetId());
|
|
// Call wr_api_stop_render_backend() before RemoveRenderer.
|
|
wr_api_stop_render_backend(mDocHandle);
|
|
|
|
layers::SynchronousTask task("Destroy WebRenderAPI");
|
|
auto event = MakeUnique<RemoveRenderer>(&task);
|
|
RunOnRenderThread(std::move(event));
|
|
task.Wait();
|
|
|
|
mRendererDestroyed = true;
|
|
}
|
|
|
|
void WebRenderAPI::UpdateDebugFlags(uint32_t aFlags) {
|
|
wr_api_set_debug_flags(mDocHandle, wr::DebugFlags{aFlags});
|
|
}
|
|
|
|
void WebRenderAPI::SendTransaction(TransactionBuilder& aTxn) {
|
|
if (mRootApi && mRootApi->mRendererDestroyed) {
|
|
return;
|
|
}
|
|
wr_api_send_transaction(mDocHandle, aTxn.Raw(), aTxn.UseSceneBuilderThread());
|
|
}
|
|
|
|
std::vector<WrHitResult> WebRenderAPI::HitTest(const wr::WorldPoint& aPoint) {
|
|
static_assert(gfx::DoesCompositorHitTestInfoFitIntoBits<12>(),
|
|
"CompositorHitTestFlags MAX value has to be less than number "
|
|
"of bits in uint16_t minus 4 for SideBitsPacked");
|
|
|
|
nsTArray<wr::HitResult> wrResults;
|
|
wr_api_hit_test(mDocHandle, aPoint, &wrResults);
|
|
|
|
std::vector<WrHitResult> geckoResults;
|
|
for (wr::HitResult wrResult : wrResults) {
|
|
WrHitResult geckoResult;
|
|
geckoResult.mLayersId = wr::AsLayersId(wrResult.pipeline_id);
|
|
geckoResult.mScrollId =
|
|
static_cast<layers::ScrollableLayerGuid::ViewID>(wrResult.scroll_id);
|
|
geckoResult.mHitInfo.deserialize(wrResult.hit_info & 0x0fff);
|
|
geckoResult.mSideBits = static_cast<SideBits>(wrResult.hit_info >> 12);
|
|
|
|
if (wrResult.animation_id != 0) {
|
|
geckoResult.mAnimationId = Some(wrResult.animation_id);
|
|
} else {
|
|
geckoResult.mAnimationId = Nothing();
|
|
}
|
|
geckoResults.push_back(geckoResult);
|
|
}
|
|
return geckoResults;
|
|
}
|
|
|
|
void WebRenderAPI::Readback(const TimeStamp& aStartTime, gfx::IntSize size,
|
|
const gfx::SurfaceFormat& aFormat,
|
|
const Range<uint8_t>& buffer, bool* aNeedsYFlip) {
|
|
class Readback : public RendererEvent {
|
|
public:
|
|
explicit Readback(layers::SynchronousTask* aTask, TimeStamp aStartTime,
|
|
gfx::IntSize aSize, const gfx::SurfaceFormat& aFormat,
|
|
const Range<uint8_t>& aBuffer, bool* aNeedsYFlip)
|
|
: mTask(aTask),
|
|
mStartTime(aStartTime),
|
|
mSize(aSize),
|
|
mFormat(aFormat),
|
|
mBuffer(aBuffer),
|
|
mNeedsYFlip(aNeedsYFlip) {
|
|
MOZ_COUNT_CTOR(Readback);
|
|
}
|
|
|
|
MOZ_COUNTED_DTOR_OVERRIDE(Readback)
|
|
|
|
void Run(RenderThread& aRenderThread, WindowId aWindowId) override {
|
|
aRenderThread.UpdateAndRender(aWindowId, VsyncId(), mStartTime,
|
|
/* aRender */ true, Some(mSize),
|
|
wr::SurfaceFormatToImageFormat(mFormat),
|
|
Some(mBuffer), mNeedsYFlip);
|
|
layers::AutoCompleteTask complete(mTask);
|
|
}
|
|
|
|
layers::SynchronousTask* mTask;
|
|
TimeStamp mStartTime;
|
|
gfx::IntSize mSize;
|
|
gfx::SurfaceFormat mFormat;
|
|
const Range<uint8_t>& mBuffer;
|
|
bool* mNeedsYFlip;
|
|
};
|
|
|
|
// Disable debug flags during readback. See bug 1436020.
|
|
UpdateDebugFlags(0);
|
|
|
|
layers::SynchronousTask task("Readback");
|
|
auto event = MakeUnique<Readback>(&task, aStartTime, size, aFormat, buffer,
|
|
aNeedsYFlip);
|
|
// This event will be passed from wr_backend thread to renderer thread. That
|
|
// implies that all frame data have been processed when the renderer runs this
|
|
// read-back event. Then, we could make sure this read-back event gets the
|
|
// latest result.
|
|
RunOnRenderThread(std::move(event));
|
|
|
|
task.Wait();
|
|
|
|
UpdateDebugFlags(gfx::gfxVars::WebRenderDebugFlags());
|
|
}
|
|
|
|
void WebRenderAPI::ClearAllCaches() { wr_api_clear_all_caches(mDocHandle); }
|
|
|
|
void WebRenderAPI::EnableNativeCompositor(bool aEnable) {
|
|
wr_api_enable_native_compositor(mDocHandle, aEnable);
|
|
}
|
|
|
|
void WebRenderAPI::SetBatchingLookback(uint32_t aCount) {
|
|
wr_api_set_batching_lookback(mDocHandle, aCount);
|
|
}
|
|
|
|
void WebRenderAPI::SetBool(wr::BoolParameter aKey, bool aValue) {
|
|
wr_api_set_bool(mDocHandle, aKey, aValue);
|
|
}
|
|
|
|
void WebRenderAPI::SetInt(wr::IntParameter aKey, int32_t aValue) {
|
|
wr_api_set_int(mDocHandle, aKey, aValue);
|
|
}
|
|
|
|
void WebRenderAPI::SetClearColor(const gfx::DeviceColor& aColor) {
|
|
RenderThread::Get()->SetClearColor(mId, ToColorF(aColor));
|
|
}
|
|
|
|
void WebRenderAPI::SetProfilerUI(const nsACString& aUIString) {
|
|
RenderThread::Get()->SetProfilerUI(mId, aUIString);
|
|
}
|
|
|
|
void WebRenderAPI::Pause() {
|
|
class PauseEvent : public RendererEvent {
|
|
public:
|
|
explicit PauseEvent(layers::SynchronousTask* aTask) : mTask(aTask) {
|
|
MOZ_COUNT_CTOR(PauseEvent);
|
|
}
|
|
|
|
MOZ_COUNTED_DTOR_OVERRIDE(PauseEvent)
|
|
|
|
void Run(RenderThread& aRenderThread, WindowId aWindowId) override {
|
|
aRenderThread.Pause(aWindowId);
|
|
layers::AutoCompleteTask complete(mTask);
|
|
}
|
|
|
|
layers::SynchronousTask* mTask;
|
|
};
|
|
|
|
layers::SynchronousTask task("Pause");
|
|
auto event = MakeUnique<PauseEvent>(&task);
|
|
// This event will be passed from wr_backend thread to renderer thread. That
|
|
// implies that all frame data have been processed when the renderer runs this
|
|
// event.
|
|
RunOnRenderThread(std::move(event));
|
|
|
|
task.Wait();
|
|
}
|
|
|
|
bool WebRenderAPI::Resume() {
|
|
class ResumeEvent : public RendererEvent {
|
|
public:
|
|
explicit ResumeEvent(layers::SynchronousTask* aTask, bool* aResult)
|
|
: mTask(aTask), mResult(aResult) {
|
|
MOZ_COUNT_CTOR(ResumeEvent);
|
|
}
|
|
|
|
MOZ_COUNTED_DTOR_OVERRIDE(ResumeEvent)
|
|
|
|
void Run(RenderThread& aRenderThread, WindowId aWindowId) override {
|
|
*mResult = aRenderThread.Resume(aWindowId);
|
|
layers::AutoCompleteTask complete(mTask);
|
|
}
|
|
|
|
layers::SynchronousTask* mTask;
|
|
bool* mResult;
|
|
};
|
|
|
|
bool result = false;
|
|
layers::SynchronousTask task("Resume");
|
|
auto event = MakeUnique<ResumeEvent>(&task, &result);
|
|
// This event will be passed from wr_backend thread to renderer thread. That
|
|
// implies that all frame data have been processed when the renderer runs this
|
|
// event.
|
|
RunOnRenderThread(std::move(event));
|
|
|
|
task.Wait();
|
|
return result;
|
|
}
|
|
|
|
void WebRenderAPI::NotifyMemoryPressure() {
|
|
wr_api_notify_memory_pressure(mDocHandle);
|
|
}
|
|
|
|
void WebRenderAPI::AccumulateMemoryReport(MemoryReport* aReport) {
|
|
wr_api_accumulate_memory_report(mDocHandle, aReport, &WebRenderMallocSizeOf,
|
|
&WebRenderMallocEnclosingSizeOf);
|
|
}
|
|
|
|
void WebRenderAPI::WakeSceneBuilder() { wr_api_wake_scene_builder(mDocHandle); }
|
|
|
|
void WebRenderAPI::FlushSceneBuilder() {
|
|
wr_api_flush_scene_builder(mDocHandle);
|
|
}
|
|
|
|
void WebRenderAPI::WaitFlushed() {
|
|
class WaitFlushedEvent : public RendererEvent {
|
|
public:
|
|
explicit WaitFlushedEvent(layers::SynchronousTask* aTask) : mTask(aTask) {
|
|
MOZ_COUNT_CTOR(WaitFlushedEvent);
|
|
}
|
|
|
|
MOZ_COUNTED_DTOR_OVERRIDE(WaitFlushedEvent)
|
|
|
|
void Run(RenderThread& aRenderThread, WindowId aWindowId) override {
|
|
layers::AutoCompleteTask complete(mTask);
|
|
}
|
|
|
|
layers::SynchronousTask* mTask;
|
|
};
|
|
|
|
layers::SynchronousTask task("WaitFlushed");
|
|
auto event = MakeUnique<WaitFlushedEvent>(&task);
|
|
// This event will be passed from wr_backend thread to renderer thread. That
|
|
// implies that all frame data have been processed when the renderer runs this
|
|
// event.
|
|
RunOnRenderThread(std::move(event));
|
|
|
|
task.Wait();
|
|
}
|
|
|
|
void WebRenderAPI::Capture() {
|
|
// see CaptureBits
|
|
// SCENE | FRAME | TILE_CACHE
|
|
uint8_t bits = 15; // TODO: get from JavaScript
|
|
const char* path = "wr-capture"; // TODO: get from JavaScript
|
|
wr_api_capture(mDocHandle, path, bits);
|
|
}
|
|
|
|
void WebRenderAPI::StartCaptureSequence(const nsACString& aPath,
|
|
uint32_t aFlags) {
|
|
if (mCaptureSequence) {
|
|
wr_api_stop_capture_sequence(mDocHandle);
|
|
}
|
|
|
|
wr_api_start_capture_sequence(mDocHandle, PromiseFlatCString(aPath).get(),
|
|
aFlags);
|
|
|
|
mCaptureSequence = true;
|
|
}
|
|
|
|
void WebRenderAPI::StopCaptureSequence() {
|
|
if (mCaptureSequence) {
|
|
wr_api_stop_capture_sequence(mDocHandle);
|
|
}
|
|
|
|
mCaptureSequence = false;
|
|
}
|
|
|
|
void WebRenderAPI::BeginRecording(const TimeStamp& aRecordingStart,
|
|
wr::PipelineId aRootPipelineId) {
|
|
class BeginRecordingEvent final : public RendererEvent {
|
|
public:
|
|
explicit BeginRecordingEvent(const TimeStamp& aRecordingStart,
|
|
wr::PipelineId aRootPipelineId)
|
|
: mRecordingStart(aRecordingStart), mRootPipelineId(aRootPipelineId) {
|
|
MOZ_COUNT_CTOR(BeginRecordingEvent);
|
|
}
|
|
|
|
~BeginRecordingEvent() { MOZ_COUNT_DTOR(BeginRecordingEvent); }
|
|
|
|
void Run(RenderThread& aRenderThread, WindowId aWindowId) override {
|
|
aRenderThread.BeginRecordingForWindow(aWindowId, mRecordingStart,
|
|
mRootPipelineId);
|
|
}
|
|
|
|
private:
|
|
TimeStamp mRecordingStart;
|
|
wr::PipelineId mRootPipelineId;
|
|
};
|
|
|
|
auto event =
|
|
MakeUnique<BeginRecordingEvent>(aRecordingStart, aRootPipelineId);
|
|
RunOnRenderThread(std::move(event));
|
|
}
|
|
|
|
RefPtr<WebRenderAPI::WriteCollectedFramesPromise>
|
|
WebRenderAPI::WriteCollectedFrames() {
|
|
class WriteCollectedFramesEvent final : public RendererEvent {
|
|
public:
|
|
explicit WriteCollectedFramesEvent() {
|
|
MOZ_COUNT_CTOR(WriteCollectedFramesEvent);
|
|
}
|
|
|
|
MOZ_COUNTED_DTOR(WriteCollectedFramesEvent)
|
|
|
|
void Run(RenderThread& aRenderThread, WindowId aWindowId) override {
|
|
aRenderThread.WriteCollectedFramesForWindow(aWindowId);
|
|
mPromise.Resolve(true, __func__);
|
|
}
|
|
|
|
RefPtr<WebRenderAPI::WriteCollectedFramesPromise> GetPromise() {
|
|
return mPromise.Ensure(__func__);
|
|
}
|
|
|
|
private:
|
|
MozPromiseHolder<WebRenderAPI::WriteCollectedFramesPromise> mPromise;
|
|
};
|
|
|
|
auto event = MakeUnique<WriteCollectedFramesEvent>();
|
|
auto promise = event->GetPromise();
|
|
|
|
RunOnRenderThread(std::move(event));
|
|
return promise;
|
|
}
|
|
|
|
RefPtr<WebRenderAPI::GetCollectedFramesPromise>
|
|
WebRenderAPI::GetCollectedFrames() {
|
|
class GetCollectedFramesEvent final : public RendererEvent {
|
|
public:
|
|
explicit GetCollectedFramesEvent() {
|
|
MOZ_COUNT_CTOR(GetCollectedFramesEvent);
|
|
}
|
|
|
|
MOZ_COUNTED_DTOR(GetCollectedFramesEvent);
|
|
|
|
void Run(RenderThread& aRenderThread, WindowId aWindowId) override {
|
|
Maybe<layers::CollectedFrames> frames =
|
|
aRenderThread.GetCollectedFramesForWindow(aWindowId);
|
|
|
|
if (frames) {
|
|
mPromise.Resolve(std::move(*frames), __func__);
|
|
} else {
|
|
mPromise.Reject(NS_ERROR_UNEXPECTED, __func__);
|
|
}
|
|
}
|
|
|
|
RefPtr<WebRenderAPI::GetCollectedFramesPromise> GetPromise() {
|
|
return mPromise.Ensure(__func__);
|
|
}
|
|
|
|
private:
|
|
MozPromiseHolder<WebRenderAPI::GetCollectedFramesPromise> mPromise;
|
|
};
|
|
|
|
auto event = MakeUnique<GetCollectedFramesEvent>();
|
|
auto promise = event->GetPromise();
|
|
|
|
RunOnRenderThread(std::move(event));
|
|
return promise;
|
|
}
|
|
|
|
void TransactionBuilder::Clear() { wr_resource_updates_clear(mTxn); }
|
|
|
|
void TransactionBuilder::Notify(wr::Checkpoint aWhen,
|
|
UniquePtr<NotificationHandler> aEvent) {
|
|
wr_transaction_notify(mTxn, aWhen,
|
|
reinterpret_cast<uintptr_t>(aEvent.release()));
|
|
}
|
|
|
|
void TransactionBuilder::AddImage(ImageKey key,
|
|
const ImageDescriptor& aDescriptor,
|
|
wr::Vec<uint8_t>& aBytes) {
|
|
wr_resource_updates_add_image(mTxn, key, &aDescriptor, &aBytes.inner);
|
|
}
|
|
|
|
void TransactionBuilder::AddBlobImage(BlobImageKey key,
|
|
const ImageDescriptor& aDescriptor,
|
|
uint16_t aTileSize,
|
|
wr::Vec<uint8_t>& aBytes,
|
|
const wr::DeviceIntRect& aVisibleRect) {
|
|
wr_resource_updates_add_blob_image(mTxn, key, &aDescriptor, aTileSize,
|
|
&aBytes.inner, aVisibleRect);
|
|
}
|
|
|
|
void TransactionBuilder::AddExternalImage(ImageKey key,
|
|
const ImageDescriptor& aDescriptor,
|
|
ExternalImageId aExtID,
|
|
wr::ExternalImageType aImageType,
|
|
uint8_t aChannelIndex) {
|
|
wr_resource_updates_add_external_image(mTxn, key, &aDescriptor, aExtID,
|
|
&aImageType, aChannelIndex);
|
|
}
|
|
|
|
void TransactionBuilder::AddExternalImageBuffer(
|
|
ImageKey aKey, const ImageDescriptor& aDescriptor,
|
|
ExternalImageId aHandle) {
|
|
auto channelIndex = 0;
|
|
AddExternalImage(aKey, aDescriptor, aHandle, wr::ExternalImageType::Buffer(),
|
|
channelIndex);
|
|
}
|
|
|
|
void TransactionBuilder::UpdateImageBuffer(ImageKey aKey,
|
|
const ImageDescriptor& aDescriptor,
|
|
wr::Vec<uint8_t>& aBytes) {
|
|
wr_resource_updates_update_image(mTxn, aKey, &aDescriptor, &aBytes.inner);
|
|
}
|
|
|
|
void TransactionBuilder::UpdateBlobImage(BlobImageKey aKey,
|
|
const ImageDescriptor& aDescriptor,
|
|
wr::Vec<uint8_t>& aBytes,
|
|
const wr::DeviceIntRect& aVisibleRect,
|
|
const wr::LayoutIntRect& aDirtyRect) {
|
|
wr_resource_updates_update_blob_image(mTxn, aKey, &aDescriptor, &aBytes.inner,
|
|
aVisibleRect, aDirtyRect);
|
|
}
|
|
|
|
void TransactionBuilder::UpdateExternalImage(ImageKey aKey,
|
|
const ImageDescriptor& aDescriptor,
|
|
ExternalImageId aExtID,
|
|
wr::ExternalImageType aImageType,
|
|
uint8_t aChannelIndex) {
|
|
wr_resource_updates_update_external_image(mTxn, aKey, &aDescriptor, aExtID,
|
|
&aImageType, aChannelIndex);
|
|
}
|
|
|
|
void TransactionBuilder::UpdateExternalImageWithDirtyRect(
|
|
ImageKey aKey, const ImageDescriptor& aDescriptor, ExternalImageId aExtID,
|
|
wr::ExternalImageType aImageType, const wr::DeviceIntRect& aDirtyRect,
|
|
uint8_t aChannelIndex) {
|
|
wr_resource_updates_update_external_image_with_dirty_rect(
|
|
mTxn, aKey, &aDescriptor, aExtID, &aImageType, aChannelIndex, aDirtyRect);
|
|
}
|
|
|
|
void TransactionBuilder::SetBlobImageVisibleArea(
|
|
BlobImageKey aKey, const wr::DeviceIntRect& aArea) {
|
|
wr_resource_updates_set_blob_image_visible_area(mTxn, aKey, &aArea);
|
|
}
|
|
|
|
void TransactionBuilder::DeleteImage(ImageKey aKey) {
|
|
wr_resource_updates_delete_image(mTxn, aKey);
|
|
}
|
|
|
|
void TransactionBuilder::DeleteBlobImage(BlobImageKey aKey) {
|
|
wr_resource_updates_delete_blob_image(mTxn, aKey);
|
|
}
|
|
|
|
void TransactionBuilder::AddRawFont(wr::FontKey aKey, wr::Vec<uint8_t>& aBytes,
|
|
uint32_t aIndex) {
|
|
wr_resource_updates_add_raw_font(mTxn, aKey, &aBytes.inner, aIndex);
|
|
}
|
|
|
|
void TransactionBuilder::AddFontDescriptor(wr::FontKey aKey,
|
|
wr::Vec<uint8_t>& aBytes,
|
|
uint32_t aIndex) {
|
|
wr_resource_updates_add_font_descriptor(mTxn, aKey, &aBytes.inner, aIndex);
|
|
}
|
|
|
|
void TransactionBuilder::DeleteFont(wr::FontKey aKey) {
|
|
wr_resource_updates_delete_font(mTxn, aKey);
|
|
}
|
|
|
|
void TransactionBuilder::AddFontInstance(
|
|
wr::FontInstanceKey aKey, wr::FontKey aFontKey, float aGlyphSize,
|
|
const wr::FontInstanceOptions* aOptions,
|
|
const wr::FontInstancePlatformOptions* aPlatformOptions,
|
|
wr::Vec<uint8_t>& aVariations) {
|
|
wr_resource_updates_add_font_instance(mTxn, aKey, aFontKey, aGlyphSize,
|
|
aOptions, aPlatformOptions,
|
|
&aVariations.inner);
|
|
}
|
|
|
|
void TransactionBuilder::DeleteFontInstance(wr::FontInstanceKey aKey) {
|
|
wr_resource_updates_delete_font_instance(mTxn, aKey);
|
|
}
|
|
|
|
void TransactionBuilder::UpdateQualitySettings(
|
|
bool aForceSubpixelAAWherePossible) {
|
|
wr_transaction_set_quality_settings(mTxn, aForceSubpixelAAWherePossible);
|
|
}
|
|
|
|
class FrameStartTime : public RendererEvent {
|
|
public:
|
|
explicit FrameStartTime(const TimeStamp& aTime) : mTime(aTime) {
|
|
MOZ_COUNT_CTOR(FrameStartTime);
|
|
}
|
|
|
|
MOZ_COUNTED_DTOR_OVERRIDE(FrameStartTime)
|
|
|
|
void Run(RenderThread& aRenderThread, WindowId aWindowId) override {
|
|
auto renderer = aRenderThread.GetRenderer(aWindowId);
|
|
if (renderer) {
|
|
renderer->SetFrameStartTime(mTime);
|
|
}
|
|
}
|
|
|
|
private:
|
|
TimeStamp mTime;
|
|
};
|
|
|
|
void WebRenderAPI::SetFrameStartTime(const TimeStamp& aTime) {
|
|
auto event = MakeUnique<FrameStartTime>(aTime);
|
|
RunOnRenderThread(std::move(event));
|
|
}
|
|
|
|
void WebRenderAPI::RunOnRenderThread(UniquePtr<RendererEvent> aEvent) {
|
|
auto event = reinterpret_cast<uintptr_t>(aEvent.release());
|
|
wr_api_send_external_event(mDocHandle, event);
|
|
}
|
|
|
|
DisplayListBuilder::DisplayListBuilder(PipelineId aId,
|
|
WebRenderBackend aBackend)
|
|
: mCurrentSpaceAndClipChain(wr::RootScrollNodeWithChain()),
|
|
mActiveFixedPosTracker(nullptr),
|
|
mPipelineId(aId),
|
|
mBackend(aBackend),
|
|
mDisplayItemCache(nullptr) {
|
|
MOZ_COUNT_CTOR(DisplayListBuilder);
|
|
mWrState = wr_state_new(aId);
|
|
|
|
if (mDisplayItemCache && mDisplayItemCache->IsEnabled()) {
|
|
mDisplayItemCache->SetPipelineId(aId);
|
|
}
|
|
}
|
|
|
|
DisplayListBuilder::~DisplayListBuilder() {
|
|
MOZ_COUNT_DTOR(DisplayListBuilder);
|
|
wr_state_delete(mWrState);
|
|
}
|
|
|
|
void DisplayListBuilder::Save() { wr_dp_save(mWrState); }
|
|
void DisplayListBuilder::Restore() { wr_dp_restore(mWrState); }
|
|
void DisplayListBuilder::ClearSave() { wr_dp_clear_save(mWrState); }
|
|
|
|
usize DisplayListBuilder::Dump(usize aIndent, const Maybe<usize>& aStart,
|
|
const Maybe<usize>& aEnd) {
|
|
return wr_dump_display_list(mWrState, aIndent, aStart.ptrOr(nullptr),
|
|
aEnd.ptrOr(nullptr));
|
|
}
|
|
|
|
void DisplayListBuilder::DumpSerializedDisplayList() {
|
|
wr_dump_serialized_display_list(mWrState);
|
|
}
|
|
|
|
void DisplayListBuilder::Begin(layers::DisplayItemCache* aCache) {
|
|
wr_api_begin_builder(mWrState);
|
|
|
|
mScrollIds.clear();
|
|
mCurrentSpaceAndClipChain = wr::RootScrollNodeWithChain();
|
|
mClipChainLeaf = Nothing();
|
|
mSuspendedSpaceAndClipChain = Nothing();
|
|
mSuspendedClipChainLeaf = Nothing();
|
|
mCachedTextDT = nullptr;
|
|
mCachedContext = nullptr;
|
|
mActiveFixedPosTracker = nullptr;
|
|
mDisplayItemCache = aCache;
|
|
mCurrentCacheSlot = Nothing();
|
|
mRemotePipelineIds.Clear();
|
|
}
|
|
|
|
void DisplayListBuilder::End(BuiltDisplayList& aOutDisplayList) {
|
|
wr_api_end_builder(
|
|
mWrState, &aOutDisplayList.dl_desc, &aOutDisplayList.dl_items.inner,
|
|
&aOutDisplayList.dl_cache.inner, &aOutDisplayList.dl_spatial_tree.inner);
|
|
|
|
mDisplayItemCache = nullptr;
|
|
}
|
|
|
|
void DisplayListBuilder::End(layers::DisplayListData& aOutTransaction) {
|
|
if (mDisplayItemCache && mDisplayItemCache->IsEnabled()) {
|
|
wr_dp_set_cache_size(mWrState, mDisplayItemCache->CurrentSize());
|
|
}
|
|
|
|
wr::VecU8 dlItems, dlCache, dlSpatialTree;
|
|
wr_api_end_builder(mWrState, &aOutTransaction.mDLDesc, &dlItems.inner,
|
|
&dlCache.inner, &dlSpatialTree.inner);
|
|
aOutTransaction.mDLItems.emplace(dlItems.inner.data, dlItems.inner.length,
|
|
dlItems.inner.capacity);
|
|
aOutTransaction.mDLCache.emplace(dlCache.inner.data, dlCache.inner.length,
|
|
dlCache.inner.capacity);
|
|
aOutTransaction.mDLSpatialTree.emplace(dlSpatialTree.inner.data,
|
|
dlSpatialTree.inner.length,
|
|
dlSpatialTree.inner.capacity);
|
|
aOutTransaction.mRemotePipelineIds = mRemotePipelineIds.Clone();
|
|
dlItems.inner.capacity = 0;
|
|
dlItems.inner.data = nullptr;
|
|
dlCache.inner.capacity = 0;
|
|
dlCache.inner.data = nullptr;
|
|
dlSpatialTree.inner.capacity = 0;
|
|
dlSpatialTree.inner.data = nullptr;
|
|
}
|
|
|
|
Maybe<wr::WrSpatialId> DisplayListBuilder::PushStackingContext(
|
|
const wr::StackingContextParams& aParams, const wr::LayoutRect& aBounds,
|
|
const wr::RasterSpace& aRasterSpace) {
|
|
MOZ_ASSERT(mClipChainLeaf.isNothing(),
|
|
"Non-empty leaf from clip chain given, but not used with SC!");
|
|
|
|
WRDL_LOG(
|
|
"PushStackingContext b=%s t=%s id=0x%" PRIx64 "\n", mWrState,
|
|
ToString(aBounds).c_str(),
|
|
aParams.mTransformPtr ? ToString(*aParams.mTransformPtr).c_str() : "none",
|
|
aParams.animation ? aParams.animation->id : 0);
|
|
|
|
auto spatialId = wr_dp_push_stacking_context(
|
|
mWrState, aBounds, mCurrentSpaceAndClipChain.space, &aParams,
|
|
aParams.mTransformPtr, aParams.mFilters.Elements(),
|
|
aParams.mFilters.Length(), aParams.mFilterDatas.Elements(),
|
|
aParams.mFilterDatas.Length(), aRasterSpace);
|
|
|
|
return spatialId.id != 0 ? Some(spatialId) : Nothing();
|
|
}
|
|
|
|
void DisplayListBuilder::PopStackingContext(bool aIsReferenceFrame) {
|
|
WRDL_LOG("PopStackingContext\n", mWrState);
|
|
wr_dp_pop_stacking_context(mWrState, aIsReferenceFrame);
|
|
}
|
|
|
|
wr::WrClipChainId DisplayListBuilder::DefineClipChain(
|
|
const nsTArray<wr::WrClipId>& aClips, bool aParentWithCurrentChain) {
|
|
CancelGroup();
|
|
|
|
const uint64_t* parent = nullptr;
|
|
if (aParentWithCurrentChain &&
|
|
mCurrentSpaceAndClipChain.clip_chain != wr::ROOT_CLIP_CHAIN) {
|
|
parent = &mCurrentSpaceAndClipChain.clip_chain;
|
|
}
|
|
uint64_t clipchainId = wr_dp_define_clipchain(
|
|
mWrState, parent, aClips.Elements(), aClips.Length());
|
|
WRDL_LOG("DefineClipChain id=%" PRIu64 " clips=%zu\n", mWrState, clipchainId,
|
|
aClips.Length());
|
|
return wr::WrClipChainId{clipchainId};
|
|
}
|
|
|
|
wr::WrClipId DisplayListBuilder::DefineImageMaskClip(
|
|
const wr::ImageMask& aMask, const nsTArray<wr::LayoutPoint>& aPoints,
|
|
wr::FillRule aFillRule) {
|
|
CancelGroup();
|
|
|
|
WrClipId clipId = wr_dp_define_image_mask_clip_with_parent_clip_chain(
|
|
mWrState, mCurrentSpaceAndClipChain.space, aMask, aPoints.Elements(),
|
|
aPoints.Length(), aFillRule);
|
|
|
|
return clipId;
|
|
}
|
|
|
|
wr::WrClipId DisplayListBuilder::DefineRoundedRectClip(
|
|
Maybe<wr::WrSpatialId> aSpace, const wr::ComplexClipRegion& aComplex) {
|
|
CancelGroup();
|
|
|
|
WrClipId clipId;
|
|
if (aSpace) {
|
|
clipId = wr_dp_define_rounded_rect_clip(mWrState, *aSpace, aComplex);
|
|
} else {
|
|
clipId = wr_dp_define_rounded_rect_clip(
|
|
mWrState, mCurrentSpaceAndClipChain.space, aComplex);
|
|
}
|
|
|
|
return clipId;
|
|
}
|
|
|
|
wr::WrClipId DisplayListBuilder::DefineRectClip(Maybe<wr::WrSpatialId> aSpace,
|
|
wr::LayoutRect aClipRect) {
|
|
CancelGroup();
|
|
|
|
WrClipId clipId;
|
|
if (aSpace) {
|
|
clipId = wr_dp_define_rect_clip(mWrState, *aSpace, aClipRect);
|
|
} else {
|
|
clipId = wr_dp_define_rect_clip(mWrState, mCurrentSpaceAndClipChain.space,
|
|
aClipRect);
|
|
}
|
|
|
|
return clipId;
|
|
}
|
|
|
|
wr::WrSpatialId DisplayListBuilder::DefineStickyFrame(
|
|
const wr::LayoutRect& aContentRect, const float* aTopMargin,
|
|
const float* aRightMargin, const float* aBottomMargin,
|
|
const float* aLeftMargin, const StickyOffsetBounds& aVerticalBounds,
|
|
const StickyOffsetBounds& aHorizontalBounds,
|
|
const wr::LayoutVector2D& aAppliedOffset, wr::SpatialTreeItemKey aKey) {
|
|
auto spatialId = wr_dp_define_sticky_frame(
|
|
mWrState, mCurrentSpaceAndClipChain.space, aContentRect, aTopMargin,
|
|
aRightMargin, aBottomMargin, aLeftMargin, aVerticalBounds,
|
|
aHorizontalBounds, aAppliedOffset, aKey);
|
|
|
|
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(),
|
|
aTopMargin ? ToString(*aTopMargin).c_str() : "none",
|
|
aRightMargin ? ToString(*aRightMargin).c_str() : "none",
|
|
aBottomMargin ? ToString(*aBottomMargin).c_str() : "none",
|
|
aLeftMargin ? ToString(*aLeftMargin).c_str() : "none",
|
|
ToString(aVerticalBounds).c_str(),
|
|
ToString(aHorizontalBounds).c_str(),
|
|
ToString(aAppliedOffset).c_str());
|
|
|
|
return spatialId;
|
|
}
|
|
|
|
Maybe<wr::WrSpatialId> DisplayListBuilder::GetScrollIdForDefinedScrollLayer(
|
|
layers::ScrollableLayerGuid::ViewID aViewId) const {
|
|
if (aViewId == layers::ScrollableLayerGuid::NULL_SCROLL_ID) {
|
|
return Some(wr::RootScrollNode());
|
|
}
|
|
|
|
auto it = mScrollIds.find(aViewId);
|
|
if (it == mScrollIds.end()) {
|
|
return Nothing();
|
|
}
|
|
|
|
return Some(it->second);
|
|
}
|
|
|
|
wr::WrSpatialId DisplayListBuilder::DefineScrollLayer(
|
|
const layers::ScrollableLayerGuid::ViewID& aViewId,
|
|
const Maybe<wr::WrSpatialId>& aParent, const wr::LayoutRect& aContentRect,
|
|
const wr::LayoutRect& aClipRect, const wr::LayoutVector2D& aScrollOffset,
|
|
wr::APZScrollGeneration aScrollOffsetGeneration,
|
|
wr::HasScrollLinkedEffect aHasScrollLinkedEffect,
|
|
wr::SpatialTreeItemKey aKey) {
|
|
auto it = mScrollIds.find(aViewId);
|
|
if (it != mScrollIds.end()) {
|
|
return it->second;
|
|
}
|
|
|
|
// We haven't defined aViewId before, so let's define it now.
|
|
wr::WrSpatialId defaultParent = mCurrentSpaceAndClipChain.space;
|
|
|
|
auto space = wr_dp_define_scroll_layer(
|
|
mWrState, aViewId, aParent ? aParent.ptr() : &defaultParent, aContentRect,
|
|
aClipRect, aScrollOffset, aScrollOffsetGeneration, aHasScrollLinkedEffect,
|
|
aKey);
|
|
|
|
WRDL_LOG("DefineScrollLayer id=%" PRIu64
|
|
"/%zu p=%s co=%s cl=%s generation=%s hasScrollLinkedEffect=%s\n",
|
|
mWrState, aViewId, space.id,
|
|
aParent ? ToString(aParent->id).c_str() : "(nil)",
|
|
ToString(aContentRect).c_str(), ToString(aClipRect).c_str(),
|
|
ToString(aScrollOffsetGeneration).c_str(),
|
|
ToString(aHasScrollLinkedEffect).c_str());
|
|
|
|
mScrollIds[aViewId] = space;
|
|
return space;
|
|
}
|
|
|
|
void DisplayListBuilder::PushRect(const wr::LayoutRect& aBounds,
|
|
const wr::LayoutRect& aClip,
|
|
bool aIsBackfaceVisible,
|
|
bool aForceAntiAliasing, bool aIsCheckerboard,
|
|
const wr::ColorF& aColor) {
|
|
wr::LayoutRect clip = MergeClipLeaf(aClip);
|
|
WRDL_LOG("PushRect b=%s cl=%s c=%s\n", mWrState, ToString(aBounds).c_str(),
|
|
ToString(clip).c_str(), ToString(aColor).c_str());
|
|
wr_dp_push_rect(mWrState, aBounds, clip, aIsBackfaceVisible,
|
|
aForceAntiAliasing, aIsCheckerboard,
|
|
&mCurrentSpaceAndClipChain, aColor);
|
|
}
|
|
|
|
void DisplayListBuilder::PushRoundedRect(const wr::LayoutRect& aBounds,
|
|
const wr::LayoutRect& aClip,
|
|
bool aIsBackfaceVisible,
|
|
const wr::ColorF& aColor) {
|
|
wr::LayoutRect clip = MergeClipLeaf(aClip);
|
|
WRDL_LOG("PushRoundedRect b=%s cl=%s c=%s\n", mWrState,
|
|
ToString(aBounds).c_str(), ToString(clip).c_str(),
|
|
ToString(aColor).c_str());
|
|
|
|
// Draw the rounded rectangle as a border with rounded corners. We could also
|
|
// draw this as a rectangle clipped to a rounded rectangle, but:
|
|
// - clips are not cached; borders are
|
|
// - a simple border like this will be drawn as an image
|
|
// - Processing lots of clips is not WebRender's strong point.
|
|
//
|
|
// Made the borders thicker than one half the width/height, to avoid
|
|
// little white dots at the center at some magnifications.
|
|
wr::BorderSide side = {aColor, wr::BorderStyle::Solid};
|
|
float h = aBounds.width() * 0.6f;
|
|
float v = aBounds.height() * 0.6f;
|
|
wr::LayoutSideOffsets widths = {v, h, v, h};
|
|
wr::BorderRadius radii = {{h, v}, {h, v}, {h, v}, {h, v}};
|
|
|
|
// Anti-aliased borders are required for rounded borders.
|
|
wr_dp_push_border(mWrState, aBounds, clip, aIsBackfaceVisible,
|
|
&mCurrentSpaceAndClipChain, wr::AntialiasBorder::Yes,
|
|
widths, side, side, side, side, radii);
|
|
}
|
|
|
|
void DisplayListBuilder::PushHitTest(
|
|
const wr::LayoutRect& aBounds, const wr::LayoutRect& aClip,
|
|
bool aIsBackfaceVisible,
|
|
const layers::ScrollableLayerGuid::ViewID& aScrollId,
|
|
const gfx::CompositorHitTestInfo& aHitInfo, SideBits aSideBits) {
|
|
wr::LayoutRect clip = MergeClipLeaf(aClip);
|
|
WRDL_LOG("PushHitTest b=%s cl=%s\n", mWrState, ToString(aBounds).c_str(),
|
|
ToString(clip).c_str());
|
|
|
|
static_assert(gfx::DoesCompositorHitTestInfoFitIntoBits<12>(),
|
|
"CompositorHitTestFlags MAX value has to be less than number "
|
|
"of bits in uint16_t minus 4 for SideBitsPacked");
|
|
|
|
uint16_t hitInfoBits = static_cast<uint16_t>(aHitInfo.serialize()) |
|
|
(static_cast<uint16_t>(aSideBits) << 12);
|
|
|
|
wr_dp_push_hit_test(mWrState, aBounds, clip, aIsBackfaceVisible,
|
|
&mCurrentSpaceAndClipChain, aScrollId, hitInfoBits);
|
|
}
|
|
|
|
void DisplayListBuilder::PushRectWithAnimation(
|
|
const wr::LayoutRect& aBounds, const wr::LayoutRect& aClip,
|
|
bool aIsBackfaceVisible, const wr::ColorF& aColor,
|
|
const WrAnimationProperty* aAnimation) {
|
|
wr::LayoutRect clip = MergeClipLeaf(aClip);
|
|
WRDL_LOG("PushRectWithAnimation b=%s cl=%s c=%s\n", mWrState,
|
|
ToString(aBounds).c_str(), ToString(clip).c_str(),
|
|
ToString(aColor).c_str());
|
|
|
|
wr_dp_push_rect_with_animation(mWrState, aBounds, clip, aIsBackfaceVisible,
|
|
&mCurrentSpaceAndClipChain, aColor,
|
|
aAnimation);
|
|
}
|
|
|
|
void DisplayListBuilder::PushClearRect(const wr::LayoutRect& aBounds) {
|
|
wr::LayoutRect clip = MergeClipLeaf(aBounds);
|
|
WRDL_LOG("PushClearRect b=%s c=%s\n", mWrState, ToString(aBounds).c_str(),
|
|
ToString(clip).c_str());
|
|
wr_dp_push_clear_rect(mWrState, aBounds, clip, &mCurrentSpaceAndClipChain);
|
|
}
|
|
|
|
void DisplayListBuilder::PushBackdropFilter(
|
|
const wr::LayoutRect& aBounds, const wr::ComplexClipRegion& aRegion,
|
|
const nsTArray<wr::FilterOp>& aFilters,
|
|
const nsTArray<wr::WrFilterData>& aFilterDatas, bool aIsBackfaceVisible) {
|
|
wr::LayoutRect clip = MergeClipLeaf(aBounds);
|
|
WRDL_LOG("PushBackdropFilter b=%s c=%s\n", mWrState,
|
|
ToString(aBounds).c_str(), ToString(clip).c_str());
|
|
|
|
auto clipId = DefineRoundedRectClip(Nothing(), aRegion);
|
|
auto clipChainId = DefineClipChain({clipId}, true);
|
|
auto spaceAndClip =
|
|
WrSpaceAndClipChain{mCurrentSpaceAndClipChain.space, clipChainId.id};
|
|
|
|
wr_dp_push_backdrop_filter(mWrState, aBounds, clip, aIsBackfaceVisible,
|
|
&spaceAndClip, aFilters.Elements(),
|
|
aFilters.Length(), aFilterDatas.Elements(),
|
|
aFilterDatas.Length());
|
|
}
|
|
|
|
void DisplayListBuilder::PushLinearGradient(
|
|
const wr::LayoutRect& aBounds, const wr::LayoutRect& aClip,
|
|
bool aIsBackfaceVisible, const wr::LayoutPoint& aStartPoint,
|
|
const wr::LayoutPoint& aEndPoint, const nsTArray<wr::GradientStop>& aStops,
|
|
wr::ExtendMode aExtendMode, const wr::LayoutSize aTileSize,
|
|
const wr::LayoutSize aTileSpacing) {
|
|
wr_dp_push_linear_gradient(
|
|
mWrState, aBounds, MergeClipLeaf(aClip), aIsBackfaceVisible,
|
|
&mCurrentSpaceAndClipChain, aStartPoint, aEndPoint, aStops.Elements(),
|
|
aStops.Length(), aExtendMode, aTileSize, aTileSpacing);
|
|
}
|
|
|
|
void DisplayListBuilder::PushRadialGradient(
|
|
const wr::LayoutRect& aBounds, const wr::LayoutRect& aClip,
|
|
bool aIsBackfaceVisible, const wr::LayoutPoint& aCenter,
|
|
const wr::LayoutSize& aRadius, const nsTArray<wr::GradientStop>& aStops,
|
|
wr::ExtendMode aExtendMode, const wr::LayoutSize aTileSize,
|
|
const wr::LayoutSize aTileSpacing) {
|
|
wr_dp_push_radial_gradient(
|
|
mWrState, aBounds, MergeClipLeaf(aClip), aIsBackfaceVisible,
|
|
&mCurrentSpaceAndClipChain, aCenter, aRadius, aStops.Elements(),
|
|
aStops.Length(), aExtendMode, aTileSize, aTileSpacing);
|
|
}
|
|
|
|
void DisplayListBuilder::PushConicGradient(
|
|
const wr::LayoutRect& aBounds, const wr::LayoutRect& aClip,
|
|
bool aIsBackfaceVisible, const wr::LayoutPoint& aCenter, const float aAngle,
|
|
const nsTArray<wr::GradientStop>& aStops, wr::ExtendMode aExtendMode,
|
|
const wr::LayoutSize aTileSize, const wr::LayoutSize aTileSpacing) {
|
|
wr_dp_push_conic_gradient(mWrState, aBounds, MergeClipLeaf(aClip),
|
|
aIsBackfaceVisible, &mCurrentSpaceAndClipChain,
|
|
aCenter, aAngle, aStops.Elements(), aStops.Length(),
|
|
aExtendMode, aTileSize, aTileSpacing);
|
|
}
|
|
|
|
void DisplayListBuilder::PushImage(
|
|
const wr::LayoutRect& aBounds, const wr::LayoutRect& aClip,
|
|
bool aIsBackfaceVisible, bool aForceAntiAliasing,
|
|
wr::ImageRendering aFilter, wr::ImageKey aImage, bool aPremultipliedAlpha,
|
|
const wr::ColorF& aColor, bool aPreferCompositorSurface,
|
|
bool aSupportsExternalCompositing) {
|
|
wr::LayoutRect clip = MergeClipLeaf(aClip);
|
|
WRDL_LOG("PushImage b=%s cl=%s\n", mWrState, ToString(aBounds).c_str(),
|
|
ToString(clip).c_str());
|
|
wr_dp_push_image(mWrState, aBounds, clip, aIsBackfaceVisible,
|
|
aForceAntiAliasing, &mCurrentSpaceAndClipChain, aFilter,
|
|
aImage, aPremultipliedAlpha, aColor,
|
|
aPreferCompositorSurface, aSupportsExternalCompositing);
|
|
}
|
|
|
|
void DisplayListBuilder::PushRepeatingImage(
|
|
const wr::LayoutRect& aBounds, const wr::LayoutRect& aClip,
|
|
bool aIsBackfaceVisible, const wr::LayoutSize& aStretchSize,
|
|
const wr::LayoutSize& aTileSpacing, wr::ImageRendering aFilter,
|
|
wr::ImageKey aImage, bool aPremultipliedAlpha, const wr::ColorF& aColor) {
|
|
wr::LayoutRect clip = MergeClipLeaf(aClip);
|
|
WRDL_LOG("PushImage b=%s cl=%s s=%s t=%s\n", mWrState,
|
|
ToString(aBounds).c_str(), ToString(clip).c_str(),
|
|
ToString(aStretchSize).c_str(), ToString(aTileSpacing).c_str());
|
|
wr_dp_push_repeating_image(
|
|
mWrState, aBounds, clip, aIsBackfaceVisible, &mCurrentSpaceAndClipChain,
|
|
aStretchSize, aTileSpacing, aFilter, aImage, aPremultipliedAlpha, aColor);
|
|
}
|
|
|
|
void DisplayListBuilder::PushYCbCrPlanarImage(
|
|
const wr::LayoutRect& aBounds, const wr::LayoutRect& aClip,
|
|
bool aIsBackfaceVisible, wr::ImageKey aImageChannel0,
|
|
wr::ImageKey aImageChannel1, wr::ImageKey aImageChannel2,
|
|
wr::WrColorDepth aColorDepth, wr::WrYuvColorSpace aColorSpace,
|
|
wr::WrColorRange aColorRange, wr::ImageRendering aRendering,
|
|
bool aPreferCompositorSurface, bool aSupportsExternalCompositing) {
|
|
wr_dp_push_yuv_planar_image(
|
|
mWrState, aBounds, MergeClipLeaf(aClip), aIsBackfaceVisible,
|
|
&mCurrentSpaceAndClipChain, aImageChannel0, aImageChannel1,
|
|
aImageChannel2, aColorDepth, aColorSpace, aColorRange, aRendering,
|
|
aPreferCompositorSurface, aSupportsExternalCompositing);
|
|
}
|
|
|
|
void DisplayListBuilder::PushNV12Image(
|
|
const wr::LayoutRect& aBounds, const wr::LayoutRect& aClip,
|
|
bool aIsBackfaceVisible, wr::ImageKey aImageChannel0,
|
|
wr::ImageKey aImageChannel1, wr::WrColorDepth aColorDepth,
|
|
wr::WrYuvColorSpace aColorSpace, wr::WrColorRange aColorRange,
|
|
wr::ImageRendering aRendering, bool aPreferCompositorSurface,
|
|
bool aSupportsExternalCompositing) {
|
|
wr_dp_push_yuv_NV12_image(
|
|
mWrState, aBounds, MergeClipLeaf(aClip), aIsBackfaceVisible,
|
|
&mCurrentSpaceAndClipChain, aImageChannel0, aImageChannel1, aColorDepth,
|
|
aColorSpace, aColorRange, aRendering, aPreferCompositorSurface,
|
|
aSupportsExternalCompositing);
|
|
}
|
|
|
|
void DisplayListBuilder::PushP010Image(
|
|
const wr::LayoutRect& aBounds, const wr::LayoutRect& aClip,
|
|
bool aIsBackfaceVisible, wr::ImageKey aImageChannel0,
|
|
wr::ImageKey aImageChannel1, wr::WrColorDepth aColorDepth,
|
|
wr::WrYuvColorSpace aColorSpace, wr::WrColorRange aColorRange,
|
|
wr::ImageRendering aRendering, bool aPreferCompositorSurface,
|
|
bool aSupportsExternalCompositing) {
|
|
wr_dp_push_yuv_P010_image(
|
|
mWrState, aBounds, MergeClipLeaf(aClip), aIsBackfaceVisible,
|
|
&mCurrentSpaceAndClipChain, aImageChannel0, aImageChannel1, aColorDepth,
|
|
aColorSpace, aColorRange, aRendering, aPreferCompositorSurface,
|
|
aSupportsExternalCompositing);
|
|
}
|
|
|
|
void DisplayListBuilder::PushYCbCrInterleavedImage(
|
|
const wr::LayoutRect& aBounds, const wr::LayoutRect& aClip,
|
|
bool aIsBackfaceVisible, wr::ImageKey aImageChannel0,
|
|
wr::WrColorDepth aColorDepth, wr::WrYuvColorSpace aColorSpace,
|
|
wr::WrColorRange aColorRange, wr::ImageRendering aRendering,
|
|
bool aPreferCompositorSurface, bool aSupportsExternalCompositing) {
|
|
wr_dp_push_yuv_interleaved_image(
|
|
mWrState, aBounds, MergeClipLeaf(aClip), aIsBackfaceVisible,
|
|
&mCurrentSpaceAndClipChain, aImageChannel0, aColorDepth, aColorSpace,
|
|
aColorRange, aRendering, aPreferCompositorSurface,
|
|
aSupportsExternalCompositing);
|
|
}
|
|
|
|
void DisplayListBuilder::PushIFrame(const wr::LayoutRect& aBounds,
|
|
bool aIsBackfaceVisible,
|
|
PipelineId aPipeline,
|
|
bool aIgnoreMissingPipeline) {
|
|
mRemotePipelineIds.AppendElement(aPipeline);
|
|
wr_dp_push_iframe(mWrState, aBounds, MergeClipLeaf(aBounds),
|
|
aIsBackfaceVisible, &mCurrentSpaceAndClipChain, aPipeline,
|
|
aIgnoreMissingPipeline);
|
|
}
|
|
|
|
void DisplayListBuilder::PushBorder(const wr::LayoutRect& aBounds,
|
|
const wr::LayoutRect& aClip,
|
|
bool aIsBackfaceVisible,
|
|
const wr::LayoutSideOffsets& aWidths,
|
|
const Range<const wr::BorderSide>& aSides,
|
|
const wr::BorderRadius& aRadius,
|
|
wr::AntialiasBorder aAntialias) {
|
|
MOZ_ASSERT(aSides.length() == 4);
|
|
if (aSides.length() != 4) {
|
|
return;
|
|
}
|
|
wr_dp_push_border(mWrState, aBounds, MergeClipLeaf(aClip), aIsBackfaceVisible,
|
|
&mCurrentSpaceAndClipChain, aAntialias, aWidths, aSides[0],
|
|
aSides[1], aSides[2], aSides[3], aRadius);
|
|
}
|
|
|
|
void DisplayListBuilder::PushBorderImage(const wr::LayoutRect& aBounds,
|
|
const wr::LayoutRect& aClip,
|
|
bool aIsBackfaceVisible,
|
|
const wr::WrBorderImage& aParams) {
|
|
wr_dp_push_border_image(mWrState, aBounds, MergeClipLeaf(aClip),
|
|
aIsBackfaceVisible, &mCurrentSpaceAndClipChain,
|
|
&aParams);
|
|
}
|
|
|
|
void DisplayListBuilder::PushBorderGradient(
|
|
const wr::LayoutRect& aBounds, const wr::LayoutRect& aClip,
|
|
bool aIsBackfaceVisible, const wr::LayoutSideOffsets& aWidths,
|
|
const int32_t aWidth, const int32_t aHeight, bool aFill,
|
|
const wr::DeviceIntSideOffsets& aSlice, const wr::LayoutPoint& aStartPoint,
|
|
const wr::LayoutPoint& aEndPoint, const nsTArray<wr::GradientStop>& aStops,
|
|
wr::ExtendMode aExtendMode, const wr::LayoutSideOffsets& aOutset) {
|
|
wr_dp_push_border_gradient(mWrState, aBounds, MergeClipLeaf(aClip),
|
|
aIsBackfaceVisible, &mCurrentSpaceAndClipChain,
|
|
aWidths, aWidth, aHeight, aFill, aSlice,
|
|
aStartPoint, aEndPoint, aStops.Elements(),
|
|
aStops.Length(), aExtendMode, aOutset);
|
|
}
|
|
|
|
void DisplayListBuilder::PushBorderRadialGradient(
|
|
const wr::LayoutRect& aBounds, const wr::LayoutRect& aClip,
|
|
bool aIsBackfaceVisible, const wr::LayoutSideOffsets& aWidths, bool aFill,
|
|
const wr::LayoutPoint& aCenter, const wr::LayoutSize& aRadius,
|
|
const nsTArray<wr::GradientStop>& aStops, wr::ExtendMode aExtendMode,
|
|
const wr::LayoutSideOffsets& aOutset) {
|
|
wr_dp_push_border_radial_gradient(
|
|
mWrState, aBounds, MergeClipLeaf(aClip), aIsBackfaceVisible,
|
|
&mCurrentSpaceAndClipChain, aWidths, aFill, aCenter, aRadius,
|
|
aStops.Elements(), aStops.Length(), aExtendMode, aOutset);
|
|
}
|
|
|
|
void DisplayListBuilder::PushBorderConicGradient(
|
|
const wr::LayoutRect& aBounds, const wr::LayoutRect& aClip,
|
|
bool aIsBackfaceVisible, const wr::LayoutSideOffsets& aWidths, bool aFill,
|
|
const wr::LayoutPoint& aCenter, const float aAngle,
|
|
const nsTArray<wr::GradientStop>& aStops, wr::ExtendMode aExtendMode,
|
|
const wr::LayoutSideOffsets& aOutset) {
|
|
wr_dp_push_border_conic_gradient(
|
|
mWrState, aBounds, MergeClipLeaf(aClip), aIsBackfaceVisible,
|
|
&mCurrentSpaceAndClipChain, aWidths, aFill, aCenter, aAngle,
|
|
aStops.Elements(), aStops.Length(), aExtendMode, aOutset);
|
|
}
|
|
|
|
void DisplayListBuilder::PushText(const wr::LayoutRect& aBounds,
|
|
const wr::LayoutRect& aClip,
|
|
bool aIsBackfaceVisible,
|
|
const wr::ColorF& aColor,
|
|
wr::FontInstanceKey aFontKey,
|
|
Range<const wr::GlyphInstance> aGlyphBuffer,
|
|
const wr::GlyphOptions* aGlyphOptions) {
|
|
wr_dp_push_text(mWrState, aBounds, MergeClipLeaf(aClip), aIsBackfaceVisible,
|
|
&mCurrentSpaceAndClipChain, aColor, aFontKey,
|
|
&aGlyphBuffer[0], aGlyphBuffer.length(), aGlyphOptions);
|
|
}
|
|
|
|
void DisplayListBuilder::PushLine(const wr::LayoutRect& aClip,
|
|
bool aIsBackfaceVisible,
|
|
const wr::Line& aLine) {
|
|
wr::LayoutRect clip = MergeClipLeaf(aClip);
|
|
wr_dp_push_line(mWrState, &clip, aIsBackfaceVisible,
|
|
&mCurrentSpaceAndClipChain, &aLine.bounds,
|
|
aLine.wavyLineThickness, aLine.orientation, &aLine.color,
|
|
aLine.style);
|
|
}
|
|
|
|
void DisplayListBuilder::PushShadow(const wr::LayoutRect& aRect,
|
|
const wr::LayoutRect& aClip,
|
|
bool aIsBackfaceVisible,
|
|
const wr::Shadow& aShadow,
|
|
bool aShouldInflate) {
|
|
// Local clip_rects are translated inside of shadows, as they are assumed to
|
|
// be part of the element drawing itself, and not a parent frame clipping it.
|
|
// As such, it is not sound to apply the MergeClipLeaf optimization inside of
|
|
// shadows. So we disable the optimization when we encounter a shadow.
|
|
// Shadows don't span frames, so we don't have to worry about MergeClipLeaf
|
|
// being re-enabled mid-shadow. The optimization is restored in PopAllShadows.
|
|
SuspendClipLeafMerging();
|
|
wr_dp_push_shadow(mWrState, aRect, aClip, aIsBackfaceVisible,
|
|
&mCurrentSpaceAndClipChain, aShadow, aShouldInflate);
|
|
}
|
|
|
|
void DisplayListBuilder::PopAllShadows() {
|
|
wr_dp_pop_all_shadows(mWrState);
|
|
ResumeClipLeafMerging();
|
|
}
|
|
|
|
void DisplayListBuilder::SuspendClipLeafMerging() {
|
|
if (mClipChainLeaf) {
|
|
// No one should reinitialize mClipChainLeaf while we're suspended
|
|
MOZ_ASSERT(!mSuspendedClipChainLeaf);
|
|
|
|
mSuspendedClipChainLeaf = mClipChainLeaf;
|
|
mSuspendedSpaceAndClipChain = Some(mCurrentSpaceAndClipChain);
|
|
|
|
auto clipId = DefineRectClip(Nothing(), *mClipChainLeaf);
|
|
auto clipChainId = DefineClipChain({clipId}, true);
|
|
|
|
mCurrentSpaceAndClipChain.clip_chain = clipChainId.id;
|
|
mClipChainLeaf = Nothing();
|
|
}
|
|
}
|
|
|
|
void DisplayListBuilder::ResumeClipLeafMerging() {
|
|
if (mSuspendedClipChainLeaf) {
|
|
mCurrentSpaceAndClipChain = *mSuspendedSpaceAndClipChain;
|
|
mClipChainLeaf = mSuspendedClipChainLeaf;
|
|
|
|
mSuspendedClipChainLeaf = Nothing();
|
|
mSuspendedSpaceAndClipChain = Nothing();
|
|
}
|
|
}
|
|
|
|
void DisplayListBuilder::PushBoxShadow(
|
|
const wr::LayoutRect& aRect, const wr::LayoutRect& aClip,
|
|
bool aIsBackfaceVisible, const wr::LayoutRect& aBoxBounds,
|
|
const wr::LayoutVector2D& aOffset, const wr::ColorF& aColor,
|
|
const float& aBlurRadius, const float& aSpreadRadius,
|
|
const wr::BorderRadius& aBorderRadius,
|
|
const wr::BoxShadowClipMode& aClipMode) {
|
|
wr_dp_push_box_shadow(mWrState, aRect, MergeClipLeaf(aClip),
|
|
aIsBackfaceVisible, &mCurrentSpaceAndClipChain,
|
|
aBoxBounds, aOffset, aColor, aBlurRadius, aSpreadRadius,
|
|
aBorderRadius, aClipMode);
|
|
}
|
|
|
|
void DisplayListBuilder::StartGroup(nsPaintedDisplayItem* aItem) {
|
|
if (!mDisplayItemCache || mDisplayItemCache->IsFull()) {
|
|
return;
|
|
}
|
|
|
|
MOZ_ASSERT(!mCurrentCacheSlot);
|
|
mCurrentCacheSlot = mDisplayItemCache->AssignSlot(aItem);
|
|
|
|
if (mCurrentCacheSlot) {
|
|
wr_dp_start_item_group(mWrState);
|
|
}
|
|
}
|
|
|
|
void DisplayListBuilder::CancelGroup(const bool aDiscard) {
|
|
if (!mDisplayItemCache || !mCurrentCacheSlot) {
|
|
return;
|
|
}
|
|
|
|
wr_dp_cancel_item_group(mWrState, aDiscard);
|
|
mCurrentCacheSlot = Nothing();
|
|
}
|
|
|
|
void DisplayListBuilder::FinishGroup() {
|
|
if (!mDisplayItemCache || !mCurrentCacheSlot) {
|
|
return;
|
|
}
|
|
|
|
MOZ_ASSERT(mCurrentCacheSlot);
|
|
|
|
if (wr_dp_finish_item_group(mWrState, mCurrentCacheSlot.ref())) {
|
|
mDisplayItemCache->MarkSlotOccupied(mCurrentCacheSlot.ref(),
|
|
CurrentSpaceAndClipChain());
|
|
mDisplayItemCache->Stats().AddCached();
|
|
}
|
|
|
|
mCurrentCacheSlot = Nothing();
|
|
}
|
|
|
|
bool DisplayListBuilder::ReuseItem(nsPaintedDisplayItem* aItem) {
|
|
if (!mDisplayItemCache) {
|
|
return false;
|
|
}
|
|
|
|
mDisplayItemCache->Stats().AddTotal();
|
|
|
|
if (mDisplayItemCache->IsEmpty()) {
|
|
return false;
|
|
}
|
|
|
|
Maybe<uint16_t> slot =
|
|
mDisplayItemCache->CanReuseItem(aItem, CurrentSpaceAndClipChain());
|
|
|
|
if (slot) {
|
|
mDisplayItemCache->Stats().AddReused();
|
|
wr_dp_push_reuse_items(mWrState, slot.ref());
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
Maybe<layers::ScrollableLayerGuid::ViewID>
|
|
DisplayListBuilder::GetContainingFixedPosScrollTarget(
|
|
const ActiveScrolledRoot* aAsr) {
|
|
return mActiveFixedPosTracker
|
|
? mActiveFixedPosTracker->GetScrollTargetForASR(aAsr)
|
|
: Nothing();
|
|
}
|
|
|
|
Maybe<SideBits> DisplayListBuilder::GetContainingFixedPosSideBits(
|
|
const ActiveScrolledRoot* aAsr) {
|
|
return mActiveFixedPosTracker
|
|
? mActiveFixedPosTracker->GetSideBitsForASR(aAsr)
|
|
: Nothing();
|
|
}
|
|
|
|
DisplayListBuilder::FixedPosScrollTargetTracker::FixedPosScrollTargetTracker(
|
|
DisplayListBuilder& aBuilder, const ActiveScrolledRoot* aAsr,
|
|
layers::ScrollableLayerGuid::ViewID aScrollId, SideBits aSideBits)
|
|
: mParentTracker(aBuilder.mActiveFixedPosTracker),
|
|
mBuilder(aBuilder),
|
|
mAsr(aAsr),
|
|
mScrollId(aScrollId),
|
|
mSideBits(aSideBits) {
|
|
aBuilder.mActiveFixedPosTracker = this;
|
|
}
|
|
|
|
DisplayListBuilder::FixedPosScrollTargetTracker::
|
|
~FixedPosScrollTargetTracker() {
|
|
mBuilder.mActiveFixedPosTracker = mParentTracker;
|
|
}
|
|
|
|
Maybe<layers::ScrollableLayerGuid::ViewID>
|
|
DisplayListBuilder::FixedPosScrollTargetTracker::GetScrollTargetForASR(
|
|
const ActiveScrolledRoot* aAsr) {
|
|
return aAsr == mAsr ? Some(mScrollId) : Nothing();
|
|
}
|
|
|
|
Maybe<SideBits>
|
|
DisplayListBuilder::FixedPosScrollTargetTracker::GetSideBitsForASR(
|
|
const ActiveScrolledRoot* aAsr) {
|
|
return aAsr == mAsr ? Some(mSideBits) : Nothing();
|
|
}
|
|
|
|
already_AddRefed<gfxContext> DisplayListBuilder::GetTextContext(
|
|
wr::IpcResourceUpdateQueue& aResources,
|
|
const layers::StackingContextHelper& aSc,
|
|
layers::RenderRootStateManager* aManager, nsDisplayItem* aItem,
|
|
nsRect& aBounds, const gfx::Point& aDeviceOffset) {
|
|
if (!mCachedTextDT) {
|
|
mCachedTextDT = new layout::TextDrawTarget(*this, aResources, aSc, aManager,
|
|
aItem, aBounds);
|
|
mCachedContext = gfxContext::CreateOrNull(mCachedTextDT, aDeviceOffset);
|
|
} else {
|
|
mCachedTextDT->Reinitialize(aResources, aSc, aManager, aItem, aBounds);
|
|
mCachedContext->SetDeviceOffset(aDeviceOffset);
|
|
mCachedContext->SetMatrix(gfx::Matrix());
|
|
}
|
|
|
|
RefPtr<gfxContext> tmp = mCachedContext;
|
|
return tmp.forget();
|
|
}
|
|
|
|
void DisplayListBuilder::PushInheritedClipChain(
|
|
nsDisplayListBuilder* aBuilder, const DisplayItemClipChain* aClipChain) {
|
|
if (!aClipChain || mInheritedClipChain == aClipChain) {
|
|
return;
|
|
}
|
|
if (!mInheritedClipChain) {
|
|
mInheritedClipChain = aClipChain;
|
|
return;
|
|
}
|
|
|
|
mInheritedClipChain =
|
|
aBuilder->CreateClipChainIntersection(mInheritedClipChain, aClipChain);
|
|
}
|
|
|
|
} // namespace wr
|
|
} // namespace mozilla
|
|
|
|
extern "C" {
|
|
|
|
void wr_transaction_notification_notified(uintptr_t aHandler,
|
|
mozilla::wr::Checkpoint aWhen) {
|
|
auto handler = reinterpret_cast<mozilla::wr::NotificationHandler*>(aHandler);
|
|
handler->Notify(aWhen);
|
|
// TODO: it would be better to get a callback when the object is destroyed on
|
|
// the rust side and delete then.
|
|
delete handler;
|
|
}
|
|
|
|
void wr_register_thread_local_arena() {
|
|
#ifdef MOZ_MEMORY
|
|
jemalloc_thread_local_arena(true);
|
|
#endif
|
|
}
|
|
|
|
} // extern C
|