Merge autoland to mozilla-central a=merge

This commit is contained in:
Norisz Fay 2022-07-08 12:13:39 +03:00
commit 657dc24e72
23 changed files with 502 additions and 71 deletions

View File

@ -0,0 +1,78 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
var EXPORTED_SYMBOLS = ["PerfTestHelpers"];
const lazy = {};
ChromeUtils.defineModuleGetter(
lazy,
"NetUtil",
"resource://gre/modules/NetUtil.jsm"
);
var PerfTestHelpers = {
/**
* Maps the entries in the given iterable to the given
* promise-returning task function, and waits for all returned
* promises to have resolved. At most `limit` promises may remain
* unresolved at a time. When the limit is reached, the function will
* wait for some to resolve before spawning more tasks.
*/
async throttledMapPromises(iterable, task, limit = 64) {
let pending = new Set();
let promises = [];
for (let data of iterable) {
while (pending.size >= limit) {
await Promise.race(pending);
}
let promise = task(data);
promises.push(promise);
if (promise) {
promise.finally(() => pending.delete(promise));
pending.add(promise);
}
}
return Promise.all(promises);
},
/**
* Returns a promise which resolves to true if the resource at the
* given URI exists, false if it doesn't. This should only be used
* with local resources, such as from resource:/chrome:/jar:/file:
* URIs.
*/
checkURIExists(uri) {
return new Promise(resolve => {
try {
let channel = lazy.NetUtil.newChannel({
uri,
loadUsingSystemPrincipal: true,
});
channel.asyncOpen({
onStartRequest(request) {
resolve(Components.isSuccessCode(request.status));
request.cancel(Cr.NS_BINDING_ABORTED);
},
onStopRequest(request, status) {
// We should have already resolved from `onStartRequest`, but
// we resolve again here just as a failsafe.
resolve(Components.isSuccessCode(status));
},
});
} catch (e) {
if (
e.result != Cr.NS_ERROR_FILE_NOT_FOUND &&
e.result != Cr.NS_ERROR_NOT_AVAILABLE
) {
throw e;
}
resolve(false);
}
});
},
};

View File

@ -57,8 +57,6 @@ const startupPhases = {
"before first paint": {
denylist: {
modules: new Set([
"chrome://webcompat/content/data/ua_overrides.jsm",
"chrome://webcompat/content/lib/ua_overrider.jsm",
"resource:///modules/AboutNewTab.jsm",
"resource:///modules/BrowserUsageTelemetry.jsm",
"resource:///modules/ContentCrashHandlers.jsm",
@ -86,7 +84,6 @@ const startupPhases = {
"resource://gre/modules/BookmarkHTMLUtils.jsm",
"resource://gre/modules/Bookmarks.jsm",
"resource://gre/modules/ContextualIdentityService.jsm",
"resource://gre/modules/CrashSubmit.jsm",
"resource://gre/modules/FxAccounts.jsm",
"resource://gre/modules/FxAccountsStorage.jsm",
"resource://gre/modules/PlacesBackups.jsm",
@ -94,10 +91,7 @@ const startupPhases = {
"resource://gre/modules/PlacesSyncUtils.jsm",
"resource://gre/modules/PushComponents.jsm",
]),
services: new Set([
"@mozilla.org/browser/annotation-service;1",
"@mozilla.org/browser/nav-bookmarks-service;1",
]),
services: new Set(["@mozilla.org/browser/nav-bookmarks-service;1"]),
},
},
@ -128,6 +122,12 @@ if (
);
}
if (AppConstants.MOZ_CRASHREPORTER) {
startupPhases["before handling user events"].denylist.modules.add(
"resource://gre/modules/CrashSubmit.jsm"
);
}
add_task(async function() {
if (
!AppConstants.NIGHTLY_BUILD &&
@ -219,6 +219,29 @@ add_task(async function() {
}
}
}
if (denylist.modules) {
let results = await PerfTestHelpers.throttledMapPromises(
denylist.modules,
async uri => ({
uri,
exists: await PerfTestHelpers.checkURIExists(uri),
})
);
for (let { uri, exists } of results) {
ok(exists, `denylist entry ${uri} for phase "${phase}" must exist`);
}
}
if (denylist.services) {
for (let contract of denylist.services) {
ok(
contract in Cc,
`denylist entry ${contract} for phase "${phase}" must exist`
);
}
}
}
}
});

View File

@ -170,7 +170,7 @@ add_task(async function() {
loadedInfo.processScripts[uri] = "";
}
checkLoadedScripts({
await checkLoadedScripts({
loadedInfo,
known: known_scripts,
intermittent: intermittently_loaded_scripts,

View File

@ -141,7 +141,7 @@ add_task(async function() {
loadedInfo.processScripts[uri] = "";
}
checkLoadedScripts({
await checkLoadedScripts({
loadedInfo,
known: known_scripts,
intermittent: intermittently_loaded_scripts,

View File

@ -82,6 +82,19 @@ add_task(async function() {
return el.platforms.includes(AppConstants.platform);
});
{
let results = await PerfTestHelpers.throttledMapPromises(
knownImagesForPlatform,
async image => ({
uri: image.file,
exists: await PerfTestHelpers.checkURIExists(image.file),
})
);
for (let { uri, exists } of results) {
ok(exists, `Unshown image entry ${uri} must exist`);
}
}
let loadedImages = data["image-loading"];
let shownImages = data["image-drawing"];

View File

@ -2,6 +2,7 @@
XPCOMUtils.defineLazyModuleGetters(this, {
AboutNewTab: "resource:///modules/AboutNewTab.jsm",
PerfTestHelpers: "resource://testing-common/PerfTestHelpers.jsm",
PlacesTestUtils: "resource://testing-common/PlacesTestUtils.jsm",
PlacesUtils: "resource://gre/modules/PlacesUtils.jsm",
UrlbarTestUtils: "resource://testing-common/UrlbarTestUtils.jsm",
@ -843,7 +844,7 @@ async function runUrlbarTest(
* If true, dump the stacks for all loaded modules. Makes the output
* noisy.
*/
function checkLoadedScripts({
async function checkLoadedScripts({
loadedInfo,
known,
intermittent,
@ -852,6 +853,32 @@ function checkLoadedScripts({
}) {
let loadedList = {};
async function checkAllExist(scriptType, list, listType) {
if (scriptType == "services") {
for (let contract of list) {
ok(
contract in Cc,
`${listType} entry ${contract} for content process startup must exist`
);
}
} else {
let results = await PerfTestHelpers.throttledMapPromises(
list,
async uri => ({
uri,
exists: await PerfTestHelpers.checkURIExists(uri),
})
);
for (let { uri, exists } of results) {
ok(
exists,
`${listType} entry ${uri} for content process startup must exist`
);
}
}
}
for (let scriptType in known) {
loadedList[scriptType] = Object.keys(loadedInfo[scriptType]).filter(c => {
if (!known[scriptType].has(c)) {
@ -880,6 +907,8 @@ function checkLoadedScripts({
);
}
await checkAllExist(scriptType, intermittent[scriptType], "intermittent");
is(
known[scriptType].size,
0,
@ -919,5 +948,7 @@ function checkLoadedScripts({
);
}
}
await checkAllExist(scriptType, forbidden[scriptType], "forbidden");
}
}

View File

@ -0,0 +1,17 @@
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
BROWSER_CHROME_MANIFESTS += [
"browser.ini",
"hidpi/browser.ini",
"io/browser.ini",
"lowdpi/browser.ini",
]
TESTING_JS_MODULES += [
"PerfTestHelpers.jsm",
]

View File

@ -744,30 +744,13 @@ function convertToCodeURI(fileUri) {
}
}
function chromeFileExists(aURI) {
let available = 0;
async function chromeFileExists(aURI) {
try {
let channel = NetUtil.newChannel({
uri: aURI,
loadUsingSystemPrincipal: true,
contentPolicyType: Ci.nsIContentPolicy.TYPE_FETCH,
});
let stream = channel.open();
let sstream = Cc["@mozilla.org/scriptableinputstream;1"].createInstance(
Ci.nsIScriptableInputStream
);
sstream.init(stream);
available = sstream.available();
sstream.close();
return await PerfTestHelpers.checkURIExists(aURI);
} catch (e) {
if (
e.result != Cr.NS_ERROR_FILE_NOT_FOUND &&
e.result != Cr.NS_ERROR_NOT_AVAILABLE
) {
todo(false, "Failed to check if " + aURI + "exists: " + e);
}
todo(false, `Failed to check if ${aURI} exists: ${e}`);
return false;
}
return available > 0;
}
function findChromeUrlsFromArray(array, prefix) {
@ -875,7 +858,7 @@ add_task(async function checkAllTheFiles() {
});
// Wait for all manifest to be parsed
await throttledMapPromises(manifestURIs, parseManifest);
await PerfTestHelpers.throttledMapPromises(manifestURIs, parseManifest);
for (let jsm of Components.manager.getComponentJSMs()) {
gReferencesFromCode.set(jsm, null);
@ -908,7 +891,9 @@ add_task(async function checkAllTheFiles() {
}
// Wait for all the files to have actually loaded:
await throttledMapPromises(allPromises, ([task, uri]) => task(uri));
await PerfTestHelpers.throttledMapPromises(allPromises, ([task, uri]) =>
task(uri)
);
// Keep only chrome:// files, and filter out either the devtools paths or
// the non-devtools paths:
@ -1069,7 +1054,7 @@ add_task(async function checkAllTheFiles() {
if (
(file.startsWith("chrome://") || file.startsWith("resource://")) &&
!chromeFileExists(file)
!(await chromeFileExists(file))
) {
// Ignore chrome prefixes that have been automatically expanded.
let pathParts =

View File

@ -437,7 +437,7 @@ add_task(async function checkAllTheCSS() {
return true;
});
// Wait for all manifest to be parsed
await throttledMapPromises(manifestURIs, parseManifest);
await PerfTestHelpers.throttledMapPromises(manifestURIs, parseManifest);
// filter out either the devtools paths or the non-devtools paths:
let isDevtools = SimpleTest.harnessParameters.subsuite == "devtools";
@ -488,7 +488,7 @@ add_task(async function checkAllTheCSS() {
}
// Wait for all the files to have actually loaded:
await throttledMapPromises(allPromises, loadCSS);
await PerfTestHelpers.throttledMapPromises(allPromises, loadCSS);
// Check if all the files referenced from CSS actually exist.
// Files in browser/ should never be referenced outside browser/.

View File

@ -153,7 +153,7 @@ add_task(async function checkAllTheJS() {
// We create an array of promises so we can parallelize all our parsing
// and file loading activity:
await throttledMapPromises(uris, uri => {
await PerfTestHelpers.throttledMapPromises(uris, uri => {
if (uriIsWhiteListed(uri)) {
info("Not checking whitelisted " + uri.spec);
return undefined;

View File

@ -17,6 +17,9 @@ const ZipReader = new Components.Constructor(
const IS_ALPHA = /^[a-z]+$/i;
var { PerfTestHelpers } = ChromeUtils.import(
"resource://testing-common/PerfTestHelpers.jsm"
);
var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
var { OS, require } = ChromeUtils.import("resource://gre/modules/osfile.jsm");
@ -157,23 +160,6 @@ function fetchFile(uri) {
});
}
async function throttledMapPromises(iterable, task, limit = 64) {
let promises = new Set();
for (let data of iterable) {
while (promises.size >= limit) {
await Promise.race(promises);
}
let promise = task(data);
if (promise) {
promise.finally(() => promises.delete(promise));
promises.add(promise);
}
}
await Promise.all(promises);
}
/**
* Returns whether or not a word (presumably in en-US) is capitalized per
* expectations.

View File

@ -39,10 +39,6 @@ BROWSER_CHROME_MANIFESTS += [
"content/test/pageActions/browser.ini",
"content/test/pageinfo/browser.ini",
"content/test/pageStyle/browser.ini",
"content/test/performance/browser.ini",
"content/test/performance/hidpi/browser.ini",
"content/test/performance/io/browser.ini",
"content/test/performance/lowdpi/browser.ini",
"content/test/permissions/browser.ini",
"content/test/plugins/browser.ini",
"content/test/popupNotifications/browser.ini",
@ -71,6 +67,10 @@ BROWSER_CHROME_MANIFESTS += [
"content/test/zoom/browser.ini",
]
DIRS += [
"content/test/performance/",
]
PERFTESTS_MANIFESTS += ["content/test/perftest.ini"]
DEFINES["MOZ_APP_VERSION"] = CONFIG["MOZ_APP_VERSION"]

View File

@ -778,16 +778,20 @@ class ProviderAutofill extends UrlbarProvider {
queryType != QUERYTYPE.AUTOFILL_ORIGIN &&
queryContext.searchString.length == autofilledValue.length
) {
// Use `new URL().href` to lowercase the domain in the final completed
// URL. This isn't necessary since domains are case insensitive, but it
// looks nicer because it means the domain will remain lowercased in the
// input, and it also reflects the fact that Firefox will visit the
// lowercased name.
const originalCompleteValue = new URL(finalCompleteValue).href;
// Make sure the domain is lowercased in the final URL. This isn't
// necessary since domains are case insensitive, but it looks nicer
// because it means the domain will remain lowercased in the input, and it
// also reflects the fact that Firefox will visit the lowercased name.
let strippedAutofilledValue = autofilledValue.substring(
this._strippedPrefix.length
);
finalCompleteValue = new URL(
finalCompleteValue.substring(
0,
finalCompleteValue.length - autofilledValue.length
) + autofilledValue
finalCompleteValue.length - strippedAutofilledValue.length
) + strippedAutofilledValue
).href;
// If the character case of except origin part of the original

View File

@ -814,3 +814,95 @@ add_task(async function aboutAsPrefix() {
await cleanupPlaces();
});
// Checks a URL that has www name in history.
add_task(async function wwwHistory() {
const testData = [
{
input: "example.com/",
visitHistory: [{ uri: "http://www.example.com/", title: "Example" }],
expected: {
autofilled: "example.com/",
completed: "http://www.example.com/",
hasAutofillTitle: true,
results: [
context =>
makeVisitResult(context, {
uri: "http://www.example.com/",
title: "Example",
heuristic: true,
}),
],
},
},
{
input: "https://example.com/",
visitHistory: [{ uri: "https://www.example.com/", title: "Example" }],
expected: {
autofilled: "https://example.com/",
completed: "https://www.example.com/",
hasAutofillTitle: true,
results: [
context =>
makeVisitResult(context, {
uri: "https://www.example.com/",
title: "Example",
heuristic: true,
}),
],
},
},
{
input: "https://example.com/abc",
visitHistory: [{ uri: "https://www.example.com/abc", title: "Example" }],
expected: {
autofilled: "https://example.com/abc",
completed: "https://www.example.com/abc",
hasAutofillTitle: true,
results: [
context =>
makeVisitResult(context, {
uri: "https://www.example.com/abc",
title: "Example",
heuristic: true,
}),
],
},
},
{
input: "https://example.com/ABC",
visitHistory: [{ uri: "https://www.example.com/abc", title: "Example" }],
expected: {
autofilled: "https://example.com/ABC",
completed: "https://www.example.com/ABC",
hasAutofillTitle: false,
results: [
context =>
makeVisitResult(context, {
uri: "https://www.example.com/ABC",
title: "https://www.example.com/ABC",
heuristic: true,
}),
context =>
makeVisitResult(context, {
uri: "https://www.example.com/abc",
title: "Example",
}),
],
},
},
];
for (const { input, visitHistory, expected } of testData) {
await PlacesTestUtils.addVisits(visitHistory);
const context = createContext(input, { isPrivate: false });
await check_results({
context,
completed: expected.completed,
autofilled: expected.autofilled,
hasAutofillTitle: expected.hasAutofillTitle,
matches: expected.results.map(f => f(context)),
});
await cleanupPlaces();
}
});

View File

@ -12,6 +12,7 @@ COM Intcpt Log
COM MTA
Cache I/O
Cameras IPC
CanvasRenderer
ChainedPipePump
ChainedPipeRecv
Checker Test

View File

@ -92,7 +92,8 @@ class gfxVarReceiver;
_(UseVP9HwDecode, bool, false) \
_(HwDecodedVideoZeroCopy, bool, false) \
_(UseDMABufSurfaceExport, bool, true) \
_(ReuseDecoderDevice, bool, false)
_(ReuseDecoderDevice, bool, false) \
_(UseCanvasRenderThread, bool, false)
/* Add new entries above this line. */

View File

@ -6,6 +6,7 @@
#include "CanvasManagerParent.h"
#include "mozilla/dom/WebGLParent.h"
#include "mozilla/gfx/CanvasRenderThread.h"
#include "mozilla/gfx/gfxVars.h"
#include "mozilla/ipc/Endpoint.h"
#include "mozilla/layers/CompositorThread.h"
@ -23,9 +24,7 @@ CanvasManagerParent::ManagerSet CanvasManagerParent::sManagers;
auto manager = MakeRefPtr<CanvasManagerParent>();
if (gfxVars::SupportsThreadsafeGL()) {
manager->Bind(std::move(aEndpoint));
} else {
if (!gfxVars::SupportsThreadsafeGL()) {
nsCOMPtr<nsIThread> owningThread;
owningThread = wr::RenderThread::GetRenderThread();
MOZ_ASSERT(owningThread);
@ -33,6 +32,16 @@ CanvasManagerParent::ManagerSet CanvasManagerParent::sManagers;
owningThread->Dispatch(NewRunnableMethod<Endpoint<PCanvasManagerParent>&&>(
"CanvasManagerParent::Bind", manager, &CanvasManagerParent::Bind,
std::move(aEndpoint)));
} else if (gfxVars::UseCanvasRenderThread()) {
nsCOMPtr<nsIThread> owningThread;
owningThread = gfx::CanvasRenderThread::GetCanvasRenderThread();
MOZ_ASSERT(owningThread);
owningThread->Dispatch(NewRunnableMethod<Endpoint<PCanvasManagerParent>&&>(
"CanvasManagerParent::Bind", manager, &CanvasManagerParent::Bind,
std::move(aEndpoint)));
} else {
manager->Bind(std::move(aEndpoint));
}
}
@ -40,10 +49,12 @@ CanvasManagerParent::ManagerSet CanvasManagerParent::sManagers;
MOZ_ASSERT(NS_IsMainThread());
nsCOMPtr<nsISerialEventTarget> owningThread;
if (gfxVars::SupportsThreadsafeGL()) {
owningThread = layers::CompositorThread();
} else {
if (!gfxVars::SupportsThreadsafeGL()) {
owningThread = wr::RenderThread::GetRenderThread();
} else if (gfxVars::UseCanvasRenderThread()) {
owningThread = gfx::CanvasRenderThread::GetCanvasRenderThread();
} else {
owningThread = layers::CompositorThread();
}
if (!owningThread) {
return;

View File

@ -0,0 +1,111 @@
/* -*- 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 "CanvasRenderThread.h"
#include "mozilla/BackgroundHangMonitor.h"
#include "transport/runnable_utils.h"
namespace mozilla::gfx {
static StaticRefPtr<CanvasRenderThread> sCanvasRenderThread;
static mozilla::BackgroundHangMonitor* sBackgroundHangMonitor;
CanvasRenderThread::CanvasRenderThread(RefPtr<nsIThread> aThread)
: mThread(std::move(aThread)) {}
CanvasRenderThread::~CanvasRenderThread() {}
// static
CanvasRenderThread* CanvasRenderThread::Get() { return sCanvasRenderThread; }
// static
void CanvasRenderThread::Start() {
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(!sCanvasRenderThread);
// This is 512K, which is higher than the default 256K.
// Increased to accommodate Mesa in bug 1753340.
//
// Previously increased to 320K to avoid a stack overflow in the
// Intel Vulkan driver initialization in bug 1716120.
//
// Note: we only override it if it's limited already.
const uint32_t stackSize =
nsIThreadManager::DEFAULT_STACK_SIZE ? 512 << 10 : 0;
RefPtr<nsIThread> thread;
nsresult rv = NS_NewNamedThread(
"CanvasRenderer", getter_AddRefs(thread),
NS_NewRunnableFunction(
"CanvasRender::BackgroundHanSetup",
[]() {
sBackgroundHangMonitor = new mozilla::BackgroundHangMonitor(
"CanvasRenderer",
/* Timeout values are powers-of-two to enable us get better
data. 128ms is chosen for transient hangs because 8Hz should
be the minimally acceptable goal for Compositor
responsiveness (normal goal is 60Hz). */
128,
/* 2048ms is chosen for permanent hangs because it's longer than
* most Compositor hangs seen in the wild, but is short enough
* to not miss getting native hang stacks. */
2048);
nsCOMPtr<nsIThread> thread = NS_GetCurrentThread();
nsThread* nsthread = static_cast<nsThread*>(thread.get());
nsthread->SetUseHangMonitor(true);
nsthread->SetPriority(nsISupportsPriority::PRIORITY_HIGH);
}),
stackSize);
if (NS_FAILED(rv)) {
return;
}
sCanvasRenderThread = new CanvasRenderThread(thread);
}
// static
void CanvasRenderThread::ShutDown() {
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(sCanvasRenderThread);
layers::SynchronousTask task("CanvasRenderThread");
RefPtr<Runnable> runnable =
WrapRunnable(RefPtr<CanvasRenderThread>(sCanvasRenderThread.get()),
&CanvasRenderThread::ShutDownTask, &task);
sCanvasRenderThread->PostRunnable(runnable.forget());
task.Wait();
sCanvasRenderThread = nullptr;
}
void CanvasRenderThread::ShutDownTask(layers::SynchronousTask* aTask) {
layers::AutoCompleteTask complete(aTask);
MOZ_ASSERT(IsInCanvasRenderThread());
}
// static
bool CanvasRenderThread::IsInCanvasRenderThread() {
return sCanvasRenderThread &&
sCanvasRenderThread->mThread == NS_GetCurrentThread();
}
// static
already_AddRefed<nsIThread> CanvasRenderThread::GetCanvasRenderThread() {
nsCOMPtr<nsIThread> thread;
if (sCanvasRenderThread) {
thread = sCanvasRenderThread->mThread;
}
return thread.forget();
}
void CanvasRenderThread::PostRunnable(already_AddRefed<nsIRunnable> aRunnable) {
nsCOMPtr<nsIRunnable> runnable = aRunnable;
mThread->Dispatch(runnable.forget());
}
} // namespace mozilla::gfx

View File

@ -0,0 +1,50 @@
/* -*- 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/. */
#ifndef _include_gfx_ipc_CanvasRenderThread_h__
#define _include_gfx_ipc_CanvasRenderThread_h__
#include "mozilla/DataMutex.h"
#include "mozilla/layers/SynchronousTask.h"
#include "mozilla/StaticPtr.h"
#include "nsISupportsImpl.h"
#include "nsThread.h"
namespace mozilla::gfx {
class CanvasRenderThread final {
NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_DELETE_ON_MAIN_THREAD(
CanvasRenderThread)
public:
/// Can be called from any thread.
static CanvasRenderThread* Get();
/// Can only be called from the main thread.
static void Start();
/// Can only be called from the main thread.
static void ShutDown();
/// Can be called from any thread.
static bool IsInCanvasRenderThread();
/// Can be called from any thread.
static already_AddRefed<nsIThread> GetCanvasRenderThread();
private:
explicit CanvasRenderThread(RefPtr<nsIThread> aThread);
~CanvasRenderThread();
void ShutDownTask(layers::SynchronousTask* aTask);
void PostRunnable(already_AddRefed<nsIRunnable> aRunnable);
RefPtr<nsIThread> const mThread;
};
} // namespace mozilla::gfx
#endif // _include_gfx_ipc_CanvasRenderThread_h__

View File

@ -38,6 +38,7 @@
#include "mozilla/TimeStamp.h"
#include "mozilla/dom/MemoryReportRequest.h"
#include "mozilla/gfx/2D.h"
#include "mozilla/gfx/CanvasRenderThread.h"
#include "mozilla/gfx/gfxVars.h"
#include "mozilla/glean/GleanMetrics.h"
#include "mozilla/image/ImageMemoryReporter.h"
@ -360,6 +361,9 @@ mozilla::ipc::IPCResult GPUParent::RecvInit(
// Make sure to do this *after* we update gfxVars above.
if (gfxVars::UseWebRender()) {
if (gfxVars::UseCanvasRenderThread()) {
gfx::CanvasRenderThread::Start();
}
wr::RenderThread::Start(aWrNamespace);
image::ImageMemoryReporter::InitForWebRender();
}
@ -695,6 +699,9 @@ void GPUParent::ActorDestroy(ActorDestroyReason aWhy) {
if (wr::RenderThread::Get()) {
wr::RenderThread::ShutDown();
}
if (gfx::CanvasRenderThread::Get()) {
gfx::CanvasRenderThread::ShutDown();
}
#ifdef XP_WIN
if (widget::WinCompositorWindowThread::Get()) {
widget::WinCompositorWindowThread::ShutDown();

View File

@ -12,6 +12,7 @@ EXPORTS.mozilla += ["D3DMessageUtils.h", "GfxMessageUtils.h"]
EXPORTS.mozilla.gfx += [
"CanvasManagerChild.h",
"CanvasManagerParent.h",
"CanvasRenderThread.h",
"CrossProcessPaint.h",
"GPUChild.h",
"GPUParent.h",
@ -39,6 +40,7 @@ EXPORTS.mozilla.widget += [
UNIFIED_SOURCES += [
"CanvasManagerChild.cpp",
"CanvasManagerParent.cpp",
"CanvasRenderThread.cpp",
"CompositorSession.cpp",
"CompositorWidgetVsyncObserver.cpp",
"CrossProcessPaint.cpp",

View File

@ -22,6 +22,7 @@
#include "mozilla/gfx/GraphicsMessages.h"
#include "mozilla/gfx/CanvasManagerChild.h"
#include "mozilla/gfx/CanvasManagerParent.h"
#include "mozilla/gfx/CanvasRenderThread.h"
#include "mozilla/ClearOnShutdown.h"
#include "mozilla/StaticPrefs_accessibility.h"
#include "mozilla/StaticPrefs_apz.h"
@ -1291,6 +1292,9 @@ void gfxPlatform::InitLayersIPC() {
#endif
if (!gfxConfig::IsEnabled(Feature::GPU_PROCESS) && UseWebRender()) {
RemoteTextureMap::Init();
if (gfxVars::UseCanvasRenderThread()) {
gfx::CanvasRenderThread::Start();
}
wr::RenderThread::Start(GPUProcessManager::Get()->AllocateNamespace());
image::ImageMemoryReporter::InitForWebRender();
}
@ -1340,6 +1344,9 @@ void gfxPlatform::ShutdownLayersIPC() {
nsDependentCString(
StaticPrefs::GetPrefName_gfx_webrender_blob_tile_size()));
}
if (gfx::CanvasRenderThread::Get()) {
gfx::CanvasRenderThread::ShutDown();
}
#if defined(XP_WIN)
widget::WinWindowOcclusionTracker::ShutDown();
#endif
@ -2854,6 +2861,10 @@ void gfxPlatform::InitWebGLConfig() {
threadsafeGL &= !StaticPrefs::webgl_threadsafe_gl_force_disabled_AtStartup();
gfxVars::SetSupportsThreadsafeGL(threadsafeGL);
bool useCanvasRenderThread =
threadsafeGL && StaticPrefs::webgl_use_canvas_render_thread_AtStartup();
gfxVars::SetUseCanvasRenderThread(useCanvasRenderThread);
if (kIsAndroid) {
// Don't enable robust buffer access on Adreno 630 devices.
// It causes the linking of some shaders to fail. See bug 1485441.
@ -3520,6 +3531,9 @@ void gfxPlatform::DisableGPUProcess() {
RemoteTextureMap::Init();
if (gfxVars::UseWebRender()) {
if (gfxVars::UseCanvasRenderThread()) {
gfx::CanvasRenderThread::Start();
}
// We need to initialize the parent process to prepare for WebRender if we
// did not end up disabling it, despite losing the GPU process.
wr::RenderThread::Start(GPUProcessManager::Get()->AllocateNamespace());

View File

@ -13480,6 +13480,11 @@
value: false
mirror: once
- name: webgl.use-canvas-render-thread
type: bool
value: @IS_NOT_ANDROID@
mirror: once
- name: webgl.override-unmasked-renderer
type: String
value: ""