forked from mirrors/gecko-dev
Merge m-c to autoland, a=merge
MozReview-Commit-ID: K0Q4b2wzvlJ
This commit is contained in:
commit
1b29a33fce
306 changed files with 3040 additions and 4257 deletions
|
|
@ -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");
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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 });
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
||||
|
|
|
|||
|
|
@ -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 = {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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))) {
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ dictionary FilePropertyBag {
|
|||
|
||||
dictionary ChromeFilePropertyBag : FilePropertyBag {
|
||||
DOMString name = "";
|
||||
boolean existenceCheck = true;
|
||||
};
|
||||
|
||||
// Mozilla extensions
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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(¬ifications);
|
||||
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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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)));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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<
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -387,6 +387,7 @@ pub enum TextureUpdateOp {
|
|||
height: u32,
|
||||
data: Arc<Vec<u8>>,
|
||||
stride: Option<u32>,
|
||||
offset: u32,
|
||||
},
|
||||
UpdateForExternalBuffer {
|
||||
rect: DeviceUintRect,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)]
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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>;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
||||
|
|
|
|||
|
|
@ -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(¬Object);
|
||||
|
||||
// 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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
Loading…
Reference in a new issue