merge mozilla-inbound to mozilla-central a=merge
@ -259,12 +259,12 @@
|
||||
onpopuphidden="SocialShare.onHidden()"
|
||||
hidden="true">
|
||||
<hbox class="social-share-toolbar">
|
||||
<toolbarbutton id="manage-share-providers" class="toolbarbutton share-provider-button"
|
||||
<toolbarbutton id="manage-share-providers" class="share-provider-button"
|
||||
tooltiptext="&social.addons.label;"
|
||||
oncommand="BrowserOpenAddonsMgr('addons://list/service');
|
||||
this.parentNode.parentNode.hidePopup();"/>
|
||||
<arrowscrollbox id="social-share-provider-buttons" orient="horizontal" flex="1" pack="end">
|
||||
<toolbarbutton id="add-share-provider" class="toolbarbutton share-provider-button" type="radio"
|
||||
<toolbarbutton id="add-share-provider" class="share-provider-button" type="radio"
|
||||
group="share-providers" tooltiptext="&findShareServices.label;"
|
||||
oncommand="SocialShare.showDirectory()"/>
|
||||
</arrowscrollbox>
|
||||
|
@ -303,10 +303,12 @@ function test() {
|
||||
Services.prefs.setBoolPref(PREF_ACTIVE, true);
|
||||
Services.prefs.setBoolPref(PREF_DISPLAY, true);
|
||||
|
||||
var newTab = gBrowser.addTab();
|
||||
gBrowser.selectedTab = newTab;
|
||||
gTestBrowser = gBrowser.selectedBrowser;
|
||||
newTab.linkedBrowser.stop();
|
||||
pushPrefs(["dom.ipc.processCount", 1]).then(() => {
|
||||
var newTab = gBrowser.addTab();
|
||||
gBrowser.selectedTab = newTab;
|
||||
gTestBrowser = gBrowser.selectedBrowser;
|
||||
newTab.linkedBrowser.stop();
|
||||
|
||||
executeSoon(test1);
|
||||
executeSoon(test1);
|
||||
});
|
||||
}
|
||||
|
@ -1,5 +1,11 @@
|
||||
"use strict";
|
||||
|
||||
add_task(function* setup() {
|
||||
yield SpecialPowers.pushPrefEnv({
|
||||
set: [["dom.ipc.processCount", 1]]
|
||||
});
|
||||
})
|
||||
|
||||
add_task(function* () {
|
||||
/** Test for Bug 350525 **/
|
||||
|
||||
|
@ -69,7 +69,7 @@ add_task(function* setup() {
|
||||
|
||||
// This test takes some time to run, and it could timeout randomly.
|
||||
// So we require a longer timeout. See bug 528219.
|
||||
requestLongerTimeout(2);
|
||||
requestLongerTimeout(3);
|
||||
|
||||
// Make the main test window not count as a browser window any longer
|
||||
let oldWinType = document.documentElement.getAttribute("windowtype");
|
||||
|
32
browser/extensions/e10srollout/bootstrap.js
vendored
@ -81,6 +81,7 @@ function defineCohort() {
|
||||
let disqualified = (Services.appinfo.multiprocessBlockPolicy != 0);
|
||||
let testGroup = (getUserSample() < TEST_THRESHOLD[updateChannel]);
|
||||
let hasNonExemptAddon = Preferences.get(PREF_E10S_HAS_NONEXEMPT_ADDON, false);
|
||||
let temporaryDisqualification = getTemporaryDisqualification();
|
||||
|
||||
let cohortPrefix = "";
|
||||
if (disqualified) {
|
||||
@ -93,6 +94,17 @@ function defineCohort() {
|
||||
setCohort("optedOut");
|
||||
} else if (userOptedIn) {
|
||||
setCohort("optedIn");
|
||||
} else if (temporaryDisqualification != "") {
|
||||
// Users who are disqualified by the backend (from multiprocessBlockPolicy)
|
||||
// can be put into either the test or control groups, because e10s will
|
||||
// still be denied by the backend, which is useful so that the E10S_STATUS
|
||||
// telemetry probe can be correctly set.
|
||||
|
||||
// For these volatile disqualification reasons, however, we must not try
|
||||
// to activate e10s because the backend doesn't know about it. E10S_STATUS
|
||||
// here will be accumulated as "2 - Disabled", which is fine too.
|
||||
setCohort(`temp-disqualified-${temporaryDisqualification}`);
|
||||
Preferences.reset(PREF_TOGGLE_E10S);
|
||||
} else if (testGroup) {
|
||||
setCohort(`${cohortPrefix}test`);
|
||||
Preferences.set(PREF_TOGGLE_E10S, true);
|
||||
@ -150,3 +162,23 @@ function optedOut() {
|
||||
(Preferences.isSet(PREF_TOGGLE_E10S) &&
|
||||
Preferences.get(PREF_TOGGLE_E10S) == false);
|
||||
}
|
||||
|
||||
/* If this function returns a non-empty string, it
|
||||
* means that this particular user should be temporarily
|
||||
* disqualified due to some particular reason.
|
||||
* If a user shouldn't be disqualified, then an empty
|
||||
* string must be returned.
|
||||
*/
|
||||
function getTemporaryDisqualification() {
|
||||
let applicationLanguage =
|
||||
Cc["@mozilla.org/chrome/chrome-registry;1"]
|
||||
.getService(Ci.nsIXULChromeRegistry)
|
||||
.getSelectedLocale("global")
|
||||
.split("-")[0];
|
||||
|
||||
if (applicationLanguage == "ru") {
|
||||
return "ru";
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
<Description about="urn:mozilla:install-manifest">
|
||||
<em:id>e10srollout@mozilla.org</em:id>
|
||||
<em:version>1.2</em:version>
|
||||
<em:version>1.3</em:version>
|
||||
<em:type>2</em:type>
|
||||
<em:bootstrap>true</em:bootstrap>
|
||||
<em:multiprocessCompatible>true</em:multiprocessCompatible>
|
||||
|
@ -3,5 +3,6 @@
|
||||
- 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/. -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||
<polygon fill="highlighttext" points="12,3.5 10.5,2 4.625,8 10.5,14 12,12.5 7.625,8" />
|
||||
#include ../icon-colors.inc.svg
|
||||
<polygon class="highlighttext" points="12,3.5 10.5,2 4.625,8 10.5,14 12,12.5 7.625,8"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 432 B After Width: | Height: | Size: 464 B |
@ -3,5 +3,6 @@
|
||||
- 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/. -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||
<polygon fill="-moz-fieldtext" fill-opacity=".7" points="5,3.5 6.5,2 12.375,8 6.5,14 5,12.5 9.375,8"/>
|
||||
#include ../icon-colors.inc.svg
|
||||
<polygon class="fieldtext" points="5,3.5 6.5,2 12.375,8 6.5,14 5,12.5 9.375,8"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 447 B After Width: | Height: | Size: 457 B |
@ -3,13 +3,7 @@
|
||||
- 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/. -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
|
||||
<style>
|
||||
.icon-default {
|
||||
fill: -moz-fieldtext;
|
||||
fill-opacity: .5;
|
||||
}
|
||||
</style>
|
||||
|
||||
#include ../icon-colors.inc.svg
|
||||
<defs>
|
||||
<mask id="mask-globe">
|
||||
<circle fill="#fff" cx="12" cy="12" r="11"/>
|
||||
@ -17,5 +11,5 @@
|
||||
</mask>
|
||||
</defs>
|
||||
|
||||
<rect width="24" height="24" mask="url(#mask-globe)" class="icon-default"/>
|
||||
<rect width="24" height="24" mask="url(#mask-globe)" class="fieldtext"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 62 KiB After Width: | Height: | Size: 62 KiB |
@ -4,16 +4,12 @@
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
width="24" height="24" viewBox="0 0 24 24">
|
||||
#include ../icon-colors.inc.svg
|
||||
<style>
|
||||
svg > rect:not(:target) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#connection-degraded {
|
||||
fill: -moz-fieldtext;
|
||||
fill-opacity: .5;
|
||||
}
|
||||
|
||||
#connection-secure {
|
||||
fill: #4d9a26;
|
||||
}
|
||||
@ -36,6 +32,6 @@
|
||||
</mask>
|
||||
</defs>
|
||||
|
||||
<rect id="connection-degraded" width="24" height="24" mask="url(#mask-lock)"/>
|
||||
<rect id="connection-degraded" class="fieldtext" width="24" height="24" mask="url(#mask-lock)"/>
|
||||
<rect id="connection-secure" width="24" height="24" mask="url(#mask-lock)"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
@ -5,12 +5,7 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
width="24" height="24" viewBox="0 0 24 24">
|
||||
<style>
|
||||
.icon-default {
|
||||
fill: -moz-fieldtext;
|
||||
fill-opacity: .5;
|
||||
}
|
||||
</style>
|
||||
#include ../icon-colors.inc.svg
|
||||
<defs>
|
||||
<rect id="shape-lock-clasp-outer" x="5" y="1" width="14" height="20" rx="7" ry="7" />
|
||||
<rect id="shape-lock-clasp-inner" x="8" y="4" width="8" height="14" rx="4" ry="4" />
|
||||
@ -32,8 +27,8 @@
|
||||
</mask>
|
||||
</defs>
|
||||
|
||||
<use xlink:href="#shape-lock-clasp-outer" mask="url(#mask-clasp-cutout)" class="icon-default"/>
|
||||
<use xlink:href="#shape-lock-base" mask="url(#mask-base-cutout)" class="icon-default"/>
|
||||
<use class="fieldtext" xlink:href="#shape-lock-clasp-outer" mask="url(#mask-clasp-cutout)"/>
|
||||
<use class="fieldtext" xlink:href="#shape-lock-base" mask="url(#mask-base-cutout)"/>
|
||||
|
||||
<line x1="2.25" y1="22.75" x2="21.5" y2="2.5" stroke="#d92d21" stroke-width="3" />
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.6 KiB |
@ -2,13 +2,9 @@
|
||||
<!-- 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/. -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
|
||||
<style>
|
||||
#permissions {
|
||||
fill: -moz-fieldtext;
|
||||
fill-opacity: .5;
|
||||
}
|
||||
</style>
|
||||
<svg xmlns="http://www.w3.org/2000/svg"
|
||||
width="24" height="24" viewBox="0 0 24 24">
|
||||
#include ../icon-colors.inc.svg
|
||||
|
||||
<defs>
|
||||
<mask id="mask-permissions">
|
||||
@ -20,5 +16,5 @@
|
||||
</mask>
|
||||
</defs>
|
||||
|
||||
<rect id="permissions" width="24" height="24" mask="url(#mask-permissions)"/>
|
||||
<rect class="fieldtext" id="permissions" width="24" height="24" mask="url(#mask-permissions)"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
@ -4,14 +4,11 @@
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
width="24" height="24" viewBox="0 0 24 24">
|
||||
#include ../icon-colors.inc.svg
|
||||
<style>
|
||||
g:not(:target) {
|
||||
display: none;
|
||||
}
|
||||
.shield {
|
||||
fill: -moz-fieldtext;
|
||||
fill-opacity: .5;
|
||||
}
|
||||
</style>
|
||||
|
||||
<defs>
|
||||
@ -36,11 +33,11 @@
|
||||
</defs>
|
||||
|
||||
<g id="enabled">
|
||||
<use class="shield" xlink:href="#shape-shield-outer" mask="url(#mask-shield-cutout)"/>
|
||||
<use class="fieldtext" xlink:href="#shape-shield-outer" mask="url(#mask-shield-cutout)"/>
|
||||
</g>
|
||||
|
||||
<g id="disabled">
|
||||
<use class="shield" xlink:href="#shape-shield-outer" mask="url(#mask-shield-cutout-disabled)"/>
|
||||
<use class="fieldtext" xlink:href="#shape-shield-outer" mask="url(#mask-shield-cutout-disabled)"/>
|
||||
<line x1="3" y1="22" x2="23" y2="1" stroke="#d92d21" stroke-width="3"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 2.0 KiB |
39
browser/themes/shared/icon-colors.inc.svg
Normal file
@ -0,0 +1,39 @@
|
||||
<style>
|
||||
|
||||
.fieldtext {
|
||||
fill: -moz-fieldtext;
|
||||
#ifdef XP_LINUX
|
||||
/* The fill-opacity needs to be sufficient for high-contrast settings, and
|
||||
pathological Gtk themes where -moz-fieldtext provides low contrast by
|
||||
default. */
|
||||
fill-opacity: .7;
|
||||
#else
|
||||
fill-opacity: .5;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef XP_WIN
|
||||
@media (-moz-windows-default-theme: 0) {
|
||||
/* more opacity for high-contrast themes */
|
||||
.fieldtext {
|
||||
fill-opacity: .8;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
.highlighttext {
|
||||
fill: highlighttext;
|
||||
fill-opacity: 1;
|
||||
}
|
||||
|
||||
.black {
|
||||
fill: black;
|
||||
fill-opacity: .6;
|
||||
}
|
||||
|
||||
.white {
|
||||
fill: white;
|
||||
fill-opacity: .7;
|
||||
}
|
||||
|
||||
</style>
|
@ -4,22 +4,11 @@
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
width="16" height="16" viewBox="0 0 16 16">
|
||||
#include ../icon-colors.inc.svg
|
||||
<style>
|
||||
svg > g:not(:target) {
|
||||
display: none;
|
||||
}
|
||||
.icon-default {
|
||||
fill: -moz-fieldtext;
|
||||
fill-opacity: .5;
|
||||
}
|
||||
#icon-black > .icon-default {
|
||||
fill: black;
|
||||
fill-opacity: .6;
|
||||
}
|
||||
#icon-white > .icon-default {
|
||||
fill: white;
|
||||
fill-opacity: .7;
|
||||
}
|
||||
</style>
|
||||
|
||||
<defs>
|
||||
@ -49,17 +38,17 @@
|
||||
</defs>
|
||||
|
||||
<g id="icon">
|
||||
<use xlink:href="#lock" class="icon-default"/>
|
||||
<use xlink:href="#lock" class="fieldtext"/>
|
||||
<use xlink:href="#strike-through-red"/>
|
||||
</g>
|
||||
|
||||
<g id="icon-black">
|
||||
<use xlink:href="#lock" class="icon-default"/>
|
||||
<use xlink:href="#lock" class="black"/>
|
||||
<use xlink:href="#strike-through-red"/>
|
||||
</g>
|
||||
|
||||
<g id="icon-white">
|
||||
<use xlink:href="#lock" class="icon-default"/>
|
||||
<use xlink:href="#lock" class="white"/>
|
||||
<use xlink:href="#strike-through-red"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.0 KiB |
@ -4,22 +4,11 @@
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
width="16" height="16" viewBox="0 0 16 16">
|
||||
#include ../icon-colors.inc.svg
|
||||
<style>
|
||||
svg > g:not(:target) {
|
||||
display: none;
|
||||
}
|
||||
.icon-default {
|
||||
fill: -moz-fieldtext;
|
||||
fill-opacity: .5;
|
||||
}
|
||||
#icon-black > .icon-default {
|
||||
fill: black;
|
||||
fill-opacity: .6;
|
||||
}
|
||||
#icon-white > .icon-default {
|
||||
fill: white;
|
||||
fill-opacity: .7;
|
||||
}
|
||||
</style>
|
||||
|
||||
<defs>
|
||||
@ -47,17 +36,17 @@
|
||||
</defs>
|
||||
|
||||
<g id="icon">
|
||||
<rect width="16" height="16" mask="url(#mask-lock)" class="icon-default"/>
|
||||
<rect width="16" height="16" mask="url(#mask-lock)" class="fieldtext"/>
|
||||
<use xlink:href="#warning-triangle"/>
|
||||
</g>
|
||||
|
||||
<g id="icon-black">
|
||||
<rect width="16" height="16" mask="url(#mask-lock)" class="icon-default"/>
|
||||
<rect width="16" height="16" mask="url(#mask-lock)" class="black"/>
|
||||
<use xlink:href="#warning-triangle"/>
|
||||
</g>
|
||||
|
||||
<g id="icon-white">
|
||||
<rect width="16" height="16" mask="url(#mask-lock)" class="icon-default"/>
|
||||
<rect width="16" height="16" mask="url(#mask-lock)" class="white"/>
|
||||
<use xlink:href="#warning-triangle"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 2.2 KiB |
@ -1,47 +1,39 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- 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/. -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
width="16" height="16" viewBox="0 0 16 16">
|
||||
<style>
|
||||
use:not(:target) {
|
||||
display: none;
|
||||
}
|
||||
use {
|
||||
fill-rule: evenodd;
|
||||
fill: -moz-fieldtext;
|
||||
fill-opacity: .5;
|
||||
}
|
||||
use[id$="-black"] {
|
||||
fill: black;
|
||||
fill-opacity: .6;
|
||||
}
|
||||
use[id$="-white"] {
|
||||
fill: white;
|
||||
fill-opacity: .7;
|
||||
}
|
||||
</style>
|
||||
|
||||
<defs>
|
||||
<path id="glyph-normal" d="M128,193a7,7,0,1,1,7-7A7,7,0,0,1,128,193Zm0-13a6,6,0,1,0,6,6A6,6,0,0,0,128,180Zm0,10a1,1,0,0,1-1-1v-3a1,1,0,0,1,2,0v3A1,1,0,0,1,128,190Zm0-6a1,1,0,1,1,1-1A1,1,0,0,1,128,184Z" transform="translate(-120 -178)"/>
|
||||
<path id="glyph-hover" d="M102,179a7,7,0,1,1-7,7A7,7,0,0,1,102,179Zm0,3a1,1,0,1,1-1,1A1,1,0,0,1,102,182Zm0,3a1,1,0,0,1,1,1v3a1,1,0,0,1-2,0v-3A1,1,0,0,1,102,185Z" transform="translate(-94 -178)"/>
|
||||
<path id="glyph-notice" d="M133.5,202a2.5,2.5,0,1,1,2.5-2.5A2.5,2.5,0,0,1,133.5,202Zm-5.5,1a1,1,0,1,1,1-1A1,1,0,0,1,128,203Zm1,5a1,1,0,0,1-2,0v-3a1,1,0,0,1,2,0v3Zm-1-9a6.08,6.08,0,1,0,5.629,3.987,3.452,3.452,0,0,0,.984-0.185A6.9,6.9,0,0,1,135,205a7,7,0,1,1-7-7,6.9,6.9,0,0,1,2.2.387,3.452,3.452,0,0,0-.185.984A5.951,5.951,0,0,0,128,199Z" transform="translate(-120 -197)"/>
|
||||
<path id="glyph-notice-hover" d="M107.5,202a2.5,2.5,0,1,1,2.5-2.5A2.5,2.5,0,0,1,107.5,202Zm0,1.039a3.5,3.5,0,0,0,1.125-.2,7.124,7.124,0,1,1-4.464-4.464,3.5,3.5,0,0,0-.2,1.125A3.54,3.54,0,0,0,107.5,203.039ZM102,201a1,1,0,1,0,1,1A1,1,0,0,0,102,201Zm1,4a1,1,0,0,0-2,0v3a1,1,0,0,0,2,0v-3Z" transform="translate(-94 -197)"/>
|
||||
</defs>
|
||||
|
||||
<use id="normal" xlink:href="#glyph-normal"/>
|
||||
<use id="hover" xlink:href="#glyph-hover"/>
|
||||
<use id="notice" xlink:href="#glyph-notice"/>
|
||||
<use id="notice-hover" xlink:href="#glyph-notice-hover"/>
|
||||
|
||||
<use id="normal-black" xlink:href="#glyph-normal"/>
|
||||
<use id="hover-black" xlink:href="#glyph-hover"/>
|
||||
<use id="notice-black" xlink:href="#glyph-notice"/>
|
||||
<use id="notice-hover-black" xlink:href="#glyph-notice-hover"/>
|
||||
|
||||
<use id="normal-white" xlink:href="#glyph-normal"/>
|
||||
<use id="hover-white" xlink:href="#glyph-hover"/>
|
||||
<use id="notice-white" xlink:href="#glyph-notice"/>
|
||||
<use id="notice-hover-white" xlink:href="#glyph-notice-hover"/>
|
||||
</svg>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- 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/. -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
class="fieldtext"
|
||||
width="16" height="16" viewBox="0 0 16 16">
|
||||
#include ../icon-colors.inc.svg
|
||||
<style>
|
||||
use:not(:target) {
|
||||
display: none;
|
||||
}
|
||||
use {
|
||||
fill-rule: evenodd;
|
||||
}
|
||||
</style>
|
||||
|
||||
<defs>
|
||||
<path id="glyph-normal" d="M128,193a7,7,0,1,1,7-7A7,7,0,0,1,128,193Zm0-13a6,6,0,1,0,6,6A6,6,0,0,0,128,180Zm0,10a1,1,0,0,1-1-1v-3a1,1,0,0,1,2,0v3A1,1,0,0,1,128,190Zm0-6a1,1,0,1,1,1-1A1,1,0,0,1,128,184Z" transform="translate(-120 -178)"/>
|
||||
<path id="glyph-hover" d="M102,179a7,7,0,1,1-7,7A7,7,0,0,1,102,179Zm0,3a1,1,0,1,1-1,1A1,1,0,0,1,102,182Zm0,3a1,1,0,0,1,1,1v3a1,1,0,0,1-2,0v-3A1,1,0,0,1,102,185Z" transform="translate(-94 -178)"/>
|
||||
<path id="glyph-notice" d="M133.5,202a2.5,2.5,0,1,1,2.5-2.5A2.5,2.5,0,0,1,133.5,202Zm-5.5,1a1,1,0,1,1,1-1A1,1,0,0,1,128,203Zm1,5a1,1,0,0,1-2,0v-3a1,1,0,0,1,2,0v3Zm-1-9a6.08,6.08,0,1,0,5.629,3.987,3.452,3.452,0,0,0,.984-0.185A6.9,6.9,0,0,1,135,205a7,7,0,1,1-7-7,6.9,6.9,0,0,1,2.2.387,3.452,3.452,0,0,0-.185.984A5.951,5.951,0,0,0,128,199Z" transform="translate(-120 -197)"/>
|
||||
<path id="glyph-notice-hover" d="M107.5,202a2.5,2.5,0,1,1,2.5-2.5A2.5,2.5,0,0,1,107.5,202Zm0,1.039a3.5,3.5,0,0,0,1.125-.2,7.124,7.124,0,1,1-4.464-4.464,3.5,3.5,0,0,0-.2,1.125A3.54,3.54,0,0,0,107.5,203.039ZM102,201a1,1,0,1,0,1,1A1,1,0,0,0,102,201Zm1,4a1,1,0,0,0-2,0v3a1,1,0,0,0,2,0v-3Z" transform="translate(-94 -197)"/>
|
||||
</defs>
|
||||
|
||||
<use id="normal" xlink:href="#glyph-normal"/>
|
||||
<use id="hover" xlink:href="#glyph-hover"/>
|
||||
<use id="notice" xlink:href="#glyph-notice"/>
|
||||
<use id="notice-hover" xlink:href="#glyph-notice-hover"/>
|
||||
|
||||
<use class="black" id="normal-black" xlink:href="#glyph-normal"/>
|
||||
<use class="black" id="hover-black" xlink:href="#glyph-hover"/>
|
||||
<use class="black" id="notice-black" xlink:href="#glyph-notice"/>
|
||||
<use class="black" id="notice-hover-black" xlink:href="#glyph-notice-hover"/>
|
||||
|
||||
<use class="white" id="normal-white" xlink:href="#glyph-normal"/>
|
||||
<use class="white" id="hover-white" xlink:href="#glyph-hover"/>
|
||||
<use class="white" id="notice-white" xlink:href="#glyph-notice"/>
|
||||
<use class="white" id="notice-hover-white" xlink:href="#glyph-notice-hover"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 2.4 KiB |
@ -1,70 +1,59 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- 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/. -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
width="16" height="16" viewBox="0 0 16 16">
|
||||
<style>
|
||||
g:not(:target) {
|
||||
display: none;
|
||||
}
|
||||
.shield {
|
||||
fill: -moz-fieldtext;
|
||||
fill-opacity: .5;
|
||||
}
|
||||
g[id$="-black"] > .shield {
|
||||
fill: black;
|
||||
fill-opacity: .6;
|
||||
}
|
||||
g[id$="-white"] > .shield {
|
||||
fill: white;
|
||||
fill-opacity: .7;
|
||||
}
|
||||
</style>
|
||||
|
||||
<defs>
|
||||
<path id="shape-shield-outer" d="M8,1L2.8,1.9C2.4,1.9,2,2.4,2,2.8C2,4,2,6.1,2.1,7.1c0.3,2.7,0.8,4,1.9,5.6C5.6,14.7,8,15,8,15s2.4-0.3,4-2.4 c1.2-1.5,1.7-2.9,1.9-5.6C14,6.1,14,4,14,2.8c0-0.5-0.4-0.9-0.8-1L8,1L8,1z"/>
|
||||
<path id="shape-shield-inner" d="M8,2l5,0.8c0,2,0,3.5-0.1,4.1c-0.3,2.7-0.8,3.8-1.7,5.1c-1.1,1.5-2.7,1.9-3.2,2c-0.4-0.1-2.1-0.5-3.2-2 c-1-1.3-1.5-2.4-1.7-5.1C3,6.3,3,4.8,3,2.8L8,2"/>
|
||||
<path id="shape-shield-detail" d="M8,13c-0.5-0.1-1.6-0.5-2.4-1.5c-0.9-1.2-1.3-2.1-1.5-4.6C4,6.3,4,5.2,4,3.7L8,3 V13z"/>
|
||||
|
||||
<mask id="mask-shield-cutout">
|
||||
<rect width="16" height="16" fill="#000" />
|
||||
<use xlink:href="#shape-shield-outer" fill="#fff" />
|
||||
<use xlink:href="#shape-shield-inner" fill="#000" />
|
||||
<use xlink:href="#shape-shield-detail" fill="#fff" />
|
||||
</mask>
|
||||
|
||||
<mask id="mask-shield-cutout-disabled">
|
||||
<rect width="16" height="16" fill="#000"/>
|
||||
<use xlink:href="#shape-shield-outer" fill="#fff"/>
|
||||
<use xlink:href="#shape-shield-inner" fill="#000"/>
|
||||
<use xlink:href="#shape-shield-detail" fill="#fff"/>
|
||||
<line x1="3" y1="15" x2="15" y2="3" stroke="#000" stroke-width="2"/>
|
||||
</mask>
|
||||
|
||||
<line id="strike-through-red" x1="3" y1="14" x2="15" y2="2" stroke="#d92d21" stroke-width="2"/>
|
||||
</defs>
|
||||
|
||||
<g id="enabled">
|
||||
<use class="shield" xlink:href="#shape-shield-outer" mask="url(#mask-shield-cutout)"/>
|
||||
</g>
|
||||
<g id="enabled-black">
|
||||
<use class="shield" xlink:href="#shape-shield-outer" mask="url(#mask-shield-cutout)"/>
|
||||
</g>
|
||||
<g id="enabled-white">
|
||||
<use class="shield" xlink:href="#shape-shield-outer" mask="url(#mask-shield-cutout)"/>
|
||||
</g>
|
||||
|
||||
<g id="disabled">
|
||||
<use class="shield" xlink:href="#shape-shield-outer" mask="url(#mask-shield-cutout-disabled)"/>
|
||||
<use xlink:href="#strike-through-red"/>
|
||||
</g>
|
||||
<g id="disabled-black">
|
||||
<use class="shield" xlink:href="#shape-shield-outer" mask="url(#mask-shield-cutout-disabled)"/>
|
||||
<use xlink:href="#strike-through-red"/>
|
||||
</g>
|
||||
<g id="disabled-white">
|
||||
<use class="shield" xlink:href="#shape-shield-outer" mask="url(#mask-shield-cutout-disabled)"/>
|
||||
<use xlink:href="#strike-through-red"/>
|
||||
</g>
|
||||
</svg>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- 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/. -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
width="16" height="16" viewBox="0 0 16 16">
|
||||
#include ../icon-colors.inc.svg
|
||||
<style>
|
||||
g:not(:target) {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
|
||||
<defs>
|
||||
<path id="shape-shield-outer" d="M8,1L2.8,1.9C2.4,1.9,2,2.4,2,2.8C2,4,2,6.1,2.1,7.1c0.3,2.7,0.8,4,1.9,5.6C5.6,14.7,8,15,8,15s2.4-0.3,4-2.4 c1.2-1.5,1.7-2.9,1.9-5.6C14,6.1,14,4,14,2.8c0-0.5-0.4-0.9-0.8-1L8,1L8,1z"/>
|
||||
<path id="shape-shield-inner" d="M8,2l5,0.8c0,2,0,3.5-0.1,4.1c-0.3,2.7-0.8,3.8-1.7,5.1c-1.1,1.5-2.7,1.9-3.2,2c-0.4-0.1-2.1-0.5-3.2-2 c-1-1.3-1.5-2.4-1.7-5.1C3,6.3,3,4.8,3,2.8L8,2"/>
|
||||
<path id="shape-shield-detail" d="M8,13c-0.5-0.1-1.6-0.5-2.4-1.5c-0.9-1.2-1.3-2.1-1.5-4.6C4,6.3,4,5.2,4,3.7L8,3 V13z"/>
|
||||
|
||||
<mask id="mask-shield-cutout">
|
||||
<rect width="16" height="16" fill="#000" />
|
||||
<use xlink:href="#shape-shield-outer" fill="#fff" />
|
||||
<use xlink:href="#shape-shield-inner" fill="#000" />
|
||||
<use xlink:href="#shape-shield-detail" fill="#fff" />
|
||||
</mask>
|
||||
|
||||
<mask id="mask-shield-cutout-disabled">
|
||||
<rect width="16" height="16" fill="#000"/>
|
||||
<use xlink:href="#shape-shield-outer" fill="#fff"/>
|
||||
<use xlink:href="#shape-shield-inner" fill="#000"/>
|
||||
<use xlink:href="#shape-shield-detail" fill="#fff"/>
|
||||
<line x1="3" y1="15" x2="15" y2="3" stroke="#000" stroke-width="2"/>
|
||||
</mask>
|
||||
|
||||
<line id="strike-through-red" x1="3" y1="14" x2="15" y2="2" stroke="#d92d21" stroke-width="2"/>
|
||||
</defs>
|
||||
|
||||
<g id="enabled">
|
||||
<use class="fieldtext" xlink:href="#shape-shield-outer" mask="url(#mask-shield-cutout)"/>
|
||||
</g>
|
||||
<g id="enabled-black">
|
||||
<use class="black" xlink:href="#shape-shield-outer" mask="url(#mask-shield-cutout)"/>
|
||||
</g>
|
||||
<g id="enabled-white">
|
||||
<use class="white" xlink:href="#shape-shield-outer" mask="url(#mask-shield-cutout)"/>
|
||||
</g>
|
||||
|
||||
<g id="disabled">
|
||||
<use class="fieldtext" xlink:href="#shape-shield-outer" mask="url(#mask-shield-cutout-disabled)"/>
|
||||
<use xlink:href="#strike-through-red"/>
|
||||
</g>
|
||||
<g id="disabled-black">
|
||||
<use class="black" xlink:href="#shape-shield-outer" mask="url(#mask-shield-cutout-disabled)"/>
|
||||
<use xlink:href="#strike-through-red"/>
|
||||
</g>
|
||||
<g id="disabled-white">
|
||||
<use class="white" xlink:href="#shape-shield-outer" mask="url(#mask-shield-cutout-disabled)"/>
|
||||
<use xlink:href="#strike-through-red"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 2.6 KiB |
@ -24,13 +24,13 @@
|
||||
skin/classic/browser/addons/addon-install-restart.svg (../shared/addons/addon-install-restart.svg)
|
||||
skin/classic/browser/addons/addon-install-warning.svg (../shared/addons/addon-install-warning.svg)
|
||||
skin/classic/browser/addons/addon-install-anchor.svg (../shared/addons/addon-install-anchor.svg)
|
||||
skin/classic/browser/controlcenter/arrow-subview.svg (../shared/controlcenter/arrow-subview.svg)
|
||||
skin/classic/browser/controlcenter/arrow-subview-back.svg (../shared/controlcenter/arrow-subview-back.svg)
|
||||
skin/classic/browser/controlcenter/connection.svg (../shared/controlcenter/connection.svg)
|
||||
skin/classic/browser/controlcenter/conn-not-secure.svg (../shared/controlcenter/conn-not-secure.svg)
|
||||
skin/classic/browser/controlcenter/mcb-disabled.svg (../shared/controlcenter/mcb-disabled.svg)
|
||||
skin/classic/browser/controlcenter/permissions.svg (../shared/controlcenter/permissions.svg)
|
||||
skin/classic/browser/controlcenter/tracking-protection.svg (../shared/controlcenter/tracking-protection.svg)
|
||||
* skin/classic/browser/controlcenter/arrow-subview.svg (../shared/controlcenter/arrow-subview.svg)
|
||||
* skin/classic/browser/controlcenter/arrow-subview-back.svg (../shared/controlcenter/arrow-subview-back.svg)
|
||||
* skin/classic/browser/controlcenter/conn-not-secure.svg (../shared/controlcenter/conn-not-secure.svg)
|
||||
* skin/classic/browser/controlcenter/connection.svg (../shared/controlcenter/connection.svg)
|
||||
* skin/classic/browser/controlcenter/mcb-disabled.svg (../shared/controlcenter/mcb-disabled.svg)
|
||||
* skin/classic/browser/controlcenter/permissions.svg (../shared/controlcenter/permissions.svg)
|
||||
* skin/classic/browser/controlcenter/tracking-protection.svg (../shared/controlcenter/tracking-protection.svg)
|
||||
skin/classic/browser/controlcenter/warning-gray.svg (../shared/controlcenter/warning-gray.svg)
|
||||
skin/classic/browser/controlcenter/warning-yellow.svg (../shared/controlcenter/warning-yellow.svg)
|
||||
skin/classic/browser/customizableui/customizeFavicon.ico (../shared/customizableui/customizeFavicon.ico)
|
||||
@ -61,15 +61,15 @@
|
||||
skin/classic/browser/heartbeat-icon.svg (../shared/heartbeat-icon.svg)
|
||||
skin/classic/browser/heartbeat-star-lit.svg (../shared/heartbeat-star-lit.svg)
|
||||
skin/classic/browser/heartbeat-star-off.svg (../shared/heartbeat-star-off.svg)
|
||||
skin/classic/browser/identity-icon.svg (../shared/identity-block/identity-icon.svg)
|
||||
skin/classic/browser/connection-secure.svg (../shared/identity-block/connection-secure.svg)
|
||||
skin/classic/browser/connection-mixed-passive-loaded.svg (../shared/identity-block/connection-mixed-passive-loaded.svg)
|
||||
skin/classic/browser/connection-mixed-active-loaded.svg (../shared/identity-block/connection-mixed-active-loaded.svg)
|
||||
* skin/classic/browser/connection-mixed-passive-loaded.svg (../shared/identity-block/connection-mixed-passive-loaded.svg)
|
||||
* skin/classic/browser/connection-mixed-active-loaded.svg (../shared/identity-block/connection-mixed-active-loaded.svg)
|
||||
* skin/classic/browser/identity-icon.svg (../shared/identity-block/identity-icon.svg)
|
||||
skin/classic/browser/info.svg (../shared/info.svg)
|
||||
skin/classic/browser/menuPanel.svg (../shared/menuPanel.svg)
|
||||
skin/classic/browser/menuPanel-small.svg (../shared/menuPanel-small.svg)
|
||||
* skin/classic/browser/menuPanel.svg (../shared/menuPanel.svg)
|
||||
* skin/classic/browser/menuPanel-small.svg (../shared/menuPanel-small.svg)
|
||||
skin/classic/browser/notification-icons.svg (../shared/notification-icons.svg)
|
||||
skin/classic/browser/tracking-protection-16.svg (../shared/identity-block/tracking-protection-16.svg)
|
||||
* skin/classic/browser/tracking-protection-16.svg (../shared/identity-block/tracking-protection-16.svg)
|
||||
skin/classic/browser/newtab/close.png (../shared/newtab/close.png)
|
||||
skin/classic/browser/newtab/controls.svg (../shared/newtab/controls.svg)
|
||||
skin/classic/browser/newtab/whimsycorn.png (../shared/newtab/whimsycorn.png)
|
||||
|
@ -2,14 +2,10 @@
|
||||
<!-- 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/. -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="96" height="16" viewBox="0 0 96 16">
|
||||
<style>
|
||||
path,
|
||||
rect {
|
||||
fill: -moz-fieldText;
|
||||
fill-opacity: .5;
|
||||
}
|
||||
</style>
|
||||
<svg xmlns="http://www.w3.org/2000/svg"
|
||||
width="96" height="16" viewBox="0 0 96 16"
|
||||
class="fieldtext">
|
||||
#include icon-colors.inc.svg
|
||||
|
||||
<path id="placeholder" d="M8,16a8,8,0,1,1,8-8A8,8,0,0,1,8,16ZM12,4H4v8h8V4ZM5,9.939V6.061L6.939,8ZM9.939,11H6.061L8,9.061ZM11,11h0Zm0-4.939V9.939L9.061,8ZM11,5h0ZM6.061,5H9.939L8,6.939Z"/>
|
||||
<path id="cut" d="M29.63,15a2.426,2.426,0,0,1-2.282-1.277c-0.761-1.109-1.694-2.488-1.694-2.488S25,10.329,24.549,9.623a1.05,1.05,0,0,0-1.106-.538S20.6,4.437,20.124,3.706C19.465,2.689,20.7,1,20.7,1l4.4,7.044a19.333,19.333,0,0,0,1.867,2.286c0.519,0.4,1.382-.373,2.8.908C31.7,12.984,31.048,15,29.63,15ZM29.423,12.11c-0.933-1.042-1.728-.908-1.936-0.639a2.093,2.093,0,0,0,.38,1.748,1.612,1.612,0,0,0,1.383.74C29.838,13.959,30.356,13.153,29.423,12.11ZM25.582,7.372L24.4,5.6,27.276,1s1.233,1.69.575,2.708C27.568,4.142,26.445,5.967,25.582,7.372Zm-4.576,2.956A12.482,12.482,0,0,0,22.43,8.645l0.826,1.239c-0.428.65-.937,1.352-0.937,1.352s-0.933,1.378-1.694,2.488A2.426,2.426,0,0,1,18.344,15c-1.417,0-2.074-2.017-.138-3.765C19.624,9.956,20.487,10.732,21.006,10.329ZM18.551,12.11c-0.933,1.042-.415,1.849.173,1.849a1.612,1.612,0,0,0,1.383-.74,2.093,2.093,0,0,0,.38-1.748C20.28,11.2,19.485,11.068,18.551,12.11Z"/>
|
||||
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.1 KiB |
@ -2,13 +2,10 @@
|
||||
<!-- 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/. -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1056" height="32" viewBox="0 0 1056 32">
|
||||
<style>
|
||||
path {
|
||||
fill: -moz-fieldText;
|
||||
fill-opacity: .5;
|
||||
}
|
||||
</style>
|
||||
<svg xmlns="http://www.w3.org/2000/svg"
|
||||
width="1056" height="32" viewBox="0 0 1056 32"
|
||||
class="fieldtext">
|
||||
#include icon-colors.inc.svg
|
||||
|
||||
<path id="containers" d="M1050,30h-20a2,2,0,0,1-2-2V4.414a1.03,1.03,0,0,1,.29-0.707L1030,2h20l1.71,1.707a1.03,1.03,0,0,1,.29.707V28A2,2,0,0,1,1050,30Zm0-24h-20V28h20V6Zm-2,10h-16V8h16v8Zm-4-4.5a0.5,0.5,0,0,0-1,0V13h-6V11.5a0.5,0.5,0,0,0-1,0v2a0.5,0.5,0,0,0,.5.5h7a0.5,0.5,0,0,0,.5-0.5v-2Zm4,14.5h-16V18h16v8Zm-4-4.5a0.5,0.5,0,0,0-1,0V23h-6V21.5a0.5,0.5,0,0,0-1,0v2a0.5,0.5,0,0,0,.5.5h7a0.5,0.5,0,0,0,.5-0.5v-2Z"/>
|
||||
<path id="tabs" d="M1021.98,28h-28a2,2,0,0,1-2-2V22a2,2,0,0,1,2-2H994c4.591,0,4-3,4.009-8,0.009-4.686.166-8,6.261-8h7.41c6.13,0,6.27,3.314,6.3,8,0.02,5-.59,8,4.02,8h-0.02a2,2,0,0,1,2,2v4A2,2,0,0,1,1021.98,28Z"/>
|
||||
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
@ -200,20 +200,6 @@ interface nsIScriptSecurityManager : nsISupports
|
||||
[implicit_jscontext]
|
||||
nsIPrincipal createNullPrincipal(in jsval originAttributes);
|
||||
|
||||
/**
|
||||
* Creates an expanded principal whose capabilities are the union of the
|
||||
* given principals. An expanded principal has an asymmetric privilege
|
||||
* relationship with its sub-principals (that is to say, it subsumes the
|
||||
* sub-principals, but the sub-principals do not subsume it), even if
|
||||
* there's only one. This presents a legitimate use-case for making an
|
||||
* expanded principal around a single sub-principal, which we do frequently.
|
||||
*
|
||||
* Expanded principals cannot have origin attributes themselves, but rather
|
||||
* have them through their sub-principals - so we don't accept them here.
|
||||
*/
|
||||
nsIPrincipal createExpandedPrincipal([array, size_is(aLength)] in nsIPrincipal aPrincipalArray,
|
||||
[optional] in unsigned long aLength);
|
||||
|
||||
/**
|
||||
* Returns OK if aSourceURI and target have the same "origin"
|
||||
* (scheme, host, and port).
|
||||
|
@ -674,7 +674,8 @@ struct OriginComparator
|
||||
}
|
||||
};
|
||||
|
||||
nsExpandedPrincipal::nsExpandedPrincipal(nsTArray<nsCOMPtr <nsIPrincipal> > &aWhiteList)
|
||||
nsExpandedPrincipal::nsExpandedPrincipal(nsTArray<nsCOMPtr<nsIPrincipal>> &aWhiteList,
|
||||
const PrincipalOriginAttributes& aAttrs)
|
||||
{
|
||||
// We force the principals to be sorted by origin so that nsExpandedPrincipal
|
||||
// origins can have a canonical form.
|
||||
@ -682,6 +683,7 @@ nsExpandedPrincipal::nsExpandedPrincipal(nsTArray<nsCOMPtr <nsIPrincipal> > &aWh
|
||||
for (size_t i = 0; i < aWhiteList.Length(); ++i) {
|
||||
mPrincipals.InsertElementSorted(aWhiteList[i], c);
|
||||
}
|
||||
mOriginAttributes = aAttrs;
|
||||
}
|
||||
|
||||
nsExpandedPrincipal::~nsExpandedPrincipal()
|
||||
|
@ -67,7 +67,8 @@ protected:
|
||||
class nsExpandedPrincipal : public nsIExpandedPrincipal, public mozilla::BasePrincipal
|
||||
{
|
||||
public:
|
||||
explicit nsExpandedPrincipal(nsTArray< nsCOMPtr<nsIPrincipal> > &aWhiteList);
|
||||
nsExpandedPrincipal(nsTArray<nsCOMPtr<nsIPrincipal>> &aWhiteList,
|
||||
const mozilla::PrincipalOriginAttributes& aAttrs);
|
||||
|
||||
NS_DECL_NSIEXPANDEDPRINCIPAL
|
||||
NS_DECL_NSISERIALIZABLE
|
||||
|
@ -1181,21 +1181,6 @@ nsScriptSecurityManager::CreateNullPrincipal(JS::Handle<JS::Value> aOriginAttrib
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsScriptSecurityManager::CreateExpandedPrincipal(nsIPrincipal** aPrincipalArray, uint32_t aLength,
|
||||
nsIPrincipal** aResult)
|
||||
{
|
||||
nsTArray<nsCOMPtr<nsIPrincipal>> principals;
|
||||
principals.SetCapacity(aLength);
|
||||
for (uint32_t i = 0; i < aLength; ++i) {
|
||||
principals.AppendElement(aPrincipalArray[i]);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIPrincipal> p = new nsExpandedPrincipal(principals);
|
||||
p.forget(aResult);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsScriptSecurityManager::GetAppCodebasePrincipal(nsIURI* aURI,
|
||||
uint32_t aAppId,
|
||||
|
@ -35,6 +35,13 @@ function checkOriginAttributes(prin, attrs, suffix) {
|
||||
}
|
||||
}
|
||||
|
||||
function checkSandboxOriginAttributes(arr, attrs, options) {
|
||||
options = options || {};
|
||||
var sandbox = Cu.Sandbox(arr, options);
|
||||
checkOriginAttributes(Cu.getObjectPrincipal(sandbox), attrs,
|
||||
ChromeUtils.originAttributesToSuffix(attrs));
|
||||
}
|
||||
|
||||
// utility function useful for debugging
|
||||
function printAttrs(name, attrs) {
|
||||
do_print(name + " {\n" +
|
||||
@ -80,7 +87,7 @@ function run_test() {
|
||||
var ipv6NPPrin = ssm.createCodebasePrincipal(makeURI('https://[2001:db8::ff00:42:8329]'), {});
|
||||
do_check_eq(ipv6NPPrin.origin, 'https://[2001:db8::ff00:42:8329]');
|
||||
checkOriginAttributes(ipv6NPPrin);
|
||||
var ep = ssm.createExpandedPrincipal([exampleCom, nullPrin, exampleOrg]);
|
||||
var ep = Cu.getObjectPrincipal(Cu.Sandbox([exampleCom, nullPrin, exampleOrg]));
|
||||
checkOriginAttributes(ep);
|
||||
checkCrossOrigin(exampleCom, exampleOrg);
|
||||
checkCrossOrigin(exampleOrg, nullPrin);
|
||||
@ -177,6 +184,30 @@ function run_test() {
|
||||
// Just signedPkg (but different value from 'exampleOrg_signedPkg_app')
|
||||
var exampleOrg_signedPkg_another = ssm.createCodebasePrincipal(makeURI('http://example.org'), {signedPkg: 'whatup'});
|
||||
|
||||
checkSandboxOriginAttributes(null, {});
|
||||
checkSandboxOriginAttributes('http://example.org', {});
|
||||
checkSandboxOriginAttributes('http://example.org', {}, {originAttributes: {}});
|
||||
checkSandboxOriginAttributes('http://example.org', {appId: 42}, {originAttributes: {appId: 42}});
|
||||
checkSandboxOriginAttributes(['http://example.org'], {});
|
||||
checkSandboxOriginAttributes(['http://example.org'], {}, {originAttributes: {}});
|
||||
checkSandboxOriginAttributes(['http://example.org'], {appId: 42}, {originAttributes: {appId: 42}});
|
||||
checkSandboxOriginAttributes([exampleOrg_signedPkg, 'http://example.org'], {signedPkg: 'whatever'});
|
||||
checkSandboxOriginAttributes(['http://example.org', exampleOrg_signedPkg], {signedPkg: 'whatever'});
|
||||
checkSandboxOriginAttributes(['http://example.org', exampleOrg_app, exampleOrg_signedPkg], {signedPkg: 'whatever'}, {originAttributes: {signedPkg: 'whatever'}});
|
||||
checkSandboxOriginAttributes(['http://example.org', exampleOrg_signedPkg, exampleOrg_app], {signedPkg: 'whatever'}, {originAttributes: {signedPkg: 'whatever'}});
|
||||
checkSandboxOriginAttributes([exampleOrg_app, exampleOrg_signedPkg, 'http://example.org'], {signedPkg: 'whatever'}, {originAttributes: {signedPkg: 'whatever'}});
|
||||
checkSandboxOriginAttributes([exampleOrg_app, 'http://example.org', exampleOrg_signedPkg], {signedPkg: 'whatever'}, {originAttributes: {signedPkg: 'whatever'}});
|
||||
checkSandboxOriginAttributes([exampleOrg_signedPkg, exampleOrg_app, 'http://example.org'], {signedPkg: 'whatever'}, {originAttributes: {signedPkg: 'whatever'}});
|
||||
checkSandboxOriginAttributes([exampleOrg_signedPkg, 'http://example.org', exampleOrg_app], {signedPkg: 'whatever'}, {originAttributes: {signedPkg: 'whatever'}});
|
||||
checkThrows(() => Cu.Sandbox([exampleOrg_app, exampleOrg_signedPkg]));
|
||||
checkThrows(() => Cu.Sandbox([exampleOrg_signedPkg, exampleOrg_app]));
|
||||
checkThrows(() => Cu.Sandbox(['http://example.org', exampleOrg_app, exampleOrg_signedPkg]));
|
||||
checkThrows(() => Cu.Sandbox(['http://example.org', exampleOrg_signedPkg, exampleOrg_app]));
|
||||
checkThrows(() => Cu.Sandbox([exampleOrg_app, exampleOrg_signedPkg, 'http://example.org']));
|
||||
checkThrows(() => Cu.Sandbox([exampleOrg_app, 'http://example.org', exampleOrg_signedPkg]));
|
||||
checkThrows(() => Cu.Sandbox([exampleOrg_signedPkg, exampleOrg_app, 'http://example.org']));
|
||||
checkThrows(() => Cu.Sandbox([exampleOrg_signedPkg, 'http://example.org', exampleOrg_app]));
|
||||
|
||||
// Check that all of the above are cross-origin.
|
||||
checkCrossOrigin(exampleOrg_app, exampleOrg);
|
||||
checkCrossOrigin(exampleOrg_app, nullPrin_app);
|
||||
@ -204,7 +235,7 @@ function run_test() {
|
||||
}
|
||||
checkKind(ssm.createNullPrincipal({}), 'nullPrincipal');
|
||||
checkKind(ssm.createCodebasePrincipal(makeURI('http://www.example.com'), {}), 'codebasePrincipal');
|
||||
checkKind(ssm.createExpandedPrincipal([ssm.createCodebasePrincipal(makeURI('http://www.example.com'), {})]), 'expandedPrincipal');
|
||||
checkKind(Cu.getObjectPrincipal(Cu.Sandbox([ssm.createCodebasePrincipal(makeURI('http://www.example.com'), {})])), 'expandedPrincipal');
|
||||
checkKind(ssm.getSystemPrincipal(), 'systemPrincipal');
|
||||
|
||||
//
|
||||
|
@ -282,7 +282,6 @@ bool nsContentUtils::sEncodeDecodeURLHash = false;
|
||||
bool nsContentUtils::sGettersDecodeURLHash = false;
|
||||
bool nsContentUtils::sPrivacyResistFingerprinting = false;
|
||||
bool nsContentUtils::sSendPerformanceTimingNotifications = false;
|
||||
bool nsContentUtils::sAppendLFInSerialization = false;
|
||||
bool nsContentUtils::sUseActivityCursor = false;
|
||||
|
||||
uint32_t nsContentUtils::sHandlingInputTimeout = 1000;
|
||||
@ -600,8 +599,6 @@ nsContentUtils::Init()
|
||||
"network.cookie.cookieBehavior",
|
||||
nsICookieService::BEHAVIOR_ACCEPT);
|
||||
|
||||
Preferences::AddBoolVarCache(&sAppendLFInSerialization,
|
||||
"dom.html_fragment_serialisation.appendLF");
|
||||
#if !(defined(DEBUG) || defined(MOZ_ENABLE_JS_DUMP))
|
||||
Preferences::AddBoolVarCache(&sDOMWindowDumpEnabled,
|
||||
"browser.dom.window.dump.enabled");
|
||||
@ -9142,12 +9139,12 @@ StartElement(Element* aContent, StringBuilder& aBuilder)
|
||||
|
||||
aBuilder.Append(">");
|
||||
|
||||
|
||||
/*
|
||||
// Per HTML spec we should append one \n if the first child of
|
||||
// pre/textarea/listing is a textnode and starts with a \n.
|
||||
// But because browsers haven't traditionally had that behavior,
|
||||
// we're not changing our behavior either - yet.
|
||||
if (nsContentUtils::AppendLFInSerialization() && aContent->IsHTMLElement()) {
|
||||
if (aContent->IsHTMLElement()) {
|
||||
if (localName == nsGkAtoms::pre || localName == nsGkAtoms::textarea ||
|
||||
localName == nsGkAtoms::listing) {
|
||||
nsIContent* fc = aContent->GetFirstChild();
|
||||
@ -9160,7 +9157,7 @@ StartElement(Element* aContent, StringBuilder& aBuilder)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
static inline bool
|
||||
|
@ -1967,10 +1967,6 @@ public:
|
||||
static already_AddRefed<mozilla::layers::LayerManager>
|
||||
PersistentLayerManagerForDocument(nsIDocument *aDoc);
|
||||
|
||||
/* static */
|
||||
static bool AppendLFInSerialization()
|
||||
{ return sAppendLFInSerialization; }
|
||||
|
||||
/**
|
||||
* Determine whether a content node is focused or not,
|
||||
*
|
||||
@ -2824,7 +2820,6 @@ private:
|
||||
static bool sGettersDecodeURLHash;
|
||||
static bool sPrivacyResistFingerprinting;
|
||||
static bool sSendPerformanceTimingNotifications;
|
||||
static bool sAppendLFInSerialization;
|
||||
static bool sUseActivityCursor;
|
||||
static uint32_t sCookiesLifetimePolicy;
|
||||
static uint32_t sCookiesBehavior;
|
||||
|
@ -2099,6 +2099,8 @@ GK_ATOM(onenter, "onenter")
|
||||
GK_ATOM(onexit, "onexit")
|
||||
GK_ATOM(onencrypted, "onencrypted")
|
||||
GK_ATOM(encrypted, "encrypted")
|
||||
GK_ATOM(onwaitingforkey, "onwaitingforkey")
|
||||
GK_ATOM(onkeystatuseschange, "onkeystatuseschange")
|
||||
GK_ATOM(onremovetrack, "onremovetrack")
|
||||
GK_ATOM(loadstart, "loadstart")
|
||||
GK_ATOM(suspend, "suspend")
|
||||
|
@ -596,21 +596,21 @@ nsImageLoadingContent::GetCurrentURI(nsIURI** aURI)
|
||||
return result.StealNSResult();
|
||||
}
|
||||
|
||||
already_AddRefed<nsIStreamListener>
|
||||
NS_IMETHODIMP
|
||||
nsImageLoadingContent::LoadImageWithChannel(nsIChannel* aChannel,
|
||||
ErrorResult& aError)
|
||||
nsIStreamListener** aListener)
|
||||
{
|
||||
imgLoader* loader =
|
||||
nsContentUtils::GetImgLoaderForChannel(aChannel, GetOurOwnerDoc());
|
||||
if (!loader) {
|
||||
aError.Throw(NS_ERROR_NULL_POINTER);
|
||||
return nullptr;
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDocument> doc = GetOurOwnerDoc();
|
||||
if (!doc) {
|
||||
// Don't bother
|
||||
return nullptr;
|
||||
*aListener = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// XXX what should we do with content policies here, if anything?
|
||||
@ -621,38 +621,24 @@ nsImageLoadingContent::LoadImageWithChannel(nsIChannel* aChannel,
|
||||
AutoStateChanger changer(this, true);
|
||||
|
||||
// Do the load.
|
||||
nsCOMPtr<nsIStreamListener> listener;
|
||||
RefPtr<imgRequestProxy>& req = PrepareNextRequest(eImageLoadType_Normal);
|
||||
nsresult rv = loader->
|
||||
LoadImageWithChannel(aChannel, this, doc,
|
||||
getter_AddRefs(listener),
|
||||
getter_AddRefs(req));
|
||||
LoadImageWithChannel(aChannel, this, doc, aListener, getter_AddRefs(req));
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
TrackImage(req);
|
||||
ResetAnimationIfNeeded();
|
||||
} else {
|
||||
MOZ_ASSERT(!req, "Shouldn't have non-null request here");
|
||||
// If we don't have a current URI, we might as well store this URI so people
|
||||
// know what we tried (and failed) to load.
|
||||
if (!mCurrentRequest)
|
||||
aChannel->GetURI(getter_AddRefs(mCurrentURI));
|
||||
|
||||
FireEvent(NS_LITERAL_STRING("error"));
|
||||
FireEvent(NS_LITERAL_STRING("loadend"));
|
||||
aError.Throw(rv);
|
||||
return NS_OK;
|
||||
}
|
||||
return listener.forget();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsImageLoadingContent::LoadImageWithChannel(nsIChannel* aChannel,
|
||||
nsIStreamListener** aListener)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aListener);
|
||||
MOZ_ASSERT(!req, "Shouldn't have non-null request here");
|
||||
// If we don't have a current URI, we might as well store this URI so people
|
||||
// know what we tried (and failed) to load.
|
||||
if (!mCurrentRequest)
|
||||
aChannel->GetURI(getter_AddRefs(mCurrentURI));
|
||||
|
||||
ErrorResult result;
|
||||
*aListener = LoadImageWithChannel(aChannel, result).take();
|
||||
return result.StealNSResult();
|
||||
FireEvent(NS_LITERAL_STRING("error"));
|
||||
FireEvent(NS_LITERAL_STRING("loadend"));
|
||||
return rv;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -77,13 +77,6 @@ public:
|
||||
return ForceReload(aNotify, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to initialize content with a previously opened channel. Assumes
|
||||
* eImageLoadType_Normal
|
||||
*/
|
||||
already_AddRefed<nsIStreamListener>
|
||||
LoadImageWithChannel(nsIChannel* aChannel, mozilla::ErrorResult& aError);
|
||||
|
||||
protected:
|
||||
enum ImageLoadType {
|
||||
// Most normal image loads
|
||||
|
@ -22,9 +22,7 @@ class nsICycleCollectorListener;
|
||||
class nsScriptNameSpaceManager;
|
||||
|
||||
namespace JS {
|
||||
template <typename T>
|
||||
class AutoVectorRooter;
|
||||
typedef AutoVectorRooter<Value> AutoValueVector;
|
||||
class AutoValueVector;
|
||||
} // namespace JS
|
||||
|
||||
namespace mozilla {
|
||||
|
@ -2893,8 +2893,11 @@ nsScriptLoadHandler::TryDecodeRawData(const uint8_t* aData,
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
uint32_t haveRead = mBuffer.length();
|
||||
uint32_t capacity = haveRead + dstLen;
|
||||
if (!mBuffer.reserve(capacity)) {
|
||||
|
||||
CheckedInt<uint32_t> capacity = haveRead;
|
||||
capacity += dstLen;
|
||||
|
||||
if (!capacity.isValid() || !mBuffer.reserve(capacity.value())) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
@ -2906,7 +2909,7 @@ nsScriptLoadHandler::TryDecodeRawData(const uint8_t* aData,
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
haveRead += dstLen;
|
||||
MOZ_ASSERT(haveRead <= capacity, "mDecoder produced more data than expected");
|
||||
MOZ_ASSERT(haveRead <= capacity.value(), "mDecoder produced more data than expected");
|
||||
MOZ_ALWAYS_TRUE(mBuffer.resizeUninitialized(haveRead));
|
||||
|
||||
return NS_OK;
|
||||
|
@ -26,7 +26,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=744830
|
||||
t.appendChild(document.createElement("textarea"));
|
||||
t.firstChild.appendChild(document.createTextNode("\nhello"));
|
||||
// This is the old behavior. Spec requires something else.
|
||||
is(t.innerHTML, "<textarea>\n\nhello</textarea>",
|
||||
is(t.innerHTML, "<textarea>\nhello</textarea>",
|
||||
"No extra newlines should be inserted to the textarea!");
|
||||
|
||||
t.innerHTML = null;
|
||||
|
@ -3061,6 +3061,13 @@ UnwrapArgImpl(JS::Handle<JSObject*> src,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Only allow XPCWrappedJS stuff in system code. Ideally we would remove this
|
||||
// even there, but that involves converting some things to WebIDL callback
|
||||
// interfaces and making some other things builtinclass...
|
||||
if (!nsContentUtils::IsCallerChrome()) {
|
||||
return NS_ERROR_XPC_BAD_CONVERT_JS;
|
||||
}
|
||||
|
||||
RefPtr<nsXPCWrappedJS> wrappedJS;
|
||||
nsresult rv = nsXPCWrappedJS::GetNewOrUsed(src, iid, getter_AddRefs(wrappedJS));
|
||||
if (NS_FAILED(rv) || !wrappedJS) {
|
||||
|
@ -349,21 +349,10 @@ public:
|
||||
nsIntRegion fillPaintNeededRegion;
|
||||
nsIntRegion strokePaintNeededRegion;
|
||||
|
||||
if (aCtx->CurrentState().updateFilterOnWriteOnly) {
|
||||
aCtx->UpdateFilter();
|
||||
aCtx->CurrentState().updateFilterOnWriteOnly = false;
|
||||
}
|
||||
|
||||
// This should not be empty, but if it is, we want to handle it
|
||||
// rather than crash, as UpdateFilter() call above could have changed
|
||||
// the number of filter primitives.
|
||||
MOZ_ASSERT(!aCtx->CurrentState().filter.mPrimitives.IsEmpty());
|
||||
if (!aCtx->CurrentState().filter.mPrimitives.IsEmpty()) {
|
||||
FilterSupport::ComputeSourceNeededRegions(
|
||||
aCtx->CurrentState().filter, mPostFilterBounds,
|
||||
sourceGraphicNeededRegion, fillPaintNeededRegion,
|
||||
strokePaintNeededRegion);
|
||||
}
|
||||
FilterSupport::ComputeSourceNeededRegions(
|
||||
aCtx->CurrentState().filter, mPostFilterBounds,
|
||||
sourceGraphicNeededRegion, fillPaintNeededRegion,
|
||||
strokePaintNeededRegion);
|
||||
|
||||
mSourceGraphicRect = sourceGraphicNeededRegion.GetBounds();
|
||||
mFillPaintRect = fillPaintNeededRegion.GetBounds();
|
||||
@ -2796,9 +2785,6 @@ CanvasRenderingContext2D::SetFilter(const nsAString& aFilter, ErrorResult& aErro
|
||||
UpdateFilter();
|
||||
}
|
||||
}
|
||||
if (mCanvasElement && !mCanvasElement->IsWriteOnly()) {
|
||||
CurrentState().updateFilterOnWriteOnly = true;
|
||||
}
|
||||
}
|
||||
|
||||
class CanvasUserSpaceMetrics : public UserSpaceMetricsWithSize
|
||||
@ -2867,6 +2853,8 @@ CanvasRenderingContext2D::UpdateFilter()
|
||||
presShell->GetPresContext()),
|
||||
gfxRect(0, 0, mWidth, mHeight),
|
||||
CurrentState().filterAdditionalImages);
|
||||
CurrentState().filterSourceGraphicTainted =
|
||||
(mCanvasElement && mCanvasElement->IsWriteOnly());
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -875,8 +875,21 @@ protected:
|
||||
*/
|
||||
bool NeedToApplyFilter()
|
||||
{
|
||||
return EnsureUpdatedFilter().mPrimitives.Length() > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls UpdateFilter if the canvas's WriteOnly state has changed between the
|
||||
* last call to UpdateFilter and now.
|
||||
*/
|
||||
const gfx::FilterDescription& EnsureUpdatedFilter() {
|
||||
const ContextState& state = CurrentState();
|
||||
return state.filter.mPrimitives.Length() > 0;
|
||||
bool isWriteOnly = mCanvasElement && mCanvasElement->IsWriteOnly();
|
||||
if (state.filterSourceGraphicTainted != isWriteOnly) {
|
||||
UpdateFilter();
|
||||
}
|
||||
MOZ_ASSERT(state.filterSourceGraphicTainted == isWriteOnly);
|
||||
return state.filter;
|
||||
}
|
||||
|
||||
bool NeedToCalculateBounds()
|
||||
@ -968,7 +981,7 @@ protected:
|
||||
lineCap(mozilla::gfx::CapStyle::BUTT),
|
||||
lineJoin(mozilla::gfx::JoinStyle::MITER_OR_BEVEL),
|
||||
filterString(u"none"),
|
||||
updateFilterOnWriteOnly(false),
|
||||
filterSourceGraphicTainted(false),
|
||||
imageSmoothingEnabled(true),
|
||||
fontExplicitLanguage(false)
|
||||
{ }
|
||||
@ -1001,7 +1014,7 @@ protected:
|
||||
filterChainObserver(aOther.filterChainObserver),
|
||||
filter(aOther.filter),
|
||||
filterAdditionalImages(aOther.filterAdditionalImages),
|
||||
updateFilterOnWriteOnly(aOther.updateFilterOnWriteOnly),
|
||||
filterSourceGraphicTainted(aOther.filterSourceGraphicTainted),
|
||||
imageSmoothingEnabled(aOther.imageSmoothingEnabled),
|
||||
fontExplicitLanguage(aOther.fontExplicitLanguage)
|
||||
{ }
|
||||
@ -1079,7 +1092,7 @@ protected:
|
||||
RefPtr<nsSVGFilterChainObserver> filterChainObserver;
|
||||
mozilla::gfx::FilterDescription filter;
|
||||
nsTArray<RefPtr<mozilla::gfx::SourceSurface>> filterAdditionalImages;
|
||||
bool updateFilterOnWriteOnly;
|
||||
bool filterSourceGraphicTainted;
|
||||
|
||||
bool imageSmoothingEnabled;
|
||||
bool fontExplicitLanguage;
|
||||
|
@ -41,7 +41,6 @@ WebGL1Context::WrapObject(JSContext* cx, JS::Handle<JSObject*> givenProto)
|
||||
bool
|
||||
WebGL1Context::ValidateQueryTarget(GLenum target, const char* info)
|
||||
{
|
||||
// TODO: Implement this for EXT_disjoint_timer
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -36,9 +36,6 @@ private:
|
||||
virtual bool ValidateAttribPointerType(bool integerMode, GLenum type,
|
||||
uint32_t* alignment,
|
||||
const char* info) override;
|
||||
virtual bool ValidateBufferTarget(GLenum target, const char* info) override;
|
||||
virtual bool ValidateBufferIndexedTarget(GLenum target, const char* info) override;
|
||||
virtual bool ValidateBufferUsageEnum(GLenum usage, const char* info) override;
|
||||
virtual bool ValidateQueryTarget(GLenum target, const char* info) override;
|
||||
virtual bool ValidateUniformMatrixTranspose(bool transpose, const char* info) override;
|
||||
};
|
||||
|
@ -1,51 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* 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 "WebGL1Context.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Buffer objects
|
||||
|
||||
/** Target validation for BindBuffer, etc */
|
||||
bool
|
||||
WebGL1Context::ValidateBufferTarget(GLenum target, const char* info)
|
||||
{
|
||||
switch (target) {
|
||||
case LOCAL_GL_ARRAY_BUFFER:
|
||||
case LOCAL_GL_ELEMENT_ARRAY_BUFFER:
|
||||
return true;
|
||||
|
||||
default:
|
||||
ErrorInvalidEnumInfo(info, target);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
WebGL1Context::ValidateBufferIndexedTarget(GLenum target, const char* info)
|
||||
{
|
||||
ErrorInvalidEnumInfo(info, target);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
WebGL1Context::ValidateBufferUsageEnum(GLenum usage, const char* info)
|
||||
{
|
||||
switch (usage) {
|
||||
case LOCAL_GL_STREAM_DRAW:
|
||||
case LOCAL_GL_STATIC_DRAW:
|
||||
case LOCAL_GL_DYNAMIC_DRAW:
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
ErrorInvalidEnumInfo(info, usage);
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
@ -158,8 +158,7 @@ WebGLContext::InitWebGL2(FailureReason* const out_failReason)
|
||||
gl->GetUIntegerv(LOCAL_GL_MAX_UNIFORM_BUFFER_BINDINGS,
|
||||
&mGLMaxUniformBufferBindings);
|
||||
|
||||
mBoundTransformFeedbackBuffers.SetLength(mGLMaxTransformFeedbackSeparateAttribs);
|
||||
mBoundUniformBuffers.SetLength(mGLMaxUniformBufferBindings);
|
||||
mIndexedUniformBufferBindings.resize(mGLMaxUniformBufferBindings);
|
||||
|
||||
mDefaultTransformFeedback = new WebGLTransformFeedback(this, 0);
|
||||
mBoundTransformFeedback = mDefaultTransformFeedback;
|
||||
|
@ -273,21 +273,20 @@ public:
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Writing to the drawing buffer
|
||||
// TODO(djg): Implemented in WebGLContext
|
||||
/*
|
||||
|
||||
/* Implemented in WebGLContext
|
||||
void VertexAttribDivisor(GLuint index, GLuint divisor);
|
||||
void DrawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei instanceCount);
|
||||
void DrawElementsInstanced(GLenum mode, GLsizei count, GLenum type, GLintptr offset, GLsizei instanceCount);
|
||||
*/
|
||||
*/
|
||||
void DrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, GLintptr offset);
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Multiple Render Targets - WebGL2ContextMRTs.cpp
|
||||
// TODO(djg): Implemented in WebGLContext
|
||||
/*
|
||||
/* Implemented in WebGLContext
|
||||
void DrawBuffers(const dom::Sequence<GLenum>& buffers);
|
||||
*/
|
||||
*/
|
||||
|
||||
void ClearBufferiv_base(GLenum buffer, GLint drawbuffer, const GLint* value);
|
||||
void ClearBufferuiv_base(GLenum buffer, GLint drawbuffer, const GLuint* value);
|
||||
@ -412,9 +411,6 @@ private:
|
||||
virtual bool ValidateAttribPointerType(bool integerMode, GLenum type,
|
||||
uint32_t* alignment,
|
||||
const char* info) override;
|
||||
virtual bool ValidateBufferTarget(GLenum target, const char* info) override;
|
||||
virtual bool ValidateBufferIndexedTarget(GLenum target, const char* info) override;
|
||||
virtual bool ValidateBufferUsageEnum(GLenum usage, const char* info) override;
|
||||
virtual bool ValidateQueryTarget(GLenum target, const char* info) override;
|
||||
virtual bool ValidateUniformMatrixTranspose(bool transpose, const char* info) override;
|
||||
};
|
||||
|
@ -11,62 +11,6 @@
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
bool
|
||||
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_PIXEL_UNPACK_BUFFER:
|
||||
case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER:
|
||||
case LOCAL_GL_UNIFORM_BUFFER:
|
||||
return true;
|
||||
|
||||
default:
|
||||
ErrorInvalidEnumInfo(funcName, target);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
WebGL2Context::ValidateBufferIndexedTarget(GLenum target, const char* info)
|
||||
{
|
||||
switch (target) {
|
||||
case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER:
|
||||
case LOCAL_GL_UNIFORM_BUFFER:
|
||||
return true;
|
||||
|
||||
default:
|
||||
ErrorInvalidEnumInfo(info, target);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
WebGL2Context::ValidateBufferUsageEnum(GLenum usage, const char* info)
|
||||
{
|
||||
switch (usage) {
|
||||
case LOCAL_GL_DYNAMIC_COPY:
|
||||
case LOCAL_GL_DYNAMIC_DRAW:
|
||||
case LOCAL_GL_DYNAMIC_READ:
|
||||
case LOCAL_GL_STATIC_COPY:
|
||||
case LOCAL_GL_STATIC_DRAW:
|
||||
case LOCAL_GL_STATIC_READ:
|
||||
case LOCAL_GL_STREAM_COPY:
|
||||
case LOCAL_GL_STREAM_DRAW:
|
||||
case LOCAL_GL_STREAM_READ:
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
ErrorInvalidEnumInfo(info, usage);
|
||||
return false;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Buffer objects
|
||||
|
||||
@ -79,48 +23,58 @@ WebGL2Context::CopyBufferSubData(GLenum readTarget, GLenum writeTarget,
|
||||
if (IsContextLost())
|
||||
return;
|
||||
|
||||
if (!ValidateBufferTarget(readTarget, funcName) ||
|
||||
!ValidateBufferTarget(writeTarget, funcName))
|
||||
const auto& readBuffer = ValidateBufferSelection(funcName, readTarget);
|
||||
if (!readBuffer)
|
||||
return;
|
||||
|
||||
const auto& writeBuffer = ValidateBufferSelection(funcName, writeTarget);
|
||||
if (!writeBuffer)
|
||||
return;
|
||||
|
||||
if (readBuffer->mNumActiveTFOs ||
|
||||
writeBuffer->mNumActiveTFOs)
|
||||
{
|
||||
ErrorInvalidOperation("%s: Buffer is bound to an active transform feedback"
|
||||
" object.",
|
||||
funcName);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ValidateNonNegative(funcName, "readOffset", readOffset) ||
|
||||
!ValidateNonNegative(funcName, "writeOffset", writeOffset) ||
|
||||
!ValidateNonNegative(funcName, "size", size))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const WebGLRefPtr<WebGLBuffer>& readBufferSlot = GetBufferSlotByTarget(readTarget);
|
||||
const WebGLRefPtr<WebGLBuffer>& writeBufferSlot = GetBufferSlotByTarget(writeTarget);
|
||||
if (!readBufferSlot || !writeBufferSlot)
|
||||
return;
|
||||
const auto fnValidateOffsetSize = [&](const char* info, GLintptr offset,
|
||||
const WebGLBuffer* buffer)
|
||||
{
|
||||
const auto neededBytes = CheckedInt<size_t>(offset) + size;
|
||||
if (!neededBytes.isValid() || neededBytes.value() > buffer->ByteLength()) {
|
||||
ErrorInvalidValue("%s: Invalid %s range.", funcName, info);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
const WebGLBuffer* readBuffer = readBufferSlot.get();
|
||||
if (!readBuffer) {
|
||||
ErrorInvalidOperation("%s: No buffer bound to readTarget.", funcName);
|
||||
if (!fnValidateOffsetSize("read", readOffset, readBuffer) ||
|
||||
!fnValidateOffsetSize("write", writeOffset, writeBuffer))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
WebGLBuffer* writeBuffer = writeBufferSlot.get();
|
||||
if (!writeBuffer) {
|
||||
ErrorInvalidOperation("%s: No buffer bound to writeTarget.", funcName);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ValidateDataOffsetSize(readOffset, size, readBuffer->ByteLength(), funcName))
|
||||
return;
|
||||
|
||||
if (!ValidateDataOffsetSize(writeOffset, size, writeBuffer->ByteLength(), funcName))
|
||||
return;
|
||||
|
||||
if (readTarget == writeTarget &&
|
||||
if (readBuffer == writeBuffer &&
|
||||
!ValidateDataRanges(readOffset, writeOffset, size, funcName))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
WebGLBuffer::Kind readType = readBuffer->Content();
|
||||
WebGLBuffer::Kind writeType = writeBuffer->Content();
|
||||
|
||||
if (readType != WebGLBuffer::Kind::Undefined &&
|
||||
writeType != WebGLBuffer::Kind::Undefined &&
|
||||
writeType != readType)
|
||||
{
|
||||
const auto& readType = readBuffer->Content();
|
||||
const auto& writeType = writeBuffer->Content();
|
||||
MOZ_ASSERT(readType != WebGLBuffer::Kind::Undefined);
|
||||
MOZ_ASSERT(writeType != WebGLBuffer::Kind::Undefined);
|
||||
if (writeType != readType) {
|
||||
ErrorInvalidOperation("%s: Can't copy %s data to %s data.",
|
||||
funcName,
|
||||
(readType == WebGLBuffer::Kind::OtherData) ? "other"
|
||||
@ -130,14 +84,8 @@ WebGL2Context::CopyBufferSubData(GLenum readTarget, GLenum writeTarget,
|
||||
return;
|
||||
}
|
||||
|
||||
WebGLContextUnchecked::CopyBufferSubData(readTarget, writeTarget, readOffset,
|
||||
writeOffset, size);
|
||||
|
||||
if (writeType == WebGLBuffer::Kind::Undefined) {
|
||||
writeBuffer->BindTo(
|
||||
(readType == WebGLBuffer::Kind::OtherData) ? LOCAL_GL_ARRAY_BUFFER
|
||||
: LOCAL_GL_ELEMENT_ARRAY_BUFFER);
|
||||
}
|
||||
gl->MakeCurrent();
|
||||
gl->fCopyBufferSubData(readTarget, writeTarget, readOffset, writeOffset, size);
|
||||
}
|
||||
|
||||
void
|
||||
@ -148,88 +96,59 @@ WebGL2Context::GetBufferSubData(GLenum target, GLintptr offset,
|
||||
if (IsContextLost())
|
||||
return;
|
||||
|
||||
// For the WebGLBuffer bound to the passed target, read
|
||||
// returnedData.byteLength bytes from the buffer starting at byte
|
||||
// offset offset and write them to returnedData.
|
||||
|
||||
// If zero is bound to target, an INVALID_OPERATION error is
|
||||
// generated.
|
||||
if (!ValidateBufferTarget(target, funcName))
|
||||
if (!ValidateNonNegative(funcName, "offset", offset))
|
||||
return;
|
||||
|
||||
// If offset is less than zero, an INVALID_VALUE error is
|
||||
// generated.
|
||||
if (offset < 0) {
|
||||
ErrorInvalidValue("%s: Offset must be non-negative.", funcName);
|
||||
const auto& buffer = ValidateBufferSelection(funcName, target);
|
||||
if (!buffer)
|
||||
return;
|
||||
}
|
||||
|
||||
WebGLRefPtr<WebGLBuffer>& bufferSlot = GetBufferSlotByTarget(target);
|
||||
WebGLBuffer* boundBuffer = bufferSlot.get();
|
||||
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.
|
||||
data.ComputeLengthAndData();
|
||||
|
||||
CheckedInt<WebGLsizeiptr> neededByteLength = CheckedInt<WebGLsizeiptr>(offset) + data.LengthAllowShared();
|
||||
const auto neededByteLength = CheckedInt<size_t>(offset) + data.LengthAllowShared();
|
||||
if (!neededByteLength.isValid()) {
|
||||
ErrorInvalidValue("%s: Integer overflow computing the needed byte length.",
|
||||
funcName);
|
||||
return;
|
||||
}
|
||||
|
||||
if (neededByteLength.value() > boundBuffer->ByteLength()) {
|
||||
if (neededByteLength.value() > buffer->ByteLength()) {
|
||||
ErrorInvalidValue("%s: Not enough data. Operation requires %d bytes, but buffer"
|
||||
" only has %d bytes.",
|
||||
funcName, neededByteLength.value(), boundBuffer->ByteLength());
|
||||
funcName, neededByteLength.value(), buffer->ByteLength());
|
||||
return;
|
||||
}
|
||||
|
||||
// If target is TRANSFORM_FEEDBACK_BUFFER, and any transform
|
||||
// feedback object is currently active, an INVALID_OPERATION error
|
||||
// is generated.
|
||||
WebGLTransformFeedback* currentTF = mBoundTransformFeedback;
|
||||
if (target == LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER && currentTF) {
|
||||
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
|
||||
// bound for transform feedback causes undefined results in
|
||||
// GLES3.0 and OpenGL 4.5. In practice results of reads and
|
||||
// writes might be consistent as long as transform feedback
|
||||
// objects are not active, but neither GLES3.0 nor OpenGL 4.5
|
||||
// spec guarantees this - just being bound for transform
|
||||
// feedback is sufficient to cause undefined results.
|
||||
|
||||
BindTransformFeedback(LOCAL_GL_TRANSFORM_FEEDBACK, nullptr);
|
||||
if (buffer->mNumActiveTFOs) {
|
||||
ErrorInvalidOperation("%s: Buffer is bound to an active transform feedback"
|
||||
" object.",
|
||||
funcName);
|
||||
return;
|
||||
}
|
||||
|
||||
/* If the buffer is written and read sequentially by other
|
||||
* operations and getBufferSubData, it is the responsibility of
|
||||
* the WebGL API to ensure that data are access
|
||||
* consistently. This applies even if the buffer is currently
|
||||
* bound to a transform feedback binding point.
|
||||
*/
|
||||
|
||||
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 &&
|
||||
mBoundTransformFeedback->mIsActive)
|
||||
{
|
||||
ErrorInvalidOperation("%s: Currently bound transform feedback is active.",
|
||||
funcName);
|
||||
return;
|
||||
}
|
||||
|
||||
////
|
||||
|
||||
if (target == LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER && currentTF) {
|
||||
BindTransformFeedback(LOCAL_GL_TRANSFORM_FEEDBACK, currentTF);
|
||||
}
|
||||
gl->MakeCurrent();
|
||||
|
||||
const auto 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);
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -13,71 +13,6 @@
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
static bool
|
||||
GetFBInfoForBlit(const WebGLFramebuffer* fb, const char* const fbInfo,
|
||||
GLsizei* const out_samples,
|
||||
const webgl::FormatInfo** const out_colorFormat,
|
||||
const webgl::FormatInfo** const out_depthFormat,
|
||||
const webgl::FormatInfo** const out_stencilFormat)
|
||||
{
|
||||
*out_samples = 0;
|
||||
*out_colorFormat = nullptr;
|
||||
*out_depthFormat = nullptr;
|
||||
*out_stencilFormat = nullptr;
|
||||
|
||||
if (fb->ColorAttachment(0).IsDefined()) {
|
||||
const auto& attachment = fb->ColorAttachment(0);
|
||||
*out_samples = attachment.Samples();
|
||||
*out_colorFormat = attachment.Format()->format;
|
||||
}
|
||||
|
||||
if (fb->DepthStencilAttachment().IsDefined()) {
|
||||
const auto& attachment = fb->DepthStencilAttachment();
|
||||
*out_samples = attachment.Samples();
|
||||
|
||||
*out_depthFormat = attachment.Format()->format;
|
||||
*out_stencilFormat = *out_depthFormat;
|
||||
} else {
|
||||
if (fb->DepthAttachment().IsDefined()) {
|
||||
const auto& attachment = fb->DepthAttachment();
|
||||
*out_samples = attachment.Samples();
|
||||
*out_depthFormat = attachment.Format()->format;
|
||||
}
|
||||
|
||||
if (fb->StencilAttachment().IsDefined()) {
|
||||
const auto& attachment = fb->StencilAttachment();
|
||||
*out_samples = attachment.Samples();
|
||||
*out_stencilFormat = attachment.Format()->format;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
GetBackbufferFormats(const WebGLContextOptions& options,
|
||||
const webgl::FormatInfo** const out_color,
|
||||
const webgl::FormatInfo** const out_depth,
|
||||
const webgl::FormatInfo** const out_stencil)
|
||||
{
|
||||
const auto effFormat = options.alpha ? webgl::EffectiveFormat::RGBA8
|
||||
: webgl::EffectiveFormat::RGB8;
|
||||
*out_color = webgl::GetFormat(effFormat);
|
||||
|
||||
*out_depth = nullptr;
|
||||
*out_stencil = nullptr;
|
||||
if (options.depth && options.stencil) {
|
||||
*out_depth = webgl::GetFormat(webgl::EffectiveFormat::DEPTH24_STENCIL8);
|
||||
*out_stencil = *out_depth;
|
||||
} else {
|
||||
if (options.depth) {
|
||||
*out_depth = webgl::GetFormat(webgl::EffectiveFormat::DEPTH_COMPONENT16);
|
||||
}
|
||||
if (options.stencil) {
|
||||
*out_stencil = webgl::GetFormat(webgl::EffectiveFormat::STENCIL_INDEX8);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
WebGL2Context::BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
|
||||
GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
|
||||
@ -103,238 +38,41 @@ WebGL2Context::BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY
|
||||
return;
|
||||
}
|
||||
|
||||
const GLbitfield depthAndStencilBits = LOCAL_GL_DEPTH_BUFFER_BIT |
|
||||
LOCAL_GL_STENCIL_BUFFER_BIT;
|
||||
if (mask & depthAndStencilBits &&
|
||||
filter != LOCAL_GL_NEAREST)
|
||||
////
|
||||
|
||||
const auto& readFB = mBoundReadFramebuffer;
|
||||
if (readFB &&
|
||||
!readFB->ValidateAndInitAttachments("blitFramebuffer's READ_FRAMEBUFFER"))
|
||||
{
|
||||
ErrorInvalidOperation("blitFramebuffer: DEPTH_BUFFER_BIT and"
|
||||
" STENCIL_BUFFER_BIT can only be used with"
|
||||
" NEAREST filtering.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (mBoundReadFramebuffer == mBoundDrawFramebuffer) {
|
||||
// TODO: It's actually more complicated than this. We need to check that
|
||||
// the underlying buffers are not the same, not the framebuffers
|
||||
// themselves.
|
||||
ErrorInvalidOperation("blitFramebuffer: Source and destination must"
|
||||
" differ.");
|
||||
return;
|
||||
}
|
||||
|
||||
GLsizei srcSamples;
|
||||
const webgl::FormatInfo* srcColorFormat = nullptr;
|
||||
const webgl::FormatInfo* srcDepthFormat = nullptr;
|
||||
const webgl::FormatInfo* srcStencilFormat = nullptr;
|
||||
|
||||
if (mBoundReadFramebuffer) {
|
||||
if (!mBoundReadFramebuffer->ValidateAndInitAttachments("blitFramebuffer's READ_FRAMEBUFFER"))
|
||||
return;
|
||||
|
||||
if (!GetFBInfoForBlit(mBoundReadFramebuffer, "READ_FRAMEBUFFER", &srcSamples,
|
||||
&srcColorFormat, &srcDepthFormat, &srcStencilFormat))
|
||||
{
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
srcSamples = 0; // Always 0.
|
||||
|
||||
GetBackbufferFormats(mOptions, &srcColorFormat, &srcDepthFormat,
|
||||
&srcStencilFormat);
|
||||
}
|
||||
|
||||
GLsizei dstSamples;
|
||||
const webgl::FormatInfo* dstColorFormat = nullptr;
|
||||
const webgl::FormatInfo* dstDepthFormat = nullptr;
|
||||
const webgl::FormatInfo* dstStencilFormat = nullptr;
|
||||
|
||||
if (mBoundDrawFramebuffer) {
|
||||
if (!mBoundDrawFramebuffer->ValidateAndInitAttachments("blitFramebuffer's DRAW_FRAMEBUFFER"))
|
||||
return;
|
||||
|
||||
if (!GetFBInfoForBlit(mBoundDrawFramebuffer, "DRAW_FRAMEBUFFER", &dstSamples,
|
||||
&dstColorFormat, &dstDepthFormat, &dstStencilFormat))
|
||||
{
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
dstSamples = gl->Screen()->Samples();
|
||||
|
||||
GetBackbufferFormats(mOptions, &dstColorFormat, &dstDepthFormat,
|
||||
&dstStencilFormat);
|
||||
}
|
||||
|
||||
if (mask & LOCAL_GL_COLOR_BUFFER_BIT) {
|
||||
const auto fnSignlessType = [](const webgl::FormatInfo* format)
|
||||
-> webgl::ComponentType
|
||||
{
|
||||
if (!format)
|
||||
return webgl::ComponentType::None;
|
||||
|
||||
switch (format->componentType) {
|
||||
case webgl::ComponentType::UInt:
|
||||
return webgl::ComponentType::Int;
|
||||
|
||||
case webgl::ComponentType::NormUInt:
|
||||
return webgl::ComponentType::NormInt;
|
||||
|
||||
default:
|
||||
return format->componentType;
|
||||
}
|
||||
};
|
||||
|
||||
const auto srcType = fnSignlessType(srcColorFormat);
|
||||
const auto dstType = fnSignlessType(dstColorFormat);
|
||||
|
||||
if (srcType != dstType) {
|
||||
ErrorInvalidOperation("blitFramebuffer: Color buffer format component type"
|
||||
" mismatch.");
|
||||
return;
|
||||
}
|
||||
|
||||
const bool srcIsInt = (srcType == webgl::ComponentType::Int);
|
||||
if (srcIsInt && filter != LOCAL_GL_NEAREST) {
|
||||
ErrorInvalidOperation("blitFramebuffer: Integer read buffers can only"
|
||||
" be filtered with NEAREST.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* GLES 3.0.4, p199:
|
||||
* Calling BlitFramebuffer will result in an INVALID_OPERATION error if
|
||||
* mask includes DEPTH_BUFFER_BIT or STENCIL_BUFFER_BIT, and the source
|
||||
* and destination depth and stencil buffer formats do not match.
|
||||
*
|
||||
* jgilbert: The wording is such that if only DEPTH_BUFFER_BIT is specified,
|
||||
* the stencil formats must match. This seems wrong. It could be a spec bug,
|
||||
* or I could be missing an interaction in one of the earlier paragraphs.
|
||||
*/
|
||||
if (mask & LOCAL_GL_DEPTH_BUFFER_BIT &&
|
||||
dstDepthFormat != srcDepthFormat)
|
||||
const auto& drawFB = mBoundDrawFramebuffer;
|
||||
if (drawFB &&
|
||||
!drawFB->ValidateAndInitAttachments("blitFramebuffer's DRAW_FRAMEBUFFER"))
|
||||
{
|
||||
ErrorInvalidOperation("blitFramebuffer: Depth buffer formats must match"
|
||||
" if selected.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (mask & LOCAL_GL_STENCIL_BUFFER_BIT &&
|
||||
dstStencilFormat != srcStencilFormat)
|
||||
{
|
||||
ErrorInvalidOperation("blitFramebuffer: Stencil buffer formats must"
|
||||
" match if selected.");
|
||||
return;
|
||||
}
|
||||
////
|
||||
|
||||
if (dstSamples != 0) {
|
||||
ErrorInvalidOperation("blitFramebuffer: DRAW_FRAMEBUFFER may not have"
|
||||
" multiple samples.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (srcSamples != 0) {
|
||||
if (mask & LOCAL_GL_COLOR_BUFFER_BIT &&
|
||||
dstColorFormat != srcColorFormat)
|
||||
{
|
||||
ErrorInvalidOperation("blitFramebuffer: Color buffer formats must"
|
||||
" match if selected, when reading from a"
|
||||
" multisampled source.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (dstX0 != srcX0 ||
|
||||
dstX1 != srcX1 ||
|
||||
dstY0 != srcY0 ||
|
||||
dstY1 != srcY1)
|
||||
{
|
||||
ErrorInvalidOperation("blitFramebuffer: If the source is"
|
||||
" multisampled, then the source and dest"
|
||||
" regions must match exactly.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
MakeContextCurrent();
|
||||
gl->fBlitFramebuffer(srcX0, srcY0, srcX1, srcY1,
|
||||
dstX0, dstY0, dstX1, dstY1,
|
||||
mask, filter);
|
||||
}
|
||||
|
||||
static bool
|
||||
ValidateTextureLayerAttachment(GLenum attachment)
|
||||
{
|
||||
if (LOCAL_GL_COLOR_ATTACHMENT0 <= attachment &&
|
||||
attachment <= LOCAL_GL_COLOR_ATTACHMENT15)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
switch (attachment) {
|
||||
case LOCAL_GL_DEPTH_ATTACHMENT:
|
||||
case LOCAL_GL_DEPTH_STENCIL_ATTACHMENT:
|
||||
case LOCAL_GL_STENCIL_ATTACHMENT:
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
WebGLFramebuffer::BlitFramebuffer(this,
|
||||
readFB, srcX0, srcY0, srcX1, srcY1,
|
||||
drawFB, dstX0, dstY0, dstX1, dstY1,
|
||||
mask, filter);
|
||||
}
|
||||
|
||||
void
|
||||
WebGL2Context::FramebufferTextureLayer(GLenum target, GLenum attachment,
|
||||
WebGLTexture* texture, GLint level, GLint layer)
|
||||
{
|
||||
const char funcName[] = "framebufferTextureLayer";
|
||||
if (IsContextLost())
|
||||
return;
|
||||
|
||||
if (!ValidateFramebufferTarget(target, "framebufferTextureLayer"))
|
||||
if (!ValidateFramebufferTarget(target, funcName))
|
||||
return;
|
||||
|
||||
if (!ValidateTextureLayerAttachment(attachment))
|
||||
return ErrorInvalidEnumInfo("framebufferTextureLayer: attachment:", attachment);
|
||||
|
||||
if (texture) {
|
||||
if (texture->IsDeleted()) {
|
||||
return ErrorInvalidValue("framebufferTextureLayer: texture must be a valid "
|
||||
"texture object.");
|
||||
}
|
||||
|
||||
if (layer < 0)
|
||||
return ErrorInvalidValue("framebufferTextureLayer: layer must be >= 0.");
|
||||
|
||||
if (level < 0)
|
||||
return ErrorInvalidValue("framebufferTextureLayer: level must be >= 0.");
|
||||
|
||||
switch (texture->Target().get()) {
|
||||
case LOCAL_GL_TEXTURE_3D:
|
||||
if (uint32_t(layer) >= mImplMax3DTextureSize) {
|
||||
return ErrorInvalidValue("framebufferTextureLayer: layer must be < "
|
||||
"MAX_3D_TEXTURE_SIZE");
|
||||
}
|
||||
|
||||
if (uint32_t(level) > FloorLog2(mImplMax3DTextureSize)) {
|
||||
return ErrorInvalidValue("framebufferTextureLayer: layer mube be <= "
|
||||
"log2(MAX_3D_TEXTURE_SIZE");
|
||||
}
|
||||
break;
|
||||
|
||||
case LOCAL_GL_TEXTURE_2D_ARRAY:
|
||||
if (uint32_t(layer) >= mImplMaxArrayTextureLayers) {
|
||||
return ErrorInvalidValue("framebufferTextureLayer: layer must be < "
|
||||
"MAX_ARRAY_TEXTURE_LAYERS");
|
||||
}
|
||||
|
||||
if (uint32_t(level) > FloorLog2(mImplMaxTextureSize)) {
|
||||
return ErrorInvalidValue("framebufferTextureLayer: layer mube be <= "
|
||||
"log2(MAX_TEXTURE_SIZE");
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return ErrorInvalidOperation("framebufferTextureLayer: texture must be an "
|
||||
"existing 3D texture, or a 2D texture array.");
|
||||
}
|
||||
}
|
||||
|
||||
WebGLFramebuffer* fb;
|
||||
switch (target) {
|
||||
case LOCAL_GL_FRAMEBUFFER:
|
||||
@ -350,12 +88,10 @@ WebGL2Context::FramebufferTextureLayer(GLenum target, GLenum attachment,
|
||||
MOZ_CRASH("GFX: Bad target.");
|
||||
}
|
||||
|
||||
if (!fb) {
|
||||
return ErrorInvalidOperation("framebufferTextureLayer: cannot modify"
|
||||
" framebuffer 0.");
|
||||
}
|
||||
if (!fb)
|
||||
return ErrorInvalidOperation("%a: Xannot modify framebuffer 0.");
|
||||
|
||||
fb->FramebufferTextureLayer(attachment, texture, level, layer);
|
||||
fb->FramebufferTextureLayer(funcName, attachment, texture, level, layer);
|
||||
}
|
||||
|
||||
JS::Value
|
||||
@ -532,32 +268,12 @@ WebGL2Context::InvalidateSubFramebuffer(GLenum target, const dom::Sequence<GLenu
|
||||
void
|
||||
WebGL2Context::ReadBuffer(GLenum mode)
|
||||
{
|
||||
const char funcName[] = "readBuffer";
|
||||
if (IsContextLost())
|
||||
return;
|
||||
|
||||
const bool isColorAttachment = (mode >= LOCAL_GL_COLOR_ATTACHMENT0 &&
|
||||
mode <= LastColorAttachmentEnum());
|
||||
|
||||
if (mode != LOCAL_GL_NONE && mode != LOCAL_GL_BACK && !isColorAttachment) {
|
||||
ErrorInvalidEnum("readBuffer: `mode` must be one of NONE, BACK, or "
|
||||
"COLOR_ATTACHMENTi. Was %s",
|
||||
EnumName(mode));
|
||||
return;
|
||||
}
|
||||
|
||||
if (mBoundReadFramebuffer) {
|
||||
if (mode != LOCAL_GL_NONE &&
|
||||
!isColorAttachment)
|
||||
{
|
||||
ErrorInvalidOperation("readBuffer: If READ_FRAMEBUFFER is non-null, `mode` "
|
||||
"must be COLOR_ATTACHMENTi or NONE. Was %s",
|
||||
EnumName(mode));
|
||||
return;
|
||||
}
|
||||
|
||||
MakeContextCurrent();
|
||||
mBoundReadFramebuffer->SetReadBufferMode(mode);
|
||||
gl->fReadBuffer(mode);
|
||||
mBoundReadFramebuffer->ReadBuffer(funcName, mode);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -565,9 +281,9 @@ WebGL2Context::ReadBuffer(GLenum mode)
|
||||
if (mode != LOCAL_GL_NONE &&
|
||||
mode != LOCAL_GL_BACK)
|
||||
{
|
||||
ErrorInvalidOperation("readBuffer: If READ_FRAMEBUFFER is null, `mode`"
|
||||
" must be BACK or NONE. Was %s",
|
||||
EnumName(mode));
|
||||
ErrorInvalidOperation("%s: If READ_FRAMEBUFFER is null, `mode` must be BACK or"
|
||||
" NONE. Was %s",
|
||||
funcName, EnumName(mode));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -33,20 +33,26 @@ WebGL2Context::GetParameter(JSContext* cx, GLenum pname, ErrorResult& rv)
|
||||
/* GLboolean */
|
||||
case LOCAL_GL_RASTERIZER_DISCARD:
|
||||
case LOCAL_GL_SAMPLE_ALPHA_TO_COVERAGE:
|
||||
case LOCAL_GL_SAMPLE_COVERAGE:
|
||||
case LOCAL_GL_TRANSFORM_FEEDBACK_PAUSED:
|
||||
case LOCAL_GL_TRANSFORM_FEEDBACK_ACTIVE: {
|
||||
case LOCAL_GL_SAMPLE_COVERAGE: {
|
||||
realGLboolean b = 0;
|
||||
gl->fGetBooleanv(pname, &b);
|
||||
return JS::BooleanValue(bool(b));
|
||||
}
|
||||
|
||||
case LOCAL_GL_TRANSFORM_FEEDBACK_ACTIVE:
|
||||
return JS::BooleanValue(mBoundTransformFeedback->mIsActive);
|
||||
case LOCAL_GL_TRANSFORM_FEEDBACK_PAUSED:
|
||||
return JS::BooleanValue(mBoundTransformFeedback->mIsPaused);
|
||||
|
||||
/* GLenum */
|
||||
case LOCAL_GL_READ_BUFFER: {
|
||||
if (mBoundReadFramebuffer)
|
||||
return JS::Int32Value(mBoundReadFramebuffer->ReadBufferMode());
|
||||
if (!mBoundReadFramebuffer)
|
||||
return JS::Int32Value(gl->Screen()->GetReadBufferMode());
|
||||
|
||||
return JS::Int32Value(LOCAL_GL_BACK);
|
||||
if (!mBoundReadFramebuffer->ColorReadBuffer())
|
||||
return JS::Int32Value(LOCAL_GL_NONE);
|
||||
|
||||
return JS::Int32Value(mBoundReadFramebuffer->ColorReadBuffer()->mAttachmentPoint);
|
||||
}
|
||||
|
||||
case LOCAL_GL_FRAGMENT_SHADER_DERIVATIVE_HINT:
|
||||
@ -146,7 +152,10 @@ WebGL2Context::GetParameter(JSContext* cx, GLenum pname, ErrorResult& rv)
|
||||
return WebGLObjectAsJSValue(cx, mBoundPixelUnpackBuffer.get(), rv);
|
||||
|
||||
case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER_BINDING:
|
||||
return WebGLObjectAsJSValue(cx, mBoundTransformFeedbackBuffer.get(), rv);
|
||||
{
|
||||
const auto& tf = mBoundTransformFeedback;
|
||||
return WebGLObjectAsJSValue(cx, tf->mGenericBufferBinding.get(), rv);
|
||||
}
|
||||
|
||||
case LOCAL_GL_UNIFORM_BUFFER_BINDING:
|
||||
return WebGLObjectAsJSValue(cx, mBoundUniformBuffer.get(), rv);
|
||||
@ -164,11 +173,14 @@ WebGL2Context::GetParameter(JSContext* cx, GLenum pname, ErrorResult& rv)
|
||||
case LOCAL_GL_TEXTURE_BINDING_3D:
|
||||
return WebGLObjectAsJSValue(cx, mBound3DTextures[mActiveTexture].get(), rv);
|
||||
|
||||
case LOCAL_GL_TRANSFORM_FEEDBACK_BINDING: {
|
||||
WebGLTransformFeedback* tf =
|
||||
(mBoundTransformFeedback != mDefaultTransformFeedback) ? mBoundTransformFeedback.get() : nullptr;
|
||||
return WebGLObjectAsJSValue(cx, tf, rv);
|
||||
}
|
||||
case LOCAL_GL_TRANSFORM_FEEDBACK_BINDING:
|
||||
{
|
||||
const WebGLTransformFeedback* tf = mBoundTransformFeedback;
|
||||
if (tf == mDefaultTransformFeedback) {
|
||||
tf = nullptr;
|
||||
}
|
||||
return WebGLObjectAsJSValue(cx, tf, rv);
|
||||
}
|
||||
|
||||
case LOCAL_GL_VERTEX_ARRAY_BINDING: {
|
||||
WebGLVertexArray* vao =
|
||||
|
@ -20,28 +20,32 @@ WebGL2Context::CreateTransformFeedback()
|
||||
if (IsContextLost())
|
||||
return nullptr;
|
||||
|
||||
GLuint tf = 0;
|
||||
MakeContextCurrent();
|
||||
GLuint tf = 0;
|
||||
gl->fGenTransformFeedbacks(1, &tf);
|
||||
|
||||
RefPtr<WebGLTransformFeedback> globj = new WebGLTransformFeedback(this, tf);
|
||||
return globj.forget();
|
||||
RefPtr<WebGLTransformFeedback> ret = new WebGLTransformFeedback(this, tf);
|
||||
return ret.forget();
|
||||
}
|
||||
|
||||
void
|
||||
WebGL2Context::DeleteTransformFeedback(WebGLTransformFeedback* tf)
|
||||
{
|
||||
const char funcName[] = "deleteTransformFeedback";
|
||||
if (IsContextLost())
|
||||
return;
|
||||
|
||||
if (!ValidateObjectAllowDeletedOrNull("deleteTransformFeedback", tf))
|
||||
if (!ValidateObject(funcName, tf))
|
||||
return;
|
||||
|
||||
if (!tf || tf->IsDeleted())
|
||||
if (tf->mIsActive) {
|
||||
ErrorInvalidOperation("%s: Cannot delete active transform feedbacks.", funcName);
|
||||
return;
|
||||
}
|
||||
|
||||
if (mBoundTransformFeedback == tf)
|
||||
if (mBoundTransformFeedback == tf) {
|
||||
BindTransformFeedback(LOCAL_GL_TRANSFORM_FEEDBACK, nullptr);
|
||||
}
|
||||
|
||||
tf->RequestDelete();
|
||||
}
|
||||
@ -65,67 +69,43 @@ WebGL2Context::IsTransformFeedback(WebGLTransformFeedback* tf)
|
||||
void
|
||||
WebGL2Context::BindTransformFeedback(GLenum target, WebGLTransformFeedback* tf)
|
||||
{
|
||||
const char funcName[] = "bindTransformFeedback";
|
||||
if (IsContextLost())
|
||||
return;
|
||||
|
||||
if (!ValidateObjectAllowDeletedOrNull("bindTransformFeedback", tf))
|
||||
if (target != LOCAL_GL_TRANSFORM_FEEDBACK)
|
||||
return ErrorInvalidEnum("%s: `target` must be TRANSFORM_FEEDBACK.", funcName);
|
||||
|
||||
if (!ValidateObjectAllowDeletedOrNull(funcName, tf))
|
||||
return;
|
||||
|
||||
if (target != LOCAL_GL_TRANSFORM_FEEDBACK)
|
||||
return ErrorInvalidEnum("bindTransformFeedback: target must be TRANSFORM_FEEDBACK");
|
||||
if (tf && tf->IsDeleted())
|
||||
return ErrorInvalidOperation("%s: TFO already deleted.", funcName);
|
||||
|
||||
WebGLRefPtr<WebGLTransformFeedback> currentTF = mBoundTransformFeedback;
|
||||
if (currentTF && currentTF->mIsActive && !currentTF->mIsPaused) {
|
||||
return ErrorInvalidOperation("bindTransformFeedback: Currently bound transform "
|
||||
"feedback is active and not paused");
|
||||
if (mBoundTransformFeedback->mIsActive &&
|
||||
!mBoundTransformFeedback->mIsPaused)
|
||||
{
|
||||
ErrorInvalidOperation("%s: Currently bound transform feedback is active and not"
|
||||
" paused.",
|
||||
funcName);
|
||||
return;
|
||||
}
|
||||
|
||||
if (tf && tf->IsDeleted())
|
||||
return ErrorInvalidOperation("bindTransformFeedback: Attempt to bind deleted id");
|
||||
////
|
||||
|
||||
mBoundTransformFeedback = (tf ? tf : mDefaultTransformFeedback);
|
||||
|
||||
MakeContextCurrent();
|
||||
gl->fBindTransformFeedback(target, tf ? tf->mGLName : 0);
|
||||
if (tf)
|
||||
mBoundTransformFeedback = tf;
|
||||
else
|
||||
mBoundTransformFeedback = mDefaultTransformFeedback;
|
||||
gl->fBindTransformFeedback(target, mBoundTransformFeedback->mGLName);
|
||||
}
|
||||
|
||||
void
|
||||
WebGL2Context::BeginTransformFeedback(GLenum primitiveMode)
|
||||
WebGL2Context::BeginTransformFeedback(GLenum primMode)
|
||||
{
|
||||
if (IsContextLost())
|
||||
return;
|
||||
|
||||
WebGLTransformFeedback* tf = mBoundTransformFeedback;
|
||||
MOZ_ASSERT(tf);
|
||||
if (!tf)
|
||||
return;
|
||||
|
||||
if (tf->mIsActive)
|
||||
return ErrorInvalidOperation("beginTransformFeedback: transform feedback is active");
|
||||
|
||||
const GLenum mode = tf->mMode;
|
||||
if (mode != LOCAL_GL_POINTS && mode != LOCAL_GL_LINES && mode != LOCAL_GL_TRIANGLES)
|
||||
return ErrorInvalidEnum("beginTransformFeedback: primitive must be one of POINTS, LINES, or TRIANGLES");
|
||||
|
||||
// TODO:
|
||||
// GL_INVALID_OPERATION is generated by glBeginTransformFeedback
|
||||
// if any binding point used in transform feedback mode does not
|
||||
// have a buffer object bound. In interleaved mode, only the first
|
||||
// buffer object binding point is ever written to.
|
||||
|
||||
// GL_INVALID_OPERATION is generated by glBeginTransformFeedback
|
||||
// if no binding points would be used, either because no program
|
||||
// object is active of because the active program object has
|
||||
// specified no varying variables to record.
|
||||
if (!mCurrentProgram)
|
||||
return ErrorInvalidOperation("beginTransformFeedback: no program is active");
|
||||
|
||||
MakeContextCurrent();
|
||||
gl->fBeginTransformFeedback(primitiveMode);
|
||||
tf->mIsActive = true;
|
||||
tf->mIsPaused = false;
|
||||
mBoundTransformFeedback->BeginTransformFeedback(primMode);
|
||||
}
|
||||
|
||||
void
|
||||
@ -134,20 +114,7 @@ WebGL2Context::EndTransformFeedback()
|
||||
if (IsContextLost())
|
||||
return;
|
||||
|
||||
WebGLTransformFeedback* tf = mBoundTransformFeedback;
|
||||
MOZ_ASSERT(tf);
|
||||
|
||||
if (!tf)
|
||||
return;
|
||||
|
||||
if (!tf->mIsActive)
|
||||
return ErrorInvalidOperation("%s: transform feedback in not active",
|
||||
"endTransformFeedback");
|
||||
|
||||
MakeContextCurrent();
|
||||
gl->fEndTransformFeedback();
|
||||
tf->mIsActive = false;
|
||||
tf->mIsPaused = false;
|
||||
mBoundTransformFeedback->EndTransformFeedback();
|
||||
}
|
||||
|
||||
void
|
||||
@ -156,19 +123,7 @@ WebGL2Context::PauseTransformFeedback()
|
||||
if (IsContextLost())
|
||||
return;
|
||||
|
||||
WebGLTransformFeedback* tf = mBoundTransformFeedback;
|
||||
MOZ_ASSERT(tf);
|
||||
if (!tf)
|
||||
return;
|
||||
|
||||
if (!tf->mIsActive || tf->mIsPaused) {
|
||||
return ErrorInvalidOperation("%s: transform feedback is not active or is paused",
|
||||
"pauseTransformFeedback");
|
||||
}
|
||||
|
||||
MakeContextCurrent();
|
||||
gl->fPauseTransformFeedback();
|
||||
tf->mIsPaused = true;
|
||||
mBoundTransformFeedback->PauseTransformFeedback();
|
||||
}
|
||||
|
||||
void
|
||||
@ -177,17 +132,7 @@ WebGL2Context::ResumeTransformFeedback()
|
||||
if (IsContextLost())
|
||||
return;
|
||||
|
||||
WebGLTransformFeedback* tf = mBoundTransformFeedback;
|
||||
MOZ_ASSERT(tf);
|
||||
if (!tf)
|
||||
return;
|
||||
|
||||
if (!tf->mIsActive || !tf->mIsPaused)
|
||||
return ErrorInvalidOperation("resumeTransformFeedback: transform feedback is not active or is not paused");
|
||||
|
||||
MakeContextCurrent();
|
||||
gl->fResumeTransformFeedback();
|
||||
tf->mIsPaused = false;
|
||||
mBoundTransformFeedback->ResumeTransformFeedback();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -70,57 +70,60 @@ WebGL2Context::Uniform4ui(WebGLUniformLocation* loc, GLuint v0, GLuint v1, GLuin
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Uniform Buffer Objects and Transform Feedback Buffers
|
||||
// TODO(djg): Implemented in WebGLContext
|
||||
/*
|
||||
void BindBufferBase(GLenum target, GLuint index, WebGLBuffer* buffer);
|
||||
void BindBufferRange(GLenum target, GLuint index, WebGLBuffer* buffer,
|
||||
GLintptr offset, GLsizeiptr size);
|
||||
*/
|
||||
|
||||
/* This doesn't belong here. It's part of state querying */
|
||||
void
|
||||
WebGL2Context::GetIndexedParameter(GLenum target, GLuint index,
|
||||
dom::Nullable<dom::OwningWebGLBufferOrLongLong>& retval)
|
||||
{
|
||||
const char funcName[] = "getIndexedParameter";
|
||||
retval.SetNull();
|
||||
if (IsContextLost())
|
||||
return;
|
||||
|
||||
GLint64 data = 0;
|
||||
|
||||
MakeContextCurrent();
|
||||
|
||||
const std::vector<IndexedBufferBinding>* bindings;
|
||||
switch (target) {
|
||||
case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER_BINDING:
|
||||
if (index >= mGLMaxTransformFeedbackSeparateAttribs)
|
||||
return ErrorInvalidValue("getIndexedParameter: index should be less than "
|
||||
"MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS");
|
||||
|
||||
if (mBoundTransformFeedbackBuffers[index].get()) {
|
||||
retval.SetValue().SetAsWebGLBuffer() =
|
||||
mBoundTransformFeedbackBuffers[index].get();
|
||||
}
|
||||
return;
|
||||
|
||||
case LOCAL_GL_UNIFORM_BUFFER_BINDING:
|
||||
if (index >= mGLMaxUniformBufferBindings)
|
||||
return ErrorInvalidValue("getIndexedParameter: index should be than "
|
||||
"MAX_UNIFORM_BUFFER_BINDINGS");
|
||||
|
||||
if (mBoundUniformBuffers[index].get())
|
||||
retval.SetValue().SetAsWebGLBuffer() = mBoundUniformBuffers[index].get();
|
||||
return;
|
||||
|
||||
case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER_START:
|
||||
case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER_SIZE:
|
||||
bindings = &(mBoundTransformFeedback->mIndexedBindings);
|
||||
break;
|
||||
|
||||
case LOCAL_GL_UNIFORM_BUFFER_BINDING:
|
||||
case LOCAL_GL_UNIFORM_BUFFER_START:
|
||||
case LOCAL_GL_UNIFORM_BUFFER_SIZE:
|
||||
gl->fGetInteger64i_v(target, index, &data);
|
||||
retval.SetValue().SetAsLongLong() = data;
|
||||
bindings = &mIndexedUniformBufferBindings;
|
||||
break;
|
||||
|
||||
default:
|
||||
ErrorInvalidEnumInfo("getIndexedParameter: target", target);
|
||||
return;
|
||||
}
|
||||
|
||||
ErrorInvalidEnumInfo("getIndexedParameter: target", target);
|
||||
if (index >= bindings->size()) {
|
||||
ErrorInvalidValue("%s: `index` must be < %s.", funcName,
|
||||
"MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS");
|
||||
return;
|
||||
}
|
||||
const auto& binding = (*bindings)[index];
|
||||
|
||||
switch (target) {
|
||||
case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER_BINDING:
|
||||
case LOCAL_GL_UNIFORM_BUFFER_BINDING:
|
||||
if (binding.mBufferBinding) {
|
||||
retval.SetValue().SetAsWebGLBuffer() = binding.mBufferBinding;
|
||||
}
|
||||
break;
|
||||
|
||||
case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER_START:
|
||||
case LOCAL_GL_UNIFORM_BUFFER_START:
|
||||
retval.SetValue().SetAsLongLong() = binding.mRangeStart;
|
||||
break;
|
||||
|
||||
case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER_SIZE:
|
||||
case LOCAL_GL_UNIFORM_BUFFER_SIZE:
|
||||
retval.SetValue().SetAsLongLong() = binding.mRangeSize;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -17,23 +17,30 @@ WebGLBuffer::WebGLBuffer(WebGLContext* webgl, GLuint buf)
|
||||
, mGLName(buf)
|
||||
, mContent(Kind::Undefined)
|
||||
, mByteLength(0)
|
||||
, mNumActiveTFOs(0)
|
||||
, mBoundForTF(false)
|
||||
{
|
||||
mContext->mBuffers.insertBack(this);
|
||||
}
|
||||
|
||||
WebGLBuffer::~WebGLBuffer()
|
||||
{
|
||||
MOZ_ASSERT(!mNumActiveTFOs);
|
||||
DeleteOnce();
|
||||
}
|
||||
|
||||
void
|
||||
WebGLBuffer::BindTo(GLenum target)
|
||||
WebGLBuffer::SetContentAfterBind(GLenum target)
|
||||
{
|
||||
if (mContent != Kind::Undefined)
|
||||
return;
|
||||
|
||||
switch (target) {
|
||||
case LOCAL_GL_ELEMENT_ARRAY_BUFFER:
|
||||
mContent = Kind::ElementArray;
|
||||
if (!mCache)
|
||||
mCache = new WebGLElementArrayCache;
|
||||
if (!mCache) {
|
||||
mCache.reset(new WebGLElementArrayCache);
|
||||
}
|
||||
break;
|
||||
|
||||
case LOCAL_GL_ARRAY_BUFFER:
|
||||
@ -41,14 +48,9 @@ WebGLBuffer::BindTo(GLenum target)
|
||||
case LOCAL_GL_PIXEL_UNPACK_BUFFER:
|
||||
case LOCAL_GL_UNIFORM_BUFFER:
|
||||
case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER:
|
||||
mContent = Kind::OtherData;
|
||||
break;
|
||||
|
||||
case LOCAL_GL_COPY_READ_BUFFER:
|
||||
case LOCAL_GL_COPY_WRITE_BUFFER:
|
||||
if (mContent == Kind::Undefined) {
|
||||
mContent = Kind::OtherData;
|
||||
}
|
||||
mContent = Kind::OtherData;
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -66,6 +68,90 @@ WebGLBuffer::Delete()
|
||||
LinkedListElement<WebGLBuffer>::remove(); // remove from mContext->mBuffers
|
||||
}
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
static bool
|
||||
ValidateBufferUsageEnum(WebGLContext* webgl, const char* funcName, GLenum usage)
|
||||
{
|
||||
switch (usage) {
|
||||
case LOCAL_GL_STREAM_DRAW:
|
||||
case LOCAL_GL_STATIC_DRAW:
|
||||
case LOCAL_GL_DYNAMIC_DRAW:
|
||||
return true;
|
||||
|
||||
case LOCAL_GL_DYNAMIC_COPY:
|
||||
case LOCAL_GL_DYNAMIC_READ:
|
||||
case LOCAL_GL_STATIC_COPY:
|
||||
case LOCAL_GL_STATIC_READ:
|
||||
case LOCAL_GL_STREAM_COPY:
|
||||
case LOCAL_GL_STREAM_READ:
|
||||
if (MOZ_LIKELY(webgl->IsWebGL2()))
|
||||
return true;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
webgl->ErrorInvalidEnum("%s: Invalid `usage`: 0x%04x", funcName, usage);
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
WebGLBuffer::BufferData(GLenum target, size_t size, const void* data, GLenum usage)
|
||||
{
|
||||
const char funcName[] = "bufferData";
|
||||
|
||||
if (!ValidateBufferUsageEnum(mContext, funcName, usage))
|
||||
return;
|
||||
|
||||
if (mNumActiveTFOs) {
|
||||
mContext->ErrorInvalidOperation("%s: Buffer is bound to an active transform"
|
||||
" feedback object.",
|
||||
funcName);
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& gl = mContext->gl;
|
||||
gl->MakeCurrent();
|
||||
mContext->InvalidateBufferFetching();
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
// bug 790879
|
||||
if (gl->WorkAroundDriverBugs() &&
|
||||
size > INT32_MAX)
|
||||
{
|
||||
mContext->ErrorOutOfMemory("%s: Allocation size too large.", funcName);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
const bool sizeChanges = (size != ByteLength());
|
||||
if (sizeChanges) {
|
||||
gl::GLContext::LocalErrorScope errorScope(*gl);
|
||||
gl->fBufferData(target, size, data, usage);
|
||||
const auto error = errorScope.GetError();
|
||||
|
||||
if (error) {
|
||||
MOZ_ASSERT(error == LOCAL_GL_OUT_OF_MEMORY);
|
||||
mContext->ErrorOutOfMemory("%s: Error from driver: 0x%04x", funcName, error);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
gl->fBufferData(target, size, data, usage);
|
||||
}
|
||||
|
||||
mByteLength = size;
|
||||
|
||||
// Warning: Possibly shared memory. See bug 1225033.
|
||||
if (!ElementArrayCacheBufferData(data, size)) {
|
||||
mByteLength = 0;
|
||||
mContext->ErrorOutOfMemory("%s: Failed update index buffer cache.", funcName);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
bool
|
||||
WebGLBuffer::ElementArrayCacheBufferData(const void* ptr,
|
||||
size_t bufferSizeInBytes)
|
||||
@ -93,10 +179,9 @@ WebGLBuffer::SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const
|
||||
}
|
||||
|
||||
bool
|
||||
WebGLBuffer::Validate(GLenum type, uint32_t maxAllowed, size_t first,
|
||||
size_t count, uint32_t* const out_upperBound)
|
||||
WebGLBuffer::Validate(GLenum type, uint32_t maxAllowed, size_t first, size_t count) const
|
||||
{
|
||||
return mCache->Validate(type, maxAllowed, first, count, out_upperBound);
|
||||
return mCache->Validate(type, maxAllowed, first, count);
|
||||
}
|
||||
|
||||
bool
|
||||
@ -105,6 +190,68 @@ WebGLBuffer::IsElementArrayUsedWithMultipleTypes() const
|
||||
return mCache->BeenUsedWithMultipleTypes();
|
||||
}
|
||||
|
||||
bool
|
||||
WebGLBuffer::ValidateCanBindToTarget(const char* funcName, GLenum target)
|
||||
{
|
||||
const bool wouldBeTF = (target == LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER);
|
||||
if (mWebGLRefCnt && wouldBeTF != mBoundForTF) {
|
||||
mContext->ErrorInvalidOperation("%s: Buffers cannot be simultaneously bound to "
|
||||
" transform feedback and bound elsewhere.",
|
||||
funcName);
|
||||
return false;
|
||||
}
|
||||
mBoundForTF = wouldBeTF;
|
||||
|
||||
/* https://www.khronos.org/registry/webgl/specs/latest/2.0/#5.1
|
||||
*
|
||||
* In the WebGL 2 API, buffers have their WebGL buffer type
|
||||
* initially set to undefined. Calling bindBuffer, bindBufferRange
|
||||
* or bindBufferBase with the target argument set to any buffer
|
||||
* binding point except COPY_READ_BUFFER or COPY_WRITE_BUFFER will
|
||||
* then set the WebGL buffer type of the buffer being bound
|
||||
* according to the table above.
|
||||
*
|
||||
* Any call to one of these functions which attempts to bind a
|
||||
* WebGLBuffer that has the element array WebGL buffer type to a
|
||||
* binding point that falls under other data, or bind a
|
||||
* WebGLBuffer which has the other data WebGL buffer type to
|
||||
* ELEMENT_ARRAY_BUFFER will generate an INVALID_OPERATION error,
|
||||
* and the state of the binding point will remain untouched.
|
||||
*/
|
||||
|
||||
if (mContent == WebGLBuffer::Kind::Undefined)
|
||||
return true;
|
||||
|
||||
switch (target) {
|
||||
case LOCAL_GL_COPY_READ_BUFFER:
|
||||
case LOCAL_GL_COPY_WRITE_BUFFER:
|
||||
return true;
|
||||
|
||||
case LOCAL_GL_ELEMENT_ARRAY_BUFFER:
|
||||
if (mContent == WebGLBuffer::Kind::ElementArray)
|
||||
return true;
|
||||
break;
|
||||
|
||||
case LOCAL_GL_ARRAY_BUFFER:
|
||||
case LOCAL_GL_PIXEL_PACK_BUFFER:
|
||||
case LOCAL_GL_PIXEL_UNPACK_BUFFER:
|
||||
case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER:
|
||||
case LOCAL_GL_UNIFORM_BUFFER:
|
||||
if (mContent == WebGLBuffer::Kind::OtherData)
|
||||
return true;
|
||||
break;
|
||||
|
||||
default:
|
||||
MOZ_CRASH();
|
||||
}
|
||||
|
||||
const auto dataType = (mContent == WebGLBuffer::Kind::OtherData) ? "other"
|
||||
: "element";
|
||||
mContext->ErrorInvalidOperation("%s: Buffer already contains %s data.", funcName,
|
||||
dataType);
|
||||
return false;
|
||||
}
|
||||
|
||||
JSObject*
|
||||
WebGLBuffer::WrapObject(JSContext* cx, JS::Handle<JSObject*> givenProto)
|
||||
{
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
#include "GLDefs.h"
|
||||
#include "mozilla/LinkedList.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "nsWrapperCache.h"
|
||||
|
||||
#include "WebGLObjectModel.h"
|
||||
@ -24,8 +24,12 @@ class WebGLBuffer final
|
||||
, public LinkedListElement<WebGLBuffer>
|
||||
, public WebGLContextBoundObject
|
||||
{
|
||||
public:
|
||||
friend class WebGLContext;
|
||||
friend class WebGL2Context;
|
||||
friend class WebGLTexture;
|
||||
friend class WebGLTransformFeedback;
|
||||
|
||||
public:
|
||||
enum class Kind {
|
||||
Undefined,
|
||||
ElementArray,
|
||||
@ -34,23 +38,21 @@ public:
|
||||
|
||||
WebGLBuffer(WebGLContext* webgl, GLuint buf);
|
||||
|
||||
void BindTo(GLenum target);
|
||||
void SetContentAfterBind(GLenum target);
|
||||
Kind Content() const { return mContent; }
|
||||
|
||||
void Delete();
|
||||
|
||||
size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
|
||||
|
||||
WebGLsizeiptr ByteLength() const { return mByteLength; }
|
||||
void SetByteLength(WebGLsizeiptr byteLength) { mByteLength = byteLength; }
|
||||
size_t ByteLength() const { return mByteLength; }
|
||||
|
||||
bool ElementArrayCacheBufferData(const void* ptr, size_t bufferSizeInBytes);
|
||||
|
||||
void ElementArrayCacheBufferSubData(size_t pos, const void* ptr,
|
||||
size_t updateSizeInBytes);
|
||||
|
||||
bool Validate(GLenum type, uint32_t max_allowed, size_t first, size_t count,
|
||||
uint32_t* const out_upperBound);
|
||||
bool Validate(GLenum type, uint32_t max_allowed, size_t first, size_t count) const;
|
||||
|
||||
bool IsElementArrayUsedWithMultipleTypes() const;
|
||||
|
||||
@ -60,6 +62,9 @@ public:
|
||||
|
||||
virtual JSObject* WrapObject(JSContext* cx, JS::Handle<JSObject*> givenProto) override;
|
||||
|
||||
bool ValidateCanBindToTarget(const char* funcName, GLenum target);
|
||||
void BufferData(GLenum target, size_t size, const void* data, GLenum usage);
|
||||
|
||||
const GLenum mGLName;
|
||||
|
||||
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLBuffer)
|
||||
@ -69,8 +74,10 @@ protected:
|
||||
~WebGLBuffer();
|
||||
|
||||
Kind mContent;
|
||||
WebGLsizeiptr mByteLength;
|
||||
nsAutoPtr<WebGLElementArrayCache> mCache;
|
||||
size_t mByteLength;
|
||||
UniquePtr<WebGLElementArrayCache> mCache;
|
||||
size_t mNumActiveTFOs;
|
||||
bool mBoundForTF;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -247,7 +247,6 @@ WebGLContext::DestroyResourcesAndContext()
|
||||
mBoundCopyWriteBuffer = nullptr;
|
||||
mBoundPixelPackBuffer = nullptr;
|
||||
mBoundPixelUnpackBuffer = nullptr;
|
||||
mBoundTransformFeedbackBuffer = nullptr;
|
||||
mBoundUniformBuffer = nullptr;
|
||||
mCurrentProgram = nullptr;
|
||||
mActiveProgramLinkInfo = nullptr;
|
||||
@ -260,8 +259,7 @@ WebGLContext::DestroyResourcesAndContext()
|
||||
mBoundTransformFeedback = nullptr;
|
||||
mDefaultTransformFeedback = nullptr;
|
||||
|
||||
mBoundTransformFeedbackBuffers.Clear();
|
||||
mBoundUniformBuffers.Clear();
|
||||
mIndexedUniformBufferBindings.clear();
|
||||
|
||||
//////
|
||||
|
||||
@ -1637,18 +1635,11 @@ WebGLContext::DummyReadFramebufferOperation(const char* funcName)
|
||||
if (!mBoundReadFramebuffer)
|
||||
return; // Infallible.
|
||||
|
||||
nsCString fbStatusInfo;
|
||||
const auto status = mBoundReadFramebuffer->CheckFramebufferStatus(&fbStatusInfo);
|
||||
const auto status = mBoundReadFramebuffer->CheckFramebufferStatus(funcName);
|
||||
|
||||
if (status != LOCAL_GL_FRAMEBUFFER_COMPLETE) {
|
||||
nsCString errorText("Incomplete framebuffer");
|
||||
|
||||
if (fbStatusInfo.Length()) {
|
||||
errorText += ": ";
|
||||
errorText += fbStatusInfo;
|
||||
}
|
||||
|
||||
ErrorInvalidFramebufferOperation("%s: %s.", funcName, errorText.BeginReading());
|
||||
ErrorInvalidFramebufferOperation("%s: Framebuffer must be complete.",
|
||||
funcName);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1951,8 +1942,18 @@ WebGLContext::GetSurfaceSnapshot(bool* out_premultAlpha)
|
||||
{
|
||||
ScopedBindFramebuffer autoFB(gl, 0);
|
||||
ClearBackbufferIfNeeded();
|
||||
// TODO: Save, override, then restore glReadBuffer if present.
|
||||
|
||||
// Save, override, then restore glReadBuffer.
|
||||
const GLenum readBufferMode = gl->Screen()->GetReadBufferMode();
|
||||
|
||||
if (readBufferMode != LOCAL_GL_BACK) {
|
||||
gl->fReadBuffer(LOCAL_GL_BACK);
|
||||
}
|
||||
ReadPixelsIntoDataSurface(gl, surf);
|
||||
|
||||
if (readBufferMode != LOCAL_GL_BACK) {
|
||||
gl->fReadBuffer(readBufferMode);
|
||||
}
|
||||
}
|
||||
|
||||
if (out_premultAlpha) {
|
||||
@ -2078,6 +2079,30 @@ WebGLContext::ScopedMaskWorkaround::HasDepthButNoStencil(const WebGLFramebuffer*
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
IndexedBufferBinding::IndexedBufferBinding()
|
||||
: mRangeStart(0)
|
||||
, mRangeSize(0)
|
||||
{ }
|
||||
|
||||
uint64_t
|
||||
IndexedBufferBinding::ByteCount() const
|
||||
{
|
||||
if (!mBufferBinding)
|
||||
return 0;
|
||||
|
||||
uint64_t bufferSize = mBufferBinding->ByteLength();
|
||||
if (!mRangeSize) // BindBufferBase
|
||||
return bufferSize;
|
||||
|
||||
if (mRangeStart >= bufferSize)
|
||||
return 0;
|
||||
bufferSize -= mRangeStart;
|
||||
|
||||
return std::min(bufferSize, mRangeSize);
|
||||
}
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
ScopedUnpackReset::ScopedUnpackReset(WebGLContext* webgl)
|
||||
: ScopedGLWrapper<ScopedUnpackReset>(webgl->gl)
|
||||
, mWebGL(webgl)
|
||||
@ -2116,6 +2141,24 @@ ScopedUnpackReset::UnwrapImpl()
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////
|
||||
|
||||
void
|
||||
ScopedFBRebinder::UnwrapImpl()
|
||||
{
|
||||
const auto fnName = [&](WebGLFramebuffer* fb) {
|
||||
return fb ? fb->mGLName : 0;
|
||||
};
|
||||
|
||||
if (mWebGL->IsWebGL2()) {
|
||||
mGL->fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER, fnName(mWebGL->mBoundDrawFramebuffer));
|
||||
mGL->fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER, fnName(mWebGL->mBoundReadFramebuffer));
|
||||
} else {
|
||||
MOZ_ASSERT(mWebGL->mBoundDrawFramebuffer == mWebGL->mBoundReadFramebuffer);
|
||||
mGL->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, fnName(mWebGL->mBoundDrawFramebuffer));
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
void
|
||||
@ -2435,6 +2478,24 @@ WebGLContext::StartVRPresentation()
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// XPCOM goop
|
||||
|
||||
void
|
||||
ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& callback,
|
||||
const std::vector<IndexedBufferBinding>& field,
|
||||
const char* name, uint32_t flags)
|
||||
{
|
||||
for (const auto& cur : field) {
|
||||
ImplCycleCollectionTraverse(callback, cur.mBufferBinding, name, flags);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ImplCycleCollectionUnlink(std::vector<IndexedBufferBinding>& field)
|
||||
{
|
||||
field.clear();
|
||||
}
|
||||
|
||||
////
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(WebGLContext)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(WebGLContext)
|
||||
|
||||
@ -2452,7 +2513,7 @@ NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(WebGLContext,
|
||||
mBoundCopyWriteBuffer,
|
||||
mBoundPixelPackBuffer,
|
||||
mBoundPixelUnpackBuffer,
|
||||
mBoundTransformFeedbackBuffer,
|
||||
mBoundTransformFeedback,
|
||||
mBoundUniformBuffer,
|
||||
mCurrentProgram,
|
||||
mBoundDrawFramebuffer,
|
||||
|
@ -124,6 +124,7 @@ struct LinkedProgramInfo;
|
||||
class ShaderValidator;
|
||||
class TexUnpackBlob;
|
||||
struct UniformInfo;
|
||||
struct UniformBlockInfo;
|
||||
} // namespace webgl
|
||||
|
||||
WebGLTexelFormat GetWebGLTexelFormat(TexInternalFormat format);
|
||||
@ -181,6 +182,19 @@ public:
|
||||
GLfloat AsFloat() const { return (mType == Float) ? mValue.f : GLfloat(mValue.i); }
|
||||
};
|
||||
|
||||
struct IndexedBufferBinding
|
||||
{
|
||||
WebGLRefPtr<WebGLBuffer> mBufferBinding;
|
||||
uint64_t mRangeStart;
|
||||
uint64_t mRangeSize;
|
||||
|
||||
IndexedBufferBinding();
|
||||
|
||||
uint64_t ByteCount() const;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class WebGLContext
|
||||
: public nsIDOMWebGLRenderingContext
|
||||
, public nsICanvasRenderingContextInternal
|
||||
@ -189,6 +203,9 @@ class WebGLContext
|
||||
, public WebGLRectangleObject
|
||||
, public nsWrapperCache
|
||||
{
|
||||
friend class ScopedDrawHelper;
|
||||
friend class ScopedDrawWithTransformFeedback;
|
||||
friend class ScopedFBRebinder;
|
||||
friend class WebGL2Context;
|
||||
friend class WebGLContextUserData;
|
||||
friend class WebGLExtensionCompressedTextureATC;
|
||||
@ -202,6 +219,7 @@ class WebGLContext
|
||||
friend class WebGLExtensionLoseContext;
|
||||
friend class WebGLExtensionVertexArray;
|
||||
friend class WebGLMemoryTracker;
|
||||
friend struct webgl::UniformBlockInfo;
|
||||
|
||||
enum {
|
||||
UNPACK_FLIP_Y_WEBGL = 0x9240,
|
||||
@ -725,11 +743,6 @@ public:
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Buffer Objects (WebGLContextBuffers.cpp)
|
||||
private:
|
||||
void UpdateBoundBuffer(GLenum target, WebGLBuffer* buffer);
|
||||
void UpdateBoundBufferIndexed(GLenum target, GLuint index, WebGLBuffer* buffer);
|
||||
|
||||
public:
|
||||
void BindBuffer(GLenum target, WebGLBuffer* buffer);
|
||||
void BindBufferBase(GLenum target, GLuint index, WebGLBuffer* buf);
|
||||
void BindBufferRange(GLenum target, GLuint index, WebGLBuffer* buf,
|
||||
@ -771,18 +784,14 @@ protected:
|
||||
WebGLRefPtr<WebGLBuffer> mBoundCopyWriteBuffer;
|
||||
WebGLRefPtr<WebGLBuffer> mBoundPixelPackBuffer;
|
||||
WebGLRefPtr<WebGLBuffer> mBoundPixelUnpackBuffer;
|
||||
WebGLRefPtr<WebGLBuffer> mBoundTransformFeedbackBuffer;
|
||||
WebGLRefPtr<WebGLBuffer> mBoundUniformBuffer;
|
||||
|
||||
nsTArray<WebGLRefPtr<WebGLBuffer>> mBoundUniformBuffers;
|
||||
nsTArray<WebGLRefPtr<WebGLBuffer>> mBoundTransformFeedbackBuffers;
|
||||
std::vector<IndexedBufferBinding> mIndexedUniformBufferBindings;
|
||||
|
||||
WebGLRefPtr<WebGLBuffer>& GetBufferSlotByTarget(GLenum target);
|
||||
WebGLRefPtr<WebGLBuffer>& GetBufferSlotByTargetIndexed(GLenum target,
|
||||
GLuint index);
|
||||
|
||||
GLenum GetCurrentBinding(WebGLBuffer* buffer) const;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Queries (WebGL2ContextQueries.cpp)
|
||||
protected:
|
||||
@ -1045,11 +1054,11 @@ private:
|
||||
uint32_t mMaxFetchedInstances;
|
||||
bool mBufferFetch_IsAttrib0Active;
|
||||
|
||||
bool DrawArrays_check(GLint first, GLsizei count, GLsizei primcount,
|
||||
const char* info);
|
||||
bool DrawElements_check(GLsizei count, GLenum type, WebGLintptr byteOffset,
|
||||
GLsizei primcount, const char* info,
|
||||
GLuint* out_upperBound);
|
||||
bool DrawArrays_check(const char* funcName, GLenum mode, GLint first,
|
||||
GLsizei vertCount, GLsizei instanceCount);
|
||||
bool DrawElements_check(const char* funcName, GLenum mode, GLsizei vertCount,
|
||||
GLenum type, WebGLintptr byteOffset,
|
||||
GLsizei instanceCount);
|
||||
bool DrawInstanced_check(const char* info);
|
||||
void Draw_cleanup(const char* funcName);
|
||||
|
||||
@ -1138,6 +1147,8 @@ public:
|
||||
return LOCAL_GL_COLOR_ATTACHMENT0 + mImplMaxColorAttachments - 1;
|
||||
}
|
||||
|
||||
const decltype(mOptions)& Options() const { return mOptions; }
|
||||
|
||||
protected:
|
||||
|
||||
// Texture sizes are often not actually the GL values. Let's be explicit that these
|
||||
@ -1252,7 +1263,6 @@ protected:
|
||||
bool ValidateBlendFuncSrcEnum(GLenum mode, const char* info);
|
||||
bool ValidateBlendFuncEnumsCompatibility(GLenum sfactor, GLenum dfactor,
|
||||
const char* info);
|
||||
bool ValidateDataOffsetSize(WebGLintptr offset, WebGLsizeiptr size, WebGLsizeiptr bufferSize, const char* info);
|
||||
bool ValidateDataRanges(WebGLintptr readOffset, WebGLintptr writeOffset, WebGLsizeiptr size, const char* info);
|
||||
bool ValidateTextureTargetEnum(GLenum target, const char* info);
|
||||
bool ValidateComparisonEnum(GLenum target, const char* info);
|
||||
@ -1319,6 +1329,28 @@ protected:
|
||||
const webgl::FormatUsageInfo** const out_format,
|
||||
uint32_t* const out_width, uint32_t* const out_height);
|
||||
|
||||
bool HasDrawBuffers() const {
|
||||
return IsWebGL2() ||
|
||||
IsExtensionEnabled(WebGLExtensionID::WEBGL_draw_buffers);
|
||||
}
|
||||
|
||||
WebGLRefPtr<WebGLBuffer>* ValidateBufferSlot(const char* funcName, GLenum target);
|
||||
WebGLBuffer* ValidateBufferSelection(const char* funcName, GLenum target);
|
||||
IndexedBufferBinding* ValidateIndexedBufferSlot(const char* funcName, GLenum target,
|
||||
GLuint index);
|
||||
|
||||
bool ValidateIndexedBufferBinding(const char* funcName, GLenum target, GLuint index,
|
||||
WebGLRefPtr<WebGLBuffer>** const out_genericBinding,
|
||||
IndexedBufferBinding** const out_indexedBinding);
|
||||
|
||||
bool ValidateNonNegative(const char* funcName, const char* argName, int64_t val) {
|
||||
if (MOZ_UNLIKELY(val < 0)) {
|
||||
ErrorInvalidValue("%s: `%s` must be non-negative.", funcName, argName);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void Invalidate();
|
||||
void DestroyResourcesAndContext();
|
||||
|
||||
@ -1364,20 +1396,9 @@ private:
|
||||
virtual WebGLVertexArray* CreateVertexArrayImpl();
|
||||
|
||||
virtual bool ValidateAttribPointerType(bool integerMode, GLenum type, uint32_t* alignment, const char* info) = 0;
|
||||
virtual bool ValidateBufferTarget(GLenum target, const char* info) = 0;
|
||||
virtual bool ValidateBufferIndexedTarget(GLenum target, const char* info) = 0;
|
||||
virtual bool ValidateBufferForTarget(GLenum target, WebGLBuffer* buffer, const char* info);
|
||||
virtual bool ValidateBufferUsageEnum(GLenum usage, const char* info) = 0;
|
||||
virtual bool ValidateQueryTarget(GLenum usage, const char* info) = 0;
|
||||
virtual bool ValidateUniformMatrixTranspose(bool transpose, const char* info) = 0;
|
||||
|
||||
protected:
|
||||
/** Like glBufferData, but if the call may change the buffer size, checks
|
||||
* any GL error generated by this glBufferData call and returns it.
|
||||
*/
|
||||
GLenum CheckedBufferData(GLenum target, GLsizeiptr size, const GLvoid* data,
|
||||
GLenum usage);
|
||||
|
||||
public:
|
||||
void ForceLoseContext(bool simulateLoss = false);
|
||||
|
||||
@ -1780,18 +1801,36 @@ public:
|
||||
void operator =(const UniqueBuffer& other) = delete; // assign using Move()!
|
||||
};
|
||||
|
||||
class ScopedUnpackReset
|
||||
class ScopedUnpackReset final
|
||||
: public gl::ScopedGLWrapper<ScopedUnpackReset>
|
||||
{
|
||||
friend struct gl::ScopedGLWrapper<ScopedUnpackReset>;
|
||||
|
||||
protected:
|
||||
private:
|
||||
WebGLContext* const mWebGL;
|
||||
|
||||
public:
|
||||
explicit ScopedUnpackReset(WebGLContext* webgl);
|
||||
|
||||
protected:
|
||||
private:
|
||||
void UnwrapImpl();
|
||||
};
|
||||
|
||||
class ScopedFBRebinder final
|
||||
: public gl::ScopedGLWrapper<ScopedFBRebinder>
|
||||
{
|
||||
friend struct gl::ScopedGLWrapper<ScopedFBRebinder>;
|
||||
|
||||
private:
|
||||
WebGLContext* const mWebGL;
|
||||
|
||||
public:
|
||||
explicit ScopedFBRebinder(WebGLContext* webgl)
|
||||
: ScopedGLWrapper<ScopedFBRebinder>(webgl->gl)
|
||||
, mWebGL(webgl)
|
||||
{ }
|
||||
|
||||
private:
|
||||
void UnwrapImpl();
|
||||
};
|
||||
|
||||
@ -1811,6 +1850,16 @@ ZeroTextureData(WebGLContext* webgl, const char* funcName, GLuint tex,
|
||||
const webgl::FormatUsageInfo* usage, uint32_t xOffset, uint32_t yOffset,
|
||||
uint32_t zOffset, uint32_t width, uint32_t height, uint32_t depth);
|
||||
|
||||
////
|
||||
|
||||
void
|
||||
ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& callback,
|
||||
const std::vector<IndexedBufferBinding>& field,
|
||||
const char* name, uint32_t flags = 0);
|
||||
|
||||
void
|
||||
ImplCycleCollectionUnlink(std::vector<IndexedBufferBinding>& field);
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
||||
|
@ -11,177 +11,316 @@
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
void
|
||||
WebGLContext::UpdateBoundBuffer(GLenum target, WebGLBuffer* buffer)
|
||||
WebGLRefPtr<WebGLBuffer>*
|
||||
WebGLContext::ValidateBufferSlot(const char* funcName, GLenum target)
|
||||
{
|
||||
WebGLRefPtr<WebGLBuffer>& bufferSlot = GetBufferSlotByTarget(target);
|
||||
bufferSlot = buffer;
|
||||
WebGLRefPtr<WebGLBuffer>* slot = nullptr;
|
||||
|
||||
if (!buffer)
|
||||
return;
|
||||
switch (target) {
|
||||
case LOCAL_GL_ARRAY_BUFFER:
|
||||
slot = &mBoundArrayBuffer;
|
||||
break;
|
||||
|
||||
buffer->BindTo(target);
|
||||
case LOCAL_GL_ELEMENT_ARRAY_BUFFER:
|
||||
slot = &(mBoundVertexArray->mElementArrayBuffer);
|
||||
break;
|
||||
}
|
||||
|
||||
if (IsWebGL2()) {
|
||||
switch (target) {
|
||||
case LOCAL_GL_COPY_READ_BUFFER:
|
||||
slot = &mBoundCopyReadBuffer;
|
||||
break;
|
||||
|
||||
case LOCAL_GL_COPY_WRITE_BUFFER:
|
||||
slot = &mBoundCopyWriteBuffer;
|
||||
break;
|
||||
|
||||
case LOCAL_GL_PIXEL_PACK_BUFFER:
|
||||
slot = &mBoundPixelPackBuffer;
|
||||
break;
|
||||
|
||||
case LOCAL_GL_PIXEL_UNPACK_BUFFER:
|
||||
slot = &mBoundPixelUnpackBuffer;
|
||||
break;
|
||||
|
||||
case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER:
|
||||
slot = &(mBoundTransformFeedback->mGenericBufferBinding);
|
||||
break;
|
||||
|
||||
case LOCAL_GL_UNIFORM_BUFFER:
|
||||
slot = &mBoundUniformBuffer;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!slot) {
|
||||
ErrorInvalidEnum("%s: Bad `target`: 0x%04x", funcName, target);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return slot;
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::UpdateBoundBufferIndexed(GLenum target, GLuint index, WebGLBuffer* buffer)
|
||||
WebGLBuffer*
|
||||
WebGLContext::ValidateBufferSelection(const char* funcName, GLenum target)
|
||||
{
|
||||
UpdateBoundBuffer(target, buffer);
|
||||
const auto& slot = ValidateBufferSlot(funcName, target);
|
||||
if (!slot)
|
||||
return nullptr;
|
||||
const auto& buffer = *slot;
|
||||
|
||||
WebGLRefPtr<WebGLBuffer>& bufferIndexSlot =
|
||||
GetBufferSlotByTargetIndexed(target, index);
|
||||
bufferIndexSlot = buffer;
|
||||
if (!buffer) {
|
||||
ErrorInvalidOperation("%s: Buffer for `target` is null.", funcName);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return buffer.get();
|
||||
}
|
||||
|
||||
IndexedBufferBinding*
|
||||
WebGLContext::ValidateIndexedBufferSlot(const char* funcName, GLenum target, GLuint index)
|
||||
{
|
||||
decltype(mIndexedUniformBufferBindings)* bindings;
|
||||
const char* maxIndexEnum;
|
||||
switch (target) {
|
||||
case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER:
|
||||
bindings = &(mBoundTransformFeedback->mIndexedBindings);
|
||||
maxIndexEnum = "MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS";
|
||||
break;
|
||||
|
||||
case LOCAL_GL_UNIFORM_BUFFER:
|
||||
bindings = &mIndexedUniformBufferBindings;
|
||||
maxIndexEnum = "MAX_UNIFORM_BUFFER_BINDINGS";
|
||||
break;
|
||||
|
||||
default:
|
||||
ErrorInvalidEnum("%s: Bad `target`: 0x%04x", funcName, target);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (index >= bindings->size()) {
|
||||
ErrorInvalidOperation("%s: `index` >= %s.", funcName, maxIndexEnum);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return &(*bindings)[index];
|
||||
}
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
void
|
||||
WebGLContext::BindBuffer(GLenum target, WebGLBuffer* buffer)
|
||||
{
|
||||
const char funcName[] = "bindBuffer";
|
||||
if (IsContextLost())
|
||||
return;
|
||||
|
||||
if (!ValidateObjectAllowDeletedOrNull("bindBuffer", buffer))
|
||||
if (!ValidateObjectAllowDeletedOrNull(funcName, buffer))
|
||||
return;
|
||||
|
||||
// silently ignore a deleted buffer
|
||||
if (buffer && buffer->IsDeleted())
|
||||
return;
|
||||
|
||||
if (!ValidateBufferTarget(target, "bindBuffer"))
|
||||
const auto& slot = ValidateBufferSlot(funcName, target);
|
||||
if (!slot)
|
||||
return;
|
||||
|
||||
if (!ValidateBufferForTarget(target, buffer, "bindBuffer"))
|
||||
if (buffer && !buffer->ValidateCanBindToTarget(funcName, target))
|
||||
return;
|
||||
|
||||
WebGLContextUnchecked::BindBuffer(target, buffer);
|
||||
gl->MakeCurrent();
|
||||
gl->fBindBuffer(target, buffer ? buffer->mGLName : 0);
|
||||
|
||||
UpdateBoundBuffer(target, buffer);
|
||||
*slot = buffer;
|
||||
if (buffer) {
|
||||
buffer->SetContentAfterBind(target);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
bool
|
||||
WebGLContext::ValidateIndexedBufferBinding(const char* funcName, GLenum target,
|
||||
GLuint index,
|
||||
WebGLRefPtr<WebGLBuffer>** const out_genericBinding,
|
||||
IndexedBufferBinding** const out_indexedBinding)
|
||||
{
|
||||
*out_genericBinding = ValidateBufferSlot(funcName, target);
|
||||
if (!*out_genericBinding)
|
||||
return false;
|
||||
|
||||
*out_indexedBinding = ValidateIndexedBufferSlot(funcName, target, index);
|
||||
if (!*out_indexedBinding)
|
||||
return false;
|
||||
|
||||
if (target == LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER &&
|
||||
mBoundTransformFeedback->mIsActive)
|
||||
{
|
||||
ErrorInvalidOperation("%s: Cannot update indexed buffer bindings on active"
|
||||
" transform feedback objects.",
|
||||
funcName);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::BindBufferBase(GLenum target, GLuint index, WebGLBuffer* buffer)
|
||||
{
|
||||
const char funcName[] = "bindBufferBase";
|
||||
if (IsContextLost())
|
||||
return;
|
||||
|
||||
if (!ValidateObjectAllowDeletedOrNull("bindBufferBase", buffer))
|
||||
if (!ValidateObjectAllowDeletedOrNull(funcName, buffer))
|
||||
return;
|
||||
|
||||
// silently ignore a deleted buffer
|
||||
if (buffer && buffer->IsDeleted())
|
||||
return;
|
||||
|
||||
// ValidateBufferTarget
|
||||
switch (target) {
|
||||
case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER:
|
||||
if (index >= mGLMaxTransformFeedbackSeparateAttribs)
|
||||
return ErrorInvalidValue("bindBufferBase: index should be less than "
|
||||
"MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS");
|
||||
break;
|
||||
|
||||
case LOCAL_GL_UNIFORM_BUFFER:
|
||||
if (index >= mGLMaxUniformBufferBindings)
|
||||
return ErrorInvalidValue("bindBufferBase: index should be less than "
|
||||
"MAX_UNIFORM_BUFFER_BINDINGS");
|
||||
break;
|
||||
|
||||
default:
|
||||
return ErrorInvalidEnumInfo("bindBufferBase: target", target);
|
||||
WebGLRefPtr<WebGLBuffer>* genericBinding;
|
||||
IndexedBufferBinding* indexedBinding;
|
||||
if (!ValidateIndexedBufferBinding(funcName, target, index, &genericBinding,
|
||||
&indexedBinding))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ValidateBufferForTarget(target, buffer, "bindBufferBase"))
|
||||
if (buffer && !buffer->ValidateCanBindToTarget(funcName, target))
|
||||
return;
|
||||
|
||||
WebGLContextUnchecked::BindBufferBase(target, index, buffer);
|
||||
////
|
||||
|
||||
UpdateBoundBufferIndexed(target, index, buffer);
|
||||
gl->MakeCurrent();
|
||||
gl->fBindBufferBase(target, index, buffer ? buffer->mGLName : 0);
|
||||
|
||||
////
|
||||
|
||||
*genericBinding = buffer;
|
||||
indexedBinding->mBufferBinding = buffer;
|
||||
indexedBinding->mRangeStart = 0;
|
||||
indexedBinding->mRangeSize = 0;
|
||||
|
||||
if (buffer) {
|
||||
buffer->SetContentAfterBind(target);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::BindBufferRange(GLenum target, GLuint index, WebGLBuffer* buffer,
|
||||
WebGLintptr offset, WebGLsizeiptr size)
|
||||
{
|
||||
const char funcName[] = "bindBufferRange";
|
||||
if (IsContextLost())
|
||||
return;
|
||||
|
||||
if (!ValidateObjectAllowDeletedOrNull("bindBufferRange", buffer))
|
||||
if (!ValidateObjectAllowDeletedOrNull(funcName, buffer))
|
||||
return;
|
||||
|
||||
// silently ignore a deleted buffer
|
||||
if (buffer && buffer->IsDeleted())
|
||||
return;
|
||||
|
||||
// ValidateBufferTarget
|
||||
if (!ValidateNonNegative(funcName, "offset", offset) ||
|
||||
!ValidateNonNegative(funcName, "size", size))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
WebGLRefPtr<WebGLBuffer>* genericBinding;
|
||||
IndexedBufferBinding* indexedBinding;
|
||||
if (!ValidateIndexedBufferBinding(funcName, target, index, &genericBinding,
|
||||
&indexedBinding))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (buffer && !buffer->ValidateCanBindToTarget(funcName, target))
|
||||
return;
|
||||
|
||||
////
|
||||
|
||||
gl->MakeCurrent();
|
||||
|
||||
switch (target) {
|
||||
case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER:
|
||||
if (index >= mGLMaxTransformFeedbackSeparateAttribs)
|
||||
return ErrorInvalidValue("bindBufferRange: index should be less than "
|
||||
"MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS");
|
||||
if (offset % 4 != 0 || size % 4 != 0) {
|
||||
ErrorInvalidValue("%s: For %s, `offset` and `size` must be multiples of 4.",
|
||||
funcName, "TRANSFORM_FEEDBACK_BUFFER");
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case LOCAL_GL_UNIFORM_BUFFER:
|
||||
if (index >= mGLMaxUniformBufferBindings)
|
||||
return ErrorInvalidValue("bindBufferRange: index should be less than "
|
||||
"MAX_UNIFORM_BUFFER_BINDINGS");
|
||||
{
|
||||
GLuint offsetAlignment = 0;
|
||||
gl->GetUIntegerv(LOCAL_GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &offsetAlignment);
|
||||
if (offset % offsetAlignment != 0) {
|
||||
ErrorInvalidValue("%s: For %s, `offset` must be a multiple of %s.",
|
||||
funcName, "UNIFORM_BUFFER",
|
||||
"UNIFORM_BUFFER_OFFSET_ALIGNMENT");
|
||||
return;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return ErrorInvalidEnumInfo("bindBufferRange: target", target);
|
||||
}
|
||||
|
||||
if (!ValidateBufferForTarget(target, buffer, "bindBufferRange"))
|
||||
return;
|
||||
////
|
||||
|
||||
WebGLContextUnchecked::BindBufferRange(target, index, buffer, offset, size);
|
||||
#ifdef XP_MACOSX
|
||||
if (buffer && buffer->Content() == WebGLBuffer::Kind::Undefined &&
|
||||
gl->WorkAroundDriverBugs())
|
||||
{
|
||||
// BindBufferRange will fail if the buffer's contents is undefined.
|
||||
// Bind so driver initializes the buffer.
|
||||
gl->fBindBuffer(target, buffer->mGLName);
|
||||
}
|
||||
#endif
|
||||
|
||||
UpdateBoundBufferIndexed(target, index, buffer);
|
||||
gl->fBindBufferRange(target, index, buffer ? buffer->mGLName : 0, offset, size);
|
||||
|
||||
////
|
||||
|
||||
*genericBinding = buffer;
|
||||
indexedBinding->mBufferBinding = buffer;
|
||||
indexedBinding->mRangeStart = offset;
|
||||
indexedBinding->mRangeSize = size;
|
||||
|
||||
if (buffer) {
|
||||
buffer->SetContentAfterBind(target);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
void
|
||||
WebGLContext::BufferData(GLenum target, WebGLsizeiptr size, GLenum usage)
|
||||
{
|
||||
const char funcName[] = "bufferData";
|
||||
if (IsContextLost())
|
||||
return;
|
||||
|
||||
if (!ValidateBufferTarget(target, "bufferData"))
|
||||
return;
|
||||
|
||||
WebGLRefPtr<WebGLBuffer>& bufferSlot = GetBufferSlotByTarget(target);
|
||||
|
||||
if (size < 0)
|
||||
return ErrorInvalidValue("bufferData: negative size");
|
||||
|
||||
if (!ValidateBufferUsageEnum(usage, "bufferData: usage"))
|
||||
if (!ValidateNonNegative(funcName, "size", size))
|
||||
return;
|
||||
|
||||
// careful: WebGLsizeiptr is always 64-bit, but GLsizeiptr is like intptr_t.
|
||||
if (!CheckedInt<GLsizeiptr>(size).isValid())
|
||||
return ErrorOutOfMemory("bufferData: bad size");
|
||||
return ErrorOutOfMemory("%s: bad size", funcName);
|
||||
|
||||
WebGLBuffer* boundBuffer = bufferSlot.get();
|
||||
const auto& buffer = ValidateBufferSelection(funcName, target);
|
||||
if (!buffer)
|
||||
return;
|
||||
|
||||
if (!boundBuffer)
|
||||
return ErrorInvalidOperation("bufferData: no buffer bound!");
|
||||
////
|
||||
|
||||
UniquePtr<uint8_t> zeroBuffer((uint8_t*)calloc(size, 1));
|
||||
if (!zeroBuffer)
|
||||
return ErrorOutOfMemory("bufferData: out of memory");
|
||||
return ErrorOutOfMemory("%s: Failed to allocate zeros.", funcName);
|
||||
|
||||
MakeContextCurrent();
|
||||
InvalidateBufferFetching();
|
||||
|
||||
GLenum error = CheckedBufferData(target, size, zeroBuffer.get(), usage);
|
||||
|
||||
if (error) {
|
||||
GenerateWarning("bufferData generated error %s", ErrorName(error));
|
||||
return;
|
||||
}
|
||||
|
||||
boundBuffer->SetByteLength(size);
|
||||
|
||||
if (!boundBuffer->ElementArrayCacheBufferData(nullptr, size)) {
|
||||
boundBuffer->SetByteLength(0);
|
||||
return ErrorOutOfMemory("bufferData: out of memory");
|
||||
}
|
||||
buffer->BufferData(target, size_t(size), zeroBuffer.get(), usage);
|
||||
}
|
||||
|
||||
// BufferT may be one of
|
||||
@ -194,14 +333,10 @@ WebGLContext::BufferDataT(GLenum target,
|
||||
const BufferT& data,
|
||||
GLenum usage)
|
||||
{
|
||||
const char funcName[] = "bufferData";
|
||||
if (IsContextLost())
|
||||
return;
|
||||
|
||||
if (!ValidateBufferTarget(target, "bufferData"))
|
||||
return;
|
||||
|
||||
const WebGLRefPtr<WebGLBuffer>& bufferSlot = GetBufferSlotByTarget(target);
|
||||
|
||||
data.ComputeLengthAndData();
|
||||
|
||||
// Careful: data.Length() could conceivably be any uint32_t, but GLsizeiptr
|
||||
@ -209,32 +344,12 @@ WebGLContext::BufferDataT(GLenum target,
|
||||
if (!CheckedInt<GLsizeiptr>(data.LengthAllowShared()).isValid())
|
||||
return ErrorOutOfMemory("bufferData: bad size");
|
||||
|
||||
if (!ValidateBufferUsageEnum(usage, "bufferData: usage"))
|
||||
const auto& buffer = ValidateBufferSelection(funcName, target);
|
||||
if (!buffer)
|
||||
return;
|
||||
|
||||
WebGLBuffer* boundBuffer = bufferSlot.get();
|
||||
|
||||
if (!boundBuffer)
|
||||
return ErrorInvalidOperation("bufferData: no buffer bound!");
|
||||
|
||||
MakeContextCurrent();
|
||||
InvalidateBufferFetching();
|
||||
|
||||
// Warning: Possibly shared memory. See bug 1225033.
|
||||
GLenum error = CheckedBufferData(target, data.LengthAllowShared(), data.DataAllowShared(), usage);
|
||||
|
||||
if (error) {
|
||||
GenerateWarning("bufferData generated error %s", ErrorName(error));
|
||||
return;
|
||||
}
|
||||
|
||||
boundBuffer->SetByteLength(data.LengthAllowShared());
|
||||
|
||||
// Warning: Possibly shared memory. See bug 1225033.
|
||||
if (!boundBuffer->ElementArrayCacheBufferData(data.DataAllowShared(), data.LengthAllowShared())) {
|
||||
boundBuffer->SetByteLength(0);
|
||||
return ErrorOutOfMemory("bufferData: out of memory");
|
||||
}
|
||||
buffer->BufferData(target, data.LengthAllowShared(), data.DataAllowShared(), usage);
|
||||
}
|
||||
|
||||
void
|
||||
@ -264,6 +379,8 @@ WebGLContext::BufferData(GLenum target, const dom::ArrayBufferView& data,
|
||||
BufferDataT(target, data, usage);
|
||||
}
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
// BufferT may be one of
|
||||
// const dom::ArrayBuffer&
|
||||
// const dom::SharedArrayBuffer&
|
||||
@ -274,25 +391,28 @@ WebGLContext::BufferSubDataT(GLenum target,
|
||||
WebGLsizeiptr byteOffset,
|
||||
const BufferT& data)
|
||||
{
|
||||
const char funcName[] = "bufferSubData";
|
||||
if (IsContextLost())
|
||||
return;
|
||||
|
||||
if (!ValidateBufferTarget(target, "bufferSubData"))
|
||||
if (!ValidateNonNegative(funcName, "byteOffset", byteOffset))
|
||||
return;
|
||||
|
||||
WebGLRefPtr<WebGLBuffer>& bufferSlot = GetBufferSlotByTarget(target);
|
||||
const auto& buffer = ValidateBufferSelection(funcName, target);
|
||||
if (!buffer)
|
||||
return;
|
||||
|
||||
if (byteOffset < 0)
|
||||
return ErrorInvalidValue("bufferSubData: negative offset");
|
||||
|
||||
WebGLBuffer* boundBuffer = bufferSlot.get();
|
||||
if (!boundBuffer)
|
||||
return ErrorInvalidOperation("bufferData: no buffer bound!");
|
||||
if (buffer->mNumActiveTFOs) {
|
||||
ErrorInvalidOperation("%s: Buffer is bound to an active transform feedback"
|
||||
" object.",
|
||||
"bufferSubData");
|
||||
return;
|
||||
}
|
||||
|
||||
data.ComputeLengthAndData();
|
||||
|
||||
CheckedInt<WebGLsizeiptr> checked_neededByteLength =
|
||||
CheckedInt<WebGLsizeiptr>(byteOffset) + data.LengthAllowShared();
|
||||
const auto checked_neededByteLength =
|
||||
CheckedInt<size_t>(byteOffset) + data.LengthAllowShared();
|
||||
|
||||
if (!checked_neededByteLength.isValid()) {
|
||||
ErrorInvalidValue("bufferSubData: Integer overflow computing the needed"
|
||||
@ -300,21 +420,22 @@ WebGLContext::BufferSubDataT(GLenum target,
|
||||
return;
|
||||
}
|
||||
|
||||
if (checked_neededByteLength.value() > boundBuffer->ByteLength()) {
|
||||
if (checked_neededByteLength.value() > buffer->ByteLength()) {
|
||||
ErrorInvalidValue("bufferSubData: Not enough data. Operation requires"
|
||||
" %d bytes, but buffer only has %d bytes.",
|
||||
checked_neededByteLength.value(),
|
||||
boundBuffer->ByteLength());
|
||||
buffer->ByteLength());
|
||||
return;
|
||||
}
|
||||
|
||||
// Warning: Possibly shared memory. See bug 1225033.
|
||||
boundBuffer->ElementArrayCacheBufferSubData(byteOffset, data.DataAllowShared(),
|
||||
data.LengthAllowShared());
|
||||
|
||||
MakeContextCurrent();
|
||||
// Warning: Possibly shared memory. See bug 1225033.
|
||||
gl->fBufferSubData(target, byteOffset, data.LengthAllowShared(), data.DataAllowShared());
|
||||
gl->fBufferSubData(target, byteOffset, data.LengthAllowShared(),
|
||||
data.DataAllowShared());
|
||||
|
||||
// Warning: Possibly shared memory. See bug 1225033.
|
||||
buffer->ElementArrayCacheBufferSubData(byteOffset, data.DataAllowShared(),
|
||||
data.LengthAllowShared());
|
||||
}
|
||||
|
||||
void
|
||||
@ -342,6 +463,8 @@ WebGLContext::BufferSubData(GLenum target, WebGLsizeiptr byteOffset,
|
||||
BufferSubDataT(target, byteOffset, data);
|
||||
}
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
already_AddRefed<WebGLBuffer>
|
||||
WebGLContext::CreateBuffer()
|
||||
{
|
||||
@ -368,60 +491,45 @@ WebGLContext::DeleteBuffer(WebGLBuffer* buffer)
|
||||
if (!buffer || buffer->IsDeleted())
|
||||
return;
|
||||
|
||||
// TODO: Extract this into a helper function?
|
||||
if (mBoundArrayBuffer == buffer) {
|
||||
WebGLContextUnchecked::BindBuffer(LOCAL_GL_ARRAY_BUFFER, nullptr);
|
||||
mBoundArrayBuffer = nullptr;
|
||||
}
|
||||
////
|
||||
|
||||
if (mBoundVertexArray->mElementArrayBuffer == buffer) {
|
||||
WebGLContextUnchecked::BindBuffer(LOCAL_GL_ELEMENT_ARRAY_BUFFER, nullptr);
|
||||
mBoundVertexArray->mElementArrayBuffer = nullptr;
|
||||
}
|
||||
const auto fnClearIfBuffer = [&](WebGLRefPtr<WebGLBuffer>& bindPoint) {
|
||||
if (bindPoint == buffer) {
|
||||
bindPoint = nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
fnClearIfBuffer(mBoundArrayBuffer);
|
||||
fnClearIfBuffer(mBoundVertexArray->mElementArrayBuffer);
|
||||
|
||||
// WebGL binding points
|
||||
if (IsWebGL2()) {
|
||||
if (mBoundCopyReadBuffer == buffer)
|
||||
mBoundCopyReadBuffer = nullptr;
|
||||
fnClearIfBuffer(mBoundCopyReadBuffer);
|
||||
fnClearIfBuffer(mBoundCopyWriteBuffer);
|
||||
fnClearIfBuffer(mBoundPixelPackBuffer);
|
||||
fnClearIfBuffer(mBoundPixelUnpackBuffer);
|
||||
fnClearIfBuffer(mBoundUniformBuffer);
|
||||
fnClearIfBuffer(mBoundTransformFeedback->mGenericBufferBinding);
|
||||
|
||||
if (mBoundCopyWriteBuffer == buffer)
|
||||
mBoundCopyWriteBuffer = nullptr;
|
||||
|
||||
if (mBoundPixelPackBuffer == buffer)
|
||||
mBoundPixelPackBuffer = nullptr;
|
||||
|
||||
if (mBoundPixelUnpackBuffer == buffer)
|
||||
mBoundPixelUnpackBuffer = nullptr;
|
||||
|
||||
if (mBoundTransformFeedbackBuffer == buffer)
|
||||
mBoundTransformFeedbackBuffer = nullptr;
|
||||
|
||||
if (mBoundUniformBuffer == buffer)
|
||||
mBoundUniformBuffer = nullptr;
|
||||
|
||||
const size_t xfBufferCount = mBoundTransformFeedbackBuffers.Length();
|
||||
for (size_t n = 0; n < xfBufferCount; n++) {
|
||||
if (mBoundTransformFeedbackBuffers[n] == buffer) {
|
||||
mBoundTransformFeedbackBuffers[n] = nullptr;
|
||||
if (!mBoundTransformFeedback->mIsActive) {
|
||||
for (auto& binding : mBoundTransformFeedback->mIndexedBindings) {
|
||||
fnClearIfBuffer(binding.mBufferBinding);
|
||||
}
|
||||
}
|
||||
|
||||
const size_t uniformBufferCount = mBoundUniformBuffers.Length();
|
||||
for (size_t n = 0; n < uniformBufferCount; n++) {
|
||||
if (mBoundUniformBuffers[n] == buffer) {
|
||||
mBoundUniformBuffers[n] = nullptr;
|
||||
}
|
||||
for (auto& binding : mIndexedUniformBufferBindings) {
|
||||
fnClearIfBuffer(binding.mBufferBinding);
|
||||
}
|
||||
}
|
||||
|
||||
for (int32_t i = 0; i < mGLMaxVertexAttribs; i++) {
|
||||
if (mBoundVertexArray->HasAttrib(i) &&
|
||||
mBoundVertexArray->mAttribs[i].buf == buffer)
|
||||
{
|
||||
mBoundVertexArray->mAttribs[i].buf = nullptr;
|
||||
if (mBoundVertexArray->HasAttrib(i)) {
|
||||
fnClearIfBuffer(mBoundVertexArray->mAttribs[i].buf);
|
||||
}
|
||||
}
|
||||
|
||||
////
|
||||
|
||||
buffer->RequestDelete();
|
||||
}
|
||||
|
||||
@ -441,211 +549,4 @@ WebGLContext::IsBuffer(WebGLBuffer* buffer)
|
||||
return gl->fIsBuffer(buffer->mGLName);
|
||||
}
|
||||
|
||||
bool
|
||||
WebGLContext::ValidateBufferForTarget(GLenum target, WebGLBuffer* buffer,
|
||||
const char* info)
|
||||
{
|
||||
if (!buffer)
|
||||
return true;
|
||||
|
||||
/* https://www.khronos.org/registry/webgl/specs/latest/2.0/#5.1
|
||||
*
|
||||
* In the WebGL 2 API, buffers have their WebGL buffer type
|
||||
* initially set to undefined. Calling bindBuffer, bindBufferRange
|
||||
* or bindBufferBase with the target argument set to any buffer
|
||||
* binding point except COPY_READ_BUFFER or COPY_WRITE_BUFFER will
|
||||
* then set the WebGL buffer type of the buffer being bound
|
||||
* according to the table above.
|
||||
*
|
||||
* Any call to one of these functions which attempts to bind a
|
||||
* WebGLBuffer that has the element array WebGL buffer type to a
|
||||
* binding point that falls under other data, or bind a
|
||||
* WebGLBuffer which has the other data WebGL buffer type to
|
||||
* ELEMENT_ARRAY_BUFFER will generate an INVALID_OPERATION error,
|
||||
* and the state of the binding point will remain untouched.
|
||||
*/
|
||||
|
||||
GLenum boundTo = GetCurrentBinding(buffer);
|
||||
if (boundTo != LOCAL_GL_NONE) {
|
||||
if (target == LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER &&
|
||||
boundTo != LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER)
|
||||
{
|
||||
ErrorInvalidOperation("Can't bind buffer to TRANSFORM_FEEDBACK_BUFFER as the "
|
||||
"buffer is already bound to another bind point.");
|
||||
return false;
|
||||
}
|
||||
else if (target != LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER &&
|
||||
boundTo == LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER)
|
||||
{
|
||||
ErrorInvalidOperation("Can't bind buffer to bind point as it is currently "
|
||||
"bound to TRANSFORM_FEEDBACK_BUFFER.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
WebGLBuffer::Kind content = buffer->Content();
|
||||
if (content == WebGLBuffer::Kind::Undefined)
|
||||
return true;
|
||||
|
||||
switch (target) {
|
||||
case LOCAL_GL_COPY_READ_BUFFER:
|
||||
case LOCAL_GL_COPY_WRITE_BUFFER:
|
||||
return true;
|
||||
|
||||
case LOCAL_GL_ELEMENT_ARRAY_BUFFER:
|
||||
if (content == WebGLBuffer::Kind::ElementArray)
|
||||
return true;
|
||||
break;
|
||||
|
||||
case LOCAL_GL_ARRAY_BUFFER:
|
||||
case LOCAL_GL_PIXEL_PACK_BUFFER:
|
||||
case LOCAL_GL_PIXEL_UNPACK_BUFFER:
|
||||
case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER:
|
||||
case LOCAL_GL_UNIFORM_BUFFER:
|
||||
if (content == WebGLBuffer::Kind::OtherData)
|
||||
return true;
|
||||
break;
|
||||
|
||||
default:
|
||||
MOZ_CRASH();
|
||||
}
|
||||
|
||||
ErrorInvalidOperation("%s: buffer already contains %s data.", info,
|
||||
content == WebGLBuffer::Kind::OtherData ? "other" : "element");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
WebGLContext::ValidateBufferUsageEnum(GLenum target, const char* info)
|
||||
{
|
||||
switch (target) {
|
||||
case LOCAL_GL_STREAM_DRAW:
|
||||
case LOCAL_GL_STATIC_DRAW:
|
||||
case LOCAL_GL_DYNAMIC_DRAW:
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
ErrorInvalidEnumInfo(info, target);
|
||||
return false;
|
||||
}
|
||||
|
||||
WebGLRefPtr<WebGLBuffer>&
|
||||
WebGLContext::GetBufferSlotByTarget(GLenum target)
|
||||
{
|
||||
/* This function assumes that target has been validated for either
|
||||
* WebGL1 or WebGL2.
|
||||
*/
|
||||
switch (target) {
|
||||
case LOCAL_GL_ARRAY_BUFFER:
|
||||
return mBoundArrayBuffer;
|
||||
|
||||
case LOCAL_GL_COPY_READ_BUFFER:
|
||||
return mBoundCopyReadBuffer;
|
||||
|
||||
case LOCAL_GL_COPY_WRITE_BUFFER:
|
||||
return mBoundCopyWriteBuffer;
|
||||
|
||||
case LOCAL_GL_ELEMENT_ARRAY_BUFFER:
|
||||
return mBoundVertexArray->mElementArrayBuffer;
|
||||
|
||||
case LOCAL_GL_PIXEL_PACK_BUFFER:
|
||||
return mBoundPixelPackBuffer;
|
||||
|
||||
case LOCAL_GL_PIXEL_UNPACK_BUFFER:
|
||||
return mBoundPixelUnpackBuffer;
|
||||
|
||||
case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER:
|
||||
return mBoundTransformFeedbackBuffer;
|
||||
|
||||
case LOCAL_GL_UNIFORM_BUFFER:
|
||||
return mBoundUniformBuffer;
|
||||
|
||||
default:
|
||||
MOZ_CRASH("GFX: Should not get here.");
|
||||
}
|
||||
}
|
||||
|
||||
WebGLRefPtr<WebGLBuffer>&
|
||||
WebGLContext::GetBufferSlotByTargetIndexed(GLenum target, GLuint index)
|
||||
{
|
||||
/* This function assumes that target has been validated for either WebGL1 or WebGL. */
|
||||
switch (target) {
|
||||
case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER:
|
||||
MOZ_ASSERT(index < mGLMaxTransformFeedbackSeparateAttribs);
|
||||
return mBoundTransformFeedbackBuffers[index];
|
||||
|
||||
case LOCAL_GL_UNIFORM_BUFFER:
|
||||
MOZ_ASSERT(index < mGLMaxUniformBufferBindings);
|
||||
return mBoundUniformBuffers[index];
|
||||
|
||||
default:
|
||||
MOZ_CRASH("GFX: Should not get here.");
|
||||
}
|
||||
}
|
||||
|
||||
GLenum
|
||||
WebGLContext::GetCurrentBinding(WebGLBuffer* buffer) const
|
||||
{
|
||||
if (mBoundArrayBuffer == buffer)
|
||||
return LOCAL_GL_ARRAY_BUFFER;
|
||||
|
||||
if (mBoundCopyReadBuffer == buffer)
|
||||
return LOCAL_GL_COPY_READ_BUFFER;
|
||||
|
||||
if (mBoundCopyWriteBuffer == buffer)
|
||||
return LOCAL_GL_COPY_WRITE_BUFFER;
|
||||
|
||||
if (mBoundPixelPackBuffer == buffer)
|
||||
return LOCAL_GL_PIXEL_PACK_BUFFER;
|
||||
|
||||
if (mBoundPixelUnpackBuffer == buffer)
|
||||
return LOCAL_GL_PIXEL_UNPACK_BUFFER;
|
||||
|
||||
if (mBoundTransformFeedbackBuffer == buffer ||
|
||||
mBoundTransformFeedbackBuffers.Contains(buffer)) {
|
||||
return LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER;
|
||||
}
|
||||
|
||||
if (mBoundUniformBuffer == buffer ||
|
||||
mBoundUniformBuffers.Contains(buffer)) {
|
||||
return LOCAL_GL_UNIFORM_BUFFER;
|
||||
}
|
||||
|
||||
return LOCAL_GL_NONE;
|
||||
}
|
||||
|
||||
GLenum
|
||||
WebGLContext::CheckedBufferData(GLenum target, GLsizeiptr size,
|
||||
const GLvoid* data, GLenum usage)
|
||||
{
|
||||
#ifdef XP_MACOSX
|
||||
// bug 790879
|
||||
if (gl->WorkAroundDriverBugs() &&
|
||||
int64_t(size) > INT32_MAX) // cast avoids a potential always-true warning on 32bit
|
||||
{
|
||||
GenerateWarning("Rejecting valid bufferData call with size %lu to avoid"
|
||||
" a Mac bug", size);
|
||||
return LOCAL_GL_INVALID_VALUE;
|
||||
}
|
||||
#endif
|
||||
|
||||
WebGLRefPtr<WebGLBuffer>& bufferSlot = GetBufferSlotByTarget(target);
|
||||
WebGLBuffer* boundBuffer = bufferSlot.get();
|
||||
MOZ_ASSERT(boundBuffer, "No buffer bound for this target.");
|
||||
|
||||
bool sizeChanges = uint32_t(size) != boundBuffer->ByteLength();
|
||||
if (sizeChanges) {
|
||||
GetAndFlushUnderlyingGLErrors();
|
||||
gl->fBufferData(target, size, data, usage);
|
||||
GLenum error = GetAndFlushUnderlyingGLErrors();
|
||||
return error;
|
||||
} else {
|
||||
gl->fBufferData(target, size, data, usage);
|
||||
return LOCAL_GL_NO_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -101,10 +101,17 @@ ScopedResolveTexturesForDraw::ScopedResolveTexturesForDraw(WebGLContext* webgl,
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<const WebGLFBAttachPoint*> fbAttachments;
|
||||
if (mWebGL->mBoundDrawFramebuffer) {
|
||||
const auto& fb = mWebGL->mBoundDrawFramebuffer;
|
||||
fb->GatherAttachments(&fbAttachments);
|
||||
const std::vector<const WebGLFBAttachPoint*>* attachList = nullptr;
|
||||
const auto& fb = mWebGL->mBoundDrawFramebuffer;
|
||||
if (fb) {
|
||||
if (!fb->ValidateAndInitAttachments(funcName)) {
|
||||
*out_error = true;
|
||||
return;
|
||||
}
|
||||
|
||||
attachList = &(fb->ResolvedCompleteData()->texDrawBuffers);
|
||||
} else {
|
||||
webgl->ClearBackbufferIfNeeded();
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mWebGL->mActiveProgramLinkInfo);
|
||||
@ -120,7 +127,9 @@ ScopedResolveTexturesForDraw::ScopedResolveTexturesForDraw(WebGLContext* webgl,
|
||||
if (!tex)
|
||||
continue;
|
||||
|
||||
if (tex->IsFeedback(mWebGL, funcName, texUnit, fbAttachments)) {
|
||||
if (attachList &&
|
||||
tex->IsFeedback(mWebGL, funcName, texUnit, *attachList))
|
||||
{
|
||||
*out_error = true;
|
||||
return;
|
||||
}
|
||||
@ -241,22 +250,21 @@ WebGLContext::DrawInstanced_check(const char* info)
|
||||
}
|
||||
|
||||
bool
|
||||
WebGLContext::DrawArrays_check(GLint first, GLsizei count, GLsizei primcount,
|
||||
const char* info)
|
||||
WebGLContext::DrawArrays_check(const char* funcName, GLenum mode, GLint first,
|
||||
GLsizei vertCount, GLsizei instanceCount)
|
||||
{
|
||||
if (first < 0 || count < 0) {
|
||||
ErrorInvalidValue("%s: negative first or count", info);
|
||||
if (!ValidateDrawModeEnum(mode, funcName))
|
||||
return false;
|
||||
|
||||
if (!ValidateNonNegative(funcName, "first", first) ||
|
||||
!ValidateNonNegative(funcName, "vertCount", vertCount) ||
|
||||
!ValidateNonNegative(funcName, "instanceCount", instanceCount))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (primcount < 0) {
|
||||
ErrorInvalidValue("%s: negative primcount", info);
|
||||
if (!ValidateStencilParamsForDrawCall())
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ValidateStencilParamsForDrawCall()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (IsWebGL2() && !gl->IsSupported(gl::GLFeature::prim_restart_fixed)) {
|
||||
MOZ_ASSERT(gl->IsSupported(gl::GLFeature::prim_restart));
|
||||
@ -268,133 +276,295 @@ WebGLContext::DrawArrays_check(GLint first, GLsizei count, GLsizei primcount,
|
||||
}
|
||||
}
|
||||
|
||||
// If count is 0, there's nothing to do.
|
||||
if (count == 0 || primcount == 0) {
|
||||
if (!vertCount || !instanceCount)
|
||||
return false; // No error, just early out.
|
||||
|
||||
if (!ValidateBufferFetching(funcName))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ValidateBufferFetching(info)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
CheckedInt<GLsizei> checked_firstPlusCount = CheckedInt<GLsizei>(first) + count;
|
||||
|
||||
const auto checked_firstPlusCount = CheckedInt<GLsizei>(first) + vertCount;
|
||||
if (!checked_firstPlusCount.isValid()) {
|
||||
ErrorInvalidOperation("%s: overflow in first+count", info);
|
||||
ErrorInvalidOperation("%s: overflow in first+vertCount", funcName);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (uint32_t(checked_firstPlusCount.value()) > mMaxFetchedVertices) {
|
||||
ErrorInvalidOperation("%s: bound vertex attribute buffers do not have sufficient size for given first and count", info);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (uint32_t(primcount) > mMaxFetchedInstances) {
|
||||
ErrorInvalidOperation("%s: bound instance attribute buffers do not have sufficient size for given primcount", info);
|
||||
return false;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(gl->IsCurrent());
|
||||
|
||||
if (mBoundDrawFramebuffer) {
|
||||
if (!mBoundDrawFramebuffer->ValidateAndInitAttachments(info))
|
||||
return false;
|
||||
} else {
|
||||
ClearBackbufferIfNeeded();
|
||||
}
|
||||
|
||||
if (!DoFakeVertexAttrib0(checked_firstPlusCount.value())) {
|
||||
ErrorInvalidOperation("%s: Bound vertex attribute buffers do not have sufficient"
|
||||
" size for given first and count.",
|
||||
funcName);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
class ScopedDrawHelper final
|
||||
{
|
||||
WebGLContext* const mWebGL;
|
||||
bool mDidFake;
|
||||
|
||||
public:
|
||||
ScopedDrawHelper(WebGLContext* webgl, const char* funcName, uint32_t firstVertex,
|
||||
uint32_t vertCount, uint32_t instanceCount, bool* const out_error)
|
||||
: mWebGL(webgl)
|
||||
, mDidFake(false)
|
||||
{
|
||||
if (instanceCount > mWebGL->mMaxFetchedInstances) {
|
||||
mWebGL->ErrorInvalidOperation("%s: Bound instance attribute buffers do not"
|
||||
" have sufficient size for given"
|
||||
" `instanceCount`.",
|
||||
funcName);
|
||||
*out_error = true;
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mWebGL->gl->IsCurrent());
|
||||
|
||||
if (mWebGL->mBoundDrawFramebuffer) {
|
||||
if (!mWebGL->mBoundDrawFramebuffer->ValidateAndInitAttachments(funcName)) {
|
||||
*out_error = true;
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
mWebGL->ClearBackbufferIfNeeded();
|
||||
}
|
||||
|
||||
////
|
||||
|
||||
const size_t requiredVerts = firstVertex + vertCount;
|
||||
if (!mWebGL->DoFakeVertexAttrib0(requiredVerts)) {
|
||||
*out_error = true;
|
||||
return;
|
||||
}
|
||||
mDidFake = true;
|
||||
|
||||
////
|
||||
// Check UBO sizes.
|
||||
|
||||
const auto& linkInfo = webgl->mActiveProgramLinkInfo;
|
||||
for (const auto& cur : linkInfo->uniformBlocks) {
|
||||
const auto& dataSize = cur->mDataSize;
|
||||
const auto& binding = cur->mBinding;
|
||||
if (!binding) {
|
||||
mWebGL->ErrorInvalidOperation("%s: Buffer for uniform block is null.",
|
||||
funcName);
|
||||
*out_error = true;
|
||||
return;
|
||||
}
|
||||
|
||||
const auto availByteCount = binding->ByteCount();
|
||||
if (dataSize > availByteCount) {
|
||||
mWebGL->ErrorInvalidOperation("%s: Buffer for uniform block is smaller"
|
||||
" than UNIFORM_BLOCK_DATA_SIZE.",
|
||||
funcName);
|
||||
*out_error = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
////
|
||||
|
||||
mWebGL->RunContextLossTimer();
|
||||
}
|
||||
|
||||
~ScopedDrawHelper() {
|
||||
if (mDidFake) {
|
||||
mWebGL->UndoFakeVertexAttrib0();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
static uint32_t
|
||||
UsedVertsForTFDraw(GLenum mode, uint32_t vertCount)
|
||||
{
|
||||
uint8_t vertsPerPrim;
|
||||
|
||||
switch (mode) {
|
||||
case LOCAL_GL_POINTS:
|
||||
vertsPerPrim = 1;
|
||||
break;
|
||||
case LOCAL_GL_LINES:
|
||||
vertsPerPrim = 2;
|
||||
break;
|
||||
case LOCAL_GL_TRIANGLES:
|
||||
vertsPerPrim = 3;
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("`mode`");
|
||||
}
|
||||
|
||||
return vertCount / vertsPerPrim * vertsPerPrim;
|
||||
}
|
||||
|
||||
class ScopedDrawWithTransformFeedback final
|
||||
{
|
||||
WebGLContext* const mWebGL;
|
||||
WebGLTransformFeedback* const mTFO;
|
||||
const bool mWithTF;
|
||||
uint32_t mUsedVerts;
|
||||
|
||||
public:
|
||||
ScopedDrawWithTransformFeedback(WebGLContext* webgl, const char* funcName,
|
||||
GLenum mode, uint32_t vertCount,
|
||||
uint32_t instanceCount, bool* const out_error)
|
||||
: mWebGL(webgl)
|
||||
, mTFO(mWebGL->mBoundTransformFeedback)
|
||||
, mWithTF(mTFO &&
|
||||
mTFO->mIsActive &&
|
||||
!mTFO->mIsPaused)
|
||||
, mUsedVerts(0)
|
||||
{
|
||||
*out_error = false;
|
||||
if (!mWithTF)
|
||||
return;
|
||||
|
||||
if (mode != mTFO->mActive_PrimMode) {
|
||||
mWebGL->ErrorInvalidOperation("%s: Drawing with transform feedback requires"
|
||||
" `mode` to match BeginTransformFeedback's"
|
||||
" `primitiveMode`.",
|
||||
funcName);
|
||||
*out_error = true;
|
||||
return;
|
||||
}
|
||||
|
||||
const auto usedVertsPerInstance = UsedVertsForTFDraw(mode, vertCount);
|
||||
const auto usedVerts = CheckedInt<uint32_t>(usedVertsPerInstance) * instanceCount;
|
||||
|
||||
const auto remainingCapacity = mTFO->mActive_VertCapacity - mTFO->mActive_VertPosition;
|
||||
if (!usedVerts.isValid() ||
|
||||
usedVerts.value() > remainingCapacity)
|
||||
{
|
||||
mWebGL->ErrorInvalidOperation("%s: Insufficient buffer capacity remaining for"
|
||||
" transform feedback.",
|
||||
funcName);
|
||||
*out_error = true;
|
||||
return;
|
||||
}
|
||||
|
||||
mUsedVerts = usedVerts.value();
|
||||
}
|
||||
|
||||
void Advance() const {
|
||||
if (!mWithTF)
|
||||
return;
|
||||
|
||||
mTFO->mActive_VertPosition += mUsedVerts;
|
||||
}
|
||||
};
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
void
|
||||
WebGLContext::DrawArrays(GLenum mode, GLint first, GLsizei count)
|
||||
WebGLContext::DrawArrays(GLenum mode, GLint first, GLsizei vertCount)
|
||||
{
|
||||
const char funcName[] = "drawArrays";
|
||||
if (IsContextLost())
|
||||
return;
|
||||
|
||||
if (!ValidateDrawModeEnum(mode, funcName))
|
||||
return;
|
||||
|
||||
MakeContextCurrent();
|
||||
|
||||
bool error;
|
||||
bool error = false;
|
||||
ScopedResolveTexturesForDraw scopedResolve(this, funcName, &error);
|
||||
if (error)
|
||||
return;
|
||||
|
||||
if (!DrawArrays_check(first, count, 1, funcName))
|
||||
const GLsizei instanceCount = 1;
|
||||
if (!DrawArrays_check(funcName, mode, first, vertCount, instanceCount))
|
||||
return;
|
||||
|
||||
RunContextLossTimer();
|
||||
const ScopedDrawHelper scopedHelper(this, funcName, first, vertCount, instanceCount, &error);
|
||||
if (error)
|
||||
return;
|
||||
|
||||
const ScopedDrawWithTransformFeedback scopedTF(this, funcName, mode, vertCount,
|
||||
instanceCount, &error);
|
||||
if (error)
|
||||
return;
|
||||
|
||||
{
|
||||
ScopedMaskWorkaround autoMask(*this);
|
||||
gl->fDrawArrays(mode, first, count);
|
||||
gl->fDrawArrays(mode, first, vertCount);
|
||||
}
|
||||
|
||||
Draw_cleanup(funcName);
|
||||
scopedTF.Advance();
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::DrawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei primcount)
|
||||
WebGLContext::DrawArraysInstanced(GLenum mode, GLint first, GLsizei vertCount,
|
||||
GLsizei instanceCount)
|
||||
{
|
||||
const char funcName[] = "drawArraysInstanced";
|
||||
if (IsContextLost())
|
||||
return;
|
||||
|
||||
if (!ValidateDrawModeEnum(mode, funcName))
|
||||
return;
|
||||
|
||||
MakeContextCurrent();
|
||||
|
||||
bool error;
|
||||
bool error = false;
|
||||
ScopedResolveTexturesForDraw scopedResolve(this, funcName, &error);
|
||||
if (error)
|
||||
return;
|
||||
|
||||
if (!DrawArrays_check(first, count, primcount, funcName))
|
||||
if (!DrawArrays_check(funcName, mode, first, vertCount, instanceCount))
|
||||
return;
|
||||
|
||||
if (!DrawInstanced_check(funcName))
|
||||
return;
|
||||
|
||||
RunContextLossTimer();
|
||||
const ScopedDrawHelper scopedHelper(this, funcName, first, vertCount, instanceCount, &error);
|
||||
if (error)
|
||||
return;
|
||||
|
||||
const ScopedDrawWithTransformFeedback scopedTF(this, funcName, mode, vertCount,
|
||||
instanceCount, &error);
|
||||
if (error)
|
||||
return;
|
||||
|
||||
{
|
||||
ScopedMaskWorkaround autoMask(*this);
|
||||
gl->fDrawArraysInstanced(mode, first, count, primcount);
|
||||
gl->fDrawArraysInstanced(mode, first, vertCount, instanceCount);
|
||||
}
|
||||
|
||||
Draw_cleanup(funcName);
|
||||
scopedTF.Advance();
|
||||
}
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
bool
|
||||
WebGLContext::DrawElements_check(GLsizei count, GLenum type,
|
||||
WebGLintptr byteOffset, GLsizei primcount,
|
||||
const char* info, GLuint* out_upperBound)
|
||||
WebGLContext::DrawElements_check(const char* funcName, GLenum mode, GLsizei vertCount,
|
||||
GLenum type, WebGLintptr byteOffset,
|
||||
GLsizei instanceCount)
|
||||
{
|
||||
if (count < 0 || byteOffset < 0) {
|
||||
ErrorInvalidValue("%s: negative count or offset", info);
|
||||
if (!ValidateDrawModeEnum(mode, funcName))
|
||||
return false;
|
||||
|
||||
if (mBoundTransformFeedback &&
|
||||
mBoundTransformFeedback->mIsActive &&
|
||||
!mBoundTransformFeedback->mIsPaused)
|
||||
{
|
||||
ErrorInvalidOperation("%s: DrawElements* functions are incompatible with"
|
||||
" transform feedback.",
|
||||
funcName);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (primcount < 0) {
|
||||
ErrorInvalidValue("%s: negative primcount", info);
|
||||
if (!ValidateNonNegative(funcName, "vertCount", vertCount) ||
|
||||
!ValidateNonNegative(funcName, "byteOffset", byteOffset) ||
|
||||
!ValidateNonNegative(funcName, "instanceCount", instanceCount))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ValidateStencilParamsForDrawCall()) {
|
||||
if (!ValidateStencilParamsForDrawCall())
|
||||
return false;
|
||||
}
|
||||
|
||||
// If count is 0, there's nothing to do.
|
||||
if (count == 0 || primcount == 0)
|
||||
return false;
|
||||
if (!vertCount || !instanceCount)
|
||||
return false; // No error, just early out.
|
||||
|
||||
uint8_t bytesPerElem = 0;
|
||||
switch (type) {
|
||||
@ -414,13 +584,13 @@ WebGLContext::DrawElements_check(GLsizei count, GLenum type,
|
||||
}
|
||||
|
||||
if (!bytesPerElem) {
|
||||
ErrorInvalidEnum("%s: Invalid `type`: 0x%04x", info, type);
|
||||
ErrorInvalidEnum("%s: Invalid `type`: 0x%04x", funcName, type);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (byteOffset % bytesPerElem != 0) {
|
||||
ErrorInvalidOperation("%s: `byteOffset` must be a multiple of the size of `type`",
|
||||
info);
|
||||
funcName);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -439,51 +609,49 @@ WebGLContext::DrawElements_check(GLsizei count, GLenum type,
|
||||
////
|
||||
|
||||
const GLsizei first = byteOffset / bytesPerElem;
|
||||
const CheckedUint32 checked_byteCount = bytesPerElem * CheckedUint32(count);
|
||||
const CheckedUint32 checked_byteCount = bytesPerElem * CheckedUint32(vertCount);
|
||||
|
||||
if (!checked_byteCount.isValid()) {
|
||||
ErrorInvalidValue("%s: overflow in byteCount", info);
|
||||
ErrorInvalidValue("%s: Overflow in byteCount.", funcName);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!mBoundVertexArray->mElementArrayBuffer) {
|
||||
ErrorInvalidOperation("%s: must have element array buffer binding", info);
|
||||
ErrorInvalidOperation("%s: Must have element array buffer binding.", funcName);
|
||||
return false;
|
||||
}
|
||||
|
||||
WebGLBuffer& elemArrayBuffer = *mBoundVertexArray->mElementArrayBuffer;
|
||||
|
||||
if (!elemArrayBuffer.ByteLength()) {
|
||||
ErrorInvalidOperation("%s: bound element array buffer doesn't have any data", info);
|
||||
ErrorInvalidOperation("%s: Bound element array buffer doesn't have any data.",
|
||||
funcName);
|
||||
return false;
|
||||
}
|
||||
|
||||
CheckedInt<GLsizei> checked_neededByteCount = checked_byteCount.toChecked<GLsizei>() + byteOffset;
|
||||
|
||||
if (!checked_neededByteCount.isValid()) {
|
||||
ErrorInvalidOperation("%s: overflow in byteOffset+byteCount", info);
|
||||
ErrorInvalidOperation("%s: Overflow in byteOffset+byteCount.", funcName);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (uint32_t(checked_neededByteCount.value()) > elemArrayBuffer.ByteLength()) {
|
||||
ErrorInvalidOperation("%s: bound element array buffer is too small for given count and offset", info);
|
||||
ErrorInvalidOperation("%s: Bound element array buffer is too small for given"
|
||||
" count and offset.",
|
||||
funcName);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ValidateBufferFetching(info))
|
||||
if (!ValidateBufferFetching(funcName))
|
||||
return false;
|
||||
|
||||
if (!mMaxFetchedVertices ||
|
||||
!elemArrayBuffer.Validate(type, mMaxFetchedVertices - 1, first, count, out_upperBound))
|
||||
!elemArrayBuffer.Validate(type, mMaxFetchedVertices - 1, first, vertCount))
|
||||
{
|
||||
ErrorInvalidOperation(
|
||||
"%s: bound vertex attribute buffers do not have sufficient "
|
||||
"size for given indices from the bound element array", info);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (uint32_t(primcount) > mMaxFetchedInstances) {
|
||||
ErrorInvalidOperation("%s: bound instance attribute buffers do not have sufficient size for given primcount", info);
|
||||
ErrorInvalidOperation("%s: bound vertex attribute buffers do not have sufficient "
|
||||
"size for given indices from the bound element array",
|
||||
funcName);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -491,106 +659,86 @@ WebGLContext::DrawElements_check(GLsizei count, GLenum type,
|
||||
if (elemArrayBuffer.IsElementArrayUsedWithMultipleTypes()) {
|
||||
GenerateWarning("%s: bound element array buffer previously used with a type other than "
|
||||
"%s, this will affect performance.",
|
||||
info,
|
||||
WebGLContext::EnumName(type));
|
||||
}
|
||||
|
||||
MOZ_ASSERT(gl->IsCurrent());
|
||||
|
||||
if (mBoundDrawFramebuffer) {
|
||||
if (!mBoundDrawFramebuffer->ValidateAndInitAttachments(info))
|
||||
return false;
|
||||
} else {
|
||||
ClearBackbufferIfNeeded();
|
||||
}
|
||||
|
||||
if (!DoFakeVertexAttrib0(mMaxFetchedVertices)) {
|
||||
return false;
|
||||
funcName, WebGLContext::EnumName(type));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::DrawElements(GLenum mode, GLsizei count, GLenum type,
|
||||
WebGLContext::DrawElements(GLenum mode, GLsizei vertCount, GLenum type,
|
||||
WebGLintptr byteOffset)
|
||||
{
|
||||
const char funcName[] = "drawElements";
|
||||
if (IsContextLost())
|
||||
return;
|
||||
|
||||
if (!ValidateDrawModeEnum(mode, funcName))
|
||||
return;
|
||||
|
||||
MakeContextCurrent();
|
||||
|
||||
bool error;
|
||||
bool error = false;
|
||||
ScopedResolveTexturesForDraw scopedResolve(this, funcName, &error);
|
||||
if (error)
|
||||
return;
|
||||
|
||||
GLuint upperBound = 0;
|
||||
if (!DrawElements_check(count, type, byteOffset, 1, funcName, &upperBound))
|
||||
const GLsizei instanceCount = 1;
|
||||
if (!DrawElements_check(funcName, mode, vertCount, type, byteOffset, instanceCount))
|
||||
return;
|
||||
|
||||
RunContextLossTimer();
|
||||
const ScopedDrawHelper scopedHelper(this, funcName, 0, mMaxFetchedVertices, instanceCount,
|
||||
&error);
|
||||
if (error)
|
||||
return;
|
||||
|
||||
{
|
||||
ScopedMaskWorkaround autoMask(*this);
|
||||
|
||||
if (gl->IsSupported(gl::GLFeature::draw_range_elements)) {
|
||||
gl->fDrawRangeElements(mode, 0, upperBound, count, type,
|
||||
reinterpret_cast<GLvoid*>(byteOffset));
|
||||
} else {
|
||||
gl->fDrawElements(mode, count, type,
|
||||
reinterpret_cast<GLvoid*>(byteOffset));
|
||||
}
|
||||
gl->fDrawElements(mode, vertCount, type,
|
||||
reinterpret_cast<GLvoid*>(byteOffset));
|
||||
}
|
||||
|
||||
Draw_cleanup(funcName);
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::DrawElementsInstanced(GLenum mode, GLsizei count, GLenum type,
|
||||
WebGLintptr byteOffset, GLsizei primcount)
|
||||
WebGLContext::DrawElementsInstanced(GLenum mode, GLsizei vertCount, GLenum type,
|
||||
WebGLintptr byteOffset, GLsizei instanceCount)
|
||||
{
|
||||
const char funcName[] = "drawElementsInstanced";
|
||||
if (IsContextLost())
|
||||
return;
|
||||
|
||||
if (!ValidateDrawModeEnum(mode, funcName))
|
||||
return;
|
||||
|
||||
MakeContextCurrent();
|
||||
|
||||
bool error;
|
||||
bool error = false;
|
||||
ScopedResolveTexturesForDraw scopedResolve(this, funcName, &error);
|
||||
if (error)
|
||||
return;
|
||||
|
||||
GLuint upperBound = 0;
|
||||
if (!DrawElements_check(count, type, byteOffset, primcount, funcName, &upperBound))
|
||||
if (!DrawElements_check(funcName, mode, vertCount, type, byteOffset, instanceCount))
|
||||
return;
|
||||
|
||||
if (!DrawInstanced_check(funcName))
|
||||
return;
|
||||
|
||||
RunContextLossTimer();
|
||||
const ScopedDrawHelper scopedHelper(this, funcName, 0, mMaxFetchedVertices, instanceCount,
|
||||
&error);
|
||||
if (error)
|
||||
return;
|
||||
|
||||
{
|
||||
ScopedMaskWorkaround autoMask(*this);
|
||||
gl->fDrawElementsInstanced(mode, count, type,
|
||||
gl->fDrawElementsInstanced(mode, vertCount, type,
|
||||
reinterpret_cast<GLvoid*>(byteOffset),
|
||||
primcount);
|
||||
instanceCount);
|
||||
}
|
||||
|
||||
Draw_cleanup(funcName);
|
||||
}
|
||||
|
||||
void WebGLContext::Draw_cleanup(const char* funcName)
|
||||
{
|
||||
UndoFakeVertexAttrib0();
|
||||
////////////////////////////////////////
|
||||
|
||||
void
|
||||
WebGLContext::Draw_cleanup(const char* funcName)
|
||||
{
|
||||
if (!mBoundDrawFramebuffer) {
|
||||
Invalidate();
|
||||
mShouldPresent = true;
|
||||
@ -614,9 +762,12 @@ void WebGLContext::Draw_cleanup(const char* funcName)
|
||||
uint32_t destHeight = mViewportHeight;
|
||||
|
||||
if (mBoundDrawFramebuffer) {
|
||||
const auto& fba = mBoundDrawFramebuffer->ColorAttachment(0);
|
||||
if (fba.IsDefined()) {
|
||||
fba.Size(&destWidth, &destHeight);
|
||||
const auto& drawBuffers = mBoundDrawFramebuffer->ColorDrawBuffers();
|
||||
for (const auto& cur : drawBuffers) {
|
||||
if (!cur->IsDefined())
|
||||
continue;
|
||||
cur->Size(&destWidth, &destHeight);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
destWidth = mWidth;
|
||||
|
@ -144,76 +144,37 @@ WebGLContext::DrawBuffers(const dom::Sequence<GLenum>& buffers)
|
||||
if (IsContextLost())
|
||||
return;
|
||||
|
||||
if (!mBoundDrawFramebuffer) {
|
||||
// GLES 3.0.4 p186:
|
||||
// "If the GL is bound to the default framebuffer, then `n` must be 1 and the
|
||||
// constant must be BACK or NONE. [...] If DrawBuffers is supplied with a
|
||||
// constant other than BACK and NONE, or with a value of `n` other than 1, the
|
||||
// error INVALID_OPERATION is generated."
|
||||
if (buffers.Length() != 1) {
|
||||
ErrorInvalidOperation("%s: For the default framebuffer, `buffers` must have a"
|
||||
" length of 1.",
|
||||
funcName);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (buffers[0]) {
|
||||
case LOCAL_GL_NONE:
|
||||
case LOCAL_GL_BACK:
|
||||
break;
|
||||
|
||||
default:
|
||||
ErrorInvalidOperation("%s: For the default framebuffer, `buffers[0]` must be"
|
||||
" BACK or NONE.",
|
||||
funcName);
|
||||
return;
|
||||
}
|
||||
|
||||
mDefaultFB_DrawBuffer0 = buffers[0];
|
||||
gl->Screen()->SetDrawBuffer(buffers[0]);
|
||||
if (mBoundDrawFramebuffer) {
|
||||
mBoundDrawFramebuffer->DrawBuffers(funcName, buffers);
|
||||
return;
|
||||
}
|
||||
|
||||
// Framebuffer object (not default framebuffer)
|
||||
|
||||
if (buffers.Length() > mImplMaxDrawBuffers) {
|
||||
// "An INVALID_VALUE error is generated if `n` is greater than MAX_DRAW_BUFFERS."
|
||||
ErrorInvalidValue("%s: `buffers` must have a length <= MAX_DRAW_BUFFERS.",
|
||||
funcName);
|
||||
// GLES 3.0.4 p186:
|
||||
// "If the GL is bound to the default framebuffer, then `n` must be 1 and the
|
||||
// constant must be BACK or NONE. [...] If DrawBuffers is supplied with a
|
||||
// constant other than BACK and NONE, or with a value of `n` other than 1, the
|
||||
// error INVALID_OPERATION is generated."
|
||||
if (buffers.Length() != 1) {
|
||||
ErrorInvalidOperation("%s: For the default framebuffer, `buffers` must have a"
|
||||
" length of 1.",
|
||||
funcName);
|
||||
return;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < buffers.Length(); i++) {
|
||||
// "If the GL is bound to a draw framebuffer object, the `i`th buffer listed in
|
||||
// bufs must be COLOR_ATTACHMENTi or NONE. Specifying a buffer out of order,
|
||||
// BACK, or COLOR_ATTACHMENTm where `m` is greater than or equal to the value of
|
||||
// MAX_COLOR_ATTACHMENTS, will generate the error INVALID_OPERATION.
|
||||
switch (buffers[0]) {
|
||||
case LOCAL_GL_NONE:
|
||||
case LOCAL_GL_BACK:
|
||||
break;
|
||||
|
||||
// WEBGL_draw_buffers:
|
||||
// "The value of the MAX_COLOR_ATTACHMENTS_WEBGL parameter must be greater than or
|
||||
// equal to that of the MAX_DRAW_BUFFERS_WEBGL parameter."
|
||||
// This means that if buffers.Length() isn't larger than MaxDrawBuffers, it won't
|
||||
// be larger than MaxColorAttachments.
|
||||
if (buffers[i] != LOCAL_GL_NONE &&
|
||||
buffers[i] != LOCAL_GL_COLOR_ATTACHMENT0 + i)
|
||||
{
|
||||
ErrorInvalidOperation("%s: `buffers[i]` must be NONE or COLOR_ATTACHMENTi.",
|
||||
funcName);
|
||||
return;
|
||||
}
|
||||
default:
|
||||
ErrorInvalidOperation("%s: For the default framebuffer, `buffers[0]` must be"
|
||||
" BACK or NONE.",
|
||||
funcName);
|
||||
return;
|
||||
}
|
||||
|
||||
MakeContextCurrent();
|
||||
|
||||
const GLenum* ptr = nullptr;
|
||||
if (buffers.Length()) {
|
||||
ptr = buffers.Elements();
|
||||
}
|
||||
|
||||
gl->fDrawBuffers(buffers.Length(), ptr);
|
||||
|
||||
const auto end = ptr + buffers.Length();
|
||||
mBoundDrawFramebuffer->mDrawBuffers.assign(ptr, end);
|
||||
mDefaultFB_DrawBuffer0 = buffers[0];
|
||||
gl->Screen()->SetDrawBuffer(buffers[0]);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -252,10 +252,11 @@ WebGLContext::BlendFuncSeparate(GLenum srcRGB, GLenum dstRGB,
|
||||
GLenum
|
||||
WebGLContext::CheckFramebufferStatus(GLenum target)
|
||||
{
|
||||
const char funcName[] = "checkFramebufferStatus";
|
||||
if (IsContextLost())
|
||||
return LOCAL_GL_FRAMEBUFFER_UNSUPPORTED;
|
||||
|
||||
if (!ValidateFramebufferTarget(target, "invalidateFramebuffer"))
|
||||
if (!ValidateFramebufferTarget(target, funcName))
|
||||
return 0;
|
||||
|
||||
WebGLFramebuffer* fb;
|
||||
@ -276,8 +277,7 @@ WebGLContext::CheckFramebufferStatus(GLenum target)
|
||||
if (!fb)
|
||||
return LOCAL_GL_FRAMEBUFFER_COMPLETE;
|
||||
|
||||
nsCString fbErrorInfo;
|
||||
return fb->CheckFramebufferStatus(&fbErrorInfo).get();
|
||||
return fb->CheckFramebufferStatus(funcName).get();
|
||||
}
|
||||
|
||||
already_AddRefed<WebGLProgram>
|
||||
@ -484,10 +484,11 @@ void
|
||||
WebGLContext::FramebufferRenderbuffer(GLenum target, GLenum attachment,
|
||||
GLenum rbtarget, WebGLRenderbuffer* wrb)
|
||||
{
|
||||
const char funcName[] = "framebufferRenderbuffer";
|
||||
if (IsContextLost())
|
||||
return;
|
||||
|
||||
if (!ValidateFramebufferTarget(target, "framebufferRenderbuffer"))
|
||||
if (!ValidateFramebufferTarget(target, funcName))
|
||||
return;
|
||||
|
||||
WebGLFramebuffer* fb;
|
||||
@ -505,20 +506,10 @@ WebGLContext::FramebufferRenderbuffer(GLenum target, GLenum attachment,
|
||||
MOZ_CRASH("GFX: Bad target.");
|
||||
}
|
||||
|
||||
if (!fb) {
|
||||
return ErrorInvalidOperation("framebufferRenderbuffer: cannot modify"
|
||||
" framebuffer 0.");
|
||||
}
|
||||
if (!fb)
|
||||
return ErrorInvalidOperation("%s: Cannot modify framebuffer 0.", funcName);
|
||||
|
||||
if (rbtarget != LOCAL_GL_RENDERBUFFER) {
|
||||
return ErrorInvalidEnumInfo("framebufferRenderbuffer: rbtarget:",
|
||||
rbtarget);
|
||||
}
|
||||
|
||||
if (!ValidateFramebufferAttachment(fb, attachment, "framebufferRenderbuffer"))
|
||||
return;
|
||||
|
||||
fb->FramebufferRenderbuffer(attachment, rbtarget, wrb);
|
||||
fb->FramebufferRenderbuffer(funcName, attachment, rbtarget, wrb);
|
||||
}
|
||||
|
||||
void
|
||||
@ -528,57 +519,13 @@ WebGLContext::FramebufferTexture2D(GLenum target,
|
||||
WebGLTexture* tobj,
|
||||
GLint level)
|
||||
{
|
||||
const char funcName[] = "framebufferTexture2D";
|
||||
if (IsContextLost())
|
||||
return;
|
||||
|
||||
if (!ValidateFramebufferTarget(target, "framebufferTexture2D"))
|
||||
if (!ValidateFramebufferTarget(target, funcName))
|
||||
return;
|
||||
|
||||
if (level < 0) {
|
||||
ErrorInvalidValue("framebufferTexture2D: level must not be negative.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (textarget != LOCAL_GL_TEXTURE_2D &&
|
||||
(textarget < LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X ||
|
||||
textarget > LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z))
|
||||
{
|
||||
return ErrorInvalidEnumInfo("framebufferTexture2D: textarget:",
|
||||
textarget);
|
||||
}
|
||||
|
||||
if (IsWebGL2()) {
|
||||
/* GLES 3.0.4 p208:
|
||||
* If textarget is one of TEXTURE_CUBE_MAP_POSITIVE_X,
|
||||
* TEXTURE_CUBE_MAP_POSITIVE_Y, TEXTURE_CUBE_MAP_POSITIVE_Z,
|
||||
* TEXTURE_CUBE_MAP_NEGATIVE_X, TEXTURE_CUBE_MAP_NEGATIVE_Y,
|
||||
* or TEXTURE_CUBE_MAP_NEGATIVE_Z, then level must be greater
|
||||
* than or equal to zero and less than or equal to log2 of the
|
||||
* value of MAX_CUBE_MAP_TEXTURE_SIZE. If textarget is TEXTURE_2D,
|
||||
* level must be greater than or equal to zero and no larger than
|
||||
* log2 of the value of MAX_TEXTURE_SIZE. Otherwise, an
|
||||
* INVALID_VALUE error is generated.
|
||||
*/
|
||||
|
||||
if (textarget == LOCAL_GL_TEXTURE_2D) {
|
||||
if (uint32_t(level) > FloorLog2(mImplMaxTextureSize)) {
|
||||
ErrorInvalidValue("framebufferTexture2D: level is too large.");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
MOZ_ASSERT(textarget >= LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X &&
|
||||
textarget <= LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z);
|
||||
|
||||
if (uint32_t(level) > FloorLog2(mImplMaxCubeMapTextureSize)) {
|
||||
ErrorInvalidValue("framebufferTexture2D: level is too large.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else if (level != 0) {
|
||||
ErrorInvalidValue("framebufferTexture2D: level must be 0.");
|
||||
return;
|
||||
}
|
||||
|
||||
WebGLFramebuffer* fb;
|
||||
switch (target) {
|
||||
case LOCAL_GL_FRAMEBUFFER:
|
||||
@ -594,15 +541,10 @@ WebGLContext::FramebufferTexture2D(GLenum target,
|
||||
MOZ_CRASH("GFX: Bad target.");
|
||||
}
|
||||
|
||||
if (!fb) {
|
||||
return ErrorInvalidOperation("framebufferTexture2D: cannot modify"
|
||||
" framebuffer 0.");
|
||||
}
|
||||
if (!fb)
|
||||
return ErrorInvalidOperation("%s: Cannot modify framebuffer 0.", funcName);
|
||||
|
||||
if (!ValidateFramebufferAttachment(fb, attachment, "framebufferTexture2D"))
|
||||
return;
|
||||
|
||||
fb->FramebufferTexture2D(attachment, textarget, tobj, level);
|
||||
fb->FramebufferTexture2D(funcName, attachment, textarget, tobj, level);
|
||||
}
|
||||
|
||||
void
|
||||
@ -684,15 +626,10 @@ WebGLContext::GetBufferParameter(GLenum target, GLenum pname)
|
||||
if (IsContextLost())
|
||||
return JS::NullValue();
|
||||
|
||||
if (!ValidateBufferTarget(target, "getBufferParameter"))
|
||||
const auto& buffer = ValidateBufferSelection("getBufferParameter", target);
|
||||
if (!buffer)
|
||||
return JS::NullValue();
|
||||
|
||||
WebGLRefPtr<WebGLBuffer>& slot = GetBufferSlotByTarget(target);
|
||||
if (!slot) {
|
||||
ErrorInvalidOperation("No buffer bound to `target` (0x%4x).", target);
|
||||
return JS::NullValue();
|
||||
}
|
||||
|
||||
MakeContextCurrent();
|
||||
|
||||
switch (pname) {
|
||||
@ -1557,6 +1494,13 @@ WebGL2Context::ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenu
|
||||
return;
|
||||
}
|
||||
|
||||
if (mBoundPixelPackBuffer->mNumActiveTFOs) {
|
||||
ErrorInvalidOperation("%s: Buffer is bound to an active transform feedback"
|
||||
" object.",
|
||||
"readPixels");
|
||||
return;
|
||||
}
|
||||
|
||||
//////
|
||||
|
||||
if (offset < 0) {
|
||||
|
@ -7,7 +7,6 @@
|
||||
#include "WebGLContextUnchecked.h"
|
||||
|
||||
#include "GLContext.h"
|
||||
#include "WebGLBuffer.h"
|
||||
#include "WebGLSampler.h"
|
||||
|
||||
namespace mozilla {
|
||||
@ -17,50 +16,6 @@ WebGLContextUnchecked::WebGLContextUnchecked(gl::GLContext* _gl)
|
||||
, gl(mGL_OnlyClearInDestroyResourcesAndContext) // const reference
|
||||
{ }
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Buffer Objects
|
||||
|
||||
void
|
||||
WebGLContextUnchecked::BindBuffer(GLenum target, WebGLBuffer* buffer)
|
||||
{
|
||||
gl->MakeCurrent();
|
||||
gl->fBindBuffer(target, buffer ? buffer->mGLName : 0);
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContextUnchecked::BindBufferBase(GLenum target, GLuint index, WebGLBuffer* buffer)
|
||||
{
|
||||
gl->MakeCurrent();
|
||||
gl->fBindBufferBase(target, index, buffer ? buffer->mGLName : 0);
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContextUnchecked::BindBufferRange(GLenum target, GLuint index, WebGLBuffer* buffer, WebGLintptr offset, WebGLsizeiptr size)
|
||||
{
|
||||
gl->MakeCurrent();
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
if (buffer && buffer->Content() == WebGLBuffer::Kind::Undefined &&
|
||||
gl->WorkAroundDriverBugs())
|
||||
{
|
||||
// BindBufferRange will fail if the buffer's contents is undefined.
|
||||
// Bind so driver initializes the buffer.
|
||||
gl->fBindBuffer(target, buffer->mGLName);
|
||||
}
|
||||
#endif
|
||||
|
||||
gl->fBindBufferRange(target, index, buffer ? buffer->mGLName : 0, offset, size);
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContextUnchecked::CopyBufferSubData(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size)
|
||||
{
|
||||
gl->MakeCurrent();
|
||||
gl->fCopyBufferSubData(readTarget, writeTarget, readOffset, writeOffset, size);
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Sampler Objects
|
||||
|
||||
|
@ -20,13 +20,6 @@ class WebGLContextUnchecked
|
||||
public:
|
||||
explicit WebGLContextUnchecked(gl::GLContext* gl);
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Buffer Objects
|
||||
void BindBuffer(GLenum target, WebGLBuffer* buffer);
|
||||
void BindBufferBase(GLenum target, GLuint index, WebGLBuffer* buffer);
|
||||
void BindBufferRange(GLenum taret, GLuint index, WebGLBuffer* buffer, WebGLintptr offset, WebGLsizeiptr size);
|
||||
void CopyBufferSubData(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size);
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Sampler Objects
|
||||
void BindSampler(GLuint unit, WebGLSampler* sampler);
|
||||
|
@ -122,36 +122,11 @@ WebGLContext::ValidateBlendFuncEnumsCompatibility(GLenum sfactor,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
WebGLContext::ValidateDataOffsetSize(WebGLintptr offset, WebGLsizeiptr size, WebGLsizeiptr bufferSize, const char* info)
|
||||
{
|
||||
if (offset < 0) {
|
||||
ErrorInvalidValue("%s: offset must be positive", info);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (size < 0) {
|
||||
ErrorInvalidValue("%s: size must be positive", info);
|
||||
return false;
|
||||
}
|
||||
|
||||
// *** Careful *** WebGLsizeiptr is always 64-bits but GLsizeiptr
|
||||
// is like intptr_t. On some platforms it is 32-bits.
|
||||
CheckedInt<GLsizeiptr> neededBytes = CheckedInt<GLsizeiptr>(offset) + size;
|
||||
if (!neededBytes.isValid() || neededBytes.value() > bufferSize) {
|
||||
ErrorInvalidValue("%s: invalid range", info);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check data ranges [readOffset, readOffset + size] and [writeOffset,
|
||||
* writeOffset + size] for overlap.
|
||||
*
|
||||
* It is assumed that offset and size have already been validated with
|
||||
* ValidateDataOffsetSize().
|
||||
* It is assumed that offset and size have already been validated.
|
||||
*/
|
||||
bool
|
||||
WebGLContext::ValidateDataRanges(WebGLintptr readOffset, WebGLintptr writeOffset, WebGLsizeiptr size, const char* info)
|
||||
@ -738,7 +713,6 @@ WebGLContext::InitAndValidateGL(FailureReason* const out_failReason)
|
||||
mBoundSamplers.Clear();
|
||||
|
||||
mBoundArrayBuffer = nullptr;
|
||||
mBoundTransformFeedbackBuffer = nullptr;
|
||||
mCurrentProgram = nullptr;
|
||||
|
||||
mBoundDrawFramebuffer = nullptr;
|
||||
@ -980,7 +954,6 @@ WebGLContext::InitAndValidateGL(FailureReason* const out_failReason)
|
||||
// vertex array object (the name zero) is also deprecated. [...]"
|
||||
|
||||
if (gl->IsCoreProfile()) {
|
||||
MakeContextCurrent();
|
||||
mDefaultVertexArray->GenVertexArray();
|
||||
mDefaultVertexArray->BindVertexArray();
|
||||
}
|
||||
|
@ -15,16 +15,6 @@
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
static void
|
||||
UpdateUpperBound(uint32_t* const out_upperBound, uint32_t newBound)
|
||||
{
|
||||
MOZ_ASSERT(out_upperBound);
|
||||
// Move *out_upperBound to a local variable to work around a false positive
|
||||
// -Wuninitialized gcc warning about std::max() in PGO builds.
|
||||
uint32_t upperBound = *out_upperBound;
|
||||
*out_upperBound = std::max(upperBound, newBound);
|
||||
}
|
||||
|
||||
/* WebGLElementArrayCacheTree contains most of the implementation of
|
||||
* WebGLElementArrayCache, which performs WebGL element array buffer validation
|
||||
* for drawElements.
|
||||
@ -245,8 +235,7 @@ public:
|
||||
return ((numElements - 1) | kElementsPerLeafMask) + 1;
|
||||
}
|
||||
|
||||
bool Validate(T maxAllowed, size_t firstLeaf, size_t lastLeaf,
|
||||
uint32_t* const out_upperBound)
|
||||
bool Validate(T maxAllowed, size_t firstLeaf, size_t lastLeaf)
|
||||
{
|
||||
size_t firstTreeIndex = TreeIndexForLeaf(firstLeaf);
|
||||
size_t lastTreeIndex = TreeIndexForLeaf(lastLeaf);
|
||||
@ -260,7 +249,6 @@ public:
|
||||
// current tree level:
|
||||
if (lastTreeIndex == firstTreeIndex) {
|
||||
const T& curData = mTreeData[firstTreeIndex];
|
||||
UpdateUpperBound(out_upperBound, curData);
|
||||
return curData <= maxAllowed;
|
||||
}
|
||||
|
||||
@ -269,7 +257,6 @@ public:
|
||||
// a left node.
|
||||
if (IsRightNode(firstTreeIndex)) {
|
||||
const T& curData = mTreeData[firstTreeIndex];
|
||||
UpdateUpperBound(out_upperBound, curData);
|
||||
if (curData > maxAllowed)
|
||||
return false;
|
||||
|
||||
@ -281,7 +268,6 @@ public:
|
||||
// right node.
|
||||
if (IsLeftNode(lastTreeIndex)) {
|
||||
const T& curData = mTreeData[lastTreeIndex];
|
||||
UpdateUpperBound(out_upperBound, curData);
|
||||
if (curData > maxAllowed)
|
||||
return false;
|
||||
|
||||
@ -514,18 +500,13 @@ WebGLElementArrayCache::UpdateTrees(size_t firstByte, size_t lastByte)
|
||||
template<typename T>
|
||||
bool
|
||||
WebGLElementArrayCache::Validate(uint32_t maxAllowed, size_t firstElement,
|
||||
size_t countElements,
|
||||
uint32_t* const out_upperBound)
|
||||
size_t countElements)
|
||||
{
|
||||
*out_upperBound = 0;
|
||||
|
||||
// If maxAllowed is >= the max T value, then there is no way that a T index
|
||||
// could be invalid.
|
||||
uint32_t maxTSize = std::numeric_limits<T>::max();
|
||||
if (maxAllowed >= maxTSize) {
|
||||
UpdateUpperBound(out_upperBound, maxTSize);
|
||||
if (maxAllowed >= maxTSize)
|
||||
return true;
|
||||
}
|
||||
|
||||
T maxAllowedT(maxAllowed);
|
||||
|
||||
@ -556,10 +537,8 @@ WebGLElementArrayCache::Validate(uint32_t maxAllowed, size_t firstElement,
|
||||
// Fast-exit path when the global maximum for the whole element array buffer
|
||||
// falls in the allowed range:
|
||||
T globalMax = tree->GlobalMaximum();
|
||||
if (globalMax <= maxAllowedT) {
|
||||
UpdateUpperBound(out_upperBound, globalMax);
|
||||
if (globalMax <= maxAllowedT)
|
||||
return true;
|
||||
}
|
||||
|
||||
const T* elements = Elements<T>();
|
||||
|
||||
@ -570,7 +549,6 @@ WebGLElementArrayCache::Validate(uint32_t maxAllowed, size_t firstElement,
|
||||
tree->LastElementUnderSameLeaf(firstElement));
|
||||
while (firstElement <= firstElementAdjustmentEnd) {
|
||||
const T& curData = elements[firstElement];
|
||||
UpdateUpperBound(out_upperBound, curData);
|
||||
if (curData > maxAllowedT)
|
||||
return false;
|
||||
|
||||
@ -580,7 +558,6 @@ WebGLElementArrayCache::Validate(uint32_t maxAllowed, size_t firstElement,
|
||||
tree->FirstElementUnderSameLeaf(lastElement));
|
||||
while (lastElement >= lastElementAdjustmentEnd) {
|
||||
const T& curData = elements[lastElement];
|
||||
UpdateUpperBound(out_upperBound, curData);
|
||||
if (curData > maxAllowedT)
|
||||
return false;
|
||||
|
||||
@ -593,23 +570,19 @@ WebGLElementArrayCache::Validate(uint32_t maxAllowed, size_t firstElement,
|
||||
|
||||
// general case
|
||||
return tree->Validate(maxAllowedT, tree->LeafForElement(firstElement),
|
||||
tree->LeafForElement(lastElement), out_upperBound);
|
||||
tree->LeafForElement(lastElement));
|
||||
}
|
||||
|
||||
bool
|
||||
WebGLElementArrayCache::Validate(GLenum type, uint32_t maxAllowed,
|
||||
size_t firstElement, size_t countElements,
|
||||
uint32_t* const out_upperBound)
|
||||
size_t firstElement, size_t countElements)
|
||||
{
|
||||
if (type == LOCAL_GL_UNSIGNED_BYTE)
|
||||
return Validate<uint8_t>(maxAllowed, firstElement, countElements,
|
||||
out_upperBound);
|
||||
return Validate<uint8_t>(maxAllowed, firstElement, countElements);
|
||||
if (type == LOCAL_GL_UNSIGNED_SHORT)
|
||||
return Validate<uint16_t>(maxAllowed, firstElement, countElements,
|
||||
out_upperBound);
|
||||
return Validate<uint16_t>(maxAllowed, firstElement, countElements);
|
||||
if (type == LOCAL_GL_UNSIGNED_INT)
|
||||
return Validate<uint32_t>(maxAllowed, firstElement, countElements,
|
||||
out_upperBound);
|
||||
return Validate<uint32_t>(maxAllowed, firstElement, countElements);
|
||||
|
||||
MOZ_ASSERT(false, "Invalid type.");
|
||||
return false;
|
||||
|
@ -37,8 +37,7 @@ public:
|
||||
bool BufferData(const void* ptr, size_t byteLength);
|
||||
bool BufferSubData(size_t pos, const void* ptr, size_t updateByteSize);
|
||||
|
||||
bool Validate(GLenum type, uint32_t maxAllowed, size_t first, size_t count,
|
||||
uint32_t* const out_upperBound);
|
||||
bool Validate(GLenum type, uint32_t maxAllowed, size_t first, size_t count);
|
||||
|
||||
template<typename T>
|
||||
T Element(size_t i) const { return Elements<T>()[i]; }
|
||||
@ -74,8 +73,7 @@ private:
|
||||
* than maxAllowed.
|
||||
*/
|
||||
template<typename T>
|
||||
bool Validate(uint32_t maxAllowed, size_t first, size_t count,
|
||||
uint32_t* const out_upperBound);
|
||||
bool Validate(uint32_t maxAllowed, size_t first, size_t count);
|
||||
|
||||
template<typename T>
|
||||
const T* Elements() const {
|
||||
|
@ -27,31 +27,34 @@ class WebGLTexture;
|
||||
template<typename T>
|
||||
class PlacementArray;
|
||||
|
||||
class WebGLFBAttachPoint
|
||||
namespace gl {
|
||||
class GLContext;
|
||||
} // namespace gl
|
||||
|
||||
class WebGLFBAttachPoint final
|
||||
{
|
||||
friend class WebGLFramebuffer;
|
||||
public:
|
||||
WebGLFramebuffer* const mFB;
|
||||
const GLenum mAttachmentPoint;
|
||||
private:
|
||||
|
||||
protected:
|
||||
WebGLRefPtr<WebGLTexture> mTexturePtr;
|
||||
WebGLRefPtr<WebGLRenderbuffer> mRenderbufferPtr;
|
||||
TexImageTarget mTexImageTarget;
|
||||
GLint mTexImageLayer;
|
||||
uint32_t mTexImageLevel;
|
||||
|
||||
// PlacementArray needs a default constructor.
|
||||
template<typename T>
|
||||
friend class PlacementArray;
|
||||
////
|
||||
|
||||
WebGLFBAttachPoint()
|
||||
: mFB(nullptr)
|
||||
, mAttachmentPoint(0)
|
||||
{ }
|
||||
WebGLFBAttachPoint();
|
||||
WebGLFBAttachPoint(WebGLFramebuffer* fb, GLenum attachmentPoint);
|
||||
|
||||
public:
|
||||
WebGLFBAttachPoint(WebGLFramebuffer* fb, GLenum attachmentPoint);
|
||||
~WebGLFBAttachPoint();
|
||||
|
||||
////
|
||||
|
||||
void Unlink();
|
||||
|
||||
bool IsDefined() const;
|
||||
@ -65,23 +68,13 @@ public:
|
||||
|
||||
void Clear();
|
||||
|
||||
void SetTexImage(WebGLTexture* tex, TexImageTarget target, GLint level);
|
||||
void SetTexImageLayer(WebGLTexture* tex, TexImageTarget target, GLint level,
|
||||
GLint layer);
|
||||
void SetTexImage(WebGLTexture* tex, TexImageTarget target, GLint level,
|
||||
GLint layer = 0);
|
||||
void SetRenderbuffer(WebGLRenderbuffer* rb);
|
||||
|
||||
const WebGLTexture* Texture() const {
|
||||
return mTexturePtr;
|
||||
}
|
||||
WebGLTexture* Texture() {
|
||||
return mTexturePtr;
|
||||
}
|
||||
const WebGLRenderbuffer* Renderbuffer() const {
|
||||
return mRenderbufferPtr;
|
||||
}
|
||||
WebGLRenderbuffer* Renderbuffer() {
|
||||
return mRenderbufferPtr;
|
||||
}
|
||||
WebGLTexture* Texture() const { return mTexturePtr; }
|
||||
WebGLRenderbuffer* Renderbuffer() const { return mRenderbufferPtr; }
|
||||
|
||||
TexImageTarget ImageTarget() const {
|
||||
return mTexImageTarget;
|
||||
}
|
||||
@ -94,69 +87,45 @@ public:
|
||||
void AttachmentName(nsCString* out) const;
|
||||
|
||||
bool HasUninitializedImageData() const;
|
||||
void SetImageDataStatus(WebGLImageDataStatus x);
|
||||
void SetImageDataStatus(WebGLImageDataStatus x) const;
|
||||
|
||||
void Size(uint32_t* const out_width, uint32_t* const out_height) const;
|
||||
|
||||
bool HasImage() const;
|
||||
bool IsComplete(WebGLContext* webgl, nsCString* const out_info) const;
|
||||
|
||||
void FinalizeAttachment(gl::GLContext* gl, GLenum attachmentLoc) const;
|
||||
void Resolve(gl::GLContext* gl) const;
|
||||
|
||||
JS::Value GetParameter(const char* funcName, WebGLContext* webgl, JSContext* cx,
|
||||
GLenum target, GLenum attachment, GLenum pname,
|
||||
ErrorResult* const out_error);
|
||||
ErrorResult* const out_error) const;
|
||||
|
||||
void OnBackingStoreRespecified() const;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class PlacementArray
|
||||
{
|
||||
public:
|
||||
const size_t mCapacity;
|
||||
protected:
|
||||
size_t mSize;
|
||||
T* const mArray;
|
||||
////
|
||||
|
||||
public:
|
||||
explicit PlacementArray(size_t capacity)
|
||||
: mCapacity(capacity)
|
||||
, mSize(0)
|
||||
, mArray((T*)moz_xmalloc(sizeof(T) * capacity))
|
||||
{ }
|
||||
struct Ordered {
|
||||
const WebGLFBAttachPoint& mRef;
|
||||
|
||||
~PlacementArray() {
|
||||
for (auto& cur : *this) {
|
||||
cur.~T();
|
||||
explicit Ordered(const WebGLFBAttachPoint& ref)
|
||||
: mRef(ref)
|
||||
{ }
|
||||
|
||||
bool operator<(const Ordered& other) const {
|
||||
MOZ_ASSERT(mRef.IsDefined() && other.mRef.IsDefined());
|
||||
|
||||
#define ORDER_BY(X) if (X != other.X) return X < other.X;
|
||||
|
||||
ORDER_BY(mRef.mRenderbufferPtr)
|
||||
ORDER_BY(mRef.mTexturePtr)
|
||||
ORDER_BY(mRef.mTexImageTarget.get())
|
||||
ORDER_BY(mRef.mTexImageLevel)
|
||||
ORDER_BY(mRef.mTexImageLayer)
|
||||
|
||||
#undef ORDER_BY
|
||||
return false;
|
||||
}
|
||||
free(mArray);
|
||||
}
|
||||
|
||||
T* begin() const {
|
||||
return mArray;
|
||||
}
|
||||
|
||||
T* end() const {
|
||||
return mArray + mSize;
|
||||
}
|
||||
|
||||
T& operator [](size_t offset) const {
|
||||
MOZ_ASSERT(offset < mSize);
|
||||
return mArray[offset];
|
||||
}
|
||||
|
||||
const size_t& Size() const { return mSize; }
|
||||
|
||||
template<typename A, typename B>
|
||||
void AppendNew(A a, B b) {
|
||||
if (mSize == mCapacity)
|
||||
MOZ_CRASH("GFX: Bad EmplaceAppend.");
|
||||
|
||||
// Placement `new`:
|
||||
new (&(mArray[mSize])) T(a, b);
|
||||
++mSize;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
class WebGLFramebuffer final
|
||||
@ -173,28 +142,7 @@ public:
|
||||
|
||||
const GLuint mGLName;
|
||||
|
||||
private:
|
||||
mutable bool mIsKnownFBComplete;
|
||||
|
||||
GLenum mReadBufferMode;
|
||||
|
||||
// No need to chase pointers for the oft-used color0.
|
||||
WebGLFBAttachPoint mColorAttachment0;
|
||||
WebGLFBAttachPoint mDepthAttachment;
|
||||
WebGLFBAttachPoint mStencilAttachment;
|
||||
WebGLFBAttachPoint mDepthStencilAttachment;
|
||||
|
||||
PlacementArray<WebGLFBAttachPoint> mMoreColorAttachments;
|
||||
|
||||
std::vector<GLenum> mDrawBuffers;
|
||||
|
||||
bool IsDrawBuffer(size_t n) const {
|
||||
if (n < mDrawBuffers.size())
|
||||
return bool(mDrawBuffers[n]);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected:
|
||||
#ifdef ANDROID
|
||||
// Bug 1140459: Some drivers (including our test slaves!) don't
|
||||
// give reasonable answers for IsRenderbuffer, maybe others.
|
||||
@ -204,94 +152,133 @@ private:
|
||||
bool mIsFB;
|
||||
#endif
|
||||
|
||||
////
|
||||
|
||||
WebGLFBAttachPoint mDepthAttachment;
|
||||
WebGLFBAttachPoint mStencilAttachment;
|
||||
WebGLFBAttachPoint mDepthStencilAttachment;
|
||||
|
||||
// In theory, this number can be unbounded based on the driver. However, no driver
|
||||
// appears to expose more than 8. We might as well stop there too, for now.
|
||||
// (http://opengl.gpuinfo.org/gl_stats_caps_single.php?listreportsbycap=GL_MAX_COLOR_ATTACHMENTS)
|
||||
static const size_t kMaxColorAttachments = 8; // jgilbert's MacBook Pro exposes 8.
|
||||
WebGLFBAttachPoint mColorAttachments[kMaxColorAttachments];
|
||||
|
||||
////
|
||||
|
||||
std::vector<const WebGLFBAttachPoint*> mColorDrawBuffers; // Non-null
|
||||
const WebGLFBAttachPoint* mColorReadBuffer; // Null if NONE
|
||||
|
||||
////
|
||||
|
||||
struct ResolvedData {
|
||||
// BlitFramebuffer
|
||||
bool hasSampleBuffers;
|
||||
const WebGLFBAttachPoint* depthBuffer;
|
||||
const WebGLFBAttachPoint* stencilBuffer;
|
||||
|
||||
// IsFeedback
|
||||
std::vector<const WebGLFBAttachPoint*> texDrawBuffers; // Non-null
|
||||
std::set<WebGLFBAttachPoint::Ordered> drawSet;
|
||||
std::set<WebGLFBAttachPoint::Ordered> readSet;
|
||||
|
||||
explicit ResolvedData(const WebGLFramebuffer& parent);
|
||||
};
|
||||
|
||||
UniquePtr<const ResolvedData> mResolvedCompleteData;
|
||||
|
||||
////
|
||||
|
||||
public:
|
||||
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLFramebuffer)
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLFramebuffer)
|
||||
|
||||
WebGLFramebuffer(WebGLContext* webgl, GLuint fbo);
|
||||
|
||||
WebGLContext* GetParentObject() const { return mContext; }
|
||||
virtual JSObject* WrapObject(JSContext* cx, JS::Handle<JSObject*> givenProto) override;
|
||||
|
||||
private:
|
||||
~WebGLFramebuffer() {
|
||||
DeleteOnce();
|
||||
}
|
||||
|
||||
const WebGLRectangleObject& GetAnyRectObject() const;
|
||||
|
||||
public:
|
||||
void Delete();
|
||||
|
||||
void FramebufferRenderbuffer(GLenum attachment, RBTarget rbtarget,
|
||||
WebGLRenderbuffer* rb);
|
||||
void FramebufferTexture2D(GLenum attachment, TexImageTarget texImageTarget,
|
||||
WebGLTexture* tex, GLint level);
|
||||
void FramebufferTextureLayer(GLenum attachment, WebGLTexture* tex, GLint level,
|
||||
GLint layer);
|
||||
////
|
||||
|
||||
bool HasDefinedAttachments() const;
|
||||
bool HasIncompleteAttachments(nsCString* const out_info) const;
|
||||
bool AllImageRectsMatch() const;
|
||||
bool AllImageSamplesMatch() const;
|
||||
FBStatus PrecheckFramebufferStatus(nsCString* const out_info) const;
|
||||
FBStatus CheckFramebufferStatus(nsCString* const out_info) const;
|
||||
|
||||
const webgl::FormatUsageInfo*
|
||||
GetFormatForAttachment(const WebGLFBAttachPoint& attachment) const;
|
||||
|
||||
const WebGLFBAttachPoint& ColorAttachment(size_t colorAttachmentId) const {
|
||||
MOZ_ASSERT(colorAttachmentId < 1 + mMoreColorAttachments.Size());
|
||||
return colorAttachmentId ? mMoreColorAttachments[colorAttachmentId - 1]
|
||||
: mColorAttachment0;
|
||||
}
|
||||
|
||||
const WebGLFBAttachPoint& DepthAttachment() const {
|
||||
return mDepthAttachment;
|
||||
}
|
||||
|
||||
const WebGLFBAttachPoint& StencilAttachment() const {
|
||||
return mStencilAttachment;
|
||||
}
|
||||
|
||||
const WebGLFBAttachPoint& DepthStencilAttachment() const {
|
||||
return mDepthStencilAttachment;
|
||||
}
|
||||
|
||||
void SetReadBufferMode(GLenum readBufferMode) {
|
||||
mReadBufferMode = readBufferMode;
|
||||
}
|
||||
|
||||
GLenum ReadBufferMode() const { return mReadBufferMode; }
|
||||
|
||||
void GatherAttachments(std::vector<const WebGLFBAttachPoint*>* const out) const;
|
||||
|
||||
protected:
|
||||
WebGLFBAttachPoint* GetAttachPoint(GLenum attachment); // Fallible
|
||||
Maybe<WebGLFBAttachPoint*> GetAttachPoint(GLenum attachment); // Fallible
|
||||
Maybe<WebGLFBAttachPoint*> GetColorAttachPoint(GLenum attachment); // Fallible
|
||||
void ResolveAttachments() const;
|
||||
void RefreshDrawBuffers() const;
|
||||
void RefreshReadBuffer() const;
|
||||
bool ResolveAttachmentData(const char* funcName) const;
|
||||
|
||||
public:
|
||||
void DetachTexture(const WebGLTexture* tex);
|
||||
|
||||
void DetachRenderbuffer(const WebGLRenderbuffer* rb);
|
||||
|
||||
WebGLContext* GetParentObject() const {
|
||||
return mContext;
|
||||
}
|
||||
|
||||
void FinalizeAttachments() const;
|
||||
|
||||
virtual JSObject* WrapObject(JSContext* cx, JS::Handle<JSObject*> givenProto) override;
|
||||
|
||||
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLFramebuffer)
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLFramebuffer)
|
||||
|
||||
bool ValidateAndInitAttachments(const char* funcName);
|
||||
|
||||
void InvalidateFramebufferStatus() const {
|
||||
mIsKnownFBComplete = false;
|
||||
}
|
||||
|
||||
bool ValidateForRead(const char* info,
|
||||
const webgl::FormatUsageInfo** const out_format,
|
||||
uint32_t* const out_width, uint32_t* const out_height);
|
||||
|
||||
////////////////
|
||||
// Getters
|
||||
|
||||
#define GETTER(X) const decltype(m##X)& X() const { return m##X; }
|
||||
|
||||
GETTER(DepthAttachment)
|
||||
GETTER(StencilAttachment)
|
||||
GETTER(DepthStencilAttachment)
|
||||
GETTER(ColorDrawBuffers)
|
||||
GETTER(ColorReadBuffer)
|
||||
GETTER(ResolvedCompleteData)
|
||||
|
||||
#undef GETTER
|
||||
|
||||
////////////////
|
||||
// Invalidation
|
||||
|
||||
bool IsResolvedComplete() const { return bool(mResolvedCompleteData); }
|
||||
|
||||
void InvalidateFramebufferStatus() {
|
||||
mResolvedCompleteData = nullptr;
|
||||
}
|
||||
|
||||
void RefreshResolvedData();
|
||||
|
||||
////////////////
|
||||
// WebGL funcs
|
||||
|
||||
FBStatus CheckFramebufferStatus(const char* funcName);
|
||||
void FramebufferRenderbuffer(const char* funcName, GLenum attachment, GLenum rbtarget,
|
||||
WebGLRenderbuffer* rb);
|
||||
void FramebufferTexture2D(const char* funcName, GLenum attachment,
|
||||
GLenum texImageTarget, WebGLTexture* tex, GLint level);
|
||||
void FramebufferTextureLayer(const char* funcName, GLenum attachment,
|
||||
WebGLTexture* tex, GLint level, GLint layer);
|
||||
void DrawBuffers(const char* funcName, const dom::Sequence<GLenum>& buffers);
|
||||
void ReadBuffer(const char* funcName, GLenum attachPoint);
|
||||
|
||||
JS::Value GetAttachmentParameter(const char* funcName, JSContext* cx, GLenum target,
|
||||
GLenum attachment, GLenum pname,
|
||||
ErrorResult* const out_error);
|
||||
|
||||
static void BlitFramebuffer(WebGLContext* webgl,
|
||||
const WebGLFramebuffer* src, GLint srcX0, GLint srcY0,
|
||||
GLint srcX1, GLint srcY1,
|
||||
const WebGLFramebuffer* dst, GLint dstX0, GLint dstY0,
|
||||
GLint dstX1, GLint dstY1,
|
||||
GLbitfield mask, GLenum filter);
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -331,7 +331,7 @@ ImplCycleCollectionUnlink(mozilla::WebGLRefPtr<T>& field)
|
||||
template <typename T>
|
||||
inline void
|
||||
ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& callback,
|
||||
mozilla::WebGLRefPtr<T>& field,
|
||||
const mozilla::WebGLRefPtr<T>& field,
|
||||
const char* name,
|
||||
uint32_t flags = 0)
|
||||
{
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include "WebGLActiveInfo.h"
|
||||
#include "WebGLContext.h"
|
||||
#include "WebGLShader.h"
|
||||
#include "WebGLTransformFeedback.h"
|
||||
#include "WebGLUniformLocation.h"
|
||||
#include "WebGLValidateStrings.h"
|
||||
|
||||
@ -331,6 +332,13 @@ QueryProgramInfo(WebGLProgram* prog, gl::GLContext* gl)
|
||||
}
|
||||
}
|
||||
|
||||
////
|
||||
|
||||
GLuint dataSize = 0;
|
||||
gl->fGetActiveUniformBlockiv(prog->mGLName, i,
|
||||
LOCAL_GL_UNIFORM_BLOCK_DATA_SIZE,
|
||||
(GLint*)&dataSize);
|
||||
|
||||
#ifdef DUMP_SHADERVAR_MAPPINGS
|
||||
printf_stderr("[uniform block %i] %s/%i/%s/%s\n", i,
|
||||
mappedName.BeginReading(), (int)isArray,
|
||||
@ -339,7 +347,8 @@ QueryProgramInfo(WebGLProgram* prog, gl::GLContext* gl)
|
||||
printf_stderr(" isArray: %d\n", (int)isArray);
|
||||
#endif
|
||||
|
||||
const auto* block = new webgl::UniformBlockInfo(baseUserName, baseMappedName);
|
||||
auto* block = new webgl::UniformBlockInfo(webgl, baseUserName, baseMappedName,
|
||||
dataSize);
|
||||
info->uniformBlocks.push_back(block);
|
||||
}
|
||||
}
|
||||
@ -436,7 +445,8 @@ CreateProgram(gl::GLContext* gl)
|
||||
WebGLProgram::WebGLProgram(WebGLContext* webgl)
|
||||
: WebGLContextBoundObject(webgl)
|
||||
, mGLName(CreateProgram(webgl->GL()))
|
||||
, mTransformFeedbackBufferMode(LOCAL_GL_NONE)
|
||||
, mNumActiveTFOs(0)
|
||||
, mNextLink_TransformFeedbackBufferMode(LOCAL_GL_SEPARATE_ATTRIBS)
|
||||
{
|
||||
mContext->mPrograms.insertBack(this);
|
||||
}
|
||||
@ -517,7 +527,7 @@ WebGLProgram::BindAttribLocation(GLuint loc, const nsAString& name)
|
||||
|
||||
NS_LossyConvertUTF16toASCII asciiName(name);
|
||||
|
||||
auto res = mBoundAttribLocs.insert(std::pair<nsCString, GLuint>(asciiName, loc));
|
||||
auto res = mNextLink_BoundAttribLocs.insert({asciiName, loc});
|
||||
|
||||
const bool wasInserted = res.second;
|
||||
if (!wasInserted) {
|
||||
@ -675,11 +685,13 @@ WebGLProgram::GetProgramParameter(GLenum pname) const
|
||||
if (mContext->IsWebGL2()) {
|
||||
switch (pname) {
|
||||
case LOCAL_GL_ACTIVE_UNIFORM_BLOCKS:
|
||||
case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER_MODE:
|
||||
return JS::Int32Value(GetProgramiv(gl, mGLName, pname));
|
||||
|
||||
case LOCAL_GL_TRANSFORM_FEEDBACK_VARYINGS:
|
||||
return JS::Int32Value(mTransformFeedbackVaryings.size());
|
||||
return JS::Int32Value(mNextLink_TransformFeedbackVaryings.size());
|
||||
|
||||
case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER_MODE:
|
||||
return JS::Int32Value(mNextLink_TransformFeedbackBufferMode);
|
||||
}
|
||||
}
|
||||
|
||||
@ -936,57 +948,58 @@ WebGLProgram::GetUniformIndices(const dom::Sequence<nsString>& uniformNames,
|
||||
|
||||
|
||||
void
|
||||
WebGLProgram::UniformBlockBinding(GLuint uniformBlockIndex, GLuint uniformBlockBinding) const
|
||||
WebGLProgram::UniformBlockBinding(GLuint uniformBlockIndex,
|
||||
GLuint uniformBlockBinding) const
|
||||
{
|
||||
const char funcName[] = "getActiveUniformBlockName";
|
||||
if (!IsLinked()) {
|
||||
mContext->ErrorInvalidOperation("getActiveUniformBlockName: `program` must be linked.");
|
||||
mContext->ErrorInvalidOperation("%s: `program` must be linked.", funcName);
|
||||
return;
|
||||
}
|
||||
|
||||
const webgl::LinkedProgramInfo* linkInfo = LinkInfo();
|
||||
if (uniformBlockIndex >= linkInfo->uniformBlocks.size()) {
|
||||
mContext->ErrorInvalidValue("getActiveUniformBlockName: index %u invalid.", uniformBlockIndex);
|
||||
const auto& uniformBlocks = LinkInfo()->uniformBlocks;
|
||||
if (uniformBlockIndex >= uniformBlocks.size()) {
|
||||
mContext->ErrorInvalidValue("%s: Index %u invalid.", funcName, uniformBlockIndex);
|
||||
return;
|
||||
}
|
||||
const auto& uniformBlock = uniformBlocks[uniformBlockIndex];
|
||||
|
||||
if (uniformBlockBinding > mContext->mGLMaxUniformBufferBindings) {
|
||||
mContext->ErrorInvalidEnum("getActiveUniformBlockName: binding %u invalid.", uniformBlockBinding);
|
||||
const auto& indexedBindings = mContext->mIndexedUniformBufferBindings;
|
||||
if (uniformBlockBinding >= indexedBindings.size()) {
|
||||
mContext->ErrorInvalidValue("%s: Binding %u invalid.", funcName,
|
||||
uniformBlockBinding);
|
||||
return;
|
||||
}
|
||||
const auto& indexedBinding = indexedBindings[uniformBlockBinding];
|
||||
|
||||
////
|
||||
|
||||
gl::GLContext* gl = mContext->GL();
|
||||
gl->MakeCurrent();
|
||||
gl->fUniformBlockBinding(mGLName, uniformBlockIndex, uniformBlockBinding);
|
||||
|
||||
////
|
||||
|
||||
uniformBlock->mBinding = &indexedBinding;
|
||||
}
|
||||
|
||||
void
|
||||
WebGLProgram::LinkProgram()
|
||||
bool
|
||||
WebGLProgram::ValidateForLink()
|
||||
{
|
||||
mContext->InvalidateBufferFetching(); // we do it early in this function
|
||||
// as some of the validation below changes program state
|
||||
|
||||
mLinkLog.Truncate();
|
||||
mMostRecentLinkInfo = nullptr;
|
||||
|
||||
if (!mVertShader || !mVertShader->IsCompiled()) {
|
||||
mLinkLog.AssignLiteral("Must have a compiled vertex shader attached.");
|
||||
mContext->GenerateWarning("linkProgram: %s", mLinkLog.BeginReading());
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!mFragShader || !mFragShader->IsCompiled()) {
|
||||
mLinkLog.AssignLiteral("Must have an compiled fragment shader attached.");
|
||||
mContext->GenerateWarning("linkProgram: %s", mLinkLog.BeginReading());
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!mFragShader->CanLinkTo(mVertShader, &mLinkLog)) {
|
||||
mContext->GenerateWarning("linkProgram: %s", mLinkLog.BeginReading());
|
||||
return;
|
||||
}
|
||||
if (!mFragShader->CanLinkTo(mVertShader, &mLinkLog))
|
||||
return false;
|
||||
|
||||
gl::GLContext* gl = mContext->gl;
|
||||
gl->MakeCurrent();
|
||||
const auto& gl = mContext->gl;
|
||||
|
||||
if (gl->WorkAroundDriverBugs() &&
|
||||
mContext->mIsMesa)
|
||||
@ -998,34 +1011,70 @@ WebGLProgram::LinkProgram()
|
||||
if (numSamplerUniforms_upperBound > 16) {
|
||||
mLinkLog.AssignLiteral("Programs with more than 16 samplers are disallowed on"
|
||||
" Mesa drivers to avoid crashing.");
|
||||
mContext->GenerateWarning("linkProgram: %s", mLinkLog.BeginReading());
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Bug 1203135: Mesa crashes internally if we exceed the reported maximum attribute count.
|
||||
if (mVertShader->NumAttributes() > mContext->MaxVertexAttribs()) {
|
||||
mLinkLog.AssignLiteral("Number of attributes exceeds Mesa's reported max attribute count.");
|
||||
mContext->GenerateWarning("linkProgram: %s", mLinkLog.BeginReading());
|
||||
return;
|
||||
mLinkLog.AssignLiteral("Number of attributes exceeds Mesa's reported max"
|
||||
" attribute count.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
WebGLProgram::LinkProgram()
|
||||
{
|
||||
const char funcName[] = "linkProgram";
|
||||
|
||||
if (mNumActiveTFOs) {
|
||||
mContext->ErrorInvalidOperation("%s: Program is in-use by one or more active"
|
||||
" transform feedback objects.",
|
||||
funcName);
|
||||
return;
|
||||
}
|
||||
|
||||
mContext->MakeContextCurrent();
|
||||
mContext->InvalidateBufferFetching(); // we do it early in this function
|
||||
// as some of the validation changes program state
|
||||
|
||||
mLinkLog.Truncate();
|
||||
mMostRecentLinkInfo = nullptr;
|
||||
|
||||
if (!ValidateForLink()) {
|
||||
mContext->GenerateWarning("%s: %s", funcName, mLinkLog.BeginReading());
|
||||
return;
|
||||
}
|
||||
|
||||
// Bind the attrib locations.
|
||||
// This can't be done trivially, because we have to deal with mapped attrib names.
|
||||
for (auto itr = mBoundAttribLocs.begin(); itr != mBoundAttribLocs.end(); ++itr) {
|
||||
const nsCString& name = itr->first;
|
||||
GLuint index = itr->second;
|
||||
for (const auto& pair : mNextLink_BoundAttribLocs) {
|
||||
const auto& name = pair.first;
|
||||
const auto& index = pair.second;
|
||||
|
||||
mVertShader->BindAttribLocation(mGLName, name, index);
|
||||
}
|
||||
|
||||
if (!mTransformFeedbackVaryings.empty()) {
|
||||
// Bind the transform feedback varyings.
|
||||
// This can't be done trivially, because we have to deal with mapped names too.
|
||||
mVertShader->ApplyTransformFeedbackVaryings(mGLName,
|
||||
mTransformFeedbackVaryings,
|
||||
mTransformFeedbackBufferMode,
|
||||
&mTempMappedVaryings);
|
||||
// Storage for transform feedback varyings before link.
|
||||
// (Work around for bug seen on nVidia drivers.)
|
||||
std::vector<std::string> scopedMappedTFVaryings;
|
||||
|
||||
if (mContext->IsWebGL2()) {
|
||||
mVertShader->MapTransformFeedbackVaryings(mNextLink_TransformFeedbackVaryings,
|
||||
&scopedMappedTFVaryings);
|
||||
|
||||
std::vector<const char*> driverVaryings;
|
||||
driverVaryings.reserve(scopedMappedTFVaryings.size());
|
||||
for (const auto& cur : scopedMappedTFVaryings) {
|
||||
driverVaryings.push_back(cur.c_str());
|
||||
}
|
||||
|
||||
mContext->gl->fTransformFeedbackVaryings(mGLName, driverVaryings.size(),
|
||||
driverVaryings.data(),
|
||||
mNextLink_TransformFeedbackBufferMode);
|
||||
}
|
||||
|
||||
LinkAndUpdate();
|
||||
@ -1080,10 +1129,63 @@ NumUsedLocationsByElemType(GLenum elemType)
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t
|
||||
NumComponents(GLenum elemType)
|
||||
{
|
||||
switch (elemType) {
|
||||
case LOCAL_GL_FLOAT:
|
||||
case LOCAL_GL_INT:
|
||||
case LOCAL_GL_UNSIGNED_INT:
|
||||
case LOCAL_GL_BOOL:
|
||||
return 1;
|
||||
|
||||
case LOCAL_GL_FLOAT_VEC2:
|
||||
case LOCAL_GL_INT_VEC2:
|
||||
case LOCAL_GL_UNSIGNED_INT_VEC2:
|
||||
case LOCAL_GL_BOOL_VEC2:
|
||||
return 2;
|
||||
|
||||
case LOCAL_GL_FLOAT_VEC3:
|
||||
case LOCAL_GL_INT_VEC3:
|
||||
case LOCAL_GL_UNSIGNED_INT_VEC3:
|
||||
case LOCAL_GL_BOOL_VEC3:
|
||||
return 3;
|
||||
|
||||
case LOCAL_GL_FLOAT_VEC4:
|
||||
case LOCAL_GL_INT_VEC4:
|
||||
case LOCAL_GL_UNSIGNED_INT_VEC4:
|
||||
case LOCAL_GL_BOOL_VEC4:
|
||||
case LOCAL_GL_FLOAT_MAT2:
|
||||
return 4;
|
||||
|
||||
case LOCAL_GL_FLOAT_MAT2x3:
|
||||
case LOCAL_GL_FLOAT_MAT3x2:
|
||||
return 6;
|
||||
|
||||
case LOCAL_GL_FLOAT_MAT2x4:
|
||||
case LOCAL_GL_FLOAT_MAT4x2:
|
||||
return 8;
|
||||
|
||||
case LOCAL_GL_FLOAT_MAT3:
|
||||
return 9;
|
||||
|
||||
case LOCAL_GL_FLOAT_MAT3x4:
|
||||
case LOCAL_GL_FLOAT_MAT4x3:
|
||||
return 12;
|
||||
|
||||
case LOCAL_GL_FLOAT_MAT4:
|
||||
return 16;
|
||||
|
||||
default:
|
||||
MOZ_CRASH("`elemType`");
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
WebGLProgram::ValidateAfterTentativeLink(nsCString* const out_linkLog) const
|
||||
{
|
||||
const auto& linkInfo = mMostRecentLinkInfo;
|
||||
const auto& gl = mContext->gl;
|
||||
|
||||
// Check if the attrib name conflicting to uniform name
|
||||
for (const auto& attrib : linkInfo->attribs) {
|
||||
@ -1123,15 +1225,107 @@ WebGLProgram::ValidateAfterTentativeLink(nsCString* const out_linkLog) const
|
||||
}
|
||||
}
|
||||
|
||||
// Forbid:
|
||||
// * Unrecognized varying name
|
||||
// * Duplicate varying name
|
||||
// * Too many components for specified buffer mode
|
||||
if (mNextLink_TransformFeedbackVaryings.size()) {
|
||||
GLuint maxComponentsPerIndex = 0;
|
||||
switch (mNextLink_TransformFeedbackBufferMode) {
|
||||
case LOCAL_GL_INTERLEAVED_ATTRIBS:
|
||||
gl->GetUIntegerv(LOCAL_GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS,
|
||||
&maxComponentsPerIndex);
|
||||
break;
|
||||
|
||||
case LOCAL_GL_SEPARATE_ATTRIBS:
|
||||
gl->GetUIntegerv(LOCAL_GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS,
|
||||
&maxComponentsPerIndex);
|
||||
break;
|
||||
|
||||
default:
|
||||
MOZ_CRASH("`bufferMode`");
|
||||
}
|
||||
|
||||
std::vector<size_t> componentsPerVert;
|
||||
std::set<const WebGLActiveInfo*> alreadyUsed;
|
||||
for (const auto& wideUserName : mNextLink_TransformFeedbackVaryings) {
|
||||
if (!componentsPerVert.size() ||
|
||||
mNextLink_TransformFeedbackBufferMode == LOCAL_GL_SEPARATE_ATTRIBS)
|
||||
{
|
||||
componentsPerVert.push_back(0);
|
||||
}
|
||||
|
||||
////
|
||||
|
||||
const WebGLActiveInfo* curInfo = nullptr;
|
||||
for (const auto& info : linkInfo->transformFeedbackVaryings) {
|
||||
const NS_ConvertASCIItoUTF16 info_wideUserName(info->mBaseUserName);
|
||||
if (info_wideUserName == wideUserName) {
|
||||
curInfo = info.get();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!curInfo) {
|
||||
const NS_LossyConvertUTF16toASCII asciiUserName(wideUserName);
|
||||
*out_linkLog = nsPrintfCString("Transform feedback varying \"%s\" not"
|
||||
" found.",
|
||||
asciiUserName.BeginReading());
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto insertResPair = alreadyUsed.insert(curInfo);
|
||||
const auto& didInsert = insertResPair.second;
|
||||
if (!didInsert) {
|
||||
const NS_LossyConvertUTF16toASCII asciiUserName(wideUserName);
|
||||
*out_linkLog = nsPrintfCString("Transform feedback varying \"%s\""
|
||||
" specified twice.",
|
||||
asciiUserName.BeginReading());
|
||||
return false;
|
||||
}
|
||||
|
||||
////
|
||||
|
||||
size_t varyingComponents = NumComponents(curInfo->mElemType);
|
||||
varyingComponents *= curInfo->mElemCount;
|
||||
|
||||
auto& totalComponentsForIndex = *(componentsPerVert.rbegin());
|
||||
totalComponentsForIndex += varyingComponents;
|
||||
|
||||
if (totalComponentsForIndex > maxComponentsPerIndex) {
|
||||
const NS_LossyConvertUTF16toASCII asciiUserName(wideUserName);
|
||||
*out_linkLog = nsPrintfCString("Transform feedback varying \"%s\""
|
||||
" pushed `componentsForIndex` over the"
|
||||
" limit of %u.",
|
||||
asciiUserName.BeginReading(),
|
||||
maxComponentsPerIndex);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
linkInfo->componentsPerTFVert.swap(componentsPerVert);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
WebGLProgram::UseProgram() const
|
||||
{
|
||||
const char funcName[] = "useProgram";
|
||||
|
||||
if (!mMostRecentLinkInfo) {
|
||||
mContext->ErrorInvalidOperation("useProgram: Program has not been successfully"
|
||||
" linked.");
|
||||
mContext->ErrorInvalidOperation("%s: Program has not been successfully linked.",
|
||||
funcName);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mContext->mBoundTransformFeedback &&
|
||||
mContext->mBoundTransformFeedback->mIsActive &&
|
||||
!mContext->mBoundTransformFeedback->mIsPaused)
|
||||
{
|
||||
mContext->ErrorInvalidOperation("%s: Transform feedback active and not paused.",
|
||||
funcName);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1183,11 +1377,6 @@ WebGLProgram::LinkAndUpdate()
|
||||
mLinkLog.SetLength(0);
|
||||
}
|
||||
|
||||
// Post link, temporary mapped varying names for transform feedback can be discarded.
|
||||
// The memory can only be deleted after log is queried or the link status will fail.
|
||||
std::vector<std::string> empty;
|
||||
empty.swap(mTempMappedVaryings);
|
||||
|
||||
GLint ok = 0;
|
||||
gl->fGetProgramiv(mGLName, LOCAL_GL_LINK_STATUS, &ok);
|
||||
if (!ok)
|
||||
@ -1237,42 +1426,43 @@ void
|
||||
WebGLProgram::TransformFeedbackVaryings(const dom::Sequence<nsString>& varyings,
|
||||
GLenum bufferMode)
|
||||
{
|
||||
if (bufferMode != LOCAL_GL_INTERLEAVED_ATTRIBS &&
|
||||
bufferMode != LOCAL_GL_SEPARATE_ATTRIBS)
|
||||
{
|
||||
mContext->ErrorInvalidEnum("transformFeedbackVaryings: `bufferMode` %s is "
|
||||
"invalid. Must be one of gl.INTERLEAVED_ATTRIBS or "
|
||||
"gl.SEPARATE_ATTRIBS.",
|
||||
mContext->EnumName(bufferMode));
|
||||
const char funcName[] = "transformFeedbackVaryings";
|
||||
|
||||
const auto& gl = mContext->gl;
|
||||
gl->MakeCurrent();
|
||||
|
||||
switch (bufferMode) {
|
||||
case LOCAL_GL_INTERLEAVED_ATTRIBS:
|
||||
break;
|
||||
|
||||
case LOCAL_GL_SEPARATE_ATTRIBS:
|
||||
{
|
||||
GLuint maxAttribs = 0;
|
||||
gl->GetUIntegerv(LOCAL_GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS,
|
||||
&maxAttribs);
|
||||
if (varyings.Length() >= maxAttribs) {
|
||||
mContext->ErrorInvalidValue("%s: Length of `varyings` exceeds %s.",
|
||||
funcName,
|
||||
"TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS");
|
||||
return;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
mContext->ErrorInvalidEnum("%s: Bad `bufferMode`: 0x%04x.", funcName, bufferMode);
|
||||
return;
|
||||
}
|
||||
|
||||
size_t varyingsCount = varyings.Length();
|
||||
if (bufferMode == LOCAL_GL_SEPARATE_ATTRIBS &&
|
||||
varyingsCount >= mContext->mGLMaxTransformFeedbackSeparateAttribs)
|
||||
{
|
||||
mContext->ErrorInvalidValue("transformFeedbackVaryings: Number of `varyings` exc"
|
||||
"eeds gl.MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS.");
|
||||
return;
|
||||
}
|
||||
////
|
||||
|
||||
std::vector<nsCString> asciiVaryings;
|
||||
for (size_t i = 0; i < varyingsCount; i++) {
|
||||
if (!ValidateGLSLVariableName(varyings[i], mContext, "transformFeedbackVaryings"))
|
||||
return;
|
||||
|
||||
NS_LossyConvertUTF16toASCII asciiName(varyings[i]);
|
||||
asciiVaryings.push_back(asciiName);
|
||||
}
|
||||
|
||||
// All validated. Translate the strings and store them until
|
||||
// program linking.
|
||||
mTransformFeedbackBufferMode = bufferMode;
|
||||
mTransformFeedbackVaryings.swap(asciiVaryings);
|
||||
mNextLink_TransformFeedbackVaryings.assign(varyings.Elements(),
|
||||
varyings.Elements() + varyings.Length());
|
||||
mNextLink_TransformFeedbackBufferMode = bufferMode;
|
||||
}
|
||||
|
||||
already_AddRefed<WebGLActiveInfo>
|
||||
WebGLProgram::GetTransformFeedbackVarying(GLuint index)
|
||||
WebGLProgram::GetTransformFeedbackVarying(GLuint index) const
|
||||
{
|
||||
// No docs in the WebGL 2 spec for this function. Taking the language for
|
||||
// getActiveAttrib, which states that the function returns null on any error.
|
||||
|
@ -61,18 +61,25 @@ struct UniformBlockInfo final
|
||||
{
|
||||
const nsCString mBaseUserName;
|
||||
const nsCString mBaseMappedName;
|
||||
const uint32_t mDataSize;
|
||||
|
||||
UniformBlockInfo(const nsACString& baseUserName,
|
||||
const nsACString& baseMappedName)
|
||||
const IndexedBufferBinding* mBinding;
|
||||
|
||||
UniformBlockInfo(WebGLContext* webgl, const nsACString& baseUserName,
|
||||
const nsACString& baseMappedName, uint32_t dataSize)
|
||||
: mBaseUserName(baseUserName)
|
||||
, mBaseMappedName(baseMappedName)
|
||||
{}
|
||||
, mDataSize(dataSize)
|
||||
, mBinding(&webgl->mIndexedUniformBufferBindings[0])
|
||||
{ }
|
||||
};
|
||||
|
||||
struct LinkedProgramInfo final
|
||||
: public RefCounted<LinkedProgramInfo>
|
||||
, public SupportsWeakPtr<LinkedProgramInfo>
|
||||
{
|
||||
friend class WebGLProgram;
|
||||
|
||||
MOZ_DECLARE_REFCOUNTED_TYPENAME(LinkedProgramInfo)
|
||||
MOZ_DECLARE_WEAKREFERENCE_TYPENAME(LinkedProgramInfo)
|
||||
|
||||
@ -82,12 +89,14 @@ struct LinkedProgramInfo final
|
||||
|
||||
std::vector<AttribInfo> attribs;
|
||||
std::vector<UniformInfo*> uniforms; // Owns its contents.
|
||||
std::vector<const UniformBlockInfo*> uniformBlocks; // Owns its contents.
|
||||
std::vector<UniformBlockInfo*> uniformBlocks; // Owns its contents.
|
||||
std::vector<RefPtr<WebGLActiveInfo>> transformFeedbackVaryings;
|
||||
|
||||
// Needed for draw call validation.
|
||||
std::vector<UniformInfo*> uniformSamplers;
|
||||
|
||||
mutable std::vector<size_t> componentsPerTFVert;
|
||||
|
||||
//////
|
||||
|
||||
// The maps for the frag data names to the translated names.
|
||||
@ -123,6 +132,8 @@ class WebGLProgram final
|
||||
, public LinkedListElement<WebGLProgram>
|
||||
, public WebGLContextBoundObject
|
||||
{
|
||||
friend class WebGLTransformFeedback;
|
||||
|
||||
public:
|
||||
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLProgram)
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLProgram)
|
||||
@ -174,7 +185,7 @@ public:
|
||||
|
||||
void TransformFeedbackVaryings(const dom::Sequence<nsString>& varyings,
|
||||
GLenum bufferMode);
|
||||
already_AddRefed<WebGLActiveInfo> GetTransformFeedbackVarying(GLuint index);
|
||||
already_AddRefed<WebGLActiveInfo> GetTransformFeedbackVarying(GLuint index) const;
|
||||
|
||||
void EnumerateFragOutputs(std::map<nsCString, const nsCString> &out_FragOutputs) const;
|
||||
|
||||
@ -194,6 +205,7 @@ private:
|
||||
~WebGLProgram();
|
||||
|
||||
void LinkAndUpdate();
|
||||
bool ValidateForLink();
|
||||
bool ValidateAfterTentativeLink(nsCString* const out_linkLog) const;
|
||||
|
||||
public:
|
||||
@ -202,14 +214,15 @@ public:
|
||||
private:
|
||||
WebGLRefPtr<WebGLShader> mVertShader;
|
||||
WebGLRefPtr<WebGLShader> mFragShader;
|
||||
std::map<nsCString, GLuint> mBoundAttribLocs;
|
||||
std::vector<nsCString> mTransformFeedbackVaryings;
|
||||
GLenum mTransformFeedbackBufferMode;
|
||||
size_t mNumActiveTFOs;
|
||||
|
||||
std::map<nsCString, GLuint> mNextLink_BoundAttribLocs;
|
||||
|
||||
std::vector<nsString> mNextLink_TransformFeedbackVaryings;
|
||||
GLenum mNextLink_TransformFeedbackBufferMode;
|
||||
|
||||
nsCString mLinkLog;
|
||||
RefPtr<const webgl::LinkedProgramInfo> mMostRecentLinkInfo;
|
||||
// Storage for transform feedback varyings before link.
|
||||
// (Work around for bug seen on nVidia drivers.)
|
||||
std::vector<std::string> mTempMappedVaryings;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -228,22 +228,20 @@ WebGLRenderbuffer::RenderbufferStorage(const char* funcName, uint32_t samples,
|
||||
}
|
||||
|
||||
void
|
||||
WebGLRenderbuffer::DoFramebufferRenderbuffer(GLenum attachment) const
|
||||
WebGLRenderbuffer::DoFramebufferRenderbuffer(FBTarget target, GLenum attachment) const
|
||||
{
|
||||
gl::GLContext* gl = mContext->gl;
|
||||
|
||||
if (attachment == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) {
|
||||
const GLuint stencilRB = (mSecondaryRB ? mSecondaryRB : mPrimaryRB);
|
||||
gl->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER,
|
||||
LOCAL_GL_DEPTH_ATTACHMENT,
|
||||
gl->fFramebufferRenderbuffer(target.get(), LOCAL_GL_DEPTH_ATTACHMENT,
|
||||
LOCAL_GL_RENDERBUFFER, mPrimaryRB);
|
||||
gl->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER,
|
||||
LOCAL_GL_STENCIL_ATTACHMENT,
|
||||
gl->fFramebufferRenderbuffer(target.get(), LOCAL_GL_STENCIL_ATTACHMENT,
|
||||
LOCAL_GL_RENDERBUFFER, stencilRB);
|
||||
return;
|
||||
}
|
||||
|
||||
gl->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, attachment,
|
||||
gl->fFramebufferRenderbuffer(target.get(), attachment,
|
||||
LOCAL_GL_RENDERBUFFER, mPrimaryRB);
|
||||
}
|
||||
|
||||
|
@ -85,7 +85,7 @@ protected:
|
||||
DeleteOnce();
|
||||
}
|
||||
|
||||
void DoFramebufferRenderbuffer(GLenum attachment) const;
|
||||
void DoFramebufferRenderbuffer(FBTarget target, GLenum attachment) const;
|
||||
GLenum DoRenderbufferStorage(uint32_t samples, const webgl::FormatUsageInfo* format,
|
||||
uint32_t width, uint32_t height);
|
||||
};
|
||||
|
@ -408,40 +408,24 @@ WebGLShader::EnumerateFragOutputs(std::map<nsCString, const nsCString> &out_Frag
|
||||
}
|
||||
|
||||
void
|
||||
WebGLShader::ApplyTransformFeedbackVaryings(GLuint prog,
|
||||
const std::vector<nsCString>& varyings,
|
||||
GLenum bufferMode,
|
||||
std::vector<std::string>* out_mappedVaryings) const
|
||||
WebGLShader::MapTransformFeedbackVaryings(const std::vector<nsString>& varyings,
|
||||
std::vector<std::string>* out_mappedVaryings) const
|
||||
{
|
||||
MOZ_ASSERT(mType == LOCAL_GL_VERTEX_SHADER);
|
||||
MOZ_ASSERT(!varyings.empty());
|
||||
MOZ_ASSERT(out_mappedVaryings);
|
||||
|
||||
const size_t varyingsCount = varyings.size();
|
||||
std::vector<std::string> mappedVaryings;
|
||||
out_mappedVaryings->clear();
|
||||
out_mappedVaryings->reserve(varyings.size());
|
||||
|
||||
for (size_t i = 0; i < varyingsCount; i++) {
|
||||
const nsCString& userName = varyings[i];
|
||||
std::string userNameStr(userName.BeginReading());
|
||||
|
||||
const std::string* mappedNameStr = &userNameStr;
|
||||
if (mValidator)
|
||||
mValidator->FindVaryingMappedNameByUserName(userNameStr, &mappedNameStr);
|
||||
|
||||
mappedVaryings.push_back(*mappedNameStr);
|
||||
for (const auto& wideUserName : varyings) {
|
||||
const NS_LossyConvertUTF16toASCII mozUserName(wideUserName); // Don't validate here.
|
||||
const std::string userName(mozUserName.BeginReading(), mozUserName.Length());
|
||||
const std::string* pMappedName = &userName;
|
||||
if (mValidator) {
|
||||
mValidator->FindVaryingMappedNameByUserName(userName, &pMappedName);
|
||||
}
|
||||
out_mappedVaryings->push_back(*pMappedName);
|
||||
}
|
||||
|
||||
// Temporary, tight packed array of string pointers into mappedVaryings.
|
||||
std::vector<const GLchar*> strings;
|
||||
strings.resize(varyingsCount);
|
||||
for (size_t i = 0; i < varyingsCount; i++) {
|
||||
strings[i] = mappedVaryings[i].c_str();
|
||||
}
|
||||
|
||||
mContext->MakeContextCurrent();
|
||||
mContext->gl->fTransformFeedbackVaryings(prog, varyingsCount, &strings[0], bufferMode);
|
||||
|
||||
out_mappedVaryings->swap(mappedVaryings);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -52,7 +52,6 @@ public:
|
||||
bool CanLinkTo(const WebGLShader* prev, nsCString* const out_log) const;
|
||||
size_t CalcNumSamplerUniforms() const;
|
||||
size_t NumAttributes() const;
|
||||
void BindAttribLocation(GLuint prog, const nsCString& userName, GLuint index) const;
|
||||
bool FindAttribUserNameByMappedName(const nsACString& mappedName,
|
||||
nsDependentCString* const out_userName) const;
|
||||
bool FindVaryingByMappedName(const nsACString& mappedName,
|
||||
@ -71,11 +70,12 @@ public:
|
||||
return mTranslationSuccessful && mCompilationSuccessful;
|
||||
}
|
||||
|
||||
void ApplyTransformFeedbackVaryings(GLuint prog,
|
||||
const std::vector<nsCString>& varyings,
|
||||
GLenum bufferMode,
|
||||
std::vector<std::string>* out_mappedVaryings) const;
|
||||
private:
|
||||
void BindAttribLocation(GLuint prog, const nsCString& userName, GLuint index) const;
|
||||
void MapTransformFeedbackVaryings(const std::vector<nsString>& varyings,
|
||||
std::vector<std::string>* out_mappedVaryings) const;
|
||||
|
||||
public:
|
||||
// Other funcs
|
||||
size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
|
||||
void Delete();
|
||||
|
@ -64,6 +64,10 @@ public:
|
||||
std::string* const out_userName) const;
|
||||
|
||||
void EnumerateFragOutputs(std::map<nsCString, const nsCString> &out_FragOutputs) const;
|
||||
|
||||
bool ValidateTransformFeedback(const std::vector<nsString>& userNames,
|
||||
uint32_t maxComponents, nsCString* const out_errorText,
|
||||
std::vector<std::string>* const out_mappedNames);
|
||||
};
|
||||
|
||||
} // namespace webgl
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include "mozilla/Unused.h"
|
||||
#include "ScopedGLHelpers.h"
|
||||
#include "TexUnpackBlob.h"
|
||||
#include "WebGLBuffer.h"
|
||||
#include "WebGLContext.h"
|
||||
#include "WebGLContextUtils.h"
|
||||
#include "WebGLFramebuffer.h"
|
||||
@ -213,6 +214,15 @@ WebGLContext::ValidateUnpackInfo(const char* funcName, bool usePBOs, GLenum form
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mBoundPixelUnpackBuffer &&
|
||||
mBoundPixelUnpackBuffer->mNumActiveTFOs)
|
||||
{
|
||||
ErrorInvalidOperation("%s: Buffer is bound to an active transform feedback"
|
||||
" object.",
|
||||
funcName);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!mFormatUsage->AreUnpackEnumsValid(format, type)) {
|
||||
ErrorInvalidEnum("%s: Invalid unpack format/type: 0x%04x/0x%04x", funcName,
|
||||
format, type);
|
||||
@ -315,7 +325,7 @@ WebGLTexture::TexOrSubImage(bool isSubImage, const char* funcName, TexImageTarge
|
||||
const auto bufferByteCount = packBuffer->ByteLength();
|
||||
|
||||
uint32_t byteCount = 0;
|
||||
if (bufferByteCount >= offset) {
|
||||
if (bufferByteCount >= uint64_t(offset)) {
|
||||
byteCount = bufferByteCount - offset;
|
||||
}
|
||||
|
||||
@ -1969,20 +1979,18 @@ WebGLTexture::ValidateCopyTexImageForFeedback(const char* funcName, uint32_t lev
|
||||
{
|
||||
const auto& fb = mContext->mBoundReadFramebuffer;
|
||||
if (fb) {
|
||||
const auto readBuffer = fb->ReadBufferMode();
|
||||
MOZ_ASSERT(readBuffer != LOCAL_GL_NONE);
|
||||
const uint32_t colorAttachment = readBuffer - LOCAL_GL_COLOR_ATTACHMENT0;
|
||||
const auto& attach = fb->ColorAttachment(colorAttachment);
|
||||
const auto& attach = fb->ColorReadBuffer();
|
||||
MOZ_ASSERT(attach);
|
||||
|
||||
if (attach.Texture() == this &&
|
||||
uint32_t(attach.MipLevel()) == level)
|
||||
if (attach->Texture() == this &&
|
||||
uint32_t(attach->MipLevel()) == level)
|
||||
{
|
||||
// Note that the TexImageTargets *don't* have to match for this to be
|
||||
// undefined per GLES 3.0.4 p211, thus an INVALID_OP in WebGL.
|
||||
mContext->ErrorInvalidOperation("%s: Feedback loop detected, as this texture"
|
||||
" is already attached to READ_FRAMEBUFFER's"
|
||||
" READ_BUFFER-selected COLOR_ATTACHMENT%u.",
|
||||
funcName, colorAttachment);
|
||||
funcName, attach->mAttachmentPoint);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -11,48 +11,206 @@
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
WebGLTransformFeedback::WebGLTransformFeedback(WebGLContext* webgl,
|
||||
GLuint tf)
|
||||
WebGLTransformFeedback::WebGLTransformFeedback(WebGLContext* webgl, GLuint tf)
|
||||
: WebGLContextBoundObject(webgl)
|
||||
, mGLName(tf)
|
||||
, mMode(LOCAL_GL_NONE)
|
||||
, mIsActive(false)
|
||||
, mIndexedBindings(webgl->mGLMaxTransformFeedbackSeparateAttribs)
|
||||
, mIsPaused(false)
|
||||
, mIsActive(false)
|
||||
{
|
||||
mContext->mTransformFeedbacks.insertBack(this);
|
||||
}
|
||||
|
||||
WebGLTransformFeedback::~WebGLTransformFeedback()
|
||||
{
|
||||
mMode = LOCAL_GL_NONE;
|
||||
mIsActive = false;
|
||||
mIsPaused = false;
|
||||
DeleteOnce();
|
||||
}
|
||||
|
||||
void
|
||||
WebGLTransformFeedback::Delete()
|
||||
{
|
||||
mContext->MakeContextCurrent();
|
||||
mContext->gl->fDeleteTransformFeedbacks(1, &mGLName);
|
||||
if (mGLName) {
|
||||
mContext->MakeContextCurrent();
|
||||
mContext->gl->fDeleteTransformFeedbacks(1, &mGLName);
|
||||
}
|
||||
removeFrom(mContext->mTransformFeedbacks);
|
||||
}
|
||||
|
||||
WebGLContext*
|
||||
WebGLTransformFeedback::GetParentObject() const
|
||||
////////////////////////////////////////
|
||||
|
||||
void
|
||||
WebGLTransformFeedback::BeginTransformFeedback(GLenum primMode)
|
||||
{
|
||||
return mContext;
|
||||
const char funcName[] = "beginTransformFeedback";
|
||||
|
||||
if (mIsActive)
|
||||
return mContext->ErrorInvalidOperation("%s: Already active.", funcName);
|
||||
|
||||
switch (primMode) {
|
||||
case LOCAL_GL_POINTS:
|
||||
case LOCAL_GL_LINES:
|
||||
case LOCAL_GL_TRIANGLES:
|
||||
break;
|
||||
default:
|
||||
mContext->ErrorInvalidEnum("%s: `primitiveMode` must be one of POINTS, LINES, or"
|
||||
" TRIANGLES.",
|
||||
funcName);
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& prog = mContext->mCurrentProgram;
|
||||
if (!prog ||
|
||||
!prog->IsLinked() ||
|
||||
!prog->LinkInfo()->componentsPerTFVert.size())
|
||||
{
|
||||
mContext->ErrorInvalidOperation("%s: Current program not valid for transform"
|
||||
" feedback.",
|
||||
funcName);
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& linkInfo = prog->LinkInfo();
|
||||
const auto& componentsPerTFVert = linkInfo->componentsPerTFVert;
|
||||
|
||||
size_t minVertCapacity = SIZE_MAX;
|
||||
for (size_t i = 0; i < componentsPerTFVert.size(); i++) {
|
||||
const auto& indexedBinding = mIndexedBindings[i];
|
||||
const auto& componentsPerVert = componentsPerTFVert[i];
|
||||
|
||||
const auto& buffer = indexedBinding.mBufferBinding;
|
||||
if (!buffer) {
|
||||
mContext->ErrorInvalidOperation("%s: No buffer attached to required transform"
|
||||
" feedback index %u.",
|
||||
funcName, (uint32_t)i);
|
||||
return;
|
||||
}
|
||||
|
||||
const size_t vertCapacity = buffer->ByteLength() / 4 / componentsPerVert;
|
||||
minVertCapacity = std::min(minVertCapacity, vertCapacity);
|
||||
}
|
||||
|
||||
////
|
||||
|
||||
const auto& gl = mContext->gl;
|
||||
gl->MakeCurrent();
|
||||
gl->fBeginTransformFeedback(primMode);
|
||||
|
||||
////
|
||||
|
||||
mIsActive = true;
|
||||
MOZ_ASSERT(!mIsPaused);
|
||||
|
||||
mActive_Program = prog;
|
||||
mActive_PrimMode = primMode;
|
||||
mActive_VertPosition = 0;
|
||||
mActive_VertCapacity = minVertCapacity;
|
||||
|
||||
////
|
||||
|
||||
for (const auto& cur : mIndexedBindings) {
|
||||
const auto& buffer = cur.mBufferBinding;
|
||||
if (buffer) {
|
||||
buffer->mNumActiveTFOs++;
|
||||
}
|
||||
}
|
||||
|
||||
mActive_Program->mNumActiveTFOs++;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
WebGLTransformFeedback::EndTransformFeedback()
|
||||
{
|
||||
const char funcName[] = "endTransformFeedback";
|
||||
|
||||
if (!mIsActive)
|
||||
return mContext->ErrorInvalidOperation("%s: Not active.", funcName);
|
||||
|
||||
////
|
||||
|
||||
const auto& gl = mContext->gl;
|
||||
gl->MakeCurrent();
|
||||
gl->fEndTransformFeedback();
|
||||
|
||||
////
|
||||
|
||||
mIsActive = false;
|
||||
mIsPaused = false;
|
||||
|
||||
////
|
||||
|
||||
for (const auto& cur : mIndexedBindings) {
|
||||
const auto& buffer = cur.mBufferBinding;
|
||||
if (buffer) {
|
||||
buffer->mNumActiveTFOs--;
|
||||
}
|
||||
}
|
||||
|
||||
mActive_Program->mNumActiveTFOs--;
|
||||
}
|
||||
|
||||
void
|
||||
WebGLTransformFeedback::PauseTransformFeedback()
|
||||
{
|
||||
const char funcName[] = "pauseTransformFeedback";
|
||||
|
||||
if (!mIsActive ||
|
||||
mIsPaused)
|
||||
{
|
||||
mContext->ErrorInvalidOperation("%s: Not active or is paused.", funcName);
|
||||
return;
|
||||
}
|
||||
|
||||
////
|
||||
|
||||
const auto& gl = mContext->gl;
|
||||
gl->MakeCurrent();
|
||||
gl->fPauseTransformFeedback();
|
||||
|
||||
////
|
||||
|
||||
mIsPaused = true;
|
||||
}
|
||||
|
||||
void
|
||||
WebGLTransformFeedback::ResumeTransformFeedback()
|
||||
{
|
||||
const char funcName[] = "resumeTransformFeedback";
|
||||
|
||||
if (!mIsPaused)
|
||||
return mContext->ErrorInvalidOperation("%s: Not paused.", funcName);
|
||||
|
||||
if (mContext->mCurrentProgram != mActive_Program) {
|
||||
mContext->ErrorInvalidOperation("%s: Active program differs from original.",
|
||||
funcName);
|
||||
return;
|
||||
}
|
||||
|
||||
////
|
||||
|
||||
const auto& gl = mContext->gl;
|
||||
gl->MakeCurrent();
|
||||
gl->fResumeTransformFeedback();
|
||||
|
||||
////
|
||||
|
||||
MOZ_ASSERT(mIsActive);
|
||||
mIsPaused = false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
JSObject*
|
||||
WebGLTransformFeedback::WrapObject(JSContext* cx, JS::Handle<JSObject*> givenProto)
|
||||
{
|
||||
return dom::WebGLTransformFeedbackBinding::Wrap(cx, this, givenProto);
|
||||
}
|
||||
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(WebGLTransformFeedback)
|
||||
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebGLTransformFeedback, AddRef)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WebGLTransformFeedback, Release)
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(WebGLTransformFeedback,
|
||||
mGenericBufferBinding,
|
||||
mIndexedBindings,
|
||||
mActive_Program)
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -18,27 +18,43 @@ class WebGLTransformFeedback final
|
||||
, public LinkedListElement<WebGLTransformFeedback>
|
||||
, public WebGLContextBoundObject
|
||||
{
|
||||
friend class ScopedDrawWithTransformFeedback;
|
||||
friend class WebGLContext;
|
||||
friend class WebGL2Context;
|
||||
friend class WebGLProgram;
|
||||
|
||||
public:
|
||||
const GLuint mGLName;
|
||||
private:
|
||||
// GLES 3.0.4 p267, Table 6.24 "Transform Feedback State"
|
||||
WebGLRefPtr<WebGLBuffer> mGenericBufferBinding;
|
||||
std::vector<IndexedBufferBinding> mIndexedBindings;
|
||||
bool mIsPaused;
|
||||
bool mIsActive;
|
||||
// Not in state tables:
|
||||
WebGLRefPtr<WebGLProgram> mActive_Program;
|
||||
GLenum mActive_PrimMode;
|
||||
size_t mActive_VertPosition;
|
||||
size_t mActive_VertCapacity;
|
||||
|
||||
public:
|
||||
WebGLTransformFeedback(WebGLContext* webgl, GLuint tf);
|
||||
|
||||
void Delete();
|
||||
WebGLContext* GetParentObject() const;
|
||||
virtual JSObject* WrapObject(JSContext* cx, JS::Handle<JSObject*> givenProto) override;
|
||||
|
||||
const GLuint mGLName;
|
||||
|
||||
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLTransformFeedback)
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLTransformFeedback)
|
||||
|
||||
private:
|
||||
~WebGLTransformFeedback();
|
||||
|
||||
GLenum mMode;
|
||||
bool mIsActive;
|
||||
bool mIsPaused;
|
||||
public:
|
||||
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLTransformFeedback)
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLTransformFeedback)
|
||||
|
||||
void Delete();
|
||||
WebGLContext* GetParentObject() const { return mContext; }
|
||||
virtual JSObject* WrapObject(JSContext*, JS::Handle<JSObject*>) override;
|
||||
|
||||
// GL Funcs
|
||||
void BeginTransformFeedback(GLenum primMode);
|
||||
void EndTransformFeedback();
|
||||
void PauseTransformFeedback();
|
||||
void ResumeTransformFeedback();
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -41,26 +41,19 @@ struct WebGLVertexAttribData
|
||||
GLuint componentSize() const {
|
||||
switch(type) {
|
||||
case LOCAL_GL_BYTE:
|
||||
return sizeof(GLbyte);
|
||||
|
||||
case LOCAL_GL_UNSIGNED_BYTE:
|
||||
return sizeof(GLubyte);
|
||||
return 1;
|
||||
|
||||
case LOCAL_GL_SHORT:
|
||||
return sizeof(GLshort);
|
||||
|
||||
case LOCAL_GL_UNSIGNED_SHORT:
|
||||
return sizeof(GLushort);
|
||||
case LOCAL_GL_HALF_FLOAT:
|
||||
case LOCAL_GL_HALF_FLOAT_OES:
|
||||
return 2;
|
||||
|
||||
case LOCAL_GL_INT:
|
||||
return sizeof(GLint);
|
||||
|
||||
case LOCAL_GL_UNSIGNED_INT:
|
||||
return sizeof(GLuint);
|
||||
|
||||
// case LOCAL_GL_FIXED:
|
||||
case LOCAL_GL_FLOAT:
|
||||
return sizeof(GLfloat);
|
||||
return 4;
|
||||
|
||||
default:
|
||||
MOZ_ASSERT(false, "Should never get here!");
|
||||
|
@ -66,14 +66,8 @@ void
|
||||
CheckValidate(bool expectSuccess, mozilla::WebGLElementArrayCache& c, GLenum type,
|
||||
uint32_t maxAllowed, size_t first, size_t count)
|
||||
{
|
||||
uint32_t out_upperBound = 0;
|
||||
const bool success = c.Validate(type, maxAllowed, first, count, &out_upperBound);
|
||||
const bool success = c.Validate(type, maxAllowed, first, count);
|
||||
VERIFY(success == expectSuccess);
|
||||
if (success) {
|
||||
VERIFY(out_upperBound <= maxAllowed);
|
||||
} else {
|
||||
VERIFY(out_upperBound > maxAllowed);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
|
@ -71,7 +71,6 @@ SOURCES += [
|
||||
UNIFIED_SOURCES += [
|
||||
'TexUnpackBlob.cpp',
|
||||
'WebGL1Context.cpp',
|
||||
'WebGL1ContextBuffers.cpp',
|
||||
'WebGL1ContextUniforms.cpp',
|
||||
'WebGL2Context.cpp',
|
||||
'WebGL2ContextBuffers.cpp',
|
||||
|
@ -4593,7 +4593,6 @@ skip-if = (os == 'android' || os == 'linux' || (os == 'win' && os_version == '5.
|
||||
[generated/test_2_conformance2__state__gl-object-get-calls.html]
|
||||
skip-if = (os == 'android' || os == 'linux' || (os == 'win' && os_version == '5.1'))
|
||||
[generated/test_2_conformance2__transform_feedback__transform_feedback.html]
|
||||
fail-if = (os == 'win' && (os_version == '6.1' || os_version == '6.2' || os_version == '10.0'))
|
||||
skip-if = (os == 'android' || os == 'linux' || (os == 'win' && os_version == '5.1'))
|
||||
[generated/test_2_conformance2__vertex_arrays__vertex-array-object.html]
|
||||
fail-if = (os == 'mac') || (os == 'win')
|
||||
@ -6044,7 +6043,6 @@ skip-if = (os == 'win')
|
||||
[generated/test_conformance__extensions__webgl-draw-buffers-max-draw-buffers.html]
|
||||
[generated/test_conformance__extensions__webgl-draw-buffers.html]
|
||||
skip-if = (os == 'linux')
|
||||
fail-if = (os == 'mac')
|
||||
[generated/test_conformance__extensions__webgl-shared-resources.html]
|
||||
[generated/test_conformance__glsl__bugs__angle-ambiguous-function-call.html]
|
||||
[generated/test_conformance__glsl__bugs__angle-constructor-invalid-parameters.html]
|
||||
|
@ -90,7 +90,6 @@ fail-if = (os == 'mac' && os_version == '10.6')
|
||||
skip-if = (os == 'b2g') || (os == 'linux') || (os == 'android')
|
||||
|
||||
[generated/test_conformance__extensions__webgl-draw-buffers.html]
|
||||
fail-if = (os == 'mac')
|
||||
# Crashes
|
||||
skip-if = (os == 'linux')
|
||||
|
||||
@ -658,8 +657,6 @@ skip-if = (os == 'win' && os_version == '6.1')
|
||||
[generated/test_2_conformance__textures__misc__tex-image-and-sub-image-2d-with-array-buffer-view.html]
|
||||
# Failure on win7 but got passed on win7 vm
|
||||
skip-if = (os == 'win' && os_version == '6.1')
|
||||
[generated/test_2_conformance2__transform_feedback__transform_feedback.html]
|
||||
fail-if = (os == 'win' && (os_version == '6.1' || os_version == '6.2' || os_version == '10.0'))
|
||||
|
||||
####################
|
||||
# failure on Windows
|
||||
|
@ -278,7 +278,14 @@ GetFilesHelper::RunIO()
|
||||
}
|
||||
|
||||
nsAutoString path;
|
||||
path.AssignLiteral(FILESYSTEM_DOM_PATH_SEPARATOR_LITERAL);
|
||||
mErrorResult = file->GetLeafName(path);
|
||||
if (NS_WARN_IF(NS_FAILED(mErrorResult))) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (path.IsEmpty()) {
|
||||
path.AppendLiteral(FILESYSTEM_DOM_PATH_SEPARATOR_LITERAL);
|
||||
}
|
||||
|
||||
mErrorResult = ExploreDirectory(path, file);
|
||||
}
|
||||
|
@ -111,7 +111,8 @@ addMessageListener("dir.open", function (e) {
|
||||
}
|
||||
|
||||
sendAsyncMessage("dir.opened", {
|
||||
dir: testFile.path
|
||||
dir: testFile.path,
|
||||
name: testFile.leafName
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -23,6 +23,7 @@ function create_fileList(aPath) {
|
||||
|
||||
function onOpened(message) {
|
||||
SpecialPowers.wrap(fileList).mozSetDirectory(message.dir);
|
||||
fileList.setAttribute('data-name', message.name);
|
||||
|
||||
fileList.getFilesAndDirectories().then(function(array) {
|
||||
is(array.length, 1, "We want just 1 directory.");
|
||||
@ -84,6 +85,7 @@ function test_inputGetFiles() {
|
||||
|
||||
function onOpened(message) {
|
||||
SpecialPowers.wrap(fileList).mozSetDirectory(message.dir);
|
||||
fileList.setAttribute('data-name', message.name);
|
||||
|
||||
fileList.getFilesAndDirectories()
|
||||
.then(function(result) {
|
||||
@ -96,7 +98,7 @@ function test_inputGetFiles() {
|
||||
is(result.length, 1, "getFiles should return 1 element");
|
||||
ok(result[0] instanceof File, "getFile should return 1 file");
|
||||
is(result[0].name, 'foo.txt', "getFiles()[0].name should be 'foo.txt'");
|
||||
is(result[0].webkitRelativePath, '/foo.txt', "getFiles()[0].webkitRelativePath should be '/foo.txt'");
|
||||
is(result[0].webkitRelativePath, fileList.dataset.name + '/foo.txt', "getFiles()[0].webkitRelativePath should be '/foo.txt'");
|
||||
|
||||
return fileList.getFiles(true);
|
||||
})
|
||||
@ -106,10 +108,10 @@ function test_inputGetFiles() {
|
||||
function checkFile(file) {
|
||||
ok(file instanceof File, "getFile[x] should return a file");
|
||||
if (file.name == 'foo.txt') {
|
||||
is(file.webkitRelativePath, '/foo.txt', "getFiles()[x].webkitRelativePath should be '/foo.txt'");
|
||||
is(file.webkitRelativePath, fileList.dataset.name + '/foo.txt', "getFiles()[x].webkitRelativePath should be '/foo.txt'");
|
||||
} else {
|
||||
is(file.name, 'bar.txt', "getFiles()[x].name should be 'bar.txt'");
|
||||
is(file.webkitRelativePath, '/subdir/bar.txt', "getFiles()[x].webkitRelativePath should be '/subdir/bar.txt'");
|
||||
is(file.webkitRelativePath, fileList.dataset.name + '/subdir/bar.txt', "getFiles()[x].webkitRelativePath should be '/subdir/bar.txt'");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -25,6 +25,7 @@ function populateInputFile(aInputFile) {
|
||||
MockFilePicker.useDirectory(message.dir);
|
||||
|
||||
var input = document.getElementById(aInputFile);
|
||||
input.setAttribute('data-name', message.name);
|
||||
input.addEventListener('change', function change() {
|
||||
input.removeEventListener('change', change);
|
||||
MockFilePicker.cleanup();
|
||||
@ -39,11 +40,11 @@ function populateInputFile(aInputFile) {
|
||||
script.sendAsyncMessage("dir.open", { path: 'test' });
|
||||
}
|
||||
|
||||
function checkFile(file, fileList) {
|
||||
function checkFile(file, fileList, dirName) {
|
||||
for (var i = 0; i < fileList.length; ++i) {
|
||||
ok(fileList[i] instanceof File, "We want just files.");
|
||||
if (fileList[i].name == file.name) {
|
||||
is(fileList[i].webkitRelativePath, file.path, "Path matches");
|
||||
is(fileList[i].webkitRelativePath, dirName + file.path, "Path matches");
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -63,7 +64,7 @@ function test_fileList(aInputFile, aWhat) {
|
||||
|
||||
is(fileList.length, aWhat.length, "We want just " + aWhat.length + " elements for " + aInputFile);
|
||||
for (var i = 0; i < aWhat.length; ++i) {
|
||||
checkFile(aWhat[i], fileList);
|
||||
checkFile(aWhat[i], fileList, input.dataset.name);
|
||||
}
|
||||
|
||||
next();
|
||||
|
@ -5635,7 +5635,7 @@ HTMLInputElement::GetFiles(bool aRecursiveFlag, ErrorResult& aRv)
|
||||
GetFilesHelper* helper = GetOrCreateGetFilesHelper(aRecursiveFlag, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
MOZ_ASSERT(helper);
|
||||
|
||||
nsCOMPtr<nsIGlobalObject> global = OwnerDoc()->GetScopeObject();
|
||||
|
@ -6214,18 +6214,25 @@ HTMLMediaElement::SetMediaKeys(mozilla::dom::MediaKeys* aMediaKeys,
|
||||
EventHandlerNonNull*
|
||||
HTMLMediaElement::GetOnencrypted()
|
||||
{
|
||||
EventListenerManager *elm = GetExistingListenerManager();
|
||||
return elm ? elm->GetEventHandler(nsGkAtoms::onencrypted, EmptyString())
|
||||
: nullptr;
|
||||
return EventTarget::GetEventHandler(nsGkAtoms::onencrypted, EmptyString());
|
||||
}
|
||||
|
||||
void
|
||||
HTMLMediaElement::SetOnencrypted(EventHandlerNonNull* handler)
|
||||
HTMLMediaElement::SetOnencrypted(EventHandlerNonNull* aCallback)
|
||||
{
|
||||
EventListenerManager *elm = GetOrCreateListenerManager();
|
||||
if (elm) {
|
||||
elm->SetEventHandler(nsGkAtoms::onencrypted, EmptyString(), handler);
|
||||
}
|
||||
EventTarget::SetEventHandler(nsGkAtoms::onencrypted, EmptyString(), aCallback);
|
||||
}
|
||||
|
||||
EventHandlerNonNull*
|
||||
HTMLMediaElement::GetOnwaitingforkey()
|
||||
{
|
||||
return EventTarget::GetEventHandler(nsGkAtoms::onwaitingforkey, EmptyString());
|
||||
}
|
||||
|
||||
void
|
||||
HTMLMediaElement::SetOnwaitingforkey(EventHandlerNonNull* aCallback)
|
||||
{
|
||||
EventTarget::SetEventHandler(nsGkAtoms::onwaitingforkey, EmptyString(), aCallback);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -633,7 +633,10 @@ public:
|
||||
ErrorResult& aRv);
|
||||
|
||||
mozilla::dom::EventHandlerNonNull* GetOnencrypted();
|
||||
void SetOnencrypted(mozilla::dom::EventHandlerNonNull* listener);
|
||||
void SetOnencrypted(mozilla::dom::EventHandlerNonNull* aCallback);
|
||||
|
||||
mozilla::dom::EventHandlerNonNull* GetOnwaitingforkey();
|
||||
void SetOnwaitingforkey(mozilla::dom::EventHandlerNonNull* aCallback);
|
||||
|
||||
void DispatchEncrypted(const nsTArray<uint8_t>& aInitData,
|
||||
const nsAString& aInitDataType) override;
|
||||
|
@ -483,5 +483,29 @@ MediaKeySession::SetExpiration(double aExpiration)
|
||||
mExpiration = aExpiration;
|
||||
}
|
||||
|
||||
EventHandlerNonNull*
|
||||
MediaKeySession::GetOnkeystatuseschange()
|
||||
{
|
||||
return GetEventHandler(nsGkAtoms::onkeystatuseschange, EmptyString());
|
||||
}
|
||||
|
||||
void
|
||||
MediaKeySession::SetOnkeystatuseschange(EventHandlerNonNull* aCallback)
|
||||
{
|
||||
SetEventHandler(nsGkAtoms::onkeystatuseschange, EmptyString(), aCallback);
|
||||
}
|
||||
|
||||
EventHandlerNonNull*
|
||||
MediaKeySession::GetOnmessage()
|
||||
{
|
||||
return GetEventHandler(nsGkAtoms::onmessage, EmptyString());
|
||||
}
|
||||
|
||||
void
|
||||
MediaKeySession::SetOnmessage(EventHandlerNonNull* aCallback)
|
||||
{
|
||||
SetEventHandler(nsGkAtoms::onmessage, EmptyString(), aCallback);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
@ -94,6 +94,12 @@ public:
|
||||
|
||||
void SetExpiration(double aExpiry);
|
||||
|
||||
mozilla::dom::EventHandlerNonNull* GetOnkeystatuseschange();
|
||||
void SetOnkeystatuseschange(mozilla::dom::EventHandlerNonNull* aCallback);
|
||||
|
||||
mozilla::dom::EventHandlerNonNull* GetOnmessage();
|
||||
void SetOnmessage(mozilla::dom::EventHandlerNonNull* aCallback);
|
||||
|
||||
// Process-unique identifier.
|
||||
uint32_t Token() const;
|
||||
|
||||
|
@ -6,7 +6,6 @@
|
||||
#include "VideoDecoderManagerParent.h"
|
||||
#include "VideoDecoderParent.h"
|
||||
#include "base/thread.h"
|
||||
#include "mozilla/StaticMutex.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "mozilla/Services.h"
|
||||
#include "mozilla/Observer.h"
|
||||
@ -15,6 +14,7 @@
|
||||
#include "nsIEventTarget.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "ImageContainer.h"
|
||||
#include "mozilla/layers/VideoBridgeChild.h"
|
||||
|
||||
#if XP_WIN
|
||||
#include <objbase.h>
|
||||
@ -28,53 +28,11 @@ using namespace ipc;
|
||||
using namespace layers;
|
||||
using namespace gfx;
|
||||
|
||||
|
||||
struct ImageMapEntry {
|
||||
ImageMapEntry()
|
||||
: mOwner(nullptr)
|
||||
{}
|
||||
ImageMapEntry(layers::Image* aImage, VideoDecoderManagerParent* aOwner)
|
||||
: mImage(aImage)
|
||||
, mOwner(aOwner)
|
||||
{}
|
||||
~ImageMapEntry() {}
|
||||
|
||||
RefPtr<layers::Image> mImage;
|
||||
VideoDecoderManagerParent* mOwner;
|
||||
};
|
||||
std::map<uint64_t, ImageMapEntry> sImageMap;
|
||||
StaticMutex sImageMutex;
|
||||
|
||||
/* static */ layers::Image*
|
||||
VideoDecoderManagerParent::LookupImage(const SurfaceDescriptorGPUVideo& aSD)
|
||||
{
|
||||
StaticMutexAutoLock lock(sImageMutex);
|
||||
return sImageMap[aSD.handle()].mImage;
|
||||
}
|
||||
|
||||
SurfaceDescriptorGPUVideo
|
||||
VideoDecoderManagerParent::StoreImage(Image* aImage)
|
||||
VideoDecoderManagerParent::StoreImage(TextureClient* aTexture)
|
||||
{
|
||||
StaticMutexAutoLock lock(sImageMutex);
|
||||
|
||||
static uint64_t sImageCount = 0;
|
||||
sImageMap[++sImageCount] = ImageMapEntry(aImage, this);
|
||||
|
||||
return SurfaceDescriptorGPUVideo(sImageCount);
|
||||
}
|
||||
|
||||
void
|
||||
VideoDecoderManagerParent::ClearAllOwnedImages()
|
||||
{
|
||||
StaticMutexAutoLock lock(sImageMutex);
|
||||
for (auto it = sImageMap.begin(); it != sImageMap.end();)
|
||||
{
|
||||
if ((*it).second.mOwner == this) {
|
||||
it = sImageMap.erase(it);
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
mTextureMap[aTexture->GetSerial()] = aTexture;
|
||||
return SurfaceDescriptorGPUVideo(aTexture->GetSerial());
|
||||
}
|
||||
|
||||
StaticRefPtr<nsIThread> sVideoDecoderManagerThread;
|
||||
@ -126,6 +84,9 @@ VideoDecoderManagerParent::StartupThreads()
|
||||
MOZ_ASSERT(hr == S_OK);
|
||||
}), NS_DISPATCH_NORMAL);
|
||||
#endif
|
||||
sVideoDecoderManagerThread->Dispatch(NS_NewRunnableFunction([]() {
|
||||
layers::VideoBridgeChild::Startup();
|
||||
}), NS_DISPATCH_NORMAL);
|
||||
|
||||
sManagerTaskQueue = new TaskQueue(managerThread.forget());
|
||||
|
||||
@ -156,6 +117,10 @@ VideoDecoderManagerParent::ShutdownThreads()
|
||||
sManagerTaskQueue->AwaitShutdownAndIdle();
|
||||
sVideoDecoderTaskThread->Shutdown();
|
||||
sVideoDecoderTaskThread = nullptr;
|
||||
|
||||
sVideoDecoderManagerThread->Dispatch(NS_NewRunnableFunction([]() {
|
||||
layers::VideoBridgeChild::Shutdown();
|
||||
}), NS_DISPATCH_SYNC);
|
||||
sVideoDecoderManagerThread->Shutdown();
|
||||
sVideoDecoderManagerThread = nullptr;
|
||||
}
|
||||
@ -193,8 +158,6 @@ VideoDecoderManagerParent::VideoDecoderManagerParent()
|
||||
VideoDecoderManagerParent::~VideoDecoderManagerParent()
|
||||
{
|
||||
MOZ_COUNT_DTOR(VideoDecoderManagerParent);
|
||||
|
||||
ClearAllOwnedImages();
|
||||
}
|
||||
|
||||
PVideoDecoderParent*
|
||||
@ -231,8 +194,7 @@ VideoDecoderManagerParent::DeallocPVideoDecoderManagerParent()
|
||||
bool
|
||||
VideoDecoderManagerParent::RecvDeallocateSurfaceDescriptorGPUVideo(const SurfaceDescriptorGPUVideo& aSD)
|
||||
{
|
||||
StaticMutexAutoLock lock(sImageMutex);
|
||||
sImageMap.erase(aSD.handle());
|
||||
mTextureMap.erase(aSD.handle());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -19,8 +19,7 @@ public:
|
||||
static bool CreateForContent(Endpoint<PVideoDecoderManagerParent>&& aEndpoint);
|
||||
|
||||
// Can be called from any thread
|
||||
static layers::Image* LookupImage(const SurfaceDescriptorGPUVideo& aSD);
|
||||
SurfaceDescriptorGPUVideo StoreImage(layers::Image* aImage);
|
||||
SurfaceDescriptorGPUVideo StoreImage(layers::TextureClient* aImage);
|
||||
|
||||
static void StartupThreads();
|
||||
static void ShutdownThreads();
|
||||
@ -41,9 +40,9 @@ protected:
|
||||
VideoDecoderManagerParent();
|
||||
~VideoDecoderManagerParent();
|
||||
|
||||
void ClearAllOwnedImages();
|
||||
|
||||
void Open(Endpoint<PVideoDecoderManagerParent>&& aEndpoint);
|
||||
|
||||
std::map<uint64_t, RefPtr<layers::TextureClient>> mTextureMap;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
@ -7,8 +7,8 @@
|
||||
#include "mozilla/Unused.h"
|
||||
#include "mozilla/layers/CompositorThread.h"
|
||||
#include "base/thread.h"
|
||||
#include "mozilla/layers/TextureHost.h"
|
||||
#include "mozilla/layers/PTextureParent.h"
|
||||
#include "mozilla/layers/TextureClient.h"
|
||||
#include "mozilla/layers/VideoBridgeChild.h"
|
||||
#include "MediaInfo.h"
|
||||
#include "VideoDecoderManagerParent.h"
|
||||
#ifdef XP_WIN
|
||||
@ -164,6 +164,13 @@ VideoDecoderParent::Output(MediaData* aData)
|
||||
|
||||
MOZ_ASSERT(video->mImage, "Decoded video must output a layer::Image to be used with VideoDecoderParent");
|
||||
|
||||
RefPtr<TextureClient> texture = video->mImage->GetTextureClient(VideoBridgeChild::GetSingleton());
|
||||
|
||||
if (texture && !texture->IsAddedToCompositableClient()) {
|
||||
texture->InitIPDLActor(VideoBridgeChild::GetSingleton());
|
||||
texture->SetAddedToCompositableClient();
|
||||
}
|
||||
|
||||
VideoDataIPDL output(MediaDataIPDL(data->mOffset,
|
||||
data->mTime,
|
||||
data->mTimecode,
|
||||
@ -171,7 +178,7 @@ VideoDecoderParent::Output(MediaData* aData)
|
||||
data->mFrames,
|
||||
data->mKeyframe),
|
||||
video->mDisplay,
|
||||
self->GetManager()->StoreImage(video->mImage),
|
||||
texture ? self->mParent->StoreImage(texture) : SurfaceDescriptorGPUVideo(0),
|
||||
video->mFrameID);
|
||||
Unused << self->SendOutput(output);
|
||||
}));
|
||||
|
@ -48,8 +48,6 @@ public:
|
||||
private:
|
||||
~VideoDecoderParent();
|
||||
|
||||
VideoDecoderManagerParent* GetManager() { return static_cast<VideoDecoderManagerParent*>(Manager()); }
|
||||
|
||||
RefPtr<VideoDecoderManagerParent> mParent;
|
||||
RefPtr<VideoDecoderParent> mIPDLSelfRef;
|
||||
RefPtr<TaskQueue> mManagerTaskQueue;
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "mozilla/gfx/DeviceManagerDx.h"
|
||||
#include "mozilla/layers/D3D11ShareHandleImage.h"
|
||||
#include "mozilla/layers/ImageBridgeChild.h"
|
||||
#include "mozilla/layers/VideoBridgeChild.h"
|
||||
#include "mozilla/Telemetry.h"
|
||||
#include "MediaTelemetryConstants.h"
|
||||
#include "mfapi.h"
|
||||
@ -431,8 +432,11 @@ D3D9DXVA2Manager::Init(nsACString& aFailureReason)
|
||||
if (layers::ImageBridgeChild::GetSingleton()) {
|
||||
mTextureClientAllocator = new D3D9RecycleAllocator(layers::ImageBridgeChild::GetSingleton().get(),
|
||||
mDevice);
|
||||
mTextureClientAllocator->SetMaxPoolSize(5);
|
||||
} else {
|
||||
mTextureClientAllocator = new D3D9RecycleAllocator(layers::VideoBridgeChild::GetSingleton(),
|
||||
mDevice);
|
||||
}
|
||||
mTextureClientAllocator->SetMaxPoolSize(5);
|
||||
|
||||
Telemetry::Accumulate(Telemetry::MEDIA_DECODER_BACKEND_USED,
|
||||
uint32_t(media::MediaDecoderBackend::WMFDXVA2D3D9));
|
||||
@ -762,8 +766,11 @@ D3D11DXVA2Manager::Init(nsACString& aFailureReason)
|
||||
if (layers::ImageBridgeChild::GetSingleton()) {
|
||||
mTextureClientAllocator = new D3D11RecycleAllocator(layers::ImageBridgeChild::GetSingleton().get(),
|
||||
mDevice);
|
||||
mTextureClientAllocator->SetMaxPoolSize(5);
|
||||
} else {
|
||||
mTextureClientAllocator = new D3D11RecycleAllocator(layers::VideoBridgeChild::GetSingleton(),
|
||||
mDevice);
|
||||
}
|
||||
mTextureClientAllocator->SetMaxPoolSize(5);
|
||||
|
||||
Telemetry::Accumulate(Telemetry::MEDIA_DECODER_BACKEND_USED,
|
||||
uint32_t(media::MediaDecoderBackend::WMFDXVA2D3D11));
|
||||
|
@ -83,6 +83,25 @@ function startTest(test, token)
|
||||
onsessioncreated: function(session) {
|
||||
sessions.push(session);
|
||||
session.addEventListener("keystatuseschange", KeysChangeFunc(session, test.keys, token), false);
|
||||
|
||||
session.numKeystatuseschangeEvents = 0;
|
||||
session.numOnkeystatuseschangeEvents = 0;
|
||||
|
||||
session.addEventListener("keystatuseschange", function() {
|
||||
session.numKeystatuseschangeEvents += 1;
|
||||
});
|
||||
session.onkeystatuseschange = function() {
|
||||
session.numOnkeystatuseschangeEvents += 1;
|
||||
};
|
||||
|
||||
session.numMessageEvents = 0;
|
||||
session.numOnMessageEvents = 0;
|
||||
session.addEventListener("message", function() {
|
||||
session.numMessageEvents += 1;
|
||||
});
|
||||
session.onmessage = function() {
|
||||
session.numOnMessageEvents += 1;
|
||||
};
|
||||
}
|
||||
}
|
||||
);
|
||||
@ -129,6 +148,13 @@ function startTest(test, token)
|
||||
Log(token, "session[" + session.sessionId + "] key " + kid + " = " + (session.keyIdsReceived[kid] ? "true" : "false"));
|
||||
if (session.keyIdsReceived[kid]) { keyIdsReceived[kid] = true; }
|
||||
}
|
||||
ok(session.numKeystatuseschangeEvents > 0, TimeStamp(token) + " should get key status changes");
|
||||
is(session.numKeystatuseschangeEvents, session.numOnkeystatuseschangeEvents,
|
||||
TimeStamp(token) + " should have as many keystatuseschange event listener calls as event handler calls.");
|
||||
|
||||
ok(session.numMessageEvents > 0, TimeStamp(token) + " should get message events");
|
||||
is(session.numMessageEvents, session.numOnMessageEvents,
|
||||
TimeStamp(token) + " should have as many message event listener calls as event handler calls.");
|
||||
}
|
||||
for (var kid in keyIdsReceived) {
|
||||
ok(keyIdsReceived[kid], TimeStamp(token) + " key with id " + kid + " was usable as expected");
|
||||
|
@ -58,6 +58,7 @@ function startTest(test, token)
|
||||
|
||||
var gotEncrypted = 0;
|
||||
var gotWaitingForKey = 0;
|
||||
var gotOnwaitingforkey = 0;
|
||||
|
||||
v.addEventListener("encrypted", function() {
|
||||
gotEncrypted += 1;
|
||||
@ -69,6 +70,10 @@ function startTest(test, token)
|
||||
TestIfDoneDelaying()
|
||||
});
|
||||
|
||||
v.onwaitingforkey = function() {
|
||||
gotOnwaitingforkey += 1;
|
||||
};
|
||||
|
||||
v.addEventListener("loadedmetadata", function() {
|
||||
ok(SpecialPowers.do_lookupGetter(v, "isEncrypted").apply(v),
|
||||
TimeStamp(token) + " isEncrypted should be true");
|
||||
@ -81,6 +86,7 @@ function startTest(test, token)
|
||||
// I.e. one waitingForKey should be fired, after which, we process all sessions,
|
||||
// so it should not be possible to be blocked by a key after that point.
|
||||
ok(gotWaitingForKey == 1, "Expected number 1 wait, got: " + gotWaitingForKey);
|
||||
ok(gotOnwaitingforkey == gotWaitingForKey, "Should have as many event listener calls as event handler calls, got: " + gotOnwaitingforkey);
|
||||
|
||||
v.closeSessions().then(() => manager.finished(token));
|
||||
});
|
||||
|
@ -207,6 +207,10 @@ MediaEngineRemoteVideoSource::Stop(mozilla::SourceMediaStream* aSource,
|
||||
{
|
||||
MonitorAutoLock lock(mMonitor);
|
||||
|
||||
// Drop any cached image so we don't start with a stale image on next
|
||||
// usage
|
||||
mImage = nullptr;
|
||||
|
||||
size_t i = mSources.IndexOf(aSource);
|
||||
if (i == mSources.NoIndex) {
|
||||
// Already stopped - this is allowed
|
||||
@ -227,9 +231,6 @@ MediaEngineRemoteVideoSource::Stop(mozilla::SourceMediaStream* aSource,
|
||||
}
|
||||
|
||||
mState = kStopped;
|
||||
// Drop any cached image so we don't start with a stale image on next
|
||||
// usage
|
||||
mImage = nullptr;
|
||||
}
|
||||
|
||||
mozilla::camera::GetChildAndCall(
|
||||
|
@ -248,6 +248,7 @@ nsPluginTag::nsPluginTag(nsPluginInfo* aPluginInfo,
|
||||
aPluginInfo->fMimeDescriptionArray,
|
||||
aPluginInfo->fExtensionArray,
|
||||
aPluginInfo->fVariantCount);
|
||||
InitSandboxLevel();
|
||||
EnsureMembersAreUTF8();
|
||||
FixupVersion();
|
||||
}
|
||||
|
@ -120,8 +120,10 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=803225
|
||||
Services.ppmm.addMessageListener("Test:content-ready", function contentReadyListener() {
|
||||
Services.ppmm.removeMessageListener("Test:content-ready", contentReadyListener);
|
||||
sendAsyncMessage("Test:content-ready-forward");
|
||||
Services.ppmm.removeDelayedProcessScript(pScript);
|
||||
})
|
||||
Services.ppmm.loadProcessScript("data:,new " + function () {
|
||||
|
||||
var pScript = "data:,new " + function () {
|
||||
var os = Components.classes["@mozilla.org/observer-service;1"]
|
||||
.getService(Components.interfaces.nsIObserverService);
|
||||
var observer = {
|
||||
@ -133,7 +135,9 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=803225
|
||||
}
|
||||
};
|
||||
os.addObserver(observer, "content-document-global-created", false);
|
||||
}, false);
|
||||
}
|
||||
|
||||
Services.ppmm.loadProcessScript(pScript, true);
|
||||
|
||||
var uri = ioService.newURI("mailto:foo@bar.com", null, null);
|
||||
webHandler.launchWithURI(uri);
|
||||
|
@ -31,7 +31,7 @@ nsSVGElement::StringInfo SVGMPathElement::sStringInfo[2] =
|
||||
{ &nsGkAtoms::href, kNameSpaceID_XLink, false }
|
||||
};
|
||||
|
||||
// Cycle collection magic -- based on nsSVGUseElement
|
||||
// Cycle collection magic -- based on SVGUseElement
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(SVGMPathElement)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(SVGMPathElement,
|
||||
|
@ -18,7 +18,7 @@ interface FileSystemDirectoryEntry : FileSystemEntry {
|
||||
optional ErrorCallback errorCallback);
|
||||
|
||||
// This method is not implemented. ErrorCallback will be called
|
||||
// with NS_ERROR_DOM_NOT_SUPPORTED_ERR.
|
||||
// with SecurityError
|
||||
void removeRecursively(VoidCallback successCallback,
|
||||
optional ErrorCallback errorCallback);
|
||||
};
|
||||
|
@ -10,8 +10,7 @@ callback interface BlobCallback {
|
||||
|
||||
interface FileSystemFileEntry : FileSystemEntry {
|
||||
// the successCallback should be a FileWriteCallback but this method is not
|
||||
// implemented. ErrorCallback will be called with
|
||||
// NS_ERROR_DOM_NOT_SUPPORTED_ERR.
|
||||
// implemented. ErrorCallback will be called with SecurityError.
|
||||
void createWriter (VoidCallback successCallback,
|
||||
optional ErrorCallback errorCallback);
|
||||
|
||||
|