mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-28 07:13:20 +00:00
Merge autoland to mozilla-central a=merge
This commit is contained in:
commit
657dc24e72
78
browser/base/content/test/performance/PerfTestHelpers.jsm
Normal file
78
browser/base/content/test/performance/PerfTestHelpers.jsm
Normal 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);
|
||||
}
|
||||
});
|
||||
},
|
||||
};
|
@ -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`
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -170,7 +170,7 @@ add_task(async function() {
|
||||
loadedInfo.processScripts[uri] = "";
|
||||
}
|
||||
|
||||
checkLoadedScripts({
|
||||
await checkLoadedScripts({
|
||||
loadedInfo,
|
||||
known: known_scripts,
|
||||
intermittent: intermittently_loaded_scripts,
|
||||
|
@ -141,7 +141,7 @@ add_task(async function() {
|
||||
loadedInfo.processScripts[uri] = "";
|
||||
}
|
||||
|
||||
checkLoadedScripts({
|
||||
await checkLoadedScripts({
|
||||
loadedInfo,
|
||||
known: known_scripts,
|
||||
intermittent: intermittently_loaded_scripts,
|
||||
|
@ -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"];
|
||||
|
||||
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
17
browser/base/content/test/performance/moz.build
Normal file
17
browser/base/content/test/performance/moz.build
Normal 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",
|
||||
]
|
@ -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 =
|
||||
|
@ -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/.
|
||||
|
@ -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;
|
||||
|
@ -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.
|
||||
|
@ -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"]
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
}
|
||||
});
|
||||
|
@ -12,6 +12,7 @@ COM Intcpt Log
|
||||
COM MTA
|
||||
Cache I/O
|
||||
Cameras IPC
|
||||
CanvasRenderer
|
||||
ChainedPipePump
|
||||
ChainedPipeRecv
|
||||
Checker Test
|
||||
|
@ -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. */
|
||||
|
||||
|
@ -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;
|
||||
|
111
gfx/ipc/CanvasRenderThread.cpp
Normal file
111
gfx/ipc/CanvasRenderThread.cpp
Normal 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
|
50
gfx/ipc/CanvasRenderThread.h
Normal file
50
gfx/ipc/CanvasRenderThread.h
Normal 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__
|
@ -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();
|
||||
|
@ -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",
|
||||
|
@ -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());
|
||||
|
@ -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: ""
|
||||
|
Loading…
Reference in New Issue
Block a user