зеркало из https://github.com/mozilla/gecko-dev.git
merge mozilla-inbound to mozilla-central a=merge
This commit is contained in:
Коммит
ca457776f8
|
@ -102,6 +102,9 @@ XPCOMUtils.defineLazyModuleGetter(this, "SelfSupportBackend",
|
|||
XPCOMUtils.defineLazyModuleGetter(this, "SessionStore",
|
||||
"resource:///modules/sessionstore/SessionStore.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "BrowserUsageTelemetry",
|
||||
"resource:///modules/BrowserUsageTelemetry.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "BrowserUITelemetry",
|
||||
"resource:///modules/BrowserUITelemetry.jsm");
|
||||
|
||||
|
@ -781,6 +784,7 @@ BrowserGlue.prototype = {
|
|||
NewTabMessages.init();
|
||||
|
||||
SessionStore.init();
|
||||
BrowserUsageTelemetry.init();
|
||||
BrowserUITelemetry.init();
|
||||
ContentSearch.init();
|
||||
FormValidationHandler.init();
|
||||
|
@ -1174,6 +1178,7 @@ BrowserGlue.prototype = {
|
|||
Cu.reportError("Could not end startup crash tracking in quit-application-granted: " + e);
|
||||
}
|
||||
|
||||
BrowserUsageTelemetry.uninit();
|
||||
SelfSupportBackend.uninit();
|
||||
NewTabMessages.uninit();
|
||||
|
||||
|
|
|
@ -0,0 +1,175 @@
|
|||
/* -*- js-indent-level: 2; indent-tabs-mode: nil -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["BrowserUsageTelemetry"];
|
||||
|
||||
const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
// Observed topic names.
|
||||
const WINDOWS_RESTORED_TOPIC = "sessionstore-windows-restored";
|
||||
const TELEMETRY_SUBSESSIONSPLIT_TOPIC = "internal-telemetry-after-subsession-split";
|
||||
const DOMWINDOW_OPENED_TOPIC = "domwindowopened";
|
||||
const DOMWINDOW_CLOSED_TOPIC = "domwindowclosed";
|
||||
|
||||
// Probe names.
|
||||
const MAX_TAB_COUNT_SCALAR_NAME = "browser.engagement.max_concurrent_tab_count";
|
||||
const MAX_WINDOW_COUNT_SCALAR_NAME = "browser.engagement.max_concurrent_window_count";
|
||||
const TAB_OPEN_EVENT_COUNT_SCALAR_NAME = "browser.engagement.tab_open_event_count";
|
||||
const WINDOW_OPEN_EVENT_COUNT_SCALAR_NAME = "browser.engagement.window_open_event_count";
|
||||
|
||||
function getOpenTabsAndWinsCounts() {
|
||||
let tabCount = 0;
|
||||
let winCount = 0;
|
||||
|
||||
let browserEnum = Services.wm.getEnumerator("navigator:browser");
|
||||
while (browserEnum.hasMoreElements()) {
|
||||
let win = browserEnum.getNext();
|
||||
winCount++;
|
||||
tabCount += win.gBrowser.tabs.length;
|
||||
}
|
||||
|
||||
return { tabCount, winCount };
|
||||
}
|
||||
|
||||
let BrowserUsageTelemetry = {
|
||||
init() {
|
||||
Services.obs.addObserver(this, WINDOWS_RESTORED_TOPIC, false);
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle subsession splits in the parent process.
|
||||
*/
|
||||
afterSubsessionSplit() {
|
||||
// Scalars just got cleared due to a subsession split. We need to set the maximum
|
||||
// concurrent tab and window counts so that they reflect the correct value for the
|
||||
// new subsession.
|
||||
const counts = getOpenTabsAndWinsCounts();
|
||||
Services.telemetry.scalarSetMaximum(MAX_TAB_COUNT_SCALAR_NAME, counts.tabCount);
|
||||
Services.telemetry.scalarSetMaximum(MAX_WINDOW_COUNT_SCALAR_NAME, counts.winCount);
|
||||
},
|
||||
|
||||
uninit() {
|
||||
Services.obs.removeObserver(this, DOMWINDOW_OPENED_TOPIC, false);
|
||||
Services.obs.removeObserver(this, DOMWINDOW_CLOSED_TOPIC, false);
|
||||
Services.obs.removeObserver(this, TELEMETRY_SUBSESSIONSPLIT_TOPIC, false);
|
||||
Services.obs.removeObserver(this, WINDOWS_RESTORED_TOPIC, false);
|
||||
},
|
||||
|
||||
observe(subject, topic, data) {
|
||||
switch(topic) {
|
||||
case WINDOWS_RESTORED_TOPIC:
|
||||
this._setupAfterRestore();
|
||||
break;
|
||||
case DOMWINDOW_OPENED_TOPIC:
|
||||
this._onWindowOpen(subject);
|
||||
break;
|
||||
case DOMWINDOW_CLOSED_TOPIC:
|
||||
this._unregisterWindow(subject);
|
||||
break;
|
||||
case TELEMETRY_SUBSESSIONSPLIT_TOPIC:
|
||||
this.afterSubsessionSplit();
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
handleEvent(event) {
|
||||
switch(event.type) {
|
||||
case "TabOpen":
|
||||
this._onTabOpen();
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* This gets called shortly after the SessionStore has finished restoring
|
||||
* windows and tabs. It counts the open tabs and adds listeners to all the
|
||||
* windows.
|
||||
*/
|
||||
_setupAfterRestore() {
|
||||
// Make sure to catch new chrome windows and subsession splits.
|
||||
Services.obs.addObserver(this, DOMWINDOW_OPENED_TOPIC, false);
|
||||
Services.obs.addObserver(this, DOMWINDOW_CLOSED_TOPIC, false);
|
||||
Services.obs.addObserver(this, TELEMETRY_SUBSESSIONSPLIT_TOPIC, false);
|
||||
|
||||
// Attach the tabopen handlers to the existing Windows.
|
||||
let browserEnum = Services.wm.getEnumerator("navigator:browser");
|
||||
while (browserEnum.hasMoreElements()) {
|
||||
this._registerWindow(browserEnum.getNext());
|
||||
}
|
||||
|
||||
// Get the initial tab and windows max counts.
|
||||
const counts = getOpenTabsAndWinsCounts();
|
||||
Services.telemetry.scalarSetMaximum(MAX_TAB_COUNT_SCALAR_NAME, counts.tabCount);
|
||||
Services.telemetry.scalarSetMaximum(MAX_WINDOW_COUNT_SCALAR_NAME, counts.winCount);
|
||||
},
|
||||
|
||||
/**
|
||||
* Adds listeners to a single chrome window.
|
||||
*/
|
||||
_registerWindow(win) {
|
||||
win.addEventListener("TabOpen", this, true);
|
||||
},
|
||||
|
||||
/**
|
||||
* Removes listeners from a single chrome window.
|
||||
*/
|
||||
_unregisterWindow(win) {
|
||||
// Ignore non-browser windows.
|
||||
if (!(win instanceof Ci.nsIDOMWindow) ||
|
||||
win.document.documentElement.getAttribute("windowtype") != "navigator:browser") {
|
||||
return;
|
||||
}
|
||||
|
||||
win.removeEventListener("TabOpen", this, true);
|
||||
},
|
||||
|
||||
/**
|
||||
* Updates the tab counts.
|
||||
* @param {Number} [newTabCount=0] The count of the opened tabs across all windows. This
|
||||
* is computed manually if not provided.
|
||||
*/
|
||||
_onTabOpen(tabCount = 0) {
|
||||
// Use the provided tab count if available. Otherwise, go on and compute it.
|
||||
tabCount = tabCount || getOpenTabsAndWinsCounts().tabCount;
|
||||
// Update the "tab opened" count and its maximum.
|
||||
Services.telemetry.scalarAdd(TAB_OPEN_EVENT_COUNT_SCALAR_NAME, 1);
|
||||
Services.telemetry.scalarSetMaximum(MAX_TAB_COUNT_SCALAR_NAME, tabCount);
|
||||
},
|
||||
|
||||
/**
|
||||
* Tracks the window count and registers the listeners for the tab count.
|
||||
* @param{Object} win The window object.
|
||||
*/
|
||||
_onWindowOpen(win) {
|
||||
// Make sure to have a |nsIDOMWindow|.
|
||||
if (!(win instanceof Ci.nsIDOMWindow)) {
|
||||
return;
|
||||
}
|
||||
|
||||
let onLoad = () => {
|
||||
win.removeEventListener("load", onLoad, false);
|
||||
|
||||
// Ignore non browser windows.
|
||||
if (win.document.documentElement.getAttribute("windowtype") != "navigator:browser") {
|
||||
return;
|
||||
}
|
||||
|
||||
this._registerWindow(win);
|
||||
// Track the window open event and check the maximum.
|
||||
const counts = getOpenTabsAndWinsCounts();
|
||||
Services.telemetry.scalarAdd(WINDOW_OPEN_EVENT_COUNT_SCALAR_NAME, 1);
|
||||
Services.telemetry.scalarSetMaximum(MAX_WINDOW_COUNT_SCALAR_NAME, counts.winCount);
|
||||
|
||||
// We won't receive the "TabOpen" event for the first tab within a new window.
|
||||
// Account for that.
|
||||
this._onTabOpen(counts.tabCount);
|
||||
};
|
||||
win.addEventListener("load", onLoad, false);
|
||||
},
|
||||
};
|
|
@ -14,6 +14,7 @@ EXTRA_JS_MODULES += [
|
|||
'AboutHome.jsm',
|
||||
'AboutNewTab.jsm',
|
||||
'BrowserUITelemetry.jsm',
|
||||
'BrowserUsageTelemetry.jsm',
|
||||
'CaptivePortalWatcher.jsm',
|
||||
'CastingApps.jsm',
|
||||
'Chat.jsm',
|
||||
|
|
|
@ -23,3 +23,4 @@ support-files =
|
|||
../../components/uitour/UITour-lib.js
|
||||
[browser_taskbar_preview.js]
|
||||
skip-if = os != "win"
|
||||
[browser_UsageTelemetry.js]
|
||||
|
|
|
@ -20,6 +20,12 @@ const TEST_WAIT_RETRIES = 60;
|
|||
const TEST_PAGE_URL = getRootDirectory(gTestPath) + "uitour.html";
|
||||
const TEST_PAGE_URL_HTTPS = TEST_PAGE_URL.replace("chrome://mochitests/content/", "https://example.com/");
|
||||
|
||||
function sendSessionRestoredNotification() {
|
||||
let selfSupportBackendImpl =
|
||||
Cu.import("resource:///modules/SelfSupportBackend.jsm", {}).SelfSupportBackendInternal;
|
||||
selfSupportBackendImpl.observe(null, "sessionstore-windows-restored", null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a browser, with an IFRAME as parent, who has aURL as the source attribute.
|
||||
*
|
||||
|
@ -128,7 +134,7 @@ add_task(function* test_selfSupport() {
|
|||
|
||||
// SelfSupportBackend waits for "sessionstore-windows-restored" to start loading. Send it.
|
||||
info("Sending sessionstore-windows-restored");
|
||||
Services.obs.notifyObservers(null, "sessionstore-windows-restored", null);
|
||||
sendSessionRestoredNotification();
|
||||
|
||||
// Wait for the SelfSupport page to load.
|
||||
info("Waiting for the SelfSupport local page to load.");
|
||||
|
@ -196,7 +202,7 @@ add_task(function* test_selfSupport_noHTTPS() {
|
|||
|
||||
// SelfSupportBackend waits for "sessionstore-windows-restored" to start loading. Send it.
|
||||
info("Sending sessionstore-windows-restored");
|
||||
Services.obs.notifyObservers(null, "sessionstore-windows-restored", null);
|
||||
sendSessionRestoredNotification();
|
||||
|
||||
// Find the SelfSupport browser. We don't expect to find it since we are not using https.
|
||||
let selfSupportBrowser = findSelfSupportBrowser(TEST_PAGE_URL);
|
||||
|
|
|
@ -0,0 +1,143 @@
|
|||
"use strict";
|
||||
|
||||
const MAX_CONCURRENT_TABS = "browser.engagement.max_concurrent_tab_count";
|
||||
const TAB_EVENT_COUNT = "browser.engagement.tab_open_event_count";
|
||||
const MAX_CONCURRENT_WINDOWS = "browser.engagement.max_concurrent_window_count";
|
||||
const WINDOW_OPEN_COUNT = "browser.engagement.window_open_event_count";
|
||||
|
||||
const TELEMETRY_SUBSESSION_TOPIC = "internal-telemetry-after-subsession-split";
|
||||
|
||||
/**
|
||||
* An helper that checks the value of a scalar if it's expected to be > 0,
|
||||
* otherwise makes sure that the scalar it's not reported.
|
||||
*/
|
||||
let checkScalar = (scalars, scalarName, value, msg) => {
|
||||
if (value > 0) {
|
||||
is(scalars[scalarName], value, msg);
|
||||
return;
|
||||
}
|
||||
ok(!(scalarName in scalars), scalarName + " must not be reported.");
|
||||
};
|
||||
|
||||
/**
|
||||
* Get a snapshot of the scalars and check them against the provided values.
|
||||
*/
|
||||
let checkScalars = (maxTabs, tabOpenCount, maxWindows, windowsOpenCount) => {
|
||||
const scalars =
|
||||
Services.telemetry.snapshotScalars(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN);
|
||||
|
||||
// Check the expected values. Scalars that are never set must not be reported.
|
||||
checkScalar(scalars, MAX_CONCURRENT_TABS, maxTabs,
|
||||
"The maximum tab count must match the expected value.");
|
||||
checkScalar(scalars, TAB_EVENT_COUNT, tabOpenCount,
|
||||
"The number of open tab event count must match the expected value.");
|
||||
checkScalar(scalars, MAX_CONCURRENT_WINDOWS, maxWindows,
|
||||
"The maximum window count must match the expected value.");
|
||||
checkScalar(scalars, WINDOW_OPEN_COUNT, windowsOpenCount,
|
||||
"The number of window open event count must match the expected value.");
|
||||
};
|
||||
|
||||
add_task(function* test_tabsAndWindows() {
|
||||
// Let's reset the counts.
|
||||
Services.telemetry.clearScalars();
|
||||
|
||||
let openedTabs = [];
|
||||
let expectedTabOpenCount = 0;
|
||||
let expectedWinOpenCount = 0;
|
||||
let expectedMaxTabs = 0;
|
||||
let expectedMaxWins = 0;
|
||||
|
||||
// Add a new tab and check that the count is right.
|
||||
openedTabs.push(yield BrowserTestUtils.openNewForegroundTab(gBrowser, "about:blank"));
|
||||
expectedTabOpenCount = 1;
|
||||
expectedMaxTabs = 2;
|
||||
checkScalars(expectedMaxTabs, expectedTabOpenCount, expectedMaxWins, expectedWinOpenCount);
|
||||
|
||||
// Add two new tabs in the same window.
|
||||
openedTabs.push(yield BrowserTestUtils.openNewForegroundTab(gBrowser, "about:blank"));
|
||||
openedTabs.push(yield BrowserTestUtils.openNewForegroundTab(gBrowser, "about:blank"));
|
||||
expectedTabOpenCount += 2;
|
||||
expectedMaxTabs += 2;
|
||||
checkScalars(expectedMaxTabs, expectedTabOpenCount, expectedMaxWins, expectedWinOpenCount);
|
||||
|
||||
// Add a new window and then some tabs in it. An empty new windows counts as a tab.
|
||||
let win = yield BrowserTestUtils.openNewBrowserWindow();
|
||||
openedTabs.push(yield BrowserTestUtils.openNewForegroundTab(win.gBrowser, "about:blank"));
|
||||
openedTabs.push(yield BrowserTestUtils.openNewForegroundTab(win.gBrowser, "about:blank"));
|
||||
openedTabs.push(yield BrowserTestUtils.openNewForegroundTab(gBrowser, "about:blank"));
|
||||
// The new window started with a new tab, so account for it.
|
||||
expectedTabOpenCount += 4;
|
||||
expectedWinOpenCount += 1;
|
||||
expectedMaxWins = 2;
|
||||
expectedMaxTabs += 4;
|
||||
|
||||
// Remove a tab from the first window, the max shouldn't change.
|
||||
yield BrowserTestUtils.removeTab(openedTabs.pop());
|
||||
checkScalars(expectedMaxTabs, expectedTabOpenCount, expectedMaxWins, expectedWinOpenCount);
|
||||
|
||||
// Remove all the extra windows and tabs.
|
||||
for (let tab of openedTabs) {
|
||||
yield BrowserTestUtils.removeTab(tab);
|
||||
}
|
||||
yield BrowserTestUtils.closeWindow(win);
|
||||
|
||||
// Make sure all the scalars still have the expected values.
|
||||
checkScalars(expectedMaxTabs, expectedTabOpenCount, expectedMaxWins, expectedWinOpenCount);
|
||||
});
|
||||
|
||||
add_task(function* test_subsessionSplit() {
|
||||
// Let's reset the counts.
|
||||
Services.telemetry.clearScalars();
|
||||
|
||||
// Add a new window (that will have 4 tabs).
|
||||
let win = yield BrowserTestUtils.openNewBrowserWindow();
|
||||
let openedTabs = [];
|
||||
openedTabs.push(yield BrowserTestUtils.openNewForegroundTab(win.gBrowser, "about:blank"));
|
||||
openedTabs.push(yield BrowserTestUtils.openNewForegroundTab(win.gBrowser, "about:blank"));
|
||||
openedTabs.push(yield BrowserTestUtils.openNewForegroundTab(win.gBrowser, "about:blank"));
|
||||
|
||||
// Check that the scalars have the right values.
|
||||
checkScalars(5 /*maxTabs*/, 4 /*tabOpen*/, 2 /*maxWins*/, 1 /*winOpen*/);
|
||||
|
||||
// Remove a tab.
|
||||
yield BrowserTestUtils.removeTab(openedTabs.pop());
|
||||
|
||||
// Simulate a subsession split by clearing the scalars (via |snapshotScalars|) and
|
||||
// notifying the subsession split topic.
|
||||
Services.telemetry.snapshotScalars(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN,
|
||||
true /* clearScalars*/);
|
||||
Services.obs.notifyObservers(null, TELEMETRY_SUBSESSION_TOPIC, "");
|
||||
|
||||
// After a subsession split, only the MAX_CONCURRENT_* scalars must be available
|
||||
// and have the correct value. No tabs or windows were opened so other scalars
|
||||
// must not be reported.
|
||||
checkScalars(4 /*maxTabs*/, 0 /*tabOpen*/, 2 /*maxWins*/, 0 /*winOpen*/);
|
||||
|
||||
// Remove all the extra windows and tabs.
|
||||
for (let tab of openedTabs) {
|
||||
yield BrowserTestUtils.removeTab(tab);
|
||||
}
|
||||
yield BrowserTestUtils.closeWindow(win);
|
||||
});
|
||||
|
||||
add_task(function* test_privateMode() {
|
||||
// Let's reset the counts.
|
||||
Services.telemetry.clearScalars();
|
||||
|
||||
// Open a private window and load a website in it.
|
||||
let privateWin = yield BrowserTestUtils.openNewBrowserWindow({private: true});
|
||||
yield BrowserTestUtils.loadURI(privateWin.gBrowser.selectedBrowser, "http://example.com/");
|
||||
yield BrowserTestUtils.browserLoaded(privateWin.gBrowser.selectedBrowser);
|
||||
|
||||
// Check that tab and window count is recorded.
|
||||
const scalars =
|
||||
Services.telemetry.snapshotScalars(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN);
|
||||
|
||||
is(scalars[TAB_EVENT_COUNT], 1, "The number of open tab event count must match the expected value.");
|
||||
is(scalars[MAX_CONCURRENT_TABS], 2, "The maximum tab count must match the expected value.");
|
||||
is(scalars[WINDOW_OPEN_COUNT], 1, "The number of window open event count must match the expected value.");
|
||||
is(scalars[MAX_CONCURRENT_WINDOWS], 2, "The maximum window count must match the expected value.");
|
||||
|
||||
// Clean up.
|
||||
yield BrowserTestUtils.closeWindow(privateWin);
|
||||
});
|
|
@ -72,6 +72,7 @@ support-files =
|
|||
[browser_styleeditor_init.js]
|
||||
[browser_styleeditor_inline_friendly_names.js]
|
||||
[browser_styleeditor_loading.js]
|
||||
[browser_styleeditor_loading_with_containers.js]
|
||||
[browser_styleeditor_media_sidebar.js]
|
||||
[browser_styleeditor_media_sidebar_links.js]
|
||||
skip-if = e10s && debug # Bug 1252201 - Docshell leak on debug e10s
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
// Test that the stylesheets can be loaded correctly with containers
|
||||
// (bug 1282660).
|
||||
|
||||
const TESTCASE_URI = TEST_BASE_HTTP + "simple.html";
|
||||
const EXPECTED_SHEETS = [
|
||||
{
|
||||
sheetIndex: 0,
|
||||
name: /^simple.css$/,
|
||||
rules: 1,
|
||||
active: true
|
||||
}, {
|
||||
sheetIndex: 1,
|
||||
name: /^<.*>$/,
|
||||
rules: 3,
|
||||
active: false
|
||||
}
|
||||
];
|
||||
|
||||
add_task(function* () {
|
||||
// Using the personal container.
|
||||
let userContextId = 1;
|
||||
let { tab } = yield* openTabInUserContext(TESTCASE_URI, userContextId);
|
||||
let { ui } = yield openStyleEditor(tab);
|
||||
|
||||
is(ui.editors.length, 2, "The UI contains two style sheets.");
|
||||
checkSheet(ui.editors[0], EXPECTED_SHEETS[0]);
|
||||
checkSheet(ui.editors[1], EXPECTED_SHEETS[1]);
|
||||
});
|
||||
|
||||
function* openTabInUserContext(uri, userContextId) {
|
||||
// Open the tab in the correct userContextId.
|
||||
let tab = gBrowser.addTab(uri, {userContextId});
|
||||
|
||||
// Select tab and make sure its browser is focused.
|
||||
gBrowser.selectedTab = tab;
|
||||
tab.ownerDocument.defaultView.focus();
|
||||
|
||||
let browser = gBrowser.getBrowserForTab(tab);
|
||||
yield BrowserTestUtils.browserLoaded(browser);
|
||||
return {tab, browser};
|
||||
}
|
||||
|
||||
function checkSheet(editor, expected) {
|
||||
is(editor.styleSheet.styleSheetIndex, expected.sheetIndex,
|
||||
"Style sheet has correct index.");
|
||||
|
||||
let summary = editor.summary;
|
||||
let name = summary.querySelector(".stylesheet-name > label")
|
||||
.getAttribute("value");
|
||||
ok(expected.name.test(name), "The name '" + name + "' is correct.");
|
||||
|
||||
let ruleCount = summary.querySelector(".stylesheet-rule-count").textContent;
|
||||
is(parseInt(ruleCount, 10), expected.rules, "the rule count is correct");
|
||||
|
||||
is(summary.classList.contains("splitview-active"), expected.active,
|
||||
"The active status for this sheet is correct.");
|
||||
}
|
|
@ -452,10 +452,19 @@ var StyleSheetActor = protocol.ActorClassWithSpec(styleSheetSpec, {
|
|||
let options = {
|
||||
loadFromCache: true,
|
||||
policy: Ci.nsIContentPolicy.TYPE_INTERNAL_STYLESHEET,
|
||||
window: this.window,
|
||||
charset: this._getCSSCharset()
|
||||
};
|
||||
|
||||
// Bug 1282660 - We use the system principal to load the default internal
|
||||
// stylesheets instead of the content principal since such stylesheets
|
||||
// require system principal to load. At meanwhile, we strip the loadGroup
|
||||
// for preventing the assertion of the userContextId mismatching.
|
||||
// The default internal stylesheets load from the 'resource:' URL.
|
||||
if (!/^resource:\/\//.test(this.href)) {
|
||||
options.window = this.window;
|
||||
options.principal = this.document.nodePrincipal;
|
||||
}
|
||||
|
||||
return fetch(this.href, options).then(({ content }) => {
|
||||
this.text = content;
|
||||
return content;
|
||||
|
|
|
@ -14236,7 +14236,10 @@ nsDocShell::SetOriginAttributesBeforeLoading(JS::Handle<JS::Value> aOriginAttrib
|
|||
}
|
||||
|
||||
AutoJSAPI jsapi;
|
||||
jsapi.Init(&aOriginAttributes.toObject());
|
||||
if (!jsapi.Init(&aOriginAttributes.toObject())) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
JSContext* cx = jsapi.cx();
|
||||
if (NS_WARN_IF(!cx)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
|
|
|
@ -225,11 +225,11 @@ public:
|
|||
// If aGlobalObject represents a web-visible global, errors reported by this
|
||||
// AutoJSAPI as it comes off the stack will fire the relevant error events and
|
||||
// show up in the corresponding web console.
|
||||
bool Init(nsIGlobalObject* aGlobalObject);
|
||||
MOZ_MUST_USE bool Init(nsIGlobalObject* aGlobalObject);
|
||||
|
||||
// This is a helper that grabs the native global associated with aObject and
|
||||
// invokes the above Init() with that.
|
||||
bool Init(JSObject* aObject);
|
||||
MOZ_MUST_USE bool Init(JSObject* aObject);
|
||||
|
||||
// Unsurprisingly, this uses aCx and enters the compartment of aGlobalObject.
|
||||
// If aGlobalObject or its associated JS global are null then it returns
|
||||
|
@ -239,15 +239,15 @@ public:
|
|||
// If aGlobalObject represents a web-visible global, errors reported by this
|
||||
// AutoJSAPI as it comes off the stack will fire the relevant error events and
|
||||
// show up in the corresponding web console.
|
||||
bool Init(nsIGlobalObject* aGlobalObject, JSContext* aCx);
|
||||
MOZ_MUST_USE bool Init(nsIGlobalObject* aGlobalObject, JSContext* aCx);
|
||||
|
||||
// Convenience functions to take an nsPIDOMWindow* or nsGlobalWindow*,
|
||||
// when it is more easily available than an nsIGlobalObject.
|
||||
bool Init(nsPIDOMWindowInner* aWindow);
|
||||
bool Init(nsPIDOMWindowInner* aWindow, JSContext* aCx);
|
||||
MOZ_MUST_USE bool Init(nsPIDOMWindowInner* aWindow);
|
||||
MOZ_MUST_USE bool Init(nsPIDOMWindowInner* aWindow, JSContext* aCx);
|
||||
|
||||
bool Init(nsGlobalWindow* aWindow);
|
||||
bool Init(nsGlobalWindow* aWindow, JSContext* aCx);
|
||||
MOZ_MUST_USE bool Init(nsGlobalWindow* aWindow);
|
||||
MOZ_MUST_USE bool Init(nsGlobalWindow* aWindow, JSContext* aCx);
|
||||
|
||||
JSContext* cx() const {
|
||||
MOZ_ASSERT(mCx, "Must call Init before using an AutoJSAPI");
|
||||
|
@ -273,7 +273,7 @@ public:
|
|||
//
|
||||
// Note that this fails if and only if we OOM while wrapping the exception
|
||||
// into the current compartment.
|
||||
bool StealException(JS::MutableHandle<JS::Value> aVal);
|
||||
MOZ_MUST_USE bool StealException(JS::MutableHandle<JS::Value> aVal);
|
||||
|
||||
// Peek the current exception from the JS engine, without stealing it.
|
||||
// Callers must ensure that HasException() is true, and that cx() is in a
|
||||
|
@ -281,7 +281,7 @@ public:
|
|||
//
|
||||
// Note that this fails if and only if we OOM while wrapping the exception
|
||||
// into the current compartment.
|
||||
bool PeekException(JS::MutableHandle<JS::Value> aVal);
|
||||
MOZ_MUST_USE bool PeekException(JS::MutableHandle<JS::Value> aVal);
|
||||
|
||||
void ClearException() {
|
||||
MOZ_ASSERT(IsStackTop());
|
||||
|
|
|
@ -327,7 +327,9 @@ nsresult
|
|||
nsDOMClassInfo::DefineStaticJSVals()
|
||||
{
|
||||
AutoJSAPI jsapi;
|
||||
jsapi.Init(xpc::UnprivilegedJunkScope());
|
||||
if (!jsapi.Init(xpc::UnprivilegedJunkScope())) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
JSContext* cx = jsapi.cx();
|
||||
|
||||
#define SET_JSID_TO_STRING(_id, _cx, _str) \
|
||||
|
|
|
@ -7,8 +7,11 @@
|
|||
#include "nsHostObjectProtocolHandler.h"
|
||||
|
||||
#include "DOMMediaStream.h"
|
||||
#include "mozilla/dom/ContentChild.h"
|
||||
#include "mozilla/dom/Exceptions.h"
|
||||
#include "mozilla/dom/File.h"
|
||||
#include "mozilla/dom/ipc/BlobChild.h"
|
||||
#include "mozilla/dom/ipc/BlobParent.h"
|
||||
#include "mozilla/dom/MediaSource.h"
|
||||
#include "mozilla/LoadInfo.h"
|
||||
#include "mozilla/ModuleUtils.h"
|
||||
|
@ -38,9 +41,79 @@ struct DataInfo
|
|||
|
||||
static nsClassHashtable<nsCStringHashKey, DataInfo>* gDataTable;
|
||||
|
||||
static DataInfo*
|
||||
GetDataInfo(const nsACString& aUri)
|
||||
{
|
||||
if (!gDataTable) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
DataInfo* res;
|
||||
|
||||
// Let's remove any fragment and query from this URI.
|
||||
int32_t hasFragmentPos = aUri.FindChar('#');
|
||||
int32_t hasQueryPos = aUri.FindChar('?');
|
||||
|
||||
int32_t pos = -1;
|
||||
if (hasFragmentPos >= 0 && hasQueryPos >= 0) {
|
||||
pos = std::min(hasFragmentPos, hasQueryPos);
|
||||
} else if (hasFragmentPos >= 0) {
|
||||
pos = hasFragmentPos;
|
||||
} else {
|
||||
pos = hasQueryPos;
|
||||
}
|
||||
|
||||
if (pos < 0) {
|
||||
gDataTable->Get(aUri, &res);
|
||||
} else {
|
||||
gDataTable->Get(StringHead(aUri, pos), &res);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
// Memory reporting for the hash table.
|
||||
namespace mozilla {
|
||||
|
||||
void
|
||||
BroadcastBlobURLRegistration(const nsACString& aURI,
|
||||
BlobImpl* aBlobImpl,
|
||||
nsIPrincipal* aPrincipal)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(aBlobImpl);
|
||||
|
||||
if (XRE_IsParentProcess()) {
|
||||
ContentParent::BroadcastBlobURLRegistration(aURI, aBlobImpl,
|
||||
aPrincipal);
|
||||
return;
|
||||
}
|
||||
|
||||
ContentChild* cc = ContentChild::GetSingleton();
|
||||
BlobChild* actor = cc->GetOrCreateActorForBlobImpl(aBlobImpl);
|
||||
if (NS_WARN_IF(!actor)) {
|
||||
return;
|
||||
}
|
||||
|
||||
NS_WARN_IF(!cc->SendStoreAndBroadcastBlobURLRegistration(nsCString(aURI), actor,
|
||||
IPC::Principal(aPrincipal)));
|
||||
}
|
||||
|
||||
void
|
||||
BroadcastBlobURLUnregistration(const nsACString& aURI, DataInfo* aInfo)
|
||||
{
|
||||
MOZ_ASSERT(aInfo);
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (XRE_IsParentProcess()) {
|
||||
ContentParent::BroadcastBlobURLUnregistration(aURI);
|
||||
return;
|
||||
}
|
||||
|
||||
ContentChild* cc = ContentChild::GetSingleton();
|
||||
NS_WARN_IF(!cc->SendUnstoreAndBroadcastBlobURLUnregistration(nsCString(aURI)));
|
||||
}
|
||||
|
||||
class HostObjectURLsReporter final : public nsIMemoryReporter
|
||||
{
|
||||
~HostObjectURLsReporter() {}
|
||||
|
@ -321,12 +394,14 @@ nsHostObjectProtocolHandler::AddDataEntry(const nsACString& aScheme,
|
|||
nsACString& aUri)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
nsCOMPtr<BlobImpl> blobImpl(do_QueryInterface(aObject));
|
||||
nsCOMPtr<MediaSource> mediaSource(do_QueryInterface(aObject));
|
||||
nsCOMPtr<DOMMediaStream> mediaStream(do_QueryInterface(aObject));
|
||||
{
|
||||
nsCOMPtr<BlobImpl> blobImpl(do_QueryInterface(aObject));
|
||||
nsCOMPtr<MediaSource> mediaSource(do_QueryInterface(aObject));
|
||||
nsCOMPtr<DOMMediaStream> mediaStream(do_QueryInterface(aObject));
|
||||
|
||||
// We support only these types.
|
||||
MOZ_ASSERT(blobImpl || mediaSource || mediaStream);
|
||||
// We support only these types.
|
||||
MOZ_ASSERT(blobImpl || mediaSource || mediaStream);
|
||||
}
|
||||
#endif
|
||||
|
||||
Init();
|
||||
|
@ -334,6 +409,22 @@ nsHostObjectProtocolHandler::AddDataEntry(const nsACString& aScheme,
|
|||
nsresult rv = GenerateURIString(aScheme, aPrincipal, aUri);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = AddDataEntry(aUri, aObject, aPrincipal);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<BlobImpl> blobImpl = do_QueryInterface(aObject);
|
||||
if (blobImpl) {
|
||||
BroadcastBlobURLRegistration(aUri, blobImpl, aPrincipal);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* static */ nsresult
|
||||
nsHostObjectProtocolHandler::AddDataEntry(const nsACString& aURI,
|
||||
nsISupports* aObject,
|
||||
nsIPrincipal* aPrincipal)
|
||||
{
|
||||
if (!gDataTable) {
|
||||
gDataTable = new nsClassHashtable<nsCStringHashKey, DataInfo>;
|
||||
}
|
||||
|
@ -344,17 +435,62 @@ nsHostObjectProtocolHandler::AddDataEntry(const nsACString& aScheme,
|
|||
info->mPrincipal = aPrincipal;
|
||||
mozilla::BlobURLsReporter::GetJSStackForBlob(info);
|
||||
|
||||
gDataTable->Put(aUri, info);
|
||||
gDataTable->Put(aURI, info);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
nsHostObjectProtocolHandler::GetAllBlobURLEntries(nsTArray<BlobURLRegistrationData>& aRegistrations,
|
||||
ContentParent* aCP)
|
||||
{
|
||||
MOZ_ASSERT(aCP);
|
||||
|
||||
if (!gDataTable) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (auto iter = gDataTable->ConstIter(); !iter.Done(); iter.Next()) {
|
||||
DataInfo* info = iter.UserData();
|
||||
MOZ_ASSERT(info);
|
||||
|
||||
nsCOMPtr<BlobImpl> blobImpl = do_QueryInterface(info->mObject);
|
||||
if (!blobImpl) {
|
||||
continue;
|
||||
}
|
||||
|
||||
PBlobParent* blobParent = aCP->GetOrCreateActorForBlobImpl(blobImpl);
|
||||
if (!blobParent) {
|
||||
return false;
|
||||
}
|
||||
|
||||
aRegistrations.AppendElement(
|
||||
BlobURLRegistrationData(nsCString(iter.Key()), blobParent, nullptr,
|
||||
IPC::Principal(info->mPrincipal)));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
nsHostObjectProtocolHandler::RemoveDataEntry(const nsACString& aUri)
|
||||
nsHostObjectProtocolHandler::RemoveDataEntry(const nsACString& aUri,
|
||||
bool aBroadcastToOtherProcesses)
|
||||
{
|
||||
if (!gDataTable) {
|
||||
return;
|
||||
}
|
||||
|
||||
DataInfo* info = GetDataInfo(aUri);
|
||||
if (!info) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (aBroadcastToOtherProcesses) {
|
||||
nsCOMPtr<BlobImpl> blobImpl = do_QueryInterface(info->mObject);
|
||||
if (blobImpl) {
|
||||
BroadcastBlobURLUnregistration(aUri, info);
|
||||
}
|
||||
}
|
||||
|
||||
gDataTable->Remove(aUri);
|
||||
if (gDataTable->Count() == 0) {
|
||||
delete gDataTable;
|
||||
|
@ -362,6 +498,20 @@ nsHostObjectProtocolHandler::RemoveDataEntry(const nsACString& aUri)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsHostObjectProtocolHandler::RemoveDataEntries()
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsContentProcess());
|
||||
|
||||
if (!gDataTable) {
|
||||
return;
|
||||
}
|
||||
|
||||
gDataTable->Clear();
|
||||
delete gDataTable;
|
||||
gDataTable = nullptr;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsHostObjectProtocolHandler::GenerateURIString(const nsACString &aScheme,
|
||||
nsIPrincipal* aPrincipal,
|
||||
|
@ -398,37 +548,6 @@ nsHostObjectProtocolHandler::GenerateURIString(const nsACString &aScheme,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
static DataInfo*
|
||||
GetDataInfo(const nsACString& aUri)
|
||||
{
|
||||
if (!gDataTable) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
DataInfo* res;
|
||||
|
||||
// Let's remove any fragment and query from this URI.
|
||||
int32_t hasFragmentPos = aUri.FindChar('#');
|
||||
int32_t hasQueryPos = aUri.FindChar('?');
|
||||
|
||||
int32_t pos = -1;
|
||||
if (hasFragmentPos >= 0 && hasQueryPos >= 0) {
|
||||
pos = std::min(hasFragmentPos, hasQueryPos);
|
||||
} else if (hasFragmentPos >= 0) {
|
||||
pos = hasFragmentPos;
|
||||
} else {
|
||||
pos = hasQueryPos;
|
||||
}
|
||||
|
||||
if (pos < 0) {
|
||||
gDataTable->Get(aUri, &res);
|
||||
} else {
|
||||
gDataTable->Get(StringHead(aUri, pos), &res);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
nsIPrincipal*
|
||||
nsHostObjectProtocolHandler::GetDataEntryPrincipal(const nsACString& aUri)
|
||||
{
|
||||
|
@ -509,8 +628,13 @@ nsHostObjectProtocolHandler::NewURI(const nsACString& aSpec,
|
|||
|
||||
DataInfo* info = GetDataInfo(aSpec);
|
||||
|
||||
RefPtr<nsHostObjectURI> uri =
|
||||
new nsHostObjectURI(info ? info->mPrincipal.get() : nullptr);
|
||||
RefPtr<nsHostObjectURI> uri;
|
||||
if (info) {
|
||||
nsCOMPtr<BlobImpl> blob = do_QueryInterface(info->mObject);
|
||||
uri = new nsHostObjectURI(info->mPrincipal, blob);
|
||||
} else {
|
||||
uri = new nsHostObjectURI(nullptr, nullptr);
|
||||
}
|
||||
|
||||
rv = uri->SetSpec(aSpec);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
@ -528,22 +652,26 @@ nsHostObjectProtocolHandler::NewChannel2(nsIURI* uri,
|
|||
{
|
||||
*result = nullptr;
|
||||
|
||||
nsCOMPtr<nsIURIWithBlobImpl> uriBlobImpl = do_QueryInterface(uri);
|
||||
if (!uriBlobImpl) {
|
||||
return NS_ERROR_DOM_BAD_URI;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsISupports> tmp;
|
||||
MOZ_ALWAYS_SUCCEEDS(uriBlobImpl->GetBlobImpl(getter_AddRefs(tmp)));
|
||||
nsCOMPtr<BlobImpl> blobImpl = do_QueryInterface(tmp);
|
||||
if (!blobImpl) {
|
||||
return NS_ERROR_DOM_BAD_URI;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
nsCString spec;
|
||||
uri->GetSpec(spec);
|
||||
|
||||
DataInfo* info = GetDataInfo(spec);
|
||||
|
||||
if (!info) {
|
||||
return NS_ERROR_DOM_BAD_URI;
|
||||
}
|
||||
|
||||
nsCOMPtr<BlobImpl> blob = do_QueryInterface(info->mObject);
|
||||
if (!blob) {
|
||||
return NS_ERROR_DOM_BAD_URI;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
{
|
||||
// Info can be null, in case this blob URL has been revoked already.
|
||||
if (info) {
|
||||
nsCOMPtr<nsIURIWithPrincipal> uriPrinc = do_QueryInterface(uri);
|
||||
nsCOMPtr<nsIPrincipal> principal;
|
||||
uriPrinc->GetPrincipal(getter_AddRefs(principal));
|
||||
|
@ -553,13 +681,13 @@ nsHostObjectProtocolHandler::NewChannel2(nsIURI* uri,
|
|||
|
||||
ErrorResult rv;
|
||||
nsCOMPtr<nsIInputStream> stream;
|
||||
blob->GetInternalStream(getter_AddRefs(stream), rv);
|
||||
blobImpl->GetInternalStream(getter_AddRefs(stream), rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
return rv.StealNSResult();
|
||||
}
|
||||
|
||||
nsAutoString contentType;
|
||||
blob->GetType(contentType);
|
||||
blobImpl->GetType(contentType);
|
||||
|
||||
nsCOMPtr<nsIChannel> channel;
|
||||
rv = NS_NewInputStreamChannelInternal(getter_AddRefs(channel),
|
||||
|
@ -572,13 +700,13 @@ nsHostObjectProtocolHandler::NewChannel2(nsIURI* uri,
|
|||
return rv.StealNSResult();
|
||||
}
|
||||
|
||||
if (blob->IsFile()) {
|
||||
if (blobImpl->IsFile()) {
|
||||
nsString filename;
|
||||
blob->GetName(filename);
|
||||
blobImpl->GetName(filename);
|
||||
channel->SetContentDispositionFilename(filename);
|
||||
}
|
||||
|
||||
uint64_t size = blob->GetSize(rv);
|
||||
uint64_t size = blobImpl->GetSize(rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
return rv.StealNSResult();
|
||||
}
|
||||
|
@ -795,3 +923,4 @@ static const mozilla::Module kHostObjectProtocolHandlerModule = {
|
|||
};
|
||||
|
||||
NSMODULE_DEFN(HostObjectProtocolHandler) = &kHostObjectProtocolHandlerModule;
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "nsIURI.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIInputStream.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
#define BLOBURI_SCHEME "blob"
|
||||
#define MEDIASTREAMURI_SCHEME "mediastream"
|
||||
|
@ -25,6 +26,8 @@ namespace mozilla {
|
|||
class DOMMediaStream;
|
||||
namespace dom {
|
||||
class BlobImpl;
|
||||
class BlobURLRegistrationData;
|
||||
class ContentParent;
|
||||
class MediaSource;
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
@ -55,10 +58,23 @@ public:
|
|||
nsISupports* aObject,
|
||||
nsIPrincipal* aPrincipal,
|
||||
nsACString& aUri);
|
||||
static void RemoveDataEntry(const nsACString& aUri);
|
||||
static void RemoveDataEntry(const nsACString& aUri,
|
||||
bool aBroadcastToOTherProcesses = true);
|
||||
|
||||
// This is for IPC only.
|
||||
static void RemoveDataEntries();
|
||||
|
||||
static nsIPrincipal* GetDataEntryPrincipal(const nsACString& aUri);
|
||||
static void Traverse(const nsACString& aUri, nsCycleCollectionTraversalCallback& aCallback);
|
||||
|
||||
// IPC or internal use only
|
||||
static nsresult AddDataEntry(const nsACString& aURI,
|
||||
nsISupports* aObject,
|
||||
nsIPrincipal* aPrincipal);
|
||||
static bool
|
||||
GetAllBlobURLEntries(nsTArray<mozilla::dom::BlobURLRegistrationData>& aRegistrations,
|
||||
mozilla::dom::ContentParent* aCP);
|
||||
|
||||
protected:
|
||||
virtual ~nsHostObjectProtocolHandler() {}
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ NS_IMPL_ADDREF_INHERITED(nsHostObjectURI, mozilla::net::nsSimpleURI)
|
|||
NS_IMPL_RELEASE_INHERITED(nsHostObjectURI, mozilla::net::nsSimpleURI)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN(nsHostObjectURI)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIURIWithBlobImpl)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIURIWithPrincipal)
|
||||
if (aIID.Equals(kHOSTOBJECTURICID))
|
||||
foundInterface = static_cast<nsIURI*>(this);
|
||||
|
@ -34,6 +35,16 @@ NS_INTERFACE_MAP_BEGIN(nsHostObjectURI)
|
|||
else
|
||||
NS_INTERFACE_MAP_END_INHERITING(mozilla::net::nsSimpleURI)
|
||||
|
||||
// nsIURIWithBlobImpl methods:
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHostObjectURI::GetBlobImpl(nsISupports** aBlobImpl)
|
||||
{
|
||||
RefPtr<BlobImpl> blobImpl(mBlobImpl);
|
||||
blobImpl.forget(aBlobImpl);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// nsIURIWithPrincipal methods:
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -126,6 +137,10 @@ nsHostObjectURI::Deserialize(const mozilla::ipc::URIParams& aParams)
|
|||
if (!mozilla::net::nsSimpleURI::Deserialize(hostParams.simpleParams())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// XXXbaku: when we will have shared blobURL maps, we can populate mBlobImpl
|
||||
// here asll well.
|
||||
|
||||
if (hostParams.principal().type() == OptionalPrincipalInfo::Tvoid_t) {
|
||||
return true;
|
||||
}
|
||||
|
@ -162,6 +177,7 @@ nsHostObjectURI::CloneInternal(mozilla::net::nsSimpleURI::RefHandlingEnum aRefHa
|
|||
nsHostObjectURI* u = static_cast<nsHostObjectURI*>(simpleClone.get());
|
||||
|
||||
u->mPrincipal = mPrincipal;
|
||||
u->mBlobImpl = mBlobImpl;
|
||||
|
||||
simpleClone.forget(aClone);
|
||||
return NS_OK;
|
||||
|
@ -190,7 +206,10 @@ nsHostObjectURI::EqualsInternal(nsIURI* aOther,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
// Compare the piece of additional member data that we add to base class.
|
||||
// Compare the piece of additional member data that we add to base class,
|
||||
// but we cannot compare BlobImpl. This should not be a problem, because we
|
||||
// don't support changing the underlying mBlobImpl.
|
||||
|
||||
if (mPrincipal && otherUri->mPrincipal) {
|
||||
// Both of us have mPrincipals. Compare them.
|
||||
return mPrincipal->Equals(otherUri->mPrincipal, aResult);
|
||||
|
|
|
@ -8,10 +8,12 @@
|
|||
#define nsHostObjectURI_h
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/dom/File.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIClassInfo.h"
|
||||
#include "nsIPrincipal.h"
|
||||
#include "nsISerializable.h"
|
||||
#include "nsIURIWithBlobImpl.h"
|
||||
#include "nsIURIWithPrincipal.h"
|
||||
#include "nsSimpleURI.h"
|
||||
#include "nsIIPCSerializableURI.h"
|
||||
|
@ -21,18 +23,23 @@
|
|||
* MediaStreams, with scheme "mediastream", and MediaSources, with scheme
|
||||
* "mediasource".
|
||||
*/
|
||||
class nsHostObjectURI : public mozilla::net::nsSimpleURI,
|
||||
public nsIURIWithPrincipal
|
||||
class nsHostObjectURI : public mozilla::net::nsSimpleURI
|
||||
, public nsIURIWithPrincipal
|
||||
, public nsIURIWithBlobImpl
|
||||
{
|
||||
public:
|
||||
explicit nsHostObjectURI(nsIPrincipal* aPrincipal) :
|
||||
mozilla::net::nsSimpleURI(), mPrincipal(aPrincipal)
|
||||
nsHostObjectURI(nsIPrincipal* aPrincipal,
|
||||
mozilla::dom::BlobImpl* aBlobImpl)
|
||||
: mozilla::net::nsSimpleURI()
|
||||
, mPrincipal(aPrincipal)
|
||||
, mBlobImpl(aBlobImpl)
|
||||
{}
|
||||
|
||||
// For use only from deserialization
|
||||
nsHostObjectURI() : mozilla::net::nsSimpleURI() {}
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_NSIURIWITHBLOBIMPL
|
||||
NS_DECL_NSIURIWITHPRINCIPAL
|
||||
NS_DECL_NSISERIALIZABLE
|
||||
NS_DECL_NSICLASSINFO
|
||||
|
@ -52,6 +59,7 @@ public:
|
|||
{ return new nsHostObjectURI(); }
|
||||
|
||||
nsCOMPtr<nsIPrincipal> mPrincipal;
|
||||
RefPtr<mozilla::dom::BlobImpl> mBlobImpl;
|
||||
|
||||
protected:
|
||||
virtual ~nsHostObjectURI() {}
|
||||
|
|
|
@ -191,7 +191,6 @@ TexUnpackBlob::ConvertIfNeeded(WebGLContext* webgl, const char* funcName,
|
|||
const bool isDstPremult = webgl->mPixelStore_PremultiplyAlpha;
|
||||
|
||||
const auto pi = dstDUI->ToPacking();
|
||||
const auto dstFormat = FormatForPackingInfo(pi);
|
||||
|
||||
const auto dstBPP = webgl::BytesPerPixel(pi);
|
||||
const auto dstWidthBytes = CheckedUint32(dstBPP) * mWidth;
|
||||
|
@ -203,8 +202,9 @@ TexUnpackBlob::ConvertIfNeeded(WebGLContext* webgl, const char* funcName,
|
|||
//////
|
||||
|
||||
const auto dstTotalRows = CheckedUint32(mDepth - 1) * mImageHeight + mHeight;
|
||||
const auto dstUsedSizeExceptLastRow = (dstTotalRows - 1) * dstStride;
|
||||
|
||||
const auto dstSize = skipBytes + (dstTotalRows - 1) * dstStride + dstWidthBytes;
|
||||
const auto dstSize = skipBytes + dstUsedSizeExceptLastRow + dstWidthBytes;
|
||||
if (!dstSize.isValid()) {
|
||||
webgl->ErrorOutOfMemory("%s: Invalid dstSize calculation during conversion.",
|
||||
funcName);
|
||||
|
@ -213,32 +213,71 @@ TexUnpackBlob::ConvertIfNeeded(WebGLContext* webgl, const char* funcName,
|
|||
|
||||
//////
|
||||
|
||||
bool needsConvert = (srcOrigin != dstOrigin ||
|
||||
srcFormat != dstFormat ||
|
||||
srcStride != dstStride.value());
|
||||
const auto dstFormat = FormatForPackingInfo(pi);
|
||||
|
||||
if (UnpackFormatHasAlpha(dstDUI->unpackFormat)) {
|
||||
needsConvert |= (mIsSrcPremult != isDstPremult);
|
||||
bool premultMatches = (mIsSrcPremult == isDstPremult);
|
||||
if (!UnpackFormatHasAlpha(dstDUI->unpackFormat)) {
|
||||
premultMatches = true;
|
||||
}
|
||||
|
||||
if (!needsConvert)
|
||||
const bool needsPixelConversion = (srcFormat != dstFormat || !premultMatches);
|
||||
const bool originsMatch = (srcOrigin == dstOrigin);
|
||||
|
||||
MOZ_ASSERT_IF(!needsPixelConversion, srcBPP == dstBPP);
|
||||
|
||||
if (!needsPixelConversion &&
|
||||
originsMatch &&
|
||||
srcStride == dstStride.value())
|
||||
{
|
||||
// No conversion needed!
|
||||
return true;
|
||||
|
||||
////////////
|
||||
// Ugh, ok, fine!
|
||||
|
||||
webgl->GenerateWarning("%s: Incurred CPU data conversion, which is slow.",
|
||||
funcName);
|
||||
}
|
||||
|
||||
//////
|
||||
// We need some sort of conversion, so create the dest buffer.
|
||||
|
||||
*out_anchoredBuffer = calloc(1, dstSize.value());
|
||||
if (!out_anchoredBuffer->get()) {
|
||||
*out_bytes = out_anchoredBuffer->get();
|
||||
if (!*out_bytes) {
|
||||
webgl->ErrorOutOfMemory("%s: Unable to allocate buffer during conversion.",
|
||||
funcName);
|
||||
return false;
|
||||
}
|
||||
const auto dstBegin = (uint8_t*)out_anchoredBuffer->get() + skipBytes;
|
||||
const auto dstBegin = (uint8_t*)(*out_bytes) + skipBytes;
|
||||
|
||||
//////
|
||||
// Row conversion
|
||||
|
||||
if (!needsPixelConversion) {
|
||||
webgl->GenerateWarning("%s: Incurred CPU row conversion, which is slow.",
|
||||
funcName);
|
||||
|
||||
const uint8_t* srcRow = srcBegin;
|
||||
uint8_t* dstRow = dstBegin;
|
||||
const auto widthBytes = dstWidthBytes.value();
|
||||
ptrdiff_t dstCopyStride = dstStride.value();
|
||||
|
||||
if (!originsMatch) {
|
||||
dstRow += dstUsedSizeExceptLastRow.value();
|
||||
dstCopyStride = -dstCopyStride;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < dstTotalRows.value(); i++) {
|
||||
memcpy(dstRow, srcRow, widthBytes);
|
||||
srcRow += srcStride;
|
||||
dstRow += dstCopyStride;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////
|
||||
// Pixel conversion.
|
||||
|
||||
MOZ_ASSERT(srcFormat != WebGLTexelFormat::FormatNotSupportingAnyConversion);
|
||||
MOZ_ASSERT(dstFormat != WebGLTexelFormat::FormatNotSupportingAnyConversion);
|
||||
|
||||
webgl->GenerateWarning("%s: Incurred CPU pixel conversion, which is very slow.",
|
||||
funcName);
|
||||
|
||||
//////
|
||||
|
||||
|
@ -259,7 +298,6 @@ TexUnpackBlob::ConvertIfNeeded(WebGLContext* webgl, const char* funcName,
|
|||
funcName, dstDUI->unpackFormat, dstDUI->unpackType);
|
||||
}
|
||||
|
||||
*out_bytes = out_anchoredBuffer->get();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -297,7 +335,6 @@ TexUnpackBytes::TexOrSubImage(bool isSubImage, bool needsRespec, const char* fun
|
|||
WebGLContext* webgl = tex->mContext;
|
||||
|
||||
const auto pi = dui->ToPacking();
|
||||
const auto format = FormatForPackingInfo(pi);
|
||||
|
||||
const auto bytesPerPixel = webgl::BytesPerPixel(pi);
|
||||
const auto bytesPerRow = CheckedUint32(mRowLength) * bytesPerPixel;
|
||||
|
@ -306,6 +343,8 @@ TexUnpackBytes::TexOrSubImage(bool isSubImage, bool needsRespec, const char* fun
|
|||
MOZ_CRASH("Should be checked earlier.");
|
||||
}
|
||||
|
||||
const auto format = FormatForPackingInfo(pi);
|
||||
|
||||
const void* uploadBytes;
|
||||
UniqueBuffer tempBuffer;
|
||||
if (!ConvertIfNeeded(webgl, funcName, mBytes, rowStride.value(), bytesPerPixel,
|
||||
|
|
|
@ -55,7 +55,16 @@ public:
|
|||
const dom::Nullable<dom::ArrayBuffer>& maybeData);
|
||||
void GetBufferSubData(GLenum target, GLintptr offset,
|
||||
const dom::SharedArrayBuffer& data);
|
||||
void ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format,
|
||||
GLenum type, WebGLsizeiptr offset, ErrorResult& out_error);
|
||||
|
||||
void ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height,
|
||||
GLenum format, GLenum type,
|
||||
const dom::Nullable<dom::ArrayBufferView>& pixels,
|
||||
ErrorResult& out_error)
|
||||
{
|
||||
WebGLContext::ReadPixels(x, y, width, height, format, type, pixels, out_error);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Framebuffer objects - WebGL2ContextFramebuffers.cpp
|
||||
|
@ -142,111 +151,68 @@ public:
|
|||
void VertexAttribIPointer(GLuint index, GLint size, GLenum type, GLsizei stride, GLintptr offset);
|
||||
|
||||
// GL 3.0 & ES 3.0
|
||||
void Uniform1ui(WebGLUniformLocation* location, GLuint v0);
|
||||
void Uniform2ui(WebGLUniformLocation* location, GLuint v0, GLuint v1);
|
||||
void Uniform3ui(WebGLUniformLocation* location, GLuint v0, GLuint v1, GLuint v2);
|
||||
void Uniform4ui(WebGLUniformLocation* location, GLuint v0, GLuint v1, GLuint v2, GLuint v3);
|
||||
void Uniform1ui(WebGLUniformLocation* loc, GLuint v0);
|
||||
void Uniform2ui(WebGLUniformLocation* loc, GLuint v0, GLuint v1);
|
||||
void Uniform3ui(WebGLUniformLocation* loc, GLuint v0, GLuint v1, GLuint v2);
|
||||
void Uniform4ui(WebGLUniformLocation* loc, GLuint v0, GLuint v1, GLuint v2,
|
||||
GLuint v3);
|
||||
|
||||
private:
|
||||
void Uniform1uiv_base(WebGLUniformLocation* loc, size_t arrayLength, const GLuint* data);
|
||||
void Uniform2uiv_base(WebGLUniformLocation* loc, size_t arrayLength, const GLuint* data);
|
||||
void Uniform3uiv_base(WebGLUniformLocation* loc, size_t arrayLength, const GLuint* data);
|
||||
void Uniform4uiv_base(WebGLUniformLocation* loc, size_t arrayLength, const GLuint* data);
|
||||
////////////////
|
||||
|
||||
protected:
|
||||
typedef Arr<GLuint, dom::Uint32Array> UintArr;
|
||||
|
||||
void UniformNuiv(const char* funcName, uint8_t N, WebGLUniformLocation* loc,
|
||||
const UintArr& arr);
|
||||
|
||||
//////
|
||||
|
||||
public:
|
||||
void Uniform1uiv(WebGLUniformLocation* loc, const dom::Sequence<GLuint>& arr) {
|
||||
Uniform1uiv_base(loc, arr.Length(), arr.Elements());
|
||||
template<typename T>
|
||||
void Uniform1uiv(WebGLUniformLocation* loc, const T& arr) {
|
||||
UniformNuiv("uniform1uiv", 1, loc, UintArr(arr));
|
||||
}
|
||||
void Uniform2uiv(WebGLUniformLocation* loc, const dom::Sequence<GLuint>& arr) {
|
||||
Uniform2uiv_base(loc, arr.Length(), arr.Elements());
|
||||
template<typename T>
|
||||
void Uniform2uiv(WebGLUniformLocation* loc, const T& arr) {
|
||||
UniformNuiv("uniform2uiv", 2, loc, UintArr(arr));
|
||||
}
|
||||
void Uniform3uiv(WebGLUniformLocation* loc, const dom::Sequence<GLuint>& arr) {
|
||||
Uniform3uiv_base(loc, arr.Length(), arr.Elements());
|
||||
template<typename T>
|
||||
void Uniform3uiv(WebGLUniformLocation* loc, const T& arr) {
|
||||
UniformNuiv("uniform3uiv", 3, loc, UintArr(arr));
|
||||
}
|
||||
void Uniform4uiv(WebGLUniformLocation* loc, const dom::Sequence<GLuint>& arr) {
|
||||
Uniform4uiv_base(loc, arr.Length(), arr.Elements());
|
||||
}
|
||||
void Uniform1uiv(WebGLUniformLocation* loc, const dom::Uint32Array& arr) {
|
||||
arr.ComputeLengthAndData();
|
||||
Uniform1uiv_base(loc, arr.Length(), arr.Data());
|
||||
}
|
||||
void Uniform2uiv(WebGLUniformLocation* loc, const dom::Uint32Array& arr) {
|
||||
arr.ComputeLengthAndData();
|
||||
Uniform2uiv_base(loc, arr.Length(), arr.Data());
|
||||
}
|
||||
void Uniform3uiv(WebGLUniformLocation* loc, const dom::Uint32Array& arr) {
|
||||
arr.ComputeLengthAndData();
|
||||
Uniform3uiv_base(loc, arr.Length(), arr.Data());
|
||||
}
|
||||
void Uniform4uiv(WebGLUniformLocation* loc, const dom::Uint32Array& arr) {
|
||||
arr.ComputeLengthAndData();
|
||||
Uniform4uiv_base(loc, arr.Length(), arr.Data());
|
||||
template<typename T>
|
||||
void Uniform4uiv(WebGLUniformLocation* loc, const T& arr) {
|
||||
UniformNuiv("uniform4uiv", 4, loc, UintArr(arr));
|
||||
}
|
||||
|
||||
private:
|
||||
void UniformMatrix2x3fv_base(WebGLUniformLocation* loc, bool transpose,
|
||||
size_t arrayLength, const GLfloat* data);
|
||||
void UniformMatrix3x2fv_base(WebGLUniformLocation* loc, bool transpose,
|
||||
size_t arrayLength, const GLfloat* data);
|
||||
void UniformMatrix2x4fv_base(WebGLUniformLocation* loc, bool transpose,
|
||||
size_t arrayLength, const GLfloat* data);
|
||||
void UniformMatrix4x2fv_base(WebGLUniformLocation* loc, bool transpose,
|
||||
size_t arrayLength, const GLfloat* data);
|
||||
void UniformMatrix3x4fv_base(WebGLUniformLocation* loc, bool transpose,
|
||||
size_t arrayLength, const GLfloat* data);
|
||||
void UniformMatrix4x3fv_base(WebGLUniformLocation* loc, bool transpose,
|
||||
size_t arrayLength, const GLfloat* data);
|
||||
//////
|
||||
|
||||
public:
|
||||
// GL 2.1 & ES 3.0
|
||||
void UniformMatrix2x3fv(WebGLUniformLocation* loc, bool transpose, const dom::Sequence<GLfloat>& value){
|
||||
UniformMatrix2x3fv_base(loc, transpose, value.Length(), value.Elements());
|
||||
template<typename T>
|
||||
void UniformMatrix2x3fv(WebGLUniformLocation* loc, bool transpose, const T& arr) {
|
||||
UniformMatrixAxBfv("uniformMatrix2x3fv", 2, 3, loc, transpose, FloatArr(arr));
|
||||
}
|
||||
void UniformMatrix2x4fv(WebGLUniformLocation* loc, bool transpose, const dom::Sequence<GLfloat>& value){
|
||||
UniformMatrix2x4fv_base(loc, transpose, value.Length(), value.Elements());
|
||||
template<typename T>
|
||||
void UniformMatrix2x4fv(WebGLUniformLocation* loc, bool transpose, const T& arr) {
|
||||
UniformMatrixAxBfv("uniformMatrix2x4fv", 2, 4, loc, transpose, FloatArr(arr));
|
||||
}
|
||||
void UniformMatrix3x2fv(WebGLUniformLocation* loc, bool transpose, const dom::Sequence<GLfloat>& value){
|
||||
UniformMatrix3x2fv_base(loc, transpose, value.Length(), value.Elements());
|
||||
template<typename T>
|
||||
void UniformMatrix3x2fv(WebGLUniformLocation* loc, bool transpose, const T& arr) {
|
||||
UniformMatrixAxBfv("uniformMatrix3x2fv", 3, 2, loc, transpose, FloatArr(arr));
|
||||
}
|
||||
void UniformMatrix3x4fv(WebGLUniformLocation* loc, bool transpose, const dom::Sequence<GLfloat>& value){
|
||||
UniformMatrix3x4fv_base(loc, transpose, value.Length(), value.Elements());
|
||||
template<typename T>
|
||||
void UniformMatrix3x4fv(WebGLUniformLocation* loc, bool transpose, const T& arr) {
|
||||
UniformMatrixAxBfv("uniformMatrix3x4fv", 3, 4, loc, transpose, FloatArr(arr));
|
||||
}
|
||||
void UniformMatrix4x2fv(WebGLUniformLocation* loc, bool transpose, const dom::Sequence<GLfloat>& value){
|
||||
UniformMatrix4x2fv_base(loc, transpose, value.Length(), value.Elements());
|
||||
template<typename T>
|
||||
void UniformMatrix4x2fv(WebGLUniformLocation* loc, bool transpose, const T& arr) {
|
||||
UniformMatrixAxBfv("uniformMatrix4x2fv", 4, 2, loc, transpose, FloatArr(arr));
|
||||
}
|
||||
void UniformMatrix4x3fv(WebGLUniformLocation* loc, bool transpose, const dom::Sequence<GLfloat>& value){
|
||||
UniformMatrix4x3fv_base(loc, transpose, value.Length(), value.Elements());
|
||||
template<typename T>
|
||||
void UniformMatrix4x3fv(WebGLUniformLocation* loc, bool transpose, const T& arr) {
|
||||
UniformMatrixAxBfv("uniformMatrix4x3fv", 4, 3, loc, transpose, FloatArr(arr));
|
||||
}
|
||||
|
||||
void UniformMatrix2x3fv(WebGLUniformLocation* loc, bool transpose, const dom::Float32Array& value){
|
||||
value.ComputeLengthAndData();
|
||||
UniformMatrix2x3fv_base(loc, transpose, value.Length(), value.Data());
|
||||
}
|
||||
|
||||
void UniformMatrix2x4fv(WebGLUniformLocation* loc, bool transpose, const dom::Float32Array& value){
|
||||
value.ComputeLengthAndData();
|
||||
UniformMatrix2x4fv_base(loc, transpose, value.Length(), value.Data());
|
||||
}
|
||||
|
||||
void UniformMatrix3x2fv(WebGLUniformLocation* loc, bool transpose, const dom::Float32Array& value){
|
||||
value.ComputeLengthAndData();
|
||||
UniformMatrix3x2fv_base(loc, transpose, value.Length(), value.Data());
|
||||
}
|
||||
|
||||
void UniformMatrix3x4fv(WebGLUniformLocation* loc, bool transpose, const dom::Float32Array& value){
|
||||
value.ComputeLengthAndData();
|
||||
UniformMatrix3x4fv_base(loc, transpose, value.Length(), value.Data());
|
||||
}
|
||||
|
||||
void UniformMatrix4x2fv(WebGLUniformLocation* loc, bool transpose, const dom::Float32Array& value){
|
||||
value.ComputeLengthAndData();
|
||||
UniformMatrix4x2fv_base(loc, transpose, value.Length(), value.Data());
|
||||
}
|
||||
|
||||
void UniformMatrix4x3fv(WebGLUniformLocation* loc, bool transpose, const dom::Float32Array& value){
|
||||
value.ComputeLengthAndData();
|
||||
UniformMatrix4x3fv_base(loc, transpose, value.Length(), value.Data());
|
||||
}
|
||||
////////////////
|
||||
|
||||
private:
|
||||
void VertexAttribI4iv(GLuint index, size_t length, const GLint* v);
|
||||
|
|
|
@ -12,26 +12,26 @@
|
|||
namespace mozilla {
|
||||
|
||||
bool
|
||||
WebGL2Context::ValidateBufferTarget(GLenum target, const char* info)
|
||||
WebGL2Context::ValidateBufferTarget(GLenum target, const char* funcName)
|
||||
{
|
||||
switch (target) {
|
||||
case LOCAL_GL_ARRAY_BUFFER:
|
||||
case LOCAL_GL_COPY_READ_BUFFER:
|
||||
case LOCAL_GL_COPY_WRITE_BUFFER:
|
||||
case LOCAL_GL_ELEMENT_ARRAY_BUFFER:
|
||||
case LOCAL_GL_PIXEL_PACK_BUFFER:
|
||||
case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER:
|
||||
case LOCAL_GL_UNIFORM_BUFFER:
|
||||
return true;
|
||||
|
||||
case LOCAL_GL_PIXEL_PACK_BUFFER:
|
||||
case LOCAL_GL_PIXEL_UNPACK_BUFFER:
|
||||
ErrorInvalidOperation("%s: PBOs are still under development, and are currently"
|
||||
" disabled.",
|
||||
info);
|
||||
funcName);
|
||||
return false;
|
||||
|
||||
default:
|
||||
ErrorInvalidEnumInfo(info, target);
|
||||
ErrorInvalidEnumInfo(funcName, target);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -80,11 +80,12 @@ WebGL2Context::CopyBufferSubData(GLenum readTarget, GLenum writeTarget,
|
|||
GLintptr readOffset, GLintptr writeOffset,
|
||||
GLsizeiptr size)
|
||||
{
|
||||
const char funcName[] = "copyBufferSubData";
|
||||
if (IsContextLost())
|
||||
return;
|
||||
|
||||
if (!ValidateBufferTarget(readTarget, "copyBufferSubData") ||
|
||||
!ValidateBufferTarget(writeTarget, "copyBufferSubData"))
|
||||
if (!ValidateBufferTarget(readTarget, funcName) ||
|
||||
!ValidateBufferTarget(writeTarget, funcName))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@ -95,27 +96,25 @@ WebGL2Context::CopyBufferSubData(GLenum readTarget, GLenum writeTarget,
|
|||
return;
|
||||
|
||||
const WebGLBuffer* readBuffer = readBufferSlot.get();
|
||||
if (!readBuffer)
|
||||
return ErrorInvalidOperation("copyBufferSubData: No buffer bound to readTarget");
|
||||
if (!readBuffer) {
|
||||
ErrorInvalidOperation("%s: No buffer bound to readTarget.", funcName);
|
||||
return;
|
||||
}
|
||||
|
||||
WebGLBuffer* writeBuffer = writeBufferSlot.get();
|
||||
if (!writeBuffer)
|
||||
return ErrorInvalidOperation("copyBufferSubData: No buffer bound to writeTarget");
|
||||
|
||||
if (!ValidateDataOffsetSize(readOffset, size, readBuffer->ByteLength(),
|
||||
"copyBufferSubData"))
|
||||
{
|
||||
if (!writeBuffer) {
|
||||
ErrorInvalidOperation("%s: No buffer bound to writeTarget.", funcName);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ValidateDataOffsetSize(writeOffset, size, writeBuffer->ByteLength(),
|
||||
"copyBufferSubData"))
|
||||
{
|
||||
if (!ValidateDataOffsetSize(readOffset, size, readBuffer->ByteLength(), funcName))
|
||||
return;
|
||||
|
||||
if (!ValidateDataOffsetSize(writeOffset, size, writeBuffer->ByteLength(), funcName))
|
||||
return;
|
||||
}
|
||||
|
||||
if (readTarget == writeTarget &&
|
||||
!ValidateDataRanges(readOffset, writeOffset, size, "copyBufferSubData"))
|
||||
!ValidateDataRanges(readOffset, writeOffset, size, funcName))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@ -127,9 +126,12 @@ WebGL2Context::CopyBufferSubData(GLenum readTarget, GLenum writeTarget,
|
|||
writeType != WebGLBuffer::Kind::Undefined &&
|
||||
writeType != readType)
|
||||
{
|
||||
ErrorInvalidOperation("copyBufferSubData: Can't copy %s data to %s data",
|
||||
(readType == WebGLBuffer::Kind::OtherData) ? "other" : "element",
|
||||
(writeType == WebGLBuffer::Kind::OtherData) ? "other" : "element");
|
||||
ErrorInvalidOperation("%s: Can't copy %s data to %s data.",
|
||||
funcName,
|
||||
(readType == WebGLBuffer::Kind::OtherData) ? "other"
|
||||
: "element",
|
||||
(writeType == WebGLBuffer::Kind::OtherData) ? "other"
|
||||
: "element");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -150,6 +152,7 @@ template<typename BufferT>
|
|||
void
|
||||
WebGL2Context::GetBufferSubDataT(GLenum target, GLintptr offset, const BufferT& data)
|
||||
{
|
||||
const char funcName[] = "getBufferSubData";
|
||||
if (IsContextLost())
|
||||
return;
|
||||
|
||||
|
@ -159,18 +162,22 @@ WebGL2Context::GetBufferSubDataT(GLenum target, GLintptr offset, const BufferT&
|
|||
|
||||
// If zero is bound to target, an INVALID_OPERATION error is
|
||||
// generated.
|
||||
if (!ValidateBufferTarget(target, "getBufferSubData"))
|
||||
if (!ValidateBufferTarget(target, funcName))
|
||||
return;
|
||||
|
||||
// If offset is less than zero, an INVALID_VALUE error is
|
||||
// generated.
|
||||
if (offset < 0)
|
||||
return ErrorInvalidValue("getBufferSubData: negative offset");
|
||||
if (offset < 0) {
|
||||
ErrorInvalidValue("%s: Offset must be non-negative.", funcName);
|
||||
return;
|
||||
}
|
||||
|
||||
WebGLRefPtr<WebGLBuffer>& bufferSlot = GetBufferSlotByTarget(target);
|
||||
WebGLBuffer* boundBuffer = bufferSlot.get();
|
||||
if (!boundBuffer)
|
||||
return ErrorInvalidOperation("getBufferSubData: no buffer bound");
|
||||
if (!boundBuffer) {
|
||||
ErrorInvalidOperation("%s: No buffer bound.", funcName);
|
||||
return;
|
||||
}
|
||||
|
||||
// If offset + returnedData.byteLength would extend beyond the end
|
||||
// of the buffer an INVALID_VALUE error is generated.
|
||||
|
@ -178,15 +185,15 @@ WebGL2Context::GetBufferSubDataT(GLenum target, GLintptr offset, const BufferT&
|
|||
|
||||
CheckedInt<WebGLsizeiptr> neededByteLength = CheckedInt<WebGLsizeiptr>(offset) + data.LengthAllowShared();
|
||||
if (!neededByteLength.isValid()) {
|
||||
ErrorInvalidValue("getBufferSubData: Integer overflow computing the needed"
|
||||
" byte length.");
|
||||
ErrorInvalidValue("%s: Integer overflow computing the needed byte length.",
|
||||
funcName);
|
||||
return;
|
||||
}
|
||||
|
||||
if (neededByteLength.value() > boundBuffer->ByteLength()) {
|
||||
ErrorInvalidValue("getBufferSubData: Not enough data. Operation requires"
|
||||
" %d bytes, but buffer only has %d bytes.",
|
||||
neededByteLength.value(), boundBuffer->ByteLength());
|
||||
ErrorInvalidValue("%s: Not enough data. Operation requires %d bytes, but buffer"
|
||||
" only has %d bytes.",
|
||||
funcName, neededByteLength.value(), boundBuffer->ByteLength());
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -195,9 +202,11 @@ WebGL2Context::GetBufferSubDataT(GLenum target, GLintptr offset, const BufferT&
|
|||
// is generated.
|
||||
WebGLTransformFeedback* currentTF = mBoundTransformFeedback;
|
||||
if (target == LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER && currentTF) {
|
||||
if (currentTF->mIsActive)
|
||||
return ErrorInvalidOperation("getBufferSubData: Currently bound transform"
|
||||
" feedback is active");
|
||||
if (currentTF->mIsActive) {
|
||||
ErrorInvalidOperation("%s: Currently bound transform feedback is active.",
|
||||
funcName);
|
||||
return;
|
||||
}
|
||||
|
||||
// https://github.com/NVIDIA/WebGL/commit/63aff5e58c1d79825a596f0f4aa46174b9a5f72c
|
||||
// Performing reads and writes on a buffer that is currently
|
||||
|
@ -218,30 +227,37 @@ WebGL2Context::GetBufferSubDataT(GLenum target, GLintptr offset, const BufferT&
|
|||
* bound to a transform feedback binding point.
|
||||
*/
|
||||
|
||||
void* ptr = gl->fMapBufferRange(target, offset, data.LengthAllowShared(), LOCAL_GL_MAP_READ_BIT);
|
||||
void* ptr = gl->fMapBufferRange(target, offset, data.LengthAllowShared(),
|
||||
LOCAL_GL_MAP_READ_BIT);
|
||||
// Warning: Possibly shared memory. See bug 1225033.
|
||||
memcpy(data.DataAllowShared(), ptr, data.LengthAllowShared());
|
||||
gl->fUnmapBuffer(target);
|
||||
|
||||
////
|
||||
|
||||
if (target == LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER && currentTF) {
|
||||
BindTransformFeedback(LOCAL_GL_TRANSFORM_FEEDBACK, currentTF);
|
||||
}
|
||||
}
|
||||
|
||||
void WebGL2Context::GetBufferSubData(GLenum target, GLintptr offset,
|
||||
const dom::Nullable<dom::ArrayBuffer>& maybeData)
|
||||
void
|
||||
WebGL2Context::GetBufferSubData(GLenum target, GLintptr offset,
|
||||
const dom::Nullable<dom::ArrayBuffer>& maybeData)
|
||||
{
|
||||
// If returnedData is null then an INVALID_VALUE error is
|
||||
// generated.
|
||||
if (maybeData.IsNull())
|
||||
return ErrorInvalidValue("getBufferSubData: returnedData is null");
|
||||
if (maybeData.IsNull()) {
|
||||
ErrorInvalidValue("getBufferSubData: returnedData is null");
|
||||
return;
|
||||
}
|
||||
|
||||
const dom::ArrayBuffer& data = maybeData.Value();
|
||||
GetBufferSubDataT(target, offset, data);
|
||||
}
|
||||
|
||||
void WebGL2Context::GetBufferSubData(GLenum target, GLintptr offset,
|
||||
const dom::SharedArrayBuffer& data)
|
||||
void
|
||||
WebGL2Context::GetBufferSubData(GLenum target, GLintptr offset,
|
||||
const dom::SharedArrayBuffer& data)
|
||||
{
|
||||
GetBufferSubDataT(target, offset, data);
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "WebGLBuffer.h"
|
||||
#include "WebGLContext.h"
|
||||
#include "WebGLProgram.h"
|
||||
#include "WebGLUniformLocation.h"
|
||||
#include "WebGLVertexArray.h"
|
||||
#include "WebGLVertexAttribData.h"
|
||||
|
||||
|
@ -28,220 +29,42 @@ WebGL2Context::ValidateUniformMatrixTranspose(bool /*transpose*/, const char* /*
|
|||
void
|
||||
WebGL2Context::Uniform1ui(WebGLUniformLocation* loc, GLuint v0)
|
||||
{
|
||||
GLuint rawLoc;
|
||||
if (!ValidateUniformSetter(loc, 1, LOCAL_GL_UNSIGNED_INT, "uniform1ui", &rawLoc))
|
||||
if (!ValidateUniformSetter(loc, 1, LOCAL_GL_UNSIGNED_INT, "uniform1ui"))
|
||||
return;
|
||||
|
||||
MakeContextCurrent();
|
||||
gl->fUniform1ui(rawLoc, v0);
|
||||
gl->fUniform1ui(loc->mLoc, v0);
|
||||
}
|
||||
|
||||
void
|
||||
WebGL2Context::Uniform2ui(WebGLUniformLocation* loc, GLuint v0, GLuint v1)
|
||||
{
|
||||
GLuint rawLoc;
|
||||
if (!ValidateUniformSetter(loc, 2, LOCAL_GL_UNSIGNED_INT, "uniform2ui", &rawLoc))
|
||||
if (!ValidateUniformSetter(loc, 2, LOCAL_GL_UNSIGNED_INT, "uniform2ui"))
|
||||
return;
|
||||
|
||||
MakeContextCurrent();
|
||||
gl->fUniform2ui(rawLoc, v0, v1);
|
||||
gl->fUniform2ui(loc->mLoc, v0, v1);
|
||||
}
|
||||
|
||||
void
|
||||
WebGL2Context::Uniform3ui(WebGLUniformLocation* loc, GLuint v0, GLuint v1, GLuint v2)
|
||||
{
|
||||
GLuint rawLoc;
|
||||
if (!ValidateUniformSetter(loc, 3, LOCAL_GL_UNSIGNED_INT, "uniform3ui", &rawLoc))
|
||||
if (!ValidateUniformSetter(loc, 3, LOCAL_GL_UNSIGNED_INT, "uniform3ui"))
|
||||
return;
|
||||
|
||||
MakeContextCurrent();
|
||||
gl->fUniform3ui(rawLoc, v0, v1, v2);
|
||||
gl->fUniform3ui(loc->mLoc, v0, v1, v2);
|
||||
}
|
||||
|
||||
void
|
||||
WebGL2Context::Uniform4ui(WebGLUniformLocation* loc, GLuint v0, GLuint v1, GLuint v2, GLuint v3)
|
||||
WebGL2Context::Uniform4ui(WebGLUniformLocation* loc, GLuint v0, GLuint v1, GLuint v2,
|
||||
GLuint v3)
|
||||
{
|
||||
GLuint rawLoc;
|
||||
if (!ValidateUniformSetter(loc, 4, LOCAL_GL_UNSIGNED_INT, "uniform4ui", &rawLoc))
|
||||
if (!ValidateUniformSetter(loc, 4, LOCAL_GL_UNSIGNED_INT, "uniform4ui"))
|
||||
return;
|
||||
|
||||
MakeContextCurrent();
|
||||
gl->fUniform4ui(rawLoc, v0, v1, v2, v3);
|
||||
}
|
||||
|
||||
void
|
||||
WebGL2Context::Uniform1uiv_base(WebGLUniformLocation* loc, size_t arrayLength,
|
||||
const GLuint* data)
|
||||
{
|
||||
GLuint rawLoc;
|
||||
GLsizei numElementsToUpload;
|
||||
|
||||
if (!ValidateUniformArraySetter(loc, 1, LOCAL_GL_UNSIGNED_INT, arrayLength,
|
||||
"uniform1uiv", &rawLoc, &numElementsToUpload))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
MakeContextCurrent();
|
||||
gl->fUniform1uiv(rawLoc, numElementsToUpload, data);
|
||||
}
|
||||
|
||||
void
|
||||
WebGL2Context::Uniform2uiv_base(WebGLUniformLocation* loc, size_t arrayLength,
|
||||
const GLuint* data)
|
||||
{
|
||||
GLuint rawLoc;
|
||||
GLsizei numElementsToUpload;
|
||||
|
||||
if (!ValidateUniformArraySetter(loc, 2, LOCAL_GL_UNSIGNED_INT, arrayLength,
|
||||
"uniform2uiv", &rawLoc, &numElementsToUpload))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
MakeContextCurrent();
|
||||
gl->fUniform2uiv(rawLoc, numElementsToUpload, data);
|
||||
}
|
||||
|
||||
void
|
||||
WebGL2Context::Uniform3uiv_base(WebGLUniformLocation* loc, size_t arrayLength,
|
||||
const GLuint* data)
|
||||
{
|
||||
GLuint rawLoc;
|
||||
GLsizei numElementsToUpload;
|
||||
|
||||
if (!ValidateUniformArraySetter(loc, 3, LOCAL_GL_UNSIGNED_INT, arrayLength,
|
||||
"uniform3uiv", &rawLoc, &numElementsToUpload))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
MakeContextCurrent();
|
||||
gl->fUniform1uiv(rawLoc, numElementsToUpload, data);
|
||||
}
|
||||
|
||||
void
|
||||
WebGL2Context::Uniform4uiv_base(WebGLUniformLocation* loc, size_t arrayLength,
|
||||
const GLuint* data)
|
||||
{
|
||||
GLuint rawLoc;
|
||||
GLsizei numElementsToUpload;
|
||||
|
||||
if (!ValidateUniformArraySetter(loc, 4, LOCAL_GL_UNSIGNED_INT, arrayLength,
|
||||
"uniform4uiv", &rawLoc, &numElementsToUpload)) {
|
||||
return;
|
||||
}
|
||||
|
||||
MakeContextCurrent();
|
||||
gl->fUniform4uiv(rawLoc, numElementsToUpload, data);
|
||||
}
|
||||
|
||||
void
|
||||
WebGL2Context::UniformMatrix2x3fv_base(WebGLUniformLocation* loc, bool transpose,
|
||||
size_t arrayLength, const GLfloat* data)
|
||||
{
|
||||
GLuint rawLoc;
|
||||
GLsizei numElementsToUpload;
|
||||
|
||||
if (!ValidateUniformMatrixArraySetter(loc, 2, 3, LOCAL_GL_FLOAT, arrayLength,
|
||||
transpose, "uniformMatrix2x3fv",
|
||||
&rawLoc, &numElementsToUpload))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
MakeContextCurrent();
|
||||
gl->fUniformMatrix2x3fv(rawLoc, numElementsToUpload, transpose, data);
|
||||
}
|
||||
|
||||
void
|
||||
WebGL2Context::UniformMatrix2x4fv_base(WebGLUniformLocation* loc, bool transpose,
|
||||
size_t arrayLength, const GLfloat* data)
|
||||
{
|
||||
GLuint rawLoc;
|
||||
GLsizei numElementsToUpload;
|
||||
|
||||
if (!ValidateUniformMatrixArraySetter(loc, 2, 4, LOCAL_GL_FLOAT, arrayLength,
|
||||
transpose, "uniformMatrix2x4fv",
|
||||
&rawLoc, &numElementsToUpload))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
MakeContextCurrent();
|
||||
gl->fUniformMatrix2x4fv(rawLoc, numElementsToUpload, transpose, data);
|
||||
}
|
||||
|
||||
void
|
||||
WebGL2Context::UniformMatrix3x2fv_base(WebGLUniformLocation* loc, bool transpose,
|
||||
size_t arrayLength, const GLfloat* data)
|
||||
{
|
||||
GLuint rawLoc;
|
||||
GLsizei numElementsToUpload;
|
||||
|
||||
if (!ValidateUniformMatrixArraySetter(loc, 3, 2, LOCAL_GL_FLOAT, arrayLength,
|
||||
transpose, "uniformMatrix3x2fv",
|
||||
&rawLoc, &numElementsToUpload))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
MakeContextCurrent();
|
||||
gl->fUniformMatrix3x2fv(rawLoc, numElementsToUpload, transpose, data);
|
||||
}
|
||||
|
||||
void
|
||||
WebGL2Context::UniformMatrix3x4fv_base(WebGLUniformLocation* loc, bool transpose,
|
||||
size_t arrayLength, const GLfloat* data)
|
||||
{
|
||||
GLuint rawLoc;
|
||||
GLsizei numElementsToUpload;
|
||||
|
||||
if (!ValidateUniformMatrixArraySetter(loc, 3, 4, LOCAL_GL_FLOAT, arrayLength,
|
||||
transpose, "uniformMatrix3x4fv",
|
||||
&rawLoc, &numElementsToUpload))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
MakeContextCurrent();
|
||||
gl->fUniformMatrix3x4fv(rawLoc, numElementsToUpload, transpose, data);
|
||||
}
|
||||
|
||||
void
|
||||
WebGL2Context::UniformMatrix4x2fv_base(WebGLUniformLocation* loc, bool transpose,
|
||||
size_t arrayLength, const GLfloat* data)
|
||||
{
|
||||
GLuint rawLoc;
|
||||
GLsizei numElementsToUpload;
|
||||
|
||||
if (!ValidateUniformMatrixArraySetter(loc, 4, 2, LOCAL_GL_FLOAT, arrayLength,
|
||||
transpose, "uniformMatrix4x2fv",
|
||||
&rawLoc, &numElementsToUpload))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
MakeContextCurrent();
|
||||
gl->fUniformMatrix4x2fv(rawLoc, numElementsToUpload, transpose, data);
|
||||
}
|
||||
|
||||
void
|
||||
WebGL2Context::UniformMatrix4x3fv_base(WebGLUniformLocation* loc, bool transpose,
|
||||
size_t arrayLength, const GLfloat* data)
|
||||
{
|
||||
GLuint rawLoc;
|
||||
GLsizei numElementsToUpload;
|
||||
|
||||
if (!ValidateUniformMatrixArraySetter(loc, 4, 3, LOCAL_GL_FLOAT, arrayLength,
|
||||
transpose, "uniformMatrix4x3fv",
|
||||
&rawLoc, &numElementsToUpload))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
MakeContextCurrent();
|
||||
gl->fUniformMatrix4x3fv(rawLoc, numElementsToUpload, transpose, data);
|
||||
gl->fUniform4ui(loc->mLoc, v0, v1, v2, v3);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
namespace mozilla {
|
||||
|
||||
uint8_t
|
||||
static uint8_t
|
||||
ElemSizeFromType(GLenum elemType)
|
||||
{
|
||||
switch (elemType) {
|
||||
|
@ -76,6 +76,8 @@ ElemSizeFromType(GLenum elemType)
|
|||
}
|
||||
}
|
||||
|
||||
////////////////////
|
||||
|
||||
WebGLActiveInfo::WebGLActiveInfo(WebGLContext* webgl, GLint elemCount, GLenum elemType,
|
||||
bool isArray, const nsACString& baseUserName,
|
||||
const nsACString& baseMappedName)
|
||||
|
@ -88,6 +90,32 @@ WebGLActiveInfo::WebGLActiveInfo(WebGLContext* webgl, GLint elemCount, GLenum el
|
|||
, mBaseMappedName(baseMappedName)
|
||||
{ }
|
||||
|
||||
bool
|
||||
WebGLActiveInfo::IsSampler() const
|
||||
{
|
||||
switch (mElemType) {
|
||||
case LOCAL_GL_SAMPLER_2D:
|
||||
case LOCAL_GL_SAMPLER_3D:
|
||||
case LOCAL_GL_SAMPLER_CUBE:
|
||||
case LOCAL_GL_SAMPLER_2D_SHADOW:
|
||||
case LOCAL_GL_SAMPLER_2D_ARRAY:
|
||||
case LOCAL_GL_SAMPLER_2D_ARRAY_SHADOW:
|
||||
case LOCAL_GL_SAMPLER_CUBE_SHADOW:
|
||||
case LOCAL_GL_INT_SAMPLER_2D:
|
||||
case LOCAL_GL_INT_SAMPLER_3D:
|
||||
case LOCAL_GL_INT_SAMPLER_CUBE:
|
||||
case LOCAL_GL_INT_SAMPLER_2D_ARRAY:
|
||||
case LOCAL_GL_UNSIGNED_INT_SAMPLER_2D:
|
||||
case LOCAL_GL_UNSIGNED_INT_SAMPLER_3D:
|
||||
case LOCAL_GL_UNSIGNED_INT_SAMPLER_CUBE:
|
||||
case LOCAL_GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
JSObject*
|
||||
|
|
|
@ -30,11 +30,10 @@ public:
|
|||
return mWebGL;
|
||||
}
|
||||
|
||||
|
||||
WebGLContext* const mWebGL;
|
||||
|
||||
// ActiveInfo state:
|
||||
const GLint mElemCount; // `size`
|
||||
const uint32_t mElemCount; // `size`
|
||||
const GLenum mElemType; // `type`
|
||||
const nsCString mBaseUserName; // `name`, but ASCII, and without any final "[0]".
|
||||
|
||||
|
@ -43,6 +42,8 @@ public:
|
|||
const uint8_t mElemSize;
|
||||
const nsCString mBaseMappedName; // Without any final "[0]".
|
||||
|
||||
bool IsSampler() const;
|
||||
|
||||
WebGLActiveInfo(WebGLContext* webgl, GLint elemCount, GLenum elemType, bool isArray,
|
||||
const nsACString& baseUserName, const nsACString& baseMappedName);
|
||||
|
||||
|
@ -90,7 +91,7 @@ private:
|
|||
|
||||
//////////
|
||||
|
||||
uint8_t ElemSizeFromType(GLenum elemType);
|
||||
bool IsElemTypeSampler(GLenum elemType);
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
|
|
|
@ -122,6 +122,7 @@ namespace webgl {
|
|||
struct LinkedProgramInfo;
|
||||
class ShaderValidator;
|
||||
class TexUnpackBlob;
|
||||
struct UniformInfo;
|
||||
} // namespace webgl
|
||||
|
||||
WebGLTexelFormat GetWebGLTexelFormat(TexInternalFormat format);
|
||||
|
@ -539,9 +540,13 @@ public:
|
|||
void PixelStorei(GLenum pname, GLint param);
|
||||
void PolygonOffset(GLfloat factor, GLfloat units);
|
||||
protected:
|
||||
bool DoReadPixelsAndConvert(GLint x, GLint y, GLsizei width, GLsizei height,
|
||||
GLenum destFormat, GLenum destType, void* destBytes,
|
||||
GLenum auxReadFormat, GLenum auxReadType);
|
||||
bool ReadPixels_SharedPrecheck(ErrorResult* const out_error);
|
||||
void ReadPixelsImpl(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format,
|
||||
GLenum type, void* data, uint32_t dataLen);
|
||||
bool DoReadPixelsAndConvert(const webgl::FormatInfo* srcFormat, GLint x, GLint y,
|
||||
GLsizei width, GLsizei height, GLenum format,
|
||||
GLenum destType, void* dest, uint32_t dataLen,
|
||||
uint32_t rowStride);
|
||||
public:
|
||||
void ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height,
|
||||
GLenum format, GLenum type,
|
||||
|
@ -565,160 +570,108 @@ public:
|
|||
void StencilOpSeparate(GLenum face, GLenum sfail, GLenum dpfail,
|
||||
GLenum dppass);
|
||||
|
||||
//////
|
||||
|
||||
void Uniform1i(WebGLUniformLocation* loc, GLint x);
|
||||
void Uniform2i(WebGLUniformLocation* loc, GLint x, GLint y);
|
||||
void Uniform3i(WebGLUniformLocation* loc, GLint x, GLint y, GLint z);
|
||||
void Uniform4i(WebGLUniformLocation* loc, GLint x, GLint y, GLint z,
|
||||
GLint w);
|
||||
void Uniform4i(WebGLUniformLocation* loc, GLint x, GLint y, GLint z, GLint w);
|
||||
|
||||
void Uniform1f(WebGLUniformLocation* loc, GLfloat x);
|
||||
void Uniform2f(WebGLUniformLocation* loc, GLfloat x, GLfloat y);
|
||||
void Uniform3f(WebGLUniformLocation* loc, GLfloat x, GLfloat y, GLfloat z);
|
||||
void Uniform4f(WebGLUniformLocation* loc, GLfloat x, GLfloat y, GLfloat z,
|
||||
GLfloat w);
|
||||
void Uniform4f(WebGLUniformLocation* loc, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
|
||||
|
||||
// Int array
|
||||
void Uniform1iv(WebGLUniformLocation* loc, const dom::Int32Array& arr) {
|
||||
arr.ComputeLengthAndData();
|
||||
Uniform1iv_base(loc, arr.Length(), arr.Data());
|
||||
}
|
||||
void Uniform1iv(WebGLUniformLocation* loc,
|
||||
const dom::Sequence<GLint>& arr)
|
||||
{
|
||||
Uniform1iv_base(loc, arr.Length(), arr.Elements());
|
||||
}
|
||||
void Uniform1iv_base(WebGLUniformLocation* loc, size_t arrayLength,
|
||||
const GLint* data);
|
||||
//////////////////////////
|
||||
|
||||
void Uniform2iv(WebGLUniformLocation* loc, const dom::Int32Array& arr) {
|
||||
arr.ComputeLengthAndData();
|
||||
Uniform2iv_base(loc, arr.Length(), arr.Data());
|
||||
}
|
||||
void Uniform2iv(WebGLUniformLocation* loc,
|
||||
const dom::Sequence<GLint>& arr)
|
||||
{
|
||||
Uniform2iv_base(loc, arr.Length(), arr.Elements());
|
||||
}
|
||||
void Uniform2iv_base(WebGLUniformLocation* loc, size_t arrayLength,
|
||||
const GLint* data);
|
||||
protected:
|
||||
template<typename elemT, typename arrT>
|
||||
struct Arr {
|
||||
size_t dataCount;
|
||||
const elemT* data;
|
||||
|
||||
void Uniform3iv(WebGLUniformLocation* loc, const dom::Int32Array& arr) {
|
||||
arr.ComputeLengthAndData();
|
||||
Uniform3iv_base(loc, arr.Length(), arr.Data());
|
||||
}
|
||||
void Uniform3iv(WebGLUniformLocation* loc,
|
||||
const dom::Sequence<GLint>& arr)
|
||||
{
|
||||
Uniform3iv_base(loc, arr.Length(), arr.Elements());
|
||||
}
|
||||
void Uniform3iv_base(WebGLUniformLocation* loc, size_t arrayLength,
|
||||
const GLint* data);
|
||||
explicit Arr(const arrT& arr) {
|
||||
arr.ComputeLengthAndData();
|
||||
dataCount = arr.Length();
|
||||
data = arr.Data();
|
||||
}
|
||||
|
||||
void Uniform4iv(WebGLUniformLocation* loc, const dom::Int32Array& arr) {
|
||||
arr.ComputeLengthAndData();
|
||||
Uniform4iv_base(loc, arr.Length(), arr.Data());
|
||||
}
|
||||
void Uniform4iv(WebGLUniformLocation* loc,
|
||||
const dom::Sequence<GLint>& arr)
|
||||
{
|
||||
Uniform4iv_base(loc, arr.Length(), arr.Elements());
|
||||
}
|
||||
void Uniform4iv_base(WebGLUniformLocation* loc, size_t arrayLength,
|
||||
const GLint* data);
|
||||
explicit Arr(const dom::Sequence<elemT>& arr) {
|
||||
dataCount = arr.Length();
|
||||
data = arr.Elements();
|
||||
}
|
||||
};
|
||||
|
||||
// Float array
|
||||
void Uniform1fv(WebGLUniformLocation* loc, const dom::Float32Array& arr) {
|
||||
arr.ComputeLengthAndData();
|
||||
Uniform1fv_base(loc, arr.Length(), arr.Data());
|
||||
}
|
||||
void Uniform1fv(WebGLUniformLocation* loc,
|
||||
const dom::Sequence<GLfloat>& arr)
|
||||
{
|
||||
Uniform1fv_base(loc, arr.Length(), arr.Elements());
|
||||
}
|
||||
void Uniform1fv_base(WebGLUniformLocation* loc, size_t arrayLength,
|
||||
const GLfloat* data);
|
||||
typedef Arr<GLint, dom::Int32Array> IntArr;
|
||||
typedef Arr<GLfloat, dom::Float32Array> FloatArr;
|
||||
|
||||
void Uniform2fv(WebGLUniformLocation* loc, const dom::Float32Array& arr) {
|
||||
arr.ComputeLengthAndData();
|
||||
Uniform2fv_base(loc, arr.Length(), arr.Data());
|
||||
}
|
||||
void Uniform2fv(WebGLUniformLocation* loc,
|
||||
const dom::Sequence<GLfloat>& arr)
|
||||
{
|
||||
Uniform2fv_base(loc, arr.Length(), arr.Elements());
|
||||
}
|
||||
void Uniform2fv_base(WebGLUniformLocation* loc, size_t arrayLength,
|
||||
const GLfloat* data);
|
||||
////////////////
|
||||
|
||||
void Uniform3fv(WebGLUniformLocation* loc, const dom::Float32Array& arr) {
|
||||
arr.ComputeLengthAndData();
|
||||
Uniform3fv_base(loc, arr.Length(), arr.Data());
|
||||
}
|
||||
void Uniform3fv(WebGLUniformLocation* loc,
|
||||
const dom::Sequence<GLfloat>& arr)
|
||||
{
|
||||
Uniform3fv_base(loc, arr.Length(), arr.Elements());
|
||||
}
|
||||
void Uniform3fv_base(WebGLUniformLocation* loc, size_t arrayLength,
|
||||
const GLfloat* data);
|
||||
void UniformNiv(const char* funcName, uint8_t N, WebGLUniformLocation* loc,
|
||||
const IntArr& arr);
|
||||
|
||||
void Uniform4fv(WebGLUniformLocation* loc, const dom::Float32Array& arr) {
|
||||
arr.ComputeLengthAndData();
|
||||
Uniform4fv_base(loc, arr.Length(), arr.Data());
|
||||
}
|
||||
void Uniform4fv(WebGLUniformLocation* loc,
|
||||
const dom::Sequence<GLfloat>& arr)
|
||||
{
|
||||
Uniform4fv_base(loc, arr.Length(), arr.Elements());
|
||||
}
|
||||
void Uniform4fv_base(WebGLUniformLocation* loc, size_t arrayLength,
|
||||
const GLfloat* data);
|
||||
void UniformNfv(const char* funcName, uint8_t N, WebGLUniformLocation* loc,
|
||||
const FloatArr& arr);
|
||||
|
||||
// Matrix
|
||||
void UniformMatrix2fv(WebGLUniformLocation* loc, WebGLboolean transpose,
|
||||
const dom::Float32Array& value)
|
||||
{
|
||||
value.ComputeLengthAndData();
|
||||
UniformMatrix2fv_base(loc, transpose, value.Length(), value.Data());
|
||||
}
|
||||
void UniformMatrix2fv(WebGLUniformLocation* loc, WebGLboolean transpose,
|
||||
const dom::Sequence<float>& value)
|
||||
{
|
||||
UniformMatrix2fv_base(loc, transpose, value.Length(),
|
||||
value.Elements());
|
||||
}
|
||||
void UniformMatrix2fv_base(WebGLUniformLocation* loc, bool transpose,
|
||||
size_t arrayLength, const float* data);
|
||||
void UniformMatrixAxBfv(const char* funcName, uint8_t A, uint8_t B,
|
||||
WebGLUniformLocation* loc, bool transpose,
|
||||
const FloatArr& arr);
|
||||
|
||||
void UniformMatrix3fv(WebGLUniformLocation* loc, WebGLboolean transpose,
|
||||
const dom::Float32Array& value)
|
||||
{
|
||||
value.ComputeLengthAndData();
|
||||
UniformMatrix3fv_base(loc, transpose, value.Length(), value.Data());
|
||||
}
|
||||
void UniformMatrix3fv(WebGLUniformLocation* loc, WebGLboolean transpose,
|
||||
const dom::Sequence<float>& value)
|
||||
{
|
||||
UniformMatrix3fv_base(loc, transpose, value.Length(), value.Elements());
|
||||
}
|
||||
void UniformMatrix3fv_base(WebGLUniformLocation* loc, bool transpose,
|
||||
size_t arrayLength, const float* data);
|
||||
////////////////
|
||||
|
||||
void UniformMatrix4fv(WebGLUniformLocation* loc, WebGLboolean transpose,
|
||||
const dom::Float32Array& value)
|
||||
{
|
||||
value.ComputeLengthAndData();
|
||||
UniformMatrix4fv_base(loc, transpose, value.Length(), value.Data());
|
||||
public:
|
||||
template<typename T>
|
||||
void Uniform1iv(WebGLUniformLocation* loc, const T& arr) {
|
||||
UniformNiv("uniform1iv", 1, loc, IntArr(arr));
|
||||
}
|
||||
void UniformMatrix4fv(WebGLUniformLocation* loc, bool transpose,
|
||||
const dom::Sequence<float>& value)
|
||||
{
|
||||
UniformMatrix4fv_base(loc, transpose, value.Length(),
|
||||
value.Elements());
|
||||
template<typename T>
|
||||
void Uniform2iv(WebGLUniformLocation* loc, const T& arr) {
|
||||
UniformNiv("uniform2iv", 2, loc, IntArr(arr));
|
||||
}
|
||||
void UniformMatrix4fv_base(WebGLUniformLocation* loc, bool transpose,
|
||||
size_t arrayLength, const float* data);
|
||||
template<typename T>
|
||||
void Uniform3iv(WebGLUniformLocation* loc, const T& arr) {
|
||||
UniformNiv("uniform3iv", 3, loc, IntArr(arr));
|
||||
}
|
||||
template<typename T>
|
||||
void Uniform4iv(WebGLUniformLocation* loc, const T& arr) {
|
||||
UniformNiv("uniform4iv", 4, loc, IntArr(arr));
|
||||
}
|
||||
|
||||
//////
|
||||
|
||||
template<typename T>
|
||||
void Uniform1fv(WebGLUniformLocation* loc, const T& arr) {
|
||||
UniformNfv("uniform1fv", 1, loc, FloatArr(arr));
|
||||
}
|
||||
template<typename T>
|
||||
void Uniform2fv(WebGLUniformLocation* loc, const T& arr) {
|
||||
UniformNfv("uniform2fv", 2, loc, FloatArr(arr));
|
||||
}
|
||||
template<typename T>
|
||||
void Uniform3fv(WebGLUniformLocation* loc, const T& arr) {
|
||||
UniformNfv("uniform3fv", 3, loc, FloatArr(arr));
|
||||
}
|
||||
template<typename T>
|
||||
void Uniform4fv(WebGLUniformLocation* loc, const T& arr) {
|
||||
UniformNfv("uniform4fv", 4, loc, FloatArr(arr));
|
||||
}
|
||||
|
||||
//////
|
||||
|
||||
template<typename T>
|
||||
void UniformMatrix2fv(WebGLUniformLocation* loc, bool transpose, const T& arr) {
|
||||
UniformMatrixAxBfv("uniformMatrix2fv", 2, 2, loc, transpose, FloatArr(arr));
|
||||
}
|
||||
template<typename T>
|
||||
void UniformMatrix3fv(WebGLUniformLocation* loc, bool transpose, const T& arr) {
|
||||
UniformMatrixAxBfv("uniformMatrix3fv", 3, 3, loc, transpose, FloatArr(arr));
|
||||
}
|
||||
template<typename T>
|
||||
void UniformMatrix4fv(WebGLUniformLocation* loc, bool transpose, const T& arr) {
|
||||
UniformMatrixAxBfv("uniformMatrix4fv", 4, 4, loc, transpose, FloatArr(arr));
|
||||
}
|
||||
|
||||
////////////////////////////////////
|
||||
|
||||
void UseProgram(WebGLProgram* prog);
|
||||
|
||||
|
@ -726,22 +679,19 @@ public:
|
|||
uint32_t arrayLength);
|
||||
bool ValidateUniformLocation(WebGLUniformLocation* loc, const char* funcName);
|
||||
bool ValidateUniformSetter(WebGLUniformLocation* loc, uint8_t setterSize,
|
||||
GLenum setterType, const char* info,
|
||||
GLuint* out_rawLoc);
|
||||
GLenum setterType, const char* funcName);
|
||||
bool ValidateUniformArraySetter(WebGLUniformLocation* loc,
|
||||
uint8_t setterElemSize, GLenum setterType,
|
||||
size_t setterArraySize, const char* info,
|
||||
GLuint* out_rawLoc,
|
||||
GLsizei* out_numElementsToUpload);
|
||||
uint32_t setterArraySize, const char* funcName,
|
||||
uint32_t* out_numElementsToUpload);
|
||||
bool ValidateUniformMatrixArraySetter(WebGLUniformLocation* loc,
|
||||
uint8_t setterCols,
|
||||
uint8_t setterRows,
|
||||
GLenum setterType,
|
||||
size_t setterArraySize,
|
||||
uint32_t setterArraySize,
|
||||
bool setterTranspose,
|
||||
const char* info,
|
||||
GLuint* out_rawLoc,
|
||||
GLsizei* out_numElementsToUpload);
|
||||
const char* funcName,
|
||||
uint32_t* out_numElementsToUpload);
|
||||
void ValidateProgram(WebGLProgram* prog);
|
||||
bool ValidateUniformLocation(const char* info, WebGLUniformLocation* loc);
|
||||
bool ValidateSamplerUniformSetter(const char* info,
|
||||
|
@ -1603,6 +1553,9 @@ public:
|
|||
virtual UniquePtr<webgl::FormatUsageAuthority>
|
||||
CreateFormatUsage(gl::GLContext* gl) const = 0;
|
||||
|
||||
|
||||
const decltype(mBound2DTextures)* TexListForElemType(GLenum elemType) const;
|
||||
|
||||
// Friend list
|
||||
friend class ScopedCopyTexImageSource;
|
||||
friend class ScopedResolveTexturesForDraw;
|
||||
|
@ -1611,6 +1564,7 @@ public:
|
|||
friend class webgl::TexUnpackBytes;
|
||||
friend class webgl::TexUnpackImage;
|
||||
friend class webgl::TexUnpackSurface;
|
||||
friend struct webgl::UniformInfo;
|
||||
friend class WebGLTexture;
|
||||
friend class WebGLFBAttachPoint;
|
||||
friend class WebGLFramebuffer;
|
||||
|
|
|
@ -42,26 +42,95 @@ public:
|
|||
~ScopedResolveTexturesForDraw();
|
||||
};
|
||||
|
||||
bool
|
||||
WebGLTexture::IsFeedback(WebGLContext* webgl, const char* funcName, uint32_t texUnit,
|
||||
const std::vector<const WebGLFBAttachPoint*>& fbAttachments) const
|
||||
{
|
||||
auto itr = fbAttachments.cbegin();
|
||||
for (; itr != fbAttachments.cend(); ++itr) {
|
||||
const auto& attach = *itr;
|
||||
if (attach->Texture() == this)
|
||||
break;
|
||||
}
|
||||
|
||||
if (itr == fbAttachments.cend())
|
||||
return false;
|
||||
|
||||
////
|
||||
|
||||
const auto minLevel = mBaseMipmapLevel;
|
||||
uint32_t maxLevel;
|
||||
if (!MaxEffectiveMipmapLevel(texUnit, &maxLevel)) {
|
||||
// No valid mips. Will need fake-black.
|
||||
return false;
|
||||
}
|
||||
|
||||
////
|
||||
|
||||
for (; itr != fbAttachments.cend(); ++itr) {
|
||||
const auto& attach = *itr;
|
||||
if (attach->Texture() != this)
|
||||
continue;
|
||||
|
||||
const auto dstLevel = attach->MipLevel();
|
||||
|
||||
if (minLevel <= dstLevel && dstLevel <= maxLevel) {
|
||||
webgl->ErrorInvalidOperation("%s: Feedback loop detected between tex target"
|
||||
" 0x%04x, tex unit %u, levels %u-%u; and"
|
||||
" framebuffer attachment 0x%04x, level %u.",
|
||||
funcName, mTarget.get(), texUnit, minLevel,
|
||||
maxLevel, attach->mAttachmentPoint, dstLevel);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
ScopedResolveTexturesForDraw::ScopedResolveTexturesForDraw(WebGLContext* webgl,
|
||||
const char* funcName,
|
||||
bool* const out_error)
|
||||
: mWebGL(webgl)
|
||||
{
|
||||
MOZ_ASSERT(webgl->gl->IsCurrent());
|
||||
MOZ_ASSERT(mWebGL->gl->IsCurrent());
|
||||
|
||||
typedef decltype(WebGLContext::mBound2DTextures) TexturesT;
|
||||
if (!mWebGL->mActiveProgramLinkInfo) {
|
||||
mWebGL->ErrorInvalidOperation("%s: The current program is not linked.", funcName);
|
||||
*out_error = true;
|
||||
return;
|
||||
}
|
||||
|
||||
const auto fnResolveAll = [this, funcName](const TexturesT& textures)
|
||||
{
|
||||
const auto len = textures.Length();
|
||||
for (uint32_t texUnit = 0; texUnit < len; ++texUnit) {
|
||||
WebGLTexture* tex = textures[texUnit];
|
||||
std::vector<const WebGLFBAttachPoint*> fbAttachments;
|
||||
if (mWebGL->mBoundDrawFramebuffer) {
|
||||
const auto& fb = mWebGL->mBoundDrawFramebuffer;
|
||||
fb->GatherAttachments(&fbAttachments);
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mWebGL->mActiveProgramLinkInfo);
|
||||
const auto& uniformSamplers = mWebGL->mActiveProgramLinkInfo->uniformSamplers;
|
||||
for (const auto& uniform : uniformSamplers) {
|
||||
const auto& texList = *(uniform->mSamplerTexList);
|
||||
|
||||
for (const auto& texUnit : uniform->mSamplerValues) {
|
||||
if (texUnit >= texList.Length())
|
||||
continue;
|
||||
|
||||
const auto& tex = texList[texUnit];
|
||||
if (!tex)
|
||||
continue;
|
||||
|
||||
if (tex->IsFeedback(mWebGL, funcName, texUnit, fbAttachments)) {
|
||||
*out_error = true;
|
||||
return;
|
||||
}
|
||||
|
||||
FakeBlackType fakeBlack;
|
||||
if (!tex->ResolveForDraw(funcName, texUnit, &fakeBlack))
|
||||
return false;
|
||||
if (!tex->ResolveForDraw(funcName, texUnit, &fakeBlack)) {
|
||||
mWebGL->ErrorOutOfMemory("%s: Failed to resolve textures for draw.",
|
||||
funcName);
|
||||
*out_error = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (fakeBlack == FakeBlackType::None)
|
||||
continue;
|
||||
|
@ -69,21 +138,9 @@ ScopedResolveTexturesForDraw::ScopedResolveTexturesForDraw(WebGLContext* webgl,
|
|||
mWebGL->BindFakeBlack(texUnit, tex->Target(), fakeBlack);
|
||||
mRebindRequests.push_back({texUnit, tex});
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
bool ok = true;
|
||||
ok &= fnResolveAll(mWebGL->mBound2DTextures);
|
||||
ok &= fnResolveAll(mWebGL->mBoundCubeMapTextures);
|
||||
ok &= fnResolveAll(mWebGL->mBound3DTextures);
|
||||
ok &= fnResolveAll(mWebGL->mBound2DArrayTextures);
|
||||
|
||||
if (!ok) {
|
||||
mWebGL->ErrorOutOfMemory("%s: Failed to resolve textures for draw.", funcName);
|
||||
}
|
||||
|
||||
*out_error = !ok;
|
||||
*out_error = false;
|
||||
}
|
||||
|
||||
ScopedResolveTexturesForDraw::~ScopedResolveTexturesForDraw()
|
||||
|
@ -195,12 +252,6 @@ WebGLContext::DrawArrays_check(GLint first, GLsizei count, GLsizei primcount,
|
|||
return false;
|
||||
}
|
||||
|
||||
// Any checks below this depend on a program being available.
|
||||
if (!mCurrentProgram) {
|
||||
ErrorInvalidOperation("%s: null CURRENT_PROGRAM", info);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ValidateBufferFetching(info)) {
|
||||
return false;
|
||||
}
|
||||
|
@ -360,14 +411,6 @@ WebGLContext::DrawElements_check(GLsizei count, GLenum type,
|
|||
return false;
|
||||
}
|
||||
|
||||
// Any checks below this depend on mActiveProgramLinkInfo being available.
|
||||
if (!mActiveProgramLinkInfo) {
|
||||
// Technically, this will only be null iff CURRENT_PROGRAM is null.
|
||||
// But it's better to branch on what we actually care about.
|
||||
ErrorInvalidOperation("%s: null CURRENT_PROGRAM", info);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!mBoundVertexArray->mElementArrayBuffer) {
|
||||
ErrorInvalidOperation("%s: must have element array buffer binding", info);
|
||||
return false;
|
||||
|
@ -603,8 +646,8 @@ WebGLContext::ValidateBufferFetching(const char* info)
|
|||
|
||||
mBufferFetch_IsAttrib0Active = false;
|
||||
|
||||
for (const auto& pair : mActiveProgramLinkInfo->activeAttribLocs) {
|
||||
const uint32_t attribLoc = pair.second;
|
||||
for (const auto& attrib : mActiveProgramLinkInfo->attribs) {
|
||||
const auto& attribLoc = attrib.mLoc;
|
||||
|
||||
if (attribLoc >= attribCount)
|
||||
continue;
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -437,7 +437,7 @@ WebGLContext::ValidateUniformLocation(WebGLUniformLocation* loc, const char* fun
|
|||
return false;
|
||||
}
|
||||
|
||||
return loc->ValidateForProgram(mCurrentProgram, this, funcName);
|
||||
return loc->ValidateForProgram(mCurrentProgram, funcName);
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -459,7 +459,7 @@ WebGLContext::ValidateAttribArraySetter(const char* name, uint32_t setterElemSiz
|
|||
bool
|
||||
WebGLContext::ValidateUniformSetter(WebGLUniformLocation* loc,
|
||||
uint8_t setterElemSize, GLenum setterType,
|
||||
const char* funcName, GLuint* out_rawLoc)
|
||||
const char* funcName)
|
||||
{
|
||||
if (IsContextLost())
|
||||
return false;
|
||||
|
@ -467,10 +467,9 @@ WebGLContext::ValidateUniformSetter(WebGLUniformLocation* loc,
|
|||
if (!ValidateUniformLocation(loc, funcName))
|
||||
return false;
|
||||
|
||||
if (!loc->ValidateSizeAndType(setterElemSize, setterType, this, funcName))
|
||||
if (!loc->ValidateSizeAndType(setterElemSize, setterType, funcName))
|
||||
return false;
|
||||
|
||||
*out_rawLoc = loc->mLoc;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -478,10 +477,9 @@ bool
|
|||
WebGLContext::ValidateUniformArraySetter(WebGLUniformLocation* loc,
|
||||
uint8_t setterElemSize,
|
||||
GLenum setterType,
|
||||
size_t setterArraySize,
|
||||
uint32_t setterArraySize,
|
||||
const char* funcName,
|
||||
GLuint* const out_rawLoc,
|
||||
GLsizei* const out_numElementsToUpload)
|
||||
uint32_t* const out_numElementsToUpload)
|
||||
{
|
||||
if (IsContextLost())
|
||||
return false;
|
||||
|
@ -489,16 +487,18 @@ WebGLContext::ValidateUniformArraySetter(WebGLUniformLocation* loc,
|
|||
if (!ValidateUniformLocation(loc, funcName))
|
||||
return false;
|
||||
|
||||
if (!loc->ValidateSizeAndType(setterElemSize, setterType, this, funcName))
|
||||
if (!loc->ValidateSizeAndType(setterElemSize, setterType, funcName))
|
||||
return false;
|
||||
|
||||
if (!loc->ValidateArrayLength(setterElemSize, setterArraySize, this, funcName))
|
||||
if (!loc->ValidateArrayLength(setterElemSize, setterArraySize, funcName))
|
||||
return false;
|
||||
|
||||
MOZ_ASSERT((size_t)loc->mActiveInfo->mElemCount > loc->mArrayIndex);
|
||||
size_t uniformElemCount = loc->mActiveInfo->mElemCount - loc->mArrayIndex;
|
||||
*out_rawLoc = loc->mLoc;
|
||||
*out_numElementsToUpload = std::min(uniformElemCount, setterArraySize / setterElemSize);
|
||||
const auto& elemCount = loc->mInfo->mActiveInfo->mElemCount;
|
||||
MOZ_ASSERT(elemCount > loc->mArrayIndex);
|
||||
const uint32_t uniformElemCount = elemCount - loc->mArrayIndex;
|
||||
|
||||
*out_numElementsToUpload = std::min(uniformElemCount,
|
||||
setterArraySize / setterElemSize);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -507,13 +507,12 @@ WebGLContext::ValidateUniformMatrixArraySetter(WebGLUniformLocation* loc,
|
|||
uint8_t setterCols,
|
||||
uint8_t setterRows,
|
||||
GLenum setterType,
|
||||
size_t setterArraySize,
|
||||
uint32_t setterArraySize,
|
||||
bool setterTranspose,
|
||||
const char* funcName,
|
||||
GLuint* const out_rawLoc,
|
||||
GLsizei* const out_numElementsToUpload)
|
||||
uint32_t* const out_numElementsToUpload)
|
||||
{
|
||||
uint8_t setterElemSize = setterCols * setterRows;
|
||||
const uint8_t setterElemSize = setterCols * setterRows;
|
||||
|
||||
if (IsContextLost())
|
||||
return false;
|
||||
|
@ -521,20 +520,21 @@ WebGLContext::ValidateUniformMatrixArraySetter(WebGLUniformLocation* loc,
|
|||
if (!ValidateUniformLocation(loc, funcName))
|
||||
return false;
|
||||
|
||||
if (!loc->ValidateSizeAndType(setterElemSize, setterType, this, funcName))
|
||||
if (!loc->ValidateSizeAndType(setterElemSize, setterType, funcName))
|
||||
return false;
|
||||
|
||||
if (!loc->ValidateArrayLength(setterElemSize, setterArraySize, this, funcName))
|
||||
if (!loc->ValidateArrayLength(setterElemSize, setterArraySize, funcName))
|
||||
return false;
|
||||
|
||||
if (!ValidateUniformMatrixTranspose(setterTranspose, funcName))
|
||||
return false;
|
||||
|
||||
MOZ_ASSERT((size_t)loc->mActiveInfo->mElemCount > loc->mArrayIndex);
|
||||
size_t uniformElemCount = loc->mActiveInfo->mElemCount - loc->mArrayIndex;
|
||||
*out_rawLoc = loc->mLoc;
|
||||
*out_numElementsToUpload = std::min(uniformElemCount, setterArraySize / setterElemSize);
|
||||
const auto& elemCount = loc->mInfo->mActiveInfo->mElemCount;
|
||||
MOZ_ASSERT(elemCount > loc->mArrayIndex);
|
||||
const uint32_t uniformElemCount = elemCount - loc->mArrayIndex;
|
||||
|
||||
*out_numElementsToUpload = std::min(uniformElemCount,
|
||||
setterArraySize / setterElemSize);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -440,24 +440,28 @@ FormatInfo::GetCopyDecayFormat(UnsizedFormat uf) const
|
|||
return FindOrNull(this->copyDecayFormats, uf);
|
||||
}
|
||||
|
||||
uint8_t
|
||||
BytesPerPixel(const PackingInfo& packing)
|
||||
bool
|
||||
GetBytesPerPixel(const PackingInfo& packing, uint8_t* const out_bytes)
|
||||
{
|
||||
uint8_t bytesPerChannel;
|
||||
|
||||
switch (packing.type) {
|
||||
case LOCAL_GL_UNSIGNED_SHORT_4_4_4_4:
|
||||
case LOCAL_GL_UNSIGNED_SHORT_5_5_5_1:
|
||||
case LOCAL_GL_UNSIGNED_SHORT_5_6_5:
|
||||
return 2;
|
||||
*out_bytes = 2;
|
||||
return true;
|
||||
|
||||
case LOCAL_GL_UNSIGNED_INT_10F_11F_11F_REV:
|
||||
case LOCAL_GL_UNSIGNED_INT_2_10_10_10_REV:
|
||||
case LOCAL_GL_UNSIGNED_INT_24_8:
|
||||
case LOCAL_GL_UNSIGNED_INT_5_9_9_9_REV:
|
||||
return 4;
|
||||
*out_bytes = 4;
|
||||
return true;
|
||||
|
||||
case LOCAL_GL_FLOAT_32_UNSIGNED_INT_24_8_REV:
|
||||
return 8;
|
||||
*out_bytes = 8;
|
||||
return true;
|
||||
|
||||
// Alright, that's all the fixed-size unpackTypes.
|
||||
|
||||
|
@ -480,11 +484,20 @@ BytesPerPixel(const PackingInfo& packing)
|
|||
break;
|
||||
|
||||
default:
|
||||
MOZ_CRASH("GFX: invalid PackingInfo");
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t channels;
|
||||
|
||||
switch (packing.format) {
|
||||
case LOCAL_GL_RED:
|
||||
case LOCAL_GL_RED_INTEGER:
|
||||
case LOCAL_GL_LUMINANCE:
|
||||
case LOCAL_GL_ALPHA:
|
||||
case LOCAL_GL_DEPTH_COMPONENT:
|
||||
channels = 1;
|
||||
break;
|
||||
|
||||
case LOCAL_GL_RG:
|
||||
case LOCAL_GL_RG_INTEGER:
|
||||
case LOCAL_GL_LUMINANCE_ALPHA:
|
||||
|
@ -493,23 +506,36 @@ BytesPerPixel(const PackingInfo& packing)
|
|||
|
||||
case LOCAL_GL_RGB:
|
||||
case LOCAL_GL_RGB_INTEGER:
|
||||
case LOCAL_GL_SRGB:
|
||||
channels = 3;
|
||||
break;
|
||||
|
||||
case LOCAL_GL_BGRA:
|
||||
case LOCAL_GL_RGBA:
|
||||
case LOCAL_GL_RGBA_INTEGER:
|
||||
case LOCAL_GL_SRGB_ALPHA:
|
||||
channels = 4;
|
||||
break;
|
||||
|
||||
default:
|
||||
channels = 1;
|
||||
break;
|
||||
return false;
|
||||
}
|
||||
|
||||
return bytesPerChannel * channels;
|
||||
*out_bytes = bytesPerChannel * channels;
|
||||
return true;
|
||||
}
|
||||
|
||||
uint8_t
|
||||
BytesPerPixel(const PackingInfo& packing)
|
||||
{
|
||||
uint8_t ret;
|
||||
if (MOZ_LIKELY(GetBytesPerPixel(packing, &ret)))
|
||||
return ret;
|
||||
|
||||
gfxCriticalError() << "Bad `packing`: " << gfx::hexa(packing.format) << ", "
|
||||
<< gfx::hexa(packing.type);
|
||||
MOZ_CRASH("Bad `packing`.");
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -254,6 +254,7 @@ struct DriverUnpackInfo
|
|||
|
||||
const FormatInfo* GetFormat(EffectiveFormat format);
|
||||
uint8_t BytesPerPixel(const PackingInfo& packing);
|
||||
bool GetBytesPerPixel(const PackingInfo& packing, uint8_t* const out_bytes);
|
||||
/*
|
||||
GLint ComponentSize(const FormatInfo* format, GLenum component);
|
||||
GLenum ComponentType(const FormatInfo* format);
|
||||
|
|
|
@ -1281,6 +1281,34 @@ WebGLFramebuffer::GetAttachmentParameter(const char* funcName, JSContext* cx,
|
|||
out_error);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
WebGLFramebuffer::GatherAttachments(std::vector<const WebGLFBAttachPoint*>* const out) const
|
||||
{
|
||||
auto itr = mDrawBuffers.cbegin();
|
||||
if (itr != mDrawBuffers.cend() &&
|
||||
*itr != LOCAL_GL_NONE)
|
||||
{
|
||||
out->push_back(&mColorAttachment0);
|
||||
++itr;
|
||||
}
|
||||
|
||||
size_t i = 0;
|
||||
for (; itr != mDrawBuffers.cend(); ++itr) {
|
||||
if (i >= mMoreColorAttachments.Size())
|
||||
break;
|
||||
|
||||
if (*itr != LOCAL_GL_NONE) {
|
||||
out->push_back(&mMoreColorAttachments[i]);
|
||||
}
|
||||
++i;
|
||||
}
|
||||
|
||||
out->push_back(&mDepthAttachment);
|
||||
out->push_back(&mStencilAttachment);
|
||||
out->push_back(&mDepthStencilAttachment);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Goop.
|
||||
|
||||
|
|
|
@ -38,7 +38,7 @@ private:
|
|||
WebGLRefPtr<WebGLRenderbuffer> mRenderbufferPtr;
|
||||
TexImageTarget mTexImageTarget;
|
||||
GLint mTexImageLayer;
|
||||
GLint mTexImageLevel;
|
||||
uint32_t mTexImageLevel;
|
||||
|
||||
// PlacementArray needs a default constructor.
|
||||
template<typename T>
|
||||
|
@ -89,7 +89,7 @@ public:
|
|||
GLint Layer() const {
|
||||
return mTexImageLayer;
|
||||
}
|
||||
GLint MipLevel() const {
|
||||
uint32_t MipLevel() const {
|
||||
return mTexImageLevel;
|
||||
}
|
||||
void AttachmentName(nsCString* out) const;
|
||||
|
@ -259,6 +259,8 @@ public:
|
|||
|
||||
GLenum ReadBufferMode() const { return mReadBufferMode; }
|
||||
|
||||
void GatherAttachments(std::vector<const WebGLFBAttachPoint*>* const out) const;
|
||||
|
||||
protected:
|
||||
WebGLFBAttachPoint* GetAttachPoint(GLenum attachment); // Fallible
|
||||
|
||||
|
|
|
@ -69,36 +69,60 @@ ParseName(const nsCString& name, nsCString* const out_baseName,
|
|||
return true;
|
||||
}
|
||||
|
||||
static WebGLActiveInfo*
|
||||
AddActiveInfo(WebGLContext* webgl, GLint elemCount, GLenum elemType, bool isArray,
|
||||
const nsACString& baseUserName, const nsACString& baseMappedName,
|
||||
std::vector<RefPtr<WebGLActiveInfo>>* activeInfoList,
|
||||
std::map<nsCString, const WebGLActiveInfo*>* infoLocMap)
|
||||
{
|
||||
RefPtr<WebGLActiveInfo> info = new WebGLActiveInfo(webgl, elemCount, elemType,
|
||||
isArray, baseUserName,
|
||||
baseMappedName);
|
||||
activeInfoList->push_back(info);
|
||||
//////////
|
||||
|
||||
infoLocMap->insert(std::make_pair(info->mBaseUserName, info.get()));
|
||||
return info.get();
|
||||
/*static*/ const webgl::UniformInfo::TexListT*
|
||||
webgl::UniformInfo::GetTexList(WebGLActiveInfo* activeInfo)
|
||||
{
|
||||
const auto& webgl = activeInfo->mWebGL;
|
||||
|
||||
switch (activeInfo->mElemType) {
|
||||
case LOCAL_GL_SAMPLER_2D:
|
||||
case LOCAL_GL_SAMPLER_2D_SHADOW:
|
||||
case LOCAL_GL_INT_SAMPLER_2D:
|
||||
case LOCAL_GL_UNSIGNED_INT_SAMPLER_2D:
|
||||
return &webgl->mBound2DTextures;
|
||||
|
||||
case LOCAL_GL_SAMPLER_CUBE:
|
||||
case LOCAL_GL_SAMPLER_CUBE_SHADOW:
|
||||
case LOCAL_GL_INT_SAMPLER_CUBE:
|
||||
case LOCAL_GL_UNSIGNED_INT_SAMPLER_CUBE:
|
||||
return &webgl->mBoundCubeMapTextures;
|
||||
|
||||
case LOCAL_GL_SAMPLER_3D:
|
||||
case LOCAL_GL_INT_SAMPLER_3D:
|
||||
case LOCAL_GL_UNSIGNED_INT_SAMPLER_3D:
|
||||
return &webgl->mBound3DTextures;
|
||||
|
||||
case LOCAL_GL_SAMPLER_2D_ARRAY:
|
||||
case LOCAL_GL_SAMPLER_2D_ARRAY_SHADOW:
|
||||
case LOCAL_GL_INT_SAMPLER_2D_ARRAY:
|
||||
case LOCAL_GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
|
||||
return &webgl->mBound2DArrayTextures;
|
||||
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
AddActiveBlockInfo(const nsACString& baseUserName,
|
||||
const nsACString& baseMappedName,
|
||||
std::vector<RefPtr<webgl::UniformBlockInfo>>* activeInfoList)
|
||||
webgl::UniformInfo::UniformInfo(WebGLActiveInfo* activeInfo)
|
||||
: mActiveInfo(activeInfo)
|
||||
, mSamplerTexList(GetTexList(activeInfo))
|
||||
{
|
||||
RefPtr<webgl::UniformBlockInfo> info = new webgl::UniformBlockInfo(baseUserName, baseMappedName);
|
||||
|
||||
activeInfoList->push_back(info);
|
||||
if (mSamplerTexList) {
|
||||
mSamplerValues.assign(mActiveInfo->mElemCount, 0);
|
||||
}
|
||||
}
|
||||
|
||||
//////////
|
||||
|
||||
//#define DUMP_SHADERVAR_MAPPINGS
|
||||
|
||||
static already_AddRefed<const webgl::LinkedProgramInfo>
|
||||
QueryProgramInfo(WebGLProgram* prog, gl::GLContext* gl)
|
||||
{
|
||||
WebGLContext* const webgl = prog->mContext;
|
||||
|
||||
RefPtr<webgl::LinkedProgramInfo> info(new webgl::LinkedProgramInfo(prog));
|
||||
|
||||
GLuint maxAttribLenWithNull = 0;
|
||||
|
@ -154,33 +178,37 @@ QueryProgramInfo(WebGLProgram* prog, gl::GLContext* gl)
|
|||
|
||||
mappedName.SetLength(lengthWithoutNull);
|
||||
|
||||
// Collect ActiveInfos:
|
||||
|
||||
// Attribs can't be arrays, so we can skip some of the mess we have in the Uniform
|
||||
// path.
|
||||
nsDependentCString userName;
|
||||
if (!prog->FindAttribUserNameByMappedName(mappedName, &userName))
|
||||
userName.Rebind(mappedName, 0);
|
||||
|
||||
///////
|
||||
|
||||
const GLint loc = gl->fGetAttribLocation(prog->mGLName,
|
||||
mappedName.BeginReading());
|
||||
if (loc == -1) {
|
||||
MOZ_ASSERT(mappedName == "gl_InstanceID",
|
||||
"Active attrib should have a location.");
|
||||
continue;
|
||||
}
|
||||
|
||||
#ifdef DUMP_SHADERVAR_MAPPINGS
|
||||
printf_stderr("[attrib %i] %s/%s\n", i, mappedName.BeginReading(),
|
||||
printf_stderr("[attrib %i: %i] %s/%s\n", i, loc, mappedName.BeginReading(),
|
||||
userName.BeginReading());
|
||||
printf_stderr(" lengthWithoutNull: %d\n", lengthWithoutNull);
|
||||
#endif
|
||||
|
||||
const bool isArray = false;
|
||||
const auto attrib = AddActiveInfo(prog->mContext, elemCount, elemType, isArray,
|
||||
userName, mappedName, &info->activeAttribs,
|
||||
&info->attribMap);
|
||||
///////
|
||||
|
||||
// Collect active locations:
|
||||
GLint loc = gl->fGetAttribLocation(prog->mGLName, mappedName.BeginReading());
|
||||
if (loc == -1) {
|
||||
if (mappedName != "gl_InstanceID")
|
||||
MOZ_CRASH("GFX: Active attrib has no location.");
|
||||
} else {
|
||||
info->activeAttribLocs.insert({attrib, (GLuint)loc});
|
||||
}
|
||||
const bool isArray = false;
|
||||
const RefPtr<WebGLActiveInfo> activeInfo = new WebGLActiveInfo(webgl, elemCount,
|
||||
elemType, isArray,
|
||||
userName,
|
||||
mappedName);
|
||||
const webgl::AttribInfo attrib = {activeInfo, uint32_t(loc)};
|
||||
info->attribs.push_back(attrib);
|
||||
}
|
||||
|
||||
// Uniforms
|
||||
|
@ -203,6 +231,8 @@ QueryProgramInfo(WebGLProgram* prog, gl::GLContext* gl)
|
|||
|
||||
mappedName.SetLength(lengthWithoutNull);
|
||||
|
||||
///////
|
||||
|
||||
nsAutoCString baseMappedName;
|
||||
bool isArray;
|
||||
size_t arrayIndex;
|
||||
|
@ -212,8 +242,11 @@ QueryProgramInfo(WebGLProgram* prog, gl::GLContext* gl)
|
|||
// Note that for good drivers, `isArray` should already be correct.
|
||||
// However, if FindUniform succeeds, it will be validator-guaranteed correct.
|
||||
|
||||
///////
|
||||
|
||||
nsAutoCString baseUserName;
|
||||
if (!prog->FindUniformByMappedName(baseMappedName, &baseUserName, &isArray)) {
|
||||
// Validator likely missing.
|
||||
baseUserName = baseMappedName;
|
||||
|
||||
if (needsCheckForArrays && !isArray) {
|
||||
|
@ -229,6 +262,8 @@ QueryProgramInfo(WebGLProgram* prog, gl::GLContext* gl)
|
|||
}
|
||||
}
|
||||
|
||||
///////
|
||||
|
||||
#ifdef DUMP_SHADERVAR_MAPPINGS
|
||||
printf_stderr("[uniform %i] %s/%i/%s/%s\n", i, mappedName.BeginReading(),
|
||||
(int)isArray, baseMappedName.BeginReading(),
|
||||
|
@ -237,11 +272,23 @@ QueryProgramInfo(WebGLProgram* prog, gl::GLContext* gl)
|
|||
printf_stderr(" isArray: %d\n", (int)isArray);
|
||||
#endif
|
||||
|
||||
AddActiveInfo(prog->mContext, elemCount, elemType, isArray, baseUserName,
|
||||
baseMappedName, &info->activeUniforms, &info->uniformMap);
|
||||
///////
|
||||
|
||||
const RefPtr<WebGLActiveInfo> activeInfo = new WebGLActiveInfo(webgl, elemCount,
|
||||
elemType, isArray,
|
||||
baseUserName,
|
||||
baseMappedName);
|
||||
|
||||
auto* uniform = new webgl::UniformInfo(activeInfo);
|
||||
info->uniforms.push_back(uniform);
|
||||
|
||||
if (uniform->mSamplerTexList) {
|
||||
info->uniformSamplers.push_back(uniform);
|
||||
}
|
||||
}
|
||||
|
||||
// Uniform Blocks
|
||||
// (no sampler types allowed!)
|
||||
|
||||
if (gl->IsSupported(gl::GLFeature::uniform_buffer_object)) {
|
||||
GLuint numActiveUniformBlocks = 0;
|
||||
|
@ -281,14 +328,15 @@ QueryProgramInfo(WebGLProgram* prog, gl::GLContext* gl)
|
|||
}
|
||||
|
||||
#ifdef DUMP_SHADERVAR_MAPPINGS
|
||||
printf_stderr("[uniform block %i] %s/%i/%s/%s\n", i, mappedName.BeginReading(),
|
||||
(int)isArray, baseMappedName.BeginReading(),
|
||||
baseUserName.BeginReading());
|
||||
printf_stderr("[uniform block %i] %s/%i/%s/%s\n", i,
|
||||
mappedName.BeginReading(), (int)isArray,
|
||||
baseMappedName.BeginReading(), baseUserName.BeginReading());
|
||||
printf_stderr(" lengthWithoutNull: %d\n", lengthWithoutNull);
|
||||
printf_stderr(" isArray: %d\n", (int)isArray);
|
||||
#endif
|
||||
|
||||
AddActiveBlockInfo(baseUserName, baseMappedName, &info->uniformBlocks);
|
||||
const auto* block = new webgl::UniformBlockInfo(baseUserName, baseMappedName);
|
||||
info->uniformBlocks.push_back(block);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -304,19 +352,23 @@ QueryProgramInfo(WebGLProgram* prog, gl::GLContext* gl)
|
|||
mappedName.SetLength(maxTransformFeedbackVaryingLenWithNull - 1);
|
||||
|
||||
GLint lengthWithoutNull;
|
||||
GLsizei size;
|
||||
GLenum type;
|
||||
gl->fGetTransformFeedbackVarying(prog->mGLName, i, maxTransformFeedbackVaryingLenWithNull,
|
||||
&lengthWithoutNull, &size, &type,
|
||||
GLsizei elemCount;
|
||||
GLenum elemType;
|
||||
gl->fGetTransformFeedbackVarying(prog->mGLName, i,
|
||||
maxTransformFeedbackVaryingLenWithNull,
|
||||
&lengthWithoutNull, &elemCount, &elemType,
|
||||
mappedName.BeginWriting());
|
||||
mappedName.SetLength(lengthWithoutNull);
|
||||
|
||||
////
|
||||
|
||||
nsAutoCString baseMappedName;
|
||||
bool isArray;
|
||||
size_t arrayIndex;
|
||||
if (!ParseName(mappedName, &baseMappedName, &isArray, &arrayIndex))
|
||||
MOZ_CRASH("GFX: Failed to parse `mappedName` received from driver.");
|
||||
|
||||
|
||||
nsAutoCString baseUserName;
|
||||
if (!prog->FindVaryingByMappedName(mappedName, &baseUserName, &isArray)) {
|
||||
baseUserName = baseMappedName;
|
||||
|
@ -332,9 +384,15 @@ QueryProgramInfo(WebGLProgram* prog, gl::GLContext* gl)
|
|||
}
|
||||
}
|
||||
|
||||
AddActiveInfo(prog->mContext, size, type, isArray, baseUserName, mappedName,
|
||||
&info->transformFeedbackVaryings,
|
||||
&info->transformFeedbackVaryingsMap);
|
||||
////
|
||||
|
||||
const RefPtr<WebGLActiveInfo> activeInfo = new WebGLActiveInfo(webgl,
|
||||
elemCount,
|
||||
elemType,
|
||||
isArray,
|
||||
baseUserName,
|
||||
mappedName);
|
||||
info->transformFeedbackVaryings.push_back(activeInfo);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -347,6 +405,16 @@ webgl::LinkedProgramInfo::LinkedProgramInfo(WebGLProgram* prog)
|
|||
: prog(prog)
|
||||
{ }
|
||||
|
||||
webgl::LinkedProgramInfo::~LinkedProgramInfo()
|
||||
{
|
||||
for (auto& cur : uniforms) {
|
||||
delete cur;
|
||||
}
|
||||
for (auto& cur : uniformBlocks) {
|
||||
delete cur;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// WebGLProgram
|
||||
|
||||
|
@ -487,15 +555,15 @@ WebGLProgram::GetActiveAttrib(GLuint index) const
|
|||
return ret.forget();
|
||||
}
|
||||
|
||||
const auto& activeList = mMostRecentLinkInfo->activeAttribs;
|
||||
const auto& attribs = mMostRecentLinkInfo->attribs;
|
||||
|
||||
if (index >= activeList.size()) {
|
||||
if (index >= attribs.size()) {
|
||||
mContext->ErrorInvalidValue("`index` (%i) must be less than %s (%i).",
|
||||
index, "ACTIVE_ATTRIBS", activeList.size());
|
||||
index, "ACTIVE_ATTRIBS", attribs.size());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<WebGLActiveInfo> ret = activeList[index];
|
||||
RefPtr<WebGLActiveInfo> ret = attribs[index].mActiveInfo;
|
||||
return ret.forget();
|
||||
}
|
||||
|
||||
|
@ -508,15 +576,15 @@ WebGLProgram::GetActiveUniform(GLuint index) const
|
|||
return ret.forget();
|
||||
}
|
||||
|
||||
const auto& activeList = mMostRecentLinkInfo->activeUniforms;
|
||||
const auto& uniforms = mMostRecentLinkInfo->uniforms;
|
||||
|
||||
if (index >= activeList.size()) {
|
||||
if (index >= uniforms.size()) {
|
||||
mContext->ErrorInvalidValue("`index` (%i) must be less than %s (%i).",
|
||||
index, "ACTIVE_UNIFORMS", activeList.size());
|
||||
index, "ACTIVE_UNIFORMS", uniforms.size());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<WebGLActiveInfo> ret = activeList[index];
|
||||
RefPtr<WebGLActiveInfo> ret = uniforms[index]->mActiveInfo;
|
||||
return ret.forget();
|
||||
}
|
||||
|
||||
|
@ -545,16 +613,11 @@ WebGLProgram::GetAttribLocation(const nsAString& userName_wide) const
|
|||
|
||||
const NS_LossyConvertUTF16toASCII userName(userName_wide);
|
||||
|
||||
const WebGLActiveInfo* info;
|
||||
const webgl::AttribInfo* info;
|
||||
if (!LinkInfo()->FindAttrib(userName, &info))
|
||||
return -1;
|
||||
|
||||
const nsCString& mappedName = info->mBaseMappedName;
|
||||
|
||||
gl::GLContext* gl = mContext->GL();
|
||||
gl->MakeCurrent();
|
||||
|
||||
return gl->fGetAttribLocation(mGLName, mappedName.BeginReading());
|
||||
return GLint(info->mLoc);
|
||||
}
|
||||
|
||||
GLint
|
||||
|
@ -658,13 +721,12 @@ WebGLProgram::GetUniformBlockIndex(const nsAString& userName_wide) const
|
|||
if (!ParseName(userName, &baseUserName, &isArray, &arrayIndex))
|
||||
return LOCAL_GL_INVALID_INDEX;
|
||||
|
||||
RefPtr<const webgl::UniformBlockInfo> info;
|
||||
const webgl::UniformBlockInfo* info;
|
||||
if (!LinkInfo()->FindUniformBlock(baseUserName, &info)) {
|
||||
return LOCAL_GL_INVALID_INDEX;
|
||||
}
|
||||
|
||||
const nsCString& baseMappedName = info->mBaseMappedName;
|
||||
nsAutoCString mappedName(baseMappedName);
|
||||
nsAutoCString mappedName(info->mBaseMappedName);
|
||||
if (isArray) {
|
||||
mappedName.AppendLiteral("[");
|
||||
mappedName.AppendInt(uint32_t(arrayIndex));
|
||||
|
@ -799,13 +861,11 @@ WebGLProgram::GetUniformLocation(const nsAString& userName_wide) const
|
|||
if (!ParseName(userName, &baseUserName, &isArray, &arrayIndex))
|
||||
return nullptr;
|
||||
|
||||
const WebGLActiveInfo* activeInfo;
|
||||
if (!LinkInfo()->FindUniform(baseUserName, &activeInfo))
|
||||
webgl::UniformInfo* info;
|
||||
if (!LinkInfo()->FindUniform(baseUserName, &info))
|
||||
return nullptr;
|
||||
|
||||
const nsCString& baseMappedName = activeInfo->mBaseMappedName;
|
||||
|
||||
nsAutoCString mappedName(baseMappedName);
|
||||
nsAutoCString mappedName(info->mActiveInfo->mBaseMappedName);
|
||||
if (isArray) {
|
||||
mappedName.AppendLiteral("[");
|
||||
mappedName.AppendInt(uint32_t(arrayIndex));
|
||||
|
@ -820,8 +880,7 @@ WebGLProgram::GetUniformLocation(const nsAString& userName_wide) const
|
|||
return nullptr;
|
||||
|
||||
RefPtr<WebGLUniformLocation> locObj = new WebGLUniformLocation(mContext, LinkInfo(),
|
||||
loc, arrayIndex,
|
||||
activeInfo);
|
||||
info, loc, arrayIndex);
|
||||
return locObj.forget();
|
||||
}
|
||||
|
||||
|
@ -846,15 +905,13 @@ WebGLProgram::GetUniformIndices(const dom::Sequence<nsString>& uniformNames,
|
|||
continue;
|
||||
}
|
||||
|
||||
const WebGLActiveInfo* activeInfo;
|
||||
if (!LinkInfo()->FindUniform(baseUserName, &activeInfo)) {
|
||||
webgl::UniformInfo* info;
|
||||
if (!LinkInfo()->FindUniform(baseUserName, &info)) {
|
||||
arr.AppendElement(LOCAL_GL_INVALID_INDEX);
|
||||
continue;
|
||||
}
|
||||
|
||||
const nsCString& baseMappedName = activeInfo->mBaseMappedName;
|
||||
|
||||
nsAutoCString mappedName(baseMappedName);
|
||||
nsAutoCString mappedName(info->mActiveInfo->mBaseMappedName);
|
||||
if (isArray) {
|
||||
mappedName.AppendLiteral("[");
|
||||
mappedName.AppendInt(uint32_t(arrayIndex));
|
||||
|
@ -879,8 +936,7 @@ WebGLProgram::UniformBlockBinding(GLuint uniformBlockIndex, GLuint uniformBlockB
|
|||
}
|
||||
|
||||
const webgl::LinkedProgramInfo* linkInfo = LinkInfo();
|
||||
GLuint uniformBlockCount = (GLuint)linkInfo->uniformBlocks.size();
|
||||
if (uniformBlockIndex >= uniformBlockCount) {
|
||||
if (uniformBlockIndex >= linkInfo->uniformBlocks.size()) {
|
||||
mContext->ErrorInvalidValue("getActiveUniformBlockName: index %u invalid.", uniformBlockIndex);
|
||||
return;
|
||||
}
|
||||
|
@ -990,49 +1046,70 @@ WebGLProgram::LinkProgram()
|
|||
}
|
||||
}
|
||||
|
||||
static uint8_t
|
||||
NumUsedLocationsByElemType(GLenum elemType)
|
||||
{
|
||||
// GLES 3.0.4 p55
|
||||
|
||||
switch (elemType) {
|
||||
case LOCAL_GL_FLOAT_MAT2:
|
||||
case LOCAL_GL_FLOAT_MAT2x3:
|
||||
case LOCAL_GL_FLOAT_MAT2x4:
|
||||
return 2;
|
||||
|
||||
case LOCAL_GL_FLOAT_MAT3x2:
|
||||
case LOCAL_GL_FLOAT_MAT3:
|
||||
case LOCAL_GL_FLOAT_MAT3x4:
|
||||
return 3;
|
||||
|
||||
case LOCAL_GL_FLOAT_MAT4x2:
|
||||
case LOCAL_GL_FLOAT_MAT4x3:
|
||||
case LOCAL_GL_FLOAT_MAT4:
|
||||
return 4;
|
||||
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
WebGLProgram::ValidateAfterTentativeLink(nsCString* const out_linkLog) const
|
||||
{
|
||||
const auto& linkInfo = mMostRecentLinkInfo;
|
||||
|
||||
// Check if the attrib name conflicting to uniform name
|
||||
for (const auto& uniform : linkInfo->uniformMap) {
|
||||
if (linkInfo->attribMap.find(uniform.first) != linkInfo->attribMap.end()) {
|
||||
*out_linkLog = nsPrintfCString("The uniform name (%s) conflicts with"
|
||||
" attribute name.",
|
||||
uniform.first.get());
|
||||
return false;
|
||||
for (const auto& attrib : linkInfo->attribs) {
|
||||
const auto& attribName = attrib.mActiveInfo->mBaseUserName;
|
||||
|
||||
for (const auto& uniform : linkInfo->uniforms) {
|
||||
const auto& uniformName = uniform->mActiveInfo->mBaseUserName;
|
||||
if (attribName == uniformName) {
|
||||
*out_linkLog = nsPrintfCString("Attrib name conflicts with uniform name:"
|
||||
" %s",
|
||||
attribName.BeginReading());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::map<GLuint, const WebGLActiveInfo*> attribsByLoc;
|
||||
for (const auto& pair : linkInfo->activeAttribLocs) {
|
||||
const auto dupe = attribsByLoc.find(pair.second);
|
||||
if (dupe != attribsByLoc.end()) {
|
||||
*out_linkLog = nsPrintfCString("Aliased location between active attribs"
|
||||
" \"%s\" and \"%s\".",
|
||||
dupe->second->mBaseUserName.BeginReading(),
|
||||
pair.first->mBaseUserName.BeginReading());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
std::map<uint32_t, const webgl::AttribInfo*> attribsByLoc;
|
||||
for (const auto& attrib : linkInfo->attribs) {
|
||||
const auto& elemType = attrib.mActiveInfo->mElemType;
|
||||
const auto numUsedLocs = NumUsedLocationsByElemType(elemType);
|
||||
for (uint32_t i = 0; i < numUsedLocs; i++) {
|
||||
const uint32_t usedLoc = attrib.mLoc + i;
|
||||
|
||||
for (const auto& pair : attribsByLoc) {
|
||||
const GLuint attribLoc = pair.first;
|
||||
const auto attrib = pair.second;
|
||||
|
||||
const auto elemSize = ElemSizeFromType(attrib->mElemType);
|
||||
const GLuint locationsUsed = (elemSize + 3) / 4;
|
||||
for (GLuint i = 1; i < locationsUsed; i++) {
|
||||
const GLuint usedLoc = attribLoc + i;
|
||||
|
||||
const auto dupe = attribsByLoc.find(usedLoc);
|
||||
if (dupe != attribsByLoc.end()) {
|
||||
*out_linkLog = nsPrintfCString("Attrib \"%s\" of type \"0x%04x\" aliases"
|
||||
" \"%s\" by overhanging its location.",
|
||||
attrib->mBaseUserName.BeginReading(),
|
||||
attrib->mElemType,
|
||||
dupe->second->mBaseUserName.BeginReading());
|
||||
const auto res = attribsByLoc.insert({usedLoc, &attrib});
|
||||
const bool& didInsert = res.second;
|
||||
if (!didInsert) {
|
||||
const auto& aliasingName = attrib.mActiveInfo->mBaseUserName;
|
||||
const auto& itrExisting = res.first;
|
||||
const auto& existingInfo = itrExisting->second;
|
||||
const auto& existingName = existingInfo->mActiveInfo->mBaseUserName;
|
||||
*out_linkLog = nsPrintfCString("Attrib \"%s\" aliases locations used by"
|
||||
" attrib \"%s\".",
|
||||
aliasingName.BeginReading(),
|
||||
existingName.BeginReading());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -1234,6 +1311,50 @@ WebGLProgram::FindUniformBlockByMappedName(const nsACString& mappedName,
|
|||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool
|
||||
webgl::LinkedProgramInfo::FindAttrib(const nsCString& baseUserName,
|
||||
const webgl::AttribInfo** const out) const
|
||||
{
|
||||
for (const auto& attrib : attribs) {
|
||||
if (attrib.mActiveInfo->mBaseUserName == baseUserName) {
|
||||
*out = &attrib;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
webgl::LinkedProgramInfo::FindUniform(const nsCString& baseUserName,
|
||||
webgl::UniformInfo** const out) const
|
||||
{
|
||||
for (const auto& uniform : uniforms) {
|
||||
if (uniform->mActiveInfo->mBaseUserName == baseUserName) {
|
||||
*out = uniform;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
webgl::LinkedProgramInfo::FindUniformBlock(const nsCString& baseUserName,
|
||||
const webgl::UniformBlockInfo** const out) const
|
||||
{
|
||||
for (const auto& block : uniformBlocks) {
|
||||
if (block->mBaseUserName == baseUserName) {
|
||||
*out = block;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
JSObject*
|
||||
WebGLProgram::WrapObject(JSContext* js, JS::Handle<JSObject*> givenProto)
|
||||
{
|
||||
|
|
|
@ -35,11 +35,30 @@ template<typename> class Sequence;
|
|||
|
||||
namespace webgl {
|
||||
|
||||
struct UniformBlockInfo final
|
||||
: public RefCounted<UniformBlockInfo>
|
||||
struct AttribInfo final
|
||||
{
|
||||
MOZ_DECLARE_REFCOUNTED_TYPENAME(UniformBlockInfo);
|
||||
const RefPtr<WebGLActiveInfo> mActiveInfo;
|
||||
uint32_t mLoc;
|
||||
};
|
||||
|
||||
struct UniformInfo final
|
||||
{
|
||||
typedef decltype(WebGLContext::mBound2DTextures) TexListT;
|
||||
|
||||
const RefPtr<WebGLActiveInfo> mActiveInfo;
|
||||
const TexListT* const mSamplerTexList;
|
||||
std::vector<uint32_t> mSamplerValues;
|
||||
|
||||
protected:
|
||||
static const TexListT*
|
||||
GetTexList(WebGLActiveInfo* activeInfo);
|
||||
|
||||
public:
|
||||
explicit UniformInfo(WebGLActiveInfo* activeInfo);
|
||||
};
|
||||
|
||||
struct UniformBlockInfo final
|
||||
{
|
||||
const nsCString mBaseUserName;
|
||||
const nsCString mBaseMappedName;
|
||||
|
||||
|
@ -57,61 +76,27 @@ struct LinkedProgramInfo final
|
|||
MOZ_DECLARE_REFCOUNTED_TYPENAME(LinkedProgramInfo)
|
||||
MOZ_DECLARE_WEAKREFERENCE_TYPENAME(LinkedProgramInfo)
|
||||
|
||||
//////
|
||||
|
||||
WebGLProgram* const prog;
|
||||
std::vector<RefPtr<WebGLActiveInfo>> activeAttribs;
|
||||
std::vector<RefPtr<WebGLActiveInfo>> activeUniforms;
|
||||
|
||||
std::vector<AttribInfo> attribs;
|
||||
std::vector<UniformInfo*> uniforms; // Owns its contents.
|
||||
std::vector<const UniformBlockInfo*> uniformBlocks; // Owns its contents.
|
||||
std::vector<RefPtr<WebGLActiveInfo>> transformFeedbackVaryings;
|
||||
|
||||
// Needed for Get{Attrib,Uniform}Location. The keys for these are non-mapped
|
||||
// user-facing `GLActiveInfo::name`s, without any final "[0]".
|
||||
std::map<nsCString, const WebGLActiveInfo*> attribMap;
|
||||
std::map<nsCString, const WebGLActiveInfo*> uniformMap;
|
||||
std::map<nsCString, const WebGLActiveInfo*> transformFeedbackVaryingsMap;
|
||||
|
||||
std::vector<RefPtr<UniformBlockInfo>> uniformBlocks;
|
||||
|
||||
// Needed for draw call validation.
|
||||
std::map<const WebGLActiveInfo*, GLuint> activeAttribLocs;
|
||||
std::vector<UniformInfo*> uniformSamplers;
|
||||
|
||||
//////
|
||||
|
||||
explicit LinkedProgramInfo(WebGLProgram* prog);
|
||||
~LinkedProgramInfo();
|
||||
|
||||
bool FindAttrib(const nsCString& baseUserName,
|
||||
const WebGLActiveInfo** const out_activeInfo) const
|
||||
{
|
||||
auto itr = attribMap.find(baseUserName);
|
||||
if (itr == attribMap.end())
|
||||
return false;
|
||||
|
||||
*out_activeInfo = itr->second;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FindUniform(const nsCString& baseUserName,
|
||||
const WebGLActiveInfo** const out_activeInfo) const
|
||||
{
|
||||
auto itr = uniformMap.find(baseUserName);
|
||||
if (itr == uniformMap.end())
|
||||
return false;
|
||||
|
||||
*out_activeInfo = itr->second;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FindAttrib(const nsCString& baseUserName, const AttribInfo** const out) const;
|
||||
bool FindUniform(const nsCString& baseUserName, UniformInfo** const out) const;
|
||||
bool FindUniformBlock(const nsCString& baseUserName,
|
||||
RefPtr<const UniformBlockInfo>* const out_info) const
|
||||
{
|
||||
const size_t count = uniformBlocks.size();
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
if (baseUserName == uniformBlocks[i]->mBaseUserName) {
|
||||
*out_info = uniformBlocks[i].get();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
const UniformBlockInfo** const out) const;
|
||||
};
|
||||
|
||||
} // namespace webgl
|
||||
|
|
|
@ -195,7 +195,9 @@ WebGLTexture::IsMipmapComplete(uint32_t texUnit) const
|
|||
MOZ_ASSERT(DoesMinFilterRequireMipmap());
|
||||
// GLES 3.0.4, p161
|
||||
|
||||
const uint32_t maxLevel = MaxEffectiveMipmapLevel(texUnit);
|
||||
uint32_t maxLevel;
|
||||
if (!MaxEffectiveMipmapLevel(texUnit, &maxLevel))
|
||||
return false;
|
||||
|
||||
// "* `level_base <= level_max`"
|
||||
if (mBaseMipmapLevel > maxLevel)
|
||||
|
@ -203,8 +205,6 @@ WebGLTexture::IsMipmapComplete(uint32_t texUnit) const
|
|||
|
||||
// Make a copy so we can modify it.
|
||||
const ImageInfo& baseImageInfo = BaseImageInfo();
|
||||
if (!baseImageInfo.IsDefined())
|
||||
return false;
|
||||
|
||||
// Reference dimensions based on the current level.
|
||||
uint32_t refWidth = baseImageInfo.mWidth;
|
||||
|
@ -425,24 +425,26 @@ WebGLTexture::IsComplete(uint32_t texUnit, const char** const out_reason) const
|
|||
return true;
|
||||
}
|
||||
|
||||
|
||||
uint32_t
|
||||
WebGLTexture::MaxEffectiveMipmapLevel(uint32_t texUnit) const
|
||||
bool
|
||||
WebGLTexture::MaxEffectiveMipmapLevel(uint32_t texUnit, uint32_t* const out) const
|
||||
{
|
||||
WebGLSampler* sampler = mContext->mBoundSamplers[texUnit];
|
||||
TexMinFilter minFilter = sampler ? sampler->mMinFilter : mMinFilter;
|
||||
if (minFilter == LOCAL_GL_NEAREST ||
|
||||
minFilter == LOCAL_GL_LINEAR)
|
||||
{
|
||||
// No mips used.
|
||||
return mBaseMipmapLevel;
|
||||
// No extra mips used.
|
||||
*out = mBaseMipmapLevel;
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto& imageInfo = BaseImageInfo();
|
||||
MOZ_ASSERT(imageInfo.IsDefined());
|
||||
if (!imageInfo.IsDefined())
|
||||
return false;
|
||||
|
||||
uint32_t maxLevelBySize = mBaseMipmapLevel + imageInfo.MaxMipmapLevels() - 1;
|
||||
return std::min<uint32_t>(maxLevelBySize, mMaxMipmapLevel);
|
||||
uint32_t maxLevelBySize = mBaseMipmapLevel + imageInfo.PossibleMipmapLevels() - 1;
|
||||
*out = std::min<uint32_t>(maxLevelBySize, mMaxMipmapLevel);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -466,7 +468,9 @@ WebGLTexture::GetFakeBlackType(const char* funcName, uint32_t texUnit,
|
|||
bool hasUninitializedData = false;
|
||||
bool hasInitializedData = false;
|
||||
|
||||
const auto maxLevel = MaxEffectiveMipmapLevel(texUnit);
|
||||
uint32_t maxLevel;
|
||||
MOZ_ALWAYS_TRUE( MaxEffectiveMipmapLevel(texUnit, &maxLevel) );
|
||||
|
||||
MOZ_ASSERT(mBaseMipmapLevel <= maxLevel);
|
||||
for (uint32_t level = mBaseMipmapLevel; level <= maxLevel; level++) {
|
||||
for (uint8_t face = 0; face < mFaceCount; face++) {
|
||||
|
@ -790,8 +794,8 @@ WebGLTexture::GenerateMipmap(TexTarget texTarget)
|
|||
// Record the results.
|
||||
// Note that we don't use MaxEffectiveMipmapLevel() here, since that returns
|
||||
// mBaseMipmapLevel if the min filter doesn't require mipmaps.
|
||||
const uint32_t lastLevel = mBaseMipmapLevel + baseImageInfo.MaxMipmapLevels() - 1;
|
||||
PopulateMipChain(mBaseMipmapLevel, lastLevel);
|
||||
const uint32_t maxLevel = mBaseMipmapLevel + baseImageInfo.PossibleMipmapLevels() - 1;
|
||||
PopulateMipChain(mBaseMipmapLevel, maxLevel);
|
||||
}
|
||||
|
||||
JS::Value
|
||||
|
|
|
@ -154,9 +154,10 @@ public:
|
|||
ImageInfo& operator =(const ImageInfo& a);
|
||||
|
||||
public:
|
||||
uint32_t MaxMipmapLevels() const {
|
||||
uint32_t PossibleMipmapLevels() const {
|
||||
// GLES 3.0.4, 3.8 - Mipmapping: `floor(log2(largest_of_dims)) + 1`
|
||||
uint32_t largest = std::max(std::max(mWidth, mHeight), mDepth);
|
||||
const uint32_t largest = std::max(std::max(mWidth, mHeight), mDepth);
|
||||
MOZ_ASSERT(largest != 0);
|
||||
return FloorLog2Size(largest) + 1;
|
||||
}
|
||||
|
||||
|
@ -288,7 +289,7 @@ protected:
|
|||
|
||||
void PopulateMipChain(uint32_t baseLevel, uint32_t maxLevel);
|
||||
|
||||
uint32_t MaxEffectiveMipmapLevel(uint32_t texUnit) const;
|
||||
bool MaxEffectiveMipmapLevel(uint32_t texUnit, uint32_t* const out) const;
|
||||
|
||||
static uint8_t FaceForTarget(TexImageTarget texImageTarget) {
|
||||
GLenum rawTexImageTarget = texImageTarget.get();
|
||||
|
@ -388,6 +389,9 @@ protected:
|
|||
bool GetFakeBlackType(const char* funcName, uint32_t texUnit,
|
||||
FakeBlackType* const out_fakeBlack);
|
||||
public:
|
||||
bool IsFeedback(WebGLContext* webgl, const char* funcName, uint32_t texUnit,
|
||||
const std::vector<const WebGLFBAttachPoint*>& fbAttachments) const;
|
||||
|
||||
bool ResolveForDraw(const char* funcName, uint32_t texUnit,
|
||||
FakeBlackType* const out_fakeBlack);
|
||||
|
||||
|
|
|
@ -16,34 +16,32 @@ namespace mozilla {
|
|||
|
||||
WebGLUniformLocation::WebGLUniformLocation(WebGLContext* webgl,
|
||||
const webgl::LinkedProgramInfo* linkInfo,
|
||||
GLuint loc,
|
||||
size_t arrayIndex,
|
||||
const WebGLActiveInfo* activeInfo)
|
||||
webgl::UniformInfo* info, GLuint loc,
|
||||
size_t arrayIndex)
|
||||
: WebGLContextBoundObject(webgl)
|
||||
, mLinkInfo(linkInfo)
|
||||
, mInfo(info)
|
||||
, mLoc(loc)
|
||||
, mArrayIndex(arrayIndex)
|
||||
, mActiveInfo(activeInfo)
|
||||
{ }
|
||||
|
||||
WebGLUniformLocation::~WebGLUniformLocation()
|
||||
{ }
|
||||
|
||||
bool
|
||||
WebGLUniformLocation::ValidateForProgram(WebGLProgram* prog, WebGLContext* webgl,
|
||||
const char* funcName) const
|
||||
WebGLUniformLocation::ValidateForProgram(WebGLProgram* prog, const char* funcName) const
|
||||
{
|
||||
// Check the weak-pointer.
|
||||
if (!mLinkInfo) {
|
||||
webgl->ErrorInvalidOperation("%s: This uniform location is obsolete because its"
|
||||
" program has been successfully relinked.",
|
||||
funcName);
|
||||
mContext->ErrorInvalidOperation("%s: This uniform location is obsolete because"
|
||||
" its program has been successfully relinked.",
|
||||
funcName);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mLinkInfo->prog != prog) {
|
||||
webgl->ErrorInvalidOperation("%s: This uniform location corresponds to a"
|
||||
" different program.", funcName);
|
||||
mContext->ErrorInvalidOperation("%s: This uniform location corresponds to a"
|
||||
" different program.", funcName);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -121,19 +119,22 @@ IsUniformSetterTypeValid(GLenum setterType, GLenum uniformType)
|
|||
|
||||
bool
|
||||
WebGLUniformLocation::ValidateSizeAndType(uint8_t setterElemSize, GLenum setterType,
|
||||
WebGLContext* webgl, const char* funcName) const
|
||||
const char* funcName) const
|
||||
{
|
||||
MOZ_ASSERT(mLinkInfo);
|
||||
|
||||
if (setterElemSize != mActiveInfo->mElemSize) {
|
||||
webgl->ErrorInvalidOperation("%s: Bad uniform size: %i", funcName,
|
||||
mActiveInfo->mElemSize);
|
||||
const auto& uniformElemSize = mInfo->mActiveInfo->mElemSize;
|
||||
if (setterElemSize != uniformElemSize) {
|
||||
mContext->ErrorInvalidOperation("%s: Function used differs from uniform size: %i",
|
||||
funcName, uniformElemSize);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!IsUniformSetterTypeValid(setterType, mActiveInfo->mElemType)) {
|
||||
webgl->ErrorInvalidOperation("%s: Bad uniform type: %i", funcName,
|
||||
mActiveInfo->mElemSize);
|
||||
const auto& uniformElemType = mInfo->mActiveInfo->mElemType;
|
||||
if (!IsUniformSetterTypeValid(setterType, uniformElemType)) {
|
||||
mContext->ErrorInvalidOperation("%s: Function used is incompatible with uniform"
|
||||
" type: %i",
|
||||
funcName, uniformElemType);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -142,16 +143,16 @@ WebGLUniformLocation::ValidateSizeAndType(uint8_t setterElemSize, GLenum setterT
|
|||
|
||||
bool
|
||||
WebGLUniformLocation::ValidateArrayLength(uint8_t setterElemSize, size_t setterArraySize,
|
||||
WebGLContext* webgl, const char* funcName) const
|
||||
const char* funcName) const
|
||||
{
|
||||
MOZ_ASSERT(mLinkInfo);
|
||||
|
||||
if (setterArraySize == 0 ||
|
||||
setterArraySize % setterElemSize)
|
||||
{
|
||||
webgl->ErrorInvalidValue("%s: expected an array of length a multiple of"
|
||||
" %d, got an array of length %d.",
|
||||
funcName, setterElemSize, setterArraySize);
|
||||
mContext->ErrorInvalidValue("%s: Expected an array of length a multiple of %d,"
|
||||
" got an array of length %d.",
|
||||
funcName, setterElemSize, setterArraySize);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -162,55 +163,34 @@ WebGLUniformLocation::ValidateArrayLength(uint8_t setterElemSize, size_t setterA
|
|||
* highest array element index used, as reported by `GetActiveUniform`, will be
|
||||
* ignored by GL.
|
||||
*/
|
||||
if (!mActiveInfo->mIsArray &&
|
||||
if (!mInfo->mActiveInfo->mIsArray &&
|
||||
setterArraySize != setterElemSize)
|
||||
{
|
||||
webgl->ErrorInvalidOperation("%s: expected an array of length exactly %d"
|
||||
" (since this uniform is not an array"
|
||||
" uniform), got an array of length %d.",
|
||||
funcName, setterElemSize, setterArraySize);
|
||||
mContext->ErrorInvalidOperation("%s: Expected an array of length exactly %d"
|
||||
" (since this uniform is not an array uniform),"
|
||||
" got an array of length %d.",
|
||||
funcName, setterElemSize, setterArraySize);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
WebGLUniformLocation::ValidateSamplerSetter(GLint value, WebGLContext* webgl,
|
||||
const char* funcName) const
|
||||
{
|
||||
MOZ_ASSERT(mLinkInfo);
|
||||
|
||||
if (mActiveInfo->mElemType != LOCAL_GL_SAMPLER_2D &&
|
||||
mActiveInfo->mElemType != LOCAL_GL_SAMPLER_CUBE)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (value >= 0 && value < (GLint)webgl->GLMaxTextureUnits())
|
||||
return true;
|
||||
|
||||
webgl->ErrorInvalidValue("%s: This uniform location is a sampler, but %d is not a"
|
||||
" valid texture unit.",
|
||||
funcName, value);
|
||||
return false;
|
||||
}
|
||||
|
||||
JS::Value
|
||||
WebGLUniformLocation::GetUniform(JSContext* js, WebGLContext* webgl) const
|
||||
WebGLUniformLocation::GetUniform(JSContext* js) const
|
||||
{
|
||||
MOZ_ASSERT(mLinkInfo);
|
||||
|
||||
uint8_t elemSize = mActiveInfo->mElemSize;
|
||||
const uint8_t elemSize = mInfo->mActiveInfo->mElemSize;
|
||||
static const uint8_t kMaxElemSize = 16;
|
||||
MOZ_ASSERT(elemSize <= kMaxElemSize);
|
||||
|
||||
GLuint prog = mLinkInfo->prog->mGLName;
|
||||
|
||||
gl::GLContext* gl = webgl->GL();
|
||||
gl::GLContext* gl = mContext->GL();
|
||||
gl->MakeCurrent();
|
||||
|
||||
switch (mActiveInfo->mElemType) {
|
||||
switch (mInfo->mActiveInfo->mElemType) {
|
||||
case LOCAL_GL_INT:
|
||||
case LOCAL_GL_INT_VEC2:
|
||||
case LOCAL_GL_INT_VEC3:
|
||||
|
@ -237,9 +217,9 @@ WebGLUniformLocation::GetUniform(JSContext* js, WebGLContext* webgl) const
|
|||
if (elemSize == 1)
|
||||
return JS::Int32Value(buffer[0]);
|
||||
|
||||
JSObject* obj = dom::Int32Array::Create(js, webgl, elemSize, buffer);
|
||||
JSObject* obj = dom::Int32Array::Create(js, mContext, elemSize, buffer);
|
||||
if (!obj) {
|
||||
webgl->ErrorOutOfMemory("getUniform: out of memory");
|
||||
mContext->ErrorOutOfMemory("getUniform: Out of memory.");
|
||||
return JS::NullValue();
|
||||
}
|
||||
return JS::ObjectOrNullValue(obj);
|
||||
|
@ -263,7 +243,7 @@ WebGLUniformLocation::GetUniform(JSContext* js, WebGLContext* webgl) const
|
|||
JS::RootedValue val(js);
|
||||
// Be careful: we don't want to convert all of |uv|!
|
||||
if (!dom::ToJSValue(js, boolBuffer, elemSize, &val)) {
|
||||
webgl->ErrorOutOfMemory("getUniform: out of memory");
|
||||
mContext->ErrorOutOfMemory("getUniform: Out of memory.");
|
||||
return JS::NullValue();
|
||||
}
|
||||
return val;
|
||||
|
@ -289,9 +269,9 @@ WebGLUniformLocation::GetUniform(JSContext* js, WebGLContext* webgl) const
|
|||
if (elemSize == 1)
|
||||
return JS::DoubleValue(buffer[0]);
|
||||
|
||||
JSObject* obj = dom::Float32Array::Create(js, webgl, elemSize, buffer);
|
||||
JSObject* obj = dom::Float32Array::Create(js, mContext, elemSize, buffer);
|
||||
if (!obj) {
|
||||
webgl->ErrorOutOfMemory("getUniform: out of memory");
|
||||
mContext->ErrorOutOfMemory("getUniform: Out of memory.");
|
||||
return JS::NullValue();
|
||||
}
|
||||
return JS::ObjectOrNullValue(obj);
|
||||
|
@ -308,9 +288,9 @@ WebGLUniformLocation::GetUniform(JSContext* js, WebGLContext* webgl) const
|
|||
if (elemSize == 1)
|
||||
return JS::DoubleValue(buffer[0]); // This is Double because only Int32 is special cased.
|
||||
|
||||
JSObject* obj = dom::Uint32Array::Create(js, webgl, elemSize, buffer);
|
||||
JSObject* obj = dom::Uint32Array::Create(js, mContext, elemSize, buffer);
|
||||
if (!obj) {
|
||||
webgl->ErrorOutOfMemory("getUniform: out of memory");
|
||||
mContext->ErrorOutOfMemory("getUniform: Out of memory.");
|
||||
return JS::NullValue();
|
||||
}
|
||||
return JS::ObjectOrNullValue(obj);
|
||||
|
|
|
@ -39,24 +39,25 @@ public:
|
|||
return mContext;
|
||||
}
|
||||
|
||||
//////
|
||||
|
||||
const WeakPtr<const webgl::LinkedProgramInfo> mLinkInfo;
|
||||
webgl::UniformInfo* const mInfo;
|
||||
const GLuint mLoc;
|
||||
const size_t mArrayIndex;
|
||||
const WebGLActiveInfo* const mActiveInfo;
|
||||
|
||||
//////
|
||||
|
||||
WebGLUniformLocation(WebGLContext* webgl, const webgl::LinkedProgramInfo* linkInfo,
|
||||
GLuint loc, size_t arrayIndex, const WebGLActiveInfo* activeInfo);
|
||||
webgl::UniformInfo* info, GLuint loc, size_t arrayIndex);
|
||||
|
||||
bool ValidateForProgram(WebGLProgram* prog, WebGLContext* webgl,
|
||||
const char* funcName) const;
|
||||
bool ValidateSamplerSetter(GLint value, WebGLContext* webgl,
|
||||
const char* funcName) const;
|
||||
bool ValidateForProgram(WebGLProgram* prog, const char* funcName) const;
|
||||
bool ValidateSizeAndType(uint8_t setterElemSize, GLenum setterType,
|
||||
WebGLContext* webgl, const char* funcName) const;
|
||||
const char* funcName) const;
|
||||
bool ValidateArrayLength(uint8_t setterElemSize, size_t setterArraySize,
|
||||
WebGLContext* webgl, const char* funcName) const;
|
||||
const char* funcName) const;
|
||||
|
||||
JS::Value GetUniform(JSContext* js, WebGLContext* webgl) const;
|
||||
JS::Value GetUniform(JSContext* js) const;
|
||||
|
||||
// Needed for certain helper functions like ValidateObject.
|
||||
// `WebGLUniformLocation`s can't be 'Deleted' in the WebGL sense.
|
||||
|
|
|
@ -5,12 +5,12 @@
|
|||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
TEST_DIRS += [
|
||||
'compiledtest',
|
||||
'compiledtest',
|
||||
'gtest'
|
||||
]
|
||||
|
||||
# Change the following line(s) to avoid bug 1081323 (clobber after changing a manifest):
|
||||
# * Add a regression test for triangle-then-point rendering.
|
||||
# * Implement ReadPixel with PBOs.
|
||||
|
||||
MOCHITEST_MANIFESTS += [
|
||||
'test/crash/mochitest.ini',
|
||||
|
|
|
@ -6670,7 +6670,6 @@ fail-if = (os == 'android' && android_version == '10')
|
|||
skip-if = (os == 'android') || (os == 'linux')
|
||||
fail-if = (os == 'mac') || (os == 'win')
|
||||
[generated/test_conformance__renderbuffers__feedback-loop.html]
|
||||
fail-if = 1
|
||||
[generated/test_conformance__renderbuffers__framebuffer-object-attachment.html]
|
||||
skip-if = (os == 'android')
|
||||
[generated/test_conformance__renderbuffers__framebuffer-state-restoration.html]
|
||||
|
|
|
@ -36,9 +36,6 @@ fail-if = 1
|
|||
fail-if = 1
|
||||
[generated/test_conformance__glsl__misc__shaders-with-invariance.html]
|
||||
fail-if = 1
|
||||
[generated/test_conformance__glsl__misc__shaders-with-name-conflicts.html]
|
||||
[generated/test_conformance__renderbuffers__feedback-loop.html]
|
||||
fail-if = 1
|
||||
|
||||
####################
|
||||
# Tests requesting non-local network connections.
|
||||
|
|
|
@ -71,6 +71,7 @@ fail-if = (os == 'win' && os_version == '5.1')
|
|||
[test_no_arr_points.html]
|
||||
skip-if = android_version == '18' #Android 4.3 aws only; bug 1030942
|
||||
[test_noprog_draw.html]
|
||||
[test_pixel_pack_buffer.html]
|
||||
[test_privileged_exts.html]
|
||||
[test_renderer_strings.html]
|
||||
[test_sab_with_webgl.html]
|
||||
|
|
|
@ -0,0 +1,288 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset='UTF-8'>
|
||||
<script src='/tests/SimpleTest/SimpleTest.js'></script>
|
||||
<link rel='stylesheet' href='/tests/SimpleTest/test.css'>
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
|
||||
var RED = [1, 0, 0, 1];
|
||||
var GREEN = [0, 1, 0, 1];
|
||||
var BLUE = [0, 0, 1, 1];
|
||||
var WHITE = [1, 1, 1, 1];
|
||||
var ZERO = [0, 0, 0, 0];
|
||||
|
||||
function DrawColors(gl) {
|
||||
var fnClearToColor = function(color) {
|
||||
gl.clearColor(color[0], color[1], color[2], color[3]);
|
||||
gl.clear(gl.COLOR_BUFFER_BIT);
|
||||
};
|
||||
|
||||
gl.enable(gl.SCISSOR_TEST);
|
||||
|
||||
// +---+
|
||||
// |G W|
|
||||
// |R B|
|
||||
// +---+
|
||||
|
||||
gl.scissor(0, 0, 1, 1);
|
||||
fnClearToColor(RED);
|
||||
|
||||
gl.scissor(1, 0, 1, 1);
|
||||
fnClearToColor(BLUE);
|
||||
|
||||
gl.scissor(0, 1, 1, 1);
|
||||
fnClearToColor(GREEN);
|
||||
|
||||
gl.scissor(1, 1, 1, 1);
|
||||
fnClearToColor(WHITE);
|
||||
}
|
||||
|
||||
function ClearBufferPair(gl, byteCount) {
|
||||
// Using `null` here clears to zero according to WebGL.
|
||||
gl.bufferData(gl.PIXEL_PACK_BUFFER, byteCount, gl.STREAM_READ);
|
||||
|
||||
var arr = new Uint8Array(byteCount);
|
||||
return arr;
|
||||
}
|
||||
|
||||
function ColorToString(color, offset=0) {
|
||||
var arr = [ color[offset+0],
|
||||
color[offset+1],
|
||||
color[offset+2],
|
||||
color[offset+3] ];
|
||||
return '[' + arr.join(', ') + ']';
|
||||
}
|
||||
|
||||
function TestIsUNormColor(refColor, testData, offset) {
|
||||
if (testData.length < offset + 4) {
|
||||
ok(false, 'testData not long enough.');
|
||||
}
|
||||
|
||||
var refUNormColor = [
|
||||
(refColor[0] * 255) | 0,
|
||||
(refColor[1] * 255) | 0,
|
||||
(refColor[2] * 255) | 0,
|
||||
(refColor[3] * 255) | 0,
|
||||
];
|
||||
|
||||
var refStr = ColorToString(refUNormColor);
|
||||
var testStr = ColorToString(testData, offset);
|
||||
ok(testStr == refStr, 'Expected ' + refStr + ', was ' + testStr + '.');
|
||||
}
|
||||
|
||||
function section(text) {
|
||||
ok(true, '');
|
||||
ok(true, 'Section: ' + text);
|
||||
}
|
||||
|
||||
function EnsureNoError(gl) {
|
||||
var glErr = gl.getError();
|
||||
while (gl.getError()) {}
|
||||
|
||||
if (!glErr)
|
||||
return;
|
||||
|
||||
var extraInfo = '';
|
||||
|
||||
var err = new Error();
|
||||
var stackStr = err.stack;
|
||||
if (stackStr !== undefined) {
|
||||
var stackArr = stackStr.split('\n');
|
||||
stackStr = stackArr[1]; // First one after present scope.
|
||||
extraInfo = ': ' + stackStr;
|
||||
}
|
||||
|
||||
ok(false, 'Unexpected GL error: 0x' + glErr.toString(16) + extraInfo);
|
||||
}
|
||||
|
||||
function TestError(gl, refErrVal, str='') {
|
||||
if (str == '') {
|
||||
str = 'gl.getError()';
|
||||
} else {
|
||||
str = str + ': gl.getError()';
|
||||
}
|
||||
|
||||
var err = gl.getError();
|
||||
while (gl.getError()) {}
|
||||
|
||||
ShouldBe(err.toString(16), refErrVal.toString(16), str);
|
||||
}
|
||||
|
||||
function ShouldBe(val, ref, str='') {
|
||||
if (str != '') {
|
||||
str += ': ';
|
||||
}
|
||||
|
||||
ok(val == ref, str + 'Should be `' + ref + '`, was `' + val + '`.');
|
||||
}
|
||||
|
||||
var gl;
|
||||
|
||||
function Test() {
|
||||
var canvas = document.createElement('canvas');
|
||||
canvas.width = 2;
|
||||
canvas.height = 2;
|
||||
canvas.style = 'width: 256px; height: 256px; border: 1px solid black;';
|
||||
document.body.appendChild(canvas);
|
||||
|
||||
var attribs = {
|
||||
antialias: false,
|
||||
alpha: false,
|
||||
};
|
||||
gl = canvas.getContext('webgl2', attribs);
|
||||
if (!gl) {
|
||||
todo(false, 'WebGL 2 not present, skipping.');
|
||||
return;
|
||||
}
|
||||
|
||||
////////
|
||||
|
||||
TestIsUNormColor(RED, new Uint8Array([255, 0, 0, 255]), 0);
|
||||
|
||||
////////
|
||||
|
||||
gl.clearColor(RED[0], RED[1], RED[2], RED[3]);
|
||||
gl.clear(gl.COLOR_BUFFER_BIT);
|
||||
|
||||
var data = new Uint8Array(16);
|
||||
gl.readPixels(0, 0, 2, 2, gl.RGBA, gl.UNSIGNED_BYTE, data);
|
||||
console.log(JSON.stringify(data));
|
||||
TestIsUNormColor(RED, data, 0);
|
||||
|
||||
////////
|
||||
|
||||
DrawColors(gl);
|
||||
|
||||
////////
|
||||
|
||||
EnsureNoError(gl);
|
||||
gl.readPixels(0, 0, 2, 2, gl.RGBA, gl.UNSIGNED_BYTE, 0);
|
||||
TestError(gl, gl.INVALID_OPERATION);
|
||||
|
||||
var data = new Uint8Array(16);
|
||||
gl.readPixels(0, 0, 2, 2, gl.RGBA, gl.UNSIGNED_BYTE, data);
|
||||
EnsureNoError(gl);
|
||||
TestIsUNormColor(RED, data, 0);
|
||||
TestIsUNormColor(BLUE, data, 4);
|
||||
TestIsUNormColor(GREEN, data, 8);
|
||||
TestIsUNormColor(WHITE, data, 12);
|
||||
|
||||
////////
|
||||
|
||||
var a = gl.createBuffer();
|
||||
gl.bindBuffer(gl.PIXEL_PACK_BUFFER, a);
|
||||
EnsureNoError(gl);
|
||||
|
||||
gl.readPixels(0, 0, 2, 2, gl.RGBA, gl.UNSIGNED_BYTE, data);
|
||||
TestError(gl, gl.INVALID_OPERATION);
|
||||
|
||||
////////
|
||||
|
||||
// Basic
|
||||
section('Basic readback');
|
||||
data = ClearBufferPair(gl, 16);
|
||||
EnsureNoError(gl);
|
||||
gl.readPixels(0, 0, 2, 2, gl.RGBA, gl.UNSIGNED_BYTE, 0);
|
||||
EnsureNoError(gl);
|
||||
gl.getBufferSubData(gl.PIXEL_PACK_BUFFER, 0, data.buffer);
|
||||
EnsureNoError(gl);
|
||||
TestIsUNormColor(RED, data, 0);
|
||||
TestIsUNormColor(BLUE, data, 4);
|
||||
TestIsUNormColor(GREEN, data, 8);
|
||||
TestIsUNormColor(WHITE, data, 12);
|
||||
|
||||
section('Subrect readback');
|
||||
data = ClearBufferPair(gl, 8);
|
||||
gl.readPixels(1, 1, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, 0);
|
||||
gl.getBufferSubData(gl.PIXEL_PACK_BUFFER, 0, data.buffer);
|
||||
EnsureNoError(gl);
|
||||
TestIsUNormColor(WHITE, data, 0);
|
||||
TestIsUNormColor(ZERO, data, 4);
|
||||
|
||||
section('ReadPixels offset:4');
|
||||
data = ClearBufferPair(gl, 16);
|
||||
gl.readPixels(1, 1, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, 4);
|
||||
gl.getBufferSubData(gl.PIXEL_PACK_BUFFER, 0, data.buffer);
|
||||
EnsureNoError(gl);
|
||||
TestIsUNormColor(ZERO, data, 0);
|
||||
TestIsUNormColor(WHITE, data, 4);
|
||||
TestIsUNormColor(ZERO, data, 8);
|
||||
TestIsUNormColor(ZERO, data, 12);
|
||||
|
||||
section('ReadPixels offset:5');
|
||||
gl.readPixels(1, 1, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, 5);
|
||||
gl.getBufferSubData(gl.PIXEL_PACK_BUFFER, 0, data.buffer);
|
||||
EnsureNoError(gl);
|
||||
TestIsUNormColor(ZERO, data, 0);
|
||||
TestIsUNormColor(WHITE, data, 4); // Should remain from previous read.
|
||||
TestIsUNormColor(WHITE, data, 5);
|
||||
TestIsUNormColor(ZERO, data, 9);
|
||||
TestIsUNormColor(ZERO, data, 12);
|
||||
|
||||
section('GetBufferSubData src too small');
|
||||
data = ClearBufferPair(gl, 16);
|
||||
EnsureNoError(gl);
|
||||
gl.getBufferSubData(gl.PIXEL_PACK_BUFFER, 1, data.buffer);
|
||||
TestError(gl, gl.INVALID_VALUE);
|
||||
TestIsUNormColor(ZERO, data, 0);
|
||||
TestIsUNormColor(ZERO, data, 4);
|
||||
TestIsUNormColor(ZERO, data, 8);
|
||||
TestIsUNormColor(ZERO, data, 12);
|
||||
|
||||
section('GetBufferSubData offset:1');
|
||||
data = new Uint8Array(15);
|
||||
gl.readPixels(1, 1, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, 8);
|
||||
gl.getBufferSubData(gl.PIXEL_PACK_BUFFER, 1, data.buffer);
|
||||
EnsureNoError(gl);
|
||||
TestIsUNormColor(ZERO, data, 0);
|
||||
TestIsUNormColor(ZERO, data, 3);
|
||||
TestIsUNormColor(WHITE, data, 7);
|
||||
TestIsUNormColor(ZERO, data, 11);
|
||||
|
||||
//////////////////////////////////////
|
||||
|
||||
section('Test packing state');
|
||||
EnsureNoError(gl);
|
||||
|
||||
function TestPackState(enumStr, initialVal, changedVal) {
|
||||
var enumVal = gl[enumStr];
|
||||
|
||||
ShouldBe(gl.getParameter(enumVal), initialVal, 'Initial ' + enumStr);
|
||||
gl.pixelStorei(enumVal, changedVal);
|
||||
ShouldBe(gl.getParameter(enumVal), changedVal, 'Changed ' + enumStr);
|
||||
gl.pixelStorei(enumVal, initialVal);
|
||||
ShouldBe(gl.getParameter(enumVal), initialVal, 'Reverted ' + enumStr);
|
||||
EnsureNoError(gl);
|
||||
}
|
||||
|
||||
TestPackState('PACK_ALIGNMENT', 4, 1);
|
||||
TestPackState('PACK_ROW_LENGTH', 0, 16);
|
||||
TestPackState('PACK_SKIP_PIXELS', 0, 3);
|
||||
TestPackState('PACK_SKIP_ROWS', 0, 3);
|
||||
}
|
||||
|
||||
function RunTest() {
|
||||
Test();
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
try {
|
||||
var prefArrArr = [
|
||||
['webgl.force-enabled', true],
|
||||
['webgl.disable-angle', true],
|
||||
];
|
||||
var prefEnv = {'set': prefArrArr};
|
||||
SpecialPowers.pushPrefEnv(prefEnv, RunTest);
|
||||
} catch (e) {
|
||||
todo(false, 'No SpecialPowers, but trying anyway...');
|
||||
RunTest();
|
||||
}
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -169,9 +169,12 @@ FetchRequest(nsIGlobalObject* aGlobal, const RequestOrUSVString& aInput,
|
|||
nsContentUtils::IsCallerChrome());
|
||||
|
||||
AutoJSAPI jsapi;
|
||||
jsapi.Init(aGlobal);
|
||||
JSContext* cx = jsapi.cx();
|
||||
if (!jsapi.Init(aGlobal)) {
|
||||
aRv.Throw(NS_ERROR_NOT_AVAILABLE);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
JSContext* cx = jsapi.cx();
|
||||
JS::Rooted<JSObject*> jsGlobal(cx, aGlobal->GetGlobalJSObject());
|
||||
GlobalObject global(cx, jsGlobal);
|
||||
|
||||
|
@ -1095,9 +1098,12 @@ FetchBody<Derived>::ContinueConsumeBody(nsresult aStatus, uint32_t aResultLength
|
|||
MOZ_ASSERT(aResult);
|
||||
|
||||
AutoJSAPI jsapi;
|
||||
jsapi.Init(DerivedClass()->GetParentObject());
|
||||
JSContext* cx = jsapi.cx();
|
||||
if (!jsapi.Init(DerivedClass()->GetParentObject())) {
|
||||
localPromise->MaybeReject(NS_ERROR_UNEXPECTED);
|
||||
return;
|
||||
}
|
||||
|
||||
JSContext* cx = jsapi.cx();
|
||||
ErrorResult error;
|
||||
|
||||
switch (mConsumeType) {
|
||||
|
|
|
@ -51,9 +51,6 @@ HttpServer::Init(int32_t aPort, bool aHttps, HttpServerListener* aListener)
|
|||
mHttps = aHttps;
|
||||
mListener = aListener;
|
||||
|
||||
nsCOMPtr<nsIPrefBranch> prefService;
|
||||
prefService = do_GetService(NS_PREFSERVICE_CONTRACTID);
|
||||
|
||||
if (mHttps) {
|
||||
nsCOMPtr<nsILocalCertService> lcs =
|
||||
do_CreateInstance("@mozilla.org/security/local-cert-service;1");
|
||||
|
|
|
@ -261,7 +261,10 @@ nsBrowserElement::Download(const nsAString& aUrl,
|
|||
nsCOMPtr<nsIXPConnectWrappedJS> wrappedObj = do_QueryInterface(mBrowserElementAPI);
|
||||
MOZ_ASSERT(wrappedObj, "Failed to get wrapped JS from XPCOM component.");
|
||||
AutoJSAPI jsapi;
|
||||
jsapi.Init(wrappedObj->GetJSObject());
|
||||
if (!jsapi.Init(wrappedObj->GetJSObject())) {
|
||||
aRv.Throw(NS_ERROR_UNEXPECTED);
|
||||
return nullptr;
|
||||
}
|
||||
JSContext* cx = jsapi.cx();
|
||||
JS::Rooted<JS::Value> options(cx);
|
||||
aRv.MightThrowJSException();
|
||||
|
@ -714,7 +717,10 @@ nsBrowserElement::ExecuteScript(const nsAString& aScript,
|
|||
nsCOMPtr<nsIXPConnectWrappedJS> wrappedObj = do_QueryInterface(mBrowserElementAPI);
|
||||
MOZ_ASSERT(wrappedObj, "Failed to get wrapped JS from XPCOM component.");
|
||||
AutoJSAPI jsapi;
|
||||
jsapi.Init(wrappedObj->GetJSObject());
|
||||
if (!jsapi.Init(wrappedObj->GetJSObject())) {
|
||||
aRv.Throw(NS_ERROR_UNEXPECTED);
|
||||
return nullptr;
|
||||
}
|
||||
JSContext* cx = jsapi.cx();
|
||||
JS::Rooted<JS::Value> options(cx);
|
||||
aRv.MightThrowJSException();
|
||||
|
|
|
@ -129,6 +129,7 @@
|
|||
#include "mozilla/dom/PCycleCollectWithLogsChild.h"
|
||||
|
||||
#include "nsIScriptSecurityManager.h"
|
||||
#include "nsHostObjectProtocolHandler.h"
|
||||
|
||||
#ifdef MOZ_WEBRTC
|
||||
#include "signaling/src/peerconnection/WebrtcGlobalChild.h"
|
||||
|
@ -1241,11 +1242,10 @@ ContentChild::DeallocPAPZChild(PAPZChild* aActor)
|
|||
return true;
|
||||
}
|
||||
|
||||
PCompositorBridgeChild*
|
||||
ContentChild::AllocPCompositorBridgeChild(mozilla::ipc::Transport* aTransport,
|
||||
base::ProcessId aOtherProcess)
|
||||
bool
|
||||
ContentChild::RecvInitCompositor(Endpoint<PCompositorBridgeChild>&& aEndpoint)
|
||||
{
|
||||
return CompositorBridgeChild::Create(aTransport, aOtherProcess);
|
||||
return CompositorBridgeChild::InitForContent(Move(aEndpoint));
|
||||
}
|
||||
|
||||
PSharedBufferManagerChild*
|
||||
|
@ -2243,6 +2243,8 @@ ContentChild::ActorDestroy(ActorDestroyReason why)
|
|||
sFirstIdleTask->Cancel();
|
||||
}
|
||||
|
||||
nsHostObjectProtocolHandler::RemoveDataEntries();
|
||||
|
||||
mAlertObservers.Clear();
|
||||
|
||||
mIdleObservers.Clear();
|
||||
|
@ -2635,6 +2637,22 @@ ContentChild::RecvInitServiceWorkers(const ServiceWorkerConfiguration& aConfig)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ContentChild::RecvInitBlobURLs(nsTArray<BlobURLRegistrationData>&& aRegistrations)
|
||||
{
|
||||
for (uint32_t i = 0; i < aRegistrations.Length(); ++i) {
|
||||
BlobURLRegistrationData& registration = aRegistrations[i];
|
||||
RefPtr<BlobImpl> blobImpl =
|
||||
static_cast<BlobChild*>(registration.blobChild())->GetBlobImpl();
|
||||
MOZ_ASSERT(blobImpl);
|
||||
|
||||
nsHostObjectProtocolHandler::AddDataEntry(registration.url(), blobImpl,
|
||||
registration.principal());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ContentChild::RecvLastPrivateDocShellDestroyed()
|
||||
{
|
||||
|
@ -3373,6 +3391,25 @@ ContentChild::RecvNotifyPushSubscriptionModifiedObservers(const nsCString& aScop
|
|||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ContentChild::RecvBlobURLRegistration(const nsCString& aURI, PBlobChild* aBlobChild,
|
||||
const IPC::Principal& aPrincipal)
|
||||
{
|
||||
RefPtr<BlobImpl> blobImpl = static_cast<BlobChild*>(aBlobChild)->GetBlobImpl();
|
||||
MOZ_ASSERT(blobImpl);
|
||||
|
||||
nsHostObjectProtocolHandler::AddDataEntry(aURI, blobImpl, aPrincipal);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ContentChild::RecvBlobURLUnregistration(const nsCString& aURI)
|
||||
{
|
||||
nsHostObjectProtocolHandler::RemoveDataEntry(aURI);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ContentChild::CreateGetFilesRequest(const nsAString& aDirectoryPath,
|
||||
bool aRecursiveFlag,
|
||||
|
|
|
@ -37,10 +37,6 @@ class PFileDescriptorSetChild;
|
|||
class URIParams;
|
||||
}// namespace ipc
|
||||
|
||||
namespace layers {
|
||||
class PCompositorBridgeChild;
|
||||
} // namespace layers
|
||||
|
||||
namespace dom {
|
||||
|
||||
class AlertObserver;
|
||||
|
@ -152,9 +148,8 @@ public:
|
|||
bool
|
||||
DeallocPAPZChild(PAPZChild* aActor) override;
|
||||
|
||||
PCompositorBridgeChild*
|
||||
AllocPCompositorBridgeChild(mozilla::ipc::Transport* aTransport,
|
||||
base::ProcessId aOtherProcess) override;
|
||||
bool
|
||||
RecvInitCompositor(Endpoint<PCompositorBridgeChild>&& aEndpoint) override;
|
||||
|
||||
PSharedBufferManagerChild*
|
||||
AllocPSharedBufferManagerChild(mozilla::ipc::Transport* aTransport,
|
||||
|
@ -462,6 +457,9 @@ public:
|
|||
virtual bool
|
||||
RecvInitServiceWorkers(const ServiceWorkerConfiguration& aConfig) override;
|
||||
|
||||
virtual bool
|
||||
RecvInitBlobURLs(nsTArray<BlobURLRegistrationData>&& aRegistations) override;
|
||||
|
||||
virtual bool RecvLastPrivateDocShellDestroyed() override;
|
||||
|
||||
virtual bool RecvVolumes(InfallibleTArray<VolumeInfo>&& aVolumes) override;
|
||||
|
@ -643,6 +641,13 @@ public:
|
|||
RecvGetFilesResponse(const nsID& aUUID,
|
||||
const GetFilesResponseResult& aResult) override;
|
||||
|
||||
virtual bool
|
||||
RecvBlobURLRegistration(const nsCString& aURI, PBlobChild* aBlobChild,
|
||||
const IPC::Principal& aPrincipal) override;
|
||||
|
||||
virtual bool
|
||||
RecvBlobURLUnregistration(const nsCString& aURI) override;
|
||||
|
||||
private:
|
||||
static void ForceKillTimerCallback(nsITimer* aTimer, void* aClosure);
|
||||
void StartForceKillTimer();
|
||||
|
|
|
@ -191,6 +191,7 @@
|
|||
#include "nsIBlocklistService.h"
|
||||
#include "mozilla/StyleSheetHandle.h"
|
||||
#include "mozilla/StyleSheetHandleInlines.h"
|
||||
#include "nsHostObjectProtocolHandler.h"
|
||||
|
||||
#include "nsIBidiKeyboard.h"
|
||||
|
||||
|
@ -2059,6 +2060,13 @@ ContentParent::ActorDestroy(ActorDestroyReason why)
|
|||
if (mDriverCrashGuard) {
|
||||
mDriverCrashGuard->NotifyCrashed();
|
||||
}
|
||||
|
||||
// Unregister all the BlobURLs registered by the ContentChild.
|
||||
for (uint32_t i = 0; i < mBlobURLs.Length(); ++i) {
|
||||
nsHostObjectProtocolHandler::RemoveDataEntry(mBlobURLs[i]);
|
||||
}
|
||||
|
||||
mBlobURLs.Clear();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -2422,8 +2430,13 @@ ContentParent::InitInternal(ProcessPriority aInitialPriority,
|
|||
// on demand.)
|
||||
bool useOffMainThreadCompositing = !!CompositorThreadHolder::Loop();
|
||||
if (useOffMainThreadCompositing) {
|
||||
DebugOnly<bool> opened = PCompositorBridge::Open(this);
|
||||
GPUProcessManager* gpm = GPUProcessManager::Get();
|
||||
|
||||
Endpoint<PCompositorBridgeChild> endpoint;
|
||||
DebugOnly<bool> opened =
|
||||
gpm->CreateContentCompositorBridge(OtherPid(), &endpoint);
|
||||
MOZ_ASSERT(opened);
|
||||
Unused << SendInitCompositor(Move(endpoint));
|
||||
|
||||
opened = PImageBridge::Open(this);
|
||||
MOZ_ASSERT(opened);
|
||||
|
@ -2513,13 +2526,22 @@ ContentParent::InitInternal(ProcessPriority aInitialPriority,
|
|||
}
|
||||
#endif
|
||||
|
||||
RefPtr<ServiceWorkerRegistrar> swr = ServiceWorkerRegistrar::Get();
|
||||
MOZ_ASSERT(swr);
|
||||
{
|
||||
RefPtr<ServiceWorkerRegistrar> swr = ServiceWorkerRegistrar::Get();
|
||||
MOZ_ASSERT(swr);
|
||||
|
||||
nsTArray<ServiceWorkerRegistrationData> registrations;
|
||||
swr->GetRegistrations(registrations);
|
||||
nsTArray<ServiceWorkerRegistrationData> registrations;
|
||||
swr->GetRegistrations(registrations);
|
||||
Unused << SendInitServiceWorkers(ServiceWorkerConfiguration(registrations));
|
||||
}
|
||||
|
||||
Unused << SendInitServiceWorkers(ServiceWorkerConfiguration(registrations));
|
||||
{
|
||||
nsTArray<BlobURLRegistrationData> registrations;
|
||||
if (nsHostObjectProtocolHandler::GetAllBlobURLEntries(registrations,
|
||||
this)) {
|
||||
Unused << SendInitBlobURLs(registrations);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -3210,14 +3232,6 @@ ContentParent::DeallocPAPZParent(PAPZParent* aActor)
|
|||
return true;
|
||||
}
|
||||
|
||||
PCompositorBridgeParent*
|
||||
ContentParent::AllocPCompositorBridgeParent(mozilla::ipc::Transport* aTransport,
|
||||
base::ProcessId aOtherProcess)
|
||||
{
|
||||
return GPUProcessManager::Get()->CreateTabCompositorBridge(
|
||||
aTransport, aOtherProcess);
|
||||
}
|
||||
|
||||
gfx::PVRManagerParent*
|
||||
ContentParent::AllocPVRManagerParent(Transport* aTransport,
|
||||
ProcessId aOtherProcess)
|
||||
|
@ -5696,6 +5710,73 @@ ContentParent::RecvNotifyLowMemory()
|
|||
return true;
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
ContentParent::BroadcastBlobURLRegistration(const nsACString& aURI,
|
||||
BlobImpl* aBlobImpl,
|
||||
nsIPrincipal* aPrincipal,
|
||||
ContentParent* aIgnoreThisCP)
|
||||
{
|
||||
nsCString uri(aURI);
|
||||
IPC::Principal principal(aPrincipal);
|
||||
|
||||
for (auto* cp : AllProcesses(eLive)) {
|
||||
if (cp != aIgnoreThisCP) {
|
||||
PBlobParent* blobParent = cp->GetOrCreateActorForBlobImpl(aBlobImpl);
|
||||
if (blobParent) {
|
||||
Unused << cp->SendBlobURLRegistration(uri, blobParent, principal);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
ContentParent::BroadcastBlobURLUnregistration(const nsACString& aURI,
|
||||
ContentParent* aIgnoreThisCP)
|
||||
{
|
||||
nsCString uri(aURI);
|
||||
|
||||
for (auto* cp : AllProcesses(eLive)) {
|
||||
if (cp != aIgnoreThisCP) {
|
||||
Unused << cp->SendBlobURLUnregistration(uri);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
ContentParent::RecvStoreAndBroadcastBlobURLRegistration(const nsCString& aURI,
|
||||
PBlobParent* aBlobParent,
|
||||
const Principal& aPrincipal)
|
||||
{
|
||||
RefPtr<BlobImpl> blobImpl =
|
||||
static_cast<BlobParent*>(aBlobParent)->GetBlobImpl();
|
||||
if (NS_WARN_IF(!blobImpl)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (NS_SUCCEEDED(nsHostObjectProtocolHandler::AddDataEntry(aURI, blobImpl,
|
||||
aPrincipal))) {
|
||||
BroadcastBlobURLRegistration(aURI, blobImpl, aPrincipal, this);
|
||||
|
||||
// We want to store this blobURL, so we can unregister it if the child
|
||||
// crashes.
|
||||
mBlobURLs.AppendElement(aURI);
|
||||
}
|
||||
|
||||
BroadcastBlobURLRegistration(aURI, blobImpl, aPrincipal, this);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ContentParent::RecvUnstoreAndBroadcastBlobURLUnregistration(const nsCString& aURI)
|
||||
{
|
||||
nsHostObjectProtocolHandler::RemoveDataEntry(aURI,
|
||||
false /* Don't broadcast */);
|
||||
BroadcastBlobURLUnregistration(aURI, this);
|
||||
mBlobURLs.RemoveElement(aURI);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
|
|
|
@ -66,7 +66,6 @@ class PJavaScriptParent;
|
|||
} // namespace jsipc
|
||||
|
||||
namespace layers {
|
||||
class PCompositorBridgeParent;
|
||||
class PSharedBufferManagerParent;
|
||||
struct TextureFactoryIdentifier;
|
||||
} // namespace layers
|
||||
|
@ -575,6 +574,24 @@ public:
|
|||
|
||||
static bool AllocateLayerTreeId(TabParent* aTabParent, uint64_t* aId);
|
||||
|
||||
static void
|
||||
BroadcastBlobURLRegistration(const nsACString& aURI,
|
||||
BlobImpl* aBlobImpl,
|
||||
nsIPrincipal* aPrincipal,
|
||||
ContentParent* aIgnoreThisCP = nullptr);
|
||||
|
||||
static void
|
||||
BroadcastBlobURLUnregistration(const nsACString& aURI,
|
||||
ContentParent* aIgnoreThisCP = nullptr);
|
||||
|
||||
virtual bool
|
||||
RecvStoreAndBroadcastBlobURLRegistration(const nsCString& aURI,
|
||||
PBlobParent* aBlobParent,
|
||||
const Principal& aPrincipal) override;
|
||||
|
||||
virtual bool
|
||||
RecvUnstoreAndBroadcastBlobURLUnregistration(const nsCString& aURI) override;
|
||||
|
||||
protected:
|
||||
void OnChannelConnected(int32_t pid) override;
|
||||
|
||||
|
@ -728,10 +745,6 @@ private:
|
|||
bool
|
||||
DeallocPAPZParent(PAPZParent* aActor) override;
|
||||
|
||||
PCompositorBridgeParent*
|
||||
AllocPCompositorBridgeParent(mozilla::ipc::Transport* aTransport,
|
||||
base::ProcessId aOtherProcess) override;
|
||||
|
||||
PImageBridgeParent*
|
||||
AllocPImageBridgeParent(mozilla::ipc::Transport* aTransport,
|
||||
base::ProcessId aOtherProcess) override;
|
||||
|
@ -1281,6 +1294,8 @@ private:
|
|||
// This hashtable is used to run GetFilesHelper objects in the parent process.
|
||||
// GetFilesHelper can be aborted by receiving RecvDeleteGetFilesRequest.
|
||||
nsRefPtrHashtable<nsIDHashKey, GetFilesHelper> mGetFilesPendingRequests;
|
||||
|
||||
nsTArray<nsCString> mBlobURLs;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
|
|
@ -373,11 +373,17 @@ union GetFilesResponseResult
|
|||
GetFilesResponseFailure;
|
||||
};
|
||||
|
||||
struct BlobURLRegistrationData
|
||||
{
|
||||
nsCString url;
|
||||
PBlob blob;
|
||||
Principal principal;
|
||||
};
|
||||
|
||||
prio(normal upto urgent) sync protocol PContent
|
||||
{
|
||||
parent spawns PPluginModule;
|
||||
|
||||
parent opens PCompositorBridge;
|
||||
parent opens PProcessHangMonitor;
|
||||
parent opens PSharedBufferManager;
|
||||
parent opens PImageBridge;
|
||||
|
@ -464,6 +470,9 @@ both:
|
|||
uint64_t aOuterWindowID);
|
||||
|
||||
child:
|
||||
// Give the content process its endpoint to the compositor.
|
||||
async InitCompositor(Endpoint<PCompositorBridgeChild> compositor);
|
||||
|
||||
/**
|
||||
* Enable system-level sandboxing features, if available. Can
|
||||
* usually only be performed zero or one times. The child may
|
||||
|
@ -547,6 +556,11 @@ child:
|
|||
*/
|
||||
async InitServiceWorkers(ServiceWorkerConfiguration aConfig);
|
||||
|
||||
/**
|
||||
* Send BlobURLRegistrationData to child process.
|
||||
*/
|
||||
async InitBlobURLs(BlobURLRegistrationData[] registrations);
|
||||
|
||||
// Notify child that last-pb-context-exited notification was observed
|
||||
async LastPrivateDocShellDestroyed();
|
||||
|
||||
|
@ -676,6 +690,11 @@ child:
|
|||
|
||||
async GetFilesResponse(nsID aID, GetFilesResponseResult aResult);
|
||||
|
||||
async BlobURLRegistration(nsCString aURI, PBlob aBlob,
|
||||
Principal aPrincipal);
|
||||
|
||||
async BlobURLUnregistration(nsCString aURI);
|
||||
|
||||
parent:
|
||||
/**
|
||||
* Tell the content process some attributes of itself. This is
|
||||
|
@ -1188,6 +1207,11 @@ parent:
|
|||
async GetFilesRequest(nsID aID, nsString aDirectory, bool aRecursiveFlag);
|
||||
async DeleteGetFilesRequest(nsID aID);
|
||||
|
||||
async StoreAndBroadcastBlobURLRegistration(nsCString url, PBlob blob,
|
||||
Principal principal);
|
||||
|
||||
async UnstoreAndBroadcastBlobURLUnregistration(nsCString url);
|
||||
|
||||
both:
|
||||
async AsyncMessage(nsString aMessage, CpowEntry[] aCpows,
|
||||
Principal aPrincipal, ClonedMessageData aData);
|
||||
|
|
|
@ -47,6 +47,16 @@ parent:
|
|||
* on the chrome side. This is only currently used on Windows.
|
||||
*/
|
||||
sync SetNativeChildWindow(uintptr_t childWindow);
|
||||
|
||||
child:
|
||||
/**
|
||||
* Used to set the ID of a scroll capture container from the parent process,
|
||||
* so that we can create a proxy container in the layer tree.
|
||||
* @param aScrollCaptureId async container ID of the parent container
|
||||
* @param aPluginInstanceId plugin ID on which to set the scroll capture ID
|
||||
*/
|
||||
async SetScrollCaptureId(uint64_t aScrollCaptureId,
|
||||
uintptr_t aPluginInstanceId);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -28,9 +28,13 @@ public:
|
|||
|
||||
operator nsIPrincipal*() const { return mPrincipal.get(); }
|
||||
|
||||
Principal& operator=(const Principal& aOther)
|
||||
{
|
||||
mPrincipal = aOther.mPrincipal;
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
// Unimplemented
|
||||
Principal& operator=(Principal&);
|
||||
nsCOMPtr<nsIPrincipal> mPrincipal;
|
||||
};
|
||||
|
||||
|
|
|
@ -80,7 +80,7 @@ public:
|
|||
if (!sInstance) {
|
||||
sInstance = new ReaderQueue;
|
||||
sInstance->MaxNumActive(MediaPrefs::MediaDecoderLimit());
|
||||
ClearOnShutdown(&sInstance);
|
||||
ClearOnShutdown(&sInstance, ShutdownPhase::Shutdown);
|
||||
}
|
||||
MOZ_ASSERT(sInstance);
|
||||
return *sInstance;
|
||||
|
|
|
@ -327,11 +327,6 @@ PluginPRLibrary::GetScrollCaptureContainer(NPP aInstance, ImageContainer** aCont
|
|||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
nsresult
|
||||
PluginPRLibrary::UpdateScrollState(NPP aInstance, bool aIsScrolling)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
#endif
|
||||
|
||||
nsresult
|
||||
|
|
|
@ -127,7 +127,6 @@ public:
|
|||
virtual void SetHasLocalInstance() override { }
|
||||
#if defined(XP_WIN)
|
||||
virtual nsresult GetScrollCaptureContainer(NPP aInstance, mozilla::layers::ImageContainer** aContainer) override;
|
||||
virtual nsresult UpdateScrollState(NPP aInstance, bool aIsScrolling) override;
|
||||
#endif
|
||||
virtual nsresult HandledWindowedPluginKeyEvent(
|
||||
NPP aInstance,
|
||||
|
|
|
@ -1161,15 +1161,6 @@ nsNPAPIPluginInstance::GetScrollCaptureContainer(ImageContainer**aContainer)
|
|||
AutoPluginLibraryCall library(this);
|
||||
return !library ? NS_ERROR_FAILURE : library->GetScrollCaptureContainer(&mNPP, aContainer);
|
||||
}
|
||||
nsresult
|
||||
nsNPAPIPluginInstance::UpdateScrollState(bool aIsScrolling)
|
||||
{
|
||||
if (RUNNING != mRunning)
|
||||
return NS_OK;
|
||||
|
||||
AutoPluginLibraryCall library(this);
|
||||
return !library ? NS_ERROR_FAILURE : library->UpdateScrollState(&mNPP, aIsScrolling);
|
||||
}
|
||||
#endif
|
||||
|
||||
nsresult
|
||||
|
|
|
@ -122,7 +122,6 @@ public:
|
|||
nsresult GetMIMEType(const char* *result);
|
||||
#if defined(XP_WIN)
|
||||
nsresult GetScrollCaptureContainer(mozilla::layers::ImageContainer **aContainer);
|
||||
nsresult UpdateScrollState(bool aIsScrolling);
|
||||
#endif
|
||||
nsresult HandledWindowedPluginKeyEvent(
|
||||
const mozilla::NativeEventData& aKeyEventData,
|
||||
|
|
|
@ -322,21 +322,6 @@ nsPluginInstanceOwner::GetCurrentImageSize()
|
|||
return size;
|
||||
}
|
||||
|
||||
bool
|
||||
nsPluginInstanceOwner::UpdateScrollState(bool aIsScrolling)
|
||||
{
|
||||
#if defined(XP_WIN)
|
||||
if (!mInstance) {
|
||||
return false;
|
||||
}
|
||||
mScrollState = aIsScrolling;
|
||||
nsresult rv = mInstance->UpdateScrollState(aIsScrolling);
|
||||
return NS_SUCCEEDED(rv);
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
nsPluginInstanceOwner::nsPluginInstanceOwner()
|
||||
: mPluginWindow(nullptr)
|
||||
{
|
||||
|
@ -384,7 +369,6 @@ nsPluginInstanceOwner::nsPluginInstanceOwner()
|
|||
mGotCompositionData = false;
|
||||
mSentStartComposition = false;
|
||||
mPluginDidNotHandleIMEComposition = false;
|
||||
mScrollState = false;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -229,8 +229,6 @@ public:
|
|||
// Returns true if this is windowed plugin that can return static captures
|
||||
// for scroll operations.
|
||||
bool NeedsScrollImageLayer();
|
||||
// Notification we receive from nsPluginFrame about scroll state.
|
||||
bool UpdateScrollState(bool aIsScrolling);
|
||||
|
||||
void DidComposite();
|
||||
|
||||
|
@ -411,9 +409,6 @@ private:
|
|||
#endif
|
||||
|
||||
bool mWaitingForPaint;
|
||||
#if defined(XP_WIN)
|
||||
bool mScrollState;
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif // nsPluginInstanceOwner_h_
|
||||
|
|
|
@ -61,7 +61,6 @@
|
|||
#include "nsIWidget.h"
|
||||
#include "nsPluginNativeWindow.h"
|
||||
#include "PluginQuirks.h"
|
||||
#include "nsWindowsHelpers.h"
|
||||
extern const wchar_t* kFlashFullscreenClass;
|
||||
#elif defined(MOZ_WIDGET_GTK)
|
||||
#include "mozilla/dom/ContentChild.h"
|
||||
|
@ -74,13 +73,6 @@ using namespace mozilla::plugins;
|
|||
using namespace mozilla::layers;
|
||||
using namespace mozilla::gl;
|
||||
|
||||
#if defined(XP_WIN)
|
||||
// Delays associated with attempting an e10s window capture for scrolling.
|
||||
const int kScrollCaptureDelayMs = 100;
|
||||
const int kInitScrollCaptureDelayMs = 1000;
|
||||
const uint32_t kScrollCaptureFillColor = 0xFFa0a0a0; // gray
|
||||
#endif
|
||||
|
||||
void
|
||||
StreamNotifyParent::ActorDestroy(ActorDestroyReason aWhy)
|
||||
{
|
||||
|
@ -143,10 +135,6 @@ PluginInstanceParent::PluginInstanceParent(PluginModuleParent* parent,
|
|||
, mShHeight(0)
|
||||
, mShColorSpace(nullptr)
|
||||
#endif
|
||||
#if defined(XP_WIN)
|
||||
, mValidFirstCapture(false)
|
||||
, mIsScrolling(false)
|
||||
#endif
|
||||
{
|
||||
#if defined(OS_WIN)
|
||||
if (!sPluginInstanceList) {
|
||||
|
@ -171,9 +159,6 @@ PluginInstanceParent::~PluginInstanceParent()
|
|||
if (mShColorSpace)
|
||||
::CGColorSpaceRelease(mShColorSpace);
|
||||
#endif
|
||||
#if defined(XP_WIN)
|
||||
CancelScheduledScrollCapture();
|
||||
#endif
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -448,12 +433,6 @@ PluginInstanceParent::AnswerNPN_SetValue_NPPVpluginWindow(
|
|||
// non-pointer-sized integer.
|
||||
*result = mNPNIface->setvalue(mNPP, NPPVpluginWindowBool,
|
||||
(void*)(intptr_t)windowed);
|
||||
|
||||
#if defined(XP_WIN)
|
||||
if (windowed) {
|
||||
ScheduleScrollCapture(kScrollCaptureDelayMs);
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1207,204 +1186,27 @@ PluginInstanceParent::EndUpdateBackground(const nsIntRect& aRect)
|
|||
}
|
||||
|
||||
#if defined(XP_WIN)
|
||||
//#define CAPTURE_LOG(...) printf_stderr("CAPTURE [%X]: ", this);printf_stderr(__VA_ARGS__);printf_stderr("\n");
|
||||
#define CAPTURE_LOG(...)
|
||||
|
||||
void
|
||||
PluginInstanceParent::ScheduleScrollCapture(int aTimeout)
|
||||
nsresult
|
||||
PluginInstanceParent::SetScrollCaptureId(uint64_t aScrollCaptureId)
|
||||
{
|
||||
if (mCaptureRefreshTask) {
|
||||
return;
|
||||
}
|
||||
CAPTURE_LOG("delayed scroll capture requested.");
|
||||
mCaptureRefreshTask =
|
||||
NewNonOwningCancelableRunnableMethod(this, &PluginInstanceParent::ScheduledUpdateScrollCaptureCallback);
|
||||
RefPtr<Runnable> addrefedTask = mCaptureRefreshTask;
|
||||
MessageLoop::current()->PostDelayedTask(addrefedTask.forget(),
|
||||
kScrollCaptureDelayMs);
|
||||
}
|
||||
if (aScrollCaptureId == ImageContainer::sInvalidAsyncContainerId) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
void
|
||||
PluginInstanceParent::ScheduledUpdateScrollCaptureCallback()
|
||||
{
|
||||
CAPTURE_LOG("taking delayed scrollcapture.");
|
||||
mCaptureRefreshTask = nullptr;
|
||||
bool retrigger = false;
|
||||
UpdateScrollCapture(retrigger);
|
||||
if (retrigger) {
|
||||
// reset the async request
|
||||
ScheduleScrollCapture(kScrollCaptureDelayMs);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PluginInstanceParent::CancelScheduledScrollCapture()
|
||||
{
|
||||
CAPTURE_LOG("delayed scroll capture cancelled.");
|
||||
if (mCaptureRefreshTask) {
|
||||
mCaptureRefreshTask->Cancel();
|
||||
mCaptureRefreshTask = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
PluginInstanceParent::UpdateScrollCapture(bool& aRequestNewCapture)
|
||||
{
|
||||
aRequestNewCapture = false;
|
||||
if (!::IsWindow(mChildPluginHWND)) {
|
||||
CAPTURE_LOG("invalid window");
|
||||
aRequestNewCapture = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
nsAutoHDC windowDC(::GetDC(mChildPluginHWND));
|
||||
if (!windowDC) {
|
||||
CAPTURE_LOG("no windowdc");
|
||||
aRequestNewCapture = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
RECT bounds = {0};
|
||||
::GetWindowRect(mChildPluginHWND, &bounds);
|
||||
if ((bounds.left == bounds.right && bounds.top == bounds.bottom) ||
|
||||
mWindowSize.IsEmpty()) {
|
||||
CAPTURE_LOG("empty bounds");
|
||||
// Lots of null window plugins in content, don't capture.
|
||||
return false;
|
||||
}
|
||||
|
||||
// If we need to init mScrollCapture do so, also reset it if the size of the
|
||||
// plugin window changes.
|
||||
if (!mScrollCapture || mScrollCapture->GetSize() != mWindowSize) {
|
||||
mValidFirstCapture = false;
|
||||
mScrollCapture =
|
||||
gfxPlatform::GetPlatform()->CreateOffscreenSurface(mWindowSize,
|
||||
SurfaceFormat::X8R8G8B8_UINT32);
|
||||
}
|
||||
|
||||
// Check clipping, we don't want to capture windows that are clipped by
|
||||
// the viewport.
|
||||
RECT clip = {0};
|
||||
int rgnType = ::GetWindowRgnBox(mPluginHWND, &clip);
|
||||
bool clipCorrect = !clip.left && !clip.top &&
|
||||
clip.right == mWindowSize.width &&
|
||||
clip.bottom == mWindowSize.height;
|
||||
|
||||
bool isVisible = ::IsWindowVisible(mChildPluginHWND);
|
||||
|
||||
CAPTURE_LOG("validcap=%d visible=%d region=%d clip=%d:%dx%dx%dx%d",
|
||||
mValidFirstCapture, isVisible, rgnType, clipCorrect,
|
||||
clip.left, clip.top, clip.right, clip.bottom);
|
||||
|
||||
// We have a good capture and can't update so keep using the existing
|
||||
// capture image. Otherwise fall through so we paint the fill color to
|
||||
// the layer.
|
||||
if (mValidFirstCapture && (!isVisible || !clipCorrect)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// On Windows we'll need a native bitmap for BitBlt.
|
||||
RefPtr<gfxWindowsSurface> nativeScrollCapture;
|
||||
|
||||
// Copy the plugin window if it's visible and there's no clipping, otherwise
|
||||
// use a default fill color.
|
||||
if (isVisible && clipCorrect) {
|
||||
CAPTURE_LOG("capturing window");
|
||||
nativeScrollCapture =
|
||||
new gfxWindowsSurface(mWindowSize, SurfaceFormat::X8R8G8B8_UINT32);
|
||||
if (!::BitBlt(nativeScrollCapture->GetDC(), 0, 0, mWindowSize.width,
|
||||
mWindowSize.height, windowDC, 0, 0, SRCCOPY)) {
|
||||
CAPTURE_LOG("blt failure??");
|
||||
return false;
|
||||
}
|
||||
::GdiFlush();
|
||||
mValidFirstCapture = true;
|
||||
}
|
||||
|
||||
IntSize targetSize = mScrollCapture->GetSize();
|
||||
|
||||
if (targetSize.IsEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
RefPtr<gfx::DrawTarget> dt =
|
||||
gfxPlatform::GetPlatform()->CreateDrawTargetForSurface(mScrollCapture,
|
||||
targetSize);
|
||||
|
||||
if (nativeScrollCapture) {
|
||||
// Copy the native capture image over to a remotable gfx surface.
|
||||
RefPtr<gfx::SourceSurface> sourceSurface =
|
||||
gfxPlatform::GetPlatform()->GetSourceSurfaceForSurface(nullptr,
|
||||
nativeScrollCapture);
|
||||
dt->CopySurface(sourceSurface,
|
||||
IntRect(0, 0, targetSize.width, targetSize.height),
|
||||
IntPoint());
|
||||
} else {
|
||||
CAPTURE_LOG("using fill color");
|
||||
dt->FillRect(gfx::Rect(0, 0, targetSize.width, targetSize.height),
|
||||
gfx::ColorPattern(gfx::Color::FromABGR(kScrollCaptureFillColor)),
|
||||
gfx::DrawOptions(1.f, CompositionOp::OP_SOURCE));
|
||||
aRequestNewCapture = true;
|
||||
}
|
||||
dt->Flush();
|
||||
|
||||
// Get a source for mScrollCapture and load it into the image container.
|
||||
RefPtr<gfx::SourceSurface> cachedSource =
|
||||
gfxPlatform::GetPlatform()->GetSourceSurfaceForSurface(dt,
|
||||
mScrollCapture);
|
||||
RefPtr<SourceSurfaceImage> image =
|
||||
new SourceSurfaceImage(cachedSource->GetSize(), cachedSource);
|
||||
|
||||
ImageContainer::NonOwningImage holder(image);
|
||||
holder.mFrameID = ++mFrameID;
|
||||
|
||||
AutoTArray<ImageContainer::NonOwningImage,1> imageList;
|
||||
imageList.AppendElement(holder);
|
||||
|
||||
// inits mImageContainer
|
||||
ImageContainer *container = GetImageContainer();
|
||||
container->SetCurrentImages(imageList);
|
||||
|
||||
// Invalidate our area in the page so the image gets flushed.
|
||||
NPRect nprect = {0, 0, targetSize.width, targetSize.height};
|
||||
RecvNPN_InvalidateRect(nprect);
|
||||
|
||||
return true;
|
||||
mImageContainer = new ImageContainer(aScrollCaptureId);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
PluginInstanceParent::GetScrollCaptureContainer(ImageContainer** aContainer)
|
||||
{
|
||||
if (!aContainer || !::IsWindow(mPluginHWND)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
if (!mImageContainer) {
|
||||
ScheduleScrollCapture(kInitScrollCaptureDelayMs);
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
ImageContainer *container = GetImageContainer();
|
||||
NS_IF_ADDREF(container);
|
||||
*aContainer = container;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
PluginInstanceParent::UpdateScrollState(bool aIsScrolling)
|
||||
{
|
||||
bool scrollStateChanged = (mIsScrolling != aIsScrolling);
|
||||
mIsScrolling = aIsScrolling;
|
||||
if (scrollStateChanged && !aIsScrolling) {
|
||||
// At the end of a dom scroll operation capturing now will attempt to
|
||||
// capture a window that is still hidden due to the current scroll
|
||||
// operation. (The browser process will update visibility after layer
|
||||
// updates get pushed over.) So we delay our attempt for a bit. This
|
||||
// shouldn't hurt our chances of capturing with APZ scroll since the
|
||||
// delay is short.
|
||||
ScheduleScrollCapture(kScrollCaptureDelayMs);
|
||||
if (!aContainer || !mImageContainer) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
RefPtr<ImageContainer> container = GetImageContainer();
|
||||
container.forget(aContainer);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
#endif // XP_WIN
|
||||
|
@ -1561,9 +1363,6 @@ PluginInstanceParent::NPP_SetWindow(const NPWindow* aWindow)
|
|||
window.type = aWindow->type;
|
||||
#endif
|
||||
|
||||
mWindowSize.width = window.width;
|
||||
mWindowSize.height = window.height;
|
||||
|
||||
#if defined(XP_MACOSX)
|
||||
double floatScaleFactor = 1.0;
|
||||
mNPNIface->getvalue(mNPP, NPNVcontentsScaleFactor, &floatScaleFactor);
|
||||
|
@ -1608,12 +1407,6 @@ PluginInstanceParent::NPP_SetWindow(const NPWindow* aWindow)
|
|||
}
|
||||
|
||||
RecordDrawingModel();
|
||||
|
||||
#if defined(XP_WIN)
|
||||
if (!mCaptureRefreshTask) {
|
||||
ScheduleScrollCapture(kScrollCaptureDelayMs);
|
||||
}
|
||||
#endif
|
||||
return NPERR_NO_ERROR;
|
||||
}
|
||||
|
||||
|
|
|
@ -331,8 +331,8 @@ public:
|
|||
DrawTarget** aDrawTarget);
|
||||
nsresult EndUpdateBackground(const nsIntRect& aRect);
|
||||
#if defined(XP_WIN)
|
||||
nsresult SetScrollCaptureId(uint64_t aScrollCaptureId);
|
||||
nsresult GetScrollCaptureContainer(mozilla::layers::ImageContainer** aContainer);
|
||||
nsresult UpdateScrollState(bool aIsScrolling);
|
||||
#endif
|
||||
void DidComposite();
|
||||
|
||||
|
@ -400,7 +400,6 @@ private:
|
|||
nsCString mSrcAttribute;
|
||||
NPWindowType mWindowType;
|
||||
int16_t mDrawingModel;
|
||||
IntSize mWindowSize;
|
||||
|
||||
// Since plugins may request different drawing models to find a compatible
|
||||
// one, we only record the drawing model after a SetWindow call and if the
|
||||
|
@ -465,18 +464,6 @@ private:
|
|||
RefPtr<gfxASurface> mBackground;
|
||||
|
||||
RefPtr<ImageContainer> mImageContainer;
|
||||
|
||||
#if defined(XP_WIN)
|
||||
void ScheduleScrollCapture(int aTimeout);
|
||||
void ScheduledUpdateScrollCaptureCallback();
|
||||
bool UpdateScrollCapture(bool& aRequestNewCapture);
|
||||
void CancelScheduledScrollCapture();
|
||||
|
||||
RefPtr<gfxASurface> mScrollCapture;
|
||||
RefPtr<CancelableRunnable> mCaptureRefreshTask;
|
||||
bool mValidFirstCapture;
|
||||
bool mIsScrolling;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -89,7 +89,6 @@ public:
|
|||
#endif
|
||||
#if defined(XP_WIN)
|
||||
virtual nsresult GetScrollCaptureContainer(NPP aInstance, mozilla::layers::ImageContainer** aContainer) = 0;
|
||||
virtual nsresult UpdateScrollState(NPP aInstance, bool aIsScrolling) = 0;
|
||||
#endif
|
||||
virtual nsresult HandledWindowedPluginKeyEvent(
|
||||
NPP aInstance,
|
||||
|
|
|
@ -2033,12 +2033,6 @@ PluginModuleParent::GetScrollCaptureContainer(NPP aInstance,
|
|||
PluginInstanceParent* inst = PluginInstanceParent::Cast(aInstance);
|
||||
return !inst ? NS_ERROR_FAILURE : inst->GetScrollCaptureContainer(aContainer);
|
||||
}
|
||||
nsresult
|
||||
PluginModuleParent::UpdateScrollState(NPP aInstance, bool aIsScrolling)
|
||||
{
|
||||
PluginInstanceParent* inst = PluginInstanceParent::Cast(aInstance);
|
||||
return !inst ? NS_ERROR_FAILURE : inst->UpdateScrollState(aIsScrolling);
|
||||
}
|
||||
#endif
|
||||
|
||||
nsresult
|
||||
|
|
|
@ -263,7 +263,6 @@ protected:
|
|||
|
||||
#if defined(XP_WIN)
|
||||
virtual nsresult GetScrollCaptureContainer(NPP aInstance, mozilla::layers::ImageContainer** aContainer) override;
|
||||
virtual nsresult UpdateScrollState(NPP aInstance, bool aIsScrolling);
|
||||
#endif
|
||||
|
||||
virtual nsresult HandledWindowedPluginKeyEvent(
|
||||
|
|
|
@ -12,6 +12,10 @@
|
|||
#include "mozilla/DebugOnly.h"
|
||||
#include "nsDebug.h"
|
||||
|
||||
#if defined(XP_WIN)
|
||||
#include "mozilla/plugins/PluginInstanceParent.h"
|
||||
#endif
|
||||
|
||||
#define PWLOG(...)
|
||||
//#define PWLOG(...) printf_stderr(__VA_ARGS__)
|
||||
|
||||
|
@ -31,6 +35,25 @@ PluginWidgetChild::~PluginWidgetChild()
|
|||
MOZ_COUNT_DTOR(PluginWidgetChild);
|
||||
}
|
||||
|
||||
bool
|
||||
PluginWidgetChild::RecvSetScrollCaptureId(const uint64_t& aScrollCaptureId,
|
||||
const uintptr_t& aPluginInstanceId)
|
||||
{
|
||||
#if defined(XP_WIN)
|
||||
PluginInstanceParent* instance =
|
||||
PluginInstanceParent::LookupPluginInstanceByID(aPluginInstanceId);
|
||||
if (instance) {
|
||||
NS_WARN_IF(NS_FAILED(instance->SetScrollCaptureId(aScrollCaptureId)));
|
||||
}
|
||||
|
||||
return true;
|
||||
#else
|
||||
MOZ_ASSERT_UNREACHABLE(
|
||||
"PluginWidgetChild::RecvSetScrollCaptureId calls not expected.");
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Called by the proxy widget when it is destroyed by layout. Only gets
|
||||
// called once.
|
||||
void
|
||||
|
|
|
@ -19,6 +19,9 @@ public:
|
|||
PluginWidgetChild();
|
||||
virtual ~PluginWidgetChild();
|
||||
|
||||
bool RecvSetScrollCaptureId(const uint64_t& aScrollCaptureId,
|
||||
const uintptr_t& aPluginInstanceId) override;
|
||||
|
||||
virtual void ActorDestroy(ActorDestroyReason aWhy) override;
|
||||
|
||||
void SetWidget(mozilla::widget::PluginWidgetProxy* aWidget) {
|
||||
|
|
|
@ -143,6 +143,11 @@ PluginWidgetParent::RecvCreate(nsresult* aResult)
|
|||
mozilla::dom::kPluginWidgetContentParentProperty,
|
||||
GetTabParent()->Manager()->AsContentParent());
|
||||
NS_ASSERTION(winres, "SetPropW call failure");
|
||||
|
||||
uint64_t scrollCaptureId = mWidget->CreateScrollCaptureContainer();
|
||||
uintptr_t pluginId =
|
||||
reinterpret_cast<uintptr_t>(mWidget->GetNativeData(NS_NATIVE_PLUGIN_ID));
|
||||
Unused << SendSetScrollCaptureId(scrollCaptureId, pluginId);
|
||||
#endif
|
||||
|
||||
// This is a special call we make to nsBaseWidget to register this
|
||||
|
|
|
@ -1904,8 +1904,11 @@ public:
|
|||
!JS_DefineElement(cx, values, index, value, JSPROP_ENUMERATE)) {
|
||||
MOZ_ASSERT(JS_IsExceptionPending(cx));
|
||||
JS::Rooted<JS::Value> exn(cx);
|
||||
jsapi.StealException(&exn);
|
||||
mPromise->MaybeReject(cx, exn);
|
||||
if (!jsapi.StealException(&exn)) {
|
||||
mPromise->MaybeReject(NS_ERROR_OUT_OF_MEMORY);
|
||||
} else {
|
||||
mPromise->MaybeReject(cx, exn);
|
||||
}
|
||||
}
|
||||
|
||||
--mCountdown;
|
||||
|
@ -2761,7 +2764,7 @@ Promise::Settle(JS::Handle<JS::Value> aValue, PromiseState aState)
|
|||
if (aState == PromiseState::Rejected &&
|
||||
!mHadRejectCallback &&
|
||||
!NS_IsMainThread()) {
|
||||
workers::WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
|
||||
WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
|
||||
MOZ_ASSERT(worker);
|
||||
worker->AssertIsOnWorkerThread();
|
||||
|
||||
|
@ -2825,9 +2828,9 @@ Promise::RemoveWorkerHolder()
|
|||
}
|
||||
|
||||
bool
|
||||
PromiseReportRejectWorkerHolder::Notify(workers::Status aStatus)
|
||||
PromiseReportRejectWorkerHolder::Notify(Status aStatus)
|
||||
{
|
||||
MOZ_ASSERT(aStatus > workers::Running);
|
||||
MOZ_ASSERT(aStatus > Running);
|
||||
mPromise->MaybeReportRejectedOnce();
|
||||
// After this point, `this` has been deleted by RemoveWorkerHolder!
|
||||
return true;
|
||||
|
@ -2879,7 +2882,7 @@ Promise::GetDependentPromises(nsTArray<RefPtr<Promise>>& aPromises)
|
|||
|
||||
// A WorkerRunnable to resolve/reject the Promise on the worker thread.
|
||||
// Calling thread MUST hold PromiseWorkerProxy's mutex before creating this.
|
||||
class PromiseWorkerProxyRunnable : public workers::WorkerRunnable
|
||||
class PromiseWorkerProxyRunnable : public WorkerRunnable
|
||||
{
|
||||
public:
|
||||
PromiseWorkerProxyRunnable(PromiseWorkerProxy* aPromiseWorkerProxy,
|
||||
|
@ -2894,7 +2897,7 @@ public:
|
|||
}
|
||||
|
||||
virtual bool
|
||||
WorkerRun(JSContext* aCx, workers::WorkerPrivate* aWorkerPrivate)
|
||||
WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
|
||||
{
|
||||
MOZ_ASSERT(aWorkerPrivate);
|
||||
aWorkerPrivate->AssertIsOnWorkerThread();
|
||||
|
@ -2927,9 +2930,32 @@ private:
|
|||
PromiseWorkerProxy::RunCallbackFunc mFunc;
|
||||
};
|
||||
|
||||
class PromiseWorkerHolder final : public WorkerHolder
|
||||
{
|
||||
// RawPointer because this proxy keeps alive the holder.
|
||||
PromiseWorkerProxy* mProxy;
|
||||
|
||||
public:
|
||||
explicit PromiseWorkerHolder(PromiseWorkerProxy* aProxy)
|
||||
: mProxy(aProxy)
|
||||
{
|
||||
MOZ_ASSERT(aProxy);
|
||||
}
|
||||
|
||||
bool
|
||||
Notify(Status aStatus) override
|
||||
{
|
||||
if (aStatus >= Canceling) {
|
||||
mProxy->CleanUp();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
/* static */
|
||||
already_AddRefed<PromiseWorkerProxy>
|
||||
PromiseWorkerProxy::Create(workers::WorkerPrivate* aWorkerPrivate,
|
||||
PromiseWorkerProxy::Create(WorkerPrivate* aWorkerPrivate,
|
||||
Promise* aWorkerPromise,
|
||||
const PromiseWorkerProxyStructuredCloneCallbacks* aCb)
|
||||
{
|
||||
|
@ -2955,7 +2981,7 @@ PromiseWorkerProxy::Create(workers::WorkerPrivate* aWorkerPrivate,
|
|||
|
||||
NS_IMPL_ISUPPORTS0(PromiseWorkerProxy)
|
||||
|
||||
PromiseWorkerProxy::PromiseWorkerProxy(workers::WorkerPrivate* aWorkerPrivate,
|
||||
PromiseWorkerProxy::PromiseWorkerProxy(WorkerPrivate* aWorkerPrivate,
|
||||
Promise* aWorkerPromise,
|
||||
const PromiseWorkerProxyStructuredCloneCallbacks* aCallbacks)
|
||||
: mWorkerPrivate(aWorkerPrivate)
|
||||
|
@ -2963,16 +2989,13 @@ PromiseWorkerProxy::PromiseWorkerProxy(workers::WorkerPrivate* aWorkerPrivate,
|
|||
, mCleanedUp(false)
|
||||
, mCallbacks(aCallbacks)
|
||||
, mCleanUpLock("cleanUpLock")
|
||||
#ifdef DEBUG
|
||||
, mWorkerHolderAdded(false)
|
||||
#endif
|
||||
{
|
||||
}
|
||||
|
||||
PromiseWorkerProxy::~PromiseWorkerProxy()
|
||||
{
|
||||
MOZ_ASSERT(mCleanedUp);
|
||||
MOZ_ASSERT(!mWorkerHolderAdded);
|
||||
MOZ_ASSERT(!mWorkerHolder);
|
||||
MOZ_ASSERT(!mWorkerPromise);
|
||||
MOZ_ASSERT(!mWorkerPrivate);
|
||||
}
|
||||
|
@ -2981,7 +3004,7 @@ void
|
|||
PromiseWorkerProxy::CleanProperties()
|
||||
{
|
||||
#ifdef DEBUG
|
||||
workers::WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
|
||||
WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
|
||||
MOZ_ASSERT(worker);
|
||||
worker->AssertIsOnWorkerThread();
|
||||
#endif
|
||||
|
@ -3000,21 +3023,21 @@ PromiseWorkerProxy::AddRefObject()
|
|||
{
|
||||
MOZ_ASSERT(mWorkerPrivate);
|
||||
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
MOZ_ASSERT(!mWorkerHolderAdded);
|
||||
if (NS_WARN_IF(!HoldWorker(mWorkerPrivate))) {
|
||||
|
||||
MOZ_ASSERT(!mWorkerHolder);
|
||||
mWorkerHolder.reset(new PromiseWorkerHolder(this));
|
||||
if (NS_WARN_IF(!mWorkerHolder->HoldWorker(mWorkerPrivate))) {
|
||||
mWorkerHolder = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
mWorkerHolderAdded = true;
|
||||
#endif
|
||||
// Maintain a reference so that we have a valid object to clean up when
|
||||
// removing the feature.
|
||||
AddRef();
|
||||
return true;
|
||||
}
|
||||
|
||||
workers::WorkerPrivate*
|
||||
WorkerPrivate*
|
||||
PromiseWorkerProxy::GetWorkerPrivate() const
|
||||
{
|
||||
#ifdef DEBUG
|
||||
|
@ -3025,7 +3048,7 @@ PromiseWorkerProxy::GetWorkerPrivate() const
|
|||
// Safe to check this without a lock since we assert lock ownership on the
|
||||
// main thread above.
|
||||
MOZ_ASSERT(!mCleanedUp);
|
||||
MOZ_ASSERT(mWorkerHolderAdded);
|
||||
MOZ_ASSERT(mWorkerHolder);
|
||||
|
||||
return mWorkerPrivate;
|
||||
}
|
||||
|
@ -3034,7 +3057,7 @@ Promise*
|
|||
PromiseWorkerProxy::WorkerPromise() const
|
||||
{
|
||||
#ifdef DEBUG
|
||||
workers::WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
|
||||
WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
|
||||
MOZ_ASSERT(worker);
|
||||
worker->AssertIsOnWorkerThread();
|
||||
#endif
|
||||
|
@ -3091,16 +3114,6 @@ PromiseWorkerProxy::RejectedCallback(JSContext* aCx,
|
|||
RunCallback(aCx, aValue, &Promise::MaybeReject);
|
||||
}
|
||||
|
||||
bool
|
||||
PromiseWorkerProxy::Notify(Status aStatus)
|
||||
{
|
||||
if (aStatus >= Canceling) {
|
||||
CleanUp();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
PromiseWorkerProxy::CleanUp()
|
||||
{
|
||||
|
@ -3118,14 +3131,12 @@ PromiseWorkerProxy::CleanUp()
|
|||
MOZ_ASSERT(mWorkerPrivate);
|
||||
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
|
||||
// Release the Promise and remove the PromiseWorkerProxy from the features of
|
||||
// Release the Promise and remove the PromiseWorkerProxy from the holders of
|
||||
// the worker thread since the Promise has been resolved/rejected or the
|
||||
// worker thread has been cancelled.
|
||||
MOZ_ASSERT(mWorkerHolderAdded);
|
||||
ReleaseWorker();
|
||||
#ifdef DEBUG
|
||||
mWorkerHolderAdded = false;
|
||||
#endif
|
||||
MOZ_ASSERT(mWorkerHolder);
|
||||
mWorkerHolder = nullptr;
|
||||
|
||||
CleanProperties();
|
||||
}
|
||||
Release();
|
||||
|
|
|
@ -90,7 +90,7 @@ public:
|
|||
protected:
|
||||
static void FlushUncaughtRejectionsInternal();
|
||||
friend class FlushRejections;
|
||||
friend class WorkerPrivate;
|
||||
friend class mozilla::dom::workers::WorkerPrivate;
|
||||
private:
|
||||
// Identity of the process.
|
||||
// This property is:
|
||||
|
|
|
@ -110,7 +110,6 @@ class WorkerPrivate;
|
|||
// references to it are dropped.
|
||||
|
||||
class PromiseWorkerProxy : public PromiseNativeHandler
|
||||
, public workers::WorkerHolder
|
||||
, public StructuredCloneHolderBase
|
||||
{
|
||||
friend class PromiseWorkerProxyRunnable;
|
||||
|
@ -185,8 +184,6 @@ protected:
|
|||
virtual void RejectedCallback(JSContext* aCx,
|
||||
JS::Handle<JS::Value> aValue) override;
|
||||
|
||||
virtual bool Notify(workers::Status aStatus) override;
|
||||
|
||||
private:
|
||||
PromiseWorkerProxy(workers::WorkerPrivate* aWorkerPrivate,
|
||||
Promise* aWorkerPromise,
|
||||
|
@ -227,10 +224,7 @@ private:
|
|||
// Ensure the worker and the main thread won't race to access |mCleanedUp|.
|
||||
Mutex mCleanUpLock;
|
||||
|
||||
#ifdef DEBUG
|
||||
// Maybe get rid of this entirely and rely on mCleanedUp
|
||||
bool mWorkerHolderAdded;
|
||||
#endif
|
||||
UniquePtr<workers::WorkerHolder> mWorkerHolder;
|
||||
};
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -321,6 +321,14 @@ interface WebGL2RenderingContext : WebGLRenderingContext
|
|||
void getBufferSubData(GLenum target, GLintptr offset, ArrayBuffer? returnedData);
|
||||
void getBufferSubData(GLenum target, GLintptr offset, SharedArrayBuffer returnedData);
|
||||
|
||||
[Throws] /* Throws on readback in a write-only context. */
|
||||
void readPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format,
|
||||
GLenum type, GLintptr offset);
|
||||
/* Include our WebGL 1 function override(s) */
|
||||
[Throws]
|
||||
void readPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format,
|
||||
GLenum type, ArrayBufferView? pixels);
|
||||
|
||||
/* Framebuffer objects */
|
||||
void blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0,
|
||||
GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
|
||||
|
|
|
@ -541,10 +541,12 @@ private:
|
|||
|
||||
NS_IMPL_ISUPPORTS(LoaderListener, nsIStreamLoaderObserver, nsIRequestObserver)
|
||||
|
||||
class ScriptLoaderRunnable final : public WorkerHolder
|
||||
, public nsIRunnable
|
||||
class ScriptLoaderHolder;
|
||||
|
||||
class ScriptLoaderRunnable final : public nsIRunnable
|
||||
{
|
||||
friend class ScriptExecutorRunnable;
|
||||
friend class ScriptLoaderHolder;
|
||||
friend class CachePromiseHandler;
|
||||
friend class CacheScriptLoader;
|
||||
friend class LoaderListener;
|
||||
|
@ -718,8 +720,8 @@ private:
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
virtual bool
|
||||
Notify(Status aStatus) override
|
||||
bool
|
||||
Notify(Status aStatus)
|
||||
{
|
||||
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
|
||||
|
@ -1039,7 +1041,7 @@ private:
|
|||
// Note that for data: url, where we allow it through the same-origin check
|
||||
// but then give it a different origin.
|
||||
aLoadInfo.mMutedErrorFlag.emplace(IsMainWorkerScript()
|
||||
? false
|
||||
? false
|
||||
: !principal->Subsumes(channelPrincipal));
|
||||
|
||||
// Make sure we're not seeing the result of a 404 or something by checking
|
||||
|
@ -1356,6 +1358,26 @@ private:
|
|||
|
||||
NS_IMPL_ISUPPORTS(ScriptLoaderRunnable, nsIRunnable)
|
||||
|
||||
class MOZ_STACK_CLASS ScriptLoaderHolder final : public WorkerHolder
|
||||
{
|
||||
// Raw pointer because this holder object follows the mRunnable life-time.
|
||||
ScriptLoaderRunnable* mRunnable;
|
||||
|
||||
public:
|
||||
explicit ScriptLoaderHolder(ScriptLoaderRunnable* aRunnable)
|
||||
: mRunnable(aRunnable)
|
||||
{
|
||||
MOZ_ASSERT(aRunnable);
|
||||
}
|
||||
|
||||
virtual bool
|
||||
Notify(Status aStatus) override
|
||||
{
|
||||
mRunnable->Notify(aStatus);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
NS_IMETHODIMP
|
||||
LoaderListener::OnStreamComplete(nsIStreamLoader* aLoader, nsISupports* aContext,
|
||||
nsresult aStatus, uint32_t aStringLen,
|
||||
|
@ -2008,7 +2030,6 @@ ScriptExecutorRunnable::ShutdownScriptLoader(JSContext* aCx,
|
|||
}
|
||||
}
|
||||
|
||||
mScriptLoader.ReleaseWorker();
|
||||
aWorkerPrivate->StopSyncLoop(mSyncLoopTarget, aResult);
|
||||
}
|
||||
|
||||
|
@ -2060,15 +2081,15 @@ LoadAllScripts(WorkerPrivate* aWorkerPrivate,
|
|||
|
||||
NS_ASSERTION(aLoadInfos.IsEmpty(), "Should have swapped!");
|
||||
|
||||
if (NS_WARN_IF(!loader->HoldWorker(aWorkerPrivate))) {
|
||||
ScriptLoaderHolder workerHolder(loader);
|
||||
|
||||
if (NS_WARN_IF(!workerHolder.HoldWorker(aWorkerPrivate))) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return;
|
||||
}
|
||||
|
||||
if (NS_FAILED(NS_DispatchToMainThread(loader))) {
|
||||
NS_ERROR("Failed to dispatch!");
|
||||
|
||||
loader->ReleaseWorker();
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ WorkerHolder::WorkerHolder()
|
|||
|
||||
WorkerHolder::~WorkerHolder()
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(WorkerHolder);
|
||||
ReleaseWorkerInternal();
|
||||
MOZ_ASSERT(mWorkerPrivate == nullptr);
|
||||
}
|
||||
|
@ -23,6 +24,7 @@ WorkerHolder::~WorkerHolder()
|
|||
bool
|
||||
WorkerHolder::HoldWorker(WorkerPrivate* aWorkerPrivate)
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(WorkerHolder);
|
||||
MOZ_ASSERT(aWorkerPrivate);
|
||||
aWorkerPrivate->AssertIsOnWorkerThread();
|
||||
|
||||
|
@ -37,13 +39,17 @@ WorkerHolder::HoldWorker(WorkerPrivate* aWorkerPrivate)
|
|||
void
|
||||
WorkerHolder::ReleaseWorker()
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(WorkerHolder);
|
||||
MOZ_ASSERT(mWorkerPrivate);
|
||||
|
||||
ReleaseWorkerInternal();
|
||||
}
|
||||
|
||||
void
|
||||
WorkerHolder::ReleaseWorkerInternal()
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(WorkerHolder);
|
||||
|
||||
if (mWorkerPrivate) {
|
||||
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
mWorkerPrivate->RemoveHolder(this);
|
||||
|
|
|
@ -72,6 +72,8 @@ enum Status
|
|||
class WorkerHolder
|
||||
{
|
||||
public:
|
||||
NS_DECL_OWNINGTHREAD
|
||||
|
||||
WorkerHolder();
|
||||
virtual ~WorkerHolder();
|
||||
|
||||
|
@ -84,6 +86,9 @@ protected:
|
|||
void ReleaseWorkerInternal();
|
||||
|
||||
WorkerPrivate* MOZ_NON_OWNING_REF mWorkerPrivate;
|
||||
|
||||
private:
|
||||
void AssertIsOwningThread() const;
|
||||
};
|
||||
|
||||
END_WORKERS_NAMESPACE
|
||||
|
|
|
@ -728,7 +728,8 @@ WorkerProxyToMainThreadRunnable::PostDispatchOnMainThread()
|
|||
|
||||
mRunnable->RunBackOnWorkerThread();
|
||||
|
||||
aWorkerPrivate->ModifyBusyCountFromWorker(true);
|
||||
// Let's release the worker thread.
|
||||
aWorkerPrivate->ModifyBusyCountFromWorker(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -903,9 +903,13 @@ GLBlitHelper::BlitImageToFramebuffer(layers::Image* srcImage,
|
|||
return BlitGrallocImage(static_cast<layers::GrallocImage*>(srcImage));
|
||||
#endif
|
||||
|
||||
case ConvertPlanarYCbCr:
|
||||
mGL->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 1);
|
||||
return BlitPlanarYCbCrImage(static_cast<PlanarYCbCrImage*>(srcImage));
|
||||
case ConvertPlanarYCbCr: {
|
||||
const auto saved = mGL->GetIntAs<GLint>(LOCAL_GL_UNPACK_ALIGNMENT);
|
||||
mGL->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 1);
|
||||
const auto ret = BlitPlanarYCbCrImage(static_cast<PlanarYCbCrImage*>(srcImage));
|
||||
mGL->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, saved);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef MOZ_WIDGET_ANDROID
|
||||
case ConvertSurfaceTexture:
|
||||
|
|
|
@ -19,10 +19,6 @@
|
|||
#include <string.h>
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#ifdef GetClassName
|
||||
#undef GetClassName
|
||||
#endif
|
||||
|
@ -42,7 +38,6 @@
|
|||
#include "nsISupportsImpl.h"
|
||||
#include "plstr.h"
|
||||
#include "GLContextTypes.h"
|
||||
//#include "GLTextureImage.h"
|
||||
#include "SurfaceTypes.h"
|
||||
#include "GLContextSymbols.h"
|
||||
#include "base/platform_thread.h" // for PlatformThreadId
|
||||
|
@ -1228,6 +1223,14 @@ public:
|
|||
fGetIntegerv(pname, reinterpret_cast<GLint*>(params));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T GetIntAs(GLenum pname) {
|
||||
static_assert(sizeof(T) == sizeof(GLint), "Invalid T.");
|
||||
T ret = 0;
|
||||
fGetIntegerv(pname, (GLint*)&ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void fGetFloatv(GLenum pname, GLfloat* params) {
|
||||
BEFORE_GL_CALL;
|
||||
mSymbols.fGetFloatv(pname, params);
|
||||
|
|
|
@ -6,6 +6,10 @@
|
|||
|
||||
#include "nsDebug.h"
|
||||
|
||||
#ifdef WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
namespace gl {
|
||||
|
||||
|
|
|
@ -7,10 +7,6 @@
|
|||
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#include "GLDefs.h"
|
||||
#include "nscore.h"
|
||||
#include "prlink.h"
|
||||
|
|
|
@ -393,22 +393,18 @@ ReadPixelsIntoDataSurface(GLContext* gl, DataSourceSurface* dest)
|
|||
MOZ_ASSERT(readAlignment);
|
||||
MOZ_ASSERT(reinterpret_cast<uintptr_t>(readSurf->GetData()) % readAlignment == 0);
|
||||
|
||||
GLint currentPackAlignment = 0;
|
||||
gl->fGetIntegerv(LOCAL_GL_PACK_ALIGNMENT, ¤tPackAlignment);
|
||||
|
||||
if (currentPackAlignment != readAlignment)
|
||||
gl->fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, readAlignment);
|
||||
|
||||
GLsizei width = dest->GetSize().width;
|
||||
GLsizei height = dest->GetSize().height;
|
||||
|
||||
gl->fReadPixels(0, 0,
|
||||
width, height,
|
||||
readFormat, readType,
|
||||
readSurf->GetData());
|
||||
{
|
||||
ScopedPackState safePackState(gl);
|
||||
gl->fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, readAlignment);
|
||||
|
||||
if (currentPackAlignment != readAlignment)
|
||||
gl->fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, currentPackAlignment);
|
||||
gl->fReadPixels(0, 0,
|
||||
width, height,
|
||||
readFormat, readType,
|
||||
readSurf->GetData());
|
||||
}
|
||||
|
||||
if (readSurf != dest) {
|
||||
MOZ_ASSERT(readFormat == LOCAL_GL_RGBA);
|
||||
|
|
|
@ -86,9 +86,6 @@ ScopedBindFramebuffer::ScopedBindFramebuffer(GLContext* aGL, GLuint aNewFB)
|
|||
void
|
||||
ScopedBindFramebuffer::UnwrapImpl()
|
||||
{
|
||||
// Check that we're not falling out of scope after the current context changed.
|
||||
MOZ_ASSERT(mGL->IsCurrent());
|
||||
|
||||
if (mOldReadFB == mOldDrawFB) {
|
||||
mGL->BindFB(mOldDrawFB);
|
||||
} else {
|
||||
|
@ -110,9 +107,6 @@ ScopedBindTextureUnit::ScopedBindTextureUnit(GLContext* aGL, GLenum aTexUnit)
|
|||
|
||||
void
|
||||
ScopedBindTextureUnit::UnwrapImpl() {
|
||||
// Check that we're not falling out of scope after the current context changed.
|
||||
MOZ_ASSERT(mGL->IsCurrent());
|
||||
|
||||
mGL->fActiveTexture(mOldTexUnit);
|
||||
}
|
||||
|
||||
|
@ -122,35 +116,26 @@ ScopedBindTextureUnit::UnwrapImpl() {
|
|||
ScopedTexture::ScopedTexture(GLContext* aGL)
|
||||
: ScopedGLWrapper<ScopedTexture>(aGL)
|
||||
{
|
||||
MOZ_ASSERT(mGL->IsCurrent());
|
||||
mGL->fGenTextures(1, &mTexture);
|
||||
}
|
||||
|
||||
void
|
||||
ScopedTexture::UnwrapImpl()
|
||||
{
|
||||
// Check that we're not falling out of scope after
|
||||
// the current context changed.
|
||||
MOZ_ASSERT(mGL->IsCurrent());
|
||||
mGL->fDeleteTextures(1, &mTexture);
|
||||
}
|
||||
|
||||
|
||||
/* ScopedFramebuffer **************************************************************/
|
||||
|
||||
ScopedFramebuffer::ScopedFramebuffer(GLContext* aGL)
|
||||
: ScopedGLWrapper<ScopedFramebuffer>(aGL)
|
||||
{
|
||||
MOZ_ASSERT(mGL->IsCurrent());
|
||||
mGL->fGenFramebuffers(1, &mFB);
|
||||
}
|
||||
|
||||
void
|
||||
ScopedFramebuffer::UnwrapImpl()
|
||||
{
|
||||
// Check that we're not falling out of scope after
|
||||
// the current context changed.
|
||||
MOZ_ASSERT(mGL->IsCurrent());
|
||||
mGL->fDeleteFramebuffers(1, &mFB);
|
||||
}
|
||||
|
||||
|
@ -160,16 +145,12 @@ ScopedFramebuffer::UnwrapImpl()
|
|||
ScopedRenderbuffer::ScopedRenderbuffer(GLContext* aGL)
|
||||
: ScopedGLWrapper<ScopedRenderbuffer>(aGL)
|
||||
{
|
||||
MOZ_ASSERT(mGL->IsCurrent());
|
||||
mGL->fGenRenderbuffers(1, &mRB);
|
||||
}
|
||||
|
||||
void
|
||||
ScopedRenderbuffer::UnwrapImpl()
|
||||
{
|
||||
// Check that we're not falling out of scope after
|
||||
// the current context changed.
|
||||
MOZ_ASSERT(mGL->IsCurrent());
|
||||
mGL->fDeleteRenderbuffers(1, &mRB);
|
||||
}
|
||||
|
||||
|
@ -251,10 +232,8 @@ ScopedBindRenderbuffer::ScopedBindRenderbuffer(GLContext* aGL, GLuint aNewRB)
|
|||
}
|
||||
|
||||
void
|
||||
ScopedBindRenderbuffer::UnwrapImpl() {
|
||||
// Check that we're not falling out of scope after the current context changed.
|
||||
MOZ_ASSERT(mGL->IsCurrent());
|
||||
|
||||
ScopedBindRenderbuffer::UnwrapImpl()
|
||||
{
|
||||
mGL->fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, mOldRB);
|
||||
}
|
||||
|
||||
|
@ -455,15 +434,13 @@ ScopedGLDrawState::ScopedGLDrawState(GLContext* aGL)
|
|||
, scissor (aGL, LOCAL_GL_SCISSOR_TEST, false)
|
||||
, stencil (aGL, LOCAL_GL_STENCIL_TEST, false)
|
||||
, mGL(aGL)
|
||||
, packAlign(4)
|
||||
{
|
||||
mGL->GetUIntegerv(LOCAL_GL_UNPACK_ALIGNMENT, &packAlign);
|
||||
mGL->GetUIntegerv(LOCAL_GL_CURRENT_PROGRAM, &boundProgram);
|
||||
mGL->GetUIntegerv(LOCAL_GL_ARRAY_BUFFER_BINDING, &boundBuffer);
|
||||
mGL->GetUIntegerv(LOCAL_GL_MAX_VERTEX_ATTRIBS, &maxAttrib);
|
||||
attrib_enabled = MakeUnique<GLint[]>(maxAttrib);
|
||||
|
||||
for (unsigned int i = 0; i < maxAttrib; i++) {
|
||||
for (GLuint i = 0; i < maxAttrib; i++) {
|
||||
mGL->fGetVertexAttribiv(i, LOCAL_GL_VERTEX_ATTRIB_ARRAY_ENABLED, &attrib_enabled[i]);
|
||||
mGL->fDisableVertexAttribArray(i);
|
||||
}
|
||||
|
@ -494,8 +471,6 @@ ScopedGLDrawState::~ScopedGLDrawState()
|
|||
colorMask[2],
|
||||
colorMask[3]);
|
||||
|
||||
mGL->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, packAlign);
|
||||
|
||||
for (unsigned int i = 0; i < maxAttrib; i++) {
|
||||
if (attrib_enabled[i])
|
||||
mGL->fEnableVertexAttribArray(i);
|
||||
|
@ -518,60 +493,47 @@ ScopedGLDrawState::~ScopedGLDrawState()
|
|||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// ScopedPackAlignment
|
||||
// ScopedPackState
|
||||
|
||||
ScopedPackAlignment::ScopedPackAlignment(GLContext* gl, GLint scopedVal)
|
||||
: ScopedGLWrapper<ScopedPackAlignment>(gl)
|
||||
static bool
|
||||
HasPBOState(const GLContext* gl)
|
||||
{
|
||||
MOZ_ASSERT(scopedVal == 1 ||
|
||||
scopedVal == 2 ||
|
||||
scopedVal == 4 ||
|
||||
scopedVal == 8);
|
||||
return (!gl->IsGLES() || gl->Version() >= 300);
|
||||
}
|
||||
|
||||
gl->fGetIntegerv(LOCAL_GL_PACK_ALIGNMENT, &mOldVal);
|
||||
ScopedPackState::ScopedPackState(GLContext* gl)
|
||||
: ScopedGLWrapper<ScopedPackState>(gl)
|
||||
{
|
||||
mGL->fGetIntegerv(LOCAL_GL_PACK_ALIGNMENT, &mAlignment);
|
||||
|
||||
if (scopedVal != mOldVal) {
|
||||
gl->fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, scopedVal);
|
||||
} else {
|
||||
// Don't try to re-set it during unwrap.
|
||||
mOldVal = 0;
|
||||
}
|
||||
if (mAlignment != 4) mGL->fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, 4);
|
||||
|
||||
if (!HasPBOState(mGL))
|
||||
return;
|
||||
|
||||
mGL->fGetIntegerv(LOCAL_GL_PIXEL_PACK_BUFFER_BINDING, (GLint*)&mPixelBuffer);
|
||||
mGL->fGetIntegerv(LOCAL_GL_PACK_ROW_LENGTH, &mRowLength);
|
||||
mGL->fGetIntegerv(LOCAL_GL_PACK_SKIP_PIXELS, &mSkipPixels);
|
||||
mGL->fGetIntegerv(LOCAL_GL_PACK_SKIP_ROWS, &mSkipRows);
|
||||
|
||||
if (mPixelBuffer != 0) mGL->fBindBuffer(LOCAL_GL_PIXEL_PACK_BUFFER, 0);
|
||||
if (mRowLength != 0) mGL->fPixelStorei(LOCAL_GL_PACK_ROW_LENGTH, 0);
|
||||
if (mSkipPixels != 0) mGL->fPixelStorei(LOCAL_GL_PACK_SKIP_PIXELS, 0);
|
||||
if (mSkipRows != 0) mGL->fPixelStorei(LOCAL_GL_PACK_SKIP_ROWS, 0);
|
||||
}
|
||||
|
||||
void
|
||||
ScopedPackAlignment::UnwrapImpl() {
|
||||
// Check that we're not falling out of scope after the current context changed.
|
||||
MOZ_ASSERT(mGL->IsCurrent());
|
||||
|
||||
if (mOldVal) {
|
||||
mGL->fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, mOldVal);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// ScopedUnpackAlignment
|
||||
|
||||
ScopedUnpackAlignment::ScopedUnpackAlignment(GLContext* gl, GLint scopedVal)
|
||||
: ScopedGLWrapper<ScopedUnpackAlignment>(gl)
|
||||
ScopedPackState::UnwrapImpl()
|
||||
{
|
||||
MOZ_ASSERT(scopedVal == 1 ||
|
||||
scopedVal == 2 ||
|
||||
scopedVal == 4 ||
|
||||
scopedVal == 8);
|
||||
mGL->fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, mAlignment);
|
||||
|
||||
gl->fGetIntegerv(LOCAL_GL_UNPACK_ALIGNMENT, &mOldVal);
|
||||
if (!HasPBOState(mGL))
|
||||
return;
|
||||
|
||||
if (scopedVal != mOldVal) {
|
||||
gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, scopedVal);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ScopedUnpackAlignment::UnwrapImpl() {
|
||||
// Check that we're not falling out of scope after the current context changed.
|
||||
MOZ_ASSERT(mGL->IsCurrent());
|
||||
|
||||
mGL->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, mOldVal);
|
||||
mGL->fBindBuffer(LOCAL_GL_PIXEL_PACK_BUFFER, mPixelBuffer);
|
||||
mGL->fPixelStorei(LOCAL_GL_PACK_ROW_LENGTH, mRowLength);
|
||||
mGL->fPixelStorei(LOCAL_GL_PACK_SKIP_PIXELS, mSkipPixels);
|
||||
mGL->fPixelStorei(LOCAL_GL_PACK_SKIP_ROWS, mSkipRows);
|
||||
}
|
||||
|
||||
} /* namespace gl */
|
||||
|
|
|
@ -309,7 +309,8 @@ protected:
|
|||
void UnwrapImpl();
|
||||
};
|
||||
|
||||
struct ScopedGLDrawState {
|
||||
struct ScopedGLDrawState
|
||||
{
|
||||
explicit ScopedGLDrawState(GLContext* gl);
|
||||
~ScopedGLDrawState();
|
||||
|
||||
|
@ -339,35 +340,23 @@ struct ScopedGLDrawState {
|
|||
GLint viewport[4];
|
||||
GLint scissorBox[4];
|
||||
GLContext* const mGL;
|
||||
GLuint packAlign;
|
||||
};
|
||||
|
||||
struct ScopedPackAlignment
|
||||
: public ScopedGLWrapper<ScopedPackAlignment>
|
||||
struct ScopedPackState
|
||||
: public ScopedGLWrapper<ScopedPackState>
|
||||
{
|
||||
friend struct ScopedGLWrapper<ScopedPackAlignment>;
|
||||
friend struct ScopedGLWrapper<ScopedPackState>;
|
||||
|
||||
protected:
|
||||
GLint mOldVal;
|
||||
GLint mAlignment;
|
||||
|
||||
GLuint mPixelBuffer;
|
||||
GLint mRowLength;
|
||||
GLint mSkipPixels;
|
||||
GLint mSkipRows;
|
||||
|
||||
public:
|
||||
ScopedPackAlignment(GLContext* aGL, GLint scopedVal);
|
||||
|
||||
protected:
|
||||
void UnwrapImpl();
|
||||
};
|
||||
|
||||
|
||||
struct ScopedUnpackAlignment
|
||||
: public ScopedGLWrapper<ScopedUnpackAlignment>
|
||||
{
|
||||
friend struct ScopedGLWrapper<ScopedUnpackAlignment>;
|
||||
|
||||
protected:
|
||||
GLint mOldVal;
|
||||
|
||||
public:
|
||||
ScopedUnpackAlignment(GLContext* gl, GLint scopedVal);
|
||||
explicit ScopedPackState(GLContext* gl);
|
||||
|
||||
protected:
|
||||
void UnwrapImpl();
|
||||
|
|
|
@ -569,7 +569,11 @@ ReadbackSharedSurface(SharedSurface* src, gfx::DrawTarget* dst)
|
|||
size_t alignment = 8;
|
||||
if (dstStride % 4 == 0)
|
||||
alignment = 4;
|
||||
ScopedPackAlignment autoAlign(gl, alignment);
|
||||
|
||||
ScopedPackState scopedPackState(gl);
|
||||
if (alignment != 4) {
|
||||
gl->fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, alignment);
|
||||
}
|
||||
|
||||
gl->raw_fReadPixels(0, 0, width, height, readGLFormat, readType,
|
||||
dstBytes);
|
||||
|
@ -601,7 +605,7 @@ ReadPixel(SharedSurface* src)
|
|||
|
||||
ScopedReadbackFB a(src);
|
||||
{
|
||||
ScopedPackAlignment autoAlign(gl, 4);
|
||||
ScopedPackState scopedPackState(gl);
|
||||
|
||||
UniquePtr<uint8_t[]> bytes(new uint8_t[4]);
|
||||
gl->raw_fReadPixels(0, 0, 1, 1, LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE,
|
||||
|
|
|
@ -4,58 +4,26 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#include "CompositorSession.h"
|
||||
#include "base/process_util.h"
|
||||
#include "GPUChild.h"
|
||||
#include "mozilla/gfx/Logging.h"
|
||||
#include "mozilla/gfx/GPUProcessHost.h"
|
||||
#include "mozilla/layers/CompositorBridgeChild.h"
|
||||
#include "mozilla/layers/CompositorBridgeParent.h"
|
||||
#include "mozilla/widget/PlatformWidgetTypes.h"
|
||||
#include "base/process_util.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
using namespace gfx;
|
||||
using namespace widget;
|
||||
|
||||
class InProcessCompositorSession final : public CompositorSession
|
||||
{
|
||||
public:
|
||||
InProcessCompositorSession(
|
||||
nsIWidget* aWidget,
|
||||
ClientLayerManager* aLayerManager,
|
||||
CSSToLayoutDeviceScale aScale,
|
||||
bool aUseAPZ,
|
||||
bool aUseExternalSurfaceSize,
|
||||
const gfx::IntSize& aSurfaceSize);
|
||||
|
||||
CompositorBridgeParent* GetInProcessBridge() const override;
|
||||
void SetContentController(GeckoContentController* aController) override;
|
||||
uint64_t RootLayerTreeId() const override;
|
||||
already_AddRefed<APZCTreeManager> GetAPZCTreeManager() const override;
|
||||
void Shutdown() override;
|
||||
|
||||
private:
|
||||
RefPtr<CompositorBridgeParent> mCompositorBridgeParent;
|
||||
RefPtr<CompositorWidget> mCompositorWidget;
|
||||
};
|
||||
|
||||
already_AddRefed<CompositorSession>
|
||||
CompositorSession::CreateInProcess(nsIWidget* aWidget,
|
||||
ClientLayerManager* aLayerManager,
|
||||
CSSToLayoutDeviceScale aScale,
|
||||
bool aUseAPZ,
|
||||
bool aUseExternalSurfaceSize,
|
||||
const gfx::IntSize& aSurfaceSize)
|
||||
{
|
||||
RefPtr<InProcessCompositorSession> session = new InProcessCompositorSession(
|
||||
aWidget,
|
||||
aLayerManager,
|
||||
aScale,
|
||||
aUseAPZ,
|
||||
aUseExternalSurfaceSize,
|
||||
aSurfaceSize);
|
||||
return session.forget();
|
||||
}
|
||||
|
||||
CompositorSession::CompositorSession()
|
||||
: mCompositorWidgetDelegate(nullptr)
|
||||
CompositorSession::CompositorSession(CompositorWidgetDelegate* aDelegate,
|
||||
CompositorBridgeChild* aChild,
|
||||
const uint64_t& aRootLayerTreeId)
|
||||
: mCompositorWidgetDelegate(aDelegate),
|
||||
mCompositorBridgeChild(aChild),
|
||||
mRootLayerTreeId(aRootLayerTreeId)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -69,65 +37,5 @@ CompositorSession::GetCompositorBridgeChild()
|
|||
return mCompositorBridgeChild;
|
||||
}
|
||||
|
||||
InProcessCompositorSession::InProcessCompositorSession(nsIWidget* aWidget,
|
||||
ClientLayerManager* aLayerManager,
|
||||
CSSToLayoutDeviceScale aScale,
|
||||
bool aUseAPZ,
|
||||
bool aUseExternalSurfaceSize,
|
||||
const gfx::IntSize& aSurfaceSize)
|
||||
{
|
||||
CompositorWidgetInitData initData;
|
||||
aWidget->GetCompositorWidgetInitData(&initData);
|
||||
mCompositorWidget = CompositorWidget::CreateLocal(initData, aWidget);
|
||||
mCompositorWidgetDelegate = mCompositorWidget->AsDelegate();
|
||||
|
||||
mCompositorBridgeParent = new CompositorBridgeParent(
|
||||
mCompositorWidget,
|
||||
aScale,
|
||||
aUseAPZ,
|
||||
aUseExternalSurfaceSize,
|
||||
aSurfaceSize);
|
||||
mCompositorBridgeChild = new CompositorBridgeChild(aLayerManager);
|
||||
mCompositorBridgeChild->OpenSameProcess(mCompositorBridgeParent);
|
||||
mCompositorBridgeParent->SetOtherProcessId(base::GetCurrentProcId());
|
||||
}
|
||||
|
||||
CompositorBridgeParent*
|
||||
InProcessCompositorSession::GetInProcessBridge() const
|
||||
{
|
||||
return mCompositorBridgeParent;
|
||||
}
|
||||
|
||||
void
|
||||
InProcessCompositorSession::SetContentController(GeckoContentController* aController)
|
||||
{
|
||||
mCompositorBridgeParent->SetControllerForLayerTree(RootLayerTreeId(), aController);
|
||||
}
|
||||
|
||||
uint64_t
|
||||
InProcessCompositorSession::RootLayerTreeId() const
|
||||
{
|
||||
return mCompositorBridgeParent->RootLayerTreeId();
|
||||
}
|
||||
|
||||
already_AddRefed<APZCTreeManager>
|
||||
InProcessCompositorSession::GetAPZCTreeManager() const
|
||||
{
|
||||
return mCompositorBridgeParent->GetAPZCTreeManager(RootLayerTreeId());
|
||||
}
|
||||
|
||||
void
|
||||
InProcessCompositorSession::Shutdown()
|
||||
{
|
||||
// Destroy will synchronously wait for the parent to acknowledge shutdown,
|
||||
// at which point CBP will defer a Release on the compositor thread. We
|
||||
// can safely release our reference now, and let the destructor run on either
|
||||
// thread.
|
||||
mCompositorBridgeChild->Destroy();
|
||||
mCompositorBridgeChild = nullptr;
|
||||
mCompositorBridgeParent = nullptr;
|
||||
mCompositorWidget = nullptr;
|
||||
}
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -7,9 +7,7 @@
|
|||
#define _include_mozilla_gfx_ipc_CompositorSession_h_
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "Units.h"
|
||||
#include "nsISupportsImpl.h"
|
||||
#include "mozilla/gfx/Point.h"
|
||||
|
||||
class nsIWidget;
|
||||
|
||||
|
@ -19,6 +17,7 @@ class CompositorWidget;
|
|||
class CompositorWidgetDelegate;
|
||||
} // namespace widget
|
||||
namespace gfx {
|
||||
class GPUProcessHost;
|
||||
class GPUProcessManager;
|
||||
} // namespace gfx
|
||||
namespace layers {
|
||||
|
@ -36,6 +35,7 @@ class CompositorSession
|
|||
friend class gfx::GPUProcessManager;
|
||||
|
||||
protected:
|
||||
typedef gfx::GPUProcessHost GPUProcessHost;
|
||||
typedef widget::CompositorWidget CompositorWidget;
|
||||
typedef widget::CompositorWidgetDelegate CompositorWidgetDelegate;
|
||||
|
||||
|
@ -50,9 +50,6 @@ public:
|
|||
// Set the GeckoContentController for the root of the layer tree.
|
||||
virtual void SetContentController(GeckoContentController* aController) = 0;
|
||||
|
||||
// Return the id of the root layer tree.
|
||||
virtual uint64_t RootLayerTreeId() const = 0;
|
||||
|
||||
// Return the Async Pan/Zoom Tree Manager for this compositor.
|
||||
virtual already_AddRefed<APZCTreeManager> GetAPZCTreeManager() const = 0;
|
||||
|
||||
|
@ -64,21 +61,21 @@ public:
|
|||
return mCompositorWidgetDelegate;
|
||||
}
|
||||
|
||||
// Return the id of the root layer tree.
|
||||
uint64_t RootLayerTreeId() const {
|
||||
return mRootLayerTreeId;
|
||||
}
|
||||
|
||||
protected:
|
||||
CompositorSession();
|
||||
CompositorSession(CompositorWidgetDelegate* aDelegate,
|
||||
CompositorBridgeChild* aChild,
|
||||
const uint64_t& aRootLayerTreeId);
|
||||
virtual ~CompositorSession();
|
||||
|
||||
static already_AddRefed<CompositorSession> CreateInProcess(
|
||||
nsIWidget* aWidget,
|
||||
ClientLayerManager* aLayerManager,
|
||||
CSSToLayoutDeviceScale aScale,
|
||||
bool aUseAPZ,
|
||||
bool aUseExternalSurfaceSize,
|
||||
const gfx::IntSize& aSurfaceSize);
|
||||
|
||||
protected:
|
||||
RefPtr<CompositorBridgeChild> mCompositorBridgeChild;
|
||||
CompositorWidgetDelegate* mCompositorWidgetDelegate;
|
||||
RefPtr<CompositorBridgeChild> mCompositorBridgeChild;
|
||||
uint64_t mRootLayerTreeId;
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(CompositorSession);
|
||||
|
|
|
@ -9,11 +9,14 @@
|
|||
#include "GPUProcessHost.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/ipc/ProcessChild.h"
|
||||
#include "mozilla/layers/CompositorBridgeParent.h"
|
||||
#include "mozilla/layers/CompositorThread.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace gfx {
|
||||
|
||||
using namespace ipc;
|
||||
using namespace layers;
|
||||
|
||||
GPUParent::GPUParent()
|
||||
{
|
||||
|
@ -34,7 +37,7 @@ GPUParent::Init(base::ProcessId aParentPid,
|
|||
|
||||
// Ensure gfxPrefs are initialized.
|
||||
gfxPrefs::GetSingleton();
|
||||
|
||||
CompositorThreadHolder::Start();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -57,6 +60,35 @@ GPUParent::RecvUpdatePref(const GfxPrefSetting& setting)
|
|||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
OpenParent(RefPtr<CompositorBridgeParent> aParent,
|
||||
Endpoint<PCompositorBridgeParent>&& aEndpoint)
|
||||
{
|
||||
if (!aParent->Bind(Move(aEndpoint))) {
|
||||
MOZ_CRASH("Failed to bind compositor");
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
GPUParent::RecvNewWidgetCompositor(Endpoint<layers::PCompositorBridgeParent>&& aEndpoint,
|
||||
const CSSToLayoutDeviceScale& aScale,
|
||||
const bool& aUseExternalSurfaceSize,
|
||||
const IntSize& aSurfaceSize)
|
||||
{
|
||||
RefPtr<CompositorBridgeParent> cbp =
|
||||
new CompositorBridgeParent(aScale, aUseExternalSurfaceSize, aSurfaceSize);
|
||||
|
||||
MessageLoop* loop = CompositorThreadHolder::Loop();
|
||||
loop->PostTask(NewRunnableFunction(OpenParent, cbp, Move(aEndpoint)));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
GPUParent::RecvNewContentCompositorBridge(Endpoint<PCompositorBridgeParent>&& aEndpoint)
|
||||
{
|
||||
return CompositorBridgeParent::CreateForContent(Move(aEndpoint));
|
||||
}
|
||||
|
||||
void
|
||||
GPUParent::ActorDestroy(ActorDestroyReason aWhy)
|
||||
{
|
||||
|
@ -70,9 +102,10 @@ GPUParent::ActorDestroy(ActorDestroyReason aWhy)
|
|||
// state. Currently we quick-exit in RecvBeginShutdown so this should be
|
||||
// unreachable.
|
||||
ProcessChild::QuickExit();
|
||||
#else
|
||||
XRE_ShutdownChildProcess();
|
||||
#endif
|
||||
|
||||
CompositorThreadHolder::Shutdown();
|
||||
XRE_ShutdownChildProcess();
|
||||
}
|
||||
|
||||
} // namespace gfx
|
||||
|
|
|
@ -23,6 +23,12 @@ public:
|
|||
|
||||
bool RecvInit(nsTArray<GfxPrefSetting>&& prefs) override;
|
||||
bool RecvUpdatePref(const GfxPrefSetting& pref) override;
|
||||
bool RecvNewWidgetCompositor(
|
||||
Endpoint<PCompositorBridgeParent>&& aEndpoint,
|
||||
const CSSToLayoutDeviceScale& aScale,
|
||||
const bool& aUseExternalSurface,
|
||||
const IntSize& aSurfaceSize) override;
|
||||
bool RecvNewContentCompositorBridge(Endpoint<PCompositorBridgeParent>&& aEndpoint) override;
|
||||
|
||||
void ActorDestroy(ActorDestroyReason aWhy) override;
|
||||
};
|
||||
|
|
|
@ -18,7 +18,9 @@ GPUProcessHost::GPUProcessHost(Listener* aListener)
|
|||
mListener(aListener),
|
||||
mTaskFactory(this),
|
||||
mLaunchPhase(LaunchPhase::Unlaunched),
|
||||
mShutdownRequested(false)
|
||||
mProcessToken(0),
|
||||
mShutdownRequested(false),
|
||||
mChannelClosed(false)
|
||||
{
|
||||
MOZ_COUNT_CTOR(GPUProcessHost);
|
||||
}
|
||||
|
@ -109,6 +111,8 @@ GPUProcessHost::OnChannelErrorTask()
|
|||
}
|
||||
}
|
||||
|
||||
static uint64_t sProcessTokenCounter = 0;
|
||||
|
||||
void
|
||||
GPUProcessHost::InitAfterConnect(bool aSucceeded)
|
||||
{
|
||||
|
@ -118,6 +122,7 @@ GPUProcessHost::InitAfterConnect(bool aSucceeded)
|
|||
mLaunchPhase = LaunchPhase::Complete;
|
||||
|
||||
if (aSucceeded) {
|
||||
mProcessToken = ++sProcessTokenCounter;
|
||||
mGPUChild = MakeUnique<GPUChild>(this);
|
||||
DebugOnly<bool> rv =
|
||||
mGPUChild->Open(GetChannel(), base::GetProcId(GetChildProcessHandle()));
|
||||
|
@ -144,14 +149,22 @@ GPUProcessHost::Shutdown()
|
|||
mShutdownRequested = true;
|
||||
|
||||
#ifdef NS_FREE_PERMANENT_DATA
|
||||
mGPUChild->Close();
|
||||
// The channel might already be closed if we got here unexpectedly.
|
||||
if (!mChannelClosed) {
|
||||
mGPUChild->Close();
|
||||
}
|
||||
#else
|
||||
// No need to communicate shutdown, the GPU process doesn't need to
|
||||
// communicate anything back.
|
||||
KillHard("NormalShutdown");
|
||||
#endif
|
||||
|
||||
// Wait for ActorDestroy.
|
||||
// If we're shutting down unexpectedly, we're in the middle of handling an
|
||||
// ActorDestroy for PGPUChild, which is still on the stack. We'll return
|
||||
// back to OnChannelClosed.
|
||||
//
|
||||
// Otherwise, we'll wait for OnChannelClose to be called whenever PGPUChild
|
||||
// acknowledges shutdown.
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -163,6 +176,7 @@ GPUProcessHost::OnChannelClosed()
|
|||
{
|
||||
if (!mShutdownRequested) {
|
||||
// This is an unclean shutdown. Notify our listener that we're going away.
|
||||
mChannelClosed = true;
|
||||
if (mListener) {
|
||||
mListener->OnProcessUnexpectedShutdown(this);
|
||||
}
|
||||
|
@ -194,6 +208,12 @@ GPUProcessHost::KillHard(const char* aReason)
|
|||
NewRunnableFunction(&ProcessWatcher::EnsureProcessTerminated, handle, /*force=*/true));
|
||||
}
|
||||
|
||||
uint64_t
|
||||
GPUProcessHost::GetProcessToken() const
|
||||
{
|
||||
return mProcessToken;
|
||||
}
|
||||
|
||||
static void
|
||||
DelayedDeleteSubprocess(GeckoChildProcessHost* aSubprocess)
|
||||
{
|
||||
|
|
|
@ -74,6 +74,10 @@ public:
|
|||
return mGPUChild.get();
|
||||
}
|
||||
|
||||
// Return a unique id for this process, guaranteed not to be shared with any
|
||||
// past or future instance of GPUProcessHost.
|
||||
uint64_t GetProcessToken() const;
|
||||
|
||||
bool IsConnected() const {
|
||||
return !!mGPUChild;
|
||||
}
|
||||
|
@ -114,9 +118,10 @@ private:
|
|||
LaunchPhase mLaunchPhase;
|
||||
|
||||
UniquePtr<GPUChild> mGPUChild;
|
||||
Listener* listener_;
|
||||
uint64_t mProcessToken;
|
||||
|
||||
bool mShutdownRequested;
|
||||
bool mChannelClosed;
|
||||
};
|
||||
|
||||
} // namespace gfx
|
||||
|
|
|
@ -1,12 +1,18 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=99: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#include "GPUProcessManager.h"
|
||||
#include "GPUProcessHost.h"
|
||||
#include "mozilla/layers/CompositorSession.h"
|
||||
#include "mozilla/StaticPtr.h"
|
||||
#include "mozilla/layers/CompositorBridgeParent.h"
|
||||
#include "mozilla/layers/InProcessCompositorSession.h"
|
||||
#include "mozilla/layers/RemoteCompositorSession.h"
|
||||
#include "mozilla/widget/PlatformWidgetTypes.h"
|
||||
#ifdef MOZ_WIDGET_SUPPORTS_OOP_COMPOSITING
|
||||
# include "mozilla/widget/CompositorWidgetChild.h"
|
||||
#endif
|
||||
#include "nsContentUtils.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
@ -36,7 +42,9 @@ GPUProcessManager::Shutdown()
|
|||
}
|
||||
|
||||
GPUProcessManager::GPUProcessManager()
|
||||
: mProcess(nullptr),
|
||||
: mTaskFactory(this),
|
||||
mNextLayerTreeId(0),
|
||||
mProcess(nullptr),
|
||||
mGPUChild(nullptr)
|
||||
{
|
||||
mObserver = new Observer(this);
|
||||
|
@ -127,6 +135,7 @@ GPUProcessManager::OnProcessLaunchComplete(GPUProcessHost* aHost)
|
|||
}
|
||||
|
||||
mGPUChild = mProcess->GetActor();
|
||||
mProcessToken = mProcess->GetProcessToken();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -137,6 +146,28 @@ GPUProcessManager::OnProcessUnexpectedShutdown(GPUProcessHost* aHost)
|
|||
DestroyProcess();
|
||||
}
|
||||
|
||||
void
|
||||
GPUProcessManager::NotifyRemoteActorDestroyed(const uint64_t& aProcessToken)
|
||||
{
|
||||
if (!NS_IsMainThread()) {
|
||||
RefPtr<Runnable> task = mTaskFactory.NewRunnableMethod(
|
||||
&GPUProcessManager::NotifyRemoteActorDestroyed, aProcessToken);
|
||||
NS_DispatchToMainThread(task.forget());
|
||||
return;
|
||||
}
|
||||
|
||||
if (mProcessToken != aProcessToken) {
|
||||
// This token is for an older process; we can safely ignore it.
|
||||
return;
|
||||
}
|
||||
|
||||
// One of the bridged top-level actors for the GPU process has been
|
||||
// prematurely terminated, and we're receiving a notification. This
|
||||
// can happen if the ActorDestroy for a bridged protocol fires
|
||||
// before the ActorDestroy for PGPUChild.
|
||||
DestroyProcess();
|
||||
}
|
||||
|
||||
void
|
||||
GPUProcessManager::DestroyProcess()
|
||||
{
|
||||
|
@ -145,11 +176,12 @@ GPUProcessManager::DestroyProcess()
|
|||
}
|
||||
|
||||
mProcess->Shutdown();
|
||||
mProcessToken = 0;
|
||||
mProcess = nullptr;
|
||||
mGPUChild = nullptr;
|
||||
}
|
||||
|
||||
already_AddRefed<CompositorSession>
|
||||
RefPtr<CompositorSession>
|
||||
GPUProcessManager::CreateTopLevelCompositor(nsIWidget* aWidget,
|
||||
ClientLayerManager* aLayerManager,
|
||||
CSSToLayoutDeviceScale aScale,
|
||||
|
@ -157,20 +189,123 @@ GPUProcessManager::CreateTopLevelCompositor(nsIWidget* aWidget,
|
|||
bool aUseExternalSurfaceSize,
|
||||
const gfx::IntSize& aSurfaceSize)
|
||||
{
|
||||
return CompositorSession::CreateInProcess(
|
||||
uint64_t layerTreeId = AllocateLayerTreeId();
|
||||
|
||||
if (mGPUChild) {
|
||||
RefPtr<CompositorSession> session = CreateRemoteSession(
|
||||
aWidget,
|
||||
aLayerManager,
|
||||
layerTreeId,
|
||||
aScale,
|
||||
aUseAPZ,
|
||||
aUseExternalSurfaceSize,
|
||||
aSurfaceSize);
|
||||
if (session) {
|
||||
return session;
|
||||
}
|
||||
|
||||
// We couldn't create a remote compositor, so abort the process.
|
||||
DisableGPUProcess("Failed to create remote compositor");
|
||||
}
|
||||
|
||||
return InProcessCompositorSession::Create(
|
||||
aWidget,
|
||||
aLayerManager,
|
||||
layerTreeId,
|
||||
aScale,
|
||||
aUseAPZ,
|
||||
aUseExternalSurfaceSize,
|
||||
aSurfaceSize);
|
||||
}
|
||||
|
||||
PCompositorBridgeParent*
|
||||
GPUProcessManager::CreateTabCompositorBridge(ipc::Transport* aTransport,
|
||||
base::ProcessId aOtherProcess)
|
||||
RefPtr<CompositorSession>
|
||||
GPUProcessManager::CreateRemoteSession(nsIWidget* aWidget,
|
||||
ClientLayerManager* aLayerManager,
|
||||
const uint64_t& aRootLayerTreeId,
|
||||
CSSToLayoutDeviceScale aScale,
|
||||
bool aUseAPZ,
|
||||
bool aUseExternalSurfaceSize,
|
||||
const gfx::IntSize& aSurfaceSize)
|
||||
{
|
||||
return CompositorBridgeParent::Create(aTransport, aOtherProcess);
|
||||
#ifdef MOZ_WIDGET_SUPPORTS_OOP_COMPOSITING
|
||||
ipc::Endpoint<PCompositorBridgeParent> parentPipe;
|
||||
ipc::Endpoint<PCompositorBridgeChild> childPipe;
|
||||
|
||||
nsresult rv = PCompositorBridge::CreateEndpoints(
|
||||
mGPUChild->OtherPid(),
|
||||
base::GetCurrentProcId(),
|
||||
&parentPipe,
|
||||
&childPipe);
|
||||
if (NS_FAILED(rv)) {
|
||||
gfxCriticalNote << "Failed to create PCompositorBridge endpoints: " << hexa(int(rv));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<CompositorBridgeChild> child = CompositorBridgeChild::CreateRemote(
|
||||
mProcessToken,
|
||||
aLayerManager,
|
||||
Move(childPipe));
|
||||
if (!child) {
|
||||
gfxCriticalNote << "Failed to create CompositorBridgeChild";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CompositorWidgetInitData initData;
|
||||
aWidget->GetCompositorWidgetInitData(&initData);
|
||||
|
||||
bool ok = mGPUChild->SendNewWidgetCompositor(
|
||||
Move(parentPipe),
|
||||
aScale,
|
||||
aUseExternalSurfaceSize,
|
||||
aSurfaceSize);
|
||||
if (!ok)
|
||||
return nullptr;
|
||||
|
||||
CompositorWidgetChild* widget = new CompositorWidgetChild(aWidget);
|
||||
if (!child->SendPCompositorWidgetConstructor(widget, initData))
|
||||
return nullptr;
|
||||
if (!child->SendInitialize(aRootLayerTreeId))
|
||||
return nullptr;
|
||||
|
||||
RefPtr<RemoteCompositorSession> session =
|
||||
new RemoteCompositorSession(child, widget, aRootLayerTreeId);
|
||||
return session.forget();
|
||||
#else
|
||||
gfxCriticalNote << "Platform does not support out-of-process compositing";
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool
|
||||
GPUProcessManager::CreateContentCompositorBridge(base::ProcessId aOtherProcess,
|
||||
ipc::Endpoint<PCompositorBridgeChild>* aOutEndpoint)
|
||||
{
|
||||
ipc::Endpoint<PCompositorBridgeParent> parentPipe;
|
||||
ipc::Endpoint<PCompositorBridgeChild> childPipe;
|
||||
|
||||
base::ProcessId gpuPid = mGPUChild
|
||||
? mGPUChild->OtherPid()
|
||||
: base::GetCurrentProcId();
|
||||
|
||||
nsresult rv = PCompositorBridge::CreateEndpoints(
|
||||
gpuPid,
|
||||
aOtherProcess,
|
||||
&parentPipe,
|
||||
&childPipe);
|
||||
if (NS_FAILED(rv)) {
|
||||
gfxCriticalNote << "Could not create content compositor bridge: " << hexa(int(rv));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mGPUChild) {
|
||||
mGPUChild->SendNewContentCompositorBridge(Move(parentPipe));
|
||||
} else {
|
||||
if (!CompositorBridgeParent::CreateForContent(Move(parentPipe)))
|
||||
return false;
|
||||
}
|
||||
|
||||
*aOutEndpoint = Move(childPipe);
|
||||
return true;
|
||||
}
|
||||
|
||||
already_AddRefed<APZCTreeManager>
|
||||
|
@ -182,7 +317,8 @@ GPUProcessManager::GetAPZCTreeManagerForLayers(uint64_t aLayersId)
|
|||
uint64_t
|
||||
GPUProcessManager::AllocateLayerTreeId()
|
||||
{
|
||||
return CompositorBridgeParent::AllocateLayerTreeId();
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
return ++mNextLayerTreeId;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -12,15 +12,19 @@
|
|||
#include "mozilla/dom/ipc/IdType.h"
|
||||
#include "mozilla/gfx/GPUProcessHost.h"
|
||||
#include "mozilla/gfx/Point.h"
|
||||
#include "mozilla/ipc/ProtocolUtils.h"
|
||||
#include "mozilla/ipc/TaskFactory.h"
|
||||
#include "mozilla/ipc/Transport.h"
|
||||
#include "nsIObserverService.h"
|
||||
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
class APZCTreeManager;
|
||||
class CompositorSession;
|
||||
class ClientLayerManager;
|
||||
class CompositorUpdateObserver;
|
||||
class PCompositorBridgeChild;
|
||||
class PCompositorBridgeParent;
|
||||
} // namespace layers
|
||||
namespace widget {
|
||||
|
@ -43,7 +47,10 @@ class GPUChild;
|
|||
class GPUProcessManager final : public GPUProcessHost::Listener
|
||||
{
|
||||
typedef layers::APZCTreeManager APZCTreeManager;
|
||||
typedef layers::ClientLayerManager ClientLayerManager;
|
||||
typedef layers::CompositorSession CompositorSession;
|
||||
typedef layers::CompositorUpdateObserver CompositorUpdateObserver;
|
||||
typedef layers::PCompositorBridgeChild PCompositorBridgeChild;
|
||||
|
||||
public:
|
||||
static void Initialize();
|
||||
|
@ -60,17 +67,16 @@ public:
|
|||
// Otherwise it blocks until the GPU process has finished launching.
|
||||
void EnsureGPUReady();
|
||||
|
||||
already_AddRefed<layers::CompositorSession> CreateTopLevelCompositor(
|
||||
RefPtr<CompositorSession> CreateTopLevelCompositor(
|
||||
nsIWidget* aWidget,
|
||||
layers::ClientLayerManager* aLayerManager,
|
||||
ClientLayerManager* aLayerManager,
|
||||
CSSToLayoutDeviceScale aScale,
|
||||
bool aUseAPZ,
|
||||
bool aUseExternalSurfaceSize,
|
||||
const gfx::IntSize& aSurfaceSize);
|
||||
|
||||
layers::PCompositorBridgeParent* CreateTabCompositorBridge(
|
||||
ipc::Transport* aTransport,
|
||||
base::ProcessId aOtherProcess);
|
||||
bool CreateContentCompositorBridge(base::ProcessId aOtherProcess,
|
||||
ipc::Endpoint<PCompositorBridgeChild>* aOutEndpoint);
|
||||
|
||||
// This returns a reference to the APZCTreeManager to which
|
||||
// pan/zoom-related events can be sent.
|
||||
|
@ -106,6 +112,10 @@ public:
|
|||
void OnProcessLaunchComplete(GPUProcessHost* aHost) override;
|
||||
void OnProcessUnexpectedShutdown(GPUProcessHost* aHost) override;
|
||||
|
||||
// Notify the GPUProcessManager that a top-level PGPU protocol has been
|
||||
// terminated. This may be called from any thread.
|
||||
void NotifyRemoteActorDestroyed(const uint64_t& aProcessToken);
|
||||
|
||||
// Returns access to the PGPU protocol if a GPU process is present.
|
||||
GPUChild* GetGPUChild() {
|
||||
return mGPUChild;
|
||||
|
@ -124,6 +134,15 @@ private:
|
|||
// Shutdown the GPU process.
|
||||
void DestroyProcess();
|
||||
|
||||
RefPtr<CompositorSession> CreateRemoteSession(
|
||||
nsIWidget* aWidget,
|
||||
ClientLayerManager* aLayerManager,
|
||||
const uint64_t& aRootLayerTreeId,
|
||||
CSSToLayoutDeviceScale aScale,
|
||||
bool aUseAPZ,
|
||||
bool aUseExternalSurfaceSize,
|
||||
const gfx::IntSize& aSurfaceSize);
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(GPUProcessManager);
|
||||
|
||||
class Observer final : public nsIObserver {
|
||||
|
@ -141,7 +160,11 @@ private:
|
|||
|
||||
private:
|
||||
RefPtr<Observer> mObserver;
|
||||
ipc::TaskFactory<GPUProcessManager> mTaskFactory;
|
||||
uint64_t mNextLayerTreeId;
|
||||
|
||||
GPUProcessHost* mProcess;
|
||||
uint64_t mProcessToken;
|
||||
GPUChild* mGPUChild;
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=99: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "InProcessCompositorSession.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
InProcessCompositorSession::InProcessCompositorSession(widget::CompositorWidget* aWidget,
|
||||
CompositorBridgeChild* aChild,
|
||||
CompositorBridgeParent* aParent)
|
||||
: CompositorSession(aWidget->AsDelegate(), aChild, aParent->RootLayerTreeId()),
|
||||
mCompositorBridgeParent(aParent),
|
||||
mCompositorWidget(aWidget)
|
||||
{
|
||||
}
|
||||
|
||||
/* static */ RefPtr<InProcessCompositorSession>
|
||||
InProcessCompositorSession::Create(nsIWidget* aWidget,
|
||||
ClientLayerManager* aLayerManager,
|
||||
const uint64_t& aRootLayerTreeId,
|
||||
CSSToLayoutDeviceScale aScale,
|
||||
bool aUseAPZ,
|
||||
bool aUseExternalSurfaceSize,
|
||||
const gfx::IntSize& aSurfaceSize)
|
||||
{
|
||||
CompositorWidgetInitData initData;
|
||||
aWidget->GetCompositorWidgetInitData(&initData);
|
||||
|
||||
RefPtr<CompositorWidget> widget = CompositorWidget::CreateLocal(initData, aWidget);
|
||||
RefPtr<CompositorBridgeChild> child = new CompositorBridgeChild(aLayerManager);
|
||||
RefPtr<CompositorBridgeParent> parent =
|
||||
child->InitSameProcess(widget, aRootLayerTreeId, aScale, aUseAPZ, aUseExternalSurfaceSize, aSurfaceSize);
|
||||
|
||||
return new InProcessCompositorSession(widget, child, parent);
|
||||
}
|
||||
|
||||
CompositorBridgeParent*
|
||||
InProcessCompositorSession::GetInProcessBridge() const
|
||||
{
|
||||
return mCompositorBridgeParent;
|
||||
}
|
||||
|
||||
void
|
||||
InProcessCompositorSession::SetContentController(GeckoContentController* aController)
|
||||
{
|
||||
mCompositorBridgeParent->SetControllerForLayerTree(mRootLayerTreeId, aController);
|
||||
}
|
||||
|
||||
already_AddRefed<APZCTreeManager>
|
||||
InProcessCompositorSession::GetAPZCTreeManager() const
|
||||
{
|
||||
return mCompositorBridgeParent->GetAPZCTreeManager(mRootLayerTreeId);
|
||||
}
|
||||
|
||||
void
|
||||
InProcessCompositorSession::Shutdown()
|
||||
{
|
||||
// Destroy will synchronously wait for the parent to acknowledge shutdown,
|
||||
// at which point CBP will defer a Release on the compositor thread. We
|
||||
// can safely release our reference now, and let the destructor run on either
|
||||
// thread.
|
||||
mCompositorBridgeChild->Destroy();
|
||||
mCompositorBridgeChild = nullptr;
|
||||
mCompositorBridgeParent = nullptr;
|
||||
mCompositorWidget = nullptr;
|
||||
}
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
|
@ -0,0 +1,48 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=99: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#ifndef _include_mozilla_gfx_ipc_InProcessCompositorSession_h_
|
||||
#define _include_mozilla_gfx_ipc_InProcessCompositorSession_h_
|
||||
|
||||
#include "CompositorSession.h"
|
||||
#include "mozilla/gfx/Point.h"
|
||||
#include "Units.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
// A CompositorSession where both the child and parent CompositorBridge reside
|
||||
// in the same process.
|
||||
class InProcessCompositorSession final : public CompositorSession
|
||||
{
|
||||
public:
|
||||
static RefPtr<InProcessCompositorSession> Create(
|
||||
nsIWidget* aWidget,
|
||||
ClientLayerManager* aLayerManager,
|
||||
const uint64_t& aRootLayerTreeId,
|
||||
CSSToLayoutDeviceScale aScale,
|
||||
bool aUseAPZ,
|
||||
bool aUseExternalSurfaceSize,
|
||||
const gfx::IntSize& aSurfaceSize);
|
||||
|
||||
CompositorBridgeParent* GetInProcessBridge() const override;
|
||||
void SetContentController(GeckoContentController* aController) override;
|
||||
already_AddRefed<APZCTreeManager> GetAPZCTreeManager() const override;
|
||||
void Shutdown() override;
|
||||
|
||||
private:
|
||||
InProcessCompositorSession(widget::CompositorWidget* aWidget,
|
||||
CompositorBridgeChild* aChild,
|
||||
CompositorBridgeParent* aParent);
|
||||
|
||||
private:
|
||||
RefPtr<CompositorBridgeParent> mCompositorBridgeParent;
|
||||
RefPtr<CompositorWidget> mCompositorWidget;
|
||||
};
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // _include_mozilla_gfx_ipc_InProcessCompositorSession_h_
|
|
@ -3,7 +3,10 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
include protocol PContent;
|
||||
include protocol PCompositorBridge;
|
||||
|
||||
using mozilla::CSSToLayoutDeviceScale from "Units.h";
|
||||
using mozilla::gfx::IntSize from "mozilla/gfx/2D.h";
|
||||
|
||||
namespace mozilla {
|
||||
namespace gfx {
|
||||
|
@ -28,6 +31,15 @@ parent:
|
|||
|
||||
// Called to update a gfx preference.
|
||||
async UpdatePref(GfxPrefSetting pref);
|
||||
|
||||
// Create a new top-level compositor.
|
||||
async NewWidgetCompositor(Endpoint<PCompositorBridgeParent> endpoint,
|
||||
CSSToLayoutDeviceScale scale,
|
||||
bool useExternalSurface,
|
||||
IntSize surfaceSize);
|
||||
|
||||
// Create a new content-process compositor bridge.
|
||||
async NewContentCompositorBridge(Endpoint<PCompositorBridgeParent> endpoint);
|
||||
};
|
||||
|
||||
} // namespace gfx
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=99: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#include "RemoteCompositorSession.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
using namespace gfx;
|
||||
using namespace widget;
|
||||
|
||||
RemoteCompositorSession::RemoteCompositorSession(CompositorBridgeChild* aChild,
|
||||
CompositorWidgetDelegate* aWidgetDelegate,
|
||||
const uint64_t& aRootLayerTreeId)
|
||||
: CompositorSession(aWidgetDelegate, aChild, aRootLayerTreeId)
|
||||
{
|
||||
}
|
||||
|
||||
CompositorBridgeParent*
|
||||
RemoteCompositorSession::GetInProcessBridge() const
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
RemoteCompositorSession::SetContentController(GeckoContentController* aController)
|
||||
{
|
||||
MOZ_CRASH("NYI");
|
||||
}
|
||||
|
||||
already_AddRefed<APZCTreeManager>
|
||||
RemoteCompositorSession::GetAPZCTreeManager() const
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
RemoteCompositorSession::Shutdown()
|
||||
{
|
||||
mCompositorBridgeChild->Destroy();
|
||||
mCompositorBridgeChild = nullptr;
|
||||
mCompositorWidgetDelegate = nullptr;
|
||||
}
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
|
@ -0,0 +1,33 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=99: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#ifndef include_mozilla_gfx_ipc_RemoteCompositorSession_h
|
||||
#define include_mozilla_gfx_ipc_RemoteCompositorSession_h
|
||||
|
||||
#include "CompositorSession.h"
|
||||
#include "mozilla/gfx/Point.h"
|
||||
#include "Units.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
class RemoteCompositorSession final : public CompositorSession
|
||||
{
|
||||
public:
|
||||
RemoteCompositorSession(CompositorBridgeChild* aChild,
|
||||
CompositorWidgetDelegate* aWidgetDelegate,
|
||||
const uint64_t& aRootLayerTreeId);
|
||||
|
||||
CompositorBridgeParent* GetInProcessBridge() const override;
|
||||
void SetContentController(GeckoContentController* aController) override;
|
||||
already_AddRefed<APZCTreeManager> GetAPZCTreeManager() const override;
|
||||
void Shutdown() override;
|
||||
|
||||
};
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // include_mozilla_gfx_ipc_RemoteCompositorSession_h
|
|
@ -20,6 +20,8 @@ EXPORTS.mozilla.gfx += [
|
|||
|
||||
EXPORTS.mozilla.layers += [
|
||||
'CompositorSession.h',
|
||||
'InProcessCompositorSession.h',
|
||||
'RemoteCompositorSession.h',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
|
||||
|
@ -40,6 +42,8 @@ UNIFIED_SOURCES += [
|
|||
'GPUProcessHost.cpp',
|
||||
'GPUProcessImpl.cpp',
|
||||
'GPUProcessManager.cpp',
|
||||
'InProcessCompositorSession.cpp',
|
||||
'RemoteCompositorSession.cpp',
|
||||
'SharedDIB.cpp',
|
||||
]
|
||||
|
||||
|
|
|
@ -208,11 +208,28 @@ ImageContainer::ImageContainer(Mode flag)
|
|||
break;
|
||||
}
|
||||
}
|
||||
mAsyncContainerID = mImageClient ? mImageClient->GetAsyncID()
|
||||
: sInvalidAsyncContainerId;
|
||||
}
|
||||
|
||||
ImageContainer::ImageContainer(uint64_t aAsyncContainerID)
|
||||
: mReentrantMonitor("ImageContainer.mReentrantMonitor"),
|
||||
mGenerationCounter(++sGenerationCounter),
|
||||
mPaintCount(0),
|
||||
mDroppedImageCount(0),
|
||||
mImageFactory(nullptr),
|
||||
mRecycleBin(nullptr),
|
||||
mImageClient(nullptr),
|
||||
mAsyncContainerID(aAsyncContainerID),
|
||||
mCurrentProducerID(-1),
|
||||
mIPDLChild(nullptr)
|
||||
{
|
||||
MOZ_ASSERT(mAsyncContainerID != sInvalidAsyncContainerId);
|
||||
}
|
||||
|
||||
ImageContainer::~ImageContainer()
|
||||
{
|
||||
if (IsAsync()) {
|
||||
if (mIPDLChild) {
|
||||
mIPDLChild->ForgetImageContainer();
|
||||
ImageBridgeChild::DispatchReleaseImageClient(mImageClient, mIPDLChild);
|
||||
}
|
||||
|
@ -332,7 +349,7 @@ ImageContainer::SetCurrentImages(const nsTArray<NonOwningImage>& aImages)
|
|||
{
|
||||
MOZ_ASSERT(!aImages.IsEmpty());
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
if (IsAsync()) {
|
||||
if (mImageClient) {
|
||||
ImageBridgeChild::DispatchImageClientUpdate(mImageClient, this);
|
||||
}
|
||||
SetCurrentImageInternal(aImages);
|
||||
|
@ -341,7 +358,7 @@ ImageContainer::SetCurrentImages(const nsTArray<NonOwningImage>& aImages)
|
|||
void
|
||||
ImageContainer::ClearAllImages()
|
||||
{
|
||||
if (IsAsync()) {
|
||||
if (mImageClient) {
|
||||
// Let ImageClient release all TextureClients. This doesn't return
|
||||
// until ImageBridge has called ClearCurrentImageFromImageBridge.
|
||||
ImageBridgeChild::FlushAllImages(mImageClient, this);
|
||||
|
@ -385,17 +402,13 @@ ImageContainer::SetCurrentImagesInTransaction(const nsTArray<NonOwningImage>& aI
|
|||
|
||||
bool ImageContainer::IsAsync() const
|
||||
{
|
||||
return mImageClient != nullptr;
|
||||
return mAsyncContainerID != sInvalidAsyncContainerId;
|
||||
}
|
||||
|
||||
uint64_t ImageContainer::GetAsyncContainerID() const
|
||||
{
|
||||
NS_ASSERTION(IsAsync(),"Shared image ID is only relevant to async ImageContainers");
|
||||
if (IsAsync()) {
|
||||
return mImageClient->GetAsyncID();
|
||||
} else {
|
||||
return 0; // zero is always an invalid AsyncID
|
||||
}
|
||||
return mAsyncContainerID;
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
|
@ -359,8 +359,17 @@ public:
|
|||
|
||||
enum Mode { SYNCHRONOUS = 0x0, ASYNCHRONOUS = 0x01 };
|
||||
|
||||
static const uint64_t sInvalidAsyncContainerId = 0;
|
||||
|
||||
explicit ImageContainer(ImageContainer::Mode flag = SYNCHRONOUS);
|
||||
|
||||
/**
|
||||
* Create ImageContainer just to hold another ASYNCHRONOUS ImageContainer's
|
||||
* async container ID.
|
||||
* @param aAsyncContainerID async container ID for which we are a proxy
|
||||
*/
|
||||
explicit ImageContainer(uint64_t aAsyncContainerID);
|
||||
|
||||
typedef uint32_t FrameID;
|
||||
typedef uint32_t ProducerID;
|
||||
|
||||
|
@ -627,6 +636,8 @@ private:
|
|||
// asynchronusly using the ImageBridge IPDL protocol.
|
||||
ImageClient* mImageClient;
|
||||
|
||||
uint64_t mAsyncContainerID;
|
||||
|
||||
nsTArray<FrameID> mFrameIDsNotYetComposited;
|
||||
// ProducerID for last current image(s), including the frames in
|
||||
// mFrameIDsNotYetComposited
|
||||
|
|
|
@ -3657,7 +3657,7 @@ void AsyncPanZoomController::DispatchStateChangeNotification(PanZoomState aOldSt
|
|||
#if defined(XP_WIN) || defined(MOZ_WIDGET_GTK)
|
||||
// Let the compositor know about scroll state changes so it can manage
|
||||
// windowed plugins.
|
||||
if (mCompositorBridgeParent) {
|
||||
if (gfxPrefs::HidePluginsForScroll() && mCompositorBridgeParent) {
|
||||
mCompositorBridgeParent->ScheduleHideAllPluginWindows();
|
||||
}
|
||||
#endif
|
||||
|
@ -3665,7 +3665,7 @@ void AsyncPanZoomController::DispatchStateChangeNotification(PanZoomState aOldSt
|
|||
controller->NotifyAPZStateChange(
|
||||
GetGuid(), APZStateChange::eTransformEnd);
|
||||
#if defined(XP_WIN) || defined(MOZ_WIDGET_GTK)
|
||||
if (mCompositorBridgeParent) {
|
||||
if (gfxPrefs::HidePluginsForScroll() && mCompositorBridgeParent) {
|
||||
mCompositorBridgeParent->ScheduleShowAllPluginWindows();
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -309,7 +309,7 @@ TexClientFromReadback(SharedSurface* src, ClientIPCAllocator* allocator,
|
|||
|
||||
MOZ_ASSERT(texClient);
|
||||
if (!texClient)
|
||||
return nullptr;
|
||||
return nullptr;
|
||||
|
||||
// With a texClient, we can lock for writing.
|
||||
TextureClientAutoLock autoLock(texClient, OpenMode::OPEN_WRITE);
|
||||
|
@ -324,7 +324,7 @@ TexClientFromReadback(SharedSurface* src, ClientIPCAllocator* allocator,
|
|||
auto height = src->mSize.height;
|
||||
|
||||
{
|
||||
ScopedPackAlignment autoAlign(gl, 4);
|
||||
ScopedPackState scopedPackState(gl);
|
||||
|
||||
MOZ_ASSERT(mapped.stride/4 == mapped.size.width);
|
||||
gl->raw_fReadPixels(0, 0, width, height, readFormat, readType, mapped.data);
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче