Merge m-c to autoland, a=merge

MozReview-Commit-ID: K0Q4b2wzvlJ
This commit is contained in:
Wes Kocher 2017-03-03 17:29:54 -08:00
commit 1b29a33fce
306 changed files with 3040 additions and 4257 deletions

View file

@ -40,7 +40,7 @@ function triggerSave(aWindow, aCallback) {
fileName = fp.defaultString;
info("fileName: " + fileName);
destFile.append(fileName);
MockFilePicker.returnFiles = [destFile];
MockFilePicker.setFiles([destFile]);
MockFilePicker.filterIndex = 1; // kSaveAsType_URL
info("done showCallback");
};

View file

@ -45,7 +45,7 @@ function triggerSave(aWindow, aCallback) {
fileName = fp.defaultString;
info("fileName: " + fileName);
destFile.append(fileName);
MockFilePicker.returnFiles = [destFile];
MockFilePicker.setFiles([destFile]);
MockFilePicker.filterIndex = 1; // kSaveAsType_URL
info("done showCallback");
};

View file

@ -58,7 +58,7 @@ function promiseImageDownloaded() {
MockFilePicker.showCallback = function(fp) {
fileName = fp.defaultString;
destFile.append(fileName);
MockFilePicker.returnFiles = [destFile];
MockFilePicker.setFiles([destFile]);
MockFilePicker.filterIndex = 1; // kSaveAsType_URL
};

View file

@ -34,7 +34,7 @@ add_task(function* () {
MockFilePicker.showCallback = function(fp) {
fileName = fp.defaultString;
destFile.append(fileName);
MockFilePicker.returnFiles = [destFile];
MockFilePicker.setFiles([destFile]);
MockFilePicker.filterIndex = 1; // kSaveAsType_URL
};

View file

@ -85,7 +85,7 @@ add_task(function*() {
MockFilePicker.displayDirectory = destDir;
MockFilePicker.showCallback = function(fp) {
destFile.append(fp.defaultString);
MockFilePicker.returnFiles = [destFile];
MockFilePicker.setFiles([destFile]);
MockFilePicker.filterIndex = 1; // kSaveAsType_URL
};

View file

@ -10,14 +10,14 @@ async function installFile(filename) {
let MockFilePicker = SpecialPowers.MockFilePicker;
MockFilePicker.init(window);
MockFilePicker.returnFiles = [file];
MockFilePicker.setFiles([file]);
MockFilePicker.afterOpenCallback = MockFilePicker.cleanup;
await BrowserOpenAddonsMgr("addons://list/extension");
let contentWin = gBrowser.selectedTab.linkedBrowser.contentWindow;
// Do the install...
contentWin.gViewController.doCommand("cmd_installFromFile");
MockFilePicker.cleanup();
}
add_task(() => testInstallMethod(installFile));

View file

@ -13,7 +13,6 @@ support-files =
[browser_forgetaboutsite.js]
[browser_forgetAPI_cookie_getCookiesWithOriginAttributes.js]
[browser_forgetAPI_EME_forgetThisSite.js]
skip-if = e10s # Bug 1315042
[browser_forgetAPI_quota_clearStoragesForPrincipal.js]
[browser_newtabButton.js]
[browser_usercontext.js]

View file

@ -55,7 +55,7 @@ function test() {
is(gDownloadLastDir.file.path, aDisplayDir.path,
"gDownloadLastDir should be the expected display dir");
MockFilePicker.returnFiles = [aFile];
MockFilePicker.setFiles([aFile]);
MockFilePicker.displayDirectory = null;
launcher.saveDestinationAvailable = function(file) {

View file

@ -62,7 +62,7 @@ function test() {
is(gDownloadLastDir.file.path, aDisplayDir.path,
"gDownloadLastDir should be the expected display dir");
MockFilePicker.returnFiles = [aFile];
MockFilePicker.setFiles([aFile]);
MockFilePicker.displayDirectory = null;
aWin.promiseTargetFile(params).then(function() {
// File picker should start with expected display dir.

View file

@ -47,22 +47,23 @@ module.exports = createClass({
fp.init(window,
Strings.GetStringFromName("selectAddonFromFile2"),
Ci.nsIFilePicker.modeOpen);
let res = fp.show();
if (res == Ci.nsIFilePicker.returnCancel || !fp.file) {
return;
}
let file = fp.file;
// AddonManager.installTemporaryAddon accepts either
// addon directory or final xpi file.
if (!file.isDirectory() && !file.leafName.endsWith(".xpi")) {
file = file.parent;
}
fp.open(res => {
if (res == Ci.nsIFilePicker.returnCancel || !fp.file) {
return;
}
let file = fp.file;
// AddonManager.installTemporaryAddon accepts either
// addon directory or final xpi file.
if (!file.isDirectory() && !file.leafName.endsWith(".xpi")) {
file = file.parent;
}
AddonManager.installTemporaryAddon(file)
.catch(e => {
console.error(e);
this.setState({ installError: e.message });
});
AddonManager.installTemporaryAddon(file)
.catch(e => {
console.error(e);
this.setState({ installError: e.message });
});
});
},
render() {

View file

@ -23,7 +23,7 @@ add_task(function* () {
});
add_task(function* () {
let { tab, document } = yield openAboutDebugging("addons");
let { tab, document, window } = yield openAboutDebugging("addons");
yield waitForInitialAddonList(document);
// Start an observer that looks for the install error before
@ -33,9 +33,9 @@ add_task(function* () {
// Mock the file picker to select a test addon
let MockFilePicker = SpecialPowers.MockFilePicker;
MockFilePicker.init(null);
MockFilePicker.init(window);
let file = getSupportsFile("addons/bad/manifest.json");
MockFilePicker.returnFiles = [file.file];
MockFilePicker.setFiles([file.file]);
// Trigger the file picker by clicking on the button
document.getElementById("load-addon-from-file").click();

View file

@ -35,12 +35,13 @@ function* openAboutDebugging(page, win) {
let tab = yield addTab(url, { window: win });
let browser = tab.linkedBrowser;
let document = browser.contentDocument;
let window = browser.contentWindow;
if (!document.querySelector(".app")) {
yield waitForMutation(document.body, { childList: true });
}
return { tab, document };
return { tab, document, window };
}
/**
@ -144,9 +145,9 @@ function getTabList(document) {
function* installAddon({document, path, name, isWebExtension}) {
// Mock the file picker to select a test addon
let MockFilePicker = SpecialPowers.MockFilePicker;
MockFilePicker.init(null);
MockFilePicker.init(window);
let file = getSupportsFile(path);
MockFilePicker.returnFiles = [file.file];
MockFilePicker.setFiles([file.file]);
let addonList = getTemporaryAddonList(document);
let addonListMutation = waitForMutation(addonList, { childList: true });

View file

@ -357,38 +357,40 @@ var SnapshotsListView = Heritage.extend(WidgetMethods, {
fp.appendFilter(L10N.getStr("snapshotsList.saveDialogJSONFilter"), "*.json");
fp.appendFilter(L10N.getStr("snapshotsList.saveDialogAllFilter"), "*.*");
if (fp.show() != Ci.nsIFilePicker.returnOK) {
return;
}
let channel = NetUtil.newChannel({
uri: NetUtil.newURI(fp.file), loadUsingSystemPrincipal: true});
channel.contentType = "text/plain";
NetUtil.asyncFetch(channel, (inputStream, status) => {
if (!Components.isSuccessCode(status)) {
console.error("Could not import recorded animation frame snapshot file.");
return;
}
try {
let string = NetUtil.readInputStreamToString(inputStream, inputStream.available());
var data = JSON.parse(string);
} catch (e) {
console.error("Could not read animation frame snapshot file.");
return;
}
if (data.fileType != CALLS_LIST_SERIALIZER_IDENTIFIER) {
console.error("Unrecognized animation frame snapshot file.");
fp.open(rv => {
if (rv != Ci.nsIFilePicker.returnOK) {
return;
}
// Add a `isLoadedFromDisk` flag on everything to avoid sending invalid
// requests to the backend, since we're not dealing with actors anymore.
let snapshotItem = this.addSnapshot();
snapshotItem.isLoadedFromDisk = true;
data.calls.forEach(e => e.isLoadedFromDisk = true);
let channel = NetUtil.newChannel({
uri: NetUtil.newURI(fp.file), loadUsingSystemPrincipal: true});
channel.contentType = "text/plain";
this.customizeSnapshot(snapshotItem, data.calls, data);
NetUtil.asyncFetch(channel, (inputStream, status) => {
if (!Components.isSuccessCode(status)) {
console.error("Could not import recorded animation frame snapshot file.");
return;
}
try {
let string = NetUtil.readInputStreamToString(inputStream, inputStream.available());
var data = JSON.parse(string);
} catch (e) {
console.error("Could not read animation frame snapshot file.");
return;
}
if (data.fileType != CALLS_LIST_SERIALIZER_IDENTIFIER) {
console.error("Unrecognized animation frame snapshot file.");
return;
}
// Add a `isLoadedFromDisk` flag on everything to avoid sending invalid
// requests to the backend, since we're not dealing with actors anymore.
let snapshotItem = this.addSnapshot();
snapshotItem.isLoadedFromDisk = true;
data.calls.forEach(e => e.isLoadedFromDisk = true);
this.customizeSnapshot(snapshotItem, data.calls, data);
});
});
},

View file

@ -50,11 +50,11 @@ var JsonView = {
* in the parent process.
*/
onSave: function (message) {
let value = message.data;
let file = JsonViewUtils.getTargetFile();
if (file) {
JsonViewUtils.saveToFile(file, value);
}
JsonViewUtils.getTargetFile(file => {
if (file) {
JsonViewUtils.saveToFile(file, message.data);
}
});
}
};

View file

@ -23,21 +23,24 @@ const OPEN_FLAGS = {
* Open File Save As dialog and let the user to pick proper file location.
*/
exports.getTargetFile = function () {
let fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
return new Promise(resolve => {
let fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
let win = getMostRecentBrowserWindow();
fp.init(win, null, Ci.nsIFilePicker.modeSave);
fp.appendFilter("JSON Files", "*.json; *.jsonp;");
fp.appendFilters(Ci.nsIFilePicker.filterText);
fp.appendFilters(Ci.nsIFilePicker.filterAll);
fp.filterIndex = 0;
let win = getMostRecentBrowserWindow();
fp.init(win, null, Ci.nsIFilePicker.modeSave);
fp.appendFilter("JSON Files", "*.json; *.jsonp;");
fp.appendFilters(Ci.nsIFilePicker.filterText);
fp.appendFilters(Ci.nsIFilePicker.filterAll);
fp.filterIndex = 0;
let rv = fp.show();
if (rv == Ci.nsIFilePicker.returnOK || rv == Ci.nsIFilePicker.returnReplace) {
return fp.file;
}
return null;
fp.open(rv => {
if (rv == Ci.nsIFilePicker.returnOK || rv == Ci.nsIFilePicker.returnReplace) {
resolve(fp.file);
} else {
resolve(null);
}
});
});
};
/**

View file

@ -26,8 +26,6 @@ XPCOMUtils.defineLazyGetter(this, "getMostRecentBrowserWindow", function () {
return require("sdk/window/utils").getMostRecentBrowserWindow;
});
const nsIFilePicker = Ci.nsIFilePicker;
const OPEN_FLAGS = {
RDONLY: parseInt("0x01", 16),
WRONLY: parseInt("0x02", 16),
@ -52,30 +50,6 @@ function formatDate(date) {
* Helper API for HAR export features.
*/
var HarUtils = {
/**
* Open File Save As dialog and let the user pick the proper file
* location for generated HAR log.
*/
getTargetFile: function (fileName, jsonp, compress) {
let browser = getMostRecentBrowserWindow();
let fp = Cc["@mozilla.org/filepicker;1"].createInstance(nsIFilePicker);
fp.init(browser, null, nsIFilePicker.modeSave);
fp.appendFilter(
"HTTP Archive Files", "*.har; *.harp; *.json; *.jsonp; *.zip");
fp.appendFilters(nsIFilePicker.filterAll | nsIFilePicker.filterText);
fp.filterIndex = 1;
fp.defaultString = this.getHarFileName(fileName, jsonp, compress);
let rv = fp.show();
if (rv == nsIFilePicker.returnOK || rv == nsIFilePicker.returnReplace) {
return fp.file;
}
return null;
},
getHarFileName: function (defaultFileName, jsonp, compress) {
let extension = jsonp ? ".harp" : ".har";

View file

@ -23,6 +23,8 @@ const SUPPORTED_HEADERS = [
"Access-Control-Request-Headers",
"Access-Control-Request-Method",
"Age",
"Allow",
"Authorization",
"Cache-Control",
"Connection",
"Content-Disposition",
@ -30,6 +32,7 @@ const SUPPORTED_HEADERS = [
"Content-Language",
"Content-Length",
"Content-Location",
"Content-Range",
"Content-Security-Policy",
"Content-Security-Policy-Report-Only",
"Content-Type",
@ -38,7 +41,9 @@ const SUPPORTED_HEADERS = [
"DNT",
"Date",
"ETag",
"Expect",
"Expires",
"Forwarded",
"From",
"Host",
"If-Match",
@ -47,12 +52,16 @@ const SUPPORTED_HEADERS = [
"If-Range",
"If-Unmodified-Since",
"Keep-Alive",
"Large-Allocation",
"Last-Modified",
"Location",
"Origin",
"Pragma",
"Proxy-Authenticate",
"Proxy-Authorization",
"Public-Key-Pins",
"Public-Key-Pins-Report-Only",
"Range",
"Referer",
"Referrer-Policy",
"Retry-After",
@ -68,9 +77,13 @@ const SUPPORTED_HEADERS = [
"User-Agent",
"Vary",
"Via",
"WWW-Authenticate",
"Warning",
"X-Content-Type-Options",
"X-DNS-Prefetch-Control",
"X-Forwarded-For",
"X-Forwarded-Host",
"X-Forwarded-Proto",
"X-Frame-Options",
"X-XSS-Protection"
];
@ -81,28 +94,55 @@ const SUPPORTED_HEADERS = [
*/
const SUPPORTED_HTTP_CODES = [
"100",
"101",
"200",
"201",
"202",
"203",
"204",
"205",
"206",
"300",
"301",
"302",
"303",
"304",
"307",
"308",
"400",
"401",
"403",
"404",
"405",
"406",
"407",
"408",
"409",
"410",
"411",
"412",
"413",
"414",
"415",
"416",
"417",
"426",
"428",
"429",
"431",
"451",
"500",
"501",
"502",
"503",
"504"
"504",
"505",
"511"
];
const GA_PARAMS =
"?utm_source=mozilla&utm_medium=devtools-netmonitor&utm_campaign=default";
/**
* Get the MDN URL for the specified header.
*
@ -115,7 +155,7 @@ function getHeadersURL(header) {
let idx = SUPPORTED_HEADERS.findIndex(item =>
item.toLowerCase() === lowerCaseHeader);
return idx > -1 ?
`https://developer.mozilla.org/docs/Web/HTTP/Headers/${SUPPORTED_HEADERS[idx]}?utm_source=mozilla&utm_medium=devtools-netmonitor&utm_campaign=default` : null;
`https://developer.mozilla.org/docs/Web/HTTP/Headers/${SUPPORTED_HEADERS[idx] + GA_PARAMS}` : null;
}
/**
@ -127,7 +167,7 @@ function getHeadersURL(header) {
*/
function getHTTPStatusCodeURL(statusCode) {
let idx = SUPPORTED_HTTP_CODES.indexOf(statusCode);
return idx > -1 ? `https://developer.mozilla.org/docs/Web/HTTP/Status/${SUPPORTED_HTTP_CODES[idx]}` : null;
return idx > -1 ? `https://developer.mozilla.org/docs/Web/HTTP/Status/${SUPPORTED_HTTP_CODES[idx] + GA_PARAMS}` : null;
}
module.exports = {

View file

@ -359,9 +359,11 @@ var PerformanceView = {
fp.appendFilter(L10N.getStr("recordingsList.saveDialogJSONFilter"), "*.json");
fp.appendFilter(L10N.getStr("recordingsList.saveDialogAllFilter"), "*.*");
if (fp.show() == Ci.nsIFilePicker.returnOK) {
this.emit(EVENTS.UI_IMPORT_RECORDING, fp.file);
}
fp.open(rv => {
if (rv == Ci.nsIFilePicker.returnOK) {
this.emit(EVENTS.UI_IMPORT_RECORDING, fp.file);
}
});
},
/**

View file

@ -110,62 +110,65 @@ function doOK() {
return false;
}
let folder;
/* Chrome mochitest support */
let testOptions = window.arguments[0].testOptions;
if (testOptions) {
folder = testOptions.folder;
} else {
let fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
fp.init(window, "Select directory where to create app directory", Ci.nsIFilePicker.modeGetFolder);
let res = fp.show();
if (res == Ci.nsIFilePicker.returnCancel) {
console.error("No directory selected");
return false;
let promise = new Promise((resolve, reject) => {
let testOptions = window.arguments[0].testOptions;
if (testOptions) {
resolve(testOptions.folder);
} else {
let fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
fp.init(window, "Select directory where to create app directory", Ci.nsIFilePicker.modeGetFolder);
fp.open(res => {
if (res == Ci.nsIFilePicker.returnCancel) {
console.error("No directory selected");
reject(null);
} else {
resolve(fp.file);
}
});
}
folder = fp.file;
}
// Create subfolder with fs-friendly name of project
let subfolder = projectName.replace(/[\\/:*?"<>|]/g, "").toLowerCase();
let win = Services.wm.getMostRecentWindow("devtools:webide");
folder.append(subfolder);
try {
folder.create(Ci.nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY);
} catch (e) {
win.UI.reportError("error_folderCreationFailed");
window.close();
return false;
}
// Download boilerplate zip
let template = gTemplateList[templatelistNode.selectedIndex];
let source = template.file;
let target = folder.clone();
target.append(subfolder + ".zip");
});
let bail = (e) => {
console.error(e);
window.close();
};
Downloads.fetch(source, target).then(() => {
ZipUtils.extractFiles(target, folder);
target.remove(false);
AppProjects.addPackaged(folder).then((project) => {
window.arguments[0].location = project.location;
AppManager.validateAndUpdateProject(project).then(() => {
if (project.manifest) {
project.manifest.name = projectName;
AppManager.writeManifest(project).then(() => {
AppManager.validateAndUpdateProject(project).then(
() => {window.close();}, bail);
}, bail);
} else {
bail("Manifest not found");
}
promise.then(folder => {
// Create subfolder with fs-friendly name of project
let subfolder = projectName.replace(/[\\/:*?"<>|]/g, "").toLowerCase();
let win = Services.wm.getMostRecentWindow("devtools:webide");
folder.append(subfolder);
try {
folder.create(Ci.nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY);
} catch (e) {
win.UI.reportError("error_folderCreationFailed");
window.close();
return;
}
// Download boilerplate zip
let template = gTemplateList[templatelistNode.selectedIndex];
let source = template.file;
let target = folder.clone();
target.append(subfolder + ".zip");
Downloads.fetch(source, target).then(() => {
ZipUtils.extractFiles(target, folder);
target.remove(false);
AppProjects.addPackaged(folder).then((project) => {
window.arguments[0].location = project.location;
AppManager.validateAndUpdateProject(project).then(() => {
if (project.manifest) {
project.manifest.name = projectName;
AppManager.writeManifest(project).then(() => {
AppManager.validateAndUpdateProject(project).then(
() => {window.close();}, bail);
}, bail);
} else {
bail("Manifest not found");
}
}, bail);
}, bail);
}, bail);
}, bail);

View file

@ -289,12 +289,13 @@ var SimulatorEditor = {
case "version":
switch (input.value) {
case "pick":
let file = utils.getCustomBinary(window);
if (file) {
this.version = file.path;
}
// Whatever happens, don't stay on the "pick" option.
this.updateVersionSelector();
utils.getCustomBinary(window).then(file => {
if (file) {
this.version = file.path;
}
// Whatever happens, don't stay on the "pick" option.
this.updateVersionSelector();
});
break;
case "custom":
this.version = input[input.selectedIndex].textContent;
@ -306,12 +307,13 @@ var SimulatorEditor = {
case "profile":
switch (input.value) {
case "pick":
let directory = utils.getCustomProfile(window);
if (directory) {
this.profile = directory.path;
}
// Whatever happens, don't stay on the "pick" option.
this.updateProfileSelector();
utils.getCustomProfile(window).then(directory => {
if (directory) {
this.profile = directory.path;
}
// Whatever happens, don't stay on the "pick" option.
this.updateProfileSelector();
});
break;
case "custom":
this.profile = input[input.selectedIndex].textContent;

View file

@ -92,7 +92,7 @@ ProjectList.prototype = {
let parentWindow = this._parentWindow;
let UI = this._UI;
return UI.busyUntil(Task.spawn(function* () {
let directory = utils.getPackagedDirectory(parentWindow, location);
let directory = yield utils.getPackagedDirectory(parentWindow, location);
if (!directory) {
// User cancelled directory selection

View file

@ -15,15 +15,20 @@ exports.doesFileExist = doesFileExist;
function _getFile(location, ...pickerParams) {
if (location) {
return new FileUtils.File(location);
return Promise.resolve(new FileUtils.File(location));
}
let fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
fp.init(...pickerParams);
let res = fp.show();
if (res == Ci.nsIFilePicker.returnCancel) {
return null;
}
return fp.file;
return new Promise(resolve => {
fp.open(res => {
if (res == Ci.nsIFilePicker.returnCancel) {
resolve(null);
} else {
resolve(fp.file);
}
});
});
}
function getCustomBinary(window, location) {

View file

@ -190,7 +190,7 @@
// Pick custom binary, but act like the user aborted the file picker.
MockFilePicker.returnFiles = [];
MockFilePicker.setFiles([]);
yield set(form.version, "pick");
is(form.version.value, sim20.addonID, "Version selector reverted to last valid choice after customization abort");
@ -198,10 +198,10 @@
// Pick custom binary, and actually follow through. (success, verify value = "custom" and textContent = custom path)
MockFilePicker.useAnyFile();
yield MockFilePicker.useAnyFile();
yield set(form.version, "pick");
let fakeBinary = MockFilePicker.returnFiles[0];
let fakeBinary = MockFilePicker.file;
ok(form.version.value == "custom", "Version selector was set to a new custom binary");
ok(form.version.classList.contains("custom"), "Version selector is now customized");
@ -221,7 +221,7 @@
is(form.profile.value, "default", "Default simulator profile");
ok(!form.profile.classList.contains("custom"), "Profile selector is not customized");
MockFilePicker.returnFiles = [];
MockFilePicker.setFiles([]);
yield set(form.profile, "pick");
is(form.profile.value, "default", "Profile selector reverted to last valid choice after customization abort");
@ -229,7 +229,7 @@
let fakeProfile = FileUtils.getDir("TmpD", []);
MockFilePicker.returnFiles = [ fakeProfile ];
MockFilePicker.setFiles([ fakeProfile ]);
yield set(form.profile, "pick");
ok(form.profile.value == "custom", "Profile selector was set to a new custom directory");

View file

@ -2810,27 +2810,6 @@ nsDOMWindowUtils::GetContainerElement(nsIDOMElement** aResult)
return NS_OK;
}
NS_IMETHODIMP
nsDOMWindowUtils::WrapDOMFile(nsIFile *aFile,
nsISupports **aDOMFile)
{
if (!aFile) {
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow);
NS_ENSURE_STATE(window);
nsPIDOMWindowInner* innerWindow = window->GetCurrentInnerWindow();
if (!innerWindow) {
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIDOMBlob> blob = File::CreateFromFile(innerWindow, aFile);
blob.forget(aDOMFile);
return NS_OK;
}
#ifdef DEBUG
static bool
CheckLeafLayers(Layer* aLayer, const nsIntPoint& aOffset, nsIntRegion* aCoveredRegion)

View file

@ -532,7 +532,6 @@ skip-if = toolkit == 'android' #bug 687032
[test_bug787778.html]
[test_bug789315.html]
[test_bug789856.html]
[test_bug793311.html]
[test_bug804395.html]
[test_bug809003.html]
[test_bug810494.html]

View file

@ -1,35 +0,0 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=793311
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 793311</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="application/javascript">
/** Test for Bug {793311} **/
SimpleTest.waitForExplicitFinish();
try {
SpecialPowers.DOMWindowUtils.wrapDOMFile(null);
ok(false, "wrapDOMFile(null) throws an exception");
} catch(e) {
ok(true, "wrapDOMFile(null) throws an exception");
}
SimpleTest.finish();
</script>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=793311">Mozilla Bug 793311</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
</pre>
</body>
</html>

View file

@ -50,6 +50,16 @@ public:
virtual bool IsSizeUnknown() const override { return false; }
virtual bool IsDateUnknown() const override { return false; }
void SetName(const nsAString& aName)
{
mName = aName;
}
void SetType(const nsAString& aType)
{
mContentType = aType;
}
protected:
virtual ~FileBlobImpl() = default;

View file

@ -82,7 +82,8 @@ FileCreatorHelper::CreateFileInternal(nsPIDOMWindowInner* aWindow,
RefPtr<BlobImpl> blobImpl;
aRv = CreateBlobImpl(aFile, aBag.mType, aBag.mName, lastModifiedPassed,
lastModified, aIsFromNsIFile, getter_AddRefs(blobImpl));
lastModified, aBag.mExistenceCheck, aIsFromNsIFile,
getter_AddRefs(blobImpl));
if (aRv.Failed()) {
return nullptr;
}
@ -130,7 +131,8 @@ FileCreatorHelper::SendRequest(nsIFile* aFile,
}
cc->FileCreationRequest(uuid, this, path, aBag.mType, aBag.mName,
aBag.mLastModified, aIsFromNsIFile);
aBag.mLastModified, aBag.mExistenceCheck,
aIsFromNsIFile);
}
void
@ -151,6 +153,7 @@ FileCreatorHelper::CreateBlobImplForIPC(const nsAString& aPath,
const nsAString& aName,
bool aLastModifiedPassed,
int64_t aLastModified,
bool aExistenceCheck,
bool aIsFromNsIFile,
BlobImpl** aBlobImpl)
{
@ -161,7 +164,7 @@ FileCreatorHelper::CreateBlobImplForIPC(const nsAString& aPath,
}
return CreateBlobImpl(file, aType, aName, aLastModifiedPassed, aLastModified,
aIsFromNsIFile, aBlobImpl);
aExistenceCheck, aIsFromNsIFile, aBlobImpl);
}
/* static */ nsresult
@ -170,9 +173,29 @@ FileCreatorHelper::CreateBlobImpl(nsIFile* aFile,
const nsAString& aName,
bool aLastModifiedPassed,
int64_t aLastModified,
bool aExistenceCheck,
bool aIsFromNsIFile,
BlobImpl** aBlobImpl)
{
if (!aExistenceCheck) {
RefPtr<FileBlobImpl> impl = new FileBlobImpl(aFile);
if (!aName.IsEmpty()) {
impl->SetName(aName);
}
if (!aType.IsEmpty()) {
impl->SetType(aType);
}
if (aLastModifiedPassed) {
impl->SetLastModified(aLastModified);
}
impl.forget(aBlobImpl);
return NS_OK;
}
RefPtr<MultipartBlobImpl> impl = new MultipartBlobImpl(EmptyString());
nsresult rv =
impl->InitializeChromeFile(aFile, aType, aName, aLastModifiedPassed,

View file

@ -51,6 +51,7 @@ public:
const nsAString& aName,
bool aLastModifiedPassed,
int64_t aLastModified,
bool aExistenceCheck,
bool aIsFromNsIFile,
BlobImpl** aBlobImpl);
@ -68,6 +69,7 @@ private:
const nsAString& aName,
bool aLastModifiedPassed,
int64_t aLastModified,
bool aExistenceCheck,
bool aIsFromNsIFile,
BlobImpl** aBlobImpl);

View file

@ -1563,12 +1563,6 @@ interface nsIDOMWindowUtils : nsISupports {
in AString value1,
in AString value2);
/**
* Wrap an nsIFile in an DOM File
* Returns a File object.
*/
nsISupports wrapDOMFile(in nsIFile aFile);
/**
* Get the type of the currently focused html input, if any.
*/

View file

@ -3175,6 +3175,7 @@ ContentChild::FileCreationRequest(nsID& aUUID, FileCreatorHelper* aHelper,
const nsAString& aType,
const nsAString& aName,
const Optional<int64_t>& aLastModified,
bool aExistenceCheck,
bool aIsFromNsIFile)
{
MOZ_ASSERT(aHelper);
@ -3188,7 +3189,8 @@ ContentChild::FileCreationRequest(nsID& aUUID, FileCreatorHelper* aHelper,
Unused << SendFileCreationRequest(aUUID, nsString(aFullPath), nsString(aType),
nsString(aName), lastModifiedPassed,
lastModified, aIsFromNsIFile);
lastModified, aExistenceCheck,
aIsFromNsIFile);
mFileCreationPending.Put(aUUID, aHelper);
}

View file

@ -633,7 +633,7 @@ public:
const nsAString& aFullPath, const nsAString& aType,
const nsAString& aName,
const Optional<int64_t>& aLastModified,
bool aIsFromNsIFile);
bool aExistenceCheck, bool aIsFromNsIFile);
private:
static void ForceKillTimerCallback(nsITimer* aTimer, void* aClosure);

View file

@ -5145,13 +5145,15 @@ ContentParent::RecvFileCreationRequest(const nsID& aID,
const nsString& aName,
const bool& aLastModifiedPassed,
const int64_t& aLastModified,
const bool& aExistenceCheck,
const bool& aIsFromNsIFile)
{
RefPtr<BlobImpl> blobImpl;
nsresult rv =
FileCreatorHelper::CreateBlobImplForIPC(aFullPath, aType, aName,
aLastModifiedPassed,
aLastModified, aIsFromNsIFile,
aLastModified, aExistenceCheck,
aIsFromNsIFile,
getter_AddRefs(blobImpl));
if (NS_WARN_IF(NS_FAILED(rv))) {
if (!SendFileCreationResponse(aID, FileCreationErrorResult(rv))) {

View file

@ -1112,6 +1112,7 @@ private:
const nsString& aType, const nsString& aName,
const bool& aLastModifiedPassed,
const int64_t& aLastModified,
const bool& aExistenceCheck,
const bool& aIsFromNsIFile) override;
virtual mozilla::ipc::IPCResult RecvAccumulateChildHistograms(

View file

@ -1177,7 +1177,8 @@ parent:
async FileCreationRequest(nsID aID, nsString aFullPath, nsString aType,
nsString aName, bool lastModifiedPassed,
int64_t lastModified, bool aIsFromNsIFile);
int64_t lastModified, bool aExistenceCheck,
bool aIsFromNsIFile);
async StoreAndBroadcastBlobURLRegistration(nsCString url, PBlob blob,
Principal principal);

View file

@ -25,7 +25,7 @@
function parentReady(message) {
MockFilePicker.init(content);
MockFilePicker.returnFiles = [message.data.file];
MockFilePicker.setFiles([message.data.file]);
MockFilePicker.returnValue = MockFilePicker.returnOK;
let input = content.document.getElementById("f");

View file

@ -26,6 +26,7 @@ dictionary FilePropertyBag {
dictionary ChromeFilePropertyBag : FilePropertyBag {
DOMString name = "";
boolean existenceCheck = true;
};
// Mozilla extensions

View file

@ -5052,7 +5052,7 @@ HTMLEditRules::CheckForInvisibleBR(Element& aBlock,
/**
* aLists and aTables allow the caller to specify what kind of content to
* "look inside". If aTables is Tables::yes, look inside any table content,
* and insert the inner content into the supplied issupportsarray at offset
* and insert the inner content into the supplied nsTArray at offset
* aIndex. Similarly with aLists and list content. aIndex is updated to
* point past inserted elements.
*/

View file

@ -82,7 +82,7 @@ needs-focus == spellcheck-non-latin-japanese.html spellcheck-non-latin-japanese-
needs-focus == spellcheck-non-latin-korean.html spellcheck-non-latin-korean-ref.html
== unneeded_scroll.html unneeded_scroll-ref.html
== caret_on_presshell_reinit.html caret_on_presshell_reinit-ref.html
fuzzy-if(browserIsRemote,255,3) asserts-if(browserIsRemote,0-2) == caret_on_presshell_reinit-2.html caret_on_presshell_reinit-ref.html
fuzzy-if(browserIsRemote,255,3) asserts-if(browserIsRemote,0-2) asserts-if(webrender&&!browserIsRemote,0-1) == caret_on_presshell_reinit-2.html caret_on_presshell_reinit-ref.html
fuzzy-if(asyncPan&&!layersGPUAccelerated,102,2824) == 642800.html 642800-ref.html
== selection_visibility_after_reframe.html selection_visibility_after_reframe-ref.html
!= selection_visibility_after_reframe-2.html selection_visibility_after_reframe-ref.html

View file

@ -79,4 +79,4 @@ to make sure that mozjs_sys also has its Cargo.lock file updated if needed, henc
the need to run the cargo update command in js/src as well. Hopefully this will
be resolved soon.
Latest Commit: edc74274d28b1fa1229a1d1ea05027f57172b992
Latest Commit: 501e3d79c8a3019762bd8bd2d00eecf7811a84de

View file

@ -1130,7 +1130,7 @@ CompositorBridgeChild::HandleFatalError(const char* aName, const char* aMsg) con
}
PWebRenderBridgeChild*
CompositorBridgeChild::AllocPWebRenderBridgeChild(const wr::PipelineId& aPipelineId, TextureFactoryIdentifier*)
CompositorBridgeChild::AllocPWebRenderBridgeChild(const wr::PipelineId& aPipelineId, TextureFactoryIdentifier*, uint32_t *aIdNamespace)
{
WebRenderBridgeChild* child = new WebRenderBridgeChild(aPipelineId);
child->AddIPDLReference();

View file

@ -223,7 +223,8 @@ public:
void WillEndTransaction();
PWebRenderBridgeChild* AllocPWebRenderBridgeChild(const wr::PipelineId& aPipelineId, TextureFactoryIdentifier*) override;
PWebRenderBridgeChild* AllocPWebRenderBridgeChild(const wr::PipelineId& aPipelineId, TextureFactoryIdentifier*,
uint32_t*) override;
bool DeallocPWebRenderBridgeChild(PWebRenderBridgeChild* aActor) override;
uint64_t DeviceResetSequenceNumber() const {

View file

@ -1572,7 +1572,8 @@ CompositorBridgeParent::RecvAdoptChild(const uint64_t& child)
PWebRenderBridgeParent*
CompositorBridgeParent::AllocPWebRenderBridgeParent(const wr::PipelineId& aPipelineId,
TextureFactoryIdentifier* aTextureFactoryIdentifier)
TextureFactoryIdentifier* aTextureFactoryIdentifier,
uint32_t* aIdNamespace)
{
#ifndef MOZ_ENABLE_WEBRENDER
// Extra guard since this in the parent process and we don't want a malicious
@ -1591,7 +1592,8 @@ CompositorBridgeParent::AllocPWebRenderBridgeParent(const wr::PipelineId& aPipel
RefPtr<WebRenderCompositableHolder> holder = new WebRenderCompositableHolder();
MOZ_ASSERT(api); // TODO have a fallback
api->SetRootPipeline(aPipelineId);
mWrBridge = new WebRenderBridgeParent(this, aPipelineId, mWidget, Move(api), Move(holder));
mWrBridge = new WebRenderBridgeParent(this, aPipelineId, mWidget, nullptr, Move(api), Move(holder));
*aIdNamespace = mWrBridge->GetIdNameSpace();
mCompositorScheduler = mWrBridge->CompositorScheduler();
MOZ_ASSERT(mCompositorScheduler);
@ -1816,8 +1818,44 @@ void
CompositorBridgeParent::DidComposite(TimeStamp& aCompositeStart,
TimeStamp& aCompositeEnd)
{
NotifyDidComposite(mPendingTransaction, aCompositeStart, aCompositeEnd);
mPendingTransaction = 0;
if (mWrBridge) {
NotifyDidComposite(mWrBridge->FlushPendingTransactionIds(), aCompositeStart, aCompositeEnd);
} else {
NotifyDidComposite(mPendingTransaction, aCompositeStart, aCompositeEnd);
mPendingTransaction = 0;
}
}
void
CompositorBridgeParent::NotifyDidCompositeToPipeline(const wr::PipelineId& aPipelineId, const wr::Epoch& aEpoch, TimeStamp& aCompositeStart, TimeStamp& aCompositeEnd)
{
if (mPaused) {
return;
}
MOZ_ASSERT(mWrBridge);
if (mWrBridge->PipelineId() == aPipelineId) {
uint64_t transactionId = mWrBridge->FlushTransactionIdsForEpoch(aEpoch);
Unused << SendDidComposite(0, transactionId, aCompositeStart, aCompositeEnd);
nsTArray<ImageCompositeNotificationInfo> notifications;
mWrBridge->ExtractImageCompositeNotifications(&notifications);
if (!notifications.IsEmpty()) {
Unused << ImageBridgeParent::NotifyImageComposites(notifications);
}
return;
}
MonitorAutoLock lock(*sIndirectLayerTreesLock);
ForEachIndirectLayerTree([&] (LayerTreeState* lts, const uint64_t& aLayersId) -> void {
if (lts->mCrossProcessParent &&
lts->mWrBridge &&
lts->mWrBridge->PipelineId() == aPipelineId) {
CrossProcessCompositorBridgeParent* cpcp = lts->mCrossProcessParent;
uint64_t transactionId = lts->mWrBridge->FlushTransactionIdsForEpoch(aEpoch);
Unused << cpcp->SendDidComposite(aLayersId, transactionId, aCompositeStart, aCompositeEnd);
}
});
}
void

View file

@ -36,6 +36,7 @@
#include "mozilla/layers/MetricsSharingController.h"
#include "mozilla/layers/PCompositorBridgeParent.h"
#include "mozilla/layers/APZTestData.h"
#include "mozilla/webrender/WebRenderTypes.h"
#include "mozilla/widget/CompositorWidget.h"
#include "nsISupportsImpl.h"
#include "ThreadSafeRefcountingWithMainThreadDestruction.h"
@ -118,7 +119,7 @@ public:
virtual void ObserveLayerUpdate(uint64_t aLayersId, uint64_t aEpoch, bool aActive) = 0;
virtual void NotifyDidComposite(uint64_t aTransactionId, TimeStamp& aCompositeStart, TimeStamp& aCompositeEnd) {}
virtual void NotifyDidCompositeToPipeline(const wr::PipelineId& aPipelineId, const wr::Epoch& aEpoch, TimeStamp& aCompositeStart, TimeStamp& aCompositeEnd) {}
// HostIPCAllocator
virtual base::ProcessId GetChildProcessId() override;
@ -451,7 +452,8 @@ public:
}
PWebRenderBridgeParent* AllocPWebRenderBridgeParent(const wr::PipelineId& aPipelineId,
TextureFactoryIdentifier* aTextureFactoryIdentifier) override;
TextureFactoryIdentifier* aTextureFactoryIdentifier,
uint32_t* aIdNamespace) override;
bool DeallocPWebRenderBridgeParent(PWebRenderBridgeParent* aActor) override;
static void SetWebRenderProfilerEnabled(bool aEnabled);
@ -549,7 +551,9 @@ protected:
void DidComposite(TimeStamp& aCompositeStart, TimeStamp& aCompositeEnd);
virtual void NotifyDidComposite(uint64_t aTransactionId, TimeStamp& aCompositeStart, TimeStamp& aCompositeEnd) override;
virtual void NotifyDidCompositeToPipeline(const wr::PipelineId& aPipelineId, const wr::Epoch& aEpoch, TimeStamp& aCompositeStart, TimeStamp& aCompositeEnd) override;
void NotifyDidComposite(uint64_t aTransactionId, TimeStamp& aCompositeStart, TimeStamp& aCompositeEnd);
// The indirect layer tree lock must be held before calling this function.
// Callback should take (LayerTreeState* aState, const uint64_t& aLayersId)

View file

@ -198,7 +198,8 @@ CrossProcessCompositorBridgeParent::DeallocPAPZParent(PAPZParent* aActor)
PWebRenderBridgeParent*
CrossProcessCompositorBridgeParent::AllocPWebRenderBridgeParent(const wr::PipelineId& aPipelineId,
TextureFactoryIdentifier* aTextureFactoryIdentifier)
TextureFactoryIdentifier* aTextureFactoryIdentifier,
uint32_t *aIdNamespace)
{
#ifndef MOZ_ENABLE_WEBRENDER
// Extra guard since this in the parent process and we don't want a malicious
@ -221,12 +222,14 @@ CrossProcessCompositorBridgeParent::AllocPWebRenderBridgeParent(const wr::Pipeli
WebRenderBridgeParent* parent = nullptr;
RefPtr<wr::WebRenderAPI> api = root->GetWebRenderAPI();
RefPtr<WebRenderCompositableHolder> holder = root->CompositableHolder();
parent = new WebRenderBridgeParent(this, aPipelineId, nullptr, Move(api), Move(holder));
parent = new WebRenderBridgeParent(this, aPipelineId, nullptr, root->CompositorScheduler(), Move(api), Move(holder));
parent->AddRef(); // IPDL reference
sIndirectLayerTrees[pipelineHandle].mCrossProcessParent = this;
sIndirectLayerTrees[pipelineHandle].mWrBridge = parent;
*aTextureFactoryIdentifier = parent->GetTextureFactoryIdentifier();
*aIdNamespace = parent->GetIdNameSpace();
return parent;
}
@ -323,8 +326,7 @@ CrossProcessCompositorBridgeParent::DidComposite(
Unused << SendDidComposite(aId, layerTree->GetPendingTransactionId(), aCompositeStart, aCompositeEnd);
layerTree->SetPendingTransactionId(0);
} else if (WebRenderBridgeParent* wrbridge = sIndirectLayerTrees[aId].mWrBridge) {
Unused << SendDidComposite(aId, wrbridge->GetPendingTransactionId(), aCompositeStart, aCompositeEnd);
wrbridge->SetPendingTransactionId(0);
Unused << SendDidComposite(aId, wrbridge->FlushPendingTransactionIds(), aCompositeStart, aCompositeEnd);
}
}

View file

@ -152,7 +152,8 @@ public:
virtual void UpdatePaintTime(LayerTransactionParent* aLayerTree, const TimeDuration& aPaintTime) override;
PWebRenderBridgeParent* AllocPWebRenderBridgeParent(const wr::PipelineId& aPipelineId,
TextureFactoryIdentifier* aTextureFactoryIdentifier) override;
TextureFactoryIdentifier* aTextureFactoryIdentifier,
uint32_t* aIdNamespace) override;
bool DeallocPWebRenderBridgeParent(PWebRenderBridgeParent* aActor) override;
void ObserveLayerUpdate(uint64_t aLayersId, uint64_t aEpoch, bool aActive) override;

View file

@ -243,7 +243,7 @@ parent:
// The pipelineId is the same as the layersId
sync PWebRenderBridge(PipelineId pipelineId)
returns (TextureFactoryIdentifier textureFactoryIdentifier);
returns (TextureFactoryIdentifier textureFactoryIdentifier, uint32_t idNamespace); //XXX: use the WrIdNamespace type
child:
// Send back Compositor Frame Metrics from APZCs so tiled layers can

View file

@ -18,6 +18,8 @@ using struct mozilla::layers::TextureInfo from "mozilla/layers/CompositorTypes.h
using mozilla::layers::CompositableHandle from "mozilla/layers/LayersTypes.h";
using mozilla::wr::ByteBuffer from "mozilla/webrender/WebRenderTypes.h";
using mozilla::wr::ImageKey from "mozilla/webrender/WebRenderTypes.h";
using WrBuiltDisplayListDescriptor from "mozilla/webrender/webrender_ffi.h";
using WrAuxiliaryListsDescriptor from "mozilla/webrender/webrender_ffi.h";
namespace mozilla {
namespace layers {
@ -31,15 +33,17 @@ parent:
async ReleaseCompositable(CompositableHandle compositable);
sync Create(IntSize aSize);
sync AddImage(IntSize aSize, uint32_t aStride,
SurfaceFormat aFormat, ByteBuffer aBytes)
returns (ImageKey aOutImageKey);
sync AddImage(ImageKey aImageKey, IntSize aSize, uint32_t aStride,
SurfaceFormat aFormat, ByteBuffer aBytes);
sync UpdateImage(ImageKey aImageKey, IntSize aSize,
SurfaceFormat aFormat, ByteBuffer aBytes);
sync DeleteImage(ImageKey aImageKey);
async AddRawFont(FontKey aFontKey, ByteBuffer aBytes, uint32_t aFontIndex);
async DPBegin(IntSize aSize);
async DPEnd(WebRenderCommand[] commands, OpDestroy[] toDestroy, uint64_t fwdTransactionId, uint64_t transactionId);
sync DPSyncEnd(WebRenderCommand[] commands, OpDestroy[] toDestroy, uint64_t fwdTransactionId, uint64_t transactionId);
async DPEnd(IntSize aSize, WebRenderParentCommand[] commands, OpDestroy[] toDestroy, uint64_t fwdTransactionId, uint64_t transactionId,
ByteBuffer aDL, WrBuiltDisplayListDescriptor aDLDesc, ByteBuffer aAux, WrAuxiliaryListsDescriptor aAuxDesc);
sync DPSyncEnd(IntSize aSize, WebRenderParentCommand[] commands, OpDestroy[] toDestroy, uint64_t fwdTransactionId, uint64_t transactionId,
ByteBuffer aDL, WrBuiltDisplayListDescriptor aDLDesc, ByteBuffer aAux, WrAuxiliaryListsDescriptor aAuxDesc);
sync DPGetSnapshot(PTexture texture);
async AddExternalImageId(uint64_t aImageId, CompositableHandle aHandle);
async AddExternalImageIdForCompositable(uint64_t aImageId, CompositableHandle aHandle);

View file

@ -26,6 +26,7 @@ using mozilla::wr::ByteBuffer from "mozilla/webrender/WebRenderTypes.h";
using mozilla::wr::PipelineId from "mozilla/webrender/WebRenderTypes.h";
using mozilla::wr::ImageRendering from "mozilla/webrender/WebRenderTypes.h";
using mozilla::wr::ImageKey from "mozilla/webrender/WebRenderTypes.h";
using mozilla::wr::FontKey from "mozilla/webrender/WebRenderTypes.h";
using mozilla::LayerIntRegion from "Units.h";
namespace mozilla {
@ -97,13 +98,9 @@ struct OpDPPushImage {
ImageKey key;
};
struct OpDPPushExternalImageId {
LayerIntRegion validBufferRegion;
WrRect bounds;
WrRect clip;
MaybeImageMask mask;
ImageRendering filter;
struct OpAddExternalImage {
uint64_t externalImageId;
ImageKey key;
};
struct OpDPPushIframe {
@ -116,10 +113,8 @@ struct OpDPPushText {
WrRect bounds;
WrRect clip;
WrGlyphArray[] glyph_array;
uint32_t font_index;
float glyph_size;
ByteBuffer font_buffer;
uint32_t font_buffer_length;
FontKey key;
};
struct OpDPPushBoxShadow {
@ -144,10 +139,13 @@ union WebRenderCommand {
OpDPPushLinearGradient;
OpDPPushRadialGradient;
OpDPPushImage;
OpDPPushExternalImageId;
OpDPPushIframe;
OpDPPushText;
OpDPPushBoxShadow;
};
union WebRenderParentCommand {
OpAddExternalImage;
CompositableOperation;
};

View file

@ -11,12 +11,16 @@
#include "mozilla/layers/CompositorBridgeChild.h"
#include "mozilla/layers/ImageDataSerializer.h"
#include "mozilla/layers/PTextureChild.h"
#include "mozilla/webrender/WebRenderAPI.h"
namespace mozilla {
namespace layers {
WebRenderBridgeChild::WebRenderBridgeChild(const wr::PipelineId& aPipelineId)
: mIsInTransaction(false)
, mIdNamespace(0)
, mResourceId(0)
, mPipelineId(aPipelineId)
, mIPCOpen(false)
, mDestroyed(false)
{
@ -55,6 +59,20 @@ WebRenderBridgeChild::AddWebRenderCommands(const nsTArray<WebRenderCommand>& aCo
mCommands.AppendElements(aCommands);
}
void
WebRenderBridgeChild::AddWebRenderParentCommand(const WebRenderParentCommand& aCmd)
{
MOZ_ASSERT(mIsInTransaction);
mParentCommands.AppendElement(aCmd);
}
void
WebRenderBridgeChild::AddWebRenderParentCommands(const nsTArray<WebRenderParentCommand>& aCommands)
{
MOZ_ASSERT(mIsInTransaction);
mParentCommands.AppendElements(aCommands);
}
bool
WebRenderBridgeChild::DPBegin(const gfx::IntSize& aSize)
{
@ -67,18 +85,132 @@ WebRenderBridgeChild::DPBegin(const gfx::IntSize& aSize)
return true;
}
wr::BuiltDisplayList
WebRenderBridgeChild::ProcessWebrenderCommands(const gfx::IntSize &aSize,
InfallibleTArray<WebRenderCommand>& aCommands)
{
wr::DisplayListBuilder builder(mPipelineId);
builder.Begin(ViewAs<LayerPixel>(aSize));
for (InfallibleTArray<WebRenderCommand>::index_type i = 0; i < aCommands.Length(); ++i) {
const WebRenderCommand& cmd = aCommands[i];
switch (cmd.type()) {
case WebRenderCommand::TOpDPPushStackingContext: {
const OpDPPushStackingContext& op = cmd.get_OpDPPushStackingContext();
builder.PushStackingContext(op.bounds(), op.overflow(), op.mask().ptrOr(nullptr), op.opacity(), op.matrix(), op.mixBlendMode());
break;
}
case WebRenderCommand::TOpDPPopStackingContext: {
builder.PopStackingContext();
break;
}
case WebRenderCommand::TOpDPPushScrollLayer: {
const OpDPPushScrollLayer& op = cmd.get_OpDPPushScrollLayer();
builder.PushScrollLayer(op.bounds(), op.overflow(), op.mask().ptrOr(nullptr));
break;
}
case WebRenderCommand::TOpDPPopScrollLayer: {
builder.PopScrollLayer();
break;
}
case WebRenderCommand::TOpDPPushRect: {
const OpDPPushRect& op = cmd.get_OpDPPushRect();
builder.PushRect(op.bounds(), op.clip(), op.color());
break;
}
case WebRenderCommand::TOpDPPushBorder: {
const OpDPPushBorder& op = cmd.get_OpDPPushBorder();
builder.PushBorder(op.bounds(), op.clip(),
op.top(), op.right(), op.bottom(), op.left(),
op.radius());
break;
}
case WebRenderCommand::TOpDPPushLinearGradient: {
const OpDPPushLinearGradient& op = cmd.get_OpDPPushLinearGradient();
builder.PushLinearGradient(op.bounds(), op.clip(),
op.startPoint(), op.endPoint(),
op.stops(), op.extendMode());
break;
}
case WebRenderCommand::TOpDPPushRadialGradient: {
const OpDPPushRadialGradient& op = cmd.get_OpDPPushRadialGradient();
builder.PushRadialGradient(op.bounds(), op.clip(),
op.startCenter(), op.endCenter(),
op.startRadius(), op.endRadius(),
op.stops(), op.extendMode());
break;
}
case WebRenderCommand::TOpDPPushImage: {
const OpDPPushImage& op = cmd.get_OpDPPushImage();
builder.PushImage(op.bounds(), op.clip(),
op.mask().ptrOr(nullptr), op.filter(), wr::ImageKey(op.key()));
break;
}
case WebRenderCommand::TOpDPPushIframe: {
const OpDPPushIframe& op = cmd.get_OpDPPushIframe();
builder.PushIFrame(op.bounds(), op.clip(), op.pipelineId());
break;
}
case WebRenderCommand::TOpDPPushText: {
const OpDPPushText& op = cmd.get_OpDPPushText();
const nsTArray<WrGlyphArray>& glyph_array = op.glyph_array();
for (size_t i = 0; i < glyph_array.Length(); i++) {
const nsTArray<WrGlyphInstance>& glyphs = glyph_array[i].glyphs;
builder.PushText(op.bounds(),
op.clip(),
glyph_array[i].color,
op.key(),
Range<const WrGlyphInstance>(glyphs.Elements(), glyphs.Length()),
op.glyph_size());
}
break;
}
case WebRenderCommand::TOpDPPushBoxShadow: {
const OpDPPushBoxShadow& op = cmd.get_OpDPPushBoxShadow();
builder.PushBoxShadow(op.rect(),
op.clip(),
op.box_bounds(),
op.offset(),
op.color(),
op.blur_radius(),
op.spread_radius(),
op.border_radius(),
op.clip_mode());
break;
}
default:
NS_RUNTIMEABORT("not reached");
}
}
builder.End();
wr::BuiltDisplayList dl;
builder.Finalize(dl.dl_desc, dl.dl, dl.aux_desc, dl.aux);
return dl;
}
void
WebRenderBridgeChild::DPEnd(bool aIsSync, uint64_t aTransactionId)
WebRenderBridgeChild::DPEnd(const gfx::IntSize& aSize, bool aIsSync, uint64_t aTransactionId)
{
MOZ_ASSERT(!mDestroyed);
MOZ_ASSERT(mIsInTransaction);
wr::BuiltDisplayList dl = ProcessWebrenderCommands(aSize, mCommands);
ByteBuffer dlData(Move(dl.dl));
ByteBuffer auxData(Move(dl.aux));
if (aIsSync) {
this->SendDPSyncEnd(mCommands, mDestroyedActors, GetFwdTransactionId(), aTransactionId);
this->SendDPSyncEnd(aSize, mParentCommands, mDestroyedActors, GetFwdTransactionId(), aTransactionId,
dlData, dl.dl_desc, auxData, dl.aux_desc);
} else {
this->SendDPEnd(mCommands, mDestroyedActors, GetFwdTransactionId(), aTransactionId);
this->SendDPEnd(aSize, mParentCommands, mDestroyedActors, GetFwdTransactionId(), aTransactionId,
dlData, dl.dl_desc, auxData, dl.aux_desc);
}
mCommands.Clear();
mParentCommands.Clear();
mDestroyedActors.Clear();
mIsInTransaction = false;
}
@ -221,7 +353,7 @@ WebRenderBridgeChild::RemoveTextureFromCompositable(CompositableClient* aComposi
return;
}
AddWebRenderCommand(
AddWebRenderParentCommand(
CompositableOperation(
aCompositable->GetIPCHandle(),
OpRemoveTexture(nullptr, aTexture->GetIPDLActor())));
@ -251,7 +383,7 @@ WebRenderBridgeChild::UseTextures(CompositableClient* aCompositable,
t.mFrameID, t.mProducerID));
GetCompositorBridgeChild()->HoldUntilCompositableRefReleasedIfNecessary(t.mTextureClient);
}
AddWebRenderCommand(CompositableOperation(aCompositable->GetIPCHandle(),
AddWebRenderParentCommand(CompositableOperation(aCompositable->GetIPCHandle(),
OpUseTexture(textures)));
}

View file

@ -32,9 +32,11 @@ public:
void AddWebRenderCommand(const WebRenderCommand& aCmd);
void AddWebRenderCommands(const nsTArray<WebRenderCommand>& aCommands);
void AddWebRenderParentCommand(const WebRenderParentCommand& aCmd);
void AddWebRenderParentCommands(const nsTArray<WebRenderParentCommand>& aCommands);
bool DPBegin(const gfx::IntSize& aSize);
void DPEnd(bool aIsSync, uint64_t aTransactionId);
void DPEnd(const gfx::IntSize& aSize, bool aIsSync, uint64_t aTransactionId);
CompositorBridgeChild* GetCompositorBridgeChild();
@ -54,6 +56,13 @@ public:
bool IPCOpen() const { return mIPCOpen && !mDestroyed; }
bool IsDestroyed() const { return mDestroyed; }
uint32_t GetNextResourceId() { return ++mResourceId; }
uint32_t GetNamespace() { return mIdNamespace; }
void SetNamespace(uint32_t aIdNamespace)
{
mIdNamespace = aIdNamespace;
}
private:
friend class CompositorBridgeChild;
@ -61,6 +70,9 @@ private:
uint64_t GetNextExternalImageId();
wr::BuiltDisplayList ProcessWebrenderCommands(const gfx::IntSize &aSize,
InfallibleTArray<WebRenderCommand>& aCommands);
// CompositableForwarder
void Connect(CompositableClient* aCompositable,
ImageContainer* aImageContainer = nullptr) override;
@ -99,9 +111,13 @@ private:
bool AddOpDestroy(const OpDestroy& aOp);
nsTArray<WebRenderCommand> mCommands;
nsTArray<WebRenderParentCommand> mParentCommands;
nsTArray<OpDestroy> mDestroyedActors;
nsDataHashtable<nsUint64HashKey, CompositableClient*> mCompositables;
bool mIsInTransaction;
uint32_t mIdNamespace;
uint32_t mResourceId;
wr::PipelineId mPipelineId;
bool mIPCOpen;
bool mDestroyed;

View file

@ -21,6 +21,11 @@
#include "mozilla/webrender/RenderThread.h"
#include "mozilla/widget/CompositorWidget.h"
bool is_in_main_thread()
{
return NS_IsMainThread();
}
bool is_in_compositor_thread()
{
return mozilla::layers::CompositorThreadHolder::IsInCompositorThread();
@ -75,24 +80,29 @@ private:
InfallibleTArray<OpDestroy>* mActorsToDestroy;
};
/* static */ uint32_t WebRenderBridgeParent::sIdNameSpace = 0;
WebRenderBridgeParent::WebRenderBridgeParent(CompositorBridgeParentBase* aCompositorBridge,
const wr::PipelineId& aPipelineId,
widget::CompositorWidget* aWidget,
CompositorVsyncScheduler* aScheduler,
RefPtr<wr::WebRenderAPI>&& aApi,
RefPtr<WebRenderCompositableHolder>&& aHolder)
: mCompositorBridge(aCompositorBridge)
, mPipelineId(aPipelineId)
, mWidget(aWidget)
, mBuilder(Nothing())
, mApi(aApi)
, mCompositableHolder(aHolder)
, mCompositorScheduler(aScheduler)
, mChildLayerObserverEpoch(0)
, mParentLayerObserverEpoch(0)
, mPendingTransactionId(0)
, mWrEpoch(0)
, mIdNameSpace(++sIdNameSpace)
, mDestroyed(false)
{
MOZ_ASSERT(mCompositableHolder);
if (mWidget) {
MOZ_ASSERT(!mCompositorScheduler);
mCompositorScheduler = new CompositorVsyncScheduler(this, mWidget);
}
}
@ -105,11 +115,7 @@ WebRenderBridgeParent::RecvCreate(const gfx::IntSize& aSize)
return IPC_OK();
}
if (mBuilder.isSome()) {
return IPC_OK();
}
MOZ_ASSERT(mApi);
mBuilder.emplace(LayerIntSize(aSize.width, aSize.height), mPipelineId);
return IPC_OK();
}
@ -133,29 +139,45 @@ WebRenderBridgeParent::Destroy()
if (mDestroyed) {
return;
}
MOZ_ASSERT(mBuilder.isSome());
mDestroyed = true;
ClearResources();
}
mozilla::ipc::IPCResult
WebRenderBridgeParent::RecvAddImage(const gfx::IntSize& aSize,
WebRenderBridgeParent::RecvAddImage(const wr::ImageKey& aImageKey,
const gfx::IntSize& aSize,
const uint32_t& aStride,
const gfx::SurfaceFormat& aFormat,
const ByteBuffer& aBuffer,
wr::ImageKey* aOutImageKey)
const ByteBuffer& aBuffer)
{
if (mDestroyed) {
return IPC_OK();
}
MOZ_ASSERT(mApi);
wr::ImageDescriptor descriptor(aSize, aStride, aFormat);
*aOutImageKey = mApi->AddImageBuffer(descriptor,
aBuffer.AsSlice());
mApi->AddImage(aImageKey, descriptor,
aBuffer.AsSlice());
return IPC_OK();
}
mozilla::ipc::IPCResult
WebRenderBridgeParent::RecvAddRawFont(const wr::FontKey& aFontKey,
const ByteBuffer& aBuffer,
const uint32_t& aFontIndex)
{
if (mDestroyed) {
return IPC_OK();
}
MOZ_ASSERT(mApi);
auto slice = aBuffer.AsSlice();
mApi->AddRawFont(aFontKey, slice);
return IPC_OK();
}
mozilla::ipc::IPCResult
WebRenderBridgeParent::RecvUpdateImage(const wr::ImageKey& aImageKey,
const gfx::IntSize& aSize,
@ -189,16 +211,19 @@ WebRenderBridgeParent::RecvDPBegin(const gfx::IntSize& aSize)
if (mDestroyed) {
return IPC_OK();
}
MOZ_ASSERT(mBuilder.isSome());
mBuilder.ref().Begin(LayerIntSize(aSize.width, aSize.height));
return IPC_OK();
}
void
WebRenderBridgeParent::HandleDPEnd(InfallibleTArray<WebRenderCommand>&& aCommands,
WebRenderBridgeParent::HandleDPEnd(const gfx::IntSize& aSize,
InfallibleTArray<WebRenderParentCommand>&& aCommands,
InfallibleTArray<OpDestroy>&& aToDestroy,
const uint64_t& aFwdTransactionId,
const uint64_t& aTransactionId)
const uint64_t& aTransactionId,
const ByteBuffer& dl,
const WrBuiltDisplayListDescriptor& dlDesc,
const ByteBuffer& aux,
const WrAuxiliaryListsDescriptor& auxDesc)
{
UpdateFwdTransactionId(aFwdTransactionId);
@ -212,100 +237,61 @@ WebRenderBridgeParent::HandleDPEnd(InfallibleTArray<WebRenderCommand>&& aCommand
// to early-return from RecvDPEnd without doing so.
AutoWebRenderBridgeParentAsyncMessageSender autoAsyncMessageSender(this, &aToDestroy);
ProcessWebrenderCommands(aCommands, wr::NewEpoch(aTransactionId));
// The transaction ID might get reset to 1 if the page gets reloaded, see
// https://bugzilla.mozilla.org/show_bug.cgi?id=1145295#c41
// Otherwise, it should be continually increasing.
MOZ_ASSERT(aTransactionId == 1 || aTransactionId > mPendingTransactionId);
mPendingTransactionId = aTransactionId;
++mWrEpoch; // Update webrender epoch
ProcessWebrenderCommands(aSize, aCommands, wr::NewEpoch(mWrEpoch),
dl, dlDesc, aux, auxDesc);
HoldPendingTransactionId(mWrEpoch, aTransactionId);
}
mozilla::ipc::IPCResult
WebRenderBridgeParent::RecvDPEnd(InfallibleTArray<WebRenderCommand>&& aCommands,
WebRenderBridgeParent::RecvDPEnd(const gfx::IntSize& aSize,
InfallibleTArray<WebRenderParentCommand>&& aCommands,
InfallibleTArray<OpDestroy>&& aToDestroy,
const uint64_t& aFwdTransactionId,
const uint64_t& aTransactionId)
const uint64_t& aTransactionId,
const ByteBuffer& dl,
const WrBuiltDisplayListDescriptor& dlDesc,
const ByteBuffer& aux,
const WrAuxiliaryListsDescriptor& auxDesc)
{
HandleDPEnd(Move(aCommands), Move(aToDestroy), aFwdTransactionId, aTransactionId);
HandleDPEnd(aSize, Move(aCommands), Move(aToDestroy), aFwdTransactionId, aTransactionId,
dl, dlDesc, aux, auxDesc);
return IPC_OK();
}
mozilla::ipc::IPCResult
WebRenderBridgeParent::RecvDPSyncEnd(InfallibleTArray<WebRenderCommand>&& aCommands,
WebRenderBridgeParent::RecvDPSyncEnd(const gfx::IntSize &aSize,
InfallibleTArray<WebRenderParentCommand>&& aCommands,
InfallibleTArray<OpDestroy>&& aToDestroy,
const uint64_t& aFwdTransactionId,
const uint64_t& aTransactionId)
const uint64_t& aTransactionId,
const ByteBuffer& dl,
const WrBuiltDisplayListDescriptor& dlDesc,
const ByteBuffer& aux,
const WrAuxiliaryListsDescriptor& auxDesc)
{
HandleDPEnd(Move(aCommands), Move(aToDestroy), aFwdTransactionId, aTransactionId);
HandleDPEnd(aSize, Move(aCommands), Move(aToDestroy), aFwdTransactionId, aTransactionId,
dl, dlDesc, aux, auxDesc);
return IPC_OK();
}
void
WebRenderBridgeParent::ProcessWebrenderCommands(InfallibleTArray<WebRenderCommand>& aCommands, const wr::Epoch& aEpoch)
WebRenderBridgeParent::ProcessWebrenderCommands(const gfx::IntSize &aSize,
InfallibleTArray<WebRenderParentCommand>& aCommands, const wr::Epoch& aEpoch,
const ByteBuffer& dl,
const WrBuiltDisplayListDescriptor& dlDesc,
const ByteBuffer& aux,
const WrAuxiliaryListsDescriptor& auxDesc)
{
MOZ_ASSERT(mBuilder.isSome());
wr::DisplayListBuilder& builder = mBuilder.ref();
// XXX remove it when external image key is used.
std::vector<wr::ImageKey> keysToDelete;
for (InfallibleTArray<WebRenderCommand>::index_type i = 0; i < aCommands.Length(); ++i) {
const WebRenderCommand& cmd = aCommands[i];
for (InfallibleTArray<WebRenderParentCommand>::index_type i = 0; i < aCommands.Length(); ++i) {
const WebRenderParentCommand& cmd = aCommands[i];
switch (cmd.type()) {
case WebRenderCommand::TOpDPPushStackingContext: {
const OpDPPushStackingContext& op = cmd.get_OpDPPushStackingContext();
builder.PushStackingContext(op.bounds(), op.overflow(), op.mask().ptrOr(nullptr), op.opacity(), op.matrix(), op.mixBlendMode());
break;
}
case WebRenderCommand::TOpDPPopStackingContext: {
builder.PopStackingContext();
break;
}
case WebRenderCommand::TOpDPPushScrollLayer: {
const OpDPPushScrollLayer& op = cmd.get_OpDPPushScrollLayer();
builder.PushScrollLayer(op.bounds(), op.overflow(), op.mask().ptrOr(nullptr));
break;
}
case WebRenderCommand::TOpDPPopScrollLayer: {
builder.PopScrollLayer();
break;
}
case WebRenderCommand::TOpDPPushRect: {
const OpDPPushRect& op = cmd.get_OpDPPushRect();
builder.PushRect(op.bounds(), op.clip(), op.color());
break;
}
case WebRenderCommand::TOpDPPushBorder: {
const OpDPPushBorder& op = cmd.get_OpDPPushBorder();
builder.PushBorder(op.bounds(), op.clip(),
op.top(), op.right(), op.bottom(), op.left(),
op.radius());
break;
}
case WebRenderCommand::TOpDPPushLinearGradient: {
const OpDPPushLinearGradient& op = cmd.get_OpDPPushLinearGradient();
builder.PushLinearGradient(op.bounds(), op.clip(),
op.startPoint(), op.endPoint(),
op.stops(), op.extendMode());
break;
}
case WebRenderCommand::TOpDPPushRadialGradient: {
const OpDPPushRadialGradient& op = cmd.get_OpDPPushRadialGradient();
builder.PushRadialGradient(op.bounds(), op.clip(),
op.startCenter(), op.endCenter(),
op.startRadius(), op.endRadius(),
op.stops(), op.extendMode());
break;
}
case WebRenderCommand::TOpDPPushImage: {
const OpDPPushImage& op = cmd.get_OpDPPushImage();
builder.PushImage(op.bounds(), op.clip(),
op.mask().ptrOr(nullptr), op.filter(), wr::ImageKey(op.key()));
break;
}
case WebRenderCommand::TOpDPPushExternalImageId: {
const OpDPPushExternalImageId& op = cmd.get_OpDPPushExternalImageId();
case WebRenderParentCommand::TOpAddExternalImage: {
const OpAddExternalImage& op = cmd.get_OpAddExternalImage();
MOZ_ASSERT(mExternalImageIds.Get(op.externalImageId()).get());
RefPtr<CompositableHost> host = mExternalImageIds.Get(op.externalImageId());
@ -317,38 +303,17 @@ WebRenderBridgeParent::ProcessWebrenderCommands(InfallibleTArray<WebRenderComman
break;
}
nsIntRegion validBufferRegion = op.validBufferRegion().ToUnknownRegion();
IntRect validRect = IntRect(IntPoint(0,0), dSurf->GetSize());
if (!validBufferRegion.IsEmpty()) {
IntPoint offset = validBufferRegion.GetBounds().TopLeft();
validBufferRegion.MoveBy(-offset);
validBufferRegion.AndWith(IntRect(IntPoint(0,0), dSurf->GetSize()));
validRect = validBufferRegion.GetBounds().ToUnknownRect();
// XXX Remove it when we can put subimage in WebRender.
RefPtr<DrawTarget> target =
gfx::Factory::CreateDrawTarget(gfx::BackendType::SKIA, validRect.Size(), SurfaceFormat::B8G8R8A8);
for (auto iter = validBufferRegion.RectIter(); !iter.Done(); iter.Next()) {
IntRect regionRect = iter.Get();
Rect srcRect(regionRect.x + offset.x, regionRect.y + offset.y, regionRect.width, regionRect.height);
Rect dstRect(regionRect.x, regionRect.y, regionRect.width, regionRect.height);
target->DrawSurface(dSurf, dstRect, srcRect);
}
RefPtr<SourceSurface> surf = target->Snapshot();
dSurf = surf->GetDataSurface();
}
DataSourceSurface::MappedSurface map;
if (!dSurf->Map(gfx::DataSourceSurface::MapType::READ, &map)) {
break;
}
wr::ImageDescriptor descriptor(validRect.Size(), map.mStride, SurfaceFormat::B8G8R8A8);
wr::ImageKey key;
auto slice = Range<uint8_t>(map.mData, validRect.height * map.mStride);
key = mApi->AddImageBuffer(descriptor, slice);
IntSize size = dSurf->GetSize();
wr::ImageDescriptor descriptor(size, map.mStride, SurfaceFormat::B8G8R8A8);
wr::ImageKey key = op.key();
auto slice = Range<uint8_t>(map.mData, size.height * map.mStride);
mApi->AddImage(key, descriptor, slice);
builder.PushImage(op.bounds(), op.clip(), op.mask().ptrOr(nullptr), op.filter(), key);
keysToDelete.push_back(key);
dSurf->Unmap();
// XXX workaround for releasing Readlock. See Bug 1339625
@ -357,56 +322,22 @@ WebRenderBridgeParent::ProcessWebrenderCommands(InfallibleTArray<WebRenderComman
}
break;
}
case WebRenderCommand::TOpDPPushIframe: {
const OpDPPushIframe& op = cmd.get_OpDPPushIframe();
builder.PushIFrame(op.bounds(), op.clip(), op.pipelineId());
break;
}
case WebRenderCommand::TCompositableOperation: {
case WebRenderParentCommand::TCompositableOperation: {
if (!ReceiveCompositableUpdate(cmd.get_CompositableOperation())) {
NS_ERROR("ReceiveCompositableUpdate failed");
}
break;
}
case WebRenderCommand::TOpDPPushText: {
const OpDPPushText& op = cmd.get_OpDPPushText();
const nsTArray<WrGlyphArray>& glyph_array = op.glyph_array();
// TODO: We are leaking the key
wr::FontKey fontKey;
auto slice = Range<uint8_t>(op.font_buffer().mData, op.font_buffer_length());
fontKey = mApi->AddRawFont(slice);
for (size_t i = 0; i < glyph_array.Length(); i++) {
const nsTArray<WrGlyphInstance>& glyphs = glyph_array[i].glyphs;
builder.PushText(op.bounds(),
op.clip(),
glyph_array[i].color,
fontKey,
Range<const WrGlyphInstance>(glyphs.Elements(), glyphs.Length()),
op.glyph_size());
}
default: {
// other commands are handle on the child
break;
}
case WebRenderCommand::TOpDPPushBoxShadow: {
const OpDPPushBoxShadow& op = cmd.get_OpDPPushBoxShadow();
builder.PushBoxShadow(op.rect(),
op.clip(),
op.box_bounds(),
op.offset(),
op.color(),
op.blur_radius(),
op.spread_radius(),
op.border_radius(),
op.clip_mode());
break;
}
default:
NS_RUNTIMEABORT("not reached");
}
}
builder.End(*mApi, aEpoch);
mApi->SetRootDisplayList(gfx::Color(0.3f, 0.f, 0.f, 1.f), aEpoch, LayerSize(aSize.width, aSize.height),
mPipelineId,
dlDesc, dl.mData, dl.mLength,
auxDesc, aux.mData, aux.mLength);
ScheduleComposition();
DeleteOldImages();
@ -459,7 +390,11 @@ WebRenderBridgeParent::RecvDPGetSnapshot(PTextureParent* aTexture)
// Assert the stride of the buffer is what webrender expects
MOZ_ASSERT((uint32_t)(size.width * 4) == stride);
MOZ_ASSERT(mBuilder.isSome());
if (mCompositorScheduler->NeedsComposite()) {
mCompositorScheduler->CancelCurrentCompositeTask();
mCompositorScheduler->ForceComposeToTarget(nullptr, nullptr);
}
mApi->Readback(size, buffer, buffer_size);
return IPC_OK();
@ -556,15 +491,59 @@ WebRenderBridgeParent::ActorDestroy(ActorDestroyReason aWhy)
void
WebRenderBridgeParent::CompositeToTarget(gfx::DrawTarget* aTarget, const gfx::IntRect* aRect)
{
// TODO(bug 1328602) With the RenderThread, calling SetRootStackingContext
// should trigger the composition on the render thread.
MOZ_ASSERT_UNREACHABLE("unexpected to be called");
mApi->GenerateFrame();
}
void
WebRenderBridgeParent::DidComposite(uint64_t aTransactionId, TimeStamp aStart, TimeStamp aEnd)
WebRenderBridgeParent::HoldPendingTransactionId(uint32_t aWrEpoch, uint64_t aTransactionId)
{
mCompositorBridge->NotifyDidComposite(aTransactionId, aStart, aEnd);
// The transaction ID might get reset to 1 if the page gets reloaded, see
// https://bugzilla.mozilla.org/show_bug.cgi?id=1145295#c41
// Otherwise, it should be continually increasing.
MOZ_ASSERT(aTransactionId == 1 || aTransactionId > LastPendingTransactionId());
// Handle TransactionIdAllocator(RefreshDriver) change.
if (aTransactionId == 1) {
FlushPendingTransactionIds();
}
mPendingTransactionIds.push(PendingTransactionId(wr::NewEpoch(aWrEpoch), aTransactionId));
}
uint64_t
WebRenderBridgeParent::LastPendingTransactionId()
{
uint64_t id = 0;
if (!mPendingTransactionIds.empty()) {
id = mPendingTransactionIds.back().mId;
}
return id;
}
uint64_t
WebRenderBridgeParent::FlushPendingTransactionIds()
{
uint64_t id = 0;
while (!mPendingTransactionIds.empty()) {
id = mPendingTransactionIds.front().mId;
mPendingTransactionIds.pop();
}
return id;
}
uint64_t
WebRenderBridgeParent::FlushTransactionIdsForEpoch(const wr::Epoch& aEpoch)
{
uint64_t id = 0;
while (!mPendingTransactionIds.empty()) {
id = mPendingTransactionIds.front().mId;
if (mPendingTransactionIds.front().mEpoch == aEpoch) {
mPendingTransactionIds.pop();
break;
}
mPendingTransactionIds.pop();
}
return id;
}
WebRenderBridgeParent::~WebRenderBridgeParent()
@ -583,11 +562,9 @@ WebRenderBridgeParent::DeleteOldImages()
void
WebRenderBridgeParent::ScheduleComposition()
{
MOZ_ASSERT(mApi);
// TODO(bug 1328602) should probably send a message to the render
// thread and force rendering, although in most cases where this is
// called, rendering should be triggered automatically already (maybe
// not in the ImageBridge case).
if (mCompositorScheduler) {
mCompositorScheduler->ScheduleComposition();
}
}
void
@ -602,14 +579,10 @@ WebRenderBridgeParent::ClearResources()
}
mExternalImageIds.Clear();
if (mBuilder.isSome()) {
mBuilder.reset();
}
if (mCompositorScheduler) {
if (mWidget && mCompositorScheduler) {
mCompositorScheduler->Destroy();
mCompositorScheduler = nullptr;
}
mCompositorScheduler = nullptr;
mApi = nullptr;
mCompositorBridge = nullptr;
}

View file

@ -46,6 +46,7 @@ public:
WebRenderBridgeParent(CompositorBridgeParentBase* aCompositorBridge,
const wr::PipelineId& aPipelineId,
widget::CompositorWidget* aWidget,
CompositorVsyncScheduler* aScheduler,
RefPtr<wr::WebRenderAPI>&& aApi,
RefPtr<WebRenderCompositableHolder>&& aHolder);
@ -60,25 +61,38 @@ public:
mozilla::ipc::IPCResult RecvCreate(const gfx::IntSize& aSize) override;
mozilla::ipc::IPCResult RecvShutdown() override;
mozilla::ipc::IPCResult RecvAddImage(const gfx::IntSize& aSize,
mozilla::ipc::IPCResult RecvAddImage(const wr::ImageKey& aImageKey,
const gfx::IntSize& aSize,
const uint32_t& aStride,
const gfx::SurfaceFormat& aFormat,
const ByteBuffer& aBuffer,
wr::ImageKey* aOutImageKey) override;
const ByteBuffer& aBuffer) override;
mozilla::ipc::IPCResult RecvAddRawFont(const wr::FontKey& aFontKey,
const ByteBuffer& aBuffer,
const uint32_t& aFontIndex) override;
mozilla::ipc::IPCResult RecvUpdateImage(const wr::ImageKey& aImageKey,
const gfx::IntSize& aSize,
const gfx::SurfaceFormat& aFormat,
const ByteBuffer& aBuffer) override;
mozilla::ipc::IPCResult RecvDeleteImage(const wr::ImageKey& a1) override;
mozilla::ipc::IPCResult RecvDPBegin(const gfx::IntSize& aSize) override;
mozilla::ipc::IPCResult RecvDPEnd(InfallibleTArray<WebRenderCommand>&& aCommands,
mozilla::ipc::IPCResult RecvDPEnd(const gfx::IntSize& aSize,
InfallibleTArray<WebRenderParentCommand>&& aCommands,
InfallibleTArray<OpDestroy>&& aToDestroy,
const uint64_t& aFwdTransactionId,
const uint64_t& aTransactionId) override;
mozilla::ipc::IPCResult RecvDPSyncEnd(InfallibleTArray<WebRenderCommand>&& aCommands,
const uint64_t& aTransactionId,
const ByteBuffer& dl,
const WrBuiltDisplayListDescriptor& dlDesc,
const ByteBuffer& aux,
const WrAuxiliaryListsDescriptor& auxDesc) override;
mozilla::ipc::IPCResult RecvDPSyncEnd(const gfx::IntSize& aSize,
InfallibleTArray<WebRenderParentCommand>&& aCommands,
InfallibleTArray<OpDestroy>&& aToDestroy,
const uint64_t& aFwdTransactionId,
const uint64_t& aTransactionId) override;
const uint64_t& aTransactionId,
const ByteBuffer& dl,
const WrBuiltDisplayListDescriptor& dlDesc,
const ByteBuffer& aux,
const WrAuxiliaryListsDescriptor& auxDesc) override;
mozilla::ipc::IPCResult RecvDPGetSnapshot(PTextureParent* aTexture) override;
mozilla::ipc::IPCResult RecvAddExternalImageId(const uint64_t& aImageId,
@ -95,9 +109,6 @@ public:
void Destroy();
const uint64_t& GetPendingTransactionId() { return mPendingTransactionId; }
void SetPendingTransactionId(uint64_t aId) { mPendingTransactionId = aId; }
// CompositorVsyncSchedulerOwner
bool IsPendingComposite() override { return false; }
void FinishPendingComposite() override { }
@ -111,7 +122,10 @@ public:
void SendPendingAsyncMessages() override;
void SetAboutToSendAsyncMessages() override;
void DidComposite(uint64_t aTransactionId, TimeStamp aStart, TimeStamp aEnd);
void HoldPendingTransactionId(uint32_t aWrEpoch, uint64_t aTransactionId);
uint64_t LastPendingTransactionId();
uint64_t FlushPendingTransactionIds();
uint64_t FlushTransactionIdsForEpoch(const wr::Epoch& aEpoch);
TextureFactoryIdentifier GetTextureFactoryIdentifier();
@ -127,25 +141,47 @@ public:
aNotifications->AppendElements(Move(mImageCompositeNotifications));
}
uint32_t GetIdNameSpace()
{
return mIdNameSpace;
}
private:
virtual ~WebRenderBridgeParent();
void DeleteOldImages();
void ProcessWebrenderCommands(InfallibleTArray<WebRenderCommand>& commands, const wr::Epoch& aEpoch);
void ProcessWebrenderCommands(const gfx::IntSize &aSize, InfallibleTArray<WebRenderParentCommand>& commands, const wr::Epoch& aEpoch,
const ByteBuffer& dl,
const WrBuiltDisplayListDescriptor& dlDesc,
const ByteBuffer& aux,
const WrAuxiliaryListsDescriptor& auxDesc);
void ScheduleComposition();
void ClearResources();
uint64_t GetChildLayerObserverEpoch() const { return mChildLayerObserverEpoch; }
bool ShouldParentObserveEpoch();
void HandleDPEnd(InfallibleTArray<WebRenderCommand>&& aCommands,
void HandleDPEnd(const gfx::IntSize& aSize,
InfallibleTArray<WebRenderParentCommand>&& aCommands,
InfallibleTArray<OpDestroy>&& aToDestroy,
const uint64_t& aFwdTransactionId,
const uint64_t& aTransactionId);
const uint64_t& aTransactionId,
const ByteBuffer& dl,
const WrBuiltDisplayListDescriptor& dlDesc,
const ByteBuffer& aux,
const WrAuxiliaryListsDescriptor& auxDesc);
private:
struct PendingTransactionId {
PendingTransactionId(wr::Epoch aEpoch, uint64_t aId)
: mEpoch(aEpoch)
, mId(aId)
{}
wr::Epoch mEpoch;
uint64_t mId;
};
CompositorBridgeParentBase* MOZ_NON_OWNING_REF mCompositorBridge;
wr::PipelineId mPipelineId;
RefPtr<widget::CompositorWidget> mWidget;
Maybe<wr::DisplayListBuilder> mBuilder;
RefPtr<wr::WebRenderAPI> mApi;
RefPtr<WebRenderCompositableHolder> mCompositableHolder;
RefPtr<CompositorVsyncScheduler> mCompositorScheduler;
@ -160,9 +196,13 @@ private:
uint64_t mChildLayerObserverEpoch;
uint64_t mParentLayerObserverEpoch;
uint64_t mPendingTransactionId;
std::queue<PendingTransactionId> mPendingTransactionIds;
uint32_t mWrEpoch;
uint32_t mIdNameSpace;
bool mDestroyed;
static uint32_t sIdNameSpace;
};
} // namespace layers

View file

@ -107,7 +107,11 @@ WebRenderCanvasLayer::RenderLayer()
transform,
mixBlendMode,
FrameMetrics::NULL_SCROLL_ID));
WrBridge()->AddWebRenderCommand(OpDPPushExternalImageId(LayerIntRegion(), wr::ToWrRect(rect), wr::ToWrRect(clip), Nothing(), filter, mExternalImageId));
WrImageKey key;
key.mNamespace = WrBridge()->GetNamespace();
key.mHandle = WrBridge()->GetNextResourceId();
WrBridge()->AddWebRenderParentCommand(OpAddExternalImage(mExternalImageId, key));
WrBridge()->AddWebRenderCommand(OpDPPushImage(wr::ToWrRect(rect), wr::ToWrRect(clip), Nothing(), filter, key));
WrBridge()->AddWebRenderCommand(OpDPPopStackingContext());
}

View file

@ -21,12 +21,14 @@ WebRenderDisplayItemLayer::RenderLayer()
if (mItem) {
// We might have recycled this layer. Throw away the old commands.
mCommands.Clear();
mItem->CreateWebRenderCommands(mCommands, this);
mParentCommands.Clear();
mItem->CreateWebRenderCommands(mCommands, mParentCommands, this);
}
// else we have an empty transaction and just use the
// old commands.
WrBridge()->AddWebRenderCommands(mCommands);
WrBridge()->AddWebRenderParentCommands(mParentCommands);
}
uint64_t

View file

@ -39,6 +39,7 @@ public:
private:
nsTArray<WebRenderCommand> mCommands;
nsTArray<WebRenderParentCommand> mParentCommands;
RefPtr<ImageClient> mImageClient;
RefPtr<ImageContainer> mImageContainer;
uint64_t mExternalImageId;
@ -48,4 +49,4 @@ private:
} // namespace layers
} // namespace mozilla
#endif // GFX_WEBRENDERDisplayItemLayer_H
#endif // GFX_WEBRENDERDisplayItemLayer_H

View file

@ -174,7 +174,11 @@ WebRenderImageLayer::RenderLayer()
transform,
mixBlendMode,
FrameMetrics::NULL_SCROLL_ID));
WrBridge()->AddWebRenderCommand(OpDPPushExternalImageId(LayerIntRegion(), wr::ToWrRect(rect), wr::ToWrRect(clip), Nothing(), filter, mExternalImageId));
WrImageKey key;
key.mNamespace = WrBridge()->GetNamespace();
key.mHandle = WrBridge()->GetNextResourceId();
WrBridge()->AddWebRenderParentCommand(OpAddExternalImage(mExternalImageId, key));
WrBridge()->AddWebRenderCommand(OpDPPushImage(wr::ToWrRect(rect), wr::ToWrRect(clip), Nothing(), filter, key));
WrBridge()->AddWebRenderCommand(OpDPPopStackingContext());
//mContainer->SetImageFactory(originalIF);

View file

@ -129,8 +129,10 @@ WebRenderLayer::buildMaskLayer() {
gfx::IntSize size = surface->GetSize();
MOZ_RELEASE_ASSERT(surface->GetFormat() == SurfaceFormat::A8, "bad format");
wr::ByteBuffer buf(size.height * map.GetStride(), map.GetData());
wr::ImageKey maskKey;
WrBridge()->SendAddImage(size, map.GetStride(), SurfaceFormat::A8, buf, &maskKey);
WrImageKey maskKey;
maskKey.mNamespace = WrBridge()->GetNamespace();
maskKey.mHandle = WrBridge()->GetNextResourceId();
WrBridge()->SendAddImage(maskKey, size, map.GetStride(), SurfaceFormat::A8, buf);
imageMask.image = maskKey;
imageMask.rect = wr::ToWrRect(Rect(0, 0, size.width, size.height));
@ -217,13 +219,16 @@ WebRenderLayerManager::Initialize(PCompositorBridgeChild* aCBChild,
MOZ_ASSERT(aTextureFactoryIdentifier);
TextureFactoryIdentifier textureFactoryIdentifier;
uint32_t id_namespace;
PWebRenderBridgeChild* bridge = aCBChild->SendPWebRenderBridgeConstructor(aLayersId,
&textureFactoryIdentifier);
&textureFactoryIdentifier,
&id_namespace);
MOZ_ASSERT(bridge);
mWrChild = static_cast<WebRenderBridgeChild*>(bridge);
LayoutDeviceIntSize size = mWidget->GetClientSize();
WrBridge()->SendCreate(size.ToUnknownSize());
WrBridge()->IdentifyTextureHost(textureFactoryIdentifier);
WrBridge()->SetNamespace(id_namespace);
*aTextureFactoryIdentifier = textureFactoryIdentifier;
}
@ -316,7 +321,7 @@ WebRenderLayerManager::EndTransaction(DrawPaintedLayerCallback aCallback,
bool sync = mTarget != nullptr;
mLatestTransactionId = mTransactionIdAllocator->GetTransactionId();
WrBridge()->DPEnd(sync, mLatestTransactionId);
WrBridge()->DPEnd(size.ToUnknownSize(), sync, mLatestTransactionId);
MakeSnapshotIfRequired(size);

View file

@ -327,6 +327,45 @@ struct ParamTraits<WrImageMask>
}
};
template<>
struct ParamTraits<WrBuiltDisplayListDescriptor>
{
static void
Write(Message* aMsg, const WrBuiltDisplayListDescriptor& aParam)
{
WriteParam(aMsg, aParam.display_list_items_size);
}
static bool
Read(const Message* aMsg, PickleIterator* aIter, WrBuiltDisplayListDescriptor* aResult)
{
return ReadParam(aMsg, aIter, &aResult->display_list_items_size);
}
};
template<>
struct ParamTraits<WrAuxiliaryListsDescriptor>
{
static void
Write(Message* aMsg, const WrAuxiliaryListsDescriptor& aParam)
{
WriteParam(aMsg, aParam.gradient_stops_size);
WriteParam(aMsg, aParam.complex_clip_regions_size);
WriteParam(aMsg, aParam.filters_size);
WriteParam(aMsg, aParam.glyph_instances_size);
}
static bool
Read(const Message* aMsg, PickleIterator* aIter, WrAuxiliaryListsDescriptor* aResult)
{
return ReadParam(aMsg, aIter, &aResult->gradient_stops_size)
&& ReadParam(aMsg, aIter, &aResult->complex_clip_regions_size)
&& ReadParam(aMsg, aIter, &aResult->filters_size)
&& ReadParam(aMsg, aIter, &aResult->glyph_instances_size);
}
};
template<>
struct ParamTraits<WrImageRendering>
: public ContiguousEnumSerializer<

View file

@ -233,8 +233,11 @@ WebRenderPaintedLayer::RenderLayer()
transform,
mixBlendMode,
FrameMetrics::NULL_SCROLL_ID));
WrBridge()->AddWebRenderCommand(OpDPPushExternalImageId(LayerIntRegion(), wr::ToWrRect(rect), wr::ToWrRect(clip), Nothing(), wr::ImageRendering::Auto, mExternalImageId));
WrImageKey key;
key.mNamespace = WrBridge()->GetNamespace();
key.mHandle = WrBridge()->GetNextResourceId();
WrBridge()->AddWebRenderParentCommand(OpAddExternalImage(mExternalImageId, key));
WrBridge()->AddWebRenderCommand(OpDPPushImage(wr::ToWrRect(rect), wr::ToWrRect(clip), Nothing(), wr::ImageRendering::Auto, key));
WrBridge()->AddWebRenderCommand(OpDPPopStackingContext());
}

View file

@ -40,7 +40,7 @@ WebRenderTextLayer::RenderLayer()
}
nsTArray<WebRenderCommand> commands;
mGlyphHelper.BuildWebRenderCommands(commands, mGlyphs, mFont,
mGlyphHelper.BuildWebRenderCommands(WrBridge(), commands, mGlyphs, mFont,
GetOffsetToParent(), rect, clip);
WrBridge()->AddWebRenderCommands(commands);
}

View file

@ -463,6 +463,7 @@ private:
DECL_GFX_PREF(Live, "layers.advanced.bullet-layers", LayersAllowBulletLayers, bool, false);
DECL_GFX_PREF(Live, "layers.advanced.caret-layers", LayersAllowCaretLayers, bool, false);
DECL_GFX_PREF(Live, "layers.advanced.boxshadow-outer-layers", LayersAllowOuterBoxShadow, bool, false);
DECL_GFX_PREF(Live, "layers.advanced.boxshadow-inset-layers", LayersAllowInsetBoxShadow, bool, false);
DECL_GFX_PREF(Live, "layers.advanced.outline-layers", LayersAllowOutlineLayers, bool, false);
DECL_GFX_PREF(Skip, "layers.allow-d3d9-fallback", LayersAllowD3D9Fallback, bool, false);
DECL_GFX_PREF(Once, "layers.amd-switchable-gfx.enabled", LayersAMDSwitchableGfxEnabled, bool, false);

View file

@ -27,6 +27,7 @@
#include "mozilla/UniquePtrExtensions.h"
#include "mozilla/Vector.h"
#include "mozilla/webrender/WebRenderTypes.h"
#include "mozilla/layers/WebRenderBridgeChild.h"
#include "nsComponentManagerUtils.h"
#include "nsIClipboardHelper.h"
#include "nsIFile.h"
@ -1458,7 +1459,8 @@ WriteFontFileData(const uint8_t* aData, uint32_t aLength, uint32_t aIndex,
}
void
WebRenderGlyphHelper::BuildWebRenderCommands(nsTArray<WebRenderCommand>& aCommands,
WebRenderGlyphHelper::BuildWebRenderCommands(WebRenderBridgeChild* aBridge,
nsTArray<WebRenderCommand>& aCommands,
const nsTArray<GlyphArray>& aGlyphs,
ScaledFont* aFont,
const Point& aOffset,
@ -1473,6 +1475,12 @@ WebRenderGlyphHelper::BuildWebRenderCommands(nsTArray<WebRenderCommand>& aComman
aFont->GetFontFileData(&WriteFontFileData, this);
wr::ByteBuffer fontBuffer(mFontDataLength, mFontData);
WrFontKey key;
key.mNamespace = aBridge->GetNamespace();
key.mHandle = aBridge->GetNextResourceId();
aBridge->SendAddRawFont(key, fontBuffer, mIndex);
nsTArray<WrGlyphArray> wr_glyphs;
wr_glyphs.SetLength(aGlyphs.Length());
@ -1495,10 +1503,8 @@ WebRenderGlyphHelper::BuildWebRenderCommands(nsTArray<WebRenderCommand>& aComman
wr::ToWrRect(aBounds),
wr::ToWrRect(aClip),
wr_glyphs,
mIndex,
mGlyphSize,
fontBuffer,
mFontDataLength));
key));
}
} // namespace gfx

View file

@ -17,6 +17,7 @@
#include "nsRegionFwd.h"
#include "mozilla/gfx/Rect.h"
#include "mozilla/CheckedInt.h"
#include "mozilla/webrender/webrender_ffi.h"
class gfxASurface;
class gfxDrawable;
@ -26,6 +27,7 @@ class nsIPresShell;
namespace mozilla {
namespace layers {
class WebRenderBridgeChild;
class GlyphArray;
struct PlanarYCbCrData;
class WebRenderCommand;
@ -325,7 +327,8 @@ public:
}
}
void BuildWebRenderCommands(nsTArray<layers::WebRenderCommand>& aCommands,
void BuildWebRenderCommands(layers::WebRenderBridgeChild* aChild,
nsTArray<layers::WebRenderCommand>& aCommands,
const nsTArray<layers::GlyphArray>& aGlyphs,
ScaledFont* aFont,
const Point& aOffset,

View file

@ -1631,7 +1631,12 @@ impl Device {
None => width,
};
assert!(data.len() as u32 == bpp * row_length * height);
// Take the stride into account for all rows, except the last one.
let len = bpp * row_length * (height - 1)
+ width * bpp;
assert!(data.len() as u32 >= len);
let data = &data[0..len as usize];
if let Some(..) = stride {
gl::pixel_store_i(gl::UNPACK_ROW_LENGTH, row_length as gl::GLint);

View file

@ -9,17 +9,18 @@ use internal_types::{LowLevelFilterOp};
use internal_types::{RendererFrame};
use frame_builder::{FrameBuilder, FrameBuilderConfig};
use clip_scroll_node::ClipScrollNode;
use clip_scroll_tree::{ClipScrollTree, ScrollStates};
use profiler::TextureCacheProfileCounters;
use resource_cache::ResourceCache;
use scene::{Scene, SceneProperties};
use clip_scroll_tree::{ClipScrollTree, ScrollStates};
use std::collections::HashMap;
use std::hash::BuildHasherDefault;
use tiling::{AuxiliaryListsMap, CompositeOps, PrimitiveFlags};
use webrender_traits::{AuxiliaryLists, ClipRegion, ColorF, DisplayItem, Epoch, FilterOp};
use webrender_traits::{LayerPoint, LayerRect, LayerSize, LayerToScrollTransform, LayoutTransform};
use webrender_traits::{LayerPoint, LayerRect, LayerSize, LayerToScrollTransform, LayoutTransform, TileOffset};
use webrender_traits::{MixBlendMode, PipelineId, ScrollEventPhase, ScrollLayerId, ScrollLayerState};
use webrender_traits::{ScrollLocation, ScrollPolicy, ServoScrollRootId, SpecificDisplayItem};
use webrender_traits::{StackingContext, WorldPoint};
use webrender_traits::{StackingContext, WorldPoint, ImageDisplayItem, DeviceUintSize};
#[derive(Copy, Clone, PartialEq, PartialOrd, Debug)]
pub struct FrameId(pub u32);
@ -29,6 +30,7 @@ static DEFAULT_SCROLLBAR_COLOR: ColorF = ColorF { r: 0.3, g: 0.3, b: 0.3, a: 0.6
struct FlattenContext<'a> {
scene: &'a Scene,
builder: &'a mut FrameBuilder,
resource_cache: &'a mut ResourceCache,
}
// TODO: doc
@ -226,7 +228,7 @@ impl Frame {
self.clip_scroll_tree.discard_frame_state_for_pipeline(pipeline_id);
}
pub fn create(&mut self, scene: &Scene) {
pub fn create(&mut self, scene: &Scene, resource_cache: &mut ResourceCache) {
let root_pipeline_id = match scene.root_pipeline_id {
Some(root_pipeline_id) => root_pipeline_id,
None => return,
@ -276,6 +278,7 @@ impl Frame {
let mut context = FlattenContext {
scene: scene,
builder: &mut frame_builder,
resource_cache: resource_cache
};
let mut traversal = DisplayListTraversal::new_skipping_first(display_list);
@ -547,13 +550,22 @@ impl Frame {
&item.clip, info.context_id);
}
SpecificDisplayItem::Image(ref info) => {
context.builder.add_image(item.rect,
&item.clip,
&info.stretch_size,
&info.tile_spacing,
None,
info.image_key,
info.image_rendering);
let image = context.resource_cache.get_image_properties(info.image_key);
if let Some(tile_size) = image.tiling {
// The image resource is tiled. We have to generate an image primitive
// for each tile.
let image_size = DeviceUintSize::new(image.descriptor.width, image.descriptor.height);
self.decompose_tiled_image(context, &item, info, image_size, tile_size as u32);
} else {
context.builder.add_image(item.rect,
&item.clip,
&info.stretch_size,
&info.tile_spacing,
None,
info.image_key,
info.image_rendering,
None);
}
}
SpecificDisplayItem::YuvImage(ref info) => {
context.builder.add_yuv_image(item.rect,
@ -646,15 +658,203 @@ impl Frame {
}
}
fn decompose_tiled_image(&mut self,
context: &mut FlattenContext,
item: &DisplayItem,
info: &ImageDisplayItem,
image_size: DeviceUintSize,
tile_size: u32) {
// The image resource is tiled. We have to generate an image primitive
// for each tile.
// We need to do this because the image is broken up into smaller tiles in the texture
// cache and the image shader is not able to work with this type of sparse representation.
// The tiling logic works as follows:
//
// ###################-+ -+
// # | | |//# | | image size
// # | | |//# | |
// #----+----+----+--#-+ | -+
// # | | |//# | | | regular tile size
// # | | |//# | | |
// #----+----+----+--#-+ | -+-+
// #////|////|////|//# | | | "leftover" height
// ################### | -+ ---+
// #----+----+----+----+
//
// In the ascii diagram above, a large image is plit into tiles of almost regular size.
// The tiles on the right and bottom edges (hatched in the diagram) are smaller than
// the regular tiles and are handled separately in the code see leftover_width/height.
// each generated image primitive corresponds to a tile in the texture cache, with the
// assumption that the smaller tiles with leftover sizes are sized to fit their own
// irregular size in the texture cache.
// TODO(nical) supporting tiled repeated images isn't implemented yet.
// One way to implement this is to have another level of decomposition on top of this one,
// and generate a set of image primitive per repetition just like we have a primitive
// per tile here.
//
// For the case where we don't tile along an axis, we can still perform the repetition in
// the shader (for this particular axis), and it is worth special-casing for this to avoid
// generating many primitives.
// This can happen with very tall and thin images used as a repeating background.
// Apparently web authors do that...
let mut stretch_size = info.stretch_size;
let mut repeat_x = false;
let mut repeat_y = false;
if stretch_size.width < item.rect.size.width {
if image_size.width < tile_size {
// we don't actually tile in this dimmension so repeating can be done in the shader.
repeat_x = true;
} else {
println!("Unimplemented! repeating a tiled image (x axis)");
stretch_size.width = item.rect.size.width;
}
}
if stretch_size.height < item.rect.size.height {
// we don't actually tile in this dimmension so repeating can be done in the shader.
if image_size.height < tile_size {
repeat_y = true;
} else {
println!("Unimplemented! repeating a tiled image (y axis)");
stretch_size.height = item.rect.size.height;
}
}
let tile_size_f32 = tile_size as f32;
// Note: this rounds down so it excludes the partially filled tiles on the right and
// bottom edges (we handle them separately below).
let num_tiles_x = (image_size.width / tile_size) as u16;
let num_tiles_y = (image_size.height / tile_size) as u16;
// Ratio between (image space) tile size and image size.
let img_dw = tile_size_f32 / (image_size.width as f32);
let img_dh = tile_size_f32 / (image_size.height as f32);
// Strected size of the tile in layout space.
let stretched_tile_size = LayerSize::new(
img_dw * stretch_size.width,
img_dh * stretch_size.height
);
// The size in pixels of the tiles on the right and bottom edges, smaller
// than the regular tile size if the image is not a multiple of the tile size.
// Zero means the image size is a multiple of the tile size.
let leftover = DeviceUintSize::new(image_size.width % tile_size, image_size.height % tile_size);
for ty in 0..num_tiles_y {
for tx in 0..num_tiles_x {
self.add_tile_primitive(context, item, info,
TileOffset::new(tx, ty),
stretched_tile_size,
1.0, 1.0,
repeat_x, repeat_y);
}
if leftover.width != 0 {
// Tiles on the right edge that are smaller than the tile size.
self.add_tile_primitive(context, item, info,
TileOffset::new(num_tiles_x, ty),
stretched_tile_size,
(leftover.width as f32) / tile_size_f32,
1.0,
repeat_x, repeat_y);
}
}
if leftover.height != 0 {
for tx in 0..num_tiles_x {
// Tiles on the bottom edge that are smaller than the tile size.
self.add_tile_primitive(context, item, info,
TileOffset::new(tx, num_tiles_y),
stretched_tile_size,
1.0,
(leftover.height as f32) / tile_size_f32,
repeat_x, repeat_y);
}
if leftover.width != 0 {
// Finally, the bottom-right tile with a "leftover" size.
self.add_tile_primitive(context, item, info,
TileOffset::new(num_tiles_x, num_tiles_y),
stretched_tile_size,
(leftover.width as f32) / tile_size_f32,
(leftover.height as f32) / tile_size_f32,
repeat_x, repeat_y);
}
}
}
fn add_tile_primitive(&mut self,
context: &mut FlattenContext,
item: &DisplayItem,
info: &ImageDisplayItem,
tile_offset: TileOffset,
stretched_tile_size: LayerSize,
tile_ratio_width: f32,
tile_ratio_height: f32,
repeat_x: bool,
repeat_y: bool) {
// If the the image is tiled along a given axis, we can't have the shader compute
// the image repetition pattern. In this case we base the primitive's rectangle size
// on the stretched tile size which effectively cancels the repetion (and repetition
// has to be emulated by generating more primitives).
// If the image is not tiling along this axis, we can perform the repetition in the
// shader. in this case we use the item's size in the primitive (on that particular
// axis).
// See the repeat_x/y code below.
let stretched_size = LayerSize::new(
stretched_tile_size.width * tile_ratio_width,
stretched_tile_size.height * tile_ratio_height,
);
let mut prim_rect = LayerRect::new(
item.rect.origin + LayerPoint::new(
tile_offset.x as f32 * stretched_tile_size.width,
tile_offset.y as f32 * stretched_tile_size.height,
),
stretched_size,
);
if repeat_x {
assert_eq!(tile_offset.x, 0);
prim_rect.size.width = item.rect.size.width;
}
if repeat_y {
assert_eq!(tile_offset.y, 0);
prim_rect.size.height = item.rect.size.height;
}
// Fix up the primitive's rect if it overflows the original item rect.
if let Some(prim_rect) = prim_rect.intersection(&item.rect) {
context.builder.add_image(prim_rect,
&item.clip,
&stretched_size,
&info.tile_spacing,
None,
info.image_key,
info.image_rendering,
Some(tile_offset));
}
}
pub fn build(&mut self,
resource_cache: &mut ResourceCache,
auxiliary_lists_map: &AuxiliaryListsMap,
device_pixel_ratio: f32)
device_pixel_ratio: f32,
texture_cache_profile: &mut TextureCacheProfileCounters)
-> RendererFrame {
self.clip_scroll_tree.update_all_node_transforms();
let frame = self.build_frame(resource_cache,
auxiliary_lists_map,
device_pixel_ratio);
device_pixel_ratio,
texture_cache_profile);
resource_cache.expire_old_resources(self.id);
frame
}
@ -662,14 +862,17 @@ impl Frame {
fn build_frame(&mut self,
resource_cache: &mut ResourceCache,
auxiliary_lists_map: &AuxiliaryListsMap,
device_pixel_ratio: f32) -> RendererFrame {
device_pixel_ratio: f32,
texture_cache_profile: &mut TextureCacheProfileCounters)
-> RendererFrame {
let mut frame_builder = self.frame_builder.take();
let frame = frame_builder.as_mut().map(|builder|
builder.build(resource_cache,
self.id,
&self.clip_scroll_tree,
auxiliary_lists_map,
device_pixel_ratio)
device_pixel_ratio,
texture_cache_profile)
);
self.frame_builder = frame_builder;

View file

@ -14,7 +14,7 @@ use prim_store::{ImagePrimitiveKind, PrimitiveContainer, PrimitiveGeometry, Prim
use prim_store::{PrimitiveStore, RadialGradientPrimitiveCpu, RadialGradientPrimitiveGpu};
use prim_store::{RectanglePrimitive, TextRunPrimitiveCpu, TextRunPrimitiveGpu};
use prim_store::{TexelRect, YuvImagePrimitiveCpu, YuvImagePrimitiveGpu};
use profiler::FrameProfileCounters;
use profiler::{FrameProfileCounters, TextureCacheProfileCounters};
use render_task::{AlphaRenderItem, MaskCacheKey, MaskResult, RenderTask, RenderTaskIndex};
use render_task::RenderTaskLocation;
use resource_cache::ResourceCache;
@ -28,7 +28,7 @@ use util::{self, pack_as_float, rect_from_points_f, subtract_rect, TransformedRe
use util::{RectHelpers, TransformedRectKind};
use webrender_traits::{as_scroll_parent_rect, BorderDetails, BorderDisplayItem, BorderSide, BorderStyle};
use webrender_traits::{BoxShadowClipMode, ClipRegion, ColorF, device_length, DeviceIntPoint};
use webrender_traits::{DeviceIntRect, DeviceIntSize, DeviceUintSize, ExtendMode, FontKey};
use webrender_traits::{DeviceIntRect, DeviceIntSize, DeviceUintSize, ExtendMode, FontKey, TileOffset};
use webrender_traits::{FontRenderMode, GlyphOptions, ImageKey, ImageRendering, ItemRange};
use webrender_traits::{LayerPoint, LayerRect, LayerSize, LayerToScrollTransform, PipelineId};
use webrender_traits::{RepeatMode, ScrollLayerId, ScrollLayerPixel, WebGLContextId, YuvColorSpace};
@ -417,7 +417,8 @@ impl FrameBuilder {
&segment.tile_spacing,
Some(segment.sub_rect),
border.image_key,
ImageRendering::Auto);
ImageRendering::Auto,
None);
}
}
BorderDetails::Normal(ref border) => {
@ -715,8 +716,13 @@ impl FrameBuilder {
// The local space box shadow rect. It is the element rect
// translated by the box shadow offset and inflated by the
// box shadow spread.
let inflate_amount = match clip_mode {
BoxShadowClipMode::Outset | BoxShadowClipMode::None => spread_radius,
BoxShadowClipMode::Inset => -spread_radius,
};
let bs_rect = box_bounds.translate(box_offset)
.inflate(spread_radius, spread_radius);
.inflate(inflate_amount, inflate_amount);
// Get the outer rectangle, based on the blur radius.
let outside_edge_size = 2.0 * blur_radius;
@ -833,10 +839,12 @@ impl FrameBuilder {
tile_spacing: &LayerSize,
sub_rect: Option<TexelRect>,
image_key: ImageKey,
image_rendering: ImageRendering) {
image_rendering: ImageRendering,
tile: Option<TileOffset>) {
let prim_cpu = ImagePrimitiveCpu {
kind: ImagePrimitiveKind::Image(image_key,
image_rendering,
tile,
*tile_spacing),
color_texture_id: SourceTexture::Invalid,
resource_address: GpuStoreAddress(0),
@ -1084,7 +1092,9 @@ impl FrameBuilder {
frame_id: FrameId,
clip_scroll_tree: &ClipScrollTree,
auxiliary_lists_map: &AuxiliaryListsMap,
device_pixel_ratio: f32) -> Frame {
device_pixel_ratio: f32,
texture_cache_profile: &mut TextureCacheProfileCounters)
-> Frame {
profile_scope!("build");
let mut profile_counters = FrameProfileCounters::new();
@ -1121,7 +1131,7 @@ impl FrameBuilder {
let mut required_pass_count = 0;
main_render_task.max_depth(0, &mut required_pass_count);
resource_cache.block_until_all_resources_added();
resource_cache.block_until_all_resources_added(texture_cache_profile);
for scroll_layer in self.scroll_layer_store.iter() {
if let Some(ref clip_info) = scroll_layer.clip_cache_info {
@ -1361,7 +1371,7 @@ impl<'a> LayerRectCalculationAndCullingPass<'a> {
if let Some(mask) = scroll_layer.clip_source.image_mask() {
// We don't add the image mask for resolution, because layer masks are resolved later.
self.resource_cache.request_image(mask.image, ImageRendering::Auto);
self.resource_cache.request_image(mask.image, ImageRendering::Auto, None);
}
}

View file

@ -15,16 +15,31 @@ impl FreeListItemId {
#[inline]
pub fn value(&self) -> u32 {
let FreeListItemId(value) = *self;
value
self.0
}
}
pub trait FreeListItem {
fn take(&mut self) -> Self;
fn next_free_id(&self) -> Option<FreeListItemId>;
fn set_next_free_id(&mut self, id: Option<FreeListItemId>);
}
struct FreeListIter<'a, T: 'a> {
items: &'a [T],
cur_index: Option<FreeListItemId>,
}
impl<'a, T: FreeListItem> Iterator for FreeListIter<'a, T> {
type Item = FreeListItemId;
fn next(&mut self) -> Option<Self::Item> {
self.cur_index.map(|free_id| {
self.cur_index = self.items[free_id.0 as usize].next_free_id();
free_id
})
}
}
pub struct FreeList<T> {
items: Vec<T>,
first_free_index: Option<FreeListItemId>,
@ -40,6 +55,13 @@ impl<T: FreeListItem> FreeList<T> {
}
}
fn free_iter(&self) -> FreeListIter<T> {
FreeListIter {
items: &self.items,
cur_index: self.first_free_index,
}
}
pub fn insert(&mut self, item: T) -> FreeListItemId {
self.alloc_count += 1;
match self.first_free_index {
@ -58,31 +80,14 @@ impl<T: FreeListItem> FreeList<T> {
}
}
#[allow(dead_code)]
fn assert_not_in_free_list(&self, id: FreeListItemId) {
let FreeListItemId(id) = id;
let mut next_free_id = self.first_free_index;
while let Some(free_id) = next_free_id {
let FreeListItemId(index) = free_id;
assert!(index != id);
let free_item = &self.items[index as usize];
next_free_id = free_item.next_free_id();
}
}
pub fn get(&self, id: FreeListItemId) -> &T {
//self.assert_not_in_free_list(id);
let FreeListItemId(index) = id;
&self.items[index as usize]
debug_assert_eq!(self.free_iter().find(|&fid| fid==id), None);
&self.items[id.0 as usize]
}
pub fn get_mut(&mut self, id: FreeListItemId) -> &mut T {
//self.assert_not_in_free_list(id);
let FreeListItemId(index) = id;
&mut self.items[index as usize]
debug_assert_eq!(self.free_iter().find(|&fid| fid==id), None);
&mut self.items[id.0 as usize]
}
#[allow(dead_code)]
@ -90,30 +95,27 @@ impl<T: FreeListItem> FreeList<T> {
self.alloc_count
}
// TODO(gw): Actually free items from the texture cache!!
#[allow(dead_code)]
pub fn free(&mut self, id: FreeListItemId) {
pub fn free(&mut self, id: FreeListItemId) -> T {
self.alloc_count -= 1;
let FreeListItemId(index) = id;
let item = &mut self.items[index as usize];
let data = item.take();
item.set_next_free_id(self.first_free_index);
self.first_free_index = Some(id);
data
}
pub fn for_each_item<F>(&mut self, f: F) where F: Fn(&mut T) {
let mut free_ids = HashSet::new();
let mut next_free_id = self.first_free_index;
while let Some(free_id) = next_free_id {
free_ids.insert(free_id);
let FreeListItemId(index) = free_id;
let free_item = &self.items[index as usize];
next_free_id = free_item.next_free_id();
}
//TODO: this could be done much faster. Instead of gathering the free
// indices into a set, we could re-order the free list to be ascending.
// That is an one-time operation with at most O(nf^2), where
// nf = number of elements in the free list
// Then this code would just walk both `items` and the ascending free
// list, essentially skipping the free indices for free.
let free_ids: HashSet<_> = self.free_iter().collect();
for (index, mut item) in self.items.iter_mut().enumerate() {
let id = FreeListItemId(index as u32);
if !free_ids.contains(&id) {
if !free_ids.contains(&FreeListItemId(index as u32)) {
f(&mut item);
}
}

View file

@ -387,6 +387,7 @@ pub enum TextureUpdateOp {
height: u32,
data: Arc<Vec<u8>>,
stride: Option<u32>,
offset: u32,
},
UpdateForExternalBuffer {
rect: DeviceUintRect,

View file

@ -20,7 +20,7 @@ use webrender_traits::{device_length, DeviceIntRect, DeviceIntSize};
use webrender_traits::{DeviceRect, DevicePoint, DeviceSize};
use webrender_traits::{LayerRect, LayerSize, LayerPoint};
use webrender_traits::{LayerToWorldTransform, GlyphInstance, GlyphOptions};
use webrender_traits::{ExtendMode, GradientStop};
use webrender_traits::{ExtendMode, GradientStop, TileOffset};
pub const CLIP_DATA_GPU_SIZE: usize = 5;
pub const MASK_DATA_GPU_SIZE: usize = 1;
@ -136,7 +136,7 @@ pub struct RectanglePrimitive {
#[derive(Debug)]
pub enum ImagePrimitiveKind {
Image(ImageKey, ImageRendering, LayerSize),
Image(ImageKey, ImageRendering, Option<TileOffset>, LayerSize),
WebGL(WebGLContextId),
}
@ -838,7 +838,7 @@ impl PrimitiveStore {
clip_info: &MaskCacheInfo,
resource_cache: &ResourceCache) {
if let Some((ref mask, gpu_address)) = clip_info.image {
let cache_item = resource_cache.get_cached_image(mask.image, ImageRendering::Auto);
let cache_item = resource_cache.get_cached_image(mask.image, ImageRendering::Auto, None);
let mask_data = gpu_data32.get_slice_mut(gpu_address, MASK_DATA_GPU_SIZE);
mask_data[0] = GpuBlock32::from(ImageMaskData {
uv_rect: DeviceRect::new(cache_item.uv0,
@ -899,7 +899,7 @@ impl PrimitiveStore {
let image_cpu = &mut self.cpu_images[metadata.cpu_prim_index.0];
let (texture_id, cache_item) = match image_cpu.kind {
ImagePrimitiveKind::Image(image_key, image_rendering, _) => {
ImagePrimitiveKind::Image(image_key, image_rendering, tile_offset, _) => {
// Check if an external image that needs to be resolved
// by the render thread.
let image_properties = resource_cache.get_image_properties(image_key);
@ -917,7 +917,7 @@ impl PrimitiveStore {
(SourceTexture::External(external_id), None)
}
None => {
let cache_item = resource_cache.get_cached_image(image_key, image_rendering);
let cache_item = resource_cache.get_cached_image(image_key, image_rendering, tile_offset);
(cache_item.texture_id, Some(cache_item))
}
}
@ -952,21 +952,21 @@ impl PrimitiveStore {
};
if image_cpu.y_texture_id == SourceTexture::Invalid {
let y_cache_item = resource_cache.get_cached_image(image_cpu.y_key, ImageRendering::Auto);
let y_cache_item = resource_cache.get_cached_image(image_cpu.y_key, ImageRendering::Auto, None);
image_cpu.y_texture_id = y_cache_item.texture_id;
image_gpu.y_uv0 = y_cache_item.uv0;
image_gpu.y_uv1 = y_cache_item.uv1;
}
if image_cpu.u_texture_id == SourceTexture::Invalid {
let u_cache_item = resource_cache.get_cached_image(image_cpu.u_key, ImageRendering::Auto);
let u_cache_item = resource_cache.get_cached_image(image_cpu.u_key, ImageRendering::Auto, None);
image_cpu.u_texture_id = u_cache_item.texture_id;
image_gpu.u_uv0 = u_cache_item.uv0;
image_gpu.u_uv1 = u_cache_item.uv1;
}
if image_cpu.v_texture_id == SourceTexture::Invalid {
let v_cache_item = resource_cache.get_cached_image(image_cpu.v_key, ImageRendering::Auto);
let v_cache_item = resource_cache.get_cached_image(image_cpu.v_key, ImageRendering::Auto, None);
image_cpu.v_texture_id = v_cache_item.texture_id;
image_gpu.v_uv0 = v_cache_item.uv0;
image_gpu.v_uv1 = v_cache_item.uv1;
@ -1044,7 +1044,7 @@ impl PrimitiveStore {
device_pixel_ratio,
auxiliary_lists);
if let &ClipSource::Region(ClipRegion{ image_mask: Some(ref mask), .. }) = metadata.clip_source.as_ref() {
resource_cache.request_image(mask.image, ImageRendering::Auto);
resource_cache.request_image(mask.image, ImageRendering::Auto, None);
prim_needs_resolve = true;
}
}
@ -1169,8 +1169,8 @@ impl PrimitiveStore {
prim_needs_resolve = true;
match image_cpu.kind {
ImagePrimitiveKind::Image(image_key, image_rendering, tile_spacing) => {
resource_cache.request_image(image_key, image_rendering);
ImagePrimitiveKind::Image(image_key, image_rendering, tile_offset, tile_spacing) => {
resource_cache.request_image(image_key, image_rendering, tile_offset);
// TODO(gw): This doesn't actually need to be calculated each frame.
// It's cheap enough that it's not worth introducing a cache for images
@ -1188,9 +1188,9 @@ impl PrimitiveStore {
let image_cpu = &mut self.cpu_yuv_images[metadata.cpu_prim_index.0];
prim_needs_resolve = true;
resource_cache.request_image(image_cpu.y_key, ImageRendering::Auto);
resource_cache.request_image(image_cpu.u_key, ImageRendering::Auto);
resource_cache.request_image(image_cpu.v_key, ImageRendering::Auto);
resource_cache.request_image(image_cpu.y_key, ImageRendering::Auto, None);
resource_cache.request_image(image_cpu.u_key, ImageRendering::Auto, None);
resource_cache.request_image(image_cpu.v_key, ImageRendering::Auto, None);
// TODO(nical): Currently assuming no tile_spacing for yuv images.
metadata.is_opaque = true;

View file

@ -256,11 +256,29 @@ impl FrameProfileCounters {
}
}
#[derive(Clone)]
pub struct TextureCacheProfileCounters {
pub pages_a8: ResourceProfileCounter,
pub pages_rgb8: ResourceProfileCounter,
pub pages_rgba8: ResourceProfileCounter,
}
impl TextureCacheProfileCounters {
pub fn new() -> TextureCacheProfileCounters {
TextureCacheProfileCounters {
pages_a8: ResourceProfileCounter::new("Texture A8 cached pages"),
pages_rgb8: ResourceProfileCounter::new("Texture RGB8 cached pages"),
pages_rgba8: ResourceProfileCounter::new("Texture RGBA8 cached pages"),
}
}
}
#[derive(Clone)]
pub struct BackendProfileCounters {
pub font_templates: ResourceProfileCounter,
pub image_templates: ResourceProfileCounter,
pub total_time: TimeProfileCounter,
pub texture_cache: TextureCacheProfileCounters,
}
impl BackendProfileCounters {
@ -269,6 +287,7 @@ impl BackendProfileCounters {
font_templates: ResourceProfileCounter::new("Font Templates"),
image_templates: ResourceProfileCounter::new("Image Templates"),
total_time: TimeProfileCounter::new("Backend CPU Time", false),
texture_cache: TextureCacheProfileCounters::new(),
}
}
@ -641,6 +660,12 @@ impl Profiler {
&backend_profile.image_templates,
], debug_renderer, true);
self.draw_counters(&[
&backend_profile.texture_cache.pages_a8,
&backend_profile.texture_cache.pages_rgb8,
&backend_profile.texture_cache.pages_rgba8,
], debug_renderer, true);
self.draw_counters(&[
&renderer_profile.draw_calls,
&renderer_profile.vertices,

View file

@ -7,7 +7,7 @@ use frame::Frame;
use frame_builder::FrameBuilderConfig;
use internal_types::{FontTemplate, GLContextHandleWrapper, GLContextWrapper};
use internal_types::{SourceTexture, ResultMsg, RendererFrame};
use profiler::BackendProfileCounters;
use profiler::{BackendProfileCounters, TextureCacheProfileCounters};
use record::ApiRecordingReceiver;
use resource_cache::ResourceCache;
use scene::Scene;
@ -96,8 +96,7 @@ impl RenderBackend {
}
}
pub fn run(&mut self) {
let mut profile_counters = BackendProfileCounters::new();
pub fn run(&mut self, mut profile_counters: BackendProfileCounters) {
let mut frame_counter: u32 = 0;
loop {
@ -126,11 +125,11 @@ impl RenderBackend {
};
tx.send(glyph_dimensions).unwrap();
}
ApiMsg::AddImage(id, descriptor, data) => {
ApiMsg::AddImage(id, descriptor, data, tiling) => {
if let ImageData::Raw(ref bytes) = data {
profile_counters.image_templates.inc(bytes.len());
}
self.resource_cache.add_image_template(id, descriptor, data);
self.resource_cache.add_image_template(id, descriptor, data, tiling);
}
ApiMsg::UpdateImage(id, descriptor, bytes) => {
self.resource_cache.update_image_template(id, descriptor, bytes);
@ -213,13 +212,16 @@ impl RenderBackend {
}
ApiMsg::Scroll(delta, cursor, move_phase) => {
profile_scope!("Scroll");
let frame = profile_counters.total_time.profile(|| {
if self.frame.scroll(delta, cursor, move_phase) {
Some(self.render())
} else {
None
}
});
let frame = {
let counters = &mut profile_counters.texture_cache;
profile_counters.total_time.profile(|| {
if self.frame.scroll(delta, cursor, move_phase) {
Some(self.render(counters))
} else {
None
}
})
};
match frame {
Some(frame) => {
@ -231,13 +233,16 @@ impl RenderBackend {
}
ApiMsg::ScrollLayersWithScrollId(origin, pipeline_id, scroll_root_id) => {
profile_scope!("ScrollLayersWithScrollId");
let frame = profile_counters.total_time.profile(|| {
if self.frame.scroll_nodes(origin, pipeline_id, scroll_root_id) {
Some(self.render())
} else {
None
}
});
let frame = {
let counters = &mut profile_counters.texture_cache;
profile_counters.total_time.profile(|| {
if self.frame.scroll_nodes(origin, pipeline_id, scroll_root_id) {
Some(self.render(counters))
} else {
None
}
})
};
match frame {
Some(frame) => {
@ -250,10 +255,13 @@ impl RenderBackend {
}
ApiMsg::TickScrollingBounce => {
profile_scope!("TickScrollingBounce");
let frame = profile_counters.total_time.profile(|| {
self.frame.tick_scrolling_bounce_animations();
self.render()
});
let frame = {
let counters = &mut profile_counters.texture_cache;
profile_counters.total_time.profile(|| {
self.frame.tick_scrolling_bounce_animations();
self.render(counters)
})
};
self.publish_frame_and_notify_compositor(frame, &mut profile_counters);
}
@ -346,9 +354,12 @@ impl RenderBackend {
self.build_scene();
}
let frame = profile_counters.total_time.profile(|| {
self.render()
});
let frame = {
let counters = &mut profile_counters.texture_cache;
profile_counters.total_time.profile(|| {
self.render(counters)
})
};
if self.scene.root_pipeline_id.is_some() {
self.publish_frame_and_notify_compositor(frame, &mut profile_counters);
frame_counter += 1;
@ -407,13 +418,16 @@ impl RenderBackend {
webgl_context.unbind();
}
self.frame.create(&self.scene);
self.frame.create(&self.scene, &mut self.resource_cache);
}
fn render(&mut self) -> RendererFrame {
fn render(&mut self,
texture_cache_profile: &mut TextureCacheProfileCounters)
-> RendererFrame {
let frame = self.frame.build(&mut self.resource_cache,
&self.scene.pipeline_auxiliary_lists,
self.device_pixel_ratio);
self.device_pixel_ratio,
texture_cache_profile);
frame
}

View file

@ -67,13 +67,12 @@ pub struct AlphaRenderTask {
#[derive(Debug, Copy, Clone)]
#[repr(C)]
pub enum MaskSegment {
// This must match the SEGMENT_ values
// in clip_shared.glsl!
// This must match the SEGMENT_ values in clip_shared.glsl!
All = 0,
Corner_TopLeft,
Corner_TopRight,
Corner_BottomLeft,
Corner_BottomRight,
TopLeftCorner,
TopRightCorner,
BottomLeftCorner,
BottomRightCorner,
}
#[derive(Debug, Copy, Clone)]

View file

@ -684,6 +684,7 @@ impl Renderer {
let max_texture_size = cmp::min(device_max_size, options.max_texture_size.unwrap_or(device_max_size));
let mut texture_cache = TextureCache::new(max_texture_size);
let mut backend_profile_counters = BackendProfileCounters::new();
let white_pixels: Vec<u8> = vec![
0xff, 0xff, 0xff, 0xff,
@ -698,27 +699,17 @@ impl Renderer {
// TODO: Ensure that the white texture can never get evicted when the cache supports LRU eviction!
let white_image_id = texture_cache.new_item_id();
texture_cache.insert(white_image_id,
ImageDescriptor {
width: 2,
height: 2,
stride: None,
format: ImageFormat::RGBA8,
is_opaque: false,
},
ImageDescriptor::new(2, 2, ImageFormat::RGBA8, false),
TextureFilter::Linear,
ImageData::Raw(Arc::new(white_pixels)));
ImageData::Raw(Arc::new(white_pixels)),
&mut backend_profile_counters.texture_cache);
let dummy_mask_image_id = texture_cache.new_item_id();
texture_cache.insert(dummy_mask_image_id,
ImageDescriptor {
width: 2,
height: 2,
stride: None,
format: ImageFormat::A8,
is_opaque: false,
},
ImageDescriptor::new(2, 2, ImageFormat::A8, false),
TextureFilter::Linear,
ImageData::Raw(Arc::new(mask_pixels)));
ImageData::Raw(Arc::new(mask_pixels)),
&mut backend_profile_counters.texture_cache);
let dummy_cache_texture_id = device.create_texture_ids(1, TextureTarget::Array)[0];
device.init_texture(dummy_cache_texture_id,
@ -815,7 +806,7 @@ impl Renderer {
backend_main_thread_dispatcher,
blob_image_renderer,
backend_vr_compositor);
backend.run();
backend.run(backend_profile_counters);
})};
let renderer = Renderer {
@ -1123,13 +1114,13 @@ impl Renderer {
filter,
mode);
}
TextureUpdateOp::Update { page_pos_x, page_pos_y, width, height, data, stride } => {
TextureUpdateOp::Update { page_pos_x, page_pos_y, width, height, data, stride, offset } => {
let texture_id = self.cache_texture_id_map[update.id.0];
self.device.update_texture(texture_id,
page_pos_x,
page_pos_y,
width, height, stride,
data.as_slice());
&data[offset as usize..]);
}
TextureUpdateOp::UpdateForExternalBuffer { rect, id, stride } => {
let handler = self.external_image_handler

View file

@ -8,6 +8,7 @@ use fnv::FnvHasher;
use frame::FrameId;
use internal_types::{ExternalImageUpdateList, FontTemplate, SourceTexture, TextureUpdateList};
use platform::font::{FontContext, RasterizedGlyph};
use profiler::TextureCacheProfileCounters;
use std::cell::RefCell;
use std::collections::{HashMap, HashSet};
use std::collections::hash_map::Entry::{self, Occupied, Vacant};
@ -23,7 +24,7 @@ use thread_profiler::register_thread_with_profiler;
use webrender_traits::{Epoch, FontKey, GlyphKey, ImageKey, ImageFormat, ImageRendering};
use webrender_traits::{FontRenderMode, ImageData, GlyphDimensions, WebGLContextId};
use webrender_traits::{DevicePoint, DeviceIntSize, ImageDescriptor, ColorF};
use webrender_traits::{ExternalImageId, GlyphOptions, GlyphInstance};
use webrender_traits::{ExternalImageId, GlyphOptions, GlyphInstance, TileOffset, TileSize};
use webrender_traits::{BlobImageRenderer, BlobImageDescriptor, BlobImageError};
use threadpool::ThreadPool;
use euclid::Point2D;
@ -92,6 +93,7 @@ impl RenderedGlyphKey {
pub struct ImageProperties {
pub descriptor: ImageDescriptor,
pub external_id: Option<ExternalImageId>,
pub tiling: Option<TileSize>,
}
#[derive(Debug, Copy, Clone, PartialEq)]
@ -105,6 +107,7 @@ struct ImageResource {
data: ImageData,
descriptor: ImageDescriptor,
epoch: Epoch,
tiling: Option<TileSize>,
}
struct CachedImageInfo {
@ -177,6 +180,7 @@ impl<K,V> ResourceClassCache<K,V> where K: Clone + Hash + Eq + Debug, V: Resourc
struct ImageRequest {
key: ImageKey,
rendering: ImageRendering,
tile: Option<TileOffset>,
}
struct GlyphRasterJob {
@ -259,17 +263,19 @@ impl ResourceCache {
pub fn add_image_template(&mut self,
image_key: ImageKey,
descriptor: ImageDescriptor,
data: ImageData) {
data: ImageData,
mut tiling: Option<TileSize>) {
if descriptor.width > self.max_texture_size() || descriptor.height > self.max_texture_size() {
// TODO: we need to support handle this case gracefully, cf. issue #620.
println!("Warning: texture size ({} {}) larger than the maximum size",
descriptor.width, descriptor.height);
// We aren't going to be able to upload a texture this big, so tile it, even
// if tiling was not requested.
tiling = Some(512);
}
let resource = ImageResource {
descriptor: descriptor,
data: data,
epoch: Epoch(0),
tiling: tiling,
};
self.image_templates.insert(image_key, resource);
@ -301,6 +307,7 @@ impl ResourceCache {
descriptor: descriptor,
data: ImageData::new(bytes),
epoch: next_epoch,
tiling: None,
};
self.image_templates.insert(image_key, resource);
@ -339,11 +346,16 @@ impl ResourceCache {
webgl_texture.size = size;
}
pub fn request_image(&mut self, key: ImageKey, rendering: ImageRendering) {
pub fn request_image(&mut self,
key: ImageKey,
rendering: ImageRendering,
tile: Option<TileOffset>) {
debug_assert!(self.state == State::AddResources);
let request = ImageRequest {
key: key,
rendering: rendering,
tile: tile,
};
let template = self.image_templates.get(&key).unwrap();
@ -472,11 +484,13 @@ impl ResourceCache {
#[inline]
pub fn get_cached_image(&self,
image_key: ImageKey,
image_rendering: ImageRendering) -> CacheItem {
image_rendering: ImageRendering,
tile: Option<TileOffset>) -> CacheItem {
debug_assert!(self.state == State::QueryResources);
let key = ImageRequest {
key: image_key,
rendering: image_rendering,
tile: tile,
};
let image_info = &self.cached_images.get(&key, self.current_frame_id);
let item = self.texture_cache.get(image_info.texture_cache_id);
@ -501,6 +515,7 @@ impl ResourceCache {
ImageProperties {
descriptor: image_template.descriptor,
external_id: external_id,
tiling: image_template.tiling,
}
}
@ -529,7 +544,8 @@ impl ResourceCache {
self.glyph_cache_tx.send(GlyphCacheMsg::BeginFrame(frame_id, glyph_cache)).ok();
}
pub fn block_until_all_resources_added(&mut self) {
pub fn block_until_all_resources_added(&mut self,
texture_cache_profile: &mut TextureCacheProfileCounters) {
profile_scope!("block_until_all_resources_added");
debug_assert!(self.state == State::AddResources);
@ -563,9 +579,11 @@ impl ResourceCache {
stride: None,
format: ImageFormat::RGBA8,
is_opaque: false,
offset: 0,
},
TextureFilter::Linear,
ImageData::Raw(Arc::new(glyph.bytes)));
ImageData::Raw(Arc::new(glyph.bytes)),
texture_cache_profile);
Some(image_id)
} else {
None
@ -583,7 +601,7 @@ impl ResourceCache {
let mut image_requests = mem::replace(&mut self.pending_image_requests, Vec::new());
for request in image_requests.drain(..) {
self.finalize_image_request(request, None);
self.finalize_image_request(request, None, texture_cache_profile);
}
let mut blob_image_requests = mem::replace(&mut self.blob_image_requests, HashSet::new());
@ -592,7 +610,9 @@ impl ResourceCache {
match self.blob_image_renderer.as_mut().unwrap()
.resolve_blob_image(request.key) {
Ok(image) => {
self.finalize_image_request(request, Some(ImageData::new(image.data)));
self.finalize_image_request(request,
Some(ImageData::new(image.data)),
texture_cache_profile);
}
// TODO(nical): I think that we should handle these somewhat gracefully,
// at least in the out-of-memory scenario.
@ -615,7 +635,10 @@ impl ResourceCache {
}
}
fn finalize_image_request(&mut self, request: ImageRequest, image_data: Option<ImageData>) {
fn finalize_image_request(&mut self,
request: ImageRequest,
image_data: Option<ImageData>,
texture_cache_profile: &mut TextureCacheProfileCounters) {
let image_template = &self.image_templates[&request.key];
let image_data = image_data.unwrap_or_else(||{
image_template.data.clone()
@ -650,10 +673,50 @@ impl ResourceCache {
ImageRendering::Auto | ImageRendering::CrispEdges => TextureFilter::Linear,
};
self.texture_cache.insert(image_id,
image_template.descriptor,
filter,
image_data);
if let Some(tile) = request.tile {
let tile_size = image_template.tiling.unwrap() as u32;
let image_descriptor = image_template.descriptor.clone();
let stride = image_descriptor.compute_stride();
let bpp = image_descriptor.format.bytes_per_pixel().unwrap();
// Storage for the tiles on the right and bottom edges is shrunk to
// fit the image data (See decompose_tiled_image in frame.rs).
let actual_width = if (tile.x as u32) < image_descriptor.width / tile_size {
tile_size
} else {
image_descriptor.width % tile_size
};
let actual_height = if (tile.y as u32) < image_descriptor.height / tile_size {
tile_size
} else {
image_descriptor.height % tile_size
};
let offset = image_descriptor.offset + tile.y as u32 * tile_size * stride
+ tile.x as u32 * tile_size * bpp;
let tile_descriptor = ImageDescriptor {
width: actual_width,
height: actual_height,
stride: Some(stride),
offset: offset,
format: image_descriptor.format,
is_opaque: image_descriptor.is_opaque,
};
self.texture_cache.insert(image_id,
tile_descriptor,
filter,
image_data,
texture_cache_profile);
} else {
self.texture_cache.insert(image_id,
image_template.descriptor,
filter,
image_data,
texture_cache_profile);
}
entry.insert(CachedImageInfo {
texture_cache_id: image_id,

View file

@ -7,6 +7,7 @@ use fnv::FnvHasher;
use freelist::{FreeList, FreeListItem, FreeListItemId};
use internal_types::{TextureUpdate, TextureUpdateOp};
use internal_types::{CacheTextureId, RenderTargetMode, TextureUpdateList, RectUv};
use profiler::TextureCacheProfileCounters;
use std::cmp::{self, Ordering};
use std::collections::HashMap;
use std::collections::hash_map::Entry;
@ -94,55 +95,29 @@ impl TexturePage {
smallest_index_and_area.map(|(index, _)| FreeListIndex(bin, index))
}
/// Find a suitable rect in the free list. We choose the smallest such rect
/// in terms of area (Best-Area-Fit, BAF).
fn find_index_of_best_rect(&self, requested_dimensions: &DeviceUintSize)
-> Option<FreeListIndex> {
match FreeListBin::for_size(requested_dimensions) {
FreeListBin::Large => {
self.find_index_of_best_rect_in_bin(FreeListBin::Large, requested_dimensions)
}
FreeListBin::Medium => {
match self.find_index_of_best_rect_in_bin(FreeListBin::Medium,
requested_dimensions) {
Some(index) => Some(index),
None => {
self.find_index_of_best_rect_in_bin(FreeListBin::Large,
requested_dimensions)
}
}
}
FreeListBin::Small => {
match self.find_index_of_best_rect_in_bin(FreeListBin::Small,
requested_dimensions) {
Some(index) => Some(index),
None => {
match self.find_index_of_best_rect_in_bin(FreeListBin::Medium,
requested_dimensions) {
Some(index) => Some(index),
None => {
self.find_index_of_best_rect_in_bin(FreeListBin::Large,
requested_dimensions)
}
}
}
let bin = FreeListBin::for_size(requested_dimensions);
for &target_bin in &[FreeListBin::Small, FreeListBin::Medium, FreeListBin::Large] {
if bin <= target_bin {
if let Some(index) = self.find_index_of_best_rect_in_bin(target_bin,
requested_dimensions) {
return Some(index);
}
}
}
None
}
pub fn can_allocate(&self, requested_dimensions: &DeviceUintSize) -> bool {
self.find_index_of_best_rect(requested_dimensions).is_some()
}
pub fn allocate(&mut self,
requested_dimensions: &DeviceUintSize) -> Option<DeviceUintPoint> {
// First, try to find a suitable rect in the free list. We choose the smallest such rect
// in terms of area (Best-Area-Fit, BAF).
let mut index = self.find_index_of_best_rect(requested_dimensions);
// If one couldn't be found and we're dirty, coalesce rects and try again.
if index.is_none() && self.dirty {
self.coalesce();
index = self.find_index_of_best_rect(requested_dimensions)
}
// If a rect still can't be found, fail.
let index = match index {
let index = match self.find_index_of_best_rect(requested_dimensions) {
None => return None,
Some(index) => index,
};
@ -199,7 +174,11 @@ impl TexturePage {
}
#[inline(never)]
fn coalesce(&mut self) {
pub fn coalesce(&mut self) -> bool {
if !self.dirty {
return false
}
// Iterate to a fixed point or until a timeout is reached.
let deadline = time::precise_time_ns() + COALESCING_TIMEOUT;
let mut free_list = mem::replace(&mut self.free_list, FreeRectList::new()).into_vec();
@ -218,7 +197,7 @@ impl TexturePage {
time::precise_time_ns() >= deadline {
self.free_list = FreeRectList::from_slice(&free_list[..]);
self.dirty = true;
return
return true
}
if free_list[work_index].size.width == 0 {
@ -255,7 +234,7 @@ impl TexturePage {
time::precise_time_ns() >= deadline {
self.free_list = FreeRectList::from_slice(&free_list[..]);
self.dirty = true;
return
return true
}
if free_list[work_index].size.height == 0 {
@ -280,7 +259,8 @@ impl TexturePage {
free_list = new_free_list;
self.free_list = FreeRectList::from_slice(&free_list[..]);
self.dirty = changed
self.dirty = changed;
changed
}
pub fn clear(&mut self) {
@ -391,7 +371,7 @@ impl FreeRectList {
#[derive(Debug, Clone, Copy)]
struct FreeListIndex(FreeListBin, usize);
#[derive(Debug, Clone, Copy, PartialEq)]
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
enum FreeListBin {
Small,
Medium,
@ -428,6 +408,12 @@ pub struct TextureCacheItem {
// Structure squat the width/height fields to maintain the free list information :)
impl FreeListItem for TextureCacheItem {
fn take(&mut self) -> Self {
let data = self.clone();
self.texture_id = CacheTextureId(0);
data
}
fn next_free_id(&self) -> Option<FreeListItemId> {
if self.allocated_rect.size.width == 0 {
debug_assert_eq!(self.allocated_rect.size.height, 0);
@ -580,17 +566,9 @@ impl TextureCache {
// then use it). But it has to be that way for now due to
// how the raster_jobs code works.
pub fn new_item_id(&mut self) -> TextureCacheItemId {
let new_item = TextureCacheItem {
pixel_rect: RectUv {
top_left: DeviceIntPoint::zero(),
top_right: DeviceIntPoint::zero(),
bottom_left: DeviceIntPoint::zero(),
bottom_right: DeviceIntPoint::zero(),
},
allocated_rect: DeviceUintRect::zero(),
texture_size: DeviceUintSize::zero(),
texture_id: CacheTextureId(0),
};
let new_item = TextureCacheItem::new(CacheTextureId(0),
DeviceUintRect::zero(),
&DeviceUintSize::zero());
self.items.insert(new_item)
}
@ -599,7 +577,8 @@ impl TextureCache {
requested_width: u32,
requested_height: u32,
format: ImageFormat,
filter: TextureFilter)
filter: TextureFilter,
profile: &mut TextureCacheProfileCounters)
-> AllocationResult {
let requested_size = DeviceUintSize::new(requested_width, requested_height);
@ -624,10 +603,10 @@ impl TextureCache {
}
let mode = RenderTargetMode::SimpleRenderTarget;
let page_list = match format {
ImageFormat::A8 => &mut self.arena.pages_a8,
ImageFormat::RGBA8 => &mut self.arena.pages_rgba8,
ImageFormat::RGB8 => &mut self.arena.pages_rgb8,
let (page_list, page_profile) = match format {
ImageFormat::A8 => (&mut self.arena.pages_a8, &mut profile.pages_a8),
ImageFormat::RGBA8 => (&mut self.arena.pages_rgba8, &mut profile.pages_rgba8),
ImageFormat::RGB8 => (&mut self.arena.pages_rgb8, &mut profile.pages_rgb8),
ImageFormat::Invalid | ImageFormat::RGBAF32 => unreachable!(),
};
@ -635,74 +614,92 @@ impl TextureCache {
assert!(requested_size.width < self.max_texture_size);
assert!(requested_size.height < self.max_texture_size);
// Loop until an allocation succeeds, growing or adding new
// texture pages as required.
loop {
let location = page_list.last_mut().and_then(|last_page| {
last_page.allocate(&requested_size)
});
if let Some(location) = location {
let page = page_list.last_mut().unwrap();
let requested_rect = DeviceUintRect::new(location, requested_size);
let cache_item = TextureCacheItem::new(page.texture_id,
requested_rect,
&page.texture_size);
*self.items.get_mut(image_id) = cache_item;
return AllocationResult {
item: self.items.get(image_id).clone(),
kind: AllocationKind::TexturePage,
}
let mut page_id = None; //using ID here to please the borrow checker
for (i, page) in page_list.iter_mut().enumerate() {
if page.can_allocate(&requested_size) {
page_id = Some(i);
break;
}
if !page_list.is_empty() && page_list.last().unwrap().can_grow(self.max_texture_size) {
let last_page = page_list.last_mut().unwrap();
// Grow the texture.
let new_width = cmp::min(last_page.texture_size.width * 2, self.max_texture_size);
let new_height = cmp::min(last_page.texture_size.height * 2, self.max_texture_size);
// try to coalesce it
if page.coalesce() && page.can_allocate(&requested_size) {
page_id = Some(i);
break;
}
if page.can_grow(self.max_texture_size) {
// try to grow it
let new_width = cmp::min(page.texture_size.width * 2, self.max_texture_size);
let new_height = cmp::min(page.texture_size.height * 2, self.max_texture_size);
let texture_size = DeviceUintSize::new(new_width, new_height);
self.pending_updates.push(TextureUpdate {
id: last_page.texture_id,
id: page.texture_id,
op: texture_grow_op(texture_size, format, mode),
});
last_page.grow(texture_size);
let extra_texels = new_width * new_height - page.texture_size.width * page.texture_size.height;
let extra_bytes = extra_texels * format.bytes_per_pixel().unwrap_or(0);
page_profile.inc(extra_bytes as usize);
page.grow(texture_size);
self.items.for_each_item(|item| {
if item.texture_id == last_page.texture_id {
if item.texture_id == page.texture_id {
item.texture_size = texture_size;
}
});
continue;
if page.can_allocate(&requested_size) {
page_id = Some(i);
break;
}
}
}
// We need a new page.
let texture_size = initial_texture_size(self.max_texture_size);
let free_texture_levels_entry = self.free_texture_levels.entry(format);
let mut free_texture_levels = match free_texture_levels_entry {
Entry::Vacant(entry) => entry.insert(Vec::new()),
Entry::Occupied(entry) => entry.into_mut(),
};
if free_texture_levels.is_empty() {
let texture_id = self.cache_id_list.allocate();
let mut page = match page_id {
Some(index) => &mut page_list[index],
None => {
let init_texture_size = initial_texture_size(self.max_texture_size);
let texture_size = DeviceUintSize::new(cmp::max(requested_width, init_texture_size.width),
cmp::max(requested_height, init_texture_size.height));
let extra_bytes = texture_size.width * texture_size.height * format.bytes_per_pixel().unwrap_or(0);
page_profile.inc(extra_bytes as usize);
let update_op = TextureUpdate {
id: texture_id,
op: texture_create_op(texture_size, format, mode),
let free_texture_levels_entry = self.free_texture_levels.entry(format);
let mut free_texture_levels = match free_texture_levels_entry {
Entry::Vacant(entry) => entry.insert(Vec::new()),
Entry::Occupied(entry) => entry.into_mut(),
};
self.pending_updates.push(update_op);
if free_texture_levels.is_empty() {
let texture_id = self.cache_id_list.allocate();
free_texture_levels.push(FreeTextureLevel {
texture_id: texture_id,
});
}
let free_texture_level = free_texture_levels.pop().unwrap();
let texture_id = free_texture_level.texture_id;
let update_op = TextureUpdate {
id: texture_id,
op: texture_create_op(texture_size, format, mode),
};
self.pending_updates.push(update_op);
let page = TexturePage::new(texture_id, texture_size);
page_list.push(page);
free_texture_levels.push(FreeTextureLevel {
texture_id: texture_id,
});
}
let free_texture_level = free_texture_levels.pop().unwrap();
let texture_id = free_texture_level.texture_id;
let page = TexturePage::new(texture_id, texture_size);
page_list.push(page);
page_list.last_mut().unwrap()
},
};
let location = page.allocate(&requested_size)
.expect("All the checks have passed till now, there is no way back.");
let cache_item = TextureCacheItem::new(page.texture_id,
DeviceUintRect::new(location, requested_size),
&page.texture_size);
*self.items.get_mut(image_id) = cache_item.clone();
AllocationResult {
item: cache_item,
kind: AllocationKind::TexturePage,
}
}
@ -731,6 +728,7 @@ impl TextureCache {
height: descriptor.height,
data: bytes,
stride: descriptor.stride,
offset: descriptor.offset,
}
}
};
@ -747,7 +745,8 @@ impl TextureCache {
image_id: TextureCacheItemId,
descriptor: ImageDescriptor,
filter: TextureFilter,
data: ImageData) {
data: ImageData,
profile: &mut TextureCacheProfileCounters) {
if let ImageData::Blob(..) = data {
panic!("must rasterize the vector image before adding to the cache");
}
@ -761,7 +760,8 @@ impl TextureCache {
width,
height,
format,
filter);
filter,
profile);
match result.kind {
AllocationKind::TexturePage => {
@ -782,6 +782,7 @@ impl TextureCache {
height: result.item.allocated_rect.size.height,
data: bytes,
stride: stride,
offset: descriptor.offset,
},
};
@ -831,23 +832,19 @@ impl TextureCache {
}
pub fn free(&mut self, id: TextureCacheItemId) {
{
let item = self.items.get(id);
match self.arena.texture_page_for_id(item.texture_id) {
Some(texture_page) => texture_page.free(&item.allocated_rect),
None => {
// This is a standalone texture allocation. Just push it back onto the free
// list.
self.pending_updates.push(TextureUpdate {
id: item.texture_id,
op: TextureUpdateOp::Free,
});
self.cache_id_list.free(item.texture_id);
}
let item = self.items.free(id);
match self.arena.texture_page_for_id(item.texture_id) {
Some(texture_page) => texture_page.free(&item.allocated_rect),
None => {
// This is a standalone texture allocation. Just push it back onto the free
// list.
self.pending_updates.push(TextureUpdate {
id: item.texture_id,
op: TextureUpdateOp::Free,
});
self.cache_id_list.free(item.texture_id);
}
}
self.items.free(id)
}
}

View file

@ -808,22 +808,22 @@ impl ClipBatcher {
self.rectangles.extend(&[
CacheClipInstance {
address: GpuStoreAddress(offset),
segment: MaskSegment::Corner_TopLeft as i32,
segment: MaskSegment::TopLeftCorner as i32,
..instance
},
CacheClipInstance {
address: GpuStoreAddress(offset),
segment: MaskSegment::Corner_TopRight as i32,
segment: MaskSegment::TopRightCorner as i32,
..instance
},
CacheClipInstance {
address: GpuStoreAddress(offset),
segment: MaskSegment::Corner_BottomLeft as i32,
segment: MaskSegment::BottomLeftCorner as i32,
..instance
},
CacheClipInstance {
address: GpuStoreAddress(offset),
segment: MaskSegment::Corner_BottomRight as i32,
segment: MaskSegment::BottomRightCorner as i32,
..instance
},
]);
@ -832,7 +832,7 @@ impl ClipBatcher {
}
if let Some((ref mask, address)) = info.image {
let cache_item = resource_cache.get_cached_image(mask.image, ImageRendering::Auto);
let cache_item = resource_cache.get_cached_image(mask.image, ImageRendering::Auto, None);
self.images.entry(cache_item.texture_id)
.or_insert(Vec::new())
.push(CacheClipInstance {

View file

@ -5,21 +5,13 @@ authors = ["The Mozilla Project Developers"]
license = "MPL-2.0"
[dependencies]
webrender_traits = {path = "../webrender_traits", version = "0.19"}
webrender_traits = {path = "../webrender_traits", version = "0.20.0"}
euclid = "0.11"
app_units = "0.4"
gleam = "0.2"
fnv="1.0"
[dependencies.webrender]
path = "../webrender"
version = "0.19"
version = "0.19.0"
default-features = false
features = ["codegen"]
[target.'cfg(target_os = "macos")'.dependencies]
core-foundation = "0.2.2"
[target.'cfg(target_os = "windows")'.dependencies]
kernel32-sys = "0.2"
winapi = "0.2.8"

View file

@ -160,10 +160,7 @@ NotifyDidRender(layers::CompositorBridgeParentBase* aBridge,
WrPipelineId pipeline;
WrEpoch epoch;
while (wr_rendered_epochs_next(aEpochs, &pipeline, &epoch)) {
// TODO - Currently each bridge seems to only have one pipeline but at some
// point we should pass make sure we only notify bridges that have the
// corresponding pipeline id.
aBridge->NotifyDidComposite(epoch.mHandle, aStart, aEnd);
aBridge->NotifyDidCompositeToPipeline(pipeline, epoch, aStart, aEnd);
}
wr_rendered_epochs_delete(aEpochs);
}

View file

@ -14,6 +14,19 @@
namespace mozilla {
namespace wr {
WrExternalImage LockExternalImage(void* aObj, WrExternalImageId aId)
{
return WrExternalImage { /*WrExternalImageIdType::TextureHandle, */0.0f, 0.0f, 0.0f, 0.0f, 0 };
}
void UnlockExternalImage(void* aObj, WrExternalImageId aId)
{
}
void ReleaseExternalImage(void* aObj, WrExternalImageId aId)
{
}
RendererOGL::RendererOGL(RefPtr<RenderThread>&& aThread,
RefPtr<gl::GLContext>&& aGL,
RefPtr<widget::CompositorWidget>&& aWidget,
@ -41,6 +54,17 @@ RendererOGL::~RendererOGL()
wr_renderer_delete(mWrRenderer);
}
WrExternalImageHandler
RendererOGL::GetExternalImageHandler()
{
return WrExternalImageHandler {
this,
LockExternalImage,
UnlockExternalImage,
ReleaseExternalImage,
};
}
void
RendererOGL::Update()
{

View file

@ -38,7 +38,13 @@ namespace wr {
/// on the render thread instead of the compositor thread.
class RendererOGL
{
friend WrExternalImage LockExternalImage(void* aObj, WrExternalImageId aId);
friend void UnlockExternalImage(void* aObj, WrExternalImageId aId);
friend void ReleaseExternalImage(void* aObj, WrExternalImageId aId);
public:
WrExternalImageHandler GetExternalImageHandler();
/// This can be called on the render thread only.
void Update();

View file

@ -51,7 +51,7 @@ public:
*mUseANGLE = gl->IsANGLE();
WrRenderer* wrRenderer = nullptr;
if (!wr_window_new(aWindowId, gl.get(), this->mEnableProfiler, nullptr, mWrApi, &wrRenderer)) {
if (!wr_window_new(aWindowId, gl.get(), this->mEnableProfiler, mWrApi, &wrRenderer)) {
return;
}
MOZ_ASSERT(wrRenderer);
@ -63,6 +63,10 @@ public:
aWindowId,
wrRenderer,
mBridge);
if (wrRenderer && renderer) {
WrExternalImageHandler handler = renderer->GetExternalImageHandler();
wr_renderer_set_external_image_handler(wrRenderer, &handler);
}
aRenderThread.AddRenderer(aWindowId, Move(renderer));
}
@ -135,6 +139,11 @@ WebRenderAPI::Create(bool aEnableProfiler,
return RefPtr<WebRenderAPI>(new WebRenderAPI(wrApi, id, maxTextureSize, useANGLE)).forget();
}
WrIdNamespace
WebRenderAPI::GetNamespace() {
return wr_api_get_namespace(mWrApi);
}
WebRenderAPI::~WebRenderAPI()
{
layers::SynchronousTask task("Destroy WebRenderAPI");
@ -145,15 +154,34 @@ WebRenderAPI::~WebRenderAPI()
wr_api_delete(mWrApi);
}
void
WebRenderAPI::GenerateFrame()
{
wr_api_generate_frame(mWrApi);
}
void
WebRenderAPI::SetRootDisplayList(gfx::Color aBgColor,
Epoch aEpoch,
LayerSize aViewportSize,
DisplayListBuilder& aBuilder)
WrPipelineId pipeline_id,
WrBuiltDisplayListDescriptor dl_descriptor,
uint8_t *dl_data,
size_t dl_size,
WrAuxiliaryListsDescriptor aux_descriptor,
uint8_t *aux_data,
size_t aux_size)
{
wr_api_set_root_display_list(mWrApi, aBuilder.mWrState,
aEpoch,
aViewportSize.width, aViewportSize.height);
wr_api_set_root_display_list(mWrApi,
aEpoch,
aViewportSize.width, aViewportSize.height,
pipeline_id,
dl_descriptor,
dl_data,
dl_size,
aux_descriptor,
aux_data,
aux_size);
}
void
@ -209,24 +237,40 @@ WebRenderAPI::SetRootPipeline(PipelineId aPipeline)
wr_api_set_root_pipeline(mWrApi, aPipeline);
}
ImageKey
WebRenderAPI::AddImageBuffer(const ImageDescriptor& aDescritptor,
Range<uint8_t> aBytes)
void
WebRenderAPI::AddImage(ImageKey key, const ImageDescriptor& aDescritptor,
Range<uint8_t> aBytes)
{
return ImageKey(wr_api_add_image(mWrApi,
&aDescritptor,
&aBytes[0], aBytes.length()));
wr_api_add_image(mWrApi,
key,
&aDescritptor,
&aBytes[0], aBytes.length());
}
ImageKey
WebRenderAPI::AddExternalImageHandle(gfx::IntSize aSize,
void
WebRenderAPI::AddExternalImageHandle(ImageKey key,
gfx::IntSize aSize,
gfx::SurfaceFormat aFormat,
uint64_t aHandle)
{
auto format = SurfaceFormatToWrImageFormat(aFormat).value();
return ImageKey(wr_api_add_external_image_texture(mWrApi,
aSize.width, aSize.height, format,
aHandle));
wr_api_add_external_image_handle(mWrApi,
key,
aSize.width, aSize.height, format,
aHandle);
}
void
WebRenderAPI::AddExternalImageBuffer(ImageKey key,
gfx::IntSize aSize,
gfx::SurfaceFormat aFormat,
uint64_t aHandle)
{
auto format = SurfaceFormatToWrImageFormat(aFormat).value();
wr_api_add_external_image_buffer(mWrApi,
key,
aSize.width, aSize.height, format,
aHandle);
}
void
@ -246,10 +290,10 @@ WebRenderAPI::DeleteImage(ImageKey aKey)
wr_api_delete_image(mWrApi, aKey);
}
wr::FontKey
WebRenderAPI::AddRawFont(Range<uint8_t> aBytes)
void
WebRenderAPI::AddRawFont(wr::FontKey key, Range<uint8_t> aBytes)
{
return wr::FontKey(wr_api_add_raw_font(mWrApi, &aBytes[0], aBytes.length()));
wr_api_add_raw_font(mWrApi, key, &aBytes[0], aBytes.length());
}
void
@ -298,10 +342,10 @@ WebRenderAPI::RunOnRenderThread(UniquePtr<RendererEvent> aEvent)
wr_api_send_external_event(mWrApi, event);
}
DisplayListBuilder::DisplayListBuilder(const LayerIntSize& aSize, PipelineId aId)
DisplayListBuilder::DisplayListBuilder(PipelineId aId)
{
MOZ_COUNT_CTOR(DisplayListBuilder);
mWrState = wr_state_new(aSize.width, aSize.height, aId);
mWrState = wr_state_new(aId);
}
DisplayListBuilder::~DisplayListBuilder()
@ -317,9 +361,22 @@ DisplayListBuilder::Begin(const LayerIntSize& aSize)
}
void
DisplayListBuilder::End(WebRenderAPI& aApi, Epoch aEpoch)
DisplayListBuilder::End()
{
wr_dp_end(mWrState, aApi.mWrApi, aEpoch);
wr_dp_end(mWrState);
}
void
DisplayListBuilder::Finalize(WrBuiltDisplayListDescriptor& dl_descriptor,
wr::VecU8& dl_data,
WrAuxiliaryListsDescriptor& aux_descriptor,
wr::VecU8& aux_data)
{
wr_api_finalize_builder(mWrState,
dl_descriptor,
dl_data.inner,
aux_descriptor,
aux_data.inner);
}
void

View file

@ -29,6 +29,8 @@ class DisplayListBuilder;
class RendererOGL;
class RendererEvent;
class WebRenderAPI
{
NS_INLINE_DECL_REFCOUNTING(WebRenderAPI);
@ -41,19 +43,34 @@ public:
wr::WindowId GetId() const { return mId; }
void GenerateFrame();
void SetRootDisplayList(gfx::Color aBgColor,
wr::Epoch aEpoch,
Epoch aEpoch,
LayerSize aViewportSize,
DisplayListBuilder& aBuilder);
WrPipelineId pipeline_id,
WrBuiltDisplayListDescriptor dl_descriptor,
uint8_t *dl_data,
size_t dl_size,
WrAuxiliaryListsDescriptor aux_descriptor,
uint8_t *aux_data,
size_t aux_size);
void SetRootPipeline(wr::PipelineId aPipeline);
wr::ImageKey AddImageBuffer(const ImageDescriptor& aDescriptor,
Range<uint8_t> aBytes);
void AddImage(wr::ImageKey aKey,
const ImageDescriptor& aDescriptor,
Range<uint8_t> aBytes);
wr::ImageKey AddExternalImageHandle(gfx::IntSize aSize,
gfx::SurfaceFormat aFormat,
uint64_t aHandle);
void AddExternalImageHandle(ImageKey key,
gfx::IntSize aSize,
gfx::SurfaceFormat aFormat,
uint64_t aHandle);
void AddExternalImageBuffer(ImageKey key,
gfx::IntSize aSize,
gfx::SurfaceFormat aFormat,
uint64_t aHandle);
void UpdateImageBuffer(wr::ImageKey aKey,
const ImageDescriptor& aDescriptor,
@ -61,7 +78,7 @@ public:
void DeleteImage(wr::ImageKey aKey);
wr::FontKey AddRawFont(Range<uint8_t> aBytes);
void AddRawFont(wr::FontKey aKey, Range<uint8_t> aBytes);
void DeleteFont(wr::FontKey aKey);
@ -70,6 +87,7 @@ public:
void RunOnRenderThread(UniquePtr<RendererEvent> aEvent);
void Readback(gfx::IntSize aSize, uint8_t *aBuffer, uint32_t aBufferSize);
WrIdNamespace GetNamespace();
GLint GetMaxTextureSize() const { return mMaxTextureSize; }
bool GetUseANGLE() const { return mUseANGLE; }
@ -96,14 +114,18 @@ protected:
/// instead, so the interface may change a bit.
class DisplayListBuilder {
public:
DisplayListBuilder(const LayerIntSize& aSize, wr::PipelineId aId);
explicit DisplayListBuilder(wr::PipelineId aId);
DisplayListBuilder(DisplayListBuilder&&) = default;
~DisplayListBuilder();
void Begin(const LayerIntSize& aSize);
void End(WebRenderAPI& aApi, wr::Epoch aEpoch);
void End();
void Finalize(WrBuiltDisplayListDescriptor& dl_descriptor,
wr::VecU8& dl_data,
WrAuxiliaryListsDescriptor& aux_descriptor,
wr::VecU8& aux_data);
void PushStackingContext(const WrRect& aBounds, // TODO: We should work with strongly typed rects
const WrRect& aOverflow,

View file

@ -10,6 +10,9 @@
#include "mozilla/Maybe.h"
#include "mozilla/gfx/Types.h"
#include "mozilla/gfx/Tools.h"
#include "mozilla/Range.h"
#include "Units.h"
#include "nsStyleConsts.h"
typedef mozilla::Maybe<WrImageMask> MaybeImageMask;
@ -235,6 +238,33 @@ static inline WrPoint ToWrPoint(const gfx::Point& point)
return p;
}
static inline WrExternalImageId ToWrExternalImageId(uint64_t aID)
{
WrExternalImageId id;
id.id = aID;
return id;
}
struct VecU8 {
WrVecU8 inner;
VecU8() {
inner.data = nullptr;
inner.capacity = 0;
}
VecU8(VecU8&) = delete;
VecU8(VecU8&& src) {
inner = src.inner;
src.inner.data = nullptr;
src.inner.capacity = 0;
}
~VecU8() {
if (inner.data) {
wr_vec_u8_free(inner);
}
}
};
struct ByteBuffer
{
ByteBuffer(size_t aLength, uint8_t* aData)
@ -243,6 +273,23 @@ struct ByteBuffer
, mOwned(false)
{}
// XXX: this is a bit of hack that assumes
// the allocators are the same
explicit ByteBuffer(VecU8&& vec)
{
if (vec.inner.capacity) {
mLength = vec.inner.length;
mData = vec.inner.data;
vec.inner.data = nullptr;
vec.inner.capacity = 0;
mOwned = true;
} else {
mOwned = false;
mData = nullptr;
mLength = 0;
}
}
ByteBuffer()
: mLength(0)
, mData(nullptr)
@ -283,6 +330,13 @@ struct ByteBuffer
bool mOwned;
};
struct BuiltDisplayList {
VecU8 dl;
WrBuiltDisplayListDescriptor dl_desc;
VecU8 aux;
WrAuxiliaryListsDescriptor aux_desc;
};
} // namespace wr
} // namespace mozilla

View file

@ -6,11 +6,13 @@ use gleam::gl;
use webrender_traits::{BorderSide, BorderStyle, BorderRadius, BorderWidths, BorderDetails, NormalBorder};
use webrender_traits::{PipelineId, ClipRegion, PropertyBinding};
use webrender_traits::{Epoch, ExtendMode, ColorF, GlyphInstance, GradientStop, ImageDescriptor};
use webrender_traits::{FilterOp, ImageData, ImageFormat, ImageKey, ImageMask, ImageRendering, RendererKind, MixBlendMode};
use webrender_traits::{FilterOp, ImageData, ImageFormat, ImageKey, ImageMask, ImageRendering, MixBlendMode};
use webrender_traits::{ExternalImageId, RenderApi, FontKey};
use webrender_traits::{DeviceUintSize, ExternalEvent};
use webrender_traits::{LayoutPoint, LayoutRect, LayoutSize, LayoutTransform};
use webrender_traits::{BoxShadowClipMode, LayerPixel, ServoScrollRootId};
use webrender_traits::{BoxShadowClipMode, LayerPixel, ServoScrollRootId, IdNamespace};
use webrender_traits::{BuiltDisplayListDescriptor, AuxiliaryListsDescriptor};
use webrender_traits::{BuiltDisplayList, AuxiliaryLists};
use webrender::renderer::{Renderer, RendererOptions};
use webrender::renderer::{ExternalImage, ExternalImageHandler, ExternalImageSource};
use webrender::{ApiRecordingReceiver, BinaryRecorder};
@ -48,6 +50,7 @@ check_ffi_type!(_epoch_repr struct Epoch as (u32));
check_ffi_type!(_image_format_repr enum ImageFormat as u32);
check_ffi_type!(_border_style_repr enum BorderStyle as u32);
check_ffi_type!(_image_rendering_repr enum ImageRendering as u32);
check_ffi_type!(_namespace_id_repr struct IdNamespace as (u32));
#[repr(C)]
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
@ -63,6 +66,42 @@ pub struct WrImageDescriptor {
pub is_opaque: bool,
}
impl WrImageDescriptor {
pub fn to_descriptor(&self) -> ImageDescriptor {
ImageDescriptor {
width: self.width,
height: self.height,
stride: if self.stride != 0 { Some(self.stride) } else { None },
format: self.format,
is_opaque: self.is_opaque,
offset: 0,
}
}
}
#[repr(C)]
pub struct WrVecU8 {
ptr: *mut u8,
length: usize,
capacity: usize
}
impl WrVecU8 {
fn to_vec(self) -> Vec<u8> {
unsafe { Vec::from_raw_parts(self.ptr, self.length, self.capacity) }
}
fn from_vec(mut v: Vec<u8>) -> WrVecU8 {
let w = WrVecU8{ptr: v.as_mut_ptr(), length: v.len(), capacity: v.capacity()};
mem::forget(v);
w
}
}
#[no_mangle]
pub extern fn wr_vec_u8_free(v: WrVecU8) {
v.to_vec();
}
fn get_proc_address(glcontext_ptr: *mut c_void, name: &str) -> *const c_void{
extern {
@ -86,6 +125,7 @@ fn get_proc_address(glcontext_ptr: *mut c_void, name: &str) -> *const c_void{
extern {
fn is_in_compositor_thread() -> bool;
fn is_in_render_thread() -> bool;
fn is_in_main_thread() -> bool;
}
#[no_mangle]
@ -120,6 +160,22 @@ pub extern fn wr_renderer_set_profiler_enabled(renderer: &mut Renderer, enabled:
renderer.set_profiler_enabled(enabled);
}
#[no_mangle]
pub extern fn wr_renderer_set_external_image_handler(renderer: &mut Renderer,
external_image_handler: *mut WrExternalImageHandler) {
if !external_image_handler.is_null() {
renderer.set_external_image_handler(Box::new(
unsafe {
WrExternalImageHandler {
external_image_obj: (*external_image_handler).external_image_obj,
lock_func: (*external_image_handler).lock_func,
unlock_func: (*external_image_handler).unlock_func,
release_func: (*external_image_handler).release_func,
}
}));
}
}
#[no_mangle]
pub extern fn wr_renderer_current_epoch(renderer: &mut Renderer,
pipeline_id: PipelineId,
@ -136,6 +192,12 @@ pub unsafe extern fn wr_renderer_delete(renderer: *mut Renderer) {
Box::from_raw(renderer);
}
#[no_mangle]
pub unsafe extern fn wr_api_get_namespace(api: &mut RenderApi) -> IdNamespace
{
api.id_namespace
}
#[no_mangle]
pub unsafe extern fn wr_api_delete(api: *mut RenderApi) {
let api = Box::from_raw(api);
@ -143,25 +205,62 @@ pub unsafe extern fn wr_api_delete(api: *mut RenderApi) {
}
#[no_mangle]
pub unsafe extern fn wr_api_set_root_display_list(api: &mut RenderApi,
state: &mut WrState,
epoch: Epoch,
viewport_width: f32,
viewport_height: f32) {
let root_background_color = ColorF::new(0.3, 0.0, 0.0, 1.0);
pub unsafe extern fn wr_api_finalize_builder(state: &mut WrState,
dl_descriptor: &mut BuiltDisplayListDescriptor,
dl_data: &mut WrVecU8,
aux_descriptor: &mut AuxiliaryListsDescriptor,
aux_data: &mut WrVecU8)
{
let frame_builder = mem::replace(&mut state.frame_builder,
WebRenderFrameBuilder::new(state.pipeline_id));
let (_, dl, aux) = frame_builder.dl_builder.finalize();
//XXX: get rid of the copies here
*dl_data = WrVecU8::from_vec(dl.data().to_owned());
*dl_descriptor = dl.descriptor().clone();
*aux_data = WrVecU8::from_vec(aux.data().to_owned());
*aux_descriptor = aux.descriptor().clone();
}
#[no_mangle]
pub unsafe extern fn wr_api_set_root_display_list(api: &mut RenderApi,
epoch: Epoch,
viewport_width: f32,
viewport_height: f32,
pipeline_id: PipelineId,
dl_descriptor: BuiltDisplayListDescriptor,
dl_data: *mut u8,
dl_size: usize,
aux_descriptor: AuxiliaryListsDescriptor,
aux_data: *mut u8,
aux_size: usize) {
let root_background_color = ColorF::new(0.3, 0.0, 0.0, 1.0);
// See the documentation of set_root_display_list in api.rs. I don't think
// it makes a difference in gecko at the moment(until APZ is figured out)
// but I suppose it is a good default.
let preserve_frame_state = true;
//let (dl_builder, aux_builder) = fb.dl_builder.finalize();
let dl_slice = slice::from_raw_parts(dl_data, dl_size);
let mut dl_vec = Vec::new();
// XXX: see if we can get rid of the copy here
dl_vec.extend_from_slice(dl_slice);
let dl = BuiltDisplayList::from_data(dl_vec, dl_descriptor);
let aux_slice = slice::from_raw_parts(aux_data, aux_size);
let mut aux_vec = Vec::new();
// XXX: see if we can get rid of the copy here
aux_vec.extend_from_slice(aux_slice);
let aux = AuxiliaryLists::from_data(aux_vec, aux_descriptor);
api.set_root_display_list(Some(root_background_color),
epoch,
LayoutSize::new(viewport_width, viewport_height),
frame_builder.dl_builder,
(pipeline_id, dl, aux),
preserve_frame_state);
api.generate_frame(None);
}
#[no_mangle]
pub extern fn wr_api_generate_frame(api: &mut RenderApi) {
api.generate_frame(None);
}
// Call MakeCurrent before this.
@ -169,7 +268,6 @@ pub unsafe extern fn wr_api_set_root_display_list(api: &mut RenderApi,
pub extern fn wr_window_new(window_id: WrWindowId,
gl_context: *mut c_void,
enable_profiler: bool,
external_image_handler: *mut WrExternalImageHandler,
out_api: &mut *mut RenderApi,
out_renderer: &mut *mut Renderer) -> bool {
assert!(unsafe { is_in_render_thread() });
@ -189,13 +287,14 @@ pub extern fn wr_window_new(window_id: WrWindowId,
println!("WebRender - OpenGL version new {}", version);
let opts = RendererOptions {
enable_aa: false,
enable_aa: true,
enable_subpixel_aa: true,
enable_profiler: enable_profiler,
recorder: recorder,
.. Default::default()
};
let (mut renderer, sender) = match Renderer::new(opts) {
let (renderer, sender) = match Renderer::new(opts) {
Ok((renderer, sender)) => { (renderer, sender) }
Err(e) => {
println!(" Failed to create a Renderer: {:?}", e);
@ -205,18 +304,6 @@ pub extern fn wr_window_new(window_id: WrWindowId,
renderer.set_render_notifier(Box::new(CppNotifier { window_id: window_id }));
if !external_image_handler.is_null() {
renderer.set_external_image_handler(Box::new(
unsafe {
WrExternalImageHandler {
external_image_obj: (*external_image_handler).external_image_obj,
lock_func: (*external_image_handler).lock_func,
unlock_func: (*external_image_handler).unlock_func,
release_func: (*external_image_handler).release_func,
}
}));
}
*out_api = Box::into_raw(Box::new(sender.create_api()));
*out_renderer = Box::into_raw(Box::new(renderer));
@ -224,11 +311,10 @@ pub extern fn wr_window_new(window_id: WrWindowId,
}
#[no_mangle]
pub extern fn wr_state_new(width: u32, height: u32, pipeline_id: PipelineId) -> *mut WrState {
assert!(unsafe { is_in_compositor_thread() });
pub extern fn wr_state_new(pipeline_id: PipelineId) -> *mut WrState {
assert!(unsafe { is_in_main_thread() });
let state = Box::new(WrState {
size: (width, height),
pipeline_id: pipeline_id,
z_index: 0,
frame_builder: WebRenderFrameBuilder::new(pipeline_id),
@ -239,7 +325,7 @@ pub extern fn wr_state_new(width: u32, height: u32, pipeline_id: PipelineId) ->
#[no_mangle]
pub extern fn wr_state_delete(state:*mut WrState) {
assert!(unsafe { is_in_compositor_thread() });
assert!(unsafe { is_in_main_thread() });
unsafe {
Box::from_raw(state);
@ -248,8 +334,7 @@ pub extern fn wr_state_delete(state:*mut WrState) {
#[no_mangle]
pub extern fn wr_dp_begin(state: &mut WrState, width: u32, height: u32) {
assert!( unsafe { is_in_compositor_thread() });
state.size = (width, height);
assert!( unsafe { is_in_main_thread() });
state.frame_builder.dl_builder.list.clear();
state.z_index = 0;
@ -268,23 +353,9 @@ pub extern fn wr_dp_begin(state: &mut WrState, width: u32, height: u32) {
}
#[no_mangle]
pub extern fn wr_dp_end(state: &mut WrState, api: &mut RenderApi, epoch: u32) {
assert!( unsafe { is_in_compositor_thread() });
let root_background_color = ColorF::new(0.3, 0.0, 0.0, 1.0);
let pipeline_id = state.pipeline_id;
let (width, height) = state.size;
pub extern fn wr_dp_end(state: &mut WrState) {
assert!( unsafe { is_in_main_thread() });
state.frame_builder.dl_builder.pop_stacking_context();
let fb = mem::replace(&mut state.frame_builder, WebRenderFrameBuilder::new(pipeline_id));
let preserve_frame_state = true;
api.set_root_display_list(Some(root_background_color),
Epoch(epoch),
LayoutSize::new(width as f32, height as f32),
fb.dl_builder,
preserve_frame_state);
api.generate_frame(None);
}
#[no_mangle]
@ -370,23 +441,21 @@ impl WebRenderFrameBuilder {
}
pub struct WrState {
size: (u32, u32),
pipeline_id: PipelineId,
z_index: i32,
frame_builder: WebRenderFrameBuilder,
}
#[repr(C)]
enum WrExternalImageType {
TEXTURE_HANDLE,
// TODO(Jerry): handle shmem or cpu raw buffers.
//// MEM_OR_SHMEM,
}
// TODO(Jerry): handle shmem or cpu raw buffers.
//#[repr(C)]
//enum WrExternalImageType {
// TextureHandle,
// MemOrShmem,
//}
#[repr(C)]
struct WrExternalImageStruct {
image_type: WrExternalImageType,
//image_type: WrExternalImageType,
// Texture coordinate
u0: f32,
@ -418,16 +487,17 @@ impl ExternalImageHandler for WrExternalImageHandler {
fn lock(&mut self, id: ExternalImageId) -> ExternalImage {
let image = (self.lock_func)(self.external_image_obj, id);
match image.image_type {
WrExternalImageType::TEXTURE_HANDLE =>
// TODO(Jerry): handle shmem or cpu raw buffers.
//match image.image_type {
// WrExternalImageType::TextureHandle =>
ExternalImage {
u0: image.u0,
v0: image.v0,
u1: image.u1,
v1: image.v1,
source: ExternalImageSource::NativeTexture(image.handle)
},
}
}
//}
}
fn unlock(&mut self, id: ExternalImageId) {
@ -529,11 +599,11 @@ impl WrGradientExtendMode
#[no_mangle]
pub extern fn wr_dp_push_stacking_context(state:&mut WrState, bounds: WrRect, overflow: WrRect, mask: *const WrImageMask, opacity: f32, transform: &LayoutTransform, mix_blend_mode: WrMixBlendMode)
{
assert!( unsafe { is_in_compositor_thread() });
assert!( unsafe { is_in_main_thread() });
state.z_index += 1;
let bounds = bounds.to_rect();
let mut overflow = overflow.to_rect();
let overflow = overflow.to_rect();
let mix_blend_mode = mix_blend_mode.to_mix_blend_mode();
//println!("stacking context: {:?} {:?} {:?} {:?} {:?}", state.pipeline_id, bounds, overflow, mask, transform);
// convert from the C type to the Rust type
@ -562,7 +632,7 @@ pub extern fn wr_dp_push_stacking_context(state:&mut WrState, bounds: WrRect, ov
#[no_mangle]
pub extern fn wr_dp_pop_stacking_context(state: &mut WrState)
{
assert!( unsafe { is_in_compositor_thread() });
assert!( unsafe { is_in_main_thread() });
state.frame_builder.dl_builder.pop_scroll_layer();
state.frame_builder.dl_builder.pop_stacking_context();
//println!("pop_stacking {:?}", state.pipeline_id);
@ -581,7 +651,7 @@ pub extern fn wr_dp_push_scroll_layer(state: &mut WrState, bounds: WrRect, overf
#[no_mangle]
pub extern fn wr_dp_pop_scroll_layer(state: &mut WrState)
{
assert!( unsafe { is_in_compositor_thread() });
assert!( unsafe { is_in_main_thread() });
state.frame_builder.dl_builder.pop_scroll_layer();
}
@ -592,29 +662,41 @@ pub extern fn wr_api_set_root_pipeline(api: &mut RenderApi, pipeline_id: Pipelin
}
#[no_mangle]
pub extern fn wr_api_add_image(api: &mut RenderApi, descriptor: &WrImageDescriptor, bytes: * const u8, size: usize) -> ImageKey {
assert!( unsafe { is_in_compositor_thread() });
let bytes = unsafe { slice::from_raw_parts(bytes, size).to_owned() };
let image_key = api.generate_image_key();
api.add_image(
image_key,
ImageDescriptor {
width: descriptor.width,
height: descriptor.height,
stride: if descriptor.stride != 0 { Some(descriptor.stride) } else { None },
format: descriptor.format,
is_opaque: descriptor.is_opaque,
},
ImageData::new(bytes)
);
image_key
pub extern fn wr_api_generate_image_key(api: &mut RenderApi) -> ImageKey
{
api.generate_image_key()
}
#[no_mangle]
pub extern fn wr_api_add_external_image_texture(api: &mut RenderApi, width: u32, height: u32, format: ImageFormat, external_image_id: u64) -> ImageKey {
pub extern fn wr_api_add_image(api: &mut RenderApi, image_key: ImageKey, descriptor: &WrImageDescriptor, bytes: * const u8, size: usize) {
assert!( unsafe { is_in_compositor_thread() });
unimplemented!(); // TODO
//api.add_image(ImageDescriptor{width:width, height:height, stride:None, format: format, is_opaque: false}, ImageData::External(ExternalImageId(external_image_id)))
let bytes = unsafe { slice::from_raw_parts(bytes, size).to_owned() };
api.add_image(
image_key,
descriptor.to_descriptor(),
ImageData::new(bytes),
None
);
}
#[no_mangle]
pub extern fn wr_api_add_external_image_handle(api: &mut RenderApi, image_key: ImageKey, width: u32, height: u32, format: ImageFormat, external_image_id: u64) {
assert!( unsafe { is_in_compositor_thread() });
api.add_image(image_key,
ImageDescriptor{width:width, height:height, stride:None, format: format, is_opaque: false, offset: 0},
ImageData::ExternalHandle(ExternalImageId(external_image_id)),
None
);
}
#[no_mangle]
pub extern fn wr_api_add_external_image_buffer(api: &mut RenderApi, image_key: ImageKey, width: u32, height: u32, format: ImageFormat, external_image_id: u64) {
assert!( unsafe { is_in_compositor_thread() });
api.add_image(image_key,
ImageDescriptor{width:width, height:height, stride:None, format: format, is_opaque: false, offset: 0},
ImageData::ExternalBuffer(ExternalImageId(external_image_id)),
None
);
}
#[no_mangle]
@ -624,13 +706,7 @@ pub extern fn wr_api_update_image(api: &mut RenderApi, key: ImageKey, descriptor
api.update_image(
key,
ImageDescriptor {
width: descriptor.width,
height: descriptor.height,
stride: if descriptor.stride != 0 { Some(descriptor.stride) } else { None },
format: descriptor.format,
is_opaque: descriptor.is_opaque,
},
descriptor.to_descriptor(),
bytes
);
}
@ -650,7 +726,7 @@ pub extern fn wr_api_send_external_event(api: &mut RenderApi, evt: usize) {
#[no_mangle]
pub extern fn wr_dp_push_rect(state: &mut WrState, rect: WrRect, clip: WrRect, color: WrColor) {
assert!( unsafe { is_in_compositor_thread() });
assert!( unsafe { is_in_main_thread() });
let clip_region = state.frame_builder.dl_builder.new_clip_region(&clip.to_rect(), Vec::new(), None);
state.frame_builder.dl_builder.push_rect(
@ -664,7 +740,7 @@ pub extern fn wr_dp_push_box_shadow(state: &mut WrState, rect: WrRect, clip: WrR
box_bounds: WrRect, offset: WrPoint, color: WrColor,
blur_radius: f32, spread_radius: f32, border_radius: f32,
clip_mode: WrBoxShadowClipMode) {
assert!( unsafe { is_in_compositor_thread() });
assert!( unsafe { is_in_main_thread() });
let clip_region = state.frame_builder.dl_builder.new_clip_region(&clip.to_rect(), Vec::new(), None);
state.frame_builder.dl_builder.push_box_shadow(rect.to_rect(),
clip_region,
@ -681,7 +757,7 @@ pub extern fn wr_dp_push_box_shadow(state: &mut WrState, rect: WrRect, clip: WrR
pub extern fn wr_dp_push_border(state: &mut WrState, rect: WrRect, clip: WrRect,
top: WrBorderSide, right: WrBorderSide, bottom: WrBorderSide, left: WrBorderSide,
radius: WrBorderRadius) {
assert!( unsafe { is_in_compositor_thread() });
assert!( unsafe { is_in_main_thread() });
let clip_region = state.frame_builder.dl_builder.new_clip_region(&clip.to_rect(), Vec::new(), None);
let border_widths = BorderWidths {
left: left.width,
@ -708,7 +784,7 @@ pub extern fn wr_dp_push_linear_gradient(state: &mut WrState, rect: WrRect, clip
start_point: WrPoint, end_point: WrPoint,
stops: * const WrGradientStop, stops_count: usize,
extend_mode: WrGradientExtendMode) {
assert!( unsafe { is_in_compositor_thread() });
assert!( unsafe { is_in_main_thread() });
let stops = WrGradientStop::to_gradient_stops(unsafe { slice::from_raw_parts(stops, stops_count) });
let clip_region = state.frame_builder.dl_builder.new_clip_region(&clip.to_rect(), Vec::new(), None);
@ -729,7 +805,7 @@ pub extern fn wr_dp_push_radial_gradient(state: &mut WrState, rect: WrRect, clip
start_radius: f32, end_radius: f32,
stops: * const WrGradientStop, stops_count: usize,
extend_mode: WrGradientExtendMode) {
assert!( unsafe { is_in_compositor_thread() });
assert!( unsafe { is_in_main_thread() });
let stops = WrGradientStop::to_gradient_stops(unsafe { slice::from_raw_parts(stops, stops_count) });
let clip_region = state.frame_builder.dl_builder.new_clip_region(&clip.to_rect(), Vec::new(), None);
@ -748,7 +824,7 @@ pub extern fn wr_dp_push_radial_gradient(state: &mut WrState, rect: WrRect, clip
#[no_mangle]
pub extern fn wr_dp_push_iframe(state: &mut WrState, rect: WrRect, clip: WrRect, pipeline_id: PipelineId) {
assert!( unsafe { is_in_compositor_thread() });
assert!( unsafe { is_in_main_thread() });
let clip_region = state.frame_builder.dl_builder.new_clip_region(&clip.to_rect(),
Vec::new(),
@ -898,7 +974,7 @@ impl WrImageMask
#[no_mangle]
pub extern fn wr_dp_push_image(state:&mut WrState, bounds: WrRect, clip : WrRect, mask: *const WrImageMask, filter: ImageRendering, key: ImageKey) {
assert!( unsafe { is_in_compositor_thread() });
assert!( unsafe { is_in_main_thread() });
let bounds = bounds.to_rect();
let clip = clip.to_rect();
@ -918,11 +994,17 @@ pub extern fn wr_dp_push_image(state:&mut WrState, bounds: WrRect, clip : WrRect
key
);
}
#[no_mangle]
pub extern fn wr_api_generate_font_key(api: &mut RenderApi) -> FontKey
{
api.generate_font_key()
}
#[no_mangle]
pub extern fn wr_api_add_raw_font(api: &mut RenderApi,
key: FontKey,
font_buffer: *mut u8,
buffer_size: usize) -> FontKey
buffer_size: usize)
{
assert!( unsafe { is_in_compositor_thread() });
@ -932,11 +1014,10 @@ pub extern fn wr_api_add_raw_font(api: &mut RenderApi,
let mut font_vector = Vec::new();
font_vector.extend_from_slice(font_slice);
let font_key = api.generate_font_key();
api.add_raw_font(font_key, font_vector);
font_key
api.add_raw_font(key, font_vector);
}
#[no_mangle]
pub extern fn wr_dp_push_text(state: &mut WrState,
bounds: WrRect,
@ -947,7 +1028,7 @@ pub extern fn wr_dp_push_text(state: &mut WrState,
glyph_count: u32,
glyph_size: f32)
{
assert!( unsafe { is_in_compositor_thread() });
assert!( unsafe { is_in_main_thread() });
let glyph_slice = unsafe {
slice::from_raw_parts(glyphs, glyph_count as usize)

View file

@ -2,20 +2,13 @@
* 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/. */
#![deny(warnings)]
extern crate webrender;
extern crate webrender_traits;
extern crate euclid;
extern crate app_units;
extern crate gleam;
extern crate fnv;
#[cfg(target_os="macos")]
extern crate core_foundation;
#[cfg(target_os="windows")]
extern crate kernel32;
#[cfg(target_os="windows")]
extern crate winapi;
#[allow(non_snake_case)]
pub mod bindings;

View file

@ -7,9 +7,9 @@
#ifndef WR_h
#define WR_h
#include "mozilla/layers/LayersMessages.h"
#include "mozilla/gfx/Types.h"
#include "nsTArray.h"
#include "mozilla/gfx/Point.h"
// ---
#define WR_DECL_FFI_1(WrType, t1) \
struct WrType { \
@ -49,6 +49,7 @@ extern "C" {
// serialization code in WebRenderMessageUtils.h and the rust bindings.
WR_DECL_FFI_1(WrEpoch, uint32_t)
WR_DECL_FFI_1(WrIdNamespace, uint32_t)
WR_DECL_FFI_1(WrWindowId, uint64_t)
WR_DECL_FFI_2(WrPipelineId, uint32_t, uint32_t)
@ -63,6 +64,7 @@ WR_DECL_FFI_2(WrFontKey, uint32_t, uint32_t)
// ----
bool is_in_compositor_thread();
bool is_in_main_thread();
bool is_in_render_thread();
void* get_proc_address_from_glcontext(void* glcontext_ptr, const char* procname);
@ -113,12 +115,14 @@ enum class WrImageRendering: uint32_t
Sentinel /* this must be last, for IPC serialization purposes */
};
enum class WrExternalImageIdType
{
TEXTURE_HANDLE, // Currently, we only support gl texture handle.
// TODO(Jerry): handle shmem or cpu raw buffers.
//// MEM_OR_SHMEM,
};
// TODO(Jerry): handle shmem or cpu raw buffers.
//enum class WrExternalImageIdType: uint32_t
//{
// TextureHandle = 0,
// MemOrShmem = 1,
//
// Sentinel /* this must be last, for IPC serialization purposes */
//};
enum class WrMixBlendMode: uint32_t
{
@ -298,14 +302,14 @@ struct WrImageMask
}
};
struct WrExternalImageIdId
struct WrExternalImageId
{
WrImageIdType id;
};
struct WrExternalImageId
struct WrExternalImage
{
WrExternalImageIdType type;
//WrExternalImageIdType type;
// Texture coordinate
float u0, v0;
@ -320,13 +324,13 @@ struct WrExternalImageId
//// size_t size;
};
typedef WrExternalImageId (*LockExternalImageCallback)(void*, WrExternalImageIdId);
typedef void (*UnlockExternalImageCallback)(void*, WrExternalImageIdId);
typedef void (*ReleaseExternalImageCallback)(void*, WrExternalImageIdId);
typedef WrExternalImage (*LockExternalImageCallback)(void*, WrExternalImageId);
typedef void (*UnlockExternalImageCallback)(void*, WrExternalImageId);
typedef void (*ReleaseExternalImageCallback)(void*, WrExternalImageId);
struct WrExternalImageIdHandler
struct WrExternalImageHandler
{
void* ExternalImageObj;
void* renderer_obj;
LockExternalImageCallback lock_func;
UnlockExternalImageCallback unlock_func;
ReleaseExternalImageCallback release_func;
@ -340,6 +344,23 @@ struct WrImageDescriptor {
bool is_opaque;
};
struct WrBuiltDisplayListDescriptor {
size_t display_list_items_size;
};
struct WrAuxiliaryListsDescriptor {
size_t gradient_stops_size;
size_t complex_clip_regions_size;
size_t filters_size;
size_t glyph_instances_size;
};
struct WrVecU8 {
uint8_t *data;
size_t length;
size_t capacity;
};
// -----
// Functions exposed by the webrender API
// -----
@ -367,6 +388,11 @@ struct WrRenderer;
struct WrState;
struct WrAPI;
WR_INLINE void
wr_renderer_set_external_image_handler(WrRenderer* renderer,
WrExternalImageHandler* handler)
WR_FUNC;
WR_INLINE void
wr_renderer_update(WrRenderer* renderer)
WR_FUNC;
@ -403,7 +429,6 @@ WR_INLINE bool
wr_window_new(WrWindowId window_id,
void* aGLContext,
bool enable_profiler,
WrExternalImageIdHandler* handler,
WrAPI** out_api,
WrRenderer** out_renderer)
WR_FUNC;
@ -412,20 +437,19 @@ WR_INLINE void
wr_api_delete(WrAPI* api)
WR_DESTRUCTOR_SAFE_FUNC;
WR_INLINE WrImageKey
wr_api_add_image(WrAPI* api, const WrImageDescriptor* descriptor, uint8_t *buffer, size_t buffer_size)
WR_INLINE void
wr_api_add_image(WrAPI* api, WrImageKey key, const WrImageDescriptor* descriptor, uint8_t *buffer, size_t buffer_size)
WR_FUNC;
WR_INLINE WrImageKey
wr_api_add_external_image_texture(WrAPI* api, uint32_t width, uint32_t height,
WrImageFormat format, uint64_t external_image_id)
WR_INLINE void
wr_api_add_external_image_handle(WrAPI* api, WrImageKey key, uint32_t width, uint32_t height,
WrImageFormat format, uint64_t external_image_id)
WR_FUNC;
//TODO(Jerry): handle shmem in WR
//// WR_INLINE WrImageKey
//// wr_api_add_external_image_buffer(WrAPI* api, uint32_t width, uint32_t height, uint32_t stride,
//// WrImageFormat format, uint8_t *bytes, size_t size)
//// WR_FUNC;
WR_INLINE void
wr_api_add_external_image_buffer(WrAPI* api, WrImageKey key, uint32_t width, uint32_t height,
WrImageFormat format, uint64_t external_image_id)
WR_FUNC;
WR_INLINE void
wr_api_update_image(WrAPI* api, WrImageKey key,
@ -442,19 +466,30 @@ wr_api_set_root_pipeline(WrAPI* api, WrPipelineId pipeline_id)
WR_FUNC;
WR_INLINE void
wr_api_set_root_display_list(WrAPI* api, WrState* state, WrEpoch epoch, float w, float h)
wr_api_set_root_display_list(WrAPI* api, WrEpoch epoch, float w, float h,
WrPipelineId pipeline_id,
WrBuiltDisplayListDescriptor dl_descriptor,
uint8_t *dl_data,
size_t dl_size,
WrAuxiliaryListsDescriptor aux_descriptor,
uint8_t *aux_data,
size_t aux_size)
WR_FUNC;
WR_INLINE void
wr_api_generate_frame(WrAPI* api)
WR_FUNC;
WR_INLINE void
wr_api_send_external_event(WrAPI* api, uintptr_t evt)
WR_DESTRUCTOR_SAFE_FUNC;
WR_INLINE WrFontKey
wr_api_add_raw_font(WrAPI* api, uint8_t* font_buffer, size_t buffer_size)
WR_INLINE void
wr_api_add_raw_font(WrAPI* api, WrFontKey key, uint8_t* font_buffer, size_t buffer_size)
WR_FUNC;
WR_INLINE WrState*
wr_state_new(uint32_t width, uint32_t height, WrPipelineId pipeline_id)
wr_state_new(WrPipelineId pipeline_id)
WR_FUNC;
WR_INLINE void
@ -488,7 +523,7 @@ wr_dp_begin(WrState* wrState, uint32_t width, uint32_t height)
WR_FUNC;
WR_INLINE void
wr_dp_end(WrState* builder, WrAPI* api, WrEpoch epoch)
wr_dp_end(WrState* wrState)
WR_FUNC;
WR_INLINE void
@ -546,6 +581,22 @@ wr_dp_push_box_shadow(WrState* wrState, WrRect rect, WrRect clip,
WrBoxShadowClipMode clip_mode)
WR_FUNC;
WR_INLINE WrIdNamespace
wr_api_get_namespace(WrAPI* api)
WR_FUNC;
WR_INLINE void
wr_api_finalize_builder(WrState* wrState,
WrBuiltDisplayListDescriptor& dl_descriptor,
WrVecU8& dl_data,
WrAuxiliaryListsDescriptor& aux_descriptor,
WrVecU8& aux_data)
WR_FUNC;
WR_INLINE void
wr_vec_u8_free(WrVecU8 dl_data)
WR_FUNC;
#undef WR_FUNC
#undef WR_DESTRUCTOR_SAFE_FUNC
} // extern "C"

View file

@ -1,6 +1,6 @@
[package]
name = "webrender_traits"
version = "0.19.0"
version = "0.20.0"
authors = ["Glenn Watson <gw@intuitionlibrary.com>"]
license = "MPL-2.0"
repository = "https://github.com/servo/webrender"

View file

@ -9,8 +9,9 @@ use std::cell::Cell;
use {ApiMsg, ColorF, DisplayListBuilder, Epoch, ImageDescriptor};
use {FontKey, IdNamespace, ImageKey, NativeFontHandle, PipelineId};
use {RenderApiSender, ResourceId, ScrollEventPhase, ScrollLayerState, ScrollLocation, ServoScrollRootId};
use {GlyphKey, GlyphDimensions, ImageData, WebGLContextId, WebGLCommand};
use {GlyphKey, GlyphDimensions, ImageData, WebGLContextId, WebGLCommand, TileSize};
use {DeviceIntSize, DynamicProperties, LayoutPoint, LayoutSize, WorldPoint, PropertyBindingKey, PropertyBindingId};
use {BuiltDisplayList, AuxiliaryLists};
use VRCompositorCommand;
use ExternalEvent;
use std::marker::PhantomData;
@ -92,8 +93,9 @@ impl RenderApi {
pub fn add_image(&self,
key: ImageKey,
descriptor: ImageDescriptor,
data: ImageData) {
let msg = ApiMsg::AddImage(key, descriptor, data);
data: ImageData,
tiling: Option<TileSize>) {
let msg = ApiMsg::AddImage(key, descriptor, data, tiling);
self.api_sender.send(msg).unwrap();
}
@ -156,10 +158,8 @@ impl RenderApi {
background_color: Option<ColorF>,
epoch: Epoch,
viewport_size: LayoutSize,
builder: DisplayListBuilder,
(pipeline_id, display_list, auxiliary_lists): (PipelineId, BuiltDisplayList, AuxiliaryLists),
preserve_frame_state: bool) {
let pipeline_id = builder.pipeline_id;
let (display_list, auxiliary_lists) = builder.finalize();
let msg = ApiMsg::SetRootDisplayList(background_color,
epoch,
pipeline_id,

View file

@ -8,7 +8,7 @@ use std::slice;
use {AuxiliaryLists, AuxiliaryListsDescriptor, BorderDisplayItem};
use {BoxShadowClipMode, BoxShadowDisplayItem, BuiltDisplayList};
use {BuiltDisplayListDescriptor, ClipRegion, ComplexClipRegion, ColorF};
use {DisplayItem, DisplayListMode, ExtendMode, FilterOp, YuvColorSpace};
use {DisplayItem, ExtendMode, FilterOp, YuvColorSpace};
use {FontKey, GlyphInstance, GradientDisplayItem, RadialGradientDisplayItem, GradientStop, IframeDisplayItem};
use {ImageDisplayItem, ImageKey, ImageMask, ImageRendering, ItemRange, MixBlendMode, PipelineId};
use {PushScrollLayerItem, PushStackingContextDisplayItem, RectangleDisplayItem, ScrollLayerId};
@ -19,7 +19,7 @@ use {BorderDetails, BorderWidths, GlyphOptions, PropertyBinding};
impl BuiltDisplayListDescriptor {
pub fn size(&self) -> usize {
self.display_list_items_size + self.display_items_size
self.display_list_items_size
}
}
@ -48,7 +48,6 @@ impl BuiltDisplayList {
#[derive(Clone)]
pub struct DisplayListBuilder {
pub mode: DisplayListMode,
pub list: Vec<DisplayItem>,
auxiliary_lists_builder: AuxiliaryListsBuilder,
pub pipeline_id: PipelineId,
@ -58,7 +57,6 @@ pub struct DisplayListBuilder {
impl DisplayListBuilder {
pub fn new(pipeline_id: PipelineId) -> DisplayListBuilder {
DisplayListBuilder {
mode: DisplayListMode::Default,
list: Vec::new(),
auxiliary_lists_builder: AuxiliaryListsBuilder::new(),
pipeline_id: pipeline_id,
@ -365,16 +363,15 @@ impl DisplayListBuilder {
ClipRegion::new(rect, complex, image_mask, &mut self.auxiliary_lists_builder)
}
pub fn finalize(self) -> (BuiltDisplayList, AuxiliaryLists) {
pub fn finalize(self) -> (PipelineId, BuiltDisplayList, AuxiliaryLists) {
unsafe {
let blob = convert_pod_to_blob(&self.list).to_vec();
let display_list_items_size = blob.len();
(BuiltDisplayList {
(self.pipeline_id,
BuiltDisplayList {
descriptor: BuiltDisplayListDescriptor {
mode: self.mode,
display_list_items_size: display_list_items_size,
display_items_size: 0,
},
data: blob,
},

View file

@ -24,6 +24,8 @@ pub enum RendererKind {
OSMesa,
}
pub type TileSize = u16;
#[derive(Clone, Deserialize, Serialize)]
pub enum ApiMsg {
AddRawFont(FontKey, Vec<u8>),
@ -31,7 +33,7 @@ pub enum ApiMsg {
/// Gets the glyph dimensions
GetGlyphDimensions(Vec<GlyphKey>, MsgSender<Vec<Option<GlyphDimensions>>>),
/// Adds an image from the resource cache.
AddImage(ImageKey, ImageDescriptor, ImageData),
AddImage(ImageKey, ImageDescriptor, ImageData, Option<TileSize>),
/// Updates the the resource cache with the new image data.
UpdateImage(ImageKey, ImageDescriptor, Vec<u8>),
/// Drops an image from the resource cache.
@ -166,6 +168,7 @@ pub struct AuxiliaryLists {
///
/// Auxiliary lists consist of some number of gradient stops, complex clip regions, filters, and
/// glyph instances, in that order.
#[repr(C)]
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
pub struct AuxiliaryListsDescriptor {
gradient_stops_size: usize,
@ -287,14 +290,11 @@ pub struct BuiltDisplayList {
///
/// A display list consists of some number of display list items, followed by a number of display
/// items.
#[repr(C)]
#[derive(Copy, Clone, Deserialize, Serialize)]
pub struct BuiltDisplayListDescriptor {
pub mode: DisplayListMode,
/// The size in bytes of the display list items in this display list.
display_list_items_size: usize,
/// The size in bytes of the display items in this display list.
display_items_size: usize,
}
#[repr(C)]
@ -363,9 +363,27 @@ pub struct ImageDescriptor {
pub width: u32,
pub height: u32,
pub stride: Option<u32>,
pub offset: u32,
pub is_opaque: bool,
}
impl ImageDescriptor {
pub fn new(width: u32, height: u32, format: ImageFormat, is_opaque: bool) -> Self {
ImageDescriptor {
width: width,
height: height,
format: format,
stride: None,
offset: 0,
is_opaque: is_opaque,
}
}
pub fn compute_stride(&self) -> u32 {
self.stride.unwrap_or(self.width * self.format.bytes_per_pixel().unwrap())
}
}
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
pub struct ImageMask {
pub image: ImageKey,
@ -395,14 +413,6 @@ pub struct DisplayItem {
pub clip: ClipRegion,
}
#[repr(u32)]
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
pub enum DisplayListMode {
Default = 0,
PseudoFloat = 1,
PseudoPositionedContent = 2,
}
#[repr(C)]
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
pub struct Epoch(pub u32);

View file

@ -73,6 +73,10 @@ pub type WorldPoint = TypedPoint2D<f32, WorldPixel>;
pub type WorldSize = TypedSize2D<f32, WorldPixel>;
pub type WorldPoint4D = TypedPoint4D<f32, WorldPixel>;
/// Offset in number of tiles.
#[derive(Hash, Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
pub struct Tiles;
pub type TileOffset = TypedPoint2D<u16, Tiles>;
pub type LayoutTransform = TypedMatrix4D<f32, LayoutPixel, LayoutPixel>;
pub type LayerTransform = TypedMatrix4D<f32, LayerPixel, LayerPixel>;

View file

@ -2570,20 +2570,25 @@ GCMarker::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const
#ifdef DEBUG
Zone*
GCMarker::stackContainsCrossZonePointerTo(const TenuredCell* target) const
GCMarker::stackContainsCrossZonePointerTo(const Cell* target) const
{
MOZ_ASSERT(!JS::CurrentThreadIsHeapCollecting());
Zone* targetZone = target->asTenured().zone();
for (MarkStackIter iter(stack); !iter.done(); iter.next()) {
if (iter.peekTag() != MarkStack::ObjectTag)
continue;
auto source = iter.peekPtr().as<JSObject>();
if (source->is<ProxyObject>() &&
source->as<ProxyObject>().target() == static_cast<const Cell*>(target) &&
source->zone() != target->zone())
Zone* sourceZone = source->zone();
if (sourceZone == targetZone)
continue;
if ((source->is<ProxyObject>() && source->as<ProxyObject>().target() == target) ||
Debugger::isDebuggerCrossCompartmentEdge(source, target))
{
return source->zone();
return sourceZone;
}
}

View file

@ -304,7 +304,7 @@ class GCMarker : public JSTracer
bool shouldCheckCompartments() { return strictCompartmentChecking; }
Zone* stackContainsCrossZonePointerTo(const gc::TenuredCell* cell) const;
Zone* stackContainsCrossZonePointerTo(const gc::Cell* cell) const;
#endif

View file

@ -89,6 +89,13 @@ function testTrap(resultType, opcode, paramType, op, expect) {
testConversion('f32', 'convert_s', 'i64', "0x80000000", 2147483648.0);
testConversion('f32', 'convert_s', 'i64', "0x80000001", 2147483648.0); // closesth approx.
// Interesting values at the boundaries.
testConversion('f32', 'convert_s', 'i64', "0x358a09a000000002", 3857906751034621952);
testConversion('f32', 'convert_s', 'i64', "0x8000004000000001", -9223371487098961920);
testConversion('f32', 'convert_s', 'i64', "0xffdfffffdfffffff", -9007200328482816);
testConversion('f32', 'convert_s', 'i64', "0x0020000020000001", 9007200328482816);
testConversion('f32', 'convert_s', 'i64', "0x7fffff4000000001", 9223371487098961920);
testConversion('f64', 'convert_s', 'i64', 1, 1.0);
testConversion('f64', 'convert_s', 'i64', -1, -1.0);
testConversion('f64', 'convert_s', 'i64', 0, 0.0);
@ -106,12 +113,24 @@ function testTrap(resultType, opcode, paramType, op, expect) {
testConversion('f32', 'convert_u', 'i64', -1, 18446744073709551616.0);
testConversion('f32', 'convert_u', 'i64', "0xffff0000ffff0000", 18446462598732840000.0);
// Interesting values at the boundaries.
testConversion('f32', 'convert_u', 'i64', "0x100404900000008", 72128280609685500);
testConversion('f32', 'convert_u', 'i64', "0x7fffff4000000001", 9223371487098962000);
testConversion('f32', 'convert_u', 'i64', "0x0020000020000001", 9007200328482816);
testConversion('f32', 'convert_u', 'i64', "0x7fffffbfffffffff", 9223371487098961920);
testConversion('f32', 'convert_u', 'i64', "0x8000008000000001", 9223373136366403584);
testConversion('f32', 'convert_u', 'i64', "0xfffffe8000000001", 18446742974197923840);
testConversion('f64', 'convert_u', 'i64', 1, 1.0);
testConversion('f64', 'convert_u', 'i64', 0, 0.0);
testConversion('f64', 'convert_u', 'i64', "0x7fffffffffffffff", 9223372036854775807.0);
testConversion('f64', 'convert_u', 'i64', "0x8000000000000000", 9223372036854775808.0);
testConversion('f64', 'convert_u', 'i64', -1, 18446744073709551616.0);
testConversion('f64', 'convert_u', 'i64', "0xffff0000ffff0000", 18446462603027743000.0);
testConversion('f64', 'convert_u', 'i64', "0xbf869c3369c26401", 13800889852755077000);
testConversion('f64', 'convert_u', 'i64', "0x7fffff4000000001", 9223371212221054976);
testConversion('f64', 'convert_u', 'i64', "0x8000008000000001", 9223372586610589696);
testConversion('f64', 'convert_u', 'i64', "0xfffffe8000000001", 18446742424442109952);
testConversion('i64', 'trunc_s', 'f64', 0.0, 0);
testConversion('i64', 'trunc_s', 'f64', "-0.0", 0);

View file

@ -806,6 +806,11 @@ enum ABIFunctionType
// float f(float)
Args_Float32_Float32 = (ArgType_Float32 << RetType_Shift) | (ArgType_Float32 << ArgType_Shift),
// float f(int, int)
Args_Float32_IntInt = (ArgType_Float32 << RetType_Shift) |
(ArgType_General << (ArgType_Shift * 1)) |
(ArgType_General << (ArgType_Shift * 2)),
// double f(double)
Args_Double_Double = Args_Double_None | (ArgType_Double << ArgType_Shift),

View file

@ -1557,13 +1557,10 @@ DoCompareFallback(JSContext* cx, void* payload, ICCompare_Fallback* stub_, Handl
return true;
}
if ((lhs.isObject() || lhs.isNull() || lhs.isUndefined()) &&
(rhs.isObject() || rhs.isNull() || rhs.isUndefined()) &&
!stub->hasStub(ICStub::Compare_ObjectWithUndefined))
{
JitSpew(JitSpew_BaselineIC, " Generating %s(Obj/Null/Undef, Obj/Null/Undef) stub",
if (lhs.isNullOrUndefined() || rhs.isNullOrUndefined()) {
JitSpew(JitSpew_BaselineIC, " Generating %s(Null/Undef or X, Null/Undef or X) stub",
CodeName[op]);
bool lhsIsUndefined = lhs.isNull() || lhs.isUndefined();
bool lhsIsUndefined = lhs.isNullOrUndefined();
bool compareWithNull = lhs.isNull() || rhs.isNull();
ICCompare_ObjectWithUndefined::Compiler compiler(cx, op, engine,
lhsIsUndefined, compareWithNull);
@ -1810,14 +1807,31 @@ ICCompare_ObjectWithUndefined::Compiler::generateStubCode(MacroAssembler& masm)
masm.bind(&notObject);
// Also support null == null or undefined == undefined comparisons.
Label differentTypes;
if (compareWithNull)
masm.branchTestNull(Assembler::NotEqual, objectOperand, &failure);
masm.branchTestNull(Assembler::NotEqual, objectOperand, &differentTypes);
else
masm.branchTestUndefined(Assembler::NotEqual, objectOperand, &failure);
masm.branchTestUndefined(Assembler::NotEqual, objectOperand, &differentTypes);
masm.moveValue(BooleanValue(op == JSOP_STRICTEQ || op == JSOP_EQ), R0);
EmitReturnFromIC(masm);
masm.bind(&differentTypes);
// Also support null == undefined or undefined == null.
Label neverEqual;
if (compareWithNull)
masm.branchTestUndefined(Assembler::NotEqual, objectOperand, &neverEqual);
else
masm.branchTestNull(Assembler::NotEqual, objectOperand, &neverEqual);
masm.moveValue(BooleanValue(op == JSOP_EQ || op == JSOP_STRICTNE), R0);
EmitReturnFromIC(masm);
// null/undefined can only be equal to null/undefined or emulatesUndefined.
masm.bind(&neverEqual);
masm.moveValue(BooleanValue(op == JSOP_NE || op == JSOP_STRICTNE), R0);
EmitReturnFromIC(masm);
// Failure case - jump to next stub
masm.bind(&failure);
EmitStubGuardFailure(masm);

View file

@ -3026,7 +3026,6 @@ void
CodeGeneratorARM::visitInt64ToFloatingPointCall(LInt64ToFloatingPointCall* lir)
{
Register64 input = ToRegister64(lir->getInt64Operand(0));
FloatRegister output = ToFloatRegister(lir->output());
MInt64ToFloatingPoint* mir = lir->mir();
MIRType toType = mir->type();
@ -3040,16 +3039,19 @@ CodeGeneratorARM::visitInt64ToFloatingPointCall(LInt64ToFloatingPointCall* lir)
masm.setupUnalignedABICall(temp);
masm.passABIArg(input.high);
masm.passABIArg(input.low);
if (lir->mir()->isUnsigned())
masm.callWithABI(wasm::SymbolicAddress::Uint64ToFloatingPoint, MoveOp::DOUBLE);
else
masm.callWithABI(wasm::SymbolicAddress::Int64ToFloatingPoint, MoveOp::DOUBLE);
MOZ_ASSERT_IF(toType == MIRType::Double, output == ReturnDoubleReg);
if (toType == MIRType::Float32) {
MOZ_ASSERT(output == ReturnFloat32Reg);
masm.convertDoubleToFloat32(ReturnDoubleReg, output);
}
bool isUnsigned = mir->isUnsigned();
wasm::SymbolicAddress callee = toType == MIRType::Float32
? (isUnsigned ? wasm::SymbolicAddress::Uint64ToFloat32
: wasm::SymbolicAddress::Int64ToFloat32)
: (isUnsigned ? wasm::SymbolicAddress::Uint64ToDouble
: wasm::SymbolicAddress::Int64ToDouble);
masm.callWithABI(callee, toType == MIRType::Float32 ? MoveOp::FLOAT32 : MoveOp::DOUBLE);
DebugOnly<FloatRegister> output(ToFloatRegister(lir->output()));
MOZ_ASSERT_IF(toType == MIRType::Double, output.value == ReturnDoubleReg);
MOZ_ASSERT_IF(toType == MIRType::Float32, output.value == ReturnFloat32Reg);
}
void

View file

@ -2438,6 +2438,7 @@ typedef int32_t (*Prototype_Int_DoubleIntInt)(double arg0, int32_t arg1, int32_t
typedef int32_t (*Prototype_Int_IntDoubleIntInt)(int32_t arg0, double arg1, int32_t arg2,
int32_t arg3);
typedef float (*Prototype_Float32_Float32)(float arg0);
typedef float (*Prototype_Float32_IntInt)(int arg0, int arg1);
typedef double (*Prototype_DoubleInt)(double arg0, int32_t arg1);
typedef double (*Prototype_Double_IntDouble)(int32_t arg0, double arg1);
@ -2625,6 +2626,13 @@ Simulator::softwareInterrupt(SimInstruction* instr)
setCallResultFloat(fresult);
break;
}
case Args_Float32_IntInt: {
Prototype_Float32_IntInt target = reinterpret_cast<Prototype_Float32_IntInt>(external);
float fresult = target(arg0, arg1);
scratchVolatileRegisters(/* scratchFloat = true */);
setCallResultFloat(fresult);
break;
}
case Args_Double_Int: {
Prototype_Double_Int target = reinterpret_cast<Prototype_Double_Int>(external);
double dresult = target(arg0);

View file

@ -739,17 +739,21 @@ CodeGeneratorX64::visitInt64ToFloatingPoint(LInt64ToFloatingPoint* lir)
Register64 input = ToRegister64(lir->getInt64Operand(0));
FloatRegister output = ToFloatRegister(lir->output());
MIRType outputType = lir->mir()->type();
MInt64ToFloatingPoint* mir = lir->mir();
bool isUnsigned = mir->isUnsigned();
MIRType outputType = mir->type();
MOZ_ASSERT(outputType == MIRType::Double || outputType == MIRType::Float32);
MOZ_ASSERT(isUnsigned == !lir->getTemp(0)->isBogusTemp());
if (outputType == MIRType::Double) {
if (lir->mir()->isUnsigned())
masm.convertUInt64ToDouble(input, output, Register::Invalid());
if (isUnsigned)
masm.convertUInt64ToDouble(input, output, ToRegister(lir->getTemp(0)));
else
masm.convertInt64ToDouble(input, output);
} else {
if (lir->mir()->isUnsigned())
masm.convertUInt64ToFloat32(input, output, Register::Invalid());
if (isUnsigned)
masm.convertUInt64ToFloat32(input, output, ToRegister(lir->getTemp(0)));
else
masm.convertInt64ToFloat32(input, output);
}

Some files were not shown because too many files have changed in this diff Show more