From 7fc52fd3c94d699c2568a47c6c38588a34186a4b Mon Sep 17 00:00:00 2001 From: Geoff Lankow Date: Fri, 5 Aug 2011 23:55:49 +1200 Subject: [PATCH 01/63] Bug 668710 - Move mockObjects.js in with the rest of SimpleTest; r=dao --HG-- rename : toolkit/content/tests/browser/common/mockObjects.js => testing/mochitest/tests/SimpleTest/MockObjects.js --- dom/tests/mochitest/bugs/test_bug61098.html | 2 +- testing/mochitest/jar.mn | 4 ++-- testing/mochitest/tests/SimpleTest/Makefile.in | 4 ++-- .../mochitest/tests/SimpleTest/MockObjects.js | 0 toolkit/content/tests/browser/common/Makefile.in | 1 - toolkit/content/tests/browser/common/mockTransfer.js | 3 +-- 6 files changed, 6 insertions(+), 8 deletions(-) rename toolkit/content/tests/browser/common/mockObjects.js => testing/mochitest/tests/SimpleTest/MockObjects.js (100%) diff --git a/dom/tests/mochitest/bugs/test_bug61098.html b/dom/tests/mochitest/bugs/test_bug61098.html index b1c3952880ca..50be34d21947 100644 --- a/dom/tests/mochitest/bugs/test_bug61098.html +++ b/dom/tests/mochitest/bugs/test_bug61098.html @@ -8,7 +8,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=61098 - + diff --git a/testing/mochitest/jar.mn b/testing/mochitest/jar.mn index fd2b0fd1d371..342f9637e5a3 100644 --- a/testing/mochitest/jar.mn +++ b/testing/mochitest/jar.mn @@ -23,8 +23,8 @@ mochikit.jar: content/tests/SimpleTest/test.css (tests/SimpleTest/test.css) content/tests/SimpleTest/TestRunner.js (tests/SimpleTest/TestRunner.js) content/tests/SimpleTest/WindowSnapshot.js (tests/SimpleTest/WindowSnapshot.js) - content/tests/SimpleTest/mockObjects.js (../../toolkit/content/tests/browser/common/mockObjects.js) - content/tests/SimpleTest/docshell_helpers.js (../..//docshell/test/chrome/docshell_helpers.js) + content/tests/SimpleTest/MockObjects.js (tests/SimpleTest/MockObjects.js) + content/tests/SimpleTest/docshell_helpers.js (../../docshell/test/chrome/docshell_helpers.js) % resource mochikit %modules/ modules/MockFilePicker.jsm (MockFilePicker.jsm) diff --git a/testing/mochitest/tests/SimpleTest/Makefile.in b/testing/mochitest/tests/SimpleTest/Makefile.in index 87502e97b66a..79557523c4dd 100644 --- a/testing/mochitest/tests/SimpleTest/Makefile.in +++ b/testing/mochitest/tests/SimpleTest/Makefile.in @@ -53,8 +53,8 @@ _SIMPLETEST_FILES = MozillaLogger.js \ WindowSnapshot.js \ specialpowersAPI.js \ SpecialPowersObserverAPI.js \ - $(DEPTH)/toolkit/content/tests/browser/common/mockObjects.js \ - $(DEPTH)/docshell/test/chrome/docshell_helpers.js \ + MockObjects.js \ + $(DEPTH)/docshell/test/chrome/docshell_helpers.js \ $(NULL) libs:: $(_SIMPLETEST_FILES) diff --git a/toolkit/content/tests/browser/common/mockObjects.js b/testing/mochitest/tests/SimpleTest/MockObjects.js similarity index 100% rename from toolkit/content/tests/browser/common/mockObjects.js rename to testing/mochitest/tests/SimpleTest/MockObjects.js diff --git a/toolkit/content/tests/browser/common/Makefile.in b/toolkit/content/tests/browser/common/Makefile.in index 9d8e2f9be1ae..333abd319c9e 100644 --- a/toolkit/content/tests/browser/common/Makefile.in +++ b/toolkit/content/tests/browser/common/Makefile.in @@ -45,7 +45,6 @@ include $(DEPTH)/config/autoconf.mk include $(topsrcdir)/config/rules.mk _COMMON_FILES = \ - mockObjects.js \ mockTransfer.js \ $(NULL) diff --git a/toolkit/content/tests/browser/common/mockTransfer.js b/toolkit/content/tests/browser/common/mockTransfer.js index bdcd1deeaa1e..b0c22c90ea8a 100644 --- a/toolkit/content/tests/browser/common/mockTransfer.js +++ b/toolkit/content/tests/browser/common/mockTransfer.js @@ -36,8 +36,7 @@ Cc["@mozilla.org/moz/jssubscript-loader;1"] .getService(Ci.mozIJSSubScriptLoader) - .loadSubScript("chrome://mochitests/content/browser/toolkit/content/tests/browser/common/mockObjects.js", - this); + .loadSubScript("chrome://mochikit/content/tests/SimpleTest/MockObjects.js", this); var mockTransferCallback; From 50a0f04721591a4c0575b4261696587a820df708 Mon Sep 17 00:00:00 2001 From: Mike Hommey Date: Fri, 18 Nov 2011 08:54:17 +0100 Subject: [PATCH 02/63] Bug 702764 part 1 - Use RUSAGE_THREAD for library loading time consumption reporting. r=tglek --- other-licenses/android/APKOpen.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/other-licenses/android/APKOpen.cpp b/other-licenses/android/APKOpen.cpp index b49d6eb1eb88..1f3817700b03 100644 --- a/other-licenses/android/APKOpen.cpp +++ b/other-licenses/android/APKOpen.cpp @@ -62,6 +62,11 @@ #include #include +/* Android headers don't define RUSAGE_THREAD */ +#ifndef RUSAGE_THREAD +#define RUSAGE_THREAD 1 +#endif + /* compression methods */ #define STORE 0 #define DEFLATE 8 @@ -580,7 +585,7 @@ loadLibs(const char *apkName) struct timeval t0, t1; gettimeofday(&t0, 0); struct rusage usage1; - getrusage(RUSAGE_SELF, &usage1); + getrusage(RUSAGE_THREAD, &usage1); void *zip = map_file(apkName); struct cdir_end *dirend = (struct cdir_end *)((char *)zip + zip_size - sizeof(*dirend)); @@ -647,7 +652,7 @@ loadLibs(const char *apkName) #undef GETFUNC gettimeofday(&t1, 0); struct rusage usage2; - getrusage(RUSAGE_SELF, &usage2); + getrusage(RUSAGE_THREAD, &usage2); __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Loaded libs in %dms total, %dms user, %dms system, %d faults", (t1.tv_sec - t0.tv_sec)*1000 + (t1.tv_usec - t0.tv_usec)/1000, (usage2.ru_utime.tv_sec - usage1.ru_utime.tv_sec)*1000 + (usage2.ru_utime.tv_usec - usage1.ru_utime.tv_usec)/1000, From e08d276b14877b048562e2d2a17720d038448810 Mon Sep 17 00:00:00 2001 From: Mike Hommey Date: Fri, 18 Nov 2011 08:54:27 +0100 Subject: [PATCH 03/63] Bug 702764 part 2 - Make nsAppStartup::GetStartupInfo more flexible. r=tglek --- toolkit/components/startup/Makefile.in | 4 + .../components/startup/StartupTimeline.cpp | 49 ++++++++++ toolkit/components/startup/StartupTimeline.h | 89 ++++++++++++++++++ toolkit/components/startup/nsAppStartup.cpp | 94 +++++++------------ toolkit/components/telemetry/Telemetry.h | 1 + .../telemetry/TelemetryHistograms.h | 2 +- toolkit/xre/nsAppRunner.cpp | 5 +- view/src/nsViewManager.cpp | 5 +- xpfe/appshell/src/nsAppShellService.cpp | 6 +- 9 files changed, 183 insertions(+), 72 deletions(-) create mode 100644 toolkit/components/startup/StartupTimeline.cpp create mode 100644 toolkit/components/startup/StartupTimeline.h diff --git a/toolkit/components/startup/Makefile.in b/toolkit/components/startup/Makefile.in index ce24485be1e0..ba2e78ea62cb 100644 --- a/toolkit/components/startup/Makefile.in +++ b/toolkit/components/startup/Makefile.in @@ -50,8 +50,12 @@ LIBXUL_LIBRARY = 1 CPPSRCS = \ nsAppStartup.cpp \ + StartupTimeline.cpp \ $(NULL) +EXPORTS_NAMESPACES = mozilla +EXPORTS_mozilla = StartupTimeline.h + ifeq (os2,$(MOZ_WIDGET_TOOLKIT)) CPPSRCS += nsUserInfoOS2.cpp else diff --git a/toolkit/components/startup/StartupTimeline.cpp b/toolkit/components/startup/StartupTimeline.cpp new file mode 100644 index 000000000000..474e4d8c2bc6 --- /dev/null +++ b/toolkit/components/startup/StartupTimeline.cpp @@ -0,0 +1,49 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org + * + * The Initial Developer of the Original Code is + * Mozilla Foundation + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mike Hommey + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "StartupTimeline.h" + +namespace mozilla { + +PRTime StartupTimeline::sStartupTimeline[StartupTimeline::MAX_EVENT_ID]; +const char *StartupTimeline::sStartupTimelineDesc[StartupTimeline::MAX_EVENT_ID] = { +#define mozilla_StartupTimeline_Event(ev, desc) desc, +#include "StartupTimeline.h" +#undef mozilla_StartupTimeline_Event +}; + +} diff --git a/toolkit/components/startup/StartupTimeline.h b/toolkit/components/startup/StartupTimeline.h new file mode 100644 index 000000000000..992e9bd9f0d2 --- /dev/null +++ b/toolkit/components/startup/StartupTimeline.h @@ -0,0 +1,89 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org + * + * The Initial Developer of the Original Code is + * Mozilla Foundation + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mike Hommey + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifdef mozilla_StartupTimeline_Event +mozilla_StartupTimeline_Event(PROCESS_CREATION, "process") +mozilla_StartupTimeline_Event(MAIN, "main") +mozilla_StartupTimeline_Event(FIRST_PAINT, "firstPaint") +mozilla_StartupTimeline_Event(SESSION_RESTORED, "sessionRestored") +mozilla_StartupTimeline_Event(CREATE_TOP_LEVEL_WINDOW, "createTopLevelWindow") +#else + +#ifndef mozilla_StartupTimeline +#define mozilla_StartupTimeline + +#include "prtime.h" +#include "nscore.h" + +namespace mozilla { + +class StartupTimeline { +public: + enum Event { + #define mozilla_StartupTimeline_Event(ev, z) ev, + #include __FILE__ + #undef mozilla_StartupTimeline_Event + MAX_EVENT_ID + }; + + static PRTime Get(Event ev) { + return sStartupTimeline[ev]; + } + + static const char *Describe(Event ev) { + return sStartupTimelineDesc[ev]; + } + + static void Record(Event ev, PRTime when = PR_Now()) { + sStartupTimeline[ev] = when; + } + + static void RecordOnce(Event ev, PRTime when = PR_Now()) { + if (!sStartupTimeline[ev]) + sStartupTimeline[ev] = when; + } + +private: + static NS_EXTERNAL_VIS_(PRTime) sStartupTimeline[MAX_EVENT_ID]; + static NS_EXTERNAL_VIS_(const char *) sStartupTimelineDesc[MAX_EVENT_ID]; +}; + +} + +#endif /* mozilla_StartupTimeline */ + +#endif /* mozilla_StartupTimeline_Event */ diff --git a/toolkit/components/startup/nsAppStartup.cpp b/toolkit/components/startup/nsAppStartup.cpp index c0a02db11873..a5cb976d57ea 100644 --- a/toolkit/components/startup/nsAppStartup.cpp +++ b/toolkit/components/startup/nsAppStartup.cpp @@ -95,18 +95,11 @@ #endif #include "mozilla/Telemetry.h" +#include "mozilla/StartupTimeline.h" static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID); using namespace mozilla; -extern PRTime gXRE_mainTimestamp; -// The following tracks our overhead between reaching XRE_main and loading any XUL -extern PRTime gCreateTopLevelWindowTimestamp;// Timestamp of the first call to - // nsAppShellService::CreateTopLevelWindow -extern PRTime gFirstPaintTimestamp; -// mfinklesessionstore-browser-state-restored might be a better choice than the one below -static PRTime gRestoredTimestamp = 0; // Timestamp of sessionstore-windows-restored -static PRTime gProcessCreationTimestamp = 0;// Timestamp of sessionstore-windows-restored PRUint32 gRestartMode = 0; @@ -567,7 +560,7 @@ nsAppStartup::Observe(nsISupports *aSubject, } else if (!strcmp(aTopic, "xul-window-destroyed")) { ExitLastWindowClosingSurvivalArea(); } else if (!strcmp(aTopic, "sessionstore-windows-restored")) { - gRestoredTimestamp = PR_Now(); + StartupTimeline::Record(StartupTimeline::SESSION_RESTORED); } else { NS_ERROR("Unexpected observer topic."); } @@ -607,7 +600,6 @@ static void ThreadedCalculateProcessCreationTimestamp(void *aClosure) { PRTime now = PR_Now(); - gProcessCreationTimestamp = 0; long hz = sysconf(_SC_CLK_TCK); if (!hz) return; @@ -622,7 +614,7 @@ ThreadedCalculateProcessCreationTimestamp(void *aClosure) return; PRTime interval = (thread_jiffies - self_jiffies) * PR_USEC_PER_SEC / hz; - gProcessCreationTimestamp = now - interval; + StartupTimeline::Record(StartupTimeline::PROCESS_CREATION, now - interval); } static PRTime @@ -637,7 +629,7 @@ CalculateProcessCreationTimestamp() 0); PR_JoinThread(thread); - return gProcessCreationTimestamp; + return StartupTimeline::Get(StartupTimeline::PROCESS_CREATION); } #elif defined(XP_WIN) static PRTime @@ -703,23 +695,6 @@ CalculateProcessCreationTimestamp() } #endif -static void -MaybeDefineProperty(JSContext *cx, JSObject *obj, const char *name, PRTime timestamp) -{ - if (!timestamp) - return; - JSObject *date = js_NewDateObjectMsec(cx, timestamp/PR_USEC_PER_MSEC); - JS_DefineProperty(cx, obj, name, OBJECT_TO_JSVAL(date), NULL, NULL, JSPROP_ENUMERATE); -} - -enum { - INVALID_PROCESS_CREATION = 0, - INVALID_MAIN, - INVALID_FIRST_PAINT, - INVALID_SESSION_RESTORED, - INVALID_CREATE_TOP_LEVEL_WINDOW -}; - NS_IMETHODIMP nsAppStartup::GetStartupInfo() { @@ -748,40 +723,37 @@ nsAppStartup::GetStartupInfo() *retvalPtr = OBJECT_TO_JSVAL(obj); ncc->SetReturnValueWasSet(true); - char *moz_app_restart = PR_GetEnv("MOZ_APP_RESTART"); - if (moz_app_restart) { - gProcessCreationTimestamp = nsCRT::atoll(moz_app_restart) * PR_USEC_PER_MSEC; - } else if (!gProcessCreationTimestamp) { - gProcessCreationTimestamp = CalculateProcessCreationTimestamp(); - } - // Bug 670008: Avoid obviously invalid process creation times - if (PR_Now() <= gProcessCreationTimestamp) { - gProcessCreationTimestamp = 0; - Telemetry::Accumulate(Telemetry::STARTUP_MEASUREMENT_ERRORS, INVALID_PROCESS_CREATION); + PRTime ProcessCreationTimestamp = StartupTimeline::Get(StartupTimeline::PROCESS_CREATION); + + if (!ProcessCreationTimestamp) { + char *moz_app_restart = PR_GetEnv("MOZ_APP_RESTART"); + if (moz_app_restart) { + ProcessCreationTimestamp = nsCRT::atoll(moz_app_restart) * PR_USEC_PER_MSEC; + } else { + ProcessCreationTimestamp = CalculateProcessCreationTimestamp(); + } + // Bug 670008: Avoid obviously invalid process creation times + if (PR_Now() <= ProcessCreationTimestamp) { + ProcessCreationTimestamp = -1; + Telemetry::Accumulate(Telemetry::STARTUP_MEASUREMENT_ERRORS, StartupTimeline::PROCESS_CREATION); + } + StartupTimeline::Record(StartupTimeline::PROCESS_CREATION, ProcessCreationTimestamp); } - MaybeDefineProperty(cx, obj, "process", gProcessCreationTimestamp); - - if (gXRE_mainTimestamp < gProcessCreationTimestamp) - Telemetry::Accumulate(Telemetry::STARTUP_MEASUREMENT_ERRORS, INVALID_MAIN); - - // always define main to aid with bug 689256 - MaybeDefineProperty(cx, obj, "main", gXRE_mainTimestamp); - - if (gCreateTopLevelWindowTimestamp >= gProcessCreationTimestamp) - MaybeDefineProperty(cx, obj, "createTopLevelWindow", gCreateTopLevelWindowTimestamp); - else - Telemetry::Accumulate(Telemetry::STARTUP_MEASUREMENT_ERRORS, INVALID_CREATE_TOP_LEVEL_WINDOW); - - if (gFirstPaintTimestamp >= gXRE_mainTimestamp) - MaybeDefineProperty(cx, obj, "firstPaint", gFirstPaintTimestamp); - else - Telemetry::Accumulate(Telemetry::STARTUP_MEASUREMENT_ERRORS, INVALID_FIRST_PAINT); - - if (gRestoredTimestamp >= gXRE_mainTimestamp) - MaybeDefineProperty(cx, obj, "sessionRestored", gRestoredTimestamp); - else - Telemetry::Accumulate(Telemetry::STARTUP_MEASUREMENT_ERRORS, INVALID_SESSION_RESTORED); + for (int i = StartupTimeline::PROCESS_CREATION; i < StartupTimeline::MAX_EVENT_ID; ++i) { + StartupTimeline::Event ev = static_cast(i); + if (StartupTimeline::Get(ev) > 0) { + // always define main to aid with bug 689256 + if ((ev != StartupTimeline::MAIN) && + (StartupTimeline::Get(ev) < StartupTimeline::Get(StartupTimeline::PROCESS_CREATION))) { + Telemetry::Accumulate(Telemetry::STARTUP_MEASUREMENT_ERRORS, i); + StartupTimeline::Record(ev, -1); + } else { + JSObject *date = js_NewDateObjectMsec(cx, StartupTimeline::Get(ev)/PR_USEC_PER_MSEC); + JS_DefineProperty(cx, obj, StartupTimeline::Describe(ev), OBJECT_TO_JSVAL(date), NULL, NULL, JSPROP_ENUMERATE); + } + } + } return NS_OK; } diff --git a/toolkit/components/telemetry/Telemetry.h b/toolkit/components/telemetry/Telemetry.h index 5ffd2835a60d..9e29b45c8840 100644 --- a/toolkit/components/telemetry/Telemetry.h +++ b/toolkit/components/telemetry/Telemetry.h @@ -41,6 +41,7 @@ #include "mozilla/GuardObjects.h" #include "mozilla/TimeStamp.h" +#include "mozilla/StartupTimeline.h" namespace base { class Histogram; diff --git a/toolkit/components/telemetry/TelemetryHistograms.h b/toolkit/components/telemetry/TelemetryHistograms.h index 5bfce5b984ab..6b821ad957c1 100644 --- a/toolkit/components/telemetry/TelemetryHistograms.h +++ b/toolkit/components/telemetry/TelemetryHistograms.h @@ -206,7 +206,7 @@ HISTOGRAM(MOZ_SQLITE_WEBAPPS_WRITE_B, 1, 32768, 3, LINEAR, "SQLite write (bytes) HISTOGRAM(MOZ_SQLITE_OTHER_WRITE_B, 1, 32768, 3, LINEAR, "SQLite write (bytes)") HISTOGRAM(MOZ_STORAGE_ASYNC_REQUESTS_MS, 1, 32768, 20, EXPONENTIAL, "mozStorage async requests completion (ms)") HISTOGRAM(MOZ_STORAGE_ASYNC_REQUESTS_SUCCESS, 0, 1, 2, BOOLEAN, "mozStorage async requests success") -HISTOGRAM(STARTUP_MEASUREMENT_ERRORS, 1, 4, 5, LINEAR, "Flags errors in startup calculation()") +HISTOGRAM(STARTUP_MEASUREMENT_ERRORS, 1, mozilla::StartupTimeline::MAX_EVENT_ID, mozilla::StartupTimeline::MAX_EVENT_ID + 1, LINEAR, "Flags errors in startup calculation()") HISTOGRAM(NETWORK_DISK_CACHE_OPEN, 1, 10000, 10, EXPONENTIAL, "Time spent opening disk cache (ms)") HISTOGRAM(NETWORK_DISK_CACHE_TRASHRENAME, 1, 10000, 10, EXPONENTIAL, "Time spent renaming bad Cache to Cache.Trash (ms)") HISTOGRAM(NETWORK_DISK_CACHE_DELETEDIR, 1, 10000, 10, EXPONENTIAL, "Time spent deleting disk cache (ms)") diff --git a/toolkit/xre/nsAppRunner.cpp b/toolkit/xre/nsAppRunner.cpp index 487a7af70702..85497a67619e 100644 --- a/toolkit/xre/nsAppRunner.cpp +++ b/toolkit/xre/nsAppRunner.cpp @@ -160,6 +160,7 @@ using mozilla::unused; #include "nsINIParser.h" #include "mozilla/Omnijar.h" +#include "mozilla/StartupTimeline.h" #include @@ -2604,8 +2605,6 @@ static DWORD InitDwriteBG(LPVOID lpdwThreadParam) } #endif -PRTime gXRE_mainTimestamp = 0; - #ifdef MOZ_X11 #ifndef MOZ_PLATFORM_MAEMO bool fire_glxtest_process(); @@ -2621,7 +2620,7 @@ XRE_main(int argc, char* argv[], const nsXREAppData* aAppData) SAMPLER_INIT(); SAMPLE_CHECKPOINT("Startup", "XRE_Main"); - gXRE_mainTimestamp = PR_Now(); + StartupTimeline::Record(StartupTimeline::MAIN); nsresult rv; ArgResult ar; diff --git a/view/src/nsViewManager.cpp b/view/src/nsViewManager.cpp index 0dc700a54158..c71be2405bac 100644 --- a/view/src/nsViewManager.cpp +++ b/view/src/nsViewManager.cpp @@ -59,8 +59,8 @@ #include "nsIPresShell.h" #include "nsPresContext.h" #include "nsEventStateManager.h" +#include "mozilla/StartupTimeline.h" -PRTime gFirstPaintTimestamp = 0; // Timestamp of the first paint event /** XXX TODO XXX @@ -413,8 +413,7 @@ void nsViewManager::RenderViews(nsView *aView, nsIWidget *aWidget, if (mObserver) { mObserver->Paint(aView, aWidget, aRegion, aIntRegion, aPaintDefaultBackground, aWillSendDidPaint); - if (!gFirstPaintTimestamp) - gFirstPaintTimestamp = PR_Now(); + mozilla::StartupTimeline::RecordOnce(mozilla::StartupTimeline::FIRST_PAINT); } } diff --git a/xpfe/appshell/src/nsAppShellService.cpp b/xpfe/appshell/src/nsAppShellService.cpp index ab3bc5959087..92e5cacaedb5 100644 --- a/xpfe/appshell/src/nsAppShellService.cpp +++ b/xpfe/appshell/src/nsAppShellService.cpp @@ -75,6 +75,7 @@ #include "nsIChromeRegistry.h" #include "mozilla/Preferences.h" +#include "mozilla/StartupTimeline.h" using namespace mozilla; @@ -156,8 +157,6 @@ nsAppShellService::DestroyHiddenWindow() return NS_OK; } -PRTime gCreateTopLevelWindowTimestamp = 0; - /* * Create a new top level window and display the given URL within it... */ @@ -172,8 +171,7 @@ nsAppShellService::CreateTopLevelWindow(nsIXULWindow *aParent, { nsresult rv; - if (!gCreateTopLevelWindowTimestamp) - gCreateTopLevelWindowTimestamp = PR_Now(); + StartupTimeline::RecordOnce(StartupTimeline::CREATE_TOP_LEVEL_WINDOW); nsWebShellWindow *newWindow = nsnull; rv = JustCreateTopWindow(aParent, aUrl, From 1f5cbbfc2ee541fa116f1ae25350dd90aefe7939 Mon Sep 17 00:00:00 2001 From: Mike Hommey Date: Fri, 18 Nov 2011 08:54:37 +0100 Subject: [PATCH 04/63] Bug 702764 part 3 - Add linker initialization and library loading timestamps for nsAppStartup::GetStartupInfo. r=tglek --- other-licenses/android/APKOpen.cpp | 17 +++++++++++++++++ other-licenses/android/Makefile.in | 2 ++ toolkit/components/startup/StartupTimeline.h | 2 ++ 3 files changed, 21 insertions(+) diff --git a/other-licenses/android/APKOpen.cpp b/other-licenses/android/APKOpen.cpp index 1f3817700b03..eea6eaefc426 100644 --- a/other-licenses/android/APKOpen.cpp +++ b/other-licenses/android/APKOpen.cpp @@ -72,6 +72,19 @@ #define DEFLATE 8 #define LZMA 14 +enum StartupEvent { +#define mozilla_StartupTimeline_Event(ev, z) ev, +#include "StartupTimeline.h" +#undef mozilla_StartupTimeline_Event +}; + +static uint64_t *sStartupTimeline; + +void StartupTimeline_Record(StartupEvent ev, struct timeval *tm) +{ + sStartupTimeline[ev] = (((uint64_t)tm->tv_sec * 1000000LL) + (uint64_t)tm->tv_usec); +} + struct local_file_header { uint32_t signature; uint16_t min_version; @@ -650,6 +663,7 @@ loadLibs(const char *apkName) GETFUNC(cameraCallbackBridge); GETFUNC(notifyBatteryChange); #undef GETFUNC + sStartupTimeline = (uint64_t *)__wrap_dlsym(xul_handle, "_ZN7mozilla15StartupTimeline16sStartupTimelineE"); gettimeofday(&t1, 0); struct rusage usage2; getrusage(RUSAGE_THREAD, &usage2); @@ -658,6 +672,9 @@ loadLibs(const char *apkName) (usage2.ru_utime.tv_sec - usage1.ru_utime.tv_sec)*1000 + (usage2.ru_utime.tv_usec - usage1.ru_utime.tv_usec)/1000, (usage2.ru_stime.tv_sec - usage1.ru_stime.tv_sec)*1000 + (usage2.ru_stime.tv_usec - usage1.ru_stime.tv_usec)/1000, usage2.ru_majflt-usage1.ru_majflt); + + StartupTimeline_Record(LINKER_INITIALIZED, &t0); + StartupTimeline_Record(LIBRARIES_LOADED, &t1); } extern "C" NS_EXPORT void JNICALL diff --git a/other-licenses/android/Makefile.in b/other-licenses/android/Makefile.in index c14508221dde..250d99c44f77 100644 --- a/other-licenses/android/Makefile.in +++ b/other-licenses/android/Makefile.in @@ -76,6 +76,8 @@ CSRCS = \ rt.c \ $(NULL) +LOCAL_INCLUDES += -I$(topsrcdir)/toolkit/components/startup + EXPORTS = APKOpen.h include $(topsrcdir)/config/rules.mk diff --git a/toolkit/components/startup/StartupTimeline.h b/toolkit/components/startup/StartupTimeline.h index 992e9bd9f0d2..4c63a1628a08 100644 --- a/toolkit/components/startup/StartupTimeline.h +++ b/toolkit/components/startup/StartupTimeline.h @@ -41,6 +41,8 @@ mozilla_StartupTimeline_Event(MAIN, "main") mozilla_StartupTimeline_Event(FIRST_PAINT, "firstPaint") mozilla_StartupTimeline_Event(SESSION_RESTORED, "sessionRestored") mozilla_StartupTimeline_Event(CREATE_TOP_LEVEL_WINDOW, "createTopLevelWindow") +mozilla_StartupTimeline_Event(LINKER_INITIALIZED, "linkerInitialized") +mozilla_StartupTimeline_Event(LIBRARIES_LOADED, "librariesLoaded") #else #ifndef mozilla_StartupTimeline From 856c07a21709a8fc5fb7be27bb758a14600ca1aa Mon Sep 17 00:00:00 2001 From: Mike Hommey Date: Fri, 18 Nov 2011 08:54:41 +0100 Subject: [PATCH 05/63] Bug 699734 - Export the _IO_stdin_used symbol. r=ted --- .../gnu-ld-scripts/jemalloc-standalone-linkage-version-script | 1 + 1 file changed, 1 insertion(+) diff --git a/build/unix/gnu-ld-scripts/jemalloc-standalone-linkage-version-script b/build/unix/gnu-ld-scripts/jemalloc-standalone-linkage-version-script index 3e3d827ff6e5..e18efb331beb 100644 --- a/build/unix/gnu-ld-scripts/jemalloc-standalone-linkage-version-script +++ b/build/unix/gnu-ld-scripts/jemalloc-standalone-linkage-version-script @@ -16,5 +16,6 @@ __malloc_hook; __realloc_hook; __memalign_hook; + _IO_stdin_used; local: *; }; From e4fd013a05987c7f6a1659f3e1931fbceccfe9d8 Mon Sep 17 00:00:00 2001 From: Matt Woodrow Date: Fri, 18 Nov 2011 22:07:49 +1300 Subject: [PATCH 06/63] Bug 703516 - Move GLContext code into a separate folder. r=jrmuizel --HG-- rename : gfx/thebes/EGLUtils.h => gfx/gl/EGLUtils.h rename : gfx/thebes/GLContext.cpp => gfx/gl/GLContext.cpp rename : gfx/thebes/GLContext.h => gfx/gl/GLContext.h rename : gfx/thebes/GLContextProvider.h => gfx/gl/GLContextProvider.h rename : gfx/thebes/GLContextProviderCGL.mm => gfx/gl/GLContextProviderCGL.mm rename : gfx/thebes/GLContextProviderEGL.cpp => gfx/gl/GLContextProviderEGL.cpp rename : gfx/thebes/GLContextProviderGLX.cpp => gfx/gl/GLContextProviderGLX.cpp rename : gfx/thebes/GLContextProviderImpl.h => gfx/gl/GLContextProviderImpl.h rename : gfx/thebes/GLContextProviderNull.cpp => gfx/gl/GLContextProviderNull.cpp rename : gfx/thebes/GLContextProviderOSMesa.cpp => gfx/gl/GLContextProviderOSMesa.cpp rename : gfx/thebes/GLContextProviderWGL.cpp => gfx/gl/GLContextProviderWGL.cpp rename : gfx/thebes/GLContextSymbols.h => gfx/gl/GLContextSymbols.h rename : gfx/thebes/GLDefs.h => gfx/gl/GLDefs.h rename : gfx/thebes/GLXLibrary.h => gfx/gl/GLXLibrary.h rename : gfx/thebes/WGLLibrary.h => gfx/gl/WGLLibrary.h --- gfx/Makefile.in | 2 +- gfx/{thebes => gl}/EGLUtils.h | 0 gfx/{thebes => gl}/GLContext.cpp | 0 gfx/{thebes => gl}/GLContext.h | 0 gfx/{thebes => gl}/GLContextProvider.h | 0 gfx/{thebes => gl}/GLContextProviderCGL.mm | 0 gfx/{thebes => gl}/GLContextProviderEGL.cpp | 0 gfx/{thebes => gl}/GLContextProviderGLX.cpp | 0 gfx/{thebes => gl}/GLContextProviderImpl.h | 0 gfx/{thebes => gl}/GLContextProviderNull.cpp | 0 .../GLContextProviderOSMesa.cpp | 0 gfx/{thebes => gl}/GLContextProviderWGL.cpp | 0 gfx/{thebes => gl}/GLContextSymbols.h | 0 gfx/{thebes => gl}/GLDefs.h | 0 gfx/{thebes => gl}/GLXLibrary.h | 0 gfx/gl/Makefile.in | 96 +++++++++++++++++++ gfx/{thebes => gl}/WGLLibrary.h | 0 gfx/thebes/Makefile.in | 61 ------------ toolkit/library/libxul-config.mk | 2 +- 19 files changed, 98 insertions(+), 63 deletions(-) rename gfx/{thebes => gl}/EGLUtils.h (100%) rename gfx/{thebes => gl}/GLContext.cpp (100%) rename gfx/{thebes => gl}/GLContext.h (100%) rename gfx/{thebes => gl}/GLContextProvider.h (100%) rename gfx/{thebes => gl}/GLContextProviderCGL.mm (100%) rename gfx/{thebes => gl}/GLContextProviderEGL.cpp (100%) rename gfx/{thebes => gl}/GLContextProviderGLX.cpp (100%) rename gfx/{thebes => gl}/GLContextProviderImpl.h (100%) rename gfx/{thebes => gl}/GLContextProviderNull.cpp (100%) rename gfx/{thebes => gl}/GLContextProviderOSMesa.cpp (100%) rename gfx/{thebes => gl}/GLContextProviderWGL.cpp (100%) rename gfx/{thebes => gl}/GLContextSymbols.h (100%) rename gfx/{thebes => gl}/GLDefs.h (100%) rename gfx/{thebes => gl}/GLXLibrary.h (100%) create mode 100644 gfx/gl/Makefile.in rename gfx/{thebes => gl}/WGLLibrary.h (100%) diff --git a/gfx/Makefile.in b/gfx/Makefile.in index 9a8512957e69..ffb9747c1391 100644 --- a/gfx/Makefile.in +++ b/gfx/Makefile.in @@ -48,7 +48,7 @@ ifdef MOZ_TREE_CAIRO DIRS = cairo endif -DIRS += 2d ycbcr angle src qcms layers harfbuzz/src ots/src thebes ipc +DIRS += 2d ycbcr angle src qcms gl layers harfbuzz/src ots/src thebes ipc ifeq (,$(filter-out cocoa android windows,$(MOZ_WIDGET_TOOLKIT))) DIRS += skia diff --git a/gfx/thebes/EGLUtils.h b/gfx/gl/EGLUtils.h similarity index 100% rename from gfx/thebes/EGLUtils.h rename to gfx/gl/EGLUtils.h diff --git a/gfx/thebes/GLContext.cpp b/gfx/gl/GLContext.cpp similarity index 100% rename from gfx/thebes/GLContext.cpp rename to gfx/gl/GLContext.cpp diff --git a/gfx/thebes/GLContext.h b/gfx/gl/GLContext.h similarity index 100% rename from gfx/thebes/GLContext.h rename to gfx/gl/GLContext.h diff --git a/gfx/thebes/GLContextProvider.h b/gfx/gl/GLContextProvider.h similarity index 100% rename from gfx/thebes/GLContextProvider.h rename to gfx/gl/GLContextProvider.h diff --git a/gfx/thebes/GLContextProviderCGL.mm b/gfx/gl/GLContextProviderCGL.mm similarity index 100% rename from gfx/thebes/GLContextProviderCGL.mm rename to gfx/gl/GLContextProviderCGL.mm diff --git a/gfx/thebes/GLContextProviderEGL.cpp b/gfx/gl/GLContextProviderEGL.cpp similarity index 100% rename from gfx/thebes/GLContextProviderEGL.cpp rename to gfx/gl/GLContextProviderEGL.cpp diff --git a/gfx/thebes/GLContextProviderGLX.cpp b/gfx/gl/GLContextProviderGLX.cpp similarity index 100% rename from gfx/thebes/GLContextProviderGLX.cpp rename to gfx/gl/GLContextProviderGLX.cpp diff --git a/gfx/thebes/GLContextProviderImpl.h b/gfx/gl/GLContextProviderImpl.h similarity index 100% rename from gfx/thebes/GLContextProviderImpl.h rename to gfx/gl/GLContextProviderImpl.h diff --git a/gfx/thebes/GLContextProviderNull.cpp b/gfx/gl/GLContextProviderNull.cpp similarity index 100% rename from gfx/thebes/GLContextProviderNull.cpp rename to gfx/gl/GLContextProviderNull.cpp diff --git a/gfx/thebes/GLContextProviderOSMesa.cpp b/gfx/gl/GLContextProviderOSMesa.cpp similarity index 100% rename from gfx/thebes/GLContextProviderOSMesa.cpp rename to gfx/gl/GLContextProviderOSMesa.cpp diff --git a/gfx/thebes/GLContextProviderWGL.cpp b/gfx/gl/GLContextProviderWGL.cpp similarity index 100% rename from gfx/thebes/GLContextProviderWGL.cpp rename to gfx/gl/GLContextProviderWGL.cpp diff --git a/gfx/thebes/GLContextSymbols.h b/gfx/gl/GLContextSymbols.h similarity index 100% rename from gfx/thebes/GLContextSymbols.h rename to gfx/gl/GLContextSymbols.h diff --git a/gfx/thebes/GLDefs.h b/gfx/gl/GLDefs.h similarity index 100% rename from gfx/thebes/GLDefs.h rename to gfx/gl/GLDefs.h diff --git a/gfx/thebes/GLXLibrary.h b/gfx/gl/GLXLibrary.h similarity index 100% rename from gfx/thebes/GLXLibrary.h rename to gfx/gl/GLXLibrary.h diff --git a/gfx/gl/Makefile.in b/gfx/gl/Makefile.in new file mode 100644 index 000000000000..a26a7038c2eb --- /dev/null +++ b/gfx/gl/Makefile.in @@ -0,0 +1,96 @@ + +DEPTH = ../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = gl +LIBRARY_NAME = gl +LIBXUL_LIBRARY = 1 +EXPORT_LIBRARY = 1 + +EXPORTS = \ + GLDefs.h \ + GLContext.h \ + GLContextSymbols.h \ + GLContextProvider.h \ + GLContextProviderImpl.h \ + EGLUtils.h \ + $(NULL) + +ifdef MOZ_X11 +EXPORTS += \ + GLXLibrary.h \ + $(NULL) +endif + + +ifeq ($(MOZ_WIDGET_TOOLKIT),windows) +EXPORTS += \ + WGLLibrary.h \ + $(NULL) +endif + +CPPSRCS = \ + GLContext.cpp \ + GLContextProviderOSMesa.cpp \ + $(NULL) + +GL_PROVIDER = Null + +ifeq ($(MOZ_WIDGET_TOOLKIT),windows) +GL_PROVIDER = WGL +endif + +ifeq ($(MOZ_WIDGET_TOOLKIT),cocoa) +GL_PROVIDER = CGL +endif + +ifeq ($(MOZ_WIDGET_TOOLKIT),gtk2) +ifdef MOZ_PLATFORM_MAEMO +GL_PROVIDER = EGL +else +ifdef MOZ_EGL_XRENDER_COMPOSITE +GL_PROVIDER = EGL +else +GL_PROVIDER = GLX +endif +endif +endif + +ifeq ($(MOZ_WIDGET_TOOLKIT),qt) +ifdef MOZ_PLATFORM_MAEMO +GL_PROVIDER = EGL +else +GL_PROVIDER = GLX +endif +endif + +ifeq ($(MOZ_WIDGET_TOOLKIT),android) +GL_PROVIDER = EGL +endif + +ifeq ($(MOZ_WIDGET_TOOLKIT),gonk) +GL_PROVIDER = EGL +endif + +# Mac is a special snowflake +ifeq ($(GL_PROVIDER),CGL) +CMMSRCS += GLContextProvider$(GL_PROVIDER).mm +else +CPPSRCS += GLContextProvider$(GL_PROVIDER).cpp +endif + +# Win32 is a special snowflake, for ANGLE +ifeq ($(MOZ_WIDGET_TOOLKIT),windows) +CPPSRCS += GLContextProviderEGL.cpp +endif + +include $(topsrcdir)/config/rules.mk + +DEFINES := $(filter-out -DUNICODE,$(DEFINES)) + +CXXFLAGS += $(MOZ_CAIRO_CFLAGS) $(TK_CFLAGS) +CFLAGS += $(MOZ_CAIRO_CFLAGS) $(TK_CFLAGS) diff --git a/gfx/thebes/WGLLibrary.h b/gfx/gl/WGLLibrary.h similarity index 100% rename from gfx/thebes/WGLLibrary.h rename to gfx/gl/WGLLibrary.h diff --git a/gfx/thebes/Makefile.in b/gfx/thebes/Makefile.in index 3c1a157be699..ec6005a0ebc4 100644 --- a/gfx/thebes/Makefile.in +++ b/gfx/thebes/Makefile.in @@ -46,13 +46,7 @@ EXPORTS = \ gfxUnicodeProperties.h \ gfxUtils.h \ gfxUserFontSet.h \ - GLDefs.h \ - GLContext.h \ - GLContextSymbols.h \ - GLContextProvider.h \ - GLContextProviderImpl.h \ nsCoreAnimationSupport.h \ - EGLUtils.h \ gfxSharedImageSurface.h \ $(NULL) @@ -95,7 +89,6 @@ ifdef MOZ_X11 EXPORTS += \ gfxXlibSurface.h \ gfxXlibNativeRenderer.h \ - GLXLibrary.h \ $(NULL) endif @@ -131,7 +124,6 @@ EXPORTS += \ ifdef MOZ_X11 EXPORTS += \ gfxXlibSurface.h \ - GLXLibrary.h \ $(NULL) endif @@ -148,7 +140,6 @@ EXPORTS += \ gfxWindowsPlatform.h \ gfxWindowsSurface.h \ gfxWindowsNativeDrawing.h \ - WGLLibrary.h \ gfxDWriteFonts.h \ gfxD2DSurface.h \ gfxGDIFont.h \ @@ -188,8 +179,6 @@ CPPSRCS = \ gfxUnicodeProperties.cpp \ gfxScriptItemizer.cpp \ gfxHarfBuzzShaper.cpp \ - GLContext.cpp \ - GLContextProviderOSMesa.cpp \ gfxSharedImageSurface.cpp \ $(NULL) @@ -348,56 +337,6 @@ endif CSRCS += woff.c -GL_PROVIDER = Null - -ifeq ($(MOZ_WIDGET_TOOLKIT),windows) -GL_PROVIDER = WGL -endif - -ifeq ($(MOZ_WIDGET_TOOLKIT),cocoa) -GL_PROVIDER = CGL -endif - -ifeq ($(MOZ_WIDGET_TOOLKIT),gtk2) -ifdef MOZ_PLATFORM_MAEMO -GL_PROVIDER = EGL -else -ifdef MOZ_EGL_XRENDER_COMPOSITE -GL_PROVIDER = EGL -else -GL_PROVIDER = GLX -endif -endif -endif - -ifeq ($(MOZ_WIDGET_TOOLKIT),qt) -ifdef MOZ_PLATFORM_MAEMO -GL_PROVIDER = EGL -else -GL_PROVIDER = GLX -endif -endif - -ifeq ($(MOZ_WIDGET_TOOLKIT),android) -GL_PROVIDER = EGL -endif - -ifeq ($(MOZ_WIDGET_TOOLKIT),gonk) -GL_PROVIDER = EGL -endif - -# Mac is a special snowflake -ifeq ($(GL_PROVIDER),CGL) -CMMSRCS += GLContextProvider$(GL_PROVIDER).mm -else -CPPSRCS += GLContextProvider$(GL_PROVIDER).cpp -endif - -# Win32 is a special snowflake, for ANGLE -ifeq ($(MOZ_WIDGET_TOOLKIT),windows) -CPPSRCS += GLContextProviderEGL.cpp -endif - DEFINES += -DIMPL_THEBES -DWOFF_MOZILLA_CLIENT include $(topsrcdir)/config/rules.mk diff --git a/toolkit/library/libxul-config.mk b/toolkit/library/libxul-config.mk index 1c65a308c361..8bf8925a99f5 100644 --- a/toolkit/library/libxul-config.mk +++ b/toolkit/library/libxul-config.mk @@ -265,7 +265,7 @@ ifeq ($(MOZ_WIDGET_TOOLKIT),gonk) COMPONENT_LIBS += widget_gonk endif -STATIC_LIBS += thebes ycbcr +STATIC_LIBS += thebes gl ycbcr ifeq ($(MOZ_WIDGET_TOOLKIT),android) STATIC_LIBS += profiler From 9099fa5d4d00008f4b3f8ed870f30c6c33972558 Mon Sep 17 00:00:00 2001 From: Joe Drew Date: Fri, 18 Nov 2011 22:19:24 +1300 Subject: [PATCH 07/63] Bug 685767 - Factor blurring out into its own class, and use it from gfxAlphaBoxBlur. r=mattwoodrow --- gfx/2d/Blur.cpp | 527 +++++++++++++++++++++++++++++++++++++++++ gfx/2d/Blur.h | 185 +++++++++++++++ gfx/2d/Makefile.in | 2 + gfx/thebes/gfxBlur.cpp | 436 +++------------------------------- gfx/thebes/gfxBlur.h | 32 +-- 5 files changed, 757 insertions(+), 425 deletions(-) create mode 100644 gfx/2d/Blur.cpp create mode 100644 gfx/2d/Blur.h diff --git a/gfx/2d/Blur.cpp b/gfx/2d/Blur.cpp new file mode 100644 index 000000000000..0aa8022b2254 --- /dev/null +++ b/gfx/2d/Blur.cpp @@ -0,0 +1,527 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla gfx. + * + * The Initial Developer of the Original Code is Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "mozilla/gfx/Blur.h" + +#include +#include +#include + +#include "CheckedInt.h" +#include "mozilla/Util.h" + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +using namespace std; + +namespace mozilla { +namespace gfx { + +/** + * Box blur involves looking at one pixel, and setting its value to the average + * of its neighbouring pixels. + * @param aInput The input buffer. + * @param aOutput The output buffer. + * @param aLeftLobe The number of pixels to blend on the left. + * @param aRightLobe The number of pixels to blend on the right. + * @param aWidth The number of columns in the buffers. + * @param aRows The number of rows in the buffers. + * @param aSkipRect An area to skip blurring in. + * XXX shouldn't we pass stride in separately here? + */ +static void +BoxBlurHorizontal(unsigned char* aInput, + unsigned char* aOutput, + int32_t aLeftLobe, + int32_t aRightLobe, + int32_t aWidth, + int32_t aRows, + const IntRect& aSkipRect) +{ + MOZ_ASSERT(aWidth > 0); + + int32_t boxSize = aLeftLobe + aRightLobe + 1; + bool skipRectCoversWholeRow = 0 >= aSkipRect.x && + aWidth <= aSkipRect.XMost(); + + for (int32_t y = 0; y < aRows; y++) { + // Check whether the skip rect intersects this row. If the skip + // rect covers the whole surface in this row, we can avoid + // this row entirely (and any others along the skip rect). + bool inSkipRectY = y >= aSkipRect.y && + y < aSkipRect.YMost(); + if (inSkipRectY && skipRectCoversWholeRow) { + y = aSkipRect.YMost() - 1; + continue; + } + + int32_t alphaSum = 0; + for (int32_t i = 0; i < boxSize; i++) { + int32_t pos = i - aLeftLobe; + // See assertion above; if aWidth is zero, then we would have no + // valid position to clamp to. + pos = max(pos, 0); + pos = min(pos, aWidth - 1); + alphaSum += aInput[aWidth * y + pos]; + } + for (int32_t x = 0; x < aWidth; x++) { + // Check whether we are within the skip rect. If so, go + // to the next point outside the skip rect. + if (inSkipRectY && x >= aSkipRect.x && + x < aSkipRect.XMost()) { + x = aSkipRect.XMost(); + if (x >= aWidth) + break; + + // Recalculate the neighbouring alpha values for + // our new point on the surface. + alphaSum = 0; + for (int32_t i = 0; i < boxSize; i++) { + int32_t pos = x + i - aLeftLobe; + // See assertion above; if aWidth is zero, then we would have no + // valid position to clamp to. + pos = max(pos, 0); + pos = min(pos, aWidth - 1); + alphaSum += aInput[aWidth * y + pos]; + } + } + int32_t tmp = x - aLeftLobe; + int32_t last = max(tmp, 0); + int32_t next = min(tmp + boxSize, aWidth - 1); + + aOutput[aWidth * y + x] = alphaSum / boxSize; + + alphaSum += aInput[aWidth * y + next] - + aInput[aWidth * y + last]; + } + } +} + +/** + * Identical to BoxBlurHorizontal, except it blurs top and bottom instead of + * left and right. + * XXX shouldn't we pass stride in separately here? + */ +static void +BoxBlurVertical(unsigned char* aInput, + unsigned char* aOutput, + int32_t aTopLobe, + int32_t aBottomLobe, + int32_t aWidth, + int32_t aRows, + const IntRect& aSkipRect) +{ + MOZ_ASSERT(aRows > 0); + + int32_t boxSize = aTopLobe + aBottomLobe + 1; + bool skipRectCoversWholeColumn = 0 >= aSkipRect.y && + aRows <= aSkipRect.YMost(); + + for (int32_t x = 0; x < aWidth; x++) { + bool inSkipRectX = x >= aSkipRect.x && + x < aSkipRect.XMost(); + if (inSkipRectX && skipRectCoversWholeColumn) { + x = aSkipRect.XMost() - 1; + continue; + } + + int32_t alphaSum = 0; + for (int32_t i = 0; i < boxSize; i++) { + int32_t pos = i - aTopLobe; + // See assertion above; if aRows is zero, then we would have no + // valid position to clamp to. + pos = max(pos, 0); + pos = min(pos, aRows - 1); + alphaSum += aInput[aWidth * pos + x]; + } + for (int32_t y = 0; y < aRows; y++) { + if (inSkipRectX && y >= aSkipRect.y && + y < aSkipRect.YMost()) { + y = aSkipRect.YMost(); + if (y >= aRows) + break; + + alphaSum = 0; + for (int32_t i = 0; i < boxSize; i++) { + int32_t pos = y + i - aTopLobe; + // See assertion above; if aRows is zero, then we would have no + // valid position to clamp to. + pos = max(pos, 0); + pos = min(pos, aRows - 1); + alphaSum += aInput[aWidth * pos + x]; + } + } + int32_t tmp = y - aTopLobe; + int32_t last = max(tmp, 0); + int32_t next = min(tmp + boxSize, aRows - 1); + + aOutput[aWidth * y + x] = alphaSum/boxSize; + + alphaSum += aInput[aWidth * next + x] - + aInput[aWidth * last + x]; + } + } +} + +static void ComputeLobes(int32_t aRadius, int32_t aLobes[3][2]) +{ + int32_t major, minor, final; + + /* See http://www.w3.org/TR/SVG/filters.html#feGaussianBlur for + * some notes about approximating the Gaussian blur with box-blurs. + * The comments below are in the terminology of that page. + */ + int32_t z = aRadius / 3; + switch (aRadius % 3) { + case 0: + // aRadius = z*3; choose d = 2*z + 1 + major = minor = final = z; + break; + case 1: + // aRadius = z*3 + 1 + // This is a tricky case since there is no value of d which will + // yield a radius of exactly aRadius. If d is odd, i.e. d=2*k + 1 + // for some integer k, then the radius will be 3*k. If d is even, + // i.e. d=2*k, then the radius will be 3*k - 1. + // So we have to choose values that don't match the standard + // algorithm. + major = z + 1; + minor = final = z; + break; + case 2: + // aRadius = z*3 + 2; choose d = 2*z + 2 + major = final = z + 1; + minor = z; + break; + default: + // Mathematical impossibility! + MOZ_ASSERT(false); + major = minor = final = 0; + } + MOZ_ASSERT(major + minor + final == aRadius); + + aLobes[0][0] = major; + aLobes[0][1] = minor; + aLobes[1][0] = minor; + aLobes[1][1] = major; + aLobes[2][0] = final; + aLobes[2][1] = final; +} + +static void +SpreadHorizontal(unsigned char* aInput, + unsigned char* aOutput, + int32_t aRadius, + int32_t aWidth, + int32_t aRows, + int32_t aStride, + const IntRect& aSkipRect) +{ + if (aRadius == 0) { + memcpy(aOutput, aInput, aStride * aRows); + return; + } + + bool skipRectCoversWholeRow = 0 >= aSkipRect.x && + aWidth <= aSkipRect.XMost(); + for (int32_t y = 0; y < aRows; y++) { + // Check whether the skip rect intersects this row. If the skip + // rect covers the whole surface in this row, we can avoid + // this row entirely (and any others along the skip rect). + bool inSkipRectY = y >= aSkipRect.y && + y < aSkipRect.YMost(); + if (inSkipRectY && skipRectCoversWholeRow) { + y = aSkipRect.YMost() - 1; + continue; + } + + for (int32_t x = 0; x < aWidth; x++) { + // Check whether we are within the skip rect. If so, go + // to the next point outside the skip rect. + if (inSkipRectY && x >= aSkipRect.x && + x < aSkipRect.XMost()) { + x = aSkipRect.XMost(); + if (x >= aWidth) + break; + } + + int32_t sMin = max(x - aRadius, 0); + int32_t sMax = min(x + aRadius, aWidth - 1); + int32_t v = 0; + for (int32_t s = sMin; s <= sMax; ++s) { + v = max(v, aInput[aStride * y + s]); + } + aOutput[aStride * y + x] = v; + } + } +} + +static void +SpreadVertical(unsigned char* aInput, + unsigned char* aOutput, + int32_t aRadius, + int32_t aWidth, + int32_t aRows, + int32_t aStride, + const IntRect& aSkipRect) +{ + if (aRadius == 0) { + memcpy(aOutput, aInput, aStride * aRows); + return; + } + + bool skipRectCoversWholeColumn = 0 >= aSkipRect.y && + aRows <= aSkipRect.YMost(); + for (int32_t x = 0; x < aWidth; x++) { + bool inSkipRectX = x >= aSkipRect.x && + x < aSkipRect.XMost(); + if (inSkipRectX && skipRectCoversWholeColumn) { + x = aSkipRect.XMost() - 1; + continue; + } + + for (int32_t y = 0; y < aRows; y++) { + // Check whether we are within the skip rect. If so, go + // to the next point outside the skip rect. + if (inSkipRectX && y >= aSkipRect.y && + y < aSkipRect.YMost()) { + y = aSkipRect.YMost(); + if (y >= aRows) + break; + } + + int32_t sMin = max(y - aRadius, 0); + int32_t sMax = min(y + aRadius, aRows - 1); + int32_t v = 0; + for (int32_t s = sMin; s <= sMax; ++s) { + v = max(v, aInput[aStride * s + x]); + } + aOutput[aStride * y + x] = v; + } + } +} + +static CheckedInt +RoundUpToMultipleOf4(int32_t aVal) +{ + CheckedInt val(aVal); + + val += 3; + val /= 4; + val *= 4; + + return val; +} + +AlphaBoxBlur::AlphaBoxBlur(const Rect& aRect, + const IntSize& aSpreadRadius, + const IntSize& aBlurRadius, + const Rect* aDirtyRect, + const Rect* aSkipRect) + : mSpreadRadius(aSpreadRadius), + mBlurRadius(aBlurRadius), + mData(NULL) +{ + Rect rect(aRect); + rect.Inflate(Size(aBlurRadius + aSpreadRadius)); + rect.RoundOut(); + + if (aDirtyRect) { + // If we get passed a dirty rect from layout, we can minimize the + // shadow size and make painting faster. + mHasDirtyRect = true; + mDirtyRect = *aDirtyRect; + Rect requiredBlurArea = mDirtyRect.Intersect(rect); + requiredBlurArea.Inflate(Size(aBlurRadius + aSpreadRadius)); + rect = requiredBlurArea.Intersect(rect); + } else { + mHasDirtyRect = false; + } + + if (rect.IsEmpty()) { + return; + } + + if (aSkipRect) { + // If we get passed a skip rect, we can lower the amount of + // blurring/spreading we need to do. We convert it to IntRect to avoid + // expensive int<->float conversions if we were to use Rect instead. + Rect skipRect = *aSkipRect; + skipRect.RoundIn(); + skipRect.Deflate(Size(aBlurRadius + aSpreadRadius)); + mSkipRect = IntRect(skipRect.x, skipRect.y, skipRect.width, skipRect.height); + + IntRect shadowIntRect(rect.x, rect.y, rect.width, rect.height); + mSkipRect.IntersectRect(mSkipRect, shadowIntRect); + + if (mSkipRect.IsEqualInterior(shadowIntRect)) + return; + + mSkipRect -= shadowIntRect.TopLeft(); + } else { + mSkipRect = IntRect(0, 0, 0, 0); + } + + mRect = IntRect(rect.x, rect.y, rect.width, rect.height); + + CheckedInt stride = RoundUpToMultipleOf4(mRect.width); + if (stride.valid()) { + mStride = stride.value(); + + CheckedInt size = CheckedInt(mStride) * mRect.height * + sizeof(unsigned char); + if (size.valid()) { + mData = static_cast(malloc(size.value())); + memset(mData, 0, size.value()); + } + } +} + +AlphaBoxBlur::~AlphaBoxBlur() +{ + free(mData); +} + +unsigned char* +AlphaBoxBlur::GetData() +{ + return mData; +} + +IntSize +AlphaBoxBlur::GetSize() +{ + IntSize size(mRect.width, mRect.height); + return size; +} + +int32_t +AlphaBoxBlur::GetStride() +{ + return mStride; +} + +IntRect +AlphaBoxBlur::GetRect() +{ + return mRect; +} + +Rect* +AlphaBoxBlur::GetDirtyRect() +{ + if (mHasDirtyRect) { + return &mDirtyRect; + } + + return NULL; +} + +void +AlphaBoxBlur::Blur() +{ + if (!mData) { + return; + } + + // no need to do all this if not blurring or spreading + if (mBlurRadius != IntSize(0,0) || mSpreadRadius != IntSize(0,0)) { + int32_t stride = GetStride(); + + // No need to use CheckedInt here - we have validated it in the constructor. + size_t szB = stride * GetSize().height * sizeof(unsigned char); + unsigned char* tmpData = static_cast(malloc(szB)); + if (!tmpData) + return; // OOM + + memset(tmpData, 0, szB); + + if (mSpreadRadius.width > 0 || mSpreadRadius.height > 0) { + SpreadHorizontal(mData, tmpData, mSpreadRadius.width, GetSize().width, GetSize().height, stride, mSkipRect); + SpreadVertical(tmpData, mData, mSpreadRadius.height, GetSize().width, GetSize().height, stride, mSkipRect); + } + + if (mBlurRadius.width > 0) { + int32_t lobes[3][2]; + ComputeLobes(mBlurRadius.width, lobes); + BoxBlurHorizontal(mData, tmpData, lobes[0][0], lobes[0][1], stride, GetSize().height, mSkipRect); + BoxBlurHorizontal(tmpData, mData, lobes[1][0], lobes[1][1], stride, GetSize().height, mSkipRect); + BoxBlurHorizontal(mData, tmpData, lobes[2][0], lobes[2][1], stride, GetSize().height, mSkipRect); + } else { + memcpy(tmpData, mData, stride * GetSize().height); + } + + if (mBlurRadius.height > 0) { + int32_t lobes[3][2]; + ComputeLobes(mBlurRadius.height, lobes); + BoxBlurVertical(tmpData, mData, lobes[0][0], lobes[0][1], stride, GetSize().height, mSkipRect); + BoxBlurVertical(mData, tmpData, lobes[1][0], lobes[1][1], stride, GetSize().height, mSkipRect); + BoxBlurVertical(tmpData, mData, lobes[2][0], lobes[2][1], stride, GetSize().height, mSkipRect); + } else { + memcpy(mData, tmpData, stride * GetSize().height); + } + + free(tmpData); + } + +} + +/** + * Compute the box blur size (which we're calling the blur radius) from + * the standard deviation. + * + * Much of this, the 3 * sqrt(2 * pi) / 4, is the known value for + * approximating a Gaussian using box blurs. This yields quite a good + * approximation for a Gaussian. Then we multiply this by 1.5 since our + * code wants the radius of the entire triple-box-blur kernel instead of + * the diameter of an individual box blur. For more details, see: + * http://www.w3.org/TR/SVG11/filters.html#feGaussianBlurElement + * https://bugzilla.mozilla.org/show_bug.cgi?id=590039#c19 + */ +static const Float GAUSSIAN_SCALE_FACTOR = (3 * sqrt(2 * M_PI) / 4) * 1.5; + +IntSize +AlphaBoxBlur::CalculateBlurRadius(const Point& aStd) +{ + IntSize size(static_cast(floor(aStd.x * GAUSSIAN_SCALE_FACTOR + 0.5)), + static_cast(floor(aStd.y * GAUSSIAN_SCALE_FACTOR + 0.5))); + + return size; +} + +} +} diff --git a/gfx/2d/Blur.h b/gfx/2d/Blur.h new file mode 100644 index 000000000000..27a85f1708a1 --- /dev/null +++ b/gfx/2d/Blur.h @@ -0,0 +1,185 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla gfx. + * + * The Initial Developer of the Original Code is Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef MOZILLA_GFX_BLUR_H_ +#define MOZILLA_GFX_BLUR_H_ + +#include "mozilla/gfx/Rect.h" +#include "mozilla/gfx/Point.h" + +namespace mozilla { +namespace gfx { + +/** + * Implementation of a triple box blur approximation of a Gaussian blur. + * + * A Gaussian blur is good for blurring because, when done independently + * in the horizontal and vertical directions, it matches the result that + * would be obtained using a different (rotated) set of axes. A triple + * box blur is a very close approximation of a Gaussian. + * + * Creates an 8-bit alpha channel context for callers to draw in, + * spreads the contents of that context, and blurs the contents. + * + * A spread N makes each output pixel the maximum value of all source + * pixels within a square of side length 2N+1 centered on the output pixel. + * + * A temporary surface is created in the Init function. The caller then draws + * any desired content onto the context acquired through GetContext, and lastly + * calls Paint to apply the blurred content as an alpha mask. + */ +class AlphaBoxBlur +{ +public: + + /** Constructs a box blur and initializes the backing surface. + * + * @param aRect The coordinates of the surface to create in device units. + * + * @param aBlurRadius The blur radius in pixels. This is the radius of the + * entire (triple) kernel function. Each individual box blur has radius + * approximately 1/3 this value, or diameter approximately 2/3 this value. + * This parameter should nearly always be computed using CalculateBlurRadius, + * below. + * + * @param aDirtyRect A pointer to a dirty rect, measured in device units, if + * available. This will be used for optimizing the blur operation. It is + * safe to pass NULL here. + * + * @param aSkipRect A pointer to a rect, measured in device units, that + * represents an area where blurring is unnecessary and shouldn't be done for + * speed reasons. It is safe to pass NULL here. + */ + AlphaBoxBlur(const Rect& aRect, + const IntSize& aSpreadRadius, + const IntSize& aBlurRadius, + const Rect* aDirtyRect, + const Rect* aSkipRect); + + ~AlphaBoxBlur(); + + /** + * Return the pointer to memory allocated by the constructor for the 8-bit + * alpha surface you need to be blurred. After you draw to this surface, call + * Blur(), below, to have its contents blurred. + */ + unsigned char* GetData(); + + /** + * Return the size, in pixels, of the 8-bit alpha surface backed by the + * pointer returned by GetData(). + */ + IntSize GetSize(); + + /** + * Return the stride, in bytes, of the 8-bit alpha surface backed by the + * pointer returned by GetData(). + */ + int32_t GetStride(); + + /** + * Returns the device-space rectangle the 8-bit alpha surface covers. + */ + IntRect GetRect(); + + /** + * Return a pointer to a dirty rect, as passed in to the constructor, or NULL + * if none was passed in. + */ + Rect* GetDirtyRect(); + + /** + * Perform the blur in-place on the surface backed by the pointer returned by + * GetData(). + */ + void Blur(); + + /** + * Calculates a blur radius that, when used with box blur, approximates a + * Gaussian blur with the given standard deviation. The result of this + * function should be used as the aBlurRadius parameter to AlphaBoxBlur's + * constructor, above. + */ + static IntSize CalculateBlurRadius(const Point& aStandardDeviation); + +private: + + /** + * A rect indicating the area where blurring is unnecessary, and the blur + * algorithm should skip over it. + */ + IntRect mSkipRect; + + /** + * The device-space rectangle the the backing 8-bit alpha surface covers. + */ + IntRect mRect; + + /** + * A copy of the dirty rect passed to the constructor. This will only be valid if + * mHasDirtyRect is true. + */ + Rect mDirtyRect; + + /** + * The spread radius, in pixels. + */ + IntSize mSpreadRadius; + + /** + * The blur radius, in pixels. + */ + IntSize mBlurRadius; + + /** + * A pointer to the backing 8-bit alpha surface. + */ + unsigned char* mData; + + /** + * The stride of the data contained in mData. + */ + int32_t mStride; + + /** + * Whether mDirtyRect contains valid data. + */ + bool mHasDirtyRect; +}; + +} +} + +#endif /* MOZILLA_GFX_BLUR_H_ */ diff --git a/gfx/2d/Makefile.in b/gfx/2d/Makefile.in index 4cc2207b3f5c..bcb74559a7ad 100644 --- a/gfx/2d/Makefile.in +++ b/gfx/2d/Makefile.in @@ -56,6 +56,7 @@ EXPORTS_mozilla/gfx = \ BaseMargin.h \ BaseRect.h \ BaseSize.h \ + Blur.h \ PathHelpers.h \ Point.h \ Matrix.h \ @@ -68,6 +69,7 @@ CPPSRCS = \ Matrix.cpp \ DrawTargetCairo.cpp \ SourceSurfaceCairo.cpp \ + Blur.cpp \ $(NULL) diff --git a/gfx/thebes/gfxBlur.cpp b/gfx/thebes/gfxBlur.cpp index 26e18fb108ec..963c294f4abe 100644 --- a/gfx/thebes/gfxBlur.cpp +++ b/gfx/thebes/gfxBlur.cpp @@ -37,19 +37,18 @@ #include "gfxBlur.h" -#include "nsMathUtils.h" -#include "nsTArray.h" +#include "mozilla/gfx/Blur.h" -#ifndef M_PI -#define M_PI 3.14159265358979323846 -#endif +using namespace mozilla::gfx; gfxAlphaBoxBlur::gfxAlphaBoxBlur() + : mBlur(nsnull) { } gfxAlphaBoxBlur::~gfxAlphaBoxBlur() { + delete mBlur; } gfxContext* @@ -59,418 +58,63 @@ gfxAlphaBoxBlur::Init(const gfxRect& aRect, const gfxRect* aDirtyRect, const gfxRect* aSkipRect) { - mSpreadRadius = aSpreadRadius; - mBlurRadius = aBlurRadius; - - gfxRect rect(aRect); - rect.Inflate(aBlurRadius + aSpreadRadius); - rect.RoundOut(); - + Rect rect(aRect.x, aRect.y, aRect.width, aRect.height); + IntSize spreadRadius(aSpreadRadius.width, aSpreadRadius.height); + IntSize blurRadius(aBlurRadius.width, aBlurRadius.height); + nsAutoPtr dirtyRect; if (aDirtyRect) { - // If we get passed a dirty rect from layout, we can minimize the - // shadow size and make painting faster. - mHasDirtyRect = true; - mDirtyRect = *aDirtyRect; - gfxRect requiredBlurArea = mDirtyRect.Intersect(rect); - requiredBlurArea.Inflate(aBlurRadius + aSpreadRadius); - rect = requiredBlurArea.Intersect(rect); - } else { - mHasDirtyRect = false; + dirtyRect = new Rect(aDirtyRect->x, aDirtyRect->y, aDirtyRect->width, aDirtyRect->height); } - - // Check rect empty after accounting for aDirtyRect, since that may have - // make the rectangle empty. BoxBlurVertical and BoxBlurHorizontal require - // that we have a nonzero number of rows and columns. - if (rect.IsEmpty()) - return nsnull; - + nsAutoPtr skipRect; if (aSkipRect) { - // If we get passed a skip rect, we can lower the amount of - // blurring/spreading we need to do. We convert it to nsIntRect to avoid - // expensive int<->float conversions if we were to use gfxRect instead. - gfxRect skipRect = *aSkipRect; - skipRect.RoundIn(); - skipRect.Deflate(aBlurRadius + aSpreadRadius); - gfxUtils::GfxRectToIntRect(skipRect, &mSkipRect); - nsIntRect shadowIntRect; - gfxUtils::GfxRectToIntRect(rect, &shadowIntRect); - mSkipRect.IntersectRect(mSkipRect, shadowIntRect); - if (mSkipRect.IsEqualInterior(shadowIntRect)) - return nsnull; - - mSkipRect -= shadowIntRect.TopLeft(); - } else { - mSkipRect = nsIntRect(0, 0, 0, 0); + skipRect = new Rect(aSkipRect->x, aSkipRect->y, aSkipRect->width, aSkipRect->height); } + mBlur = new AlphaBoxBlur(rect, spreadRadius, blurRadius, dirtyRect, skipRect); + + unsigned char* data = mBlur->GetData(); + if (!data) + return nsnull; + + IntSize size = mBlur->GetSize(); // Make an alpha-only surface to draw on. We will play with the data after // everything is drawn to create a blur effect. - mImageSurface = new gfxImageSurface(gfxIntSize(static_cast(rect.Width()), static_cast(rect.Height())), + mImageSurface = new gfxImageSurface(data, gfxIntSize(size.width, size.height), + mBlur->GetStride(), gfxASurface::ImageFormatA8); - if (!mImageSurface || mImageSurface->CairoStatus()) + if (mImageSurface->CairoStatus()) return nsnull; + IntRect irect = mBlur->GetRect(); + gfxPoint topleft(irect.TopLeft().x, irect.TopLeft().y); + // Use a device offset so callers don't need to worry about translating // coordinates, they can draw as if this was part of the destination context // at the coordinates of rect. - mImageSurface->SetDeviceOffset(-rect.TopLeft()); + mImageSurface->SetDeviceOffset(-topleft); mContext = new gfxContext(mImageSurface); return mContext; } -/** - * Box blur involves looking at one pixel, and setting its value to the average - * of its neighbouring pixels. - * @param aInput The input buffer. - * @param aOutput The output buffer. - * @param aLeftLobe The number of pixels to blend on the left. - * @param aRightLobe The number of pixels to blend on the right. - * @param aWidth The number of columns in the buffers. - * @param aRows The number of rows in the buffers. - * @param aSkipRect An area to skip blurring in. - * XXX shouldn't we pass stride in separately here? - */ -static void -BoxBlurHorizontal(unsigned char* aInput, - unsigned char* aOutput, - PRInt32 aLeftLobe, - PRInt32 aRightLobe, - PRInt32 aWidth, - PRInt32 aRows, - const nsIntRect& aSkipRect) -{ - NS_ASSERTION(aWidth > 0, "Can't handle zero width here"); - - PRInt32 boxSize = aLeftLobe + aRightLobe + 1; - bool skipRectCoversWholeRow = 0 >= aSkipRect.x && - aWidth <= aSkipRect.XMost(); - if (boxSize == 1) { - memcpy(aOutput, aInput, aWidth*aRows); - return; - } - PRUint32 reciprocal = (PRUint64(1) << 32)/boxSize; - - for (PRInt32 y = 0; y < aRows; y++) { - // Check whether the skip rect intersects this row. If the skip - // rect covers the whole surface in this row, we can avoid - // this row entirely (and any others along the skip rect). - bool inSkipRectY = y >= aSkipRect.y && - y < aSkipRect.YMost(); - if (inSkipRectY && skipRectCoversWholeRow) { - y = aSkipRect.YMost() - 1; - continue; - } - - PRUint32 alphaSum = 0; - for (PRInt32 i = 0; i < boxSize; i++) { - PRInt32 pos = i - aLeftLobe; - // See assertion above; if aWidth is zero, then we would have no - // valid position to clamp to. - pos = NS_MAX(pos, 0); - pos = NS_MIN(pos, aWidth - 1); - alphaSum += aInput[aWidth * y + pos]; - } - for (PRInt32 x = 0; x < aWidth; x++) { - // Check whether we are within the skip rect. If so, go - // to the next point outside the skip rect. - if (inSkipRectY && x >= aSkipRect.x && - x < aSkipRect.XMost()) { - x = aSkipRect.XMost(); - if (x >= aWidth) - break; - - // Recalculate the neighbouring alpha values for - // our new point on the surface. - alphaSum = 0; - for (PRInt32 i = 0; i < boxSize; i++) { - PRInt32 pos = x + i - aLeftLobe; - // See assertion above; if aWidth is zero, then we would have no - // valid position to clamp to. - pos = NS_MAX(pos, 0); - pos = NS_MIN(pos, aWidth - 1); - alphaSum += aInput[aWidth * y + pos]; - } - } - PRInt32 tmp = x - aLeftLobe; - PRInt32 last = NS_MAX(tmp, 0); - PRInt32 next = NS_MIN(tmp + boxSize, aWidth - 1); - - aOutput[aWidth * y + x] = (PRUint64(alphaSum)*reciprocal) >> 32; - - alphaSum += aInput[aWidth * y + next] - - aInput[aWidth * y + last]; - } - } -} - -/** - * Identical to BoxBlurHorizontal, except it blurs top and bottom instead of - * left and right. - * XXX shouldn't we pass stride in separately here? - */ -static void -BoxBlurVertical(unsigned char* aInput, - unsigned char* aOutput, - PRInt32 aTopLobe, - PRInt32 aBottomLobe, - PRInt32 aWidth, - PRInt32 aRows, - const nsIntRect& aSkipRect) -{ - NS_ASSERTION(aRows > 0, "Can't handle zero rows here"); - - PRInt32 boxSize = aTopLobe + aBottomLobe + 1; - bool skipRectCoversWholeColumn = 0 >= aSkipRect.y && - aRows <= aSkipRect.YMost(); - if (boxSize == 1) { - memcpy(aOutput, aInput, aWidth*aRows); - return; - } - PRUint32 reciprocal = (PRUint64(1) << 32)/boxSize; - - for (PRInt32 x = 0; x < aWidth; x++) { - bool inSkipRectX = x >= aSkipRect.x && - x < aSkipRect.XMost(); - if (inSkipRectX && skipRectCoversWholeColumn) { - x = aSkipRect.XMost() - 1; - continue; - } - - PRUint32 alphaSum = 0; - for (PRInt32 i = 0; i < boxSize; i++) { - PRInt32 pos = i - aTopLobe; - // See assertion above; if aRows is zero, then we would have no - // valid position to clamp to. - pos = NS_MAX(pos, 0); - pos = NS_MIN(pos, aRows - 1); - alphaSum += aInput[aWidth * pos + x]; - } - for (PRInt32 y = 0; y < aRows; y++) { - if (inSkipRectX && y >= aSkipRect.y && - y < aSkipRect.YMost()) { - y = aSkipRect.YMost(); - if (y >= aRows) - break; - - alphaSum = 0; - for (PRInt32 i = 0; i < boxSize; i++) { - PRInt32 pos = y + i - aTopLobe; - // See assertion above; if aRows is zero, then we would have no - // valid position to clamp to. - pos = NS_MAX(pos, 0); - pos = NS_MIN(pos, aRows - 1); - alphaSum += aInput[aWidth * pos + x]; - } - } - PRInt32 tmp = y - aTopLobe; - PRInt32 last = NS_MAX(tmp, 0); - PRInt32 next = NS_MIN(tmp + boxSize, aRows - 1); - - aOutput[aWidth * y + x] = (PRUint64(alphaSum)*reciprocal) >> 32; - - alphaSum += aInput[aWidth * next + x] - - aInput[aWidth * last + x]; - } - } -} - -static void ComputeLobes(PRInt32 aRadius, PRInt32 aLobes[3][2]) -{ - PRInt32 major, minor, final; - - /* See http://www.w3.org/TR/SVG/filters.html#feGaussianBlur for - * some notes about approximating the Gaussian blur with box-blurs. - * The comments below are in the terminology of that page. - */ - PRInt32 z = aRadius/3; - switch (aRadius % 3) { - case 0: - // aRadius = z*3; choose d = 2*z + 1 - major = minor = final = z; - break; - case 1: - // aRadius = z*3 + 1 - // This is a tricky case since there is no value of d which will - // yield a radius of exactly aRadius. If d is odd, i.e. d=2*k + 1 - // for some integer k, then the radius will be 3*k. If d is even, - // i.e. d=2*k, then the radius will be 3*k - 1. - // So we have to choose values that don't match the standard - // algorithm. - major = z + 1; - minor = final = z; - break; - case 2: - // aRadius = z*3 + 2; choose d = 2*z + 2 - major = final = z + 1; - minor = z; - break; - default: - NS_ERROR("Mathematical impossibility."); - major = minor = final = 0; - } - NS_ASSERTION(major + minor + final == aRadius, - "Lobes don't sum to the right length"); - - aLobes[0][0] = major; - aLobes[0][1] = minor; - aLobes[1][0] = minor; - aLobes[1][1] = major; - aLobes[2][0] = final; - aLobes[2][1] = final; -} - -static void -SpreadHorizontal(unsigned char* aInput, - unsigned char* aOutput, - PRInt32 aRadius, - PRInt32 aWidth, - PRInt32 aRows, - PRInt32 aStride, - const nsIntRect& aSkipRect) -{ - if (aRadius == 0) { - memcpy(aOutput, aInput, aStride*aRows); - return; - } - - bool skipRectCoversWholeRow = 0 >= aSkipRect.x && - aWidth <= aSkipRect.XMost(); - for (PRInt32 y = 0; y < aRows; y++) { - // Check whether the skip rect intersects this row. If the skip - // rect covers the whole surface in this row, we can avoid - // this row entirely (and any others along the skip rect). - bool inSkipRectY = y >= aSkipRect.y && - y < aSkipRect.YMost(); - if (inSkipRectY && skipRectCoversWholeRow) { - y = aSkipRect.YMost() - 1; - continue; - } - - for (PRInt32 x = 0; x < aWidth; x++) { - // Check whether we are within the skip rect. If so, go - // to the next point outside the skip rect. - if (inSkipRectY && x >= aSkipRect.x && - x < aSkipRect.XMost()) { - x = aSkipRect.XMost(); - if (x >= aWidth) - break; - } - - PRInt32 sMin = NS_MAX(x - aRadius, 0); - PRInt32 sMax = NS_MIN(x + aRadius, aWidth - 1); - PRInt32 v = 0; - for (PRInt32 s = sMin; s <= sMax; ++s) { - v = NS_MAX(v, aInput[aStride * y + s]); - } - aOutput[aStride * y + x] = v; - } - } -} - -static void -SpreadVertical(unsigned char* aInput, - unsigned char* aOutput, - PRInt32 aRadius, - PRInt32 aWidth, - PRInt32 aRows, - PRInt32 aStride, - const nsIntRect& aSkipRect) -{ - if (aRadius == 0) { - memcpy(aOutput, aInput, aStride*aRows); - return; - } - - bool skipRectCoversWholeColumn = 0 >= aSkipRect.y && - aRows <= aSkipRect.YMost(); - for (PRInt32 x = 0; x < aWidth; x++) { - bool inSkipRectX = x >= aSkipRect.x && - x < aSkipRect.XMost(); - if (inSkipRectX && skipRectCoversWholeColumn) { - x = aSkipRect.XMost() - 1; - continue; - } - - for (PRInt32 y = 0; y < aRows; y++) { - // Check whether we are within the skip rect. If so, go - // to the next point outside the skip rect. - if (inSkipRectX && y >= aSkipRect.y && - y < aSkipRect.YMost()) { - y = aSkipRect.YMost(); - if (y >= aRows) - break; - } - - PRInt32 sMin = NS_MAX(y - aRadius, 0); - PRInt32 sMax = NS_MIN(y + aRadius, aRows - 1); - PRInt32 v = 0; - for (PRInt32 s = sMin; s <= sMax; ++s) { - v = NS_MAX(v, aInput[aStride * s + x]); - } - aOutput[aStride * y + x] = v; - } - } -} - void gfxAlphaBoxBlur::Paint(gfxContext* aDestinationCtx, const gfxPoint& offset) { if (!mContext) return; - unsigned char* boxData = mImageSurface->Data(); + mBlur->Blur(); - // no need to do all this if not blurring or spreading - if (mBlurRadius != gfxIntSize(0,0) || mSpreadRadius != gfxIntSize(0,0)) { - nsTArray tempAlphaDataBuf; - PRSize szB = mImageSurface->GetDataSize(); - if (!tempAlphaDataBuf.SetLength(szB)) - return; // OOM - - unsigned char* tmpData = tempAlphaDataBuf.Elements(); - // .SetLength above doesn't initialise the new elements since - // they are unsigned chars and so have no default constructor. - // So we have to initialise them by hand. - memset(tmpData, 0, szB); - - PRInt32 stride = mImageSurface->Stride(); - PRInt32 rows = mImageSurface->Height(); - PRInt32 width = mImageSurface->Width(); - - if (mSpreadRadius.width > 0 || mSpreadRadius.height > 0) { - SpreadHorizontal(boxData, tmpData, mSpreadRadius.width, width, rows, stride, mSkipRect); - SpreadVertical(tmpData, boxData, mSpreadRadius.height, width, rows, stride, mSkipRect); - } - - if (mBlurRadius.width > 0) { - PRInt32 lobes[3][2]; - ComputeLobes(mBlurRadius.width, lobes); - BoxBlurHorizontal(boxData, tmpData, lobes[0][0], lobes[0][1], stride, rows, mSkipRect); - BoxBlurHorizontal(tmpData, boxData, lobes[1][0], lobes[1][1], stride, rows, mSkipRect); - BoxBlurHorizontal(boxData, tmpData, lobes[2][0], lobes[2][1], stride, rows, mSkipRect); - } else { - memcpy(tmpData, boxData, stride*rows); - } - - if (mBlurRadius.height > 0) { - PRInt32 lobes[3][2]; - ComputeLobes(mBlurRadius.height, lobes); - BoxBlurVertical(tmpData, boxData, lobes[0][0], lobes[0][1], stride, rows, mSkipRect); - BoxBlurVertical(boxData, tmpData, lobes[1][0], lobes[1][1], stride, rows, mSkipRect); - BoxBlurVertical(tmpData, boxData, lobes[2][0], lobes[2][1], stride, rows, mSkipRect); - } else { - memcpy(boxData, tmpData, stride*rows); - } - } + Rect* dirtyrect = mBlur->GetDirtyRect(); // Avoid a semi-expensive clip operation if we can, otherwise // clip to the dirty rect - if (mHasDirtyRect) { + if (dirtyrect) { aDestinationCtx->Save(); aDestinationCtx->NewPath(); - aDestinationCtx->Rectangle(mDirtyRect); + gfxRect dirty(dirtyrect->x, dirtyrect->y, dirtyrect->width, dirtyrect->height); + aDestinationCtx->Rectangle(dirty); aDestinationCtx->Clip(); aDestinationCtx->Mask(mImageSurface, offset); aDestinationCtx->Restore(); @@ -479,23 +123,9 @@ gfxAlphaBoxBlur::Paint(gfxContext* aDestinationCtx, const gfxPoint& offset) } } -/** - * Compute the box blur size (which we're calling the blur radius) from - * the standard deviation. - * - * Much of this, the 3 * sqrt(2 * pi) / 4, is the known value for - * approximating a Gaussian using box blurs. This yields quite a good - * approximation for a Gaussian. Then we multiply this by 1.5 since our - * code wants the radius of the entire triple-box-blur kernel instead of - * the diameter of an individual box blur. For more details, see: - * http://www.w3.org/TR/SVG11/filters.html#feGaussianBlurElement - * https://bugzilla.mozilla.org/show_bug.cgi?id=590039#c19 - */ -static const gfxFloat GAUSSIAN_SCALE_FACTOR = (3 * sqrt(2 * M_PI) / 4) * 1.5; - gfxIntSize gfxAlphaBoxBlur::CalculateBlurRadius(const gfxPoint& aStd) { - return gfxIntSize( - static_cast(floor(aStd.x * GAUSSIAN_SCALE_FACTOR + 0.5)), - static_cast(floor(aStd.y * GAUSSIAN_SCALE_FACTOR + 0.5))); + Point std(aStd.x, aStd.y); + IntSize size = AlphaBoxBlur::CalculateBlurRadius(std); + return gfxIntSize(size.width, size.height); } diff --git a/gfx/thebes/gfxBlur.h b/gfx/thebes/gfxBlur.h index 48a91b5e7e77..2e758cb6da6a 100644 --- a/gfx/thebes/gfxBlur.h +++ b/gfx/thebes/gfxBlur.h @@ -42,7 +42,12 @@ #include "gfxImageSurface.h" #include "gfxTypes.h" #include "gfxUtils.h" -#include "nsRect.h" + +namespace mozilla { + namespace gfx { + class AlphaBoxBlur; + } +} /** * Implementation of a triple box blur approximation of a Gaussian blur. @@ -122,15 +127,6 @@ public: static gfxIntSize CalculateBlurRadius(const gfxPoint& aStandardDeviation); protected: - /** - * The spread radius, in pixels. - */ - gfxIntSize mSpreadRadius; - /** - * The blur radius, in pixels. - */ - gfxIntSize mBlurRadius; - /** * The context of the temporary alpha surface. */ @@ -141,18 +137,10 @@ protected: */ nsRefPtr mImageSurface; - /** - * A copy of the dirty rect passed to Init(). This will only be valid if - * mHasDirtyRect is TRUE. - */ - gfxRect mDirtyRect; - /** - * A rect indicating the area where blurring is unnecessary, and the blur - * algorithm should skip over it. - */ - nsIntRect mSkipRect; - - bool mHasDirtyRect; + /** + * The object that actually does the blurring for us. + */ + mozilla::gfx::AlphaBoxBlur *mBlur; }; #endif /* GFX_BLUR_H */ From 342f1d0cec7bdfa47294a90fb9fdfbbd742e0bc1 Mon Sep 17 00:00:00 2001 From: Jeff Muizelaar Date: Sat, 19 Nov 2011 01:39:14 +1300 Subject: [PATCH 08/63] Bug 666312. Check surface status instead of surface existance. r=mwoodrow We always have cairo surfaces now instead of having NULL ones. We should check the status instead. This fixes crashes with the quartz and skia azure backends. --- content/canvas/src/nsCanvasRenderingContext2DAzure.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/content/canvas/src/nsCanvasRenderingContext2DAzure.cpp b/content/canvas/src/nsCanvasRenderingContext2DAzure.cpp index 78e3789c5e02..849519f5a5af 100644 --- a/content/canvas/src/nsCanvasRenderingContext2DAzure.cpp +++ b/content/canvas/src/nsCanvasRenderingContext2DAzure.cpp @@ -3650,8 +3650,8 @@ nsCanvasRenderingContext2DAzure::DrawImage(nsIDOMElement *imgElt, float a1, return res.mIsStillLoading ? NS_OK : NS_ERROR_NOT_AVAILABLE; } - // Ignore nsnull cairo surfaces! See bug 666312. - if (!res.mSurface->CairoSurface()) { + // Ignore cairo surfaces that are bad! See bug 666312. + if (res.mSurface->CairoStatus()) { return NS_OK; } From 4ed618f111ce5a1259bdaa80deb8fe464e4435e7 Mon Sep 17 00:00:00 2001 From: Oleg Romashin Date: Fri, 18 Nov 2011 14:01:35 +0100 Subject: [PATCH 09/63] Bug 618765 - unbind VBO required in order to share GL context with toolkit. r=jrmuizel --- gfx/layers/opengl/LayerManagerOGL.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gfx/layers/opengl/LayerManagerOGL.cpp b/gfx/layers/opengl/LayerManagerOGL.cpp index d398dc5cc8b4..69b4c116f0c9 100644 --- a/gfx/layers/opengl/LayerManagerOGL.cpp +++ b/gfx/layers/opengl/LayerManagerOGL.cpp @@ -336,6 +336,7 @@ LayerManagerOGL::Initialize(nsRefPtr aContext) 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, }; mGLContext->fBufferData(LOCAL_GL_ARRAY_BUFFER, sizeof(vertices), vertices, LOCAL_GL_STATIC_DRAW); + mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0); nsCOMPtr console(do_GetService(NS_CONSOLESERVICE_CONTRACTID)); @@ -901,6 +902,7 @@ LayerManagerOGL::Render() mGLContext->fDisableVertexAttribArray(tcattr); mGLContext->fFlush(); + mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0); } void From fd657289a974cd0e15d11459584e563c397e6862 Mon Sep 17 00:00:00 2001 From: Hanspeter Niederstrasser Date: Fri, 18 Nov 2011 14:02:26 +0100 Subject: [PATCH 10/63] Bug 691135 - intl locale should use mac on Macs. r=ted --- intl/build/Makefile.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/intl/build/Makefile.in b/intl/build/Makefile.in index e79602aad680..2a66d6a79571 100644 --- a/intl/build/Makefile.in +++ b/intl/build/Makefile.in @@ -58,7 +58,7 @@ CPPSRCS = \ ifneq (,$(filter os2 windows, $(MOZ_WIDGET_TOOLKIT))) LOCALE_DIR = $(MOZ_WIDGET_TOOLKIT) else -ifeq ($(MOZ_WIDGET_TOOLKIT), cocoa) +ifeq ($(OS_ARCH), Darwin) LOCALE_DIR = mac else LOCALE_DIR = unix From 73c7f9d3201bbbd9cf2887b6d5ef1dc7c92171c3 Mon Sep 17 00:00:00 2001 From: Atul Aggarwal Date: Sun, 6 Nov 2011 21:15:44 +0530 Subject: [PATCH 11/63] Bug 630290 - Fixing compiler warnings. r=cjones --- xpcom/tests/TestObserverArray.cpp | 2 +- xpcom/tests/TestTArray.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/xpcom/tests/TestObserverArray.cpp b/xpcom/tests/TestObserverArray.cpp index 68cd8ee086af..53b7d1ceb4d1 100644 --- a/xpcom/tests/TestObserverArray.cpp +++ b/xpcom/tests/TestObserverArray.cpp @@ -82,7 +82,7 @@ int main(int argc, char **argv) arr.AppendElement(3); arr.AppendElement(4); - int count; + size_t count; int testNum = 0; // Basic sanity diff --git a/xpcom/tests/TestTArray.cpp b/xpcom/tests/TestTArray.cpp index 31dbd8643ed7..2394084eca2a 100644 --- a/xpcom/tests/TestTArray.cpp +++ b/xpcom/tests/TestTArray.cpp @@ -633,7 +633,7 @@ static bool test_heap() { #define CHECK_ARRAY(arr, data) \ do { \ - CHECK_EQ_INT((arr).Length(), ArrayLength(data)); \ + CHECK_EQ_INT((arr).Length(), (PRUint32)ArrayLength(data)); \ for (PRUint32 _i = 0; _i < ArrayLength(data); _i++) { \ CHECK_EQ_INT((arr)[_i], (data)[_i]); \ } \ From c265b4ae97966f613944afa319f1d02f8b136a84 Mon Sep 17 00:00:00 2001 From: Ms2ger Date: Fri, 18 Nov 2011 15:09:25 +0100 Subject: [PATCH 12/63] Bug 703374 - Add back an assignment to rv in nsHTMLDocument::StartDocumentLoad; r=hsivonen --- content/html/document/src/nsHTMLDocument.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/content/html/document/src/nsHTMLDocument.cpp b/content/html/document/src/nsHTMLDocument.cpp index a2724be426d9..c708e4490e7b 100644 --- a/content/html/document/src/nsHTMLDocument.cpp +++ b/content/html/document/src/nsHTMLDocument.cpp @@ -950,6 +950,7 @@ nsHTMLDocument::StartDocumentLoad(const char* aCommand, // Set the parser as the stream listener for the document loader... if (mParser) { + rv = NS_OK; nsCOMPtr listener = mParser->GetStreamListener(); listener.forget(aDocListener); From 477ce89a9ec9052e786fd276a8b183ff6f20760d Mon Sep 17 00:00:00 2001 From: Igor Bukanov Date: Wed, 16 Nov 2011 15:00:32 +0100 Subject: [PATCH 13/63] Bug 701560 - template version of merge sort. r=luke --- js/src/ds/Sort.h | 170 ++++++++++++++++++ js/src/jsarray.cpp | 418 ++++++++++++-------------------------------- js/src/jsarray.h | 25 --- js/src/jsopcode.cpp | 43 ++--- 4 files changed, 302 insertions(+), 354 deletions(-) create mode 100644 js/src/ds/Sort.h diff --git a/js/src/ds/Sort.h b/js/src/ds/Sort.h new file mode 100644 index 000000000000..f8c3ccb6c489 --- /dev/null +++ b/js/src/ds/Sort.h @@ -0,0 +1,170 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=4 sw=4 et tw=99 ft=cpp: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is SpiderMonkey JavaScript engine. + * + * The Initial Developer of the Original Code is + * Mozilla Corporation. + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef Sort_h__ +#define Sort_h__ + +#include "jstypes.h" + +namespace js { + +namespace detail { + +template +JS_ALWAYS_INLINE void +CopyNonEmptyArray(T *dst, const T *src, size_t nelems) +{ + JS_ASSERT(nelems != 0); + const T *end = src + nelems; + do { + *dst++ = *src++; + } while (src != end); +} + +/* Helper function for MergeSort. */ +template +JS_ALWAYS_INLINE bool +MergeArrayRuns(T *dst, const T *src, size_t run1, size_t run2, Comparator c) +{ + JS_ASSERT(run1 >= 1); + JS_ASSERT(run2 >= 1); + + /* Copy runs already in sorted order. */ + const T *b = src + run1; + bool lessOrEqual; + if (!c(b[-1], b[0], &lessOrEqual)) + return false; + + if (!lessOrEqual) { + /* Runs are not already sorted, merge them. */ + for (const T *a = src;;) { + if (!c(*a, *b, &lessOrEqual)) + return false; + if (lessOrEqual) { + *dst++ = *a++; + if (!--run1) { + src = b; + break; + } + } else { + *dst++ = *b++; + if (!--run2) { + src = a; + break; + } + } + } + } + CopyNonEmptyArray(dst, src, run1 + run2); + return true; +} + +} /* namespace detail */ + +/* + * Sort the array using the merge sort algorithm. The scratch should point to + * a temporary storage that can hold nelems elements. + * + * The comparator must provide the () operator with the following signature: + * + * bool operator()(const T& a, const T& a, bool *lessOrEqualp); + * + * It should return true on success and sets lessOrEqualp to the result of + * a <= b operation. If it returns false, the sort terminates immediately with + * the false result. In this case the content of the array and scratch is + * arbitrary. + */ +template +bool +MergeSort(T *array, size_t nelems, T *scratch, Comparator c) +{ + const size_t INS_SORT_LIMIT = 3; + + if (nelems <= 1) + return true; + + /* + * Apply insertion sort to small chunks to reduce the number of merge + * passes needed. + */ + for (size_t lo = 0; lo < nelems; lo += INS_SORT_LIMIT) { + size_t hi = lo + INS_SORT_LIMIT; + if (hi >= nelems) + hi = nelems; + for (size_t i = lo + 1; i != hi; i++) { + for (size_t j = i; ;) { + bool lessOrEqual; + if (!c(array[j - 1], array[j], &lessOrEqual)) + return false; + if (lessOrEqual) + break; + T tmp = array[j - 1]; + array[j - 1] = array[j]; + array[j] = tmp; + if (--j == lo) + break; + } + } + } + + T *vec1 = array; + T *vec2 = scratch; + for (size_t run = INS_SORT_LIMIT; run < nelems; run *= 2) { + for (size_t lo = 0; lo < nelems; lo += 2 * run) { + size_t hi = lo + run; + if (hi >= nelems) { + detail::CopyNonEmptyArray(vec2 + lo, vec1 + lo, nelems - lo); + break; + } + size_t run2 = (run <= nelems - hi) ? run : nelems - hi; + if (!detail::MergeArrayRuns(vec2 + lo, vec1 + lo, run, run2, c)) + return false; + } + T *swap = vec1; + vec1 = vec2; + vec2 = swap; + } + if (vec1 == scratch) + detail::CopyNonEmptyArray(array, scratch, nelems); + return true; +} + +} /* namespace js */ + +#endif diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp index 64a3da7f6552..cfe408b705ea 100644 --- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -131,6 +131,8 @@ #include "vm/ArgumentsObject.h" +#include "ds/Sort.h" + #include "jsarrayinlines.h" #include "jsatominlines.h" #include "jscntxtinlines.h" @@ -188,8 +190,8 @@ namespace js { * only if ToString(ToUint32(P)) is equal to P and ToUint32(P) is not equal * to 2^32-1." * - * This means the largest allowed index is actually 2^32-2 (4294967294). - * + * This means the largest allowed index is actually 2^32-2 (4294967294). + * * In our implementation, it would be sufficient to check for JSVAL_IS_INT(id) * except that by using signed 31-bit integers we miss the top half of the * valid range. This function checks the string representation itself; note @@ -207,7 +209,7 @@ StringIsArrayIndex(JSLinearString *str, jsuint *indexp) if (length == 0 || length > (sizeof("4294967294") - 1) || !JS7_ISDEC(*s)) return false; - uint32 c = 0, previous = 0; + uint32 c = 0, previous = 0; uint32 index = JS7_UNDEC(*s++); /* Don't allow leading zeros. */ @@ -224,13 +226,13 @@ StringIsArrayIndex(JSLinearString *str, jsuint *indexp) } /* Make sure we didn't overflow. */ - if (previous < (MAX_ARRAY_INDEX / 10) || (previous == (MAX_ARRAY_INDEX / 10) && + if (previous < (MAX_ARRAY_INDEX / 10) || (previous == (MAX_ARRAY_INDEX / 10) && c <= (MAX_ARRAY_INDEX % 10))) { JS_ASSERT(index <= MAX_ARRAY_INDEX); *indexp = index; return true; } - + return false; } @@ -1980,239 +1982,104 @@ array_reverse(JSContext *cx, uintN argc, Value *vp) return true; } -typedef struct MSortArgs { - size_t elsize; - JSComparator cmp; - void *arg; - JSBool isValue; -} MSortArgs; +namespace { -/* Helper function for js_MergeSort. */ -static JSBool -MergeArrays(MSortArgs *msa, void *src, void *dest, size_t run1, size_t run2) +inline bool +CompareStringValues(JSContext *cx, const Value &a, const Value &b, bool *lessOrEqualp) { - void *arg, *a, *b, *c; - size_t elsize, runtotal; - int cmp_result; - JSComparator cmp; - JSBool isValue; + if (!JS_CHECK_OPERATION_LIMIT(cx)) + return false; - runtotal = run1 + run2; + JSString *astr = a.toString(); + JSString *bstr = b.toString(); + int32 result; + if (!CompareStrings(cx, astr, bstr, &result)) + return false; - elsize = msa->elsize; - cmp = msa->cmp; - arg = msa->arg; - isValue = msa->isValue; - -#define CALL_CMP(a, b) \ - if (!cmp(arg, (a), (b), &cmp_result)) return JS_FALSE; - - /* Copy runs already in sorted order. */ - b = (char *)src + run1 * elsize; - a = (char *)b - elsize; - CALL_CMP(a, b); - if (cmp_result <= 0) { - memcpy(dest, src, runtotal * elsize); - return JS_TRUE; - } - -#define COPY_ONE(p,q,n) \ - (isValue ? (void)(*(Value*)p = *(Value*)q) : (void)memcpy(p, q, n)) - - a = src; - c = dest; - for (; runtotal != 0; runtotal--) { - JSBool from_a = run2 == 0; - if (!from_a && run1 != 0) { - CALL_CMP(a,b); - from_a = cmp_result <= 0; - } - - if (from_a) { - COPY_ONE(c, a, elsize); - run1--; - a = (char *)a + elsize; - } else { - COPY_ONE(c, b, elsize); - run2--; - b = (char *)b + elsize; - } - c = (char *)c + elsize; - } -#undef COPY_ONE -#undef CALL_CMP - - return JS_TRUE; + *lessOrEqualp = (result <= 0); + return true; } -/* - * This sort is stable, i.e. sequence of equal elements is preserved. - * See also bug #224128. - */ -bool -js_MergeSort(void *src, size_t nel, size_t elsize, - JSComparator cmp, void *arg, void *tmp, - JSMergeSortElemType elemType) -{ - void *swap, *vec1, *vec2; - MSortArgs msa; - size_t i, j, lo, hi, run; - int cmp_result; +struct SortComparatorStrings { + JSContext *const cx; - JS_ASSERT_IF(JS_SORTING_VALUES, elsize == sizeof(Value)); - bool isValue = elemType == JS_SORTING_VALUES; + SortComparatorStrings(JSContext *cx) + : cx(cx) {} - /* Avoid memcpy overhead for word-sized and word-aligned elements. */ -#define COPY_ONE(p,q,n) \ - (isValue ? (void)(*(Value*)p = *(Value*)q) : (void)memcpy(p, q, n)) -#define CALL_CMP(a, b) \ - if (!cmp(arg, (a), (b), &cmp_result)) return JS_FALSE; -#define INS_SORT_INT 4 - - /* - * Apply insertion sort to small chunks to reduce the number of merge - * passes needed. - */ - for (lo = 0; lo < nel; lo += INS_SORT_INT) { - hi = lo + INS_SORT_INT; - if (hi >= nel) - hi = nel; - for (i = lo + 1; i < hi; i++) { - vec1 = (char *)src + i * elsize; - vec2 = (char *)vec1 - elsize; - for (j = i; j > lo; j--) { - CALL_CMP(vec2, vec1); - /* "<=" instead of "<" insures the sort is stable */ - if (cmp_result <= 0) { - break; - } - - /* Swap elements, using "tmp" as tmp storage */ - COPY_ONE(tmp, vec2, elsize); - COPY_ONE(vec2, vec1, elsize); - COPY_ONE(vec1, tmp, elsize); - vec1 = vec2; - vec2 = (char *)vec1 - elsize; - } - } + bool operator()(const Value &a, const Value &b, bool *lessOrEqualp) { + return CompareStringValues(cx, a, b, lessOrEqualp); } -#undef CALL_CMP -#undef COPY_ONE - - msa.elsize = elsize; - msa.cmp = cmp; - msa.arg = arg; - msa.isValue = isValue; - - vec1 = src; - vec2 = tmp; - for (run = INS_SORT_INT; run < nel; run *= 2) { - for (lo = 0; lo < nel; lo += 2 * run) { - hi = lo + run; - if (hi >= nel) { - memcpy((char *)vec2 + lo * elsize, (char *)vec1 + lo * elsize, - (nel - lo) * elsize); - break; - } - if (!MergeArrays(&msa, (char *)vec1 + lo * elsize, - (char *)vec2 + lo * elsize, run, - hi + run > nel ? nel - hi : run)) { - return JS_FALSE; - } - } - swap = vec1; - vec1 = vec2; - vec2 = swap; - } - if (src != vec1) - memcpy(src, tmp, nel * elsize); - - return JS_TRUE; -} - -struct CompareArgs -{ - JSContext *context; - InvokeArgsGuard args; - Value fval; - - CompareArgs(JSContext *cx, Value fval) - : context(cx), fval(fval) - {} }; -static JS_REQUIRES_STACK JSBool -sort_compare(void *arg, const void *a, const void *b, int *result) -{ - const Value *av = (const Value *)a, *bv = (const Value *)b; - CompareArgs *ca = (CompareArgs *) arg; - JSContext *cx = ca->context; +struct StringValuePair { + Value str; + Value v; +}; +struct SortComparatorStringValuePairs { + JSContext *const cx; + + SortComparatorStringValuePairs(JSContext *cx) + : cx(cx) {} + + bool operator()(const StringValuePair &a, const StringValuePair &b, bool *lessOrEqualp) { + return CompareStringValues(cx, a.str, b.str, lessOrEqualp); + } +}; + +struct SortComparatorFunction { + JSContext *const cx; + const Value &fval; + InvokeArgsGuard &ag; + + SortComparatorFunction(JSContext *cx, const Value &fval, InvokeArgsGuard &ag) + : cx(cx), fval(fval), ag(ag) { } + + bool JS_REQUIRES_STACK operator()(const Value &a, const Value &b, bool *lessOrEqualp); +}; + +bool +SortComparatorFunction::operator()(const Value &a, const Value &b, bool *lessOrEqualp) +{ /* * array_sort deals with holes and undefs on its own and they should not * come here. */ - JS_ASSERT(!av->isMagic() && !av->isUndefined()); - JS_ASSERT(!av->isMagic() && !bv->isUndefined()); + JS_ASSERT(!a.isMagic() && !a.isUndefined()); + JS_ASSERT(!a.isMagic() && !b.isUndefined()); if (!JS_CHECK_OPERATION_LIMIT(cx)) - return JS_FALSE; + return false; - InvokeArgsGuard &ag = ca->args; if (!ag.pushed() && !cx->stack.pushInvokeArgs(cx, 2, &ag)) - return JS_FALSE; + return false; - ag.setCallee(ca->fval); + ag.setCallee(fval); ag.thisv() = UndefinedValue(); - ag[0] = *av; - ag[1] = *bv; + ag[0] = a; + ag[1] = b; if (!Invoke(cx, ag)) - return JS_FALSE; + return false; jsdouble cmp; if (!ToNumber(cx, ag.rval(), &cmp)) - return JS_FALSE; - - /* Clamp cmp to -1, 0, 1. */ - *result = 0; - if (!JSDOUBLE_IS_NaN(cmp) && cmp != 0) - *result = cmp > 0 ? 1 : -1; + return false; /* - * XXX else report some kind of error here? ECMA talks about 'consistent - * compare functions' that don't return NaN, but is silent about what the - * result should be. So we currently ignore it. + * XXX eport some kind of error here if cmp is NaN? ECMA talks about + * 'consistent compare functions' that don't return NaN, but is silent + * about what the result should be. So we currently ignore it. */ - - return JS_TRUE; + *lessOrEqualp = (JSDOUBLE_IS_NaN(cmp) || cmp <= 0); + return true; } -typedef JSBool (JS_REQUIRES_STACK *JSRedComparator)(void*, const void*, - const void*, int *); - -static inline JS_IGNORE_STACK JSComparator -comparator_stack_cast(JSRedComparator func) -{ - return func; -} - -static int -sort_compare_strings(void *arg, const void *a, const void *b, int *result) -{ - JSContext *cx = (JSContext *)arg; - JSString *astr = ((const Value *)a)->toString(); - JSString *bstr = ((const Value *)b)->toString(); - return JS_CHECK_OPERATION_LIMIT(cx) && CompareStrings(cx, astr, bstr, result); -} +} /* namespace anonymous */ JSBool js::array_sort(JSContext *cx, uintN argc, Value *vp) { - jsuint len, newlen, i, undefs; - size_t elemsize; - JSString *str; - CallArgs args = CallArgsFromVp(argc, vp); Value fval; if (args.length() > 0 && !args[0].isUndefined()) { @@ -2228,6 +2095,8 @@ js::array_sort(JSContext *cx, uintN argc, Value *vp) JSObject *obj = ToObject(cx, &args.thisv()); if (!obj) return false; + + jsuint len; if (!js_GetLengthProperty(cx, obj, &len)) return false; if (len == 0) { @@ -2257,23 +2126,12 @@ js::array_sort(JSContext *cx, uintN argc, Value *vp) * access the tail of vec corresponding to properties that do not * exist, allowing OS to avoiding committing RAM. See bug 330812. */ + size_t n, undefs; { - Value *vec = (Value *) cx->malloc_(2 * size_t(len) * sizeof(Value)); - if (!vec) + AutoValueVector vec(cx); + if (!vec.reserve(2 * size_t(len))) return false; - DEFINE_LOCAL_CLASS_OF_STATIC_FUNCTION(AutoFreeVector) { - JSContext *const cx; - Value *&vec; - public: - AutoFreeVector(JSContext *cx, Value *&vec) : cx(cx), vec(vec) { } - ~AutoFreeVector() { - cx->free_(vec); - } - } free_(cx, vec); - - AutoArrayRooter tvr(cx, 0, vec); - /* * By ECMA 262, 15.4.4.11, a property that does not exist (which we * call a "hole") is always greater than an existing property with @@ -2283,94 +2141,60 @@ js::array_sort(JSContext *cx, uintN argc, Value *vp) * undefs. */ undefs = 0; - newlen = 0; bool allStrings = true; - for (i = 0; i < len; i++) { + for (size_t i = 0; i < len; i++) { if (!JS_CHECK_OPERATION_LIMIT(cx)) return false; /* Clear vec[newlen] before including it in the rooted set. */ JSBool hole; - vec[newlen].setNull(); - tvr.changeLength(newlen + 1); - if (!GetElement(cx, obj, i, &hole, &vec[newlen])) + Value v; + if (!GetElement(cx, obj, i, &hole, &v)) return false; - if (hole) continue; - - if (vec[newlen].isUndefined()) { + if (v.isUndefined()) { ++undefs; continue; } - - allStrings = allStrings && vec[newlen].isString(); - - ++newlen; + vec.infallibleAppend(v); + allStrings = allStrings && v.isString(); } - if (newlen == 0) { + n = vec.length(); + if (n == 0) { args.rval().setObject(*obj); return true; /* The array has only holes and undefs. */ } - /* - * The first newlen elements of vec are copied from the array object - * (above). The remaining newlen positions are used as GC-rooted scratch - * space for mergesort. We must clear the space before including it to - * the root set covered by tvr.count. - */ - Value *mergesort_tmp = vec + newlen; - MakeRangeGCSafe(mergesort_tmp, newlen); - tvr.changeLength(newlen * 2); + JS_ALWAYS_TRUE(vec.resize(n * 2)); - /* Here len == 2 * (newlen + undefs + number_of_holes). */ + /* Here len == 2 * (n + undefs + number_of_holes). */ if (fval.isNull()) { /* * Sort using the default comparator converting all elements to * strings. */ if (allStrings) { - elemsize = sizeof(Value); + if (!MergeSort(vec.begin(), n, vec.begin() + n, SortComparatorStrings(cx))) + return false; } else { /* * To avoid string conversion on each compare we do it only once * prior to sorting. But we also need the space for the original - * values to recover the sorting result. To reuse - * sort_compare_strings we move the original values to the odd - * indexes in vec, put the string conversion results in the even - * indexes and pass 2 * sizeof(Value) as an element size to the - * sorting function. In this way sort_compare_strings will only - * see the string values when it casts the compare arguments as - * pointers to Value. - * - * This requires doubling the temporary storage including the - * scratch space for the merge sort. Since vec already contains - * the rooted scratch space for newlen elements at the tail, we - * can use it to rearrange and convert to strings first and try - * realloc only when we know that we successfully converted all - * the elements. + * values to recover the sorting result. For that we move the + * original values to the odd indexes in vec, put the string + * conversion results in the even indexes and do the merge sort + * over resulting string-value pairs using an extra allocated + * scratch space. */ -#if JS_BITS_PER_WORD == 32 - if (size_t(newlen) > size_t(-1) / (4 * sizeof(Value))) { - js_ReportAllocationOverflow(cx); - return false; - } -#endif - - /* - * Rearrange and string-convert the elements of the vector from - * the tail here and, after sorting, move the results back - * starting from the start to prevent overwrite the existing - * elements. - */ - i = newlen; + size_t i = n; do { --i; if (!JS_CHECK_OPERATION_LIMIT(cx)) return false; const Value &v = vec[i]; - str = js_ValueToString(cx, v); + JSString *str = js_ValueToString(cx, v); if (!str) return false; // Copying v must come first, because the following line overwrites v @@ -2379,40 +2203,30 @@ js::array_sort(JSContext *cx, uintN argc, Value *vp) vec[2 * i].setString(str); } while (i != 0); - JS_ASSERT(tvr.array == vec); - vec = (Value *) cx->realloc_(vec, 4 * size_t(newlen) * sizeof(Value)); - if (!vec) { - vec = tvr.array; /* N.B. AutoFreeVector */ + AutoValueVector extraScratch(cx); + if (!extraScratch.resize(n * 2)) + return false; + if (!MergeSort(reinterpret_cast(vec.begin()), n, + reinterpret_cast(extraScratch.begin()), + SortComparatorStringValuePairs(cx))) { return false; } - mergesort_tmp = vec + 2 * newlen; - MakeRangeGCSafe(mergesort_tmp, 2 * newlen); - tvr.changeArray(vec, newlen * 4); - elemsize = 2 * sizeof(Value); - } - if (!js_MergeSort(vec, size_t(newlen), elemsize, - sort_compare_strings, cx, mergesort_tmp, - JS_SORTING_GENERIC)) { - return false; - } - if (!allStrings) { + /* - * We want to make the following loop fast and to unroot the - * cached results of toString invocations before the operation - * callback has a chance to run the GC. For this reason we do - * not call JS_CHECK_OPERATION_LIMIT in the loop. + * We want to unroot the cached results of toString calls + * before the operation callback has a chance to run the GC. + * So we do not call JS_CHECK_OPERATION_LIMIT in the loop. */ i = 0; do { vec[i] = vec[2 * i + 1]; - } while (++i != newlen); + } while (++i != n); } } else { - CompareArgs ca(cx, fval); - if (!js_MergeSort(vec, size_t(newlen), sizeof(Value), - comparator_stack_cast(sort_compare), - &ca, mergesort_tmp, - JS_SORTING_VALUES)) { + InvokeArgsGuard args; + if (!MergeSort(vec.begin(), n, vec.begin() + n, + SortComparatorFunction(cx, fval, args))) + { return false; } } @@ -2422,22 +2236,20 @@ js::array_sort(JSContext *cx, uintN argc, Value *vp) * unroot it now to make the job of a potential GC under * InitArrayElements easier. */ - tvr.changeLength(newlen); - if (!InitArrayElements(cx, obj, 0, newlen, vec, false)) + vec.resize(n); + if (!InitArrayElements(cx, obj, 0, n, vec.begin(), false)) return false; } /* Set undefs that sorted after the rest of elements. */ while (undefs != 0) { --undefs; - if (!JS_CHECK_OPERATION_LIMIT(cx) || - !SetArrayElement(cx, obj, newlen++, UndefinedValue())) { + if (!JS_CHECK_OPERATION_LIMIT(cx) || !SetArrayElement(cx, obj, n++, UndefinedValue())) return false; - } } /* Re-create any holes that sorted to the end of the array. */ - while (len > newlen) { + while (len > n) { if (!JS_CHECK_OPERATION_LIMIT(cx) || DeleteArrayElement(cx, obj, --len, true) < 0) return false; } @@ -2586,7 +2398,7 @@ array_pop_dense(JSContext *cx, JSObject* obj, CallArgs &args) } index--; - + JSBool hole; Value elt; if (!GetElement(cx, obj, index, &hole, &elt)) @@ -3392,7 +3204,7 @@ array_readonlyCommon(JSContext *cx, CallArgs &args) args.rval() = Behavior::lateExitValue(); return true; } - + /* ES5 15.4.4.16. */ static JSBool array_every(JSContext *cx, uintN argc, Value *vp) @@ -3595,7 +3407,7 @@ class ArrayReduceRightBehavior { *start = len - 1; *step = -1; - /* + /* * We rely on (well defined) unsigned integer underflow to check our * end condition after visiting the full range (including 0). */ diff --git a/js/src/jsarray.h b/js/src/jsarray.h index 9db642634368..c226fcbd27cb 100644 --- a/js/src/jsarray.h +++ b/js/src/jsarray.h @@ -178,31 +178,6 @@ GetElements(JSContext *cx, JSObject *aobj, jsuint length, js::Value *vp); } -/* - * JS-specific merge sort function. - */ -typedef JSBool (*JSComparator)(void *arg, const void *a, const void *b, - int *result); - -enum JSMergeSortElemType { - JS_SORTING_VALUES, - JS_SORTING_GENERIC -}; - -/* - * NB: vec is the array to be sorted, tmp is temporary space at least as big - * as vec. Both should be GC-rooted if appropriate. - * - * isValue should true iff vec points to an array of js::Value - * - * The sorted result is in vec. vec may be in an inconsistent state if the - * comparator function cmp returns an error inside a comparison, so remember - * to check the return value of this function. - */ -extern bool -js_MergeSort(void *vec, size_t nel, size_t elsize, JSComparator cmp, - void *arg, void *tmp, JSMergeSortElemType elemType); - /* Natives exposed for optimization by the interpreter and JITs. */ namespace js { diff --git a/js/src/jsopcode.cpp b/js/src/jsopcode.cpp index 1e88b5454052..827d24da0e68 100644 --- a/js/src/jsopcode.cpp +++ b/js/src/jsopcode.cpp @@ -69,6 +69,8 @@ #include "jsscript.h" #include "jsstr.h" +#include "ds/Sort.h" + #include "frontend/BytecodeEmitter.h" #include "frontend/TokenStream.h" #include "vm/Debugger.h" @@ -1339,26 +1341,19 @@ IsInitializerOp(unsigned char op) return op == JSOP_NEWINIT || op == JSOP_NEWARRAY || op == JSOP_NEWOBJECT; } -typedef struct TableEntry { +struct TableEntry { jsval key; ptrdiff_t offset; JSAtom *label; jsint order; /* source order for stable tableswitch sort */ -} TableEntry; +}; -static JSBool -CompareOffsets(void *arg, const void *v1, const void *v2, int *result) +inline bool +CompareTableEntries(const TableEntry &a, const TableEntry &b, bool *lessOrEqualp) { - ptrdiff_t offset_diff; - const TableEntry *te1 = (const TableEntry *) v1, - *te2 = (const TableEntry *) v2; - - offset_diff = te1->offset - te2->offset; - *result = (offset_diff == 0 ? te1->order - te2->order - : offset_diff < 0 ? -1 - : 1); - return JS_TRUE; -} + *lessOrEqualp = (a.offset != b.offset) ? a.offset <= b.offset : a.order <= b.order; + return true; +}; static ptrdiff_t SprintDoubleValue(Sprinter *sp, jsval v, JSOp *opp) @@ -4334,8 +4329,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb) sn = js_GetSrcNote(jp->script, pc); LOCAL_ASSERT(sn && SN_TYPE(sn) == SRC_SWITCH); len = js_GetSrcNoteOffset(sn, 0); - jmplen = (op == JSOP_TABLESWITCH) ? JUMP_OFFSET_LEN - : JUMPX_OFFSET_LEN; + jmplen = (op == JSOP_TABLESWITCH) ? JUMP_OFFSET_LEN : JUMPX_OFFSET_LEN; pc2 = pc; off = GetJumpOffset(pc, pc2); pc2 += jmplen; @@ -4348,7 +4342,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb) if (n == 0) { table = NULL; j = 0; - ok = JS_TRUE; + ok = true; } else { table = (TableEntry *) cx->malloc_((size_t)n * sizeof *table); @@ -4374,19 +4368,16 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb) cx->malloc_((size_t)j * sizeof *table); if (tmp) { VOUCH_DOES_NOT_REQUIRE_STACK(); - ok = js_MergeSort(table, (size_t)j, sizeof(TableEntry), - CompareOffsets, NULL, tmp, - JS_SORTING_GENERIC); - cx->free_(tmp); + MergeSort(table, size_t(j), tmp, CompareTableEntries); + Foreground::free_(tmp); + ok = true; } else { - ok = JS_FALSE; + ok = false; } } - if (ok) { - ok = DecompileSwitch(ss, table, (uintN)j, pc, len, off, - JS_FALSE); - } + if (ok) + ok = DecompileSwitch(ss, table, (uintN)j, pc, len, off, false); cx->free_(table); if (!ok) return NULL; From 223554f33c24d5e635651129613c9fdd3d0fd721 Mon Sep 17 00:00:00 2001 From: Igor Bukanov Date: Fri, 18 Nov 2011 15:52:35 +0100 Subject: [PATCH 14/63] Backed out changeset e1587f23d2f0, bug 701560 - compilation errors --- js/src/ds/Sort.h | 170 ------------------ js/src/jsarray.cpp | 426 +++++++++++++++++++++++++++++++------------- js/src/jsarray.h | 25 +++ js/src/jsopcode.cpp | 43 +++-- 4 files changed, 358 insertions(+), 306 deletions(-) delete mode 100644 js/src/ds/Sort.h diff --git a/js/src/ds/Sort.h b/js/src/ds/Sort.h deleted file mode 100644 index f8c3ccb6c489..000000000000 --- a/js/src/ds/Sort.h +++ /dev/null @@ -1,170 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set ts=4 sw=4 et tw=99 ft=cpp: - * - * ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is SpiderMonkey JavaScript engine. - * - * The Initial Developer of the Original Code is - * Mozilla Corporation. - * Portions created by the Initial Developer are Copyright (C) 2011 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -#ifndef Sort_h__ -#define Sort_h__ - -#include "jstypes.h" - -namespace js { - -namespace detail { - -template -JS_ALWAYS_INLINE void -CopyNonEmptyArray(T *dst, const T *src, size_t nelems) -{ - JS_ASSERT(nelems != 0); - const T *end = src + nelems; - do { - *dst++ = *src++; - } while (src != end); -} - -/* Helper function for MergeSort. */ -template -JS_ALWAYS_INLINE bool -MergeArrayRuns(T *dst, const T *src, size_t run1, size_t run2, Comparator c) -{ - JS_ASSERT(run1 >= 1); - JS_ASSERT(run2 >= 1); - - /* Copy runs already in sorted order. */ - const T *b = src + run1; - bool lessOrEqual; - if (!c(b[-1], b[0], &lessOrEqual)) - return false; - - if (!lessOrEqual) { - /* Runs are not already sorted, merge them. */ - for (const T *a = src;;) { - if (!c(*a, *b, &lessOrEqual)) - return false; - if (lessOrEqual) { - *dst++ = *a++; - if (!--run1) { - src = b; - break; - } - } else { - *dst++ = *b++; - if (!--run2) { - src = a; - break; - } - } - } - } - CopyNonEmptyArray(dst, src, run1 + run2); - return true; -} - -} /* namespace detail */ - -/* - * Sort the array using the merge sort algorithm. The scratch should point to - * a temporary storage that can hold nelems elements. - * - * The comparator must provide the () operator with the following signature: - * - * bool operator()(const T& a, const T& a, bool *lessOrEqualp); - * - * It should return true on success and sets lessOrEqualp to the result of - * a <= b operation. If it returns false, the sort terminates immediately with - * the false result. In this case the content of the array and scratch is - * arbitrary. - */ -template -bool -MergeSort(T *array, size_t nelems, T *scratch, Comparator c) -{ - const size_t INS_SORT_LIMIT = 3; - - if (nelems <= 1) - return true; - - /* - * Apply insertion sort to small chunks to reduce the number of merge - * passes needed. - */ - for (size_t lo = 0; lo < nelems; lo += INS_SORT_LIMIT) { - size_t hi = lo + INS_SORT_LIMIT; - if (hi >= nelems) - hi = nelems; - for (size_t i = lo + 1; i != hi; i++) { - for (size_t j = i; ;) { - bool lessOrEqual; - if (!c(array[j - 1], array[j], &lessOrEqual)) - return false; - if (lessOrEqual) - break; - T tmp = array[j - 1]; - array[j - 1] = array[j]; - array[j] = tmp; - if (--j == lo) - break; - } - } - } - - T *vec1 = array; - T *vec2 = scratch; - for (size_t run = INS_SORT_LIMIT; run < nelems; run *= 2) { - for (size_t lo = 0; lo < nelems; lo += 2 * run) { - size_t hi = lo + run; - if (hi >= nelems) { - detail::CopyNonEmptyArray(vec2 + lo, vec1 + lo, nelems - lo); - break; - } - size_t run2 = (run <= nelems - hi) ? run : nelems - hi; - if (!detail::MergeArrayRuns(vec2 + lo, vec1 + lo, run, run2, c)) - return false; - } - T *swap = vec1; - vec1 = vec2; - vec2 = swap; - } - if (vec1 == scratch) - detail::CopyNonEmptyArray(array, scratch, nelems); - return true; -} - -} /* namespace js */ - -#endif diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp index cfe408b705ea..64a3da7f6552 100644 --- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -131,8 +131,6 @@ #include "vm/ArgumentsObject.h" -#include "ds/Sort.h" - #include "jsarrayinlines.h" #include "jsatominlines.h" #include "jscntxtinlines.h" @@ -190,8 +188,8 @@ namespace js { * only if ToString(ToUint32(P)) is equal to P and ToUint32(P) is not equal * to 2^32-1." * - * This means the largest allowed index is actually 2^32-2 (4294967294). - * + * This means the largest allowed index is actually 2^32-2 (4294967294). + * * In our implementation, it would be sufficient to check for JSVAL_IS_INT(id) * except that by using signed 31-bit integers we miss the top half of the * valid range. This function checks the string representation itself; note @@ -209,7 +207,7 @@ StringIsArrayIndex(JSLinearString *str, jsuint *indexp) if (length == 0 || length > (sizeof("4294967294") - 1) || !JS7_ISDEC(*s)) return false; - uint32 c = 0, previous = 0; + uint32 c = 0, previous = 0; uint32 index = JS7_UNDEC(*s++); /* Don't allow leading zeros. */ @@ -226,13 +224,13 @@ StringIsArrayIndex(JSLinearString *str, jsuint *indexp) } /* Make sure we didn't overflow. */ - if (previous < (MAX_ARRAY_INDEX / 10) || (previous == (MAX_ARRAY_INDEX / 10) && + if (previous < (MAX_ARRAY_INDEX / 10) || (previous == (MAX_ARRAY_INDEX / 10) && c <= (MAX_ARRAY_INDEX % 10))) { JS_ASSERT(index <= MAX_ARRAY_INDEX); *indexp = index; return true; } - + return false; } @@ -1982,104 +1980,239 @@ array_reverse(JSContext *cx, uintN argc, Value *vp) return true; } -namespace { +typedef struct MSortArgs { + size_t elsize; + JSComparator cmp; + void *arg; + JSBool isValue; +} MSortArgs; -inline bool -CompareStringValues(JSContext *cx, const Value &a, const Value &b, bool *lessOrEqualp) +/* Helper function for js_MergeSort. */ +static JSBool +MergeArrays(MSortArgs *msa, void *src, void *dest, size_t run1, size_t run2) { - if (!JS_CHECK_OPERATION_LIMIT(cx)) - return false; + void *arg, *a, *b, *c; + size_t elsize, runtotal; + int cmp_result; + JSComparator cmp; + JSBool isValue; - JSString *astr = a.toString(); - JSString *bstr = b.toString(); - int32 result; - if (!CompareStrings(cx, astr, bstr, &result)) - return false; + runtotal = run1 + run2; - *lessOrEqualp = (result <= 0); - return true; + elsize = msa->elsize; + cmp = msa->cmp; + arg = msa->arg; + isValue = msa->isValue; + +#define CALL_CMP(a, b) \ + if (!cmp(arg, (a), (b), &cmp_result)) return JS_FALSE; + + /* Copy runs already in sorted order. */ + b = (char *)src + run1 * elsize; + a = (char *)b - elsize; + CALL_CMP(a, b); + if (cmp_result <= 0) { + memcpy(dest, src, runtotal * elsize); + return JS_TRUE; + } + +#define COPY_ONE(p,q,n) \ + (isValue ? (void)(*(Value*)p = *(Value*)q) : (void)memcpy(p, q, n)) + + a = src; + c = dest; + for (; runtotal != 0; runtotal--) { + JSBool from_a = run2 == 0; + if (!from_a && run1 != 0) { + CALL_CMP(a,b); + from_a = cmp_result <= 0; + } + + if (from_a) { + COPY_ONE(c, a, elsize); + run1--; + a = (char *)a + elsize; + } else { + COPY_ONE(c, b, elsize); + run2--; + b = (char *)b + elsize; + } + c = (char *)c + elsize; + } +#undef COPY_ONE +#undef CALL_CMP + + return JS_TRUE; } -struct SortComparatorStrings { - JSContext *const cx; - - SortComparatorStrings(JSContext *cx) - : cx(cx) {} - - bool operator()(const Value &a, const Value &b, bool *lessOrEqualp) { - return CompareStringValues(cx, a, b, lessOrEqualp); - } -}; - -struct StringValuePair { - Value str; - Value v; -}; - -struct SortComparatorStringValuePairs { - JSContext *const cx; - - SortComparatorStringValuePairs(JSContext *cx) - : cx(cx) {} - - bool operator()(const StringValuePair &a, const StringValuePair &b, bool *lessOrEqualp) { - return CompareStringValues(cx, a.str, b.str, lessOrEqualp); - } -}; - -struct SortComparatorFunction { - JSContext *const cx; - const Value &fval; - InvokeArgsGuard &ag; - - SortComparatorFunction(JSContext *cx, const Value &fval, InvokeArgsGuard &ag) - : cx(cx), fval(fval), ag(ag) { } - - bool JS_REQUIRES_STACK operator()(const Value &a, const Value &b, bool *lessOrEqualp); -}; - +/* + * This sort is stable, i.e. sequence of equal elements is preserved. + * See also bug #224128. + */ bool -SortComparatorFunction::operator()(const Value &a, const Value &b, bool *lessOrEqualp) +js_MergeSort(void *src, size_t nel, size_t elsize, + JSComparator cmp, void *arg, void *tmp, + JSMergeSortElemType elemType) { + void *swap, *vec1, *vec2; + MSortArgs msa; + size_t i, j, lo, hi, run; + int cmp_result; + + JS_ASSERT_IF(JS_SORTING_VALUES, elsize == sizeof(Value)); + bool isValue = elemType == JS_SORTING_VALUES; + + /* Avoid memcpy overhead for word-sized and word-aligned elements. */ +#define COPY_ONE(p,q,n) \ + (isValue ? (void)(*(Value*)p = *(Value*)q) : (void)memcpy(p, q, n)) +#define CALL_CMP(a, b) \ + if (!cmp(arg, (a), (b), &cmp_result)) return JS_FALSE; +#define INS_SORT_INT 4 + + /* + * Apply insertion sort to small chunks to reduce the number of merge + * passes needed. + */ + for (lo = 0; lo < nel; lo += INS_SORT_INT) { + hi = lo + INS_SORT_INT; + if (hi >= nel) + hi = nel; + for (i = lo + 1; i < hi; i++) { + vec1 = (char *)src + i * elsize; + vec2 = (char *)vec1 - elsize; + for (j = i; j > lo; j--) { + CALL_CMP(vec2, vec1); + /* "<=" instead of "<" insures the sort is stable */ + if (cmp_result <= 0) { + break; + } + + /* Swap elements, using "tmp" as tmp storage */ + COPY_ONE(tmp, vec2, elsize); + COPY_ONE(vec2, vec1, elsize); + COPY_ONE(vec1, tmp, elsize); + vec1 = vec2; + vec2 = (char *)vec1 - elsize; + } + } + } +#undef CALL_CMP +#undef COPY_ONE + + msa.elsize = elsize; + msa.cmp = cmp; + msa.arg = arg; + msa.isValue = isValue; + + vec1 = src; + vec2 = tmp; + for (run = INS_SORT_INT; run < nel; run *= 2) { + for (lo = 0; lo < nel; lo += 2 * run) { + hi = lo + run; + if (hi >= nel) { + memcpy((char *)vec2 + lo * elsize, (char *)vec1 + lo * elsize, + (nel - lo) * elsize); + break; + } + if (!MergeArrays(&msa, (char *)vec1 + lo * elsize, + (char *)vec2 + lo * elsize, run, + hi + run > nel ? nel - hi : run)) { + return JS_FALSE; + } + } + swap = vec1; + vec1 = vec2; + vec2 = swap; + } + if (src != vec1) + memcpy(src, tmp, nel * elsize); + + return JS_TRUE; +} + +struct CompareArgs +{ + JSContext *context; + InvokeArgsGuard args; + Value fval; + + CompareArgs(JSContext *cx, Value fval) + : context(cx), fval(fval) + {} +}; + +static JS_REQUIRES_STACK JSBool +sort_compare(void *arg, const void *a, const void *b, int *result) +{ + const Value *av = (const Value *)a, *bv = (const Value *)b; + CompareArgs *ca = (CompareArgs *) arg; + JSContext *cx = ca->context; + /* * array_sort deals with holes and undefs on its own and they should not * come here. */ - JS_ASSERT(!a.isMagic() && !a.isUndefined()); - JS_ASSERT(!a.isMagic() && !b.isUndefined()); + JS_ASSERT(!av->isMagic() && !av->isUndefined()); + JS_ASSERT(!av->isMagic() && !bv->isUndefined()); if (!JS_CHECK_OPERATION_LIMIT(cx)) - return false; + return JS_FALSE; + InvokeArgsGuard &ag = ca->args; if (!ag.pushed() && !cx->stack.pushInvokeArgs(cx, 2, &ag)) - return false; + return JS_FALSE; - ag.setCallee(fval); + ag.setCallee(ca->fval); ag.thisv() = UndefinedValue(); - ag[0] = a; - ag[1] = b; + ag[0] = *av; + ag[1] = *bv; if (!Invoke(cx, ag)) - return false; + return JS_FALSE; jsdouble cmp; if (!ToNumber(cx, ag.rval(), &cmp)) - return false; + return JS_FALSE; + + /* Clamp cmp to -1, 0, 1. */ + *result = 0; + if (!JSDOUBLE_IS_NaN(cmp) && cmp != 0) + *result = cmp > 0 ? 1 : -1; /* - * XXX eport some kind of error here if cmp is NaN? ECMA talks about - * 'consistent compare functions' that don't return NaN, but is silent - * about what the result should be. So we currently ignore it. + * XXX else report some kind of error here? ECMA talks about 'consistent + * compare functions' that don't return NaN, but is silent about what the + * result should be. So we currently ignore it. */ - *lessOrEqualp = (JSDOUBLE_IS_NaN(cmp) || cmp <= 0); - return true; + + return JS_TRUE; } -} /* namespace anonymous */ +typedef JSBool (JS_REQUIRES_STACK *JSRedComparator)(void*, const void*, + const void*, int *); + +static inline JS_IGNORE_STACK JSComparator +comparator_stack_cast(JSRedComparator func) +{ + return func; +} + +static int +sort_compare_strings(void *arg, const void *a, const void *b, int *result) +{ + JSContext *cx = (JSContext *)arg; + JSString *astr = ((const Value *)a)->toString(); + JSString *bstr = ((const Value *)b)->toString(); + return JS_CHECK_OPERATION_LIMIT(cx) && CompareStrings(cx, astr, bstr, result); +} JSBool js::array_sort(JSContext *cx, uintN argc, Value *vp) { + jsuint len, newlen, i, undefs; + size_t elemsize; + JSString *str; + CallArgs args = CallArgsFromVp(argc, vp); Value fval; if (args.length() > 0 && !args[0].isUndefined()) { @@ -2095,8 +2228,6 @@ js::array_sort(JSContext *cx, uintN argc, Value *vp) JSObject *obj = ToObject(cx, &args.thisv()); if (!obj) return false; - - jsuint len; if (!js_GetLengthProperty(cx, obj, &len)) return false; if (len == 0) { @@ -2126,12 +2257,23 @@ js::array_sort(JSContext *cx, uintN argc, Value *vp) * access the tail of vec corresponding to properties that do not * exist, allowing OS to avoiding committing RAM. See bug 330812. */ - size_t n, undefs; { - AutoValueVector vec(cx); - if (!vec.reserve(2 * size_t(len))) + Value *vec = (Value *) cx->malloc_(2 * size_t(len) * sizeof(Value)); + if (!vec) return false; + DEFINE_LOCAL_CLASS_OF_STATIC_FUNCTION(AutoFreeVector) { + JSContext *const cx; + Value *&vec; + public: + AutoFreeVector(JSContext *cx, Value *&vec) : cx(cx), vec(vec) { } + ~AutoFreeVector() { + cx->free_(vec); + } + } free_(cx, vec); + + AutoArrayRooter tvr(cx, 0, vec); + /* * By ECMA 262, 15.4.4.11, a property that does not exist (which we * call a "hole") is always greater than an existing property with @@ -2141,60 +2283,94 @@ js::array_sort(JSContext *cx, uintN argc, Value *vp) * undefs. */ undefs = 0; + newlen = 0; bool allStrings = true; - for (size_t i = 0; i < len; i++) { + for (i = 0; i < len; i++) { if (!JS_CHECK_OPERATION_LIMIT(cx)) return false; /* Clear vec[newlen] before including it in the rooted set. */ JSBool hole; - Value v; - if (!GetElement(cx, obj, i, &hole, &v)) + vec[newlen].setNull(); + tvr.changeLength(newlen + 1); + if (!GetElement(cx, obj, i, &hole, &vec[newlen])) return false; + if (hole) continue; - if (v.isUndefined()) { + + if (vec[newlen].isUndefined()) { ++undefs; continue; } - vec.infallibleAppend(v); - allStrings = allStrings && v.isString(); + + allStrings = allStrings && vec[newlen].isString(); + + ++newlen; } - n = vec.length(); - if (n == 0) { + if (newlen == 0) { args.rval().setObject(*obj); return true; /* The array has only holes and undefs. */ } - JS_ALWAYS_TRUE(vec.resize(n * 2)); + /* + * The first newlen elements of vec are copied from the array object + * (above). The remaining newlen positions are used as GC-rooted scratch + * space for mergesort. We must clear the space before including it to + * the root set covered by tvr.count. + */ + Value *mergesort_tmp = vec + newlen; + MakeRangeGCSafe(mergesort_tmp, newlen); + tvr.changeLength(newlen * 2); - /* Here len == 2 * (n + undefs + number_of_holes). */ + /* Here len == 2 * (newlen + undefs + number_of_holes). */ if (fval.isNull()) { /* * Sort using the default comparator converting all elements to * strings. */ if (allStrings) { - if (!MergeSort(vec.begin(), n, vec.begin() + n, SortComparatorStrings(cx))) - return false; + elemsize = sizeof(Value); } else { /* * To avoid string conversion on each compare we do it only once * prior to sorting. But we also need the space for the original - * values to recover the sorting result. For that we move the - * original values to the odd indexes in vec, put the string - * conversion results in the even indexes and do the merge sort - * over resulting string-value pairs using an extra allocated - * scratch space. + * values to recover the sorting result. To reuse + * sort_compare_strings we move the original values to the odd + * indexes in vec, put the string conversion results in the even + * indexes and pass 2 * sizeof(Value) as an element size to the + * sorting function. In this way sort_compare_strings will only + * see the string values when it casts the compare arguments as + * pointers to Value. + * + * This requires doubling the temporary storage including the + * scratch space for the merge sort. Since vec already contains + * the rooted scratch space for newlen elements at the tail, we + * can use it to rearrange and convert to strings first and try + * realloc only when we know that we successfully converted all + * the elements. */ - size_t i = n; +#if JS_BITS_PER_WORD == 32 + if (size_t(newlen) > size_t(-1) / (4 * sizeof(Value))) { + js_ReportAllocationOverflow(cx); + return false; + } +#endif + + /* + * Rearrange and string-convert the elements of the vector from + * the tail here and, after sorting, move the results back + * starting from the start to prevent overwrite the existing + * elements. + */ + i = newlen; do { --i; if (!JS_CHECK_OPERATION_LIMIT(cx)) return false; const Value &v = vec[i]; - JSString *str = js_ValueToString(cx, v); + str = js_ValueToString(cx, v); if (!str) return false; // Copying v must come first, because the following line overwrites v @@ -2203,30 +2379,40 @@ js::array_sort(JSContext *cx, uintN argc, Value *vp) vec[2 * i].setString(str); } while (i != 0); - AutoValueVector extraScratch(cx); - if (!extraScratch.resize(n * 2)) - return false; - if (!MergeSort(reinterpret_cast(vec.begin()), n, - reinterpret_cast(extraScratch.begin()), - SortComparatorStringValuePairs(cx))) { + JS_ASSERT(tvr.array == vec); + vec = (Value *) cx->realloc_(vec, 4 * size_t(newlen) * sizeof(Value)); + if (!vec) { + vec = tvr.array; /* N.B. AutoFreeVector */ return false; } - + mergesort_tmp = vec + 2 * newlen; + MakeRangeGCSafe(mergesort_tmp, 2 * newlen); + tvr.changeArray(vec, newlen * 4); + elemsize = 2 * sizeof(Value); + } + if (!js_MergeSort(vec, size_t(newlen), elemsize, + sort_compare_strings, cx, mergesort_tmp, + JS_SORTING_GENERIC)) { + return false; + } + if (!allStrings) { /* - * We want to unroot the cached results of toString calls - * before the operation callback has a chance to run the GC. - * So we do not call JS_CHECK_OPERATION_LIMIT in the loop. + * We want to make the following loop fast and to unroot the + * cached results of toString invocations before the operation + * callback has a chance to run the GC. For this reason we do + * not call JS_CHECK_OPERATION_LIMIT in the loop. */ i = 0; do { vec[i] = vec[2 * i + 1]; - } while (++i != n); + } while (++i != newlen); } } else { - InvokeArgsGuard args; - if (!MergeSort(vec.begin(), n, vec.begin() + n, - SortComparatorFunction(cx, fval, args))) - { + CompareArgs ca(cx, fval); + if (!js_MergeSort(vec, size_t(newlen), sizeof(Value), + comparator_stack_cast(sort_compare), + &ca, mergesort_tmp, + JS_SORTING_VALUES)) { return false; } } @@ -2236,20 +2422,22 @@ js::array_sort(JSContext *cx, uintN argc, Value *vp) * unroot it now to make the job of a potential GC under * InitArrayElements easier. */ - vec.resize(n); - if (!InitArrayElements(cx, obj, 0, n, vec.begin(), false)) + tvr.changeLength(newlen); + if (!InitArrayElements(cx, obj, 0, newlen, vec, false)) return false; } /* Set undefs that sorted after the rest of elements. */ while (undefs != 0) { --undefs; - if (!JS_CHECK_OPERATION_LIMIT(cx) || !SetArrayElement(cx, obj, n++, UndefinedValue())) + if (!JS_CHECK_OPERATION_LIMIT(cx) || + !SetArrayElement(cx, obj, newlen++, UndefinedValue())) { return false; + } } /* Re-create any holes that sorted to the end of the array. */ - while (len > n) { + while (len > newlen) { if (!JS_CHECK_OPERATION_LIMIT(cx) || DeleteArrayElement(cx, obj, --len, true) < 0) return false; } @@ -2398,7 +2586,7 @@ array_pop_dense(JSContext *cx, JSObject* obj, CallArgs &args) } index--; - + JSBool hole; Value elt; if (!GetElement(cx, obj, index, &hole, &elt)) @@ -3204,7 +3392,7 @@ array_readonlyCommon(JSContext *cx, CallArgs &args) args.rval() = Behavior::lateExitValue(); return true; } - + /* ES5 15.4.4.16. */ static JSBool array_every(JSContext *cx, uintN argc, Value *vp) @@ -3407,7 +3595,7 @@ class ArrayReduceRightBehavior { *start = len - 1; *step = -1; - /* + /* * We rely on (well defined) unsigned integer underflow to check our * end condition after visiting the full range (including 0). */ diff --git a/js/src/jsarray.h b/js/src/jsarray.h index c226fcbd27cb..9db642634368 100644 --- a/js/src/jsarray.h +++ b/js/src/jsarray.h @@ -178,6 +178,31 @@ GetElements(JSContext *cx, JSObject *aobj, jsuint length, js::Value *vp); } +/* + * JS-specific merge sort function. + */ +typedef JSBool (*JSComparator)(void *arg, const void *a, const void *b, + int *result); + +enum JSMergeSortElemType { + JS_SORTING_VALUES, + JS_SORTING_GENERIC +}; + +/* + * NB: vec is the array to be sorted, tmp is temporary space at least as big + * as vec. Both should be GC-rooted if appropriate. + * + * isValue should true iff vec points to an array of js::Value + * + * The sorted result is in vec. vec may be in an inconsistent state if the + * comparator function cmp returns an error inside a comparison, so remember + * to check the return value of this function. + */ +extern bool +js_MergeSort(void *vec, size_t nel, size_t elsize, JSComparator cmp, + void *arg, void *tmp, JSMergeSortElemType elemType); + /* Natives exposed for optimization by the interpreter and JITs. */ namespace js { diff --git a/js/src/jsopcode.cpp b/js/src/jsopcode.cpp index 827d24da0e68..1e88b5454052 100644 --- a/js/src/jsopcode.cpp +++ b/js/src/jsopcode.cpp @@ -69,8 +69,6 @@ #include "jsscript.h" #include "jsstr.h" -#include "ds/Sort.h" - #include "frontend/BytecodeEmitter.h" #include "frontend/TokenStream.h" #include "vm/Debugger.h" @@ -1341,19 +1339,26 @@ IsInitializerOp(unsigned char op) return op == JSOP_NEWINIT || op == JSOP_NEWARRAY || op == JSOP_NEWOBJECT; } -struct TableEntry { +typedef struct TableEntry { jsval key; ptrdiff_t offset; JSAtom *label; jsint order; /* source order for stable tableswitch sort */ -}; +} TableEntry; -inline bool -CompareTableEntries(const TableEntry &a, const TableEntry &b, bool *lessOrEqualp) +static JSBool +CompareOffsets(void *arg, const void *v1, const void *v2, int *result) { - *lessOrEqualp = (a.offset != b.offset) ? a.offset <= b.offset : a.order <= b.order; - return true; -}; + ptrdiff_t offset_diff; + const TableEntry *te1 = (const TableEntry *) v1, + *te2 = (const TableEntry *) v2; + + offset_diff = te1->offset - te2->offset; + *result = (offset_diff == 0 ? te1->order - te2->order + : offset_diff < 0 ? -1 + : 1); + return JS_TRUE; +} static ptrdiff_t SprintDoubleValue(Sprinter *sp, jsval v, JSOp *opp) @@ -4329,7 +4334,8 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb) sn = js_GetSrcNote(jp->script, pc); LOCAL_ASSERT(sn && SN_TYPE(sn) == SRC_SWITCH); len = js_GetSrcNoteOffset(sn, 0); - jmplen = (op == JSOP_TABLESWITCH) ? JUMP_OFFSET_LEN : JUMPX_OFFSET_LEN; + jmplen = (op == JSOP_TABLESWITCH) ? JUMP_OFFSET_LEN + : JUMPX_OFFSET_LEN; pc2 = pc; off = GetJumpOffset(pc, pc2); pc2 += jmplen; @@ -4342,7 +4348,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb) if (n == 0) { table = NULL; j = 0; - ok = true; + ok = JS_TRUE; } else { table = (TableEntry *) cx->malloc_((size_t)n * sizeof *table); @@ -4368,16 +4374,19 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb) cx->malloc_((size_t)j * sizeof *table); if (tmp) { VOUCH_DOES_NOT_REQUIRE_STACK(); - MergeSort(table, size_t(j), tmp, CompareTableEntries); - Foreground::free_(tmp); - ok = true; + ok = js_MergeSort(table, (size_t)j, sizeof(TableEntry), + CompareOffsets, NULL, tmp, + JS_SORTING_GENERIC); + cx->free_(tmp); } else { - ok = false; + ok = JS_FALSE; } } - if (ok) - ok = DecompileSwitch(ss, table, (uintN)j, pc, len, off, false); + if (ok) { + ok = DecompileSwitch(ss, table, (uintN)j, pc, len, off, + JS_FALSE); + } cx->free_(table); if (!ok) return NULL; From 04c9b805afac86b7f9f7040751360fba48e7afbb Mon Sep 17 00:00:00 2001 From: Igor Bukanov Date: Wed, 16 Nov 2011 15:00:32 +0100 Subject: [PATCH 15/63] Bug 701560 - template version of merge sort. r=luke This is the second attempt to land this - the previous landing attempt had compilation errors and warnings on 64 bit Linux. --- js/src/ds/Sort.h | 170 ++++++++++++++++++ js/src/jsarray.cpp | 427 +++++++++++++------------------------------- js/src/jsarray.h | 25 --- js/src/jsopcode.cpp | 41 ++--- 4 files changed, 307 insertions(+), 356 deletions(-) create mode 100644 js/src/ds/Sort.h diff --git a/js/src/ds/Sort.h b/js/src/ds/Sort.h new file mode 100644 index 000000000000..f8c3ccb6c489 --- /dev/null +++ b/js/src/ds/Sort.h @@ -0,0 +1,170 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=4 sw=4 et tw=99 ft=cpp: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is SpiderMonkey JavaScript engine. + * + * The Initial Developer of the Original Code is + * Mozilla Corporation. + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef Sort_h__ +#define Sort_h__ + +#include "jstypes.h" + +namespace js { + +namespace detail { + +template +JS_ALWAYS_INLINE void +CopyNonEmptyArray(T *dst, const T *src, size_t nelems) +{ + JS_ASSERT(nelems != 0); + const T *end = src + nelems; + do { + *dst++ = *src++; + } while (src != end); +} + +/* Helper function for MergeSort. */ +template +JS_ALWAYS_INLINE bool +MergeArrayRuns(T *dst, const T *src, size_t run1, size_t run2, Comparator c) +{ + JS_ASSERT(run1 >= 1); + JS_ASSERT(run2 >= 1); + + /* Copy runs already in sorted order. */ + const T *b = src + run1; + bool lessOrEqual; + if (!c(b[-1], b[0], &lessOrEqual)) + return false; + + if (!lessOrEqual) { + /* Runs are not already sorted, merge them. */ + for (const T *a = src;;) { + if (!c(*a, *b, &lessOrEqual)) + return false; + if (lessOrEqual) { + *dst++ = *a++; + if (!--run1) { + src = b; + break; + } + } else { + *dst++ = *b++; + if (!--run2) { + src = a; + break; + } + } + } + } + CopyNonEmptyArray(dst, src, run1 + run2); + return true; +} + +} /* namespace detail */ + +/* + * Sort the array using the merge sort algorithm. The scratch should point to + * a temporary storage that can hold nelems elements. + * + * The comparator must provide the () operator with the following signature: + * + * bool operator()(const T& a, const T& a, bool *lessOrEqualp); + * + * It should return true on success and sets lessOrEqualp to the result of + * a <= b operation. If it returns false, the sort terminates immediately with + * the false result. In this case the content of the array and scratch is + * arbitrary. + */ +template +bool +MergeSort(T *array, size_t nelems, T *scratch, Comparator c) +{ + const size_t INS_SORT_LIMIT = 3; + + if (nelems <= 1) + return true; + + /* + * Apply insertion sort to small chunks to reduce the number of merge + * passes needed. + */ + for (size_t lo = 0; lo < nelems; lo += INS_SORT_LIMIT) { + size_t hi = lo + INS_SORT_LIMIT; + if (hi >= nelems) + hi = nelems; + for (size_t i = lo + 1; i != hi; i++) { + for (size_t j = i; ;) { + bool lessOrEqual; + if (!c(array[j - 1], array[j], &lessOrEqual)) + return false; + if (lessOrEqual) + break; + T tmp = array[j - 1]; + array[j - 1] = array[j]; + array[j] = tmp; + if (--j == lo) + break; + } + } + } + + T *vec1 = array; + T *vec2 = scratch; + for (size_t run = INS_SORT_LIMIT; run < nelems; run *= 2) { + for (size_t lo = 0; lo < nelems; lo += 2 * run) { + size_t hi = lo + run; + if (hi >= nelems) { + detail::CopyNonEmptyArray(vec2 + lo, vec1 + lo, nelems - lo); + break; + } + size_t run2 = (run <= nelems - hi) ? run : nelems - hi; + if (!detail::MergeArrayRuns(vec2 + lo, vec1 + lo, run, run2, c)) + return false; + } + T *swap = vec1; + vec1 = vec2; + vec2 = swap; + } + if (vec1 == scratch) + detail::CopyNonEmptyArray(array, scratch, nelems); + return true; +} + +} /* namespace js */ + +#endif diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp index 64a3da7f6552..875a922a7327 100644 --- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -131,6 +131,8 @@ #include "vm/ArgumentsObject.h" +#include "ds/Sort.h" + #include "jsarrayinlines.h" #include "jsatominlines.h" #include "jscntxtinlines.h" @@ -188,8 +190,8 @@ namespace js { * only if ToString(ToUint32(P)) is equal to P and ToUint32(P) is not equal * to 2^32-1." * - * This means the largest allowed index is actually 2^32-2 (4294967294). - * + * This means the largest allowed index is actually 2^32-2 (4294967294). + * * In our implementation, it would be sufficient to check for JSVAL_IS_INT(id) * except that by using signed 31-bit integers we miss the top half of the * valid range. This function checks the string representation itself; note @@ -207,7 +209,7 @@ StringIsArrayIndex(JSLinearString *str, jsuint *indexp) if (length == 0 || length > (sizeof("4294967294") - 1) || !JS7_ISDEC(*s)) return false; - uint32 c = 0, previous = 0; + uint32 c = 0, previous = 0; uint32 index = JS7_UNDEC(*s++); /* Don't allow leading zeros. */ @@ -224,13 +226,13 @@ StringIsArrayIndex(JSLinearString *str, jsuint *indexp) } /* Make sure we didn't overflow. */ - if (previous < (MAX_ARRAY_INDEX / 10) || (previous == (MAX_ARRAY_INDEX / 10) && + if (previous < (MAX_ARRAY_INDEX / 10) || (previous == (MAX_ARRAY_INDEX / 10) && c <= (MAX_ARRAY_INDEX % 10))) { JS_ASSERT(index <= MAX_ARRAY_INDEX); *indexp = index; return true; } - + return false; } @@ -1980,239 +1982,104 @@ array_reverse(JSContext *cx, uintN argc, Value *vp) return true; } -typedef struct MSortArgs { - size_t elsize; - JSComparator cmp; - void *arg; - JSBool isValue; -} MSortArgs; +namespace { -/* Helper function for js_MergeSort. */ -static JSBool -MergeArrays(MSortArgs *msa, void *src, void *dest, size_t run1, size_t run2) +inline bool +CompareStringValues(JSContext *cx, const Value &a, const Value &b, bool *lessOrEqualp) { - void *arg, *a, *b, *c; - size_t elsize, runtotal; - int cmp_result; - JSComparator cmp; - JSBool isValue; + if (!JS_CHECK_OPERATION_LIMIT(cx)) + return false; - runtotal = run1 + run2; + JSString *astr = a.toString(); + JSString *bstr = b.toString(); + int32 result; + if (!CompareStrings(cx, astr, bstr, &result)) + return false; - elsize = msa->elsize; - cmp = msa->cmp; - arg = msa->arg; - isValue = msa->isValue; - -#define CALL_CMP(a, b) \ - if (!cmp(arg, (a), (b), &cmp_result)) return JS_FALSE; - - /* Copy runs already in sorted order. */ - b = (char *)src + run1 * elsize; - a = (char *)b - elsize; - CALL_CMP(a, b); - if (cmp_result <= 0) { - memcpy(dest, src, runtotal * elsize); - return JS_TRUE; - } - -#define COPY_ONE(p,q,n) \ - (isValue ? (void)(*(Value*)p = *(Value*)q) : (void)memcpy(p, q, n)) - - a = src; - c = dest; - for (; runtotal != 0; runtotal--) { - JSBool from_a = run2 == 0; - if (!from_a && run1 != 0) { - CALL_CMP(a,b); - from_a = cmp_result <= 0; - } - - if (from_a) { - COPY_ONE(c, a, elsize); - run1--; - a = (char *)a + elsize; - } else { - COPY_ONE(c, b, elsize); - run2--; - b = (char *)b + elsize; - } - c = (char *)c + elsize; - } -#undef COPY_ONE -#undef CALL_CMP - - return JS_TRUE; + *lessOrEqualp = (result <= 0); + return true; } -/* - * This sort is stable, i.e. sequence of equal elements is preserved. - * See also bug #224128. - */ -bool -js_MergeSort(void *src, size_t nel, size_t elsize, - JSComparator cmp, void *arg, void *tmp, - JSMergeSortElemType elemType) -{ - void *swap, *vec1, *vec2; - MSortArgs msa; - size_t i, j, lo, hi, run; - int cmp_result; +struct SortComparatorStrings { + JSContext *const cx; - JS_ASSERT_IF(JS_SORTING_VALUES, elsize == sizeof(Value)); - bool isValue = elemType == JS_SORTING_VALUES; + SortComparatorStrings(JSContext *cx) + : cx(cx) {} - /* Avoid memcpy overhead for word-sized and word-aligned elements. */ -#define COPY_ONE(p,q,n) \ - (isValue ? (void)(*(Value*)p = *(Value*)q) : (void)memcpy(p, q, n)) -#define CALL_CMP(a, b) \ - if (!cmp(arg, (a), (b), &cmp_result)) return JS_FALSE; -#define INS_SORT_INT 4 - - /* - * Apply insertion sort to small chunks to reduce the number of merge - * passes needed. - */ - for (lo = 0; lo < nel; lo += INS_SORT_INT) { - hi = lo + INS_SORT_INT; - if (hi >= nel) - hi = nel; - for (i = lo + 1; i < hi; i++) { - vec1 = (char *)src + i * elsize; - vec2 = (char *)vec1 - elsize; - for (j = i; j > lo; j--) { - CALL_CMP(vec2, vec1); - /* "<=" instead of "<" insures the sort is stable */ - if (cmp_result <= 0) { - break; - } - - /* Swap elements, using "tmp" as tmp storage */ - COPY_ONE(tmp, vec2, elsize); - COPY_ONE(vec2, vec1, elsize); - COPY_ONE(vec1, tmp, elsize); - vec1 = vec2; - vec2 = (char *)vec1 - elsize; - } - } + bool operator()(const Value &a, const Value &b, bool *lessOrEqualp) { + return CompareStringValues(cx, a, b, lessOrEqualp); } -#undef CALL_CMP -#undef COPY_ONE - - msa.elsize = elsize; - msa.cmp = cmp; - msa.arg = arg; - msa.isValue = isValue; - - vec1 = src; - vec2 = tmp; - for (run = INS_SORT_INT; run < nel; run *= 2) { - for (lo = 0; lo < nel; lo += 2 * run) { - hi = lo + run; - if (hi >= nel) { - memcpy((char *)vec2 + lo * elsize, (char *)vec1 + lo * elsize, - (nel - lo) * elsize); - break; - } - if (!MergeArrays(&msa, (char *)vec1 + lo * elsize, - (char *)vec2 + lo * elsize, run, - hi + run > nel ? nel - hi : run)) { - return JS_FALSE; - } - } - swap = vec1; - vec1 = vec2; - vec2 = swap; - } - if (src != vec1) - memcpy(src, tmp, nel * elsize); - - return JS_TRUE; -} - -struct CompareArgs -{ - JSContext *context; - InvokeArgsGuard args; - Value fval; - - CompareArgs(JSContext *cx, Value fval) - : context(cx), fval(fval) - {} }; -static JS_REQUIRES_STACK JSBool -sort_compare(void *arg, const void *a, const void *b, int *result) -{ - const Value *av = (const Value *)a, *bv = (const Value *)b; - CompareArgs *ca = (CompareArgs *) arg; - JSContext *cx = ca->context; +struct StringValuePair { + Value str; + Value v; +}; +struct SortComparatorStringValuePairs { + JSContext *const cx; + + SortComparatorStringValuePairs(JSContext *cx) + : cx(cx) {} + + bool operator()(const StringValuePair &a, const StringValuePair &b, bool *lessOrEqualp) { + return CompareStringValues(cx, a.str, b.str, lessOrEqualp); + } +}; + +struct SortComparatorFunction { + JSContext *const cx; + const Value &fval; + InvokeArgsGuard &ag; + + SortComparatorFunction(JSContext *cx, const Value &fval, InvokeArgsGuard &ag) + : cx(cx), fval(fval), ag(ag) { } + + bool JS_REQUIRES_STACK operator()(const Value &a, const Value &b, bool *lessOrEqualp); +}; + +bool +SortComparatorFunction::operator()(const Value &a, const Value &b, bool *lessOrEqualp) +{ /* * array_sort deals with holes and undefs on its own and they should not * come here. */ - JS_ASSERT(!av->isMagic() && !av->isUndefined()); - JS_ASSERT(!av->isMagic() && !bv->isUndefined()); + JS_ASSERT(!a.isMagic() && !a.isUndefined()); + JS_ASSERT(!a.isMagic() && !b.isUndefined()); if (!JS_CHECK_OPERATION_LIMIT(cx)) - return JS_FALSE; + return false; - InvokeArgsGuard &ag = ca->args; if (!ag.pushed() && !cx->stack.pushInvokeArgs(cx, 2, &ag)) - return JS_FALSE; - - ag.setCallee(ca->fval); + return false; + + ag.setCallee(fval); ag.thisv() = UndefinedValue(); - ag[0] = *av; - ag[1] = *bv; + ag[0] = a; + ag[1] = b; if (!Invoke(cx, ag)) - return JS_FALSE; + return false; jsdouble cmp; if (!ToNumber(cx, ag.rval(), &cmp)) - return JS_FALSE; - - /* Clamp cmp to -1, 0, 1. */ - *result = 0; - if (!JSDOUBLE_IS_NaN(cmp) && cmp != 0) - *result = cmp > 0 ? 1 : -1; + return false; /* - * XXX else report some kind of error here? ECMA talks about 'consistent - * compare functions' that don't return NaN, but is silent about what the - * result should be. So we currently ignore it. + * XXX eport some kind of error here if cmp is NaN? ECMA talks about + * 'consistent compare functions' that don't return NaN, but is silent + * about what the result should be. So we currently ignore it. */ - - return JS_TRUE; + *lessOrEqualp = (JSDOUBLE_IS_NaN(cmp) || cmp <= 0); + return true; } -typedef JSBool (JS_REQUIRES_STACK *JSRedComparator)(void*, const void*, - const void*, int *); - -static inline JS_IGNORE_STACK JSComparator -comparator_stack_cast(JSRedComparator func) -{ - return func; -} - -static int -sort_compare_strings(void *arg, const void *a, const void *b, int *result) -{ - JSContext *cx = (JSContext *)arg; - JSString *astr = ((const Value *)a)->toString(); - JSString *bstr = ((const Value *)b)->toString(); - return JS_CHECK_OPERATION_LIMIT(cx) && CompareStrings(cx, astr, bstr, result); -} +} /* namespace anonymous */ JSBool js::array_sort(JSContext *cx, uintN argc, Value *vp) { - jsuint len, newlen, i, undefs; - size_t elemsize; - JSString *str; - CallArgs args = CallArgsFromVp(argc, vp); Value fval; if (args.length() > 0 && !args[0].isUndefined()) { @@ -2228,6 +2095,8 @@ js::array_sort(JSContext *cx, uintN argc, Value *vp) JSObject *obj = ToObject(cx, &args.thisv()); if (!obj) return false; + + jsuint len; if (!js_GetLengthProperty(cx, obj, &len)) return false; if (len == 0) { @@ -2257,23 +2126,12 @@ js::array_sort(JSContext *cx, uintN argc, Value *vp) * access the tail of vec corresponding to properties that do not * exist, allowing OS to avoiding committing RAM. See bug 330812. */ + size_t n, undefs; { - Value *vec = (Value *) cx->malloc_(2 * size_t(len) * sizeof(Value)); - if (!vec) + AutoValueVector vec(cx); + if (!vec.reserve(2 * size_t(len))) return false; - DEFINE_LOCAL_CLASS_OF_STATIC_FUNCTION(AutoFreeVector) { - JSContext *const cx; - Value *&vec; - public: - AutoFreeVector(JSContext *cx, Value *&vec) : cx(cx), vec(vec) { } - ~AutoFreeVector() { - cx->free_(vec); - } - } free_(cx, vec); - - AutoArrayRooter tvr(cx, 0, vec); - /* * By ECMA 262, 15.4.4.11, a property that does not exist (which we * call a "hole") is always greater than an existing property with @@ -2283,136 +2141,95 @@ js::array_sort(JSContext *cx, uintN argc, Value *vp) * undefs. */ undefs = 0; - newlen = 0; bool allStrings = true; - for (i = 0; i < len; i++) { + for (jsuint i = 0; i < len; i++) { if (!JS_CHECK_OPERATION_LIMIT(cx)) return false; /* Clear vec[newlen] before including it in the rooted set. */ JSBool hole; - vec[newlen].setNull(); - tvr.changeLength(newlen + 1); - if (!GetElement(cx, obj, i, &hole, &vec[newlen])) + Value v; + if (!GetElement(cx, obj, i, &hole, &v)) return false; - if (hole) continue; - - if (vec[newlen].isUndefined()) { + if (v.isUndefined()) { ++undefs; continue; } - - allStrings = allStrings && vec[newlen].isString(); - - ++newlen; + vec.infallibleAppend(v); + allStrings = allStrings && v.isString(); } - if (newlen == 0) { + n = vec.length(); + if (n == 0) { args.rval().setObject(*obj); return true; /* The array has only holes and undefs. */ } - /* - * The first newlen elements of vec are copied from the array object - * (above). The remaining newlen positions are used as GC-rooted scratch - * space for mergesort. We must clear the space before including it to - * the root set covered by tvr.count. - */ - Value *mergesort_tmp = vec + newlen; - MakeRangeGCSafe(mergesort_tmp, newlen); - tvr.changeLength(newlen * 2); + JS_ALWAYS_TRUE(vec.resize(n * 2)); - /* Here len == 2 * (newlen + undefs + number_of_holes). */ + /* Here len == n + undefs + number_of_holes. */ if (fval.isNull()) { /* * Sort using the default comparator converting all elements to * strings. */ if (allStrings) { - elemsize = sizeof(Value); + if (!MergeSort(vec.begin(), n, vec.begin() + n, SortComparatorStrings(cx))) + return false; } else { /* * To avoid string conversion on each compare we do it only once * prior to sorting. But we also need the space for the original - * values to recover the sorting result. To reuse - * sort_compare_strings we move the original values to the odd - * indexes in vec, put the string conversion results in the even - * indexes and pass 2 * sizeof(Value) as an element size to the - * sorting function. In this way sort_compare_strings will only - * see the string values when it casts the compare arguments as - * pointers to Value. - * - * This requires doubling the temporary storage including the - * scratch space for the merge sort. Since vec already contains - * the rooted scratch space for newlen elements at the tail, we - * can use it to rearrange and convert to strings first and try - * realloc only when we know that we successfully converted all - * the elements. + * values to recover the sorting result. For that we move the + * original values to the odd indexes in vec, put the string + * conversion results in the even indexes and do the merge sort + * over resulting string-value pairs using an extra allocated + * scratch space. */ -#if JS_BITS_PER_WORD == 32 - if (size_t(newlen) > size_t(-1) / (4 * sizeof(Value))) { - js_ReportAllocationOverflow(cx); - return false; - } -#endif - - /* - * Rearrange and string-convert the elements of the vector from - * the tail here and, after sorting, move the results back - * starting from the start to prevent overwrite the existing - * elements. - */ - i = newlen; + size_t i = n; do { --i; if (!JS_CHECK_OPERATION_LIMIT(cx)) return false; const Value &v = vec[i]; - str = js_ValueToString(cx, v); + JSString *str = js_ValueToString(cx, v); if (!str) return false; - // Copying v must come first, because the following line overwrites v - // when i == 0. + + /* + * Copying v must come first, because the following line + * overwrites v when i == 0. + */ vec[2 * i + 1] = v; vec[2 * i].setString(str); } while (i != 0); - JS_ASSERT(tvr.array == vec); - vec = (Value *) cx->realloc_(vec, 4 * size_t(newlen) * sizeof(Value)); - if (!vec) { - vec = tvr.array; /* N.B. AutoFreeVector */ + AutoValueVector extraScratch(cx); + if (!extraScratch.resize(n * 2)) + return false; + if (!MergeSort(reinterpret_cast(vec.begin()), n, + reinterpret_cast(extraScratch.begin()), + SortComparatorStringValuePairs(cx))) { return false; } - mergesort_tmp = vec + 2 * newlen; - MakeRangeGCSafe(mergesort_tmp, 2 * newlen); - tvr.changeArray(vec, newlen * 4); - elemsize = 2 * sizeof(Value); - } - if (!js_MergeSort(vec, size_t(newlen), elemsize, - sort_compare_strings, cx, mergesort_tmp, - JS_SORTING_GENERIC)) { - return false; - } - if (!allStrings) { + /* - * We want to make the following loop fast and to unroot the - * cached results of toString invocations before the operation - * callback has a chance to run the GC. For this reason we do - * not call JS_CHECK_OPERATION_LIMIT in the loop. + * We want to unroot the cached results of toString calls + * before the operation callback has a chance to run the GC. + * So we do not call JS_CHECK_OPERATION_LIMIT in the loop. */ i = 0; do { vec[i] = vec[2 * i + 1]; - } while (++i != newlen); + } while (++i != n); } } else { - CompareArgs ca(cx, fval); - if (!js_MergeSort(vec, size_t(newlen), sizeof(Value), - comparator_stack_cast(sort_compare), - &ca, mergesort_tmp, - JS_SORTING_VALUES)) { + InvokeArgsGuard args; + if (!MergeSort(vec.begin(), n, vec.begin() + n, + SortComparatorFunction(cx, fval, args))) + { return false; } } @@ -2422,22 +2239,20 @@ js::array_sort(JSContext *cx, uintN argc, Value *vp) * unroot it now to make the job of a potential GC under * InitArrayElements easier. */ - tvr.changeLength(newlen); - if (!InitArrayElements(cx, obj, 0, newlen, vec, false)) + vec.resize(n); + if (!InitArrayElements(cx, obj, 0, jsuint(n), vec.begin(), false)) return false; } /* Set undefs that sorted after the rest of elements. */ while (undefs != 0) { --undefs; - if (!JS_CHECK_OPERATION_LIMIT(cx) || - !SetArrayElement(cx, obj, newlen++, UndefinedValue())) { + if (!JS_CHECK_OPERATION_LIMIT(cx) || !SetArrayElement(cx, obj, n++, UndefinedValue())) return false; - } } /* Re-create any holes that sorted to the end of the array. */ - while (len > newlen) { + while (len > n) { if (!JS_CHECK_OPERATION_LIMIT(cx) || DeleteArrayElement(cx, obj, --len, true) < 0) return false; } @@ -2586,7 +2401,7 @@ array_pop_dense(JSContext *cx, JSObject* obj, CallArgs &args) } index--; - + JSBool hole; Value elt; if (!GetElement(cx, obj, index, &hole, &elt)) @@ -3392,7 +3207,7 @@ array_readonlyCommon(JSContext *cx, CallArgs &args) args.rval() = Behavior::lateExitValue(); return true; } - + /* ES5 15.4.4.16. */ static JSBool array_every(JSContext *cx, uintN argc, Value *vp) @@ -3595,7 +3410,7 @@ class ArrayReduceRightBehavior { *start = len - 1; *step = -1; - /* + /* * We rely on (well defined) unsigned integer underflow to check our * end condition after visiting the full range (including 0). */ diff --git a/js/src/jsarray.h b/js/src/jsarray.h index 9db642634368..c226fcbd27cb 100644 --- a/js/src/jsarray.h +++ b/js/src/jsarray.h @@ -178,31 +178,6 @@ GetElements(JSContext *cx, JSObject *aobj, jsuint length, js::Value *vp); } -/* - * JS-specific merge sort function. - */ -typedef JSBool (*JSComparator)(void *arg, const void *a, const void *b, - int *result); - -enum JSMergeSortElemType { - JS_SORTING_VALUES, - JS_SORTING_GENERIC -}; - -/* - * NB: vec is the array to be sorted, tmp is temporary space at least as big - * as vec. Both should be GC-rooted if appropriate. - * - * isValue should true iff vec points to an array of js::Value - * - * The sorted result is in vec. vec may be in an inconsistent state if the - * comparator function cmp returns an error inside a comparison, so remember - * to check the return value of this function. - */ -extern bool -js_MergeSort(void *vec, size_t nel, size_t elsize, JSComparator cmp, - void *arg, void *tmp, JSMergeSortElemType elemType); - /* Natives exposed for optimization by the interpreter and JITs. */ namespace js { diff --git a/js/src/jsopcode.cpp b/js/src/jsopcode.cpp index 1e88b5454052..556b70612b36 100644 --- a/js/src/jsopcode.cpp +++ b/js/src/jsopcode.cpp @@ -69,6 +69,8 @@ #include "jsscript.h" #include "jsstr.h" +#include "ds/Sort.h" + #include "frontend/BytecodeEmitter.h" #include "frontend/TokenStream.h" #include "vm/Debugger.h" @@ -1339,25 +1341,18 @@ IsInitializerOp(unsigned char op) return op == JSOP_NEWINIT || op == JSOP_NEWARRAY || op == JSOP_NEWOBJECT; } -typedef struct TableEntry { +struct TableEntry { jsval key; ptrdiff_t offset; JSAtom *label; jsint order; /* source order for stable tableswitch sort */ -} TableEntry; +}; -static JSBool -CompareOffsets(void *arg, const void *v1, const void *v2, int *result) +inline bool +CompareTableEntries(const TableEntry &a, const TableEntry &b, bool *lessOrEqualp) { - ptrdiff_t offset_diff; - const TableEntry *te1 = (const TableEntry *) v1, - *te2 = (const TableEntry *) v2; - - offset_diff = te1->offset - te2->offset; - *result = (offset_diff == 0 ? te1->order - te2->order - : offset_diff < 0 ? -1 - : 1); - return JS_TRUE; + *lessOrEqualp = (a.offset != b.offset) ? a.offset <= b.offset : a.order <= b.order; + return true; } static ptrdiff_t @@ -4334,8 +4329,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb) sn = js_GetSrcNote(jp->script, pc); LOCAL_ASSERT(sn && SN_TYPE(sn) == SRC_SWITCH); len = js_GetSrcNoteOffset(sn, 0); - jmplen = (op == JSOP_TABLESWITCH) ? JUMP_OFFSET_LEN - : JUMPX_OFFSET_LEN; + jmplen = (op == JSOP_TABLESWITCH) ? JUMP_OFFSET_LEN : JUMPX_OFFSET_LEN; pc2 = pc; off = GetJumpOffset(pc, pc2); pc2 += jmplen; @@ -4348,7 +4342,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb) if (n == 0) { table = NULL; j = 0; - ok = JS_TRUE; + ok = true; } else { table = (TableEntry *) cx->malloc_((size_t)n * sizeof *table); @@ -4374,19 +4368,16 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb) cx->malloc_((size_t)j * sizeof *table); if (tmp) { VOUCH_DOES_NOT_REQUIRE_STACK(); - ok = js_MergeSort(table, (size_t)j, sizeof(TableEntry), - CompareOffsets, NULL, tmp, - JS_SORTING_GENERIC); - cx->free_(tmp); + MergeSort(table, size_t(j), tmp, CompareTableEntries); + Foreground::free_(tmp); + ok = true; } else { - ok = JS_FALSE; + ok = false; } } - if (ok) { - ok = DecompileSwitch(ss, table, (uintN)j, pc, len, off, - JS_FALSE); - } + if (ok) + ok = DecompileSwitch(ss, table, (uintN)j, pc, len, off, false); cx->free_(table); if (!ok) return NULL; From d00d22e21bedee4671c2a01a91eb59f85d2cb74c Mon Sep 17 00:00:00 2001 From: Brad Lassey Date: Thu, 17 Nov 2011 20:08:14 -0500 Subject: [PATCH 16/63] bug 702183 - Fennec 9.0b1 now asking for extra "read sensitive log data" permission r=dougt --- embedding/android/AndroidManifest.xml.in | 4 ---- 1 file changed, 4 deletions(-) diff --git a/embedding/android/AndroidManifest.xml.in b/embedding/android/AndroidManifest.xml.in index dad788ef5ec8..c762bfb75d07 100644 --- a/embedding/android/AndroidManifest.xml.in +++ b/embedding/android/AndroidManifest.xml.in @@ -18,10 +18,6 @@ - - - - From e1eb25d24a1c62b4634a56a15bc225cabfd4e425 Mon Sep 17 00:00:00 2001 From: Tatiana Meshkova Date: Wed, 9 Nov 2011 14:47:23 -0800 Subject: [PATCH 17/63] Bug 701190 - position:fixed items disappear due to wrong translation. r=roc --- layout/base/nsDisplayList.cpp | 39 ++++++++++++++--------------------- 1 file changed, 16 insertions(+), 23 deletions(-) diff --git a/layout/base/nsDisplayList.cpp b/layout/base/nsDisplayList.cpp index de169fa2e034..bc1723f95db4 100644 --- a/layout/base/nsDisplayList.cpp +++ b/layout/base/nsDisplayList.cpp @@ -138,22 +138,20 @@ static bool IsFixedFrame(nsIFrame* aFrame) return aFrame && aFrame->GetParent() && !aFrame->GetParent()->GetParent(); } -static bool IsFixedItem(nsDisplayItem *aItem, nsDisplayListBuilder* aBuilder, - bool* aIsFixedBackground) +static bool IsFixedItem(nsDisplayItem *aItem, nsDisplayListBuilder* aBuilder) { nsIFrame* activeScrolledRoot = - nsLayoutUtils::GetActiveScrolledRootFor(aItem, aBuilder, aIsFixedBackground); + nsLayoutUtils::GetActiveScrolledRootFor(aItem, aBuilder); return activeScrolledRoot && !nsLayoutUtils::ScrolledByViewportScrolling(activeScrolledRoot, aBuilder); } static bool ForceVisiblityForFixedItem(nsDisplayListBuilder* aBuilder, - nsDisplayItem* aItem, - bool* aIsFixedBackground) + nsDisplayItem* aItem) { return aBuilder->GetDisplayPort() && aBuilder->GetHasFixedItems() && - IsFixedItem(aItem, aBuilder, aIsFixedBackground); + IsFixedItem(aItem, aBuilder); } void nsDisplayListBuilder::SetDisplayPort(const nsRect& aDisplayPort) @@ -448,21 +446,18 @@ TreatAsOpaque(nsDisplayItem* aItem, nsDisplayListBuilder* aBuilder, return opaque; } -static nsRect GetDisplayPortBounds(nsDisplayListBuilder* aBuilder, - nsDisplayItem* aItem, - bool aIgnoreTransform) +static nsRect +GetDisplayPortBounds(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem) { nsIFrame* frame = aItem->GetUnderlyingFrame(); const nsRect* displayport = aBuilder->GetDisplayPort(); - if (aIgnoreTransform) { - return *displayport; - } - - return nsLayoutUtils::TransformRectToBoundsInAncestor( - frame, - nsRect(0, 0, displayport->width, displayport->height), - aBuilder->ReferenceFrame()); + nsRect result = nsLayoutUtils::TransformRectToBoundsInAncestor( + frame, + nsRect(0, 0, displayport->width, displayport->height), + aBuilder->ReferenceFrame()); + result.MoveBy(aBuilder->ToReferenceFrame(frame)); + return result; } bool @@ -507,9 +502,8 @@ nsDisplayList::ComputeVisibilityForSublist(nsDisplayListBuilder* aBuilder, nsRect bounds = item->GetBounds(aBuilder); nsRegion itemVisible; - bool isFixedBackground; - if (ForceVisiblityForFixedItem(aBuilder, item, &isFixedBackground)) { - itemVisible.And(GetDisplayPortBounds(aBuilder, item, isFixedBackground), bounds); + if (ForceVisiblityForFixedItem(aBuilder, item)) { + itemVisible.And(GetDisplayPortBounds(aBuilder, item), bounds); } else { itemVisible.And(*aVisibleRegion, bounds); } @@ -896,9 +890,8 @@ bool nsDisplayItem::RecomputeVisibility(nsDisplayListBuilder* aBuilder, nsRect bounds = GetBounds(aBuilder); nsRegion itemVisible; - bool isFixedBackground; - if (ForceVisiblityForFixedItem(aBuilder, this, &isFixedBackground)) { - itemVisible.And(GetDisplayPortBounds(aBuilder, this, isFixedBackground), bounds); + if (ForceVisiblityForFixedItem(aBuilder, this)) { + itemVisible.And(GetDisplayPortBounds(aBuilder, this), bounds); } else { itemVisible.And(*aVisibleRegion, bounds); } From a82fc659ec6a93bf6e424f3280e29ecbc29014a6 Mon Sep 17 00:00:00 2001 From: Tatiana Meshkova Date: Wed, 9 Nov 2011 11:14:43 -0800 Subject: [PATCH 18/63] Bug 701190 - position:fixed items disappear due to wrong translation. Reftest. r=roc --- layout/reftests/reftest-sanity/reftest.list | 1 + .../reftest-sanity/test-pos-fixed-transform-ref.html | 6 ++++++ .../reftests/reftest-sanity/test-pos-fixed-transform.html | 7 +++++++ 3 files changed, 14 insertions(+) create mode 100644 layout/reftests/reftest-sanity/test-pos-fixed-transform-ref.html create mode 100644 layout/reftests/reftest-sanity/test-pos-fixed-transform.html diff --git a/layout/reftests/reftest-sanity/reftest.list b/layout/reftests/reftest-sanity/reftest.list index 7830cfeee6a9..ed32a8291faa 100644 --- a/layout/reftests/reftest-sanity/reftest.list +++ b/layout/reftests/reftest-sanity/reftest.list @@ -97,6 +97,7 @@ skip-if(!browserIsRemote) == test-displayport-bg.html test-displayport-ref.html # Fixed layers are temporarily disabled (bug 656167). #== test-pos-fixed.html test-pos-fixed-ref.html == test-bg-attachment-fixed.html test-bg-attachment-fixed-ref.html +== test-pos-fixed-transform.html test-pos-fixed-transform-ref.html # reftest syntax: require-or require-or(unrecognizedCondition,skip) script scripttest-fail.html diff --git a/layout/reftests/reftest-sanity/test-pos-fixed-transform-ref.html b/layout/reftests/reftest-sanity/test-pos-fixed-transform-ref.html new file mode 100644 index 000000000000..879eadadf8e7 --- /dev/null +++ b/layout/reftests/reftest-sanity/test-pos-fixed-transform-ref.html @@ -0,0 +1,6 @@ + + + +
+ + diff --git a/layout/reftests/reftest-sanity/test-pos-fixed-transform.html b/layout/reftests/reftest-sanity/test-pos-fixed-transform.html new file mode 100644 index 000000000000..a21864729498 --- /dev/null +++ b/layout/reftests/reftest-sanity/test-pos-fixed-transform.html @@ -0,0 +1,7 @@ + + + +
+ + From ea1fe9bb3dfd96acb495f1bb7be0fe64330fe2d9 Mon Sep 17 00:00:00 2001 From: Nathan Froyd Date: Mon, 14 Nov 2011 14:51:34 -0500 Subject: [PATCH 19/63] Bug 685880 - Remove dead code from TelemetryPing.js. r=taras --- toolkit/components/telemetry/TelemetryPing.js | 50 ++----------------- 1 file changed, 4 insertions(+), 46 deletions(-) diff --git a/toolkit/components/telemetry/TelemetryPing.js b/toolkit/components/telemetry/TelemetryPing.js index cd8a30cade20..f4d3709e7d18 100644 --- a/toolkit/components/telemetry/TelemetryPing.js +++ b/toolkit/components/telemetry/TelemetryPing.js @@ -89,51 +89,6 @@ function generateUUID() { return str.substring(1, str.length - 1); } -/** - * Gets metadata about the platform the application is running on. This - * should remain consistent across multiple telemetry pings. - * - * @param reason - * The reason for the telemetry ping, this will be included in the - * returned metadata, - * @return The metadata as a JS object - */ -function getMetadata(reason) { - let ai = Services.appinfo; - let ret = { - reason: reason, - OS: ai.OS, - appID: ai.ID, - appVersion: ai.version, - appName: ai.name, - appBuildID: ai.appBuildID, - platformBuildID: ai.platformBuildID, - locale: getLocale(), - }; - - // sysinfo fields is not always available, get what we can. - let sysInfo = Cc["@mozilla.org/system-info;1"].getService(Ci.nsIPropertyBag2); - let fields = ["cpucount", "memsize", "arch", "version", "device", "manufacturer", "hardware", - "hasMMX", "hasSSE", "hasSSE2", "hasSSE3", - "hasSSSE3", "hasSSE4A", "hasSSE4_1", "hasSSE4_2", - "hasEDSP", "hasARMv6", "hasNEON"]; - for each (let field in fields) { - let value; - try { - value = sysInfo.getProperty(field); - } catch (e) { - continue - } - if (field == "memsize") { - // Send RAM size in megabytes. Rounding because sysinfo doesn't - // always provide RAM in multiples of 1024. - value = Math.round(value / 1024 / 1024) - } - ret[field] = value - } - return ret; -} - /** * Gets a series of simple measurements (counters). At the moment, this * only returns startup data from nsIAppStartup.getStartupInfo(). @@ -259,7 +214,10 @@ TelemetryPing.prototype = { // sysinfo fields are not always available, get what we can. let sysInfo = Cc["@mozilla.org/system-info;1"].getService(Ci.nsIPropertyBag2); - let fields = ["cpucount", "memsize", "arch", "version", "device", "manufacturer", "hardware"]; + let fields = ["cpucount", "memsize", "arch", "version", "device", "manufacturer", "hardware", + "hasMMX", "hasSSE", "hasSSE2", "hasSSE3", + "hasSSSE3", "hasSSE4A", "hasSSE4_1", "hasSSE4_2", + "hasEDSP", "hasARMv6", "hasNEON"]; for each (let field in fields) { let value; try { From 20971d0cc4e515392270c3998f1afe33ba8c2917 Mon Sep 17 00:00:00 2001 From: "bjarne@runitsoft.com" Date: Sat, 19 Nov 2011 12:53:57 +0100 Subject: [PATCH 20/63] Bug 528569 - Storage stream's output stream should report itself as blocking. r=biesi --- xpcom/io/nsStorageStream.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xpcom/io/nsStorageStream.cpp b/xpcom/io/nsStorageStream.cpp index d2f848e58bcb..4145d2f11d6d 100644 --- a/xpcom/io/nsStorageStream.cpp +++ b/xpcom/io/nsStorageStream.cpp @@ -238,7 +238,7 @@ nsStorageStream::WriteSegments(nsReadSegmentFun reader, void * closure, PRUint32 NS_IMETHODIMP nsStorageStream::IsNonBlocking(bool *aNonBlocking) { - *aNonBlocking = true; + *aNonBlocking = false; return NS_OK; } From e556d2cc63fc4f5e5d4dbd2906691b3d5a94f993 Mon Sep 17 00:00:00 2001 From: Atul Aggarwal Date: Wed, 16 Nov 2011 18:13:32 +0530 Subject: [PATCH 21/63] Bug 585099 - Emit adjacent consts in IDL files in the same enum in generated headers. r=ted --- xpcom/idl-parser/header.py | 48 +++++++++++++++++++++----------------- 1 file changed, 27 insertions(+), 21 deletions(-) diff --git a/xpcom/idl-parser/header.py b/xpcom/idl-parser/header.py index 2f68e5f40ceb..5dd7734fd6c5 100644 --- a/xpcom/idl-parser/header.py +++ b/xpcom/idl-parser/header.py @@ -40,7 +40,7 @@ """Print a C++ header file for the IDL files specified on the command line""" -import sys, os.path, re, xpidl +import sys, os.path, re, xpidl, itertools printdoccomments = False @@ -328,16 +328,19 @@ def write_interface(iface, fd): if iface.namemap is None: raise Exception("Interface was not resolved.") - def write_const_decl(c): - printComments(fd, c.doccomments, ' ') - - basetype = c.basetype - value = c.getValue() - - fd.write(" enum { %(name)s = %(value)s%(signed)s };\n\n" % { - 'name': c.name, - 'value': value, - 'signed': (not basetype.signed) and 'U' or ''}) + def write_const_decls(g): + fd.write(" enum {\n") + enums = [] + for c in g: + printComments(fd, c.doccomments, ' ') + basetype = c.basetype + value = c.getValue() + enums.append(" %(name)s = %(value)s%(signed)s" % { + 'name': c.name, + 'value': value, + 'signed': (not basetype.signed) and 'U' or ''}) + fd.write(",\n".join(enums)) + fd.write("\n };\n\n") def write_method_decl(m): printComments(fd, m.doccomments, ' ') @@ -395,17 +398,20 @@ def write_interface(iface, fd): if iface.base: fd.write(" : public %s" % iface.base) fd.write(iface_prolog % names) - for member in iface.members: - if isinstance(member, xpidl.ConstMember): - write_const_decl(member) - elif isinstance(member, xpidl.Attribute): - write_attr_decl(member) - elif isinstance(member, xpidl.Method): - write_method_decl(member) - elif isinstance(member, xpidl.CDATA): - fd.write(" %s" % member.data) + + for key, group in itertools.groupby(iface.members, key=type): + if key == xpidl.ConstMember: + write_const_decls(group) # iterator of all the consts else: - raise Exception("Unexpected interface member: %s" % member) + for member in group: + if key == xpidl.Attribute: + write_attr_decl(member) + elif key == xpidl.Method: + write_method_decl(member) + elif key == xpidl.CDATA: + fd.write(" %s" % member.data) + else: + raise Exception("Unexpected interface member: %s" % member) fd.write(iface_epilog % names) From bb6c49c0d1f3c882d57aa3b82f7acf12add3b275 Mon Sep 17 00:00:00 2001 From: Matt Brubeck Date: Fri, 18 Nov 2011 12:13:00 -0800 Subject: [PATCH 22/63] Bug 703661 - Add back WAKE_LOCK permission request for PowerManager [r=blassey] --- embedding/android/AndroidManifest.xml.in | 1 + 1 file changed, 1 insertion(+) diff --git a/embedding/android/AndroidManifest.xml.in b/embedding/android/AndroidManifest.xml.in index c762bfb75d07..86e28bd2cf81 100644 --- a/embedding/android/AndroidManifest.xml.in +++ b/embedding/android/AndroidManifest.xml.in @@ -18,6 +18,7 @@ + From d1caf321f43b25c02bab0facf5c68cbdadb4351d Mon Sep 17 00:00:00 2001 From: Ehsan Akhgari Date: Fri, 18 Nov 2011 16:47:40 -0500 Subject: [PATCH 23/63] Bug 682712 - Set the correct selection type when initializing the selection in editable content; r=roc --- editor/libeditor/base/nsEditor.cpp | 1 + layout/base/tests/Makefile.in | 2 ++ layout/base/tests/bug682712-1-ref.html | 25 +++++++++++++++ layout/base/tests/bug682712-1.html | 32 +++++++++++++++++++ .../base/tests/test_reftests_with_caret.html | 1 + 5 files changed, 61 insertions(+) create mode 100644 layout/base/tests/bug682712-1-ref.html create mode 100644 layout/base/tests/bug682712-1.html diff --git a/editor/libeditor/base/nsEditor.cpp b/editor/libeditor/base/nsEditor.cpp index d16a3f002ce1..068169ab85fc 100644 --- a/editor/libeditor/base/nsEditor.cpp +++ b/editor/libeditor/base/nsEditor.cpp @@ -5155,6 +5155,7 @@ nsEditor::InitializeSelection(nsIDOMEventTarget* aFocusEventTarget) // Init selection selCon->SetDisplaySelection(nsISelectionController::SELECTION_ON); + selCon->SetSelectionFlags(nsISelectionDisplay::DISPLAY_ALL); selCon->RepaintSelection(nsISelectionController::SELECTION_NORMAL); // If the computed selection root isn't root content, we should set it // as selection ancestor limit. However, if that is root element, it means diff --git a/layout/base/tests/Makefile.in b/layout/base/tests/Makefile.in index 4b58fa5097ac..68fb9ce4e9fb 100644 --- a/layout/base/tests/Makefile.in +++ b/layout/base/tests/Makefile.in @@ -157,6 +157,8 @@ _TEST_FILES = \ bug664087-1-ref.html \ bug664087-2.html \ bug664087-2-ref.html \ + bug682712-1.html \ + bug682712-1-ref.html \ test_bug514127.html \ test_bug518777.html \ test_bug548545.xhtml \ diff --git a/layout/base/tests/bug682712-1-ref.html b/layout/base/tests/bug682712-1-ref.html new file mode 100644 index 000000000000..70cd7a1da714 --- /dev/null +++ b/layout/base/tests/bug682712-1-ref.html @@ -0,0 +1,25 @@ + + + + + + + + + + diff --git a/layout/base/tests/bug682712-1.html b/layout/base/tests/bug682712-1.html new file mode 100644 index 000000000000..3d72db484e0e --- /dev/null +++ b/layout/base/tests/bug682712-1.html @@ -0,0 +1,32 @@ + + + + + + + + + + diff --git a/layout/base/tests/test_reftests_with_caret.html b/layout/base/tests/test_reftests_with_caret.html index e3b288e8ab74..650be8a73f78 100644 --- a/layout/base/tests/test_reftests_with_caret.html +++ b/layout/base/tests/test_reftests_with_caret.html @@ -137,6 +137,7 @@ if (!isWindows) { tests.push([ 'bug646382-2.html' , 'bug646382-2-ref.html' ]); // bug 680577 tests.push([ 'bug664087-1.html' , 'bug664087-1-ref.html' ]); // bug 681038 tests.push([ 'bug664087-2.html' , 'bug664087-2-ref.html' ]); // bug 680578 + tests.push([ 'bug682712-1.html' , 'bug682712-1-ref.html' ]); // disabled on Windows } tests.push(function() {SpecialPowers.clearUserPref("bidi.browser.ui");}); From b994e0854ff0915612ce2f913e03ce1022091a94 Mon Sep 17 00:00:00 2001 From: Jason Orendorff Date: Fri, 18 Nov 2011 14:58:24 -0600 Subject: [PATCH 24/63] Bug 698028 - let-binding shapes must be immutable. ("Assertion failure: !getProto()->inDictionaryMode() || getProto()->lastProp->frozen(), at ../jsobjinlines.h:302" with Debugger eval, lazily creating a Block with 129 variables.) r=jimb. --HG-- extra : rebase_source : ff7ef3dad503822d8adc7b3d8c31528fba373f48 --- js/src/frontend/Parser.cpp | 9 +++++++ js/src/jsscope.h | 10 ++++++++ js/src/jsscript.cpp | 8 +------ js/src/tests/js1_8_5/regress/jstests.list | 3 +++ .../tests/js1_8_5/regress/regress-698028-1.js | 24 +++++++++++++++++++ .../tests/js1_8_5/regress/regress-698028-2.js | 24 +++++++++++++++++++ .../tests/js1_8_5/regress/regress-698028-3.js | 15 ++++++++++++ 7 files changed, 86 insertions(+), 7 deletions(-) create mode 100644 js/src/tests/js1_8_5/regress/regress-698028-1.js create mode 100644 js/src/tests/js1_8_5/regress/regress-698028-2.js create mode 100644 js/src/tests/js1_8_5/regress/regress-698028-3.js diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index a8273cbf3b6c..84ce85d9eb58 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -1974,6 +1974,15 @@ PopStatement(TreeContext *tc) continue; tc->decls.remove(atom); } + + /* + * js_CloneBlockObject requires obj's shape to be frozen. Compare + * Bindings::makeImmutable. + * + * (This is a second pass over the shapes, if obj has a dictionary, but + * that is rare.) + */ + obj->lastProp->freezeIfDictionary(); } PopStatementTC(tc); } diff --git a/js/src/jsscope.h b/js/src/jsscope.h index b29701ebfbda..3eb13298ede6 100644 --- a/js/src/jsscope.h +++ b/js/src/jsscope.h @@ -651,6 +651,16 @@ struct Shape : public js::gc::Cell void finalize(JSContext *cx); void removeChild(js::Shape *child); + void freezeIfDictionary() { + if (inDictionary()) { + Shape *shape = this; + do { + JS_ASSERT(!shape->frozen()); + shape->setFrozen(); + } while ((shape = shape->parent) != NULL); + } + } + inline static void writeBarrierPre(const js::Shape *shape); inline static void writeBarrierPost(const js::Shape *shape, void *addr); diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp index d95b73d2723b..46e53e97bcad 100644 --- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -278,13 +278,7 @@ void Bindings::makeImmutable() { JS_ASSERT(lastBinding); - Shape *shape = lastBinding; - if (shape->inDictionary()) { - do { - JS_ASSERT(!shape->frozen()); - shape->setFrozen(); - } while ((shape = shape->parent) != NULL); - } + lastBinding->freezeIfDictionary(); } void diff --git a/js/src/tests/js1_8_5/regress/jstests.list b/js/src/tests/js1_8_5/regress/jstests.list index 0a35ee763dc9..3d20dcd1deec 100644 --- a/js/src/tests/js1_8_5/regress/jstests.list +++ b/js/src/tests/js1_8_5/regress/jstests.list @@ -116,4 +116,7 @@ script regress-673070-1.js script regress-673070-2.js script regress-673070-3.js script regress-675581.js +script regress-698028-1.js +require-or(debugMode,skip) script regress-698028-2.js +script regress-698028-3.js script regress-694306.js diff --git a/js/src/tests/js1_8_5/regress/regress-698028-1.js b/js/src/tests/js1_8_5/regress/regress-698028-1.js new file mode 100644 index 000000000000..fb1876b270de --- /dev/null +++ b/js/src/tests/js1_8_5/regress/regress-698028-1.js @@ -0,0 +1,24 @@ +// Any copyright is dedicated to the Public Domain. +// http://creativecommons.org/licenses/publicdomain/ + +{ + let x00, x01, x02, x03, x04, x05, x06, x07, x08, x09, x0a, x0b, x0c, x0d, x0e, x0f, + x10, x11, x12, x13, x14, x15, x16, x17, x18, x19, x1a, x1b, x1c, x1d, x1e, x1f, + x20, x21, x22, x23, x24, x25, x26, x27, x28, x29, x2a, x2b, x2c, x2d, x2e, x2f, + x30, x31, x32, x33, x34, x35, x36, x37, x38, x39, x3a, x3b, x3c, x3d, x3e, x3f, + x40, x41, x42, x43, x44, x45, x46, x47, x48, x49, x4a, x4b, x4c, x4d, x4e, x4f, + x50, x51, x52, x53, x54, x55, x56, x57, x58, x59, x5a, x5b, x5c, x5d, x5e, x5f, + x60, x61, x62, x63, x64, x65, x66, x67, x68, x69, x6a, x6b, x6c, x6d, x6e, x6f, + x70, x71, x72, x73, x74, x75, x76, x77, x78, x79, x7a, x7b, x7c, x7d, x7e, x7f, + x80, x81, x82, x83, x84, x85, x86, x87, x88, x89, x8a, x8b, x8c, x8d, x8e, x8f, + x90, x91, x92, x93, x94, x95, x96, x97, x98, x99, x9a, x9b, x9c, x9d, x9e, x9f, + xa0, xa1, xa2, xa3, xa4, xa5, xa6, xa7, xa8, xa9, xaa, xab, xac, xad, xae, xaf, + xb0, xb1, xb2, xb3, xb4, xb5, xb6, xb7, xb8, xb9, xba, xbb, xbc, xbd, xbe, xbf, + xc0, xc1, xc2, xc3, xc4, xc5, xc6, xc7, xc8, xc9, xca, xcb, xcc, xcd, xce, xcf, + xd0, xd1, xd2, xd3, xd4, xd5, xd6, xd7, xd8, xd9, xda, xdb, xdc, xdd, xde, xdf, + xe0, xe1, xe2, xe3, xe4, xe5, xe6, xe7, xe8, xe9, xea, xeb, xec, xed, xee, xef, + xf0, xf1, xf2, xf3, xf4, xf5, xf6, xf7, xf8, xf9, xfa, xfb, xfc, xfd, xfe, xff; + eval(""); +} + +reportCompare(0, 0, 'ok'); diff --git a/js/src/tests/js1_8_5/regress/regress-698028-2.js b/js/src/tests/js1_8_5/regress/regress-698028-2.js new file mode 100644 index 000000000000..e3918048b8a6 --- /dev/null +++ b/js/src/tests/js1_8_5/regress/regress-698028-2.js @@ -0,0 +1,24 @@ +// Any copyright is dedicated to the Public Domain. +// http://creativecommons.org/licenses/publicdomain/ + +if (typeof evalInFrame === 'function') { + let x00, x01, x02, x03, x04, x05, x06, x07, x08, x09, x0a, x0b, x0c, x0d, x0e, x0f, + x10, x11, x12, x13, x14, x15, x16, x17, x18, x19, x1a, x1b, x1c, x1d, x1e, x1f, + x20, x21, x22, x23, x24, x25, x26, x27, x28, x29, x2a, x2b, x2c, x2d, x2e, x2f, + x30, x31, x32, x33, x34, x35, x36, x37, x38, x39, x3a, x3b, x3c, x3d, x3e, x3f, + x40, x41, x42, x43, x44, x45, x46, x47, x48, x49, x4a, x4b, x4c, x4d, x4e, x4f, + x50, x51, x52, x53, x54, x55, x56, x57, x58, x59, x5a, x5b, x5c, x5d, x5e, x5f, + x60, x61, x62, x63, x64, x65, x66, x67, x68, x69, x6a, x6b, x6c, x6d, x6e, x6f, + x70, x71, x72, x73, x74, x75, x76, x77, x78, x79, x7a, x7b, x7c, x7d, x7e, x7f, + x80, x81, x82, x83, x84, x85, x86, x87, x88, x89, x8a, x8b, x8c, x8d, x8e, x8f, + x90, x91, x92, x93, x94, x95, x96, x97, x98, x99, x9a, x9b, x9c, x9d, x9e, x9f, + xa0, xa1, xa2, xa3, xa4, xa5, xa6, xa7, xa8, xa9, xaa, xab, xac, xad, xae, xaf, + xb0, xb1, xb2, xb3, xb4, xb5, xb6, xb7, xb8, xb9, xba, xbb, xbc, xbd, xbe, xbf, + xc0, xc1, xc2, xc3, xc4, xc5, xc6, xc7, xc8, xc9, xca, xcb, xcc, xcd, xce, xcf, + xd0, xd1, xd2, xd3, xd4, xd5, xd6, xd7, xd8, xd9, xda, xdb, xdc, xdd, xde, xdf, + xe0, xe1, xe2, xe3, xe4, xe5, xe6, xe7, xe8, xe9, xea, xeb, xec, xed, xee, xef, + xf0, xf1, xf2, xf3, xf4, xf5, xf6, xf7, xf8, xf9, xfa, xfb, xfc, xfd, xfe, xff; + evalInFrame(1, ""); +} + +reportCompare(0, 0, 'ok'); diff --git a/js/src/tests/js1_8_5/regress/regress-698028-3.js b/js/src/tests/js1_8_5/regress/regress-698028-3.js new file mode 100644 index 000000000000..2578e13aa653 --- /dev/null +++ b/js/src/tests/js1_8_5/regress/regress-698028-3.js @@ -0,0 +1,15 @@ +// Any copyright is dedicated to the Public Domain. +// http://creativecommons.org/licenses/publicdomain/ + +if (typeof Debugger === 'function') { + var g = newGlobal('new-compartment'); + var dbg = new Debugger(g); + dbg.onDebuggerStatement = function (frame) { frame.eval(''); }; + var s = '{ let '; + for (var i = 0; i < 128; i++) + s += 'x' + i + ', '; + s += 'X = 0; debugger; }'; + g.eval(s); +} + +reportCompare(0, 0, 'ok'); From 181b6d77323a7e295118b134325f00f1d769f37e Mon Sep 17 00:00:00 2001 From: Jason Orendorff Date: Fri, 18 Nov 2011 15:00:11 -0600 Subject: [PATCH 25/63] Bug 699682 - Only call checkForKeyword on an atom produced by a NAME token. ("Assertion failure: length != 0".) r=Waldo. --HG-- extra : rebase_source : 34cd5f85fbdd754a7164f942c608fb650274453f --- js/src/frontend/Parser.cpp | 25 +++++++--------- js/src/tests/js1_8_5/regress/jstests.list | 1 + .../tests/js1_8_5/regress/regress-699682.js | 29 +++++++++++++++++++ 3 files changed, 41 insertions(+), 14 deletions(-) create mode 100644 js/src/tests/js1_8_5/regress/regress-699682.js diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 84ce85d9eb58..423ea92fad84 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -6701,8 +6701,8 @@ Parser::primaryExpr(TokenKind tt, JSBool afterDot) for (;;) { JSAtom *atom; - tt = tokenStream.getToken(TSF_KEYWORD_IS_NAME); - switch (tt) { + TokenKind ltok = tokenStream.getToken(TSF_KEYWORD_IS_NAME); + switch (ltok) { case TOK_NUMBER: pn3 = NullaryNode::create(PNK_NUMBER, tc); if (!pn3) @@ -6788,15 +6788,9 @@ Parser::primaryExpr(TokenKind tt, JSBool afterDot) atom == context->runtime->atomState.protoAtom) { pn->pn_xflags |= PNX_NONCONST; } - } else { + } #if JS_HAS_DESTRUCTURING_SHORTHAND - if (tt != TOK_COMMA && tt != TOK_RC) { -#endif - reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_COLON_AFTER_ID); - return NULL; -#if JS_HAS_DESTRUCTURING_SHORTHAND - } - + else if (ltok == TOK_NAME && (tt == TOK_COMMA || tt == TOK_RC)) { /* * Support, e.g., |var {x, y} = o| as destructuring shorthand * for |var {x: x, y: y} = o|, per proposed JS2/ES4 for JS1.8. @@ -6806,11 +6800,14 @@ Parser::primaryExpr(TokenKind tt, JSBool afterDot) return NULL; pn->pn_xflags |= PNX_DESTRUCT | PNX_NONCONST; pnval = pn3; - if (pnval->isKind(PNK_NAME)) { - pnval->setArity(PN_NAME); - ((NameNode *)pnval)->initCommon(tc); - } + JS_ASSERT(pnval->isKind(PNK_NAME)); + pnval->setArity(PN_NAME); + ((NameNode *)pnval)->initCommon(tc); + } #endif + else { + reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_COLON_AFTER_ID); + return NULL; } pn2 = ParseNode::newBinaryOrAppend(PNK_COLON, op, pn3, pnval, tc); diff --git a/js/src/tests/js1_8_5/regress/jstests.list b/js/src/tests/js1_8_5/regress/jstests.list index 3d20dcd1deec..321a6dba8f96 100644 --- a/js/src/tests/js1_8_5/regress/jstests.list +++ b/js/src/tests/js1_8_5/regress/jstests.list @@ -120,3 +120,4 @@ script regress-698028-1.js require-or(debugMode,skip) script regress-698028-2.js script regress-698028-3.js script regress-694306.js +script regress-699682.js diff --git a/js/src/tests/js1_8_5/regress/regress-699682.js b/js/src/tests/js1_8_5/regress/regress-699682.js new file mode 100644 index 000000000000..ad1b4e41ee16 --- /dev/null +++ b/js/src/tests/js1_8_5/regress/regress-699682.js @@ -0,0 +1,29 @@ +// Any copyright is dedicated to the Public Domain. +// http://creativecommons.org/licenses/publicdomain/ + +// Don't assert trying to parse any of these. +var a = ["({''})", + "({''} = {})", + "var {''};", + "var {'', a} = {a: 0};", + "var {'bad'};", + "({'bad'} = {bad: 0});", + "var {'if'};", + "function f({''}) {}", + "function f({a, 'bad', c}) {}"]; + +var x; +for (var i = 0; i < a.length; i++) { + x = undefined; + try { + eval(a[i]); + } catch (exc) { + x = exc; + } + assertEq(x instanceof SyntaxError, true); +} +assertEq("" in this, false); +assertEq("bad" in this, false); +assertEq("if" in this, false); + +reportCompare(0, 0, 'ok'); From 1945d78d6da07f720ee8a366ffb59188cd5627c7 Mon Sep 17 00:00:00 2001 From: Ed Morley Date: Fri, 18 Nov 2011 21:59:29 +0000 Subject: [PATCH 26/63] Backout 9786b28d116e & 08b07098228a (bug 701190) for permaorange reftest on Win7; a=romaxa --- layout/base/nsDisplayList.cpp | 39 +++++++++++-------- layout/reftests/reftest-sanity/reftest.list | 1 - .../test-pos-fixed-transform-ref.html | 6 --- .../test-pos-fixed-transform.html | 7 ---- 4 files changed, 23 insertions(+), 30 deletions(-) delete mode 100644 layout/reftests/reftest-sanity/test-pos-fixed-transform-ref.html delete mode 100644 layout/reftests/reftest-sanity/test-pos-fixed-transform.html diff --git a/layout/base/nsDisplayList.cpp b/layout/base/nsDisplayList.cpp index bc1723f95db4..de169fa2e034 100644 --- a/layout/base/nsDisplayList.cpp +++ b/layout/base/nsDisplayList.cpp @@ -138,20 +138,22 @@ static bool IsFixedFrame(nsIFrame* aFrame) return aFrame && aFrame->GetParent() && !aFrame->GetParent()->GetParent(); } -static bool IsFixedItem(nsDisplayItem *aItem, nsDisplayListBuilder* aBuilder) +static bool IsFixedItem(nsDisplayItem *aItem, nsDisplayListBuilder* aBuilder, + bool* aIsFixedBackground) { nsIFrame* activeScrolledRoot = - nsLayoutUtils::GetActiveScrolledRootFor(aItem, aBuilder); + nsLayoutUtils::GetActiveScrolledRootFor(aItem, aBuilder, aIsFixedBackground); return activeScrolledRoot && !nsLayoutUtils::ScrolledByViewportScrolling(activeScrolledRoot, aBuilder); } static bool ForceVisiblityForFixedItem(nsDisplayListBuilder* aBuilder, - nsDisplayItem* aItem) + nsDisplayItem* aItem, + bool* aIsFixedBackground) { return aBuilder->GetDisplayPort() && aBuilder->GetHasFixedItems() && - IsFixedItem(aItem, aBuilder); + IsFixedItem(aItem, aBuilder, aIsFixedBackground); } void nsDisplayListBuilder::SetDisplayPort(const nsRect& aDisplayPort) @@ -446,18 +448,21 @@ TreatAsOpaque(nsDisplayItem* aItem, nsDisplayListBuilder* aBuilder, return opaque; } -static nsRect -GetDisplayPortBounds(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem) +static nsRect GetDisplayPortBounds(nsDisplayListBuilder* aBuilder, + nsDisplayItem* aItem, + bool aIgnoreTransform) { nsIFrame* frame = aItem->GetUnderlyingFrame(); const nsRect* displayport = aBuilder->GetDisplayPort(); - nsRect result = nsLayoutUtils::TransformRectToBoundsInAncestor( - frame, - nsRect(0, 0, displayport->width, displayport->height), - aBuilder->ReferenceFrame()); - result.MoveBy(aBuilder->ToReferenceFrame(frame)); - return result; + if (aIgnoreTransform) { + return *displayport; + } + + return nsLayoutUtils::TransformRectToBoundsInAncestor( + frame, + nsRect(0, 0, displayport->width, displayport->height), + aBuilder->ReferenceFrame()); } bool @@ -502,8 +507,9 @@ nsDisplayList::ComputeVisibilityForSublist(nsDisplayListBuilder* aBuilder, nsRect bounds = item->GetBounds(aBuilder); nsRegion itemVisible; - if (ForceVisiblityForFixedItem(aBuilder, item)) { - itemVisible.And(GetDisplayPortBounds(aBuilder, item), bounds); + bool isFixedBackground; + if (ForceVisiblityForFixedItem(aBuilder, item, &isFixedBackground)) { + itemVisible.And(GetDisplayPortBounds(aBuilder, item, isFixedBackground), bounds); } else { itemVisible.And(*aVisibleRegion, bounds); } @@ -890,8 +896,9 @@ bool nsDisplayItem::RecomputeVisibility(nsDisplayListBuilder* aBuilder, nsRect bounds = GetBounds(aBuilder); nsRegion itemVisible; - if (ForceVisiblityForFixedItem(aBuilder, this)) { - itemVisible.And(GetDisplayPortBounds(aBuilder, this), bounds); + bool isFixedBackground; + if (ForceVisiblityForFixedItem(aBuilder, this, &isFixedBackground)) { + itemVisible.And(GetDisplayPortBounds(aBuilder, this, isFixedBackground), bounds); } else { itemVisible.And(*aVisibleRegion, bounds); } diff --git a/layout/reftests/reftest-sanity/reftest.list b/layout/reftests/reftest-sanity/reftest.list index ed32a8291faa..7830cfeee6a9 100644 --- a/layout/reftests/reftest-sanity/reftest.list +++ b/layout/reftests/reftest-sanity/reftest.list @@ -97,7 +97,6 @@ skip-if(!browserIsRemote) == test-displayport-bg.html test-displayport-ref.html # Fixed layers are temporarily disabled (bug 656167). #== test-pos-fixed.html test-pos-fixed-ref.html == test-bg-attachment-fixed.html test-bg-attachment-fixed-ref.html -== test-pos-fixed-transform.html test-pos-fixed-transform-ref.html # reftest syntax: require-or require-or(unrecognizedCondition,skip) script scripttest-fail.html diff --git a/layout/reftests/reftest-sanity/test-pos-fixed-transform-ref.html b/layout/reftests/reftest-sanity/test-pos-fixed-transform-ref.html deleted file mode 100644 index 879eadadf8e7..000000000000 --- a/layout/reftests/reftest-sanity/test-pos-fixed-transform-ref.html +++ /dev/null @@ -1,6 +0,0 @@ - - - -
- - diff --git a/layout/reftests/reftest-sanity/test-pos-fixed-transform.html b/layout/reftests/reftest-sanity/test-pos-fixed-transform.html deleted file mode 100644 index a21864729498..000000000000 --- a/layout/reftests/reftest-sanity/test-pos-fixed-transform.html +++ /dev/null @@ -1,7 +0,0 @@ - - - -
- - From 204a335ade57eb5ae498a06c1d4bbe554325e68f Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Fri, 18 Nov 2011 14:37:51 -0800 Subject: [PATCH 27/63] Bug 702410 - mIsOpen is a Redundant Property. r=mak --- .../components/autocomplete/nsAutoCompleteController.cpp | 6 +----- toolkit/components/autocomplete/nsAutoCompleteController.h | 1 - 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/toolkit/components/autocomplete/nsAutoCompleteController.cpp b/toolkit/components/autocomplete/nsAutoCompleteController.cpp index f98f4249744f..d5412c42de8e 100644 --- a/toolkit/components/autocomplete/nsAutoCompleteController.cpp +++ b/toolkit/components/autocomplete/nsAutoCompleteController.cpp @@ -81,7 +81,6 @@ nsAutoCompleteController::nsAutoCompleteController() : mPopupClosedByCompositionStart(false), mIsIMEComposing(false), mIgnoreHandleText(false), - mIsOpen(false), mSearchStatus(nsAutoCompleteController::STATUS_NONE), mRowCount(0), mSearchesOngoing(0), @@ -131,8 +130,7 @@ nsAutoCompleteController::SetInput(nsIAutoCompleteInput *aInput) // Stop all searches in case they are async. StopSearch(); ClearResults(); - if (mIsOpen) - ClosePopup(); + ClosePopup(); mSearches.Clear(); } @@ -972,7 +970,6 @@ nsAutoCompleteController::OpenPopup() mInput->GetMinResultsForPopup(&minResults); if (mRowCount >= minResults) { - mIsOpen = true; return mInput->SetPopupOpen(true); } @@ -995,7 +992,6 @@ nsAutoCompleteController::ClosePopup() mInput->GetPopup(getter_AddRefs(popup)); NS_ENSURE_TRUE(popup != nsnull, NS_ERROR_FAILURE); popup->SetSelectedIndex(-1); - mIsOpen = false; return mInput->SetPopupOpen(false); } diff --git a/toolkit/components/autocomplete/nsAutoCompleteController.h b/toolkit/components/autocomplete/nsAutoCompleteController.h index a364aa2350a3..5a94b109f897 100644 --- a/toolkit/components/autocomplete/nsAutoCompleteController.h +++ b/toolkit/components/autocomplete/nsAutoCompleteController.h @@ -123,7 +123,6 @@ protected: bool mPopupClosedByCompositionStart; bool mIsIMEComposing; bool mIgnoreHandleText; - bool mIsOpen; PRUint16 mSearchStatus; PRUint32 mRowCount; PRUint32 mSearchesOngoing; From a43c1947598dc7e7c38cce6e34512103fe079e1c Mon Sep 17 00:00:00 2001 From: Bill McCloskey Date: Fri, 18 Nov 2011 14:59:04 -0800 Subject: [PATCH 28/63] Bug 702915 - Fix write barrier verification during array slowification (r=bhackett) --- js/src/jscntxt.h | 10 +--------- js/src/jsgc.cpp | 25 +++++++++++++++++++++++-- 2 files changed, 24 insertions(+), 11 deletions(-) diff --git a/js/src/jscntxt.h b/js/src/jscntxt.h index f91e02499e9d..f7072fd60b8a 100644 --- a/js/src/jscntxt.h +++ b/js/src/jscntxt.h @@ -1451,15 +1451,7 @@ class AutoGCRooter { /* Implemented in jsgc.cpp. */ inline void trace(JSTracer *trc); - -#ifdef __GNUC__ -# pragma GCC visibility push(default) -#endif - friend JS_FRIEND_API(void) MarkContext(JSTracer *trc, JSContext *acx); - friend void MarkRuntime(JSTracer *trc); -#ifdef __GNUC__ -# pragma GCC visibility pop -#endif + void traceAll(JSTracer *trc); protected: AutoGCRooter * const down; diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index 723a78a127d1..b1e3a53fc42a 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -2005,6 +2005,13 @@ AutoGCRooter::trace(JSTracer *trc) "js::AutoArrayRooter.array"); } +void +AutoGCRooter::traceAll(JSTracer *trc) +{ + for (js::AutoGCRooter *gcr = this; gcr; gcr = gcr->down) + gcr->trace(trc); +} + namespace js { JS_FRIEND_API(void) @@ -2018,8 +2025,8 @@ MarkContext(JSTracer *trc, JSContext *acx) if (acx->isExceptionPending()) MarkRoot(trc, acx->getPendingException(), "exception"); - for (js::AutoGCRooter *gcr = acx->autoGCRooters; gcr; gcr = gcr->down) - gcr->trace(trc); + if (acx->autoGCRooters) + acx->autoGCRooters->traceAll(trc); if (acx->sharpObjectMap.depth > 0) js_TraceSharpMap(trc, &acx->sharpObjectMap); @@ -3480,6 +3487,12 @@ oom: js_free(trc); } +static void +CheckAutorooter(JSTracer *jstrc, void *thing, JSGCTraceKind kind) +{ + static_cast(thing)->markIfUnmarked(); +} + /* * This function is called by EndVerifyBarriers for every heap edge. If the edge * already existed in the original snapshot, we "cancel it out" by overwriting @@ -3537,6 +3550,14 @@ EndVerifyBarriers(JSContext *cx) (*c)->needsBarrier_ = false; } + JS_TRACER_INIT(trc, cx, CheckAutorooter); + + JSContext *iter = NULL; + while (JSContext *acx = js_ContextIterator(rt, JS_TRUE, &iter)) { + if (acx->autoGCRooters) + acx->autoGCRooters->traceAll(trc); + } + JS_TRACER_INIT(trc, cx, CheckEdge); /* Start after the roots. */ From 2ffe276379753f4a844b964c52af8f0405e37b5f Mon Sep 17 00:00:00 2001 From: Bill McCloskey Date: Fri, 18 Nov 2011 14:59:11 -0800 Subject: [PATCH 29/63] Bug 702502 - Use an iterator to iterate over compartments (r=igor) --- js/src/jscntxt.cpp | 12 +++------ js/src/jscompartment.h | 26 ++++++++++++++++++ js/src/jsgc.cpp | 55 +++++++++++++++++++-------------------- js/src/jspropertytree.cpp | 8 +++--- js/src/jswatchpoint.cpp | 10 +++---- 5 files changed, 66 insertions(+), 45 deletions(-) diff --git a/js/src/jscntxt.cpp b/js/src/jscntxt.cpp index ac3a1ed2d112..57820d666c70 100644 --- a/js/src/jscntxt.cpp +++ b/js/src/jscntxt.cpp @@ -585,20 +585,16 @@ js_DestroyContext(JSContext *cx, JSDestroyContextMode mode) */ { AutoLockGC lock(rt); - JSCompartment **compartment = rt->compartments.begin(); - JSCompartment **end = rt->compartments.end(); - while (compartment < end) { - (*compartment)->types.print(cx, false); - compartment++; - } + for (CompartmentsIter c(rt); !c.done(); c.next()) + c->types.print(cx, false); } /* Unpin all common atoms before final GC. */ js_FinishCommonAtoms(cx); /* Clear debugging state to remove GC roots. */ - for (JSCompartment **c = rt->compartments.begin(); c != rt->compartments.end(); c++) - (*c)->clearTraps(cx, NULL); + for (CompartmentsIter c(rt); !c.done(); c.next()) + c->clearTraps(cx, NULL); JS_ClearAllWatchPoints(cx); } diff --git a/js/src/jscompartment.h b/js/src/jscompartment.h index 66aaa96aad58..397e9ae51bfe 100644 --- a/js/src/jscompartment.h +++ b/js/src/jscompartment.h @@ -833,6 +833,32 @@ class ErrorCopier ~ErrorCopier(); }; +class CompartmentsIter { + private: + JSCompartment **it, **end; + + public: + CompartmentsIter(JSRuntime *rt) { + it = rt->compartments.begin(); + end = rt->compartments.end(); + } + + bool done() const { return it == end; } + + void next() { + JS_ASSERT(!done()); + it++; + } + + JSCompartment *get() const { + JS_ASSERT(!done()); + return *it; + } + + operator JSCompartment *() const { return get(); } + JSCompartment *operator->() const { return get(); } +}; + } /* namespace js */ #endif /* jscompartment_h___ */ diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index b1e3a53fc42a..8858acc6d4cf 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -1143,8 +1143,8 @@ void js_FinishGC(JSRuntime *rt) { /* Delete all remaining Compartments. */ - for (JSCompartment **c = rt->compartments.begin(); c != rt->compartments.end(); ++c) - Foreground::delete_(*c); + for (CompartmentsIter c(rt); !c.done(); c.next()) + Foreground::delete_(c.get()); rt->compartments.clear(); rt->atomsCompartment = NULL; @@ -2506,8 +2506,8 @@ BeginMarkPhase(JSContext *cx, GCMarker *gcmarker, JSGCInvocationKind gckind) r.front()->bitmap.clear(); if (rt->gcCurrentCompartment) { - for (JSCompartment **c = rt->compartments.begin(); c != rt->compartments.end(); ++c) - (*c)->markCrossCompartmentWrappers(gcmarker); + for (CompartmentsIter c(rt); !c.done(); c.next()) + c->markCrossCompartmentWrappers(gcmarker); Debugger::markCrossCompartmentDebuggerObjectReferents(gcmarker); } @@ -2545,9 +2545,9 @@ EndMarkPhase(JSContext *cx, GCMarker *gcmarker, JSGCInvocationKind gckind) #ifdef DEBUG /* Make sure that we didn't mark an object in another compartment */ if (rt->gcCurrentCompartment) { - for (JSCompartment **c = rt->compartments.begin(); c != rt->compartments.end(); ++c) { - JS_ASSERT_IF(*c != rt->gcCurrentCompartment && *c != rt->atomsCompartment, - (*c)->arenas.checkArenaListAllUnmarked()); + for (CompartmentsIter c(rt); !c.done(); c.next()) { + JS_ASSERT_IF(c != rt->gcCurrentCompartment && c != rt->atomsCompartment, + c->arenas.checkArenaListAllUnmarked()); } } #endif @@ -2956,8 +2956,8 @@ GCCycle(JSContext *cx, JSCompartment *comp, JSGCInvocationKind gckind) rt->gcCurrentCompartment = NULL; rt->gcWeakMapList = NULL; - for (JSCompartment **c = rt->compartments.begin(); c != rt->compartments.end(); ++c) - (*c)->setGCLastBytes((*c)->gcBytes, gckind); + for (CompartmentsIter c(rt); !c.done(); c.next()) + c->setGCLastBytes(c->gcBytes, gckind); } void @@ -3037,13 +3037,13 @@ class AutoCopyFreeListToArenas { public: AutoCopyFreeListToArenas(JSRuntime *rt) : rt(rt) { - for (JSCompartment **c = rt->compartments.begin(); c != rt->compartments.end(); ++c) - (*c)->arenas.copyFreeListsToArenas(); + for (CompartmentsIter c(rt); !c.done(); c.next()) + c->arenas.copyFreeListsToArenas(); } ~AutoCopyFreeListToArenas() { - for (JSCompartment **c = rt->compartments.begin(); c != rt->compartments.end(); ++c) - (*c)->arenas.clearFreeListsInArenas(); + for (CompartmentsIter c(rt); !c.done(); c.next()) + c->arenas.clearFreeListsInArenas(); } }; @@ -3130,16 +3130,15 @@ IterateCompartmentsArenasCells(JSContext *cx, void *data, AutoUnlockGC unlock(rt); AutoCopyFreeListToArenas copy(rt); - for (JSCompartment **c = rt->compartments.begin(); c != rt->compartments.end(); ++c) { - JSCompartment *compartment = *c; - (*compartmentCallback)(cx, data, compartment); + for (CompartmentsIter c(rt); !c.done(); c.next()) { + (*compartmentCallback)(cx, data, c); for (size_t thingKind = 0; thingKind != FINALIZE_LIMIT; thingKind++) { JSGCTraceKind traceKind = MapAllocToTraceKind(AllocKind(thingKind)); size_t thingSize = Arena::thingSize(AllocKind(thingKind)); IterateArenaCallbackOp arenaOp(cx, data, arenaCallback, traceKind, thingSize); IterateCellCallbackOp cellOp(cx, data, cellCallback, traceKind, thingSize); - ForEachArenaAndCell(compartment, AllocKind(thingKind), arenaOp, cellOp); + ForEachArenaAndCell(c, AllocKind(thingKind), arenaOp, cellOp); } } } @@ -3193,8 +3192,8 @@ IterateCells(JSContext *cx, JSCompartment *compartment, AllocKind thingKind, for (CellIterUnderGC i(compartment, thingKind); !i.done(); i.next()) cellCallback(cx, data, i.getCell(), traceKind, thingSize); } else { - for (JSCompartment **c = rt->compartments.begin(); c != rt->compartments.end(); ++c) { - for (CellIterUnderGC i(*c, thingKind); !i.done(); i.next()) + for (CompartmentsIter c(rt); !c.done(); c.next()) { + for (CellIterUnderGC i(c, thingKind); !i.done(); i.next()) cellCallback(cx, data, i.getCell(), traceKind, thingSize); } } @@ -3413,10 +3412,10 @@ StartVerifyBarriers(JSContext *cx) * code in the compartment. */ #ifdef JS_METHODJIT - for (JSCompartment **c = rt->compartments.begin(); c != rt->compartments.end(); ++c) { - mjit::ClearAllFrames(*c); + for (CompartmentsIter c(rt); !c.done(); c.next()) { + mjit::ClearAllFrames(c); - for (CellIterUnderGC i(*c, FINALIZE_SCRIPT); !i.done(); i.next()) { + for (CellIterUnderGC i(c, FINALIZE_SCRIPT); !i.done(); i.next()) { JSScript *script = i.get(); mjit::ReleaseScriptCode(cx, script); @@ -3474,9 +3473,9 @@ StartVerifyBarriers(JSContext *cx) rt->gcVerifyData = trc; rt->gcIncrementalTracer = &trc->gcmarker; - for (JSCompartment **c = rt->compartments.begin(); c != rt->compartments.end(); ++c) { - (*c)->gcIncrementalTracer = &trc->gcmarker; - (*c)->needsBarrier_ = true; + for (CompartmentsIter c(rt); !c.done(); c.next()) { + c->gcIncrementalTracer = &trc->gcmarker; + c->needsBarrier_ = true; } return; @@ -3545,9 +3544,9 @@ EndVerifyBarriers(JSContext *cx) rt->gcVerifyData = NULL; rt->gcIncrementalTracer = NULL; - for (JSCompartment **c = rt->compartments.begin(); c != rt->compartments.end(); ++c) { - (*c)->gcIncrementalTracer = NULL; - (*c)->needsBarrier_ = false; + for (CompartmentsIter c(rt); !c.done(); c.next()) { + c->gcIncrementalTracer = NULL; + c->needsBarrier_ = false; } JS_TRACER_INIT(trc, cx, CheckAutorooter); diff --git a/js/src/jspropertytree.cpp b/js/src/jspropertytree.cpp index bec0df458083..14bb3f8cd6e6 100644 --- a/js/src/jspropertytree.cpp +++ b/js/src/jspropertytree.cpp @@ -351,14 +351,14 @@ js::PropertyTree::dumpShapes(JSContext *cx) JSRuntime *rt = cx->runtime; fprintf(dumpfp, "rt->gcNumber = %lu", (unsigned long)rt->gcNumber); - for (JSCompartment **c = rt->compartments.begin(); c != rt->compartments.end(); ++c) { - if (rt->gcCurrentCompartment != NULL && rt->gcCurrentCompartment != *c) + for (CompartmentsIter c(rt); !c.done(); c.next()) { + if (rt->gcCurrentCompartment != NULL && rt->gcCurrentCompartment != c) continue; - fprintf(dumpfp, "*** Compartment %p ***\n", (void *)*c); + fprintf(dumpfp, "*** Compartment %p ***\n", (void *)c.get()); typedef JSCompartment::EmptyShapeSet HS; - HS &h = (*c)->emptyShapes; + HS &h = c->emptyShapes; for (HS::Range r = h.all(); !r.empty(); r.popFront()) { Shape *empty = r.front(); empty->dumpSubtree(cx, 0, dumpfp); diff --git a/js/src/jswatchpoint.cpp b/js/src/jswatchpoint.cpp index d7e54a1f0038..ce719b4f09b2 100644 --- a/js/src/jswatchpoint.cpp +++ b/js/src/jswatchpoint.cpp @@ -184,9 +184,9 @@ WatchpointMap::markAllIteratively(JSTracer *trc) } bool mutated = false; - for (JSCompartment **c = rt->compartments.begin(); c != rt->compartments.end(); ++c) { - if ((*c)->watchpointMap) - mutated |= (*c)->watchpointMap->markIteratively(trc); + for (CompartmentsIter c(rt); !c.done(); c.next()) { + if (c->watchpointMap) + mutated |= c->watchpointMap->markIteratively(trc); } return mutated; } @@ -226,8 +226,8 @@ WatchpointMap::sweepAll(JSContext *cx) if (WatchpointMap *wpmap = rt->gcCurrentCompartment->watchpointMap) wpmap->sweep(cx); } else { - for (JSCompartment **c = rt->compartments.begin(); c != rt->compartments.end(); ++c) { - if (WatchpointMap *wpmap = (*c)->watchpointMap) + for (CompartmentsIter c(rt); !c.done(); c.next()) { + if (WatchpointMap *wpmap = c->watchpointMap) wpmap->sweep(cx); } } From 0cec9a62ce9a99c275705a4bf01ff780ffcb3209 Mon Sep 17 00:00:00 2001 From: Bill McCloskey Date: Fri, 18 Nov 2011 14:59:18 -0800 Subject: [PATCH 30/63] Bug 699668 - Increase JS type arena size to 128K (r=njn) --- js/src/jscompartment.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/src/jscompartment.h b/js/src/jscompartment.h index 397e9ae51bfe..ae13d3aeaa52 100644 --- a/js/src/jscompartment.h +++ b/js/src/jscompartment.h @@ -420,7 +420,7 @@ struct JS_FRIEND_API(JSCompartment) { * Cleared on every GC, unless the GC happens during analysis (indicated * by activeAnalysis, which is implied by activeInference). */ - static const size_t TYPE_LIFO_ALLOC_PRIMARY_CHUNK_SIZE = 4 * 1024; + static const size_t TYPE_LIFO_ALLOC_PRIMARY_CHUNK_SIZE = 128 * 1024; js::LifoAlloc typeLifoAlloc; bool activeAnalysis; bool activeInference; From fe2af34e516505828eb953b78eec48d87bd0eb5c Mon Sep 17 00:00:00 2001 From: Bill McCloskey Date: Fri, 18 Nov 2011 17:43:00 -0800 Subject: [PATCH 31/63] Bug 703544 - Fix register allocation bug in dense array write barrier (r=bhackett) --- js/src/jit-test/tests/basic/bug703544.js | 7 +++++++ js/src/methodjit/FastOps.cpp | 15 ++++++++++++++- 2 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 js/src/jit-test/tests/basic/bug703544.js diff --git a/js/src/jit-test/tests/basic/bug703544.js b/js/src/jit-test/tests/basic/bug703544.js new file mode 100644 index 000000000000..87d1a1b0d0b0 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug703544.js @@ -0,0 +1,7 @@ +gczeal(4); +function testInterpreterReentry7() { + var arr = [0, 1, 2, 3, 4]; + for (var i = (1); i < 5; i++) + arr[i] = "grue"; +} +testInterpreterReentry7(); diff --git a/js/src/methodjit/FastOps.cpp b/js/src/methodjit/FastOps.cpp index 92b83404e899..ddcecdbafb29 100644 --- a/js/src/methodjit/FastOps.cpp +++ b/js/src/methodjit/FastOps.cpp @@ -1180,9 +1180,22 @@ mjit::Compiler::jsop_setelem_dense() types::TypeSet *types = frame.extra(obj).types; if (cx->compartment->needsBarrier() && (!types || types->propertyNeedsBarrier(cx, JSID_VOID))) { Label barrierStart = stubcc.masm.label(); - frame.sync(stubcc.masm, Uses(3)); stubcc.linkExitDirect(masm.jump(), barrierStart); + + /* + * The sync call below can potentially clobber key.reg() and slotsReg. + * So we save and restore them. Additionally, the WriteBarrier stub can + * clobber both registers. The rejoin call will restore key.reg() but + * not slotsReg. So we restore it again after the stub call. + */ stubcc.masm.storePtr(slotsReg, FrameAddress(offsetof(VMFrame, scratch))); + if (!key.isConstant()) + stubcc.masm.push(key.reg()); + frame.sync(stubcc.masm, Uses(3)); + if (!key.isConstant()) + stubcc.masm.pop(key.reg()); + stubcc.masm.loadPtr(FrameAddress(offsetof(VMFrame, scratch)), slotsReg); + if (key.isConstant()) stubcc.masm.lea(Address(slotsReg, key.index() * sizeof(Value)), Registers::ArgReg1); else From e980cd896963802bccd80d07e7d3a2927add6d67 Mon Sep 17 00:00:00 2001 From: Phil Ringnalda Date: Thu, 17 Nov 2011 20:24:25 -0800 Subject: [PATCH 32/63] Bug 696670, bug 696671, bug 696672, bug 696673, bug 696674, bug 703201 - annotate failing tests in Win7 reftest-no-accel --- layout/reftests/abs-pos/reftest.list | 2 +- layout/reftests/bidi/reftest.list | 12 ++++++------ layout/reftests/svg/reftest.list | 8 ++++---- parser/htmlparser/tests/reftest/reftest.list | 2 +- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/layout/reftests/abs-pos/reftest.list b/layout/reftests/abs-pos/reftest.list index 2c9054fde5c9..4795848faf94 100644 --- a/layout/reftests/abs-pos/reftest.list +++ b/layout/reftests/abs-pos/reftest.list @@ -1,6 +1,6 @@ == font-size-wrap.html font-size-wrap-ref.html == abs-pos-auto-margin-1.html abs-pos-auto-margin-1-ref.html -== auto-offset-inline-block-1.html auto-offset-inline-block-1-ref.html +fails-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)&&!layersGPUAccelerated) == auto-offset-inline-block-1.html auto-offset-inline-block-1-ref.html # bug 696670 == fieldset-1.html fieldset-1-ref.html == table-1.html table-1-ref.html == table-2.html table-2-ref.html diff --git a/layout/reftests/bidi/reftest.list b/layout/reftests/bidi/reftest.list index 19e9aaeafcbd..3b12d30cdfc6 100644 --- a/layout/reftests/bidi/reftest.list +++ b/layout/reftests/bidi/reftest.list @@ -39,9 +39,9 @@ random-if(cocoaWidget) == mirroring-02.html mirroring-02-ref.html == 83958-1a.html 83958-1-ref.html == 83958-1b.html 83958-1-ref.html == 83958-1c.html 83958-1-ref.html -== 83958-2a.html 83958-2-ref.html -== 83958-2b.html 83958-2-ref.html -== 83958-2c.html 83958-2-ref.html +fails-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)&&!layersGPUAccelerated) == 83958-2a.html 83958-2-ref.html # bug 696671 +fails-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)&&!layersGPUAccelerated) == 83958-2b.html 83958-2-ref.html # bug 696671 +fails-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)&&!layersGPUAccelerated) == 83958-2c.html 83958-2-ref.html # bug 696671 == 115921-1.html 115921-1-ref.html == 115921-2.html 115921-2-ref.html == 229367-1.html 229367-1-ref.html @@ -83,10 +83,10 @@ random-if(winWidget) == 305643-1.html 305643-1-ref.html # depends on windows ver == 612843-1.html 612843-1-ref.html == 613149-1a.html 613149-1-ref.html == 613149-1b.html 613149-1-ref.html -== 613149-2a.html 613149-2-ref.html -== 613149-2b.html 613149-2-ref.html +fails-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)&&!layersGPUAccelerated) == 613149-2a.html 613149-2-ref.html # bug 696672 +fails-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)&&!layersGPUAccelerated) == 613149-2b.html 613149-2-ref.html # bug 696672 == 613157-1.html 613157-1-ref.html -== 613157-2.html 613157-2-ref.html +fails-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)&&!layersGPUAccelerated) == 613157-2.html 613157-2-ref.html # bug 696673 == 662288-1.html 662288-1-ref.html == 670226-1.html 670226-1-ref.html == 698706-1.html 698706-1-ref.html diff --git a/layout/reftests/svg/reftest.list b/layout/reftests/svg/reftest.list index eaef9f262f80..9c3610ca92e2 100644 --- a/layout/reftests/svg/reftest.list +++ b/layout/reftests/svg/reftest.list @@ -136,10 +136,10 @@ fails-if(Android) == filter-extref-differentOrigin-01.svg pass.svg # Bug 695385 == foreignObject-img-form-theme.html foreignObject-img-form-theme-ref.html == foreignObject-form-theme.svg foreignObject-form-theme-ref.html == getElementById-a-element-01.svg pass.svg -== gradient-live-01a.svg gradient-live-01-ref.svg -== gradient-live-01b.svg gradient-live-01-ref.svg -== gradient-live-01c.svg gradient-live-01-ref.svg -== gradient-live-01d.svg gradient-live-01-ref.svg +fails-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)&&!layersGPUAccelerated) == gradient-live-01a.svg gradient-live-01-ref.svg # bug 696674 +fails-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)&&!layersGPUAccelerated) == gradient-live-01b.svg gradient-live-01-ref.svg # bug 696674 +fails-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)&&!layersGPUAccelerated) == gradient-live-01c.svg gradient-live-01-ref.svg # bug 696674 +fails-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)&&!layersGPUAccelerated) == gradient-live-01d.svg gradient-live-01-ref.svg # bug 696674 fails == inline-in-xul-basic-01.xul pass.svg == invalid-text-01.svg pass.svg == linearGradient-basic-01.svg pass.svg diff --git a/parser/htmlparser/tests/reftest/reftest.list b/parser/htmlparser/tests/reftest/reftest.list index 01211aeb9299..664131c421fe 100644 --- a/parser/htmlparser/tests/reftest/reftest.list +++ b/parser/htmlparser/tests/reftest/reftest.list @@ -4,7 +4,7 @@ == bug582940-1.html bug582940-1-ref.html == bug592656-1.html bug592656-1-ref.html == bug608373-1.html bug608373-1-ref.html -== view-source:bug482921-1.html bug482921-1-ref.html +fails-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)&&!layersGPUAccelerated) == view-source:bug482921-1.html bug482921-1-ref.html # bug 703201 == view-source:bug482921-2.xhtml bug482921-2-ref.html == bug659763-1.html bug659763-1-ref.html == bug659763-2.html bug659763-2-ref.html From 981852a1882f855ab9de8e30e88601c4e9787c6d Mon Sep 17 00:00:00 2001 From: Alex Keybl Date: Sat, 19 Nov 2011 03:33:30 -0500 Subject: [PATCH 33/63] Bug 699134, block Roboform <= ver 7.6.1, r=jonas a=akeybl CLOSED TREE --HG-- extra : transplant_source : %E5%D3mu%E2%5B%1F%C2%93%5E%23%C4%CB%9B%8B.%25%3E3%CC --- toolkit/xre/nsWindowsDllBlocklist.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/toolkit/xre/nsWindowsDllBlocklist.cpp b/toolkit/xre/nsWindowsDllBlocklist.cpp index aec54835bf48..f6cfe62bd965 100644 --- a/toolkit/xre/nsWindowsDllBlocklist.cpp +++ b/toolkit/xre/nsWindowsDllBlocklist.cpp @@ -129,7 +129,11 @@ static DllBlockInfo sWindowsDllBlocklist[] = { // Topcrash in Firefox 4 betas (bug 618899) {"accelerator.dll", MAKE_VERSION(3,2,1,6)}, - + + // Topcrash with Roboform in Firefox 8 (bug 699134) + {"rf-firefox.dll", MAKE_VERSION(7,6,1,0)}, + {"roboform.dll", MAKE_VERSION(7,6,1,0)}, + // leave these two in always for tests { "mozdllblockingtest.dll", ALL_VERSIONS }, { "mozdllblockingtest_versioned.dll", 0x0000000400000000ULL }, From a8e21c3f88b8d1ea1c843110b950c2d9c412fd1b Mon Sep 17 00:00:00 2001 From: Benjamin Smedberg Date: Fri, 18 Nov 2011 18:26:00 -0500 Subject: [PATCH 34/63] Bug 699134 - Protect against reentrancy in the LdrLoadDll hook, with less XPCOM stringery and more locking. a=bsmedberg ON A CLOSED TREE --HG-- extra : transplant_source : %9E%CE%8C%9C%FE%BEz%14%60%D7%84%3A%D1%05%16%26G%DEj/ --- toolkit/xre/nsWindowsDllBlocklist.cpp | 70 +++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/toolkit/xre/nsWindowsDllBlocklist.cpp b/toolkit/xre/nsWindowsDllBlocklist.cpp index f6cfe62bd965..77fe237bb61d 100644 --- a/toolkit/xre/nsWindowsDllBlocklist.cpp +++ b/toolkit/xre/nsWindowsDllBlocklist.cpp @@ -39,6 +39,9 @@ #include #include +#include + +#include #ifdef XRE_WANT_DLL_BLOCKLIST #define XRE_SetupDllBlocklist SetupDllBlocklist @@ -148,10 +151,68 @@ static DllBlockInfo sWindowsDllBlocklist[] = { // define this for very verbose dll load debug spew #undef DEBUG_very_verbose +namespace { + typedef NTSTATUS (NTAPI *LdrLoadDll_func) (PWCHAR filePath, PULONG flags, PUNICODE_STRING moduleFileName, PHANDLE handle); static LdrLoadDll_func stub_LdrLoadDll = 0; +/** + * Some versions of Windows call LoadLibraryEx to get the version information + * for a DLL, which causes our patched LdrLoadDll implementation to re-enter + * itself and cause infinite recursion and a stack-exhaustion crash. We protect + * against reentrancy by allowing recursive loads of the same DLL. + * + * Note that we don't use __declspec(thread) because that doesn't work in DLLs + * loaded via LoadLibrary and there can be a limited number of TLS slots, so + * we roll our own. + */ +class ReentrancySentinel +{ +public: + explicit ReentrancySentinel(const char* dllName) + { + DWORD currentThreadId = GetCurrentThreadId(); + EnterCriticalSection(&sLock); + mPreviousDllName = (*sThreadMap)[currentThreadId]; + + // If there is a DLL currently being loaded and it has the same name + // as the current attempt, we're re-entering. + mReentered = mPreviousDllName && !stricmp(mPreviousDllName, dllName); + (*sThreadMap)[currentThreadId] = dllName; + LeaveCriticalSection(&sLock); + } + + ~ReentrancySentinel() + { + DWORD currentThreadId = GetCurrentThreadId(); + EnterCriticalSection(&sLock); + (*sThreadMap)[currentThreadId] = mPreviousDllName; + LeaveCriticalSection(&sLock); + } + + bool BailOut() const + { + return mReentered; + }; + + static void InitializeStatics() + { + InitializeCriticalSection(&sLock); + sThreadMap = new std::map; + } + +private: + static CRITICAL_SECTION sLock; + static std::map* sThreadMap; + + const char* mPreviousDllName; + bool mReentered; +}; + +CRITICAL_SECTION ReentrancySentinel::sLock; +std::map* ReentrancySentinel::sThreadMap; + static NTSTATUS NTAPI patched_LdrLoadDll (PWCHAR filePath, PULONG flags, PUNICODE_STRING moduleFileName, PHANDLE handle) { @@ -239,6 +300,11 @@ patched_LdrLoadDll (PWCHAR filePath, PULONG flags, PUNICODE_STRING moduleFileNam #endif if (info->maxVersion != ALL_VERSIONS) { + ReentrancySentinel sentinel(dllName); + if (sentinel.BailOut()) { + goto continue_loading; + } + // In Windows 8, the first parameter seems to be used for more than just the // path name. For example, its numerical value can be 1. Passing a non-valid // pointer to SearchPathW will cause a crash, so we need to check to see if we @@ -307,11 +373,15 @@ continue_loading: WindowsDllInterceptor NtDllIntercept; +} // anonymous namespace + void XRE_SetupDllBlocklist() { NtDllIntercept.Init("ntdll.dll"); + ReentrancySentinel::InitializeStatics(); + bool ok = NtDllIntercept.AddHook("LdrLoadDll", reinterpret_cast(patched_LdrLoadDll), (void**) &stub_LdrLoadDll); #ifdef DEBUG From 446aaeb959aab10b42708db66d9c95fff92d59ee Mon Sep 17 00:00:00 2001 From: Doug Sherk Date: Fri, 18 Nov 2011 22:57:29 -0500 Subject: [PATCH 35/63] Bug 699626: patch reftest analyzer and WebGL reftests r=dbaron --- content/canvas/test/webgl/resources/js-test-pre.js | 3 +-- layout/tools/reftest/reftest-analyzer.xhtml | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/content/canvas/test/webgl/resources/js-test-pre.js b/content/canvas/test/webgl/resources/js-test-pre.js index 21b3b9b00ca1..77271ebe313d 100644 --- a/content/canvas/test/webgl/resources/js-test-pre.js +++ b/content/canvas/test/webgl/resources/js-test-pre.js @@ -134,10 +134,9 @@ function testFailedRender(msg, ref, test, width, height) testFailed(msg); - var data = 'REFTEST TEST-KNOWN-FAIL | ' + msg + ' | image comparison (==)\n' + + var data = 'REFTEST TEST-DEBUG-INFO | ' + msg + ' | image comparison (==)\n' + 'REFTEST IMAGE 1 (TEST): ' + testData + '\n' + 'REFTEST IMAGE 2 (REFERENCE): ' + refData; - dump('The following information is for debugging purposes only. It will always print TEST-KNOWN-FAIL, even if it is unexpected.'); dump('FAIL: ' + data + '\n'); dump('To view the differences between these image renderings, go to the following link: https://hg.mozilla.org/mozilla-central/raw-file/tip/layout/tools/reftest/reftest-analyzer.xhtml#log=' + encodeURIComponent(encodeURIComponent(data)) + '\n'); diff --git a/layout/tools/reftest/reftest-analyzer.xhtml b/layout/tools/reftest/reftest-analyzer.xhtml index c7b3dea57e7e..b6793ef23b26 100644 --- a/layout/tools/reftest/reftest-analyzer.xhtml +++ b/layout/tools/reftest/reftest-analyzer.xhtml @@ -236,7 +236,7 @@ function process_log(contents) { if (!match) continue; line = match[1]; - match = line.match(/^(TEST-PASS|TEST-UNEXPECTED-PASS|TEST-KNOWN-FAIL|TEST-UNEXPECTED-FAIL)(\(EXPECTED RANDOM\)|) \| ([^\|]+) \|(.*)/); + match = line.match(/^(TEST-PASS|TEST-UNEXPECTED-PASS|TEST-KNOWN-FAIL|TEST-UNEXPECTED-FAIL|TEST-DEBUG-INFO)(\(EXPECTED RANDOM\)|) \| ([^\|]+) \|(.*)/); if (match) { var state = match[1]; var random = match[2]; @@ -244,7 +244,7 @@ function process_log(contents) { var extra = match[4]; gTestItems.push( { - pass: !state.match(/FAIL$/), + pass: !state.match(/DEBUG-INFO$|FAIL$/), // only one of the following three should ever be true unexpected: !!state.match(/^TEST-UNEXPECTED/), random: (random == "(EXPECTED RANDOM)"), From 75f90e54cd7bbd4538866792b2be56e7efbffbf1 Mon Sep 17 00:00:00 2001 From: Doug Sherk Date: Fri, 18 Nov 2011 22:57:29 -0500 Subject: [PATCH 36/63] Bug 699482: refactored GfxDriverInfo init to happen after global init r=bjacob This patch moves all static initialization of GfxDriverInfo and DeviceFamily classes to the point that they're actually used. It also converts all static GfxDriverInfo arrays into nsTArray so that they can be used interchangeably with the downloadable blocklist. This patch also introduces a new phase of blocklist checking called BEING_PROCESSED, which is the status set when a blocklist check is currently being processed. NO_INFO now only means that we have confirmed that a device is not blocked. --- browser/app/blocklist.xml | 2 +- widget/public/nsIGfxInfo.idl | 11 +- widget/src/android/GfxInfo.cpp | 27 +- widget/src/android/GfxInfo.h | 4 +- widget/src/cocoa/GfxInfo.h | 4 +- widget/src/cocoa/GfxInfo.mm | 36 +-- widget/src/windows/GfxInfo.cpp | 266 ++++++++++---------- widget/src/windows/GfxInfo.h | 4 +- widget/src/xpwidgets/GfxDriverInfo.cpp | 128 ++++++++++ widget/src/xpwidgets/GfxDriverInfo.h | 119 ++------- widget/src/xpwidgets/GfxInfoBase.cpp | 336 ++++++++++++++----------- widget/src/xpwidgets/GfxInfoBase.h | 18 +- widget/src/xpwidgets/GfxInfoX11.cpp | 18 +- widget/src/xpwidgets/GfxInfoX11.h | 4 +- 14 files changed, 536 insertions(+), 441 deletions(-) diff --git a/browser/app/blocklist.xml b/browser/app/blocklist.xml index 3080eac6b9df..2d37699d0bee 100644 --- a/browser/app/blocklist.xml +++ b/browser/app/blocklist.xml @@ -218,4 +218,4 @@ - \ No newline at end of file + diff --git a/widget/public/nsIGfxInfo.idl b/widget/public/nsIGfxInfo.idl index f0fea0539110..2f3f6ae17a3f 100644 --- a/widget/public/nsIGfxInfo.idl +++ b/widget/public/nsIGfxInfo.idl @@ -114,19 +114,22 @@ interface nsIGfxInfo : nsISupports /* * A set of return values from GetFeatureStatus */ + /* We don't explicitly block or discourage the feature. Which means we'll try getting it from the * hardware, and see what happens. */ const long FEATURE_NO_INFO = 1; + /* We don't know the status of the feature yet. The analysis probably hasn't finished yet. */ + const long FEATURE_STATUS_UNKNOWN = 2; /* This feature is blocked on this driver version. Updating driver will typically unblock it. */ - const long FEATURE_BLOCKED_DRIVER_VERSION = 2; + const long FEATURE_BLOCKED_DRIVER_VERSION = 3; /* This feature is blocked on this device, regardless of driver version. * Typically means we hit too many driver crashes without a good reason to hope for them to * get fixed soon. */ - const long FEATURE_BLOCKED_DEVICE = 3; + const long FEATURE_BLOCKED_DEVICE = 4; /* This feature is available and can be used, but is not suggested (e.g. shouldn't be used by default */ - const long FEATURE_DISCOURAGED = 4; + const long FEATURE_DISCOURAGED = 5; /* This feature is blocked on this OS version. */ - const long FEATURE_BLOCKED_OS_VERSION = 5; + const long FEATURE_BLOCKED_OS_VERSION = 6; /** * Ask about a feature, and return the status of that feature diff --git a/widget/src/android/GfxInfo.cpp b/widget/src/android/GfxInfo.cpp index fd09ede23836..0d1c5f510c41 100644 --- a/widget/src/android/GfxInfo.cpp +++ b/widget/src/android/GfxInfo.cpp @@ -267,30 +267,30 @@ GfxInfo::AddOpenGLCrashReportAnnotations() #endif } -static GfxDriverInfo gDriverInfo[] = { - GfxDriverInfo() -}; - -const GfxDriverInfo* +const nsTArray& GfxInfo::GetGfxDriverInfo() { - return &gDriverInfo[0]; + // Nothing here yet. + //if (!mDriverInfo->Length()) { + // + //} + return *mDriverInfo; } nsresult GfxInfo::GetFeatureStatusImpl(PRInt32 aFeature, PRInt32 *aStatus, nsAString & aSuggestedDriverVersion, - GfxDriverInfo* aDriverInfo /* = nsnull */, + const nsTArray& aDriverInfo, OperatingSystem* aOS /* = nsnull */) { - PRInt32 status = nsIGfxInfo::FEATURE_NO_INFO; + PRInt32 status = nsIGfxInfo::FEATURE_STATUS_UNKNOWN; aSuggestedDriverVersion.SetIsVoid(true); // For now, we don't implement the downloaded blacklist. - if (aDriverInfo) { - *aStatus = status; + if (aDriverInfo.Length()) { + *aStatus = nsIGfxInfo::FEATURE_NO_INFO; return NS_OK; } @@ -319,6 +319,11 @@ GfxInfo::GetFeatureStatusImpl(PRInt32 aFeature, *aOS = os; // XXX disabled for now as this calls GetAdapterVendorID and friends, which currently crash on Android, see bug 700124 - // return GfxInfoBase::GetFeatureStatusImpl(aFeature, aStatus, aSuggestedDriverVersion, aDriverInfo, &os); + // FIXME: if this gets fixed, the line setting *aStatus must be removed +#if 0 + return GfxInfoBase::GetFeatureStatusImpl(aFeature, aStatus, aSuggestedDriverVersion, aDriverInfo, &os); +#else + *aStatus = nsIGfxInfo::FEATURE_NO_INFO; +#endif return NS_OK; } diff --git a/widget/src/android/GfxInfo.h b/widget/src/android/GfxInfo.h index cd964da9639c..d54f6ed192b4 100644 --- a/widget/src/android/GfxInfo.h +++ b/widget/src/android/GfxInfo.h @@ -83,9 +83,9 @@ protected: virtual nsresult GetFeatureStatusImpl(PRInt32 aFeature, PRInt32 *aStatus, nsAString & aSuggestedDriverVersion, - GfxDriverInfo* aDriverInfo = nsnull, + const nsTArray& aDriverInfo, OperatingSystem* aOS = nsnull); - virtual const GfxDriverInfo* GetGfxDriverInfo(); + virtual const nsTArray& GetGfxDriverInfo(); private: diff --git a/widget/src/cocoa/GfxInfo.h b/widget/src/cocoa/GfxInfo.h index eaec9a62929c..d07f2637a79a 100644 --- a/widget/src/cocoa/GfxInfo.h +++ b/widget/src/cocoa/GfxInfo.h @@ -85,9 +85,9 @@ protected: virtual nsresult GetFeatureStatusImpl(PRInt32 aFeature, PRInt32 *aStatus, nsAString & aSuggestedDriverVersion, - GfxDriverInfo* aDriverInfo = nsnull, + const nsTArray& aDriverInfo, OperatingSystem* aOS = nsnull); - virtual const GfxDriverInfo* GetGfxDriverInfo(); + virtual const nsTArray& GetGfxDriverInfo(); private: diff --git a/widget/src/cocoa/GfxInfo.mm b/widget/src/cocoa/GfxInfo.mm index bb8f18e9d91d..9c7ee651c9fb 100644 --- a/widget/src/cocoa/GfxInfo.mm +++ b/widget/src/cocoa/GfxInfo.mm @@ -347,30 +347,20 @@ GfxInfo::AddCrashReportAnnotations() #endif } -static GfxDriverInfo gDriverInfo[] = { - // We don't support checking driver versions on Mac. - #define IMPLEMENT_MAC_DRIVER_BLOCKLIST(os, vendor, device, features, blockOn) \ - GfxDriverInfo(os, vendor, device, features, blockOn, \ - DRIVER_UNKNOWN_COMPARISON, V(0,0,0,0), ""), +// We don't support checking driver versions on Mac. +#define IMPLEMENT_MAC_DRIVER_BLOCKLIST(os, vendor, device, features, blockOn) \ + APPEND_TO_DRIVER_BLOCKLIST(os, vendor, device, features, blockOn, \ + DRIVER_UNKNOWN_COMPARISON, V(0,0,0,0), "") - // Example use of macro. - //IMPLEMENT_MAC_DRIVER_BLOCKLIST(DRIVER_OS_OS_X_10_7, - // GfxDriverInfo::vendorATI, GfxDriverInfo::allDevices, - // GfxDriverInfo::allFeatures, nsIGfxInfo::FEATURE_BLOCKED_OS_VERSION) - - // Block all ATI cards from using MSAA, except for two devices that have - // special exceptions in the GetFeatureStatusImpl() function. - IMPLEMENT_MAC_DRIVER_BLOCKLIST(DRIVER_OS_ALL, - GfxDriverInfo::vendorATI, GfxDriverInfo::allDevices, - nsIGfxInfo::FEATURE_WEBGL_MSAA, nsIGfxInfo::FEATURE_BLOCKED_OS_VERSION) - - GfxDriverInfo() -}; - -const GfxDriverInfo* +const nsTArray& GfxInfo::GetGfxDriverInfo() { - return &gDriverInfo[0]; + if (!mDriverInfo->Length()) { + IMPLEMENT_MAC_DRIVER_BLOCKLIST(DRIVER_OS_ALL, + GfxDriverInfo::vendorATI, GfxDriverInfo::allDevices, + nsIGfxInfo::FEATURE_WEBGL_MSAA, nsIGfxInfo::FEATURE_BLOCKED_OS_VERSION); + } + return *mDriverInfo; } static OperatingSystem @@ -392,14 +382,14 @@ nsresult GfxInfo::GetFeatureStatusImpl(PRInt32 aFeature, PRInt32* aStatus, nsAString& aSuggestedDriverVersion, - GfxDriverInfo* aDriverInfo /* = nsnull */, + const nsTArray& aDriverInfo, OperatingSystem* aOS /* = nsnull */) { NS_ENSURE_ARG_POINTER(aStatus); aSuggestedDriverVersion.SetIsVoid(true); - PRInt32 status = nsIGfxInfo::FEATURE_NO_INFO; + PRInt32 status = nsIGfxInfo::FEATURE_STATUS_UNKNOWN; OperatingSystem os = OSXVersionToOperatingSystem(nsToolkit::OSXVersion()); diff --git a/widget/src/windows/GfxInfo.cpp b/widget/src/windows/GfxInfo.cpp index 39f3f8cc6468..0123b77ffaa9 100644 --- a/widget/src/windows/GfxInfo.cpp +++ b/widget/src/windows/GfxInfo.cpp @@ -794,118 +794,6 @@ GfxInfo::AddCrashReportAnnotations() #endif } -static const GfxDriverInfo gDriverInfo[] = { - /* - * Notice that the first match defines the result. So always implement special cases firsts and general case last. - */ - - /* - * NVIDIA entries - */ - GfxDriverInfo( DRIVER_OS_WINDOWS_XP, - GfxDriverInfo::vendorNVIDIA, GfxDriverInfo::allDevices, - GfxDriverInfo::allFeatures, nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION, - DRIVER_LESS_THAN, V(6,14,12,5721), "257.21" ), - GfxDriverInfo( DRIVER_OS_WINDOWS_VISTA, - GfxDriverInfo::vendorNVIDIA, GfxDriverInfo::allDevices, - GfxDriverInfo::allFeatures, nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION, - DRIVER_LESS_THAN, V(8,17,12,5721), "257.21" ), - GfxDriverInfo( DRIVER_OS_WINDOWS_7, - GfxDriverInfo::vendorNVIDIA, GfxDriverInfo::allDevices, - GfxDriverInfo::allFeatures, nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION, - DRIVER_LESS_THAN, V(8,17,12,5721), "257.21" ), - - /* Disable D3D9 layers on NVIDIA 6100/6150/6200 series due to glitches - * whilst scrolling. See bugs: 612007, 644787 & 645872. - */ - GfxDriverInfo( DRIVER_OS_ALL, - GfxDriverInfo::vendorNVIDIA, (GfxDeviceFamily) deviceFamilyNvidiaBlockD3D9Layers, - nsIGfxInfo::FEATURE_DIRECT3D_9_LAYERS, nsIGfxInfo::FEATURE_BLOCKED_DEVICE, - DRIVER_LESS_THAN, GfxDriverInfo::allDriverVersions ), - - /* - * AMD/ATI entries - */ - GfxDriverInfo( DRIVER_OS_ALL, - GfxDriverInfo::vendorATI, GfxDriverInfo::allDevices, - GfxDriverInfo::allFeatures, nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION, - DRIVER_LESS_THAN, V(8,741,0,0), "10.6" ), - GfxDriverInfo( DRIVER_OS_ALL, - GfxDriverInfo::vendorAMD, GfxDriverInfo::allDevices, - GfxDriverInfo::allFeatures, nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION, - DRIVER_LESS_THAN, V(8,741,0,0), "10.6" ), - - /* OpenGL on any ATI/AMD hardware is discouraged - * See: - * bug 619773 - WebGL: Crash with blue screen : "NMI: Parity Check / Memory Parity Error" - * bugs 584403, 584404, 620924 - crashes in atioglxx - * + many complaints about incorrect rendering - */ - GfxDriverInfo( DRIVER_OS_ALL, - GfxDriverInfo::vendorATI, GfxDriverInfo::allDevices, - nsIGfxInfo::FEATURE_OPENGL_LAYERS, nsIGfxInfo::FEATURE_DISCOURAGED, - DRIVER_LESS_THAN, GfxDriverInfo::allDriverVersions ), - GfxDriverInfo( DRIVER_OS_ALL, - GfxDriverInfo::vendorATI, GfxDriverInfo::allDevices, - nsIGfxInfo::FEATURE_WEBGL_OPENGL, nsIGfxInfo::FEATURE_DISCOURAGED, - DRIVER_LESS_THAN, GfxDriverInfo::allDriverVersions ), - GfxDriverInfo( DRIVER_OS_ALL, - GfxDriverInfo::vendorAMD, GfxDriverInfo::allDevices, - nsIGfxInfo::FEATURE_OPENGL_LAYERS, nsIGfxInfo::FEATURE_DISCOURAGED, - DRIVER_LESS_THAN, GfxDriverInfo::allDriverVersions ), - GfxDriverInfo( DRIVER_OS_ALL, - GfxDriverInfo::vendorAMD, GfxDriverInfo::allDevices, - nsIGfxInfo::FEATURE_WEBGL_OPENGL, nsIGfxInfo::FEATURE_DISCOURAGED, - DRIVER_LESS_THAN, GfxDriverInfo::allDriverVersions ), - - /* - * Intel entries - */ - - /* implement the blocklist from bug 594877 - * Block all features on any drivers before this, as there's a crash when a MS Hotfix is installed. - * The crash itself is Direct2D-related, but for safety we block all features. - */ - #define IMPLEMENT_INTEL_DRIVER_BLOCKLIST(winVer, devFamily, driverVer) \ - GfxDriverInfo( winVer, \ - GfxDriverInfo::vendorIntel, (GfxDeviceFamily) devFamily, \ - GfxDriverInfo::allFeatures, nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION, \ - DRIVER_LESS_THAN, driverVer ), - - IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_XP, deviceFamilyIntelGMA500, V(6,14,11,1018)) - IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_XP, deviceFamilyIntelGMA900, V(6,14,10,4764)) - IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_XP, deviceFamilyIntelGMA950, V(6,14,10,4926)) - IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_XP, deviceFamilyIntelGMA3150, V(6,14,10,5260)) - IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_XP, deviceFamilyIntelGMAX3000, V(6,14,10,5218)) - IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_XP, deviceFamilyIntelGMAX4500HD, V(6,14,10,5284)) - - IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_VISTA, deviceFamilyIntelGMA500, V(7,14,10,1006)) - IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_VISTA, deviceFamilyIntelGMA900, GfxDriverInfo::allDriverVersions) - IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_VISTA, deviceFamilyIntelGMA950, V(7,14,10,1504)) - IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_VISTA, deviceFamilyIntelGMA3150, V(7,14,10,2124)) - IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_VISTA, deviceFamilyIntelGMAX3000, V(7,15,10,1666)) - IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_VISTA, deviceFamilyIntelGMAX4500HD, V(8,15,10,2202)) - - IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_7, deviceFamilyIntelGMA500, V(5,0,0,2026)) - IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_7, deviceFamilyIntelGMA900, GfxDriverInfo::allDriverVersions) - IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_7, deviceFamilyIntelGMA950, V(8,15,10,1930)) - IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_7, deviceFamilyIntelGMA3150, V(8,14,10,2117)) - IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_7, deviceFamilyIntelGMAX3000, V(8,15,10,1930)) - IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_7, deviceFamilyIntelGMAX4500HD, V(8,15,10,2202)) - - /* OpenGL on any Intel hardware is discouraged */ - GfxDriverInfo( DRIVER_OS_ALL, - GfxDriverInfo::vendorIntel, GfxDriverInfo::allDevices, - nsIGfxInfo::FEATURE_OPENGL_LAYERS, nsIGfxInfo::FEATURE_DISCOURAGED, - DRIVER_LESS_THAN, GfxDriverInfo::allDriverVersions ), - GfxDriverInfo( DRIVER_OS_ALL, - GfxDriverInfo::vendorIntel, GfxDriverInfo::allDevices, - nsIGfxInfo::FEATURE_WEBGL_OPENGL, nsIGfxInfo::FEATURE_DISCOURAGED, - DRIVER_LESS_THAN, GfxDriverInfo::allDriverVersions ), - - GfxDriverInfo() -}; - static OperatingSystem WindowsVersionToOperatingSystem(PRInt32 aWindowsVersion) { @@ -926,45 +814,149 @@ WindowsVersionToOperatingSystem(PRInt32 aWindowsVersion) }; } -const GfxDriverInfo* +const nsTArray& GfxInfo::GetGfxDriverInfo() { - return &gDriverInfo[0]; + if (!mDriverInfo->Length()) { + /* + * NVIDIA entries + */ + APPEND_TO_DRIVER_BLOCKLIST( DRIVER_OS_WINDOWS_XP, + GfxDriverInfo::vendorNVIDIA, GfxDriverInfo::allDevices, + GfxDriverInfo::allFeatures, nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION, + DRIVER_LESS_THAN, V(6,14,12,5721), "257.21" ); + APPEND_TO_DRIVER_BLOCKLIST( DRIVER_OS_WINDOWS_VISTA, + GfxDriverInfo::vendorNVIDIA, GfxDriverInfo::allDevices, + GfxDriverInfo::allFeatures, nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION, + DRIVER_LESS_THAN, V(8,17,12,5721), "257.21" ); + APPEND_TO_DRIVER_BLOCKLIST( DRIVER_OS_WINDOWS_7, + GfxDriverInfo::vendorNVIDIA, GfxDriverInfo::allDevices, + GfxDriverInfo::allFeatures, nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION, + DRIVER_LESS_THAN, V(8,17,12,5721), "257.21" ); + + /* Disable D3D9 layers on NVIDIA 6100/6150/6200 series due to glitches + * whilst scrolling. See bugs: 612007, 644787 & 645872. + */ + APPEND_TO_DRIVER_BLOCKLIST2( DRIVER_OS_ALL, + GfxDriverInfo::vendorNVIDIA, (GfxDeviceFamily) GfxDriverInfo::GetDeviceFamily(DeviceFamily::NvidiaBlockD3D9Layers), + nsIGfxInfo::FEATURE_DIRECT3D_9_LAYERS, nsIGfxInfo::FEATURE_BLOCKED_DEVICE, + DRIVER_LESS_THAN, GfxDriverInfo::allDriverVersions ); + + /* + * AMD/ATI entries + */ + APPEND_TO_DRIVER_BLOCKLIST( DRIVER_OS_ALL, + GfxDriverInfo::vendorATI, GfxDriverInfo::allDevices, + GfxDriverInfo::allFeatures, nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION, + DRIVER_LESS_THAN, V(8,741,0,0), "10.6" ); + APPEND_TO_DRIVER_BLOCKLIST( DRIVER_OS_ALL, + GfxDriverInfo::vendorAMD, GfxDriverInfo::allDevices, + GfxDriverInfo::allFeatures, nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION, + DRIVER_LESS_THAN, V(8,741,0,0), "10.6" ); + + /* OpenGL on any ATI/AMD hardware is discouraged + * See: + * bug 619773 - WebGL: Crash with blue screen : "NMI: Parity Check / Memory Parity Error" + * bugs 584403, 584404, 620924 - crashes in atioglxx + * + many complaints about incorrect rendering + */ + APPEND_TO_DRIVER_BLOCKLIST2( DRIVER_OS_ALL, + GfxDriverInfo::vendorATI, GfxDriverInfo::allDevices, + nsIGfxInfo::FEATURE_OPENGL_LAYERS, nsIGfxInfo::FEATURE_DISCOURAGED, + DRIVER_LESS_THAN, GfxDriverInfo::allDriverVersions ); + APPEND_TO_DRIVER_BLOCKLIST2( DRIVER_OS_ALL, + GfxDriverInfo::vendorATI, GfxDriverInfo::allDevices, + nsIGfxInfo::FEATURE_WEBGL_OPENGL, nsIGfxInfo::FEATURE_DISCOURAGED, + DRIVER_LESS_THAN, GfxDriverInfo::allDriverVersions ); + APPEND_TO_DRIVER_BLOCKLIST2( DRIVER_OS_ALL, + GfxDriverInfo::vendorAMD, GfxDriverInfo::allDevices, + nsIGfxInfo::FEATURE_OPENGL_LAYERS, nsIGfxInfo::FEATURE_DISCOURAGED, + DRIVER_LESS_THAN, GfxDriverInfo::allDriverVersions ); + APPEND_TO_DRIVER_BLOCKLIST2( DRIVER_OS_ALL, + GfxDriverInfo::vendorAMD, GfxDriverInfo::allDevices, + nsIGfxInfo::FEATURE_WEBGL_OPENGL, nsIGfxInfo::FEATURE_DISCOURAGED, + DRIVER_LESS_THAN, GfxDriverInfo::allDriverVersions ); + + /* + * Intel entries + */ + + /* implement the blocklist from bug 594877 + * Block all features on any drivers before this, as there's a crash when a MS Hotfix is installed. + * The crash itself is Direct2D-related, but for safety we block all features. + */ + #define IMPLEMENT_INTEL_DRIVER_BLOCKLIST(winVer, devFamily, driverVer) \ + APPEND_TO_DRIVER_BLOCKLIST2( winVer, \ + GfxDriverInfo::vendorIntel, (GfxDeviceFamily) GfxDriverInfo::GetDeviceFamily(devFamily), \ + GfxDriverInfo::allFeatures, nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION, \ + DRIVER_LESS_THAN, driverVer ) + + IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_XP, DeviceFamily::IntelGMA500, V(6,14,11,1018)); + IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_XP, DeviceFamily::IntelGMA900, V(6,14,10,4764)); + IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_XP, DeviceFamily::IntelGMA950, V(6,14,10,4926)); + IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_XP, DeviceFamily::IntelGMA3150, V(6,14,10,5260)); + IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_XP, DeviceFamily::IntelGMAX3000, V(6,14,10,5218)); + IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_XP, DeviceFamily::IntelGMAX4500HD, V(6,14,10,5284)); + + IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_VISTA, DeviceFamily::IntelGMA500, V(7,14,10,1006)); + IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_VISTA, DeviceFamily::IntelGMA900, GfxDriverInfo::allDriverVersions); + IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_VISTA, DeviceFamily::IntelGMA950, V(7,14,10,1504)); + IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_VISTA, DeviceFamily::IntelGMA3150, V(7,14,10,2124)); + IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_VISTA, DeviceFamily::IntelGMAX3000, V(7,15,10,1666)); + IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_VISTA, DeviceFamily::IntelGMAX4500HD, V(8,15,10,2202)); + + IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_7, DeviceFamily::IntelGMA500, V(5,0,0,2026)); + IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_7, DeviceFamily::IntelGMA900, GfxDriverInfo::allDriverVersions); + IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_7, DeviceFamily::IntelGMA950, V(8,15,10,1930)); + IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_7, DeviceFamily::IntelGMA3150, V(8,14,10,2117)); + IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_7, DeviceFamily::IntelGMAX3000, V(8,15,10,1930)); + IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_7, DeviceFamily::IntelGMAX4500HD, V(8,15,10,2202)); + + /* OpenGL on any Intel hardware is discouraged */ + APPEND_TO_DRIVER_BLOCKLIST2( DRIVER_OS_ALL, + GfxDriverInfo::vendorIntel, GfxDriverInfo::allDevices, + nsIGfxInfo::FEATURE_OPENGL_LAYERS, nsIGfxInfo::FEATURE_DISCOURAGED, + DRIVER_LESS_THAN, GfxDriverInfo::allDriverVersions ); + APPEND_TO_DRIVER_BLOCKLIST2( DRIVER_OS_ALL, + GfxDriverInfo::vendorIntel, GfxDriverInfo::allDevices, + nsIGfxInfo::FEATURE_WEBGL_OPENGL, nsIGfxInfo::FEATURE_DISCOURAGED, + DRIVER_LESS_THAN, GfxDriverInfo::allDriverVersions ); + } + return *mDriverInfo; } nsresult GfxInfo::GetFeatureStatusImpl(PRInt32 aFeature, PRInt32 *aStatus, nsAString & aSuggestedDriverVersion, - GfxDriverInfo* aDriverInfo /* = nsnull */, + const nsTArray& aDriverInfo, OperatingSystem* aOS /* = nsnull */) { - *aStatus = nsIGfxInfo::FEATURE_NO_INFO; aSuggestedDriverVersion.SetIsVoid(true); - PRInt32 status = nsIGfxInfo::FEATURE_NO_INFO; + PRInt32 status = nsIGfxInfo::FEATURE_STATUS_UNKNOWN; - PRUint32 adapterVendor = 0; + PRUint32 adapterVendorID = 0; PRUint32 adapterDeviceID = 0; nsAutoString adapterDriverVersionString; - if (NS_FAILED(GetAdapterVendorID(&adapterVendor)) || + if (NS_FAILED(GetAdapterVendorID(&adapterVendorID)) || NS_FAILED(GetAdapterDeviceID(&adapterDeviceID)) || NS_FAILED(GetAdapterDriverVersion(adapterDriverVersionString))) { return NS_ERROR_FAILURE; } - if (adapterVendor != GfxDriverInfo::vendorIntel && - adapterVendor != GfxDriverInfo::vendorNVIDIA && - adapterVendor != GfxDriverInfo::vendorAMD && - adapterVendor != GfxDriverInfo::vendorATI && + if (adapterVendorID != GfxDriverInfo::vendorIntel && + adapterVendorID != GfxDriverInfo::vendorNVIDIA && + adapterVendorID != GfxDriverInfo::vendorAMD && + adapterVendorID != GfxDriverInfo::vendorATI && // FIXME - these special hex values are currently used in xpcshell tests introduced by // bug 625160 patch 8/8. Maybe these tests need to be adjusted now that we're only whitelisting // intel/ati/nvidia. - adapterVendor != 0xabcd && - adapterVendor != 0xdcba && - adapterVendor != 0xabab && - adapterVendor != 0xdcdc) + adapterVendorID != 0xabcd && + adapterVendorID != 0xdcba && + adapterVendorID != 0xabab && + adapterVendorID != 0xdcdc) { *aStatus = FEATURE_BLOCKED_DEVICE; return NS_OK; @@ -974,7 +966,19 @@ GfxInfo::GetFeatureStatusImpl(PRInt32 aFeature, if (!ParseDriverVersion(adapterDriverVersionString, &driverVersion)) { return NS_ERROR_FAILURE; } - + + // special-case the WinXP test slaves: they have out-of-date drivers, but we still want to + // whitelist them, actually we do know that this combination of device and driver version + // works well. + if (mWindowsVersion == gfxWindowsPlatform::kWindowsXP && + adapterVendorID == GfxDriverInfo::vendorNVIDIA && + adapterDeviceID == 0x0861 && // GeForce 9400 + driverVersion == V(6,14,11,7756)) + { + *aStatus = FEATURE_NO_INFO; + return NS_OK; + } + if (aFeature == FEATURE_DIRECT3D_9_LAYERS && mWindowsVersion < gfxWindowsPlatform::kWindowsXP) { @@ -998,12 +1002,6 @@ GfxInfo::GetFeatureStatusImpl(PRInt32 aFeature, if (os == DRIVER_OS_WINDOWS_SERVER_2003) os = DRIVER_OS_WINDOWS_XP; - const GfxDriverInfo *info; - if (aDriverInfo) - info = aDriverInfo; - else - info = &gDriverInfo[0]; - if (mHasDriverVersionMismatch) { if (aFeature == nsIGfxInfo::FEATURE_DIRECT3D_10_LAYERS || aFeature == nsIGfxInfo::FEATURE_DIRECT3D_10_1_LAYERS || diff --git a/widget/src/windows/GfxInfo.h b/widget/src/windows/GfxInfo.h index f193f807f197..178e9c015e84 100644 --- a/widget/src/windows/GfxInfo.h +++ b/widget/src/windows/GfxInfo.h @@ -92,9 +92,9 @@ protected: virtual nsresult GetFeatureStatusImpl(PRInt32 aFeature, PRInt32 *aStatus, nsAString & aSuggestedDriverVersion, - GfxDriverInfo* aDriverInfo = nsnull, + const nsTArray& aDriverInfo, OperatingSystem* aOS = nsnull); - virtual const GfxDriverInfo* GetGfxDriverInfo(); + virtual const nsTArray& GetGfxDriverInfo(); private: diff --git a/widget/src/xpwidgets/GfxDriverInfo.cpp b/widget/src/xpwidgets/GfxDriverInfo.cpp index 6a744f95ce53..12dcc497b2d2 100644 --- a/widget/src/xpwidgets/GfxDriverInfo.cpp +++ b/widget/src/xpwidgets/GfxDriverInfo.cpp @@ -117,3 +117,131 @@ GfxDriverInfo::~GfxDriverInfo() if (mDeleteDevices) delete[] mDevices; } + +const GfxDeviceFamily GfxDriverInfo::GetDeviceFamily(DeviceFamily id) +{ + switch (id) { + case IntelGMA500: { + static const PRUint32 intelGMA500[] = { + 0x8108, /* IntelGMA500_1 */ + 0x8109, /* IntelGMA500_2 */ + 0 + }; + return (const GfxDeviceFamily) &intelGMA500[0]; + } + case IntelGMA900: { + static const PRUint32 intelGMA900[] = { + 0x2582, /* IntelGMA900_1 */ + 0x2782, /* IntelGMA900_2 */ + 0x2592, /* IntelGMA900_3 */ + 0x2792, /* IntelGMA900_4 */ + 0 + }; + return (const GfxDeviceFamily) &intelGMA900[0]; + } + case IntelGMA950: { + static const PRUint32 intelGMA950[] = { + 0x2772, /* Intel945G_1 */ + 0x2776, /* Intel945G_2 */ + 0x27A2, /* Intel945_1 */ + 0x27A6, /* Intel945_2 */ + 0x27AE, /* Intel945_3 */ + 0 + }; + return (const GfxDeviceFamily) &intelGMA950[0]; + } + case IntelGMA3150: { + static const PRUint32 intelGMA3150[] = { + 0xA001, /* IntelGMA3150_Nettop_1 */ + 0xA002, /* IntelGMA3150_Nettop_2 */ + 0xA011, /* IntelGMA3150_Netbook_1 */ + 0xA012, /* IntelGMA3150_Netbook_2 */ + 0 + }; + return (const GfxDeviceFamily) &intelGMA3150[0]; + } + case IntelGMAX3000: { + static const PRUint32 intelGMAX3000[] = { + 0x2972, /* Intel946GZ_1 */ + 0x2973, /* Intel946GZ_2 */ + 0x2982, /* IntelG35_1 */ + 0x2983, /* IntelG35_2 */ + 0x2992, /* IntelQ965_1 */ + 0x2993, /* IntelQ965_2 */ + 0x29A2, /* IntelG965_1 */ + 0x29A3, /* IntelG965_2 */ + 0x29B2, /* IntelQ35_1 */ + 0x29B3, /* IntelQ35_2 */ + 0x29C2, /* IntelG33_1 */ + 0x29C3, /* IntelG33_2 */ + 0x29D2, /* IntelQ33_1 */ + 0x29D3, /* IntelQ33_2 */ + 0x2A02, /* IntelGL960_1 */ + 0x2A03, /* IntelGL960_2 */ + 0x2A12, /* IntelGM965_1 */ + 0x2A13, /* IntelGM965_2 */ + 0 + }; + return (const GfxDeviceFamily) &intelGMAX3000[0]; + } + case IntelGMAX4500HD: { + static const PRUint32 intelGMAX4500HD[] = { + 0x2A42, /* IntelGMA4500MHD_1 */ + 0x2A43, /* IntelGMA4500MHD_2 */ + 0x2E42, /* IntelB43_1 */ + 0x2E43, /* IntelB43_2 */ + 0x2E92, /* IntelB43_3 */ + 0x2E93, /* IntelB43_4 */ + 0x2E32, /* IntelG41_1 */ + 0x2E33, /* IntelG41_2 */ + 0x2E22, /* IntelG45_1 */ + 0x2E23, /* IntelG45_2 */ + 0x2E12, /* IntelQ45_1 */ + 0x2E13, /* IntelQ45_2 */ + 0x0042, /* IntelHDGraphics */ + 0x0046, /* IntelMobileHDGraphics */ + 0x0102, /* IntelSandyBridge_1 */ + 0x0106, /* IntelSandyBridge_2 */ + 0x0112, /* IntelSandyBridge_3 */ + 0x0116, /* IntelSandyBridge_4 */ + 0x0122, /* IntelSandyBridge_5 */ + 0x0126, /* IntelSandyBridge_6 */ + 0x010A, /* IntelSandyBridge_7 */ + 0x0080, /* IntelIvyBridge */ + 0 + }; + return (const GfxDeviceFamily) &intelGMAX4500HD[0]; + } + case NvidiaBlockD3D9Layers: { + // Glitches whilst scrolling (see bugs 612007, 644787, 645872) + static const PRUint32 nvidiaBlockD3D9Layers[] = { + 0x00f3, /* NV43 [GeForce 6200 (TM)] */ + 0x0146, /* NV43 [Geforce Go 6600TE/6200TE (TM)] */ + 0x014f, /* NV43 [GeForce 6200 (TM)] */ + 0x0161, /* NV44 [GeForce 6200 TurboCache (TM)] */ + 0x0162, /* NV44 [GeForce 6200SE TurboCache (TM)] */ + 0x0163, /* NV44 [GeForce 6200 LE (TM)] */ + 0x0164, /* NV44 [GeForce Go 6200 (TM)] */ + 0x0167, /* NV43 [GeForce Go 6200/6400 (TM)] */ + 0x0168, /* NV43 [GeForce Go 6200/6400 (TM)] */ + 0x0169, /* NV44 [GeForce 6250 (TM)] */ + 0x0222, /* NV44 [GeForce 6200 A-LE (TM)] */ + 0x0240, /* C51PV [GeForce 6150 (TM)] */ + 0x0241, /* C51 [GeForce 6150 LE (TM)] */ + 0x0244, /* C51 [Geforce Go 6150 (TM)] */ + 0x0245, /* C51 [Quadro NVS 210S/GeForce 6150LE (TM)] */ + 0x0247, /* C51 [GeForce Go 6100 (TM)] */ + 0x03d0, /* C61 [GeForce 6150SE nForce 430 (TM)] */ + 0x03d1, /* C61 [GeForce 6100 nForce 405 (TM)] */ + 0x03d2, /* C61 [GeForce 6100 nForce 400 (TM)] */ + 0x03d5, /* C61 [GeForce 6100 nForce 420 (TM)] */ + 0 + }; + return (const GfxDeviceFamily) &nvidiaBlockD3D9Layers[0]; + } + default: + NS_WARNING("Invalid device family"); + } + + return nsnull; +} diff --git a/widget/src/xpwidgets/GfxDriverInfo.h b/widget/src/xpwidgets/GfxDriverInfo.h index e9340a2bd867..c446e45bbd5a 100644 --- a/widget/src/xpwidgets/GfxDriverInfo.h +++ b/widget/src/xpwidgets/GfxDriverInfo.h @@ -43,6 +43,11 @@ #define V(a,b,c,d) GFX_DRIVER_VERSION(a,b,c,d) +#define APPEND_TO_DRIVER_BLOCKLIST(os, vendor, devices, feature, featureStatus, driverComparator, driverVersion, suggestedVersion) \ + mDriverInfo->AppendElement(GfxDriverInfo(os, vendor, devices, feature, featureStatus, driverComparator, driverVersion, suggestedVersion)) +#define APPEND_TO_DRIVER_BLOCKLIST2(os, vendor, devices, feature, featureStatus, driverComparator, driverVersion) \ + mDriverInfo->AppendElement(GfxDriverInfo(os, vendor, devices, feature, featureStatus, driverComparator, driverVersion)) + namespace mozilla { namespace widget { @@ -74,112 +79,18 @@ enum VersionComparisonOp { DRIVER_UNKNOWN_COMPARISON }; -static const PRUint32 deviceFamilyIntelGMA500[] = { - 0x8108, /* IntelGMA500_1 */ - 0x8109, /* IntelGMA500_2 */ - 0 -}; - -static const PRUint32 deviceFamilyIntelGMA900[] = { - 0x2582, /* IntelGMA900_1 */ - 0x2782, /* IntelGMA900_2 */ - 0x2592, /* IntelGMA900_3 */ - 0x2792, /* IntelGMA900_4 */ - 0 -}; - -static const PRUint32 deviceFamilyIntelGMA950[] = { - 0x2772, /* Intel945G_1 */ - 0x2776, /* Intel945G_2 */ - 0x27A2, /* Intel945_1 */ - 0x27A6, /* Intel945_2 */ - 0x27AE, /* Intel945_3 */ - 0 -}; - -static const PRUint32 deviceFamilyIntelGMA3150[] = { - 0xA001, /* IntelGMA3150_Nettop_1 */ - 0xA002, /* IntelGMA3150_Nettop_2 */ - 0xA011, /* IntelGMA3150_Netbook_1 */ - 0xA012, /* IntelGMA3150_Netbook_2 */ - 0 -}; - -static const PRUint32 deviceFamilyIntelGMAX3000[] = { - 0x2972, /* Intel946GZ_1 */ - 0x2973, /* Intel946GZ_2 */ - 0x2982, /* IntelG35_1 */ - 0x2983, /* IntelG35_2 */ - 0x2992, /* IntelQ965_1 */ - 0x2993, /* IntelQ965_2 */ - 0x29A2, /* IntelG965_1 */ - 0x29A3, /* IntelG965_2 */ - 0x29B2, /* IntelQ35_1 */ - 0x29B3, /* IntelQ35_2 */ - 0x29C2, /* IntelG33_1 */ - 0x29C3, /* IntelG33_2 */ - 0x29D2, /* IntelQ33_1 */ - 0x29D3, /* IntelQ33_2 */ - 0x2A02, /* IntelGL960_1 */ - 0x2A03, /* IntelGL960_2 */ - 0x2A12, /* IntelGM965_1 */ - 0x2A13, /* IntelGM965_2 */ - 0 -}; - -static const PRUint32 deviceFamilyIntelGMAX4500HD[] = { - 0x2A42, /* IntelGMA4500MHD_1 */ - 0x2A43, /* IntelGMA4500MHD_2 */ - 0x2E42, /* IntelB43_1 */ - 0x2E43, /* IntelB43_2 */ - 0x2E92, /* IntelB43_3 */ - 0x2E93, /* IntelB43_4 */ - 0x2E32, /* IntelG41_1 */ - 0x2E33, /* IntelG41_2 */ - 0x2E22, /* IntelG45_1 */ - 0x2E23, /* IntelG45_2 */ - 0x2E12, /* IntelQ45_1 */ - 0x2E13, /* IntelQ45_2 */ - 0x0042, /* IntelHDGraphics */ - 0x0046, /* IntelMobileHDGraphics */ - 0x0102, /* IntelSandyBridge_1 */ - 0x0106, /* IntelSandyBridge_2 */ - 0x0112, /* IntelSandyBridge_3 */ - 0x0116, /* IntelSandyBridge_4 */ - 0x0122, /* IntelSandyBridge_5 */ - 0x0126, /* IntelSandyBridge_6 */ - 0x010A, /* IntelSandyBridge_7 */ - 0x0080, /* IntelIvyBridge */ - 0 -}; - -// Glitches whilst scrolling (see bugs 612007, 644787, 645872) -static const PRUint32 deviceFamilyNvidiaBlockD3D9Layers[] = { - 0x00f3, /* NV43 [GeForce 6200 (TM)] */ - 0x0146, /* NV43 [Geforce Go 6600TE/6200TE (TM)] */ - 0x014f, /* NV43 [GeForce 6200 (TM)] */ - 0x0161, /* NV44 [GeForce 6200 TurboCache (TM)] */ - 0x0162, /* NV44 [GeForce 6200SE TurboCache (TM)] */ - 0x0163, /* NV44 [GeForce 6200 LE (TM)] */ - 0x0164, /* NV44 [GeForce Go 6200 (TM)] */ - 0x0167, /* NV43 [GeForce Go 6200/6400 (TM)] */ - 0x0168, /* NV43 [GeForce Go 6200/6400 (TM)] */ - 0x0169, /* NV44 [GeForce 6250 (TM)] */ - 0x0222, /* NV44 [GeForce 6200 A-LE (TM)] */ - 0x0240, /* C51PV [GeForce 6150 (TM)] */ - 0x0241, /* C51 [GeForce 6150 LE (TM)] */ - 0x0244, /* C51 [Geforce Go 6150 (TM)] */ - 0x0245, /* C51 [Quadro NVS 210S/GeForce 6150LE (TM)] */ - 0x0247, /* C51 [GeForce Go 6100 (TM)] */ - 0x03d0, /* C61 [GeForce 6150SE nForce 430 (TM)] */ - 0x03d1, /* C61 [GeForce 6100 nForce 405 (TM)] */ - 0x03d2, /* C61 [GeForce 6100 nForce 400 (TM)] */ - 0x03d5, /* C61 [GeForce 6100 nForce 420 (TM)] */ - 0 +enum DeviceFamily { + IntelGMA500, + IntelGMA900, + IntelGMA950, + IntelGMA3150, + IntelGMAX3000, + IntelGMAX4500HD, + NvidiaBlockD3D9Layers }; /* A zero-terminated array of devices to match, or all devices */ -typedef PRUint32 *GfxDeviceFamily; +typedef PRUint32* GfxDeviceFamily; struct GfxDriverInfo { @@ -226,6 +137,8 @@ struct GfxDriverInfo static PRUint32 vendorATI; const char *mSuggestedVersion; + + static const GfxDeviceFamily GetDeviceFamily(DeviceFamily id); }; #define GFX_DRIVER_VERSION(a,b,c,d) \ diff --git a/widget/src/xpwidgets/GfxInfoBase.cpp b/widget/src/xpwidgets/GfxInfoBase.cpp index b9609245ce47..a436cb21b231 100644 --- a/widget/src/xpwidgets/GfxInfoBase.cpp +++ b/widget/src/xpwidgets/GfxInfoBase.cpp @@ -48,6 +48,7 @@ #include "nsAutoPtr.h" #include "nsString.h" #include "mozilla/Services.h" +#include "mozilla/Observer.h" #include "nsIObserver.h" #include "nsIObserverService.h" #include "nsIDOMElement.h" @@ -60,8 +61,52 @@ #include "nsExceptionHandler.h" #endif +using namespace mozilla::widget; using namespace mozilla; +nsTArray* GfxInfoBase::mDriverInfo; +bool GfxInfoBase::mDriverInfoObserverInitialized; + +// Observes for shutdown so that the child GfxDriverInfo list is freed. +class ShutdownObserver : public nsIObserver +{ +public: + ShutdownObserver() {} + virtual ~ShutdownObserver() {} + + NS_DECL_ISUPPORTS + + NS_IMETHOD Observe(nsISupports *subject, const char *aTopic, + const PRUnichar *aData) + { + MOZ_ASSERT(strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0); + if (GfxInfoBase::mDriverInfo) { + delete GfxInfoBase::mDriverInfo; + GfxInfoBase::mDriverInfo = nsnull; + } + return NS_OK; + } +}; + +NS_IMPL_ISUPPORTS1(ShutdownObserver, nsIObserver); + +void InitGfxDriverInfoShutdownObserver() +{ + if (GfxInfoBase::mDriverInfoObserverInitialized) + return; + + GfxInfoBase::mDriverInfoObserverInitialized = true; + + nsCOMPtr observerService = services::GetObserverService(); + if (!observerService) { + NS_WARNING("Could not get observer service!"); + return; + } + + ShutdownObserver *obs = new ShutdownObserver(); + observerService->AddObserver(obs, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false); +} + extern "C" { void StoreSpline(int ax, int ay, int bx, int by, int cx, int cy, int dx, int dy); void CrashSpline(double tolerance, int ax, int ay, int bx, int by, int cx, int cy, int dx, int dy); @@ -338,6 +383,8 @@ BlacklistFeatureStatusToGfxFeatureStatus(const nsAString& aStatus) else if (aStatus == NS_LITERAL_STRING("BLOCKED_OS_VERSION")) return nsIGfxInfo::FEATURE_BLOCKED_OS_VERSION; + // Do not allow it to set STATUS_UNKNOWN. + return nsIGfxInfo::FEATURE_NO_INFO; } @@ -558,12 +605,6 @@ GfxInfoBase::Init() return NS_OK; } -static const GfxDriverInfo gDriverInfo[] = { - // No combinations that cause a crash on every OS. - GfxDriverInfo() -}; - - NS_IMETHODIMP GfxInfoBase::GetFeatureStatus(PRInt32 aFeature, PRInt32* aStatus NS_OUTPARAM) { @@ -571,22 +612,145 @@ GfxInfoBase::GetFeatureStatus(PRInt32 aFeature, PRInt32* aStatus NS_OUTPARAM) return NS_OK; nsString version; - return GetFeatureStatusImpl(aFeature, aStatus, version); + nsTArray driverInfo; + return GetFeatureStatusImpl(aFeature, aStatus, version, driverInfo); +} + +PRInt32 +GfxInfoBase::FindBlocklistedDeviceInList(const nsTArray& info, + nsAString& aSuggestedVersion, + PRInt32 aFeature, + OperatingSystem os) +{ + PRInt32 status = nsIGfxInfo::FEATURE_STATUS_UNKNOWN; + + PRUint32 adapterVendorID = 0; + PRUint32 adapterDeviceID = 0; + nsAutoString adapterDriverVersionString; + if (NS_FAILED(GetAdapterVendorID(&adapterVendorID)) || + NS_FAILED(GetAdapterDeviceID(&adapterDeviceID)) || + NS_FAILED(GetAdapterDriverVersion(adapterDriverVersionString))) + { + return NS_OK; + } + + PRUint64 driverVersion; + ParseDriverVersion(adapterDriverVersionString, &driverVersion); + + PRUint32 i = 0; + for (; i < info.Length(); i++) { + if (info[i].mOperatingSystem != DRIVER_OS_ALL && + info[i].mOperatingSystem != os) + { + continue; + } + + if (info[i].mAdapterVendor != GfxDriverInfo::allAdapterVendors && + info[i].mAdapterVendor != adapterVendorID) { + continue; + } + + if (info[i].mDevices != GfxDriverInfo::allDevices) { + bool deviceMatches = false; + for (const PRUint32 *devices = info[i].mDevices; *devices; ++devices) { + if (*devices == adapterDeviceID) { + deviceMatches = true; + break; + } + } + + if (!deviceMatches) { + continue; + } + } + + bool match = false; + +#if !defined(XP_MACOSX) + switch (info[i].mComparisonOp) { + case DRIVER_LESS_THAN: + match = driverVersion < info[i].mDriverVersion; + break; + case DRIVER_LESS_THAN_OR_EQUAL: + match = driverVersion <= info[i].mDriverVersion; + break; + case DRIVER_GREATER_THAN: + match = driverVersion > info[i].mDriverVersion; + break; + case DRIVER_GREATER_THAN_OR_EQUAL: + match = driverVersion >= info[i].mDriverVersion; + break; + case DRIVER_EQUAL: + match = driverVersion == info[i].mDriverVersion; + break; + case DRIVER_NOT_EQUAL: + match = driverVersion != info[i].mDriverVersion; + break; + case DRIVER_BETWEEN_EXCLUSIVE: + match = driverVersion > info[i].mDriverVersion && driverVersion < info[i].mDriverVersionMax; + break; + case DRIVER_BETWEEN_INCLUSIVE: + match = driverVersion >= info[i].mDriverVersion && driverVersion <= info[i].mDriverVersionMax; + break; + case DRIVER_BETWEEN_INCLUSIVE_START: + match = driverVersion >= info[i].mDriverVersion && driverVersion < info[i].mDriverVersionMax; + break; + default: + NS_WARNING("Bogus op in GfxDriverInfo"); + break; + } +#else + // We don't care what driver version it was. We only check OS version and if + // the device matches. + match = true; +#endif + + if (match) { + if (info[i].mFeature == GfxDriverInfo::allFeatures || + info[i].mFeature == aFeature) + { + status = info[i].mFeatureStatus; + break; + } + } + } + + // Depends on Windows driver versioning. We don't pass a GfxDriverInfo object + // back to the Windows handler, so we must handle this here. +#if defined(XP_WIN) + if (status == FEATURE_BLOCKED_DRIVER_VERSION) { + if (info[i].mSuggestedVersion) { + aSuggestedVersion.AppendPrintf("%s", info[i].mSuggestedVersion); + } else if (info[i].mComparisonOp == DRIVER_LESS_THAN && + info[i].mDriverVersion != GfxDriverInfo::allDriverVersions) + { + aSuggestedVersion.AppendPrintf("%lld.%lld.%lld.%lld", + (info[i].mDriverVersion & 0xffff000000000000) >> 48, + (info[i].mDriverVersion & 0x0000ffff00000000) >> 32, + (info[i].mDriverVersion & 0x00000000ffff0000) >> 16, + (info[i].mDriverVersion & 0x000000000000ffff)); + } + } +#endif + + return status; } nsresult GfxInfoBase::GetFeatureStatusImpl(PRInt32 aFeature, PRInt32* aStatus, - nsAString& aVersion, - GfxDriverInfo* aDriverInfo /* = nsnull */, + nsAString& aSuggestedVersion, + const nsTArray& aDriverInfo, OperatingSystem* aOS /* = nsnull */) { - if (*aStatus != nsIGfxInfo::FEATURE_NO_INFO) { + if (*aStatus != nsIGfxInfo::FEATURE_STATUS_UNKNOWN) { // Terminate now with the status determined by the derived type (OS-specific // code). return NS_OK; } + // If an operating system was provided by the derived GetFeatureStatusImpl, + // grab it here. Otherwise, the OS is unknown. OperatingSystem os = DRIVER_OS_UNKNOWN; if (aOS) os = *aOS; @@ -604,137 +768,24 @@ GfxInfoBase::GetFeatureStatusImpl(PRInt32 aFeature, PRUint64 driverVersion; ParseDriverVersion(adapterDriverVersionString, &driverVersion); - // special-case the WinXP test slaves: they have out-of-date drivers, but we still want to - // whitelist them, actually we do know that this combination of device and driver version - // works well. - if (os == DRIVER_OS_WINDOWS_XP && - adapterVendorID == GfxDriverInfo::vendorNVIDIA && - adapterDeviceID == 0x0861 && // GeForce 9400 - driverVersion == V(6,14,11,7756)) - { - return NS_OK; + // Check if the device is blocked from the downloaded blocklist. If not, check + // the static list after that. This order is used so that we can later escape + // out of static blocks (i.e. if we were wrong or something was patched, we + // can back out our static block without doing a release). + InitGfxDriverInfoShutdownObserver(); + if (!mDriverInfo) + mDriverInfo = new nsTArray(); + PRInt32 status = FindBlocklistedDeviceInList(aDriverInfo, aSuggestedVersion, aFeature, os); + if (status == nsIGfxInfo::FEATURE_STATUS_UNKNOWN) { + status = FindBlocklistedDeviceInList(GetGfxDriverInfo(), aSuggestedVersion, aFeature, os); } - PRInt32 status = *aStatus; - const GfxDriverInfo* info = aDriverInfo ? aDriverInfo : &gDriverInfo[0]; - // This code will operate in two modes: - // It first loops over the driver tuples stored locally in gDriverInfo, - // then loops over it a second time for the OS's specific list to check for - // all combinations that can lead to disabling a feature. - bool loopingOverOS = false; - while (true) { - if (!info->mOperatingSystem) { - if (loopingOverOS) - break; - else - { - // Mark us as looping over the OS driver tuples. - loopingOverOS = true; - // Get the GfxDriverInfo table from the OS subclass. - info = GetGfxDriverInfo(); - } - } - - if (info->mOperatingSystem != DRIVER_OS_ALL && - info->mOperatingSystem != os) - { - info++; - continue; - } - - if (info->mAdapterVendor != GfxDriverInfo::allAdapterVendors && - info->mAdapterVendor != adapterVendorID) { - info++; - continue; - } - - if (info->mDevices != GfxDriverInfo::allDevices) { - bool deviceMatches = false; - for (const PRUint32 *devices = info->mDevices; *devices; ++devices) { - if (*devices == adapterDeviceID) { - deviceMatches = true; - break; - } - } - - if (!deviceMatches) { - info++; - continue; - } - } - - bool match = false; - -#if !defined(XP_MACOSX) - switch (info->mComparisonOp) { - case DRIVER_LESS_THAN: - match = driverVersion < info->mDriverVersion; - break; - case DRIVER_LESS_THAN_OR_EQUAL: - match = driverVersion <= info->mDriverVersion; - break; - case DRIVER_GREATER_THAN: - match = driverVersion > info->mDriverVersion; - break; - case DRIVER_GREATER_THAN_OR_EQUAL: - match = driverVersion >= info->mDriverVersion; - break; - case DRIVER_EQUAL: - match = driverVersion == info->mDriverVersion; - break; - case DRIVER_NOT_EQUAL: - match = driverVersion != info->mDriverVersion; - break; - case DRIVER_BETWEEN_EXCLUSIVE: - match = driverVersion > info->mDriverVersion && driverVersion < info->mDriverVersionMax; - break; - case DRIVER_BETWEEN_INCLUSIVE: - match = driverVersion >= info->mDriverVersion && driverVersion <= info->mDriverVersionMax; - break; - case DRIVER_BETWEEN_INCLUSIVE_START: - match = driverVersion >= info->mDriverVersion && driverVersion < info->mDriverVersionMax; - break; - default: - NS_WARNING("Bogus op in GfxDriverInfo"); - break; - } -#else - // We don't care what driver version it was. We only check OS version and if - // the device matches. - match = true; -#endif - - if (match) { - if (info->mFeature == GfxDriverInfo::allFeatures || - info->mFeature == aFeature) - { - status = info->mFeatureStatus; - break; - } - } - - info++; + // It's now done being processed. It's safe to set the status to NO_INFO. + if (status == nsIGfxInfo::FEATURE_STATUS_UNKNOWN) { + *aStatus = nsIGfxInfo::FEATURE_NO_INFO; + } else { + *aStatus = status; } - - *aStatus = status; - - // Depends on Windows driver versioning. We don't pass a GfxDriverInfo object - // back to the Windows handler, so we must handle this here. -#if defined(XP_WIN) - if (status == FEATURE_BLOCKED_DRIVER_VERSION) { - if (info->mSuggestedVersion) { - aVersion.AppendPrintf("%s", info->mSuggestedVersion); - } else if (info->mComparisonOp == DRIVER_LESS_THAN && - info->mDriverVersion != GfxDriverInfo::allDriverVersions) - { - aVersion.AppendPrintf("%lld.%lld.%lld.%lld", - (info->mDriverVersion & 0xffff000000000000) >> 48, - (info->mDriverVersion & 0x0000ffff00000000) >> 32, - (info->mDriverVersion & 0x00000000ffff0000) >> 16, - (info->mDriverVersion & 0x000000000000ffff)); - } - } -#endif return NS_OK; } @@ -750,7 +801,8 @@ GfxInfoBase::GetFeatureSuggestedDriverVersion(PRInt32 aFeature, } PRInt32 status; - return GetFeatureStatusImpl(aFeature, &status, aVersion); + nsTArray driverInfo; + return GetFeatureStatusImpl(aFeature, &status, aVersion, driverInfo); } @@ -776,10 +828,6 @@ GfxInfoBase::EvaluateDownloadedBlacklist(nsTArray& aDriverInfo) 0 }; - // GetFeatureStatusImpl wants a zero-GfxDriverInfo terminated array. So, we - // append that to our list. - aDriverInfo.AppendElement(GfxDriverInfo()); - // For every feature we know about, we evaluate whether this blacklist has a // non-NO_INFO status. If it does, we set the pref we evaluate in // GetFeatureStatus above, so we don't need to hold on to this blacklist @@ -790,7 +838,7 @@ GfxInfoBase::EvaluateDownloadedBlacklist(nsTArray& aDriverInfo) nsAutoString suggestedVersion; if (NS_SUCCEEDED(GetFeatureStatusImpl(features[i], &status, suggestedVersion, - aDriverInfo.Elements()))) { + aDriverInfo))) { switch (status) { default: case nsIGfxInfo::FEATURE_NO_INFO: diff --git a/widget/src/xpwidgets/GfxInfoBase.h b/widget/src/xpwidgets/GfxInfoBase.h index a5f784c1f024..9f97aaf372d3 100644 --- a/widget/src/xpwidgets/GfxInfoBase.h +++ b/widget/src/xpwidgets/GfxInfoBase.h @@ -86,14 +86,13 @@ public: // Ideally, Init() would be void-return, but the rules of // NS_GENERIC_FACTORY_CONSTRUCTOR_INIT require it be nsresult return. virtual nsresult Init(); - - // Gets the driver info table. Used by GfxInfoBase to check for general cases - // (while subclasses check for more specific ones). - virtual const GfxDriverInfo* GetGfxDriverInfo() = 0; // only useful on X11 NS_IMETHOD_(void) GetData() { } + static nsTArray* mDriverInfo; + static bool mDriverInfoObserverInitialized; + static void AddCollector(GfxInfoCollectorBase* collector); static void RemoveCollector(GfxInfoCollectorBase* collector); @@ -102,11 +101,20 @@ protected: virtual nsresult GetFeatureStatusImpl(PRInt32 aFeature, PRInt32* aStatus, nsAString& aSuggestedDriverVersion, - GfxDriverInfo* aDriverInfo = nsnull, + const nsTArray& aDriverInfo, OperatingSystem* aOS = nsnull); + // Gets the driver info table. Used by GfxInfoBase to check for general cases + // (while subclasses check for more specific ones). + virtual const nsTArray& GetGfxDriverInfo() = 0; + private: + virtual PRInt32 FindBlocklistedDeviceInList(const nsTArray& aDriverInfo, + nsAString& aSuggestedVersion, + PRInt32 aFeature, + OperatingSystem os); + void EvaluateDownloadedBlacklist(nsTArray& aDriverInfo); nsCString mFailures[9]; // The choice of 9 is Ehsan's diff --git a/widget/src/xpwidgets/GfxInfoX11.cpp b/widget/src/xpwidgets/GfxInfoX11.cpp index 2bc377dfe9f0..1c7b94b2f87e 100644 --- a/widget/src/xpwidgets/GfxInfoX11.cpp +++ b/widget/src/xpwidgets/GfxInfoX11.cpp @@ -246,29 +246,30 @@ static inline PRUint64 version(PRUint32 major, PRUint32 minor, PRUint32 revision return (PRUint64(major) << 32) + (PRUint64(minor) << 16) + PRUint64(revision); } -static GfxDriverInfo gDriverInfo[] = { - GfxDriverInfo() -}; - -const GfxDriverInfo* +const nsTArray& GfxInfo::GetGfxDriverInfo() { - return &gDriverInfo[0]; + // Nothing here yet. + //if (!mDriverInfo->Length()) { + // + //} + return *mDriverInfo; } nsresult GfxInfo::GetFeatureStatusImpl(PRInt32 aFeature, PRInt32 *aStatus, nsAString & aSuggestedDriverVersion, - GfxDriverInfo* aDriverInfo /* = nsnull */, + const nsTArray& aDriverInfo, OperatingSystem* aOS /* = nsnull */) { GetData(); - *aStatus = nsIGfxInfo::FEATURE_NO_INFO; + *aStatus = nsIGfxInfo::FEATURE_STATUS_UNKNOWN; aSuggestedDriverVersion.SetIsVoid(true); #ifdef MOZ_PLATFORM_MAEMO + *aStatus = nsIGfxInfo::FEATURE_NO_INFO; // on Maemo, the glxtest probe doesn't build, and we don't really need GfxInfo anyway return NS_OK; #endif @@ -291,6 +292,7 @@ GfxInfo::GetFeatureStatusImpl(PRInt32 aFeature, !strcmp(mRenderer.get(), "GeForce 9400/PCI/SSE2") && !strcmp(mVersion.get(), "3.2.0 NVIDIA 190.42")) { + *aStatus = nsIGfxInfo::FEATURE_NO_INFO; return NS_OK; } diff --git a/widget/src/xpwidgets/GfxInfoX11.h b/widget/src/xpwidgets/GfxInfoX11.h index 2525db0d98f3..43690c00ca13 100644 --- a/widget/src/xpwidgets/GfxInfoX11.h +++ b/widget/src/xpwidgets/GfxInfoX11.h @@ -84,9 +84,9 @@ protected: virtual nsresult GetFeatureStatusImpl(PRInt32 aFeature, PRInt32 *aStatus, nsAString & aSuggestedDriverVersion, - GfxDriverInfo* aDriverInfo = nsnull, + const nsTArray& aDriverInfo, OperatingSystem* aOS = nsnull); - virtual const GfxDriverInfo* GetGfxDriverInfo(); + virtual const nsTArray& GetGfxDriverInfo(); private: nsCString mVendor; From 7a2325141e4036253038ebd096fa64291a5965a3 Mon Sep 17 00:00:00 2001 From: Doug Sherk Date: Fri, 18 Nov 2011 22:57:29 -0500 Subject: [PATCH 37/63] Bug 656824: changed WebGL robustness timer to not get reset after each draw operation r=bjacob This patch should improve performance of the robustness timer by not resetting it each time a draw operation happens. It still checks if there's any activity and, if not, it will stop firing it. It includes a single extra timer firing after activity dies to make sure we don't miss anything. Also includes a fix for robustness being marked as existing when it really isn't. --- content/canvas/src/WebGLContext.cpp | 29 +++++----- content/canvas/src/WebGLContext.h | 26 +++++++-- content/canvas/src/WebGLContextGL.cpp | 6 +- gfx/gl/GLContext.cpp | 83 +++++++++++++++------------ gfx/gl/GLContext.h | 11 ++++ gfx/gl/GLContextProviderCGL.mm | 5 ++ gfx/gl/GLContextProviderEGL.cpp | 5 ++ gfx/gl/GLContextProviderGLX.cpp | 17 +++--- gfx/gl/GLContextProviderOSMesa.cpp | 5 ++ gfx/gl/GLContextProviderWGL.cpp | 5 ++ 10 files changed, 123 insertions(+), 69 deletions(-) diff --git a/content/canvas/src/WebGLContext.cpp b/content/canvas/src/WebGLContext.cpp index 38e1223b72c5..d2f284e1fd11 100644 --- a/content/canvas/src/WebGLContext.cpp +++ b/content/canvas/src/WebGLContext.cpp @@ -301,16 +301,17 @@ WebGLContext::WebGLContext() mContextLost = false; mAllowRestore = false; + mRobustnessTimerRunning = false; + mDrawSinceRobustnessTimerSet = false; + mContextRestorer = do_CreateInstance("@mozilla.org/timer;1"); } WebGLContext::~WebGLContext() { DestroyResourcesAndContext(); WebGLMemoryReporter::RemoveWebGLContext(this); - if (mContextRestorer) { - mContextRestorer->Cancel(); - mContextRestorer = NULL; - } + TerminateRobustnessTimer(); + mContextRestorer = nsnull; } static PLDHashOperator @@ -709,6 +710,8 @@ WebGLContext::SetDimensions(PRInt32 width, PRInt32 height) mResetLayer = true; mOptionsFrozen = true; + mHasRobustness = gl->HasRobustness(); + // increment the generation number ++mGeneration; @@ -1147,13 +1150,8 @@ WebGLContext::EnsureBackbufferClearedAsNeeded() NS_IMETHODIMP WebGLContext::Notify(nsITimer* timer) { + TerminateRobustnessTimer(); MaybeRestoreContext(); - - if (mContextRestorer) { - mContextRestorer->Cancel(); - mContextRestorer = NULL; - } - return NS_OK; } @@ -1163,6 +1161,7 @@ WebGLContext::MaybeRestoreContext() if (mContextLost || mAllowRestore) return; + gl->MakeCurrent(); GLContext::ContextResetARB resetStatus = (GLContext::ContextResetARB) gl->fGetGraphicsResetStatus(); @@ -1174,6 +1173,11 @@ WebGLContext::MaybeRestoreContext() switch (resetStatus) { case GLContext::CONTEXT_NO_ERROR: + // If there has been activity since the timer was set, it's possible + // that we did or are going to miss something, so clear this flag and + // run it again some time later. + if (mDrawSinceRobustnessTimerSet) + SetupRobustnessTimer(); return; case GLContext::CONTEXT_GUILTY_CONTEXT_RESET_ARB: NS_WARNING("WebGL content on the page caused the graphics card to reset; not restoring the context"); @@ -1191,10 +1195,7 @@ WebGLContext::MaybeRestoreContext() void WebGLContext::ForceLoseContext() { - if (mContextRestorer) { - mContextRestorer->Cancel(); - mContextRestorer = NULL; - } + TerminateRobustnessTimer(); mWebGLError = LOCAL_GL_CONTEXT_LOST; diff --git a/content/canvas/src/WebGLContext.h b/content/canvas/src/WebGLContext.h index 3d9d87a3501d..75439ce8d61f 100644 --- a/content/canvas/src/WebGLContext.h +++ b/content/canvas/src/WebGLContext.h @@ -449,17 +449,30 @@ public: // Sets up the GL_ARB_robustness timer if it isn't already, so that if the // driver gets restarted, the context may get reset with it. void SetupRobustnessTimer() { - if (mContextLost) + if (mContextLost || !mHasRobustness) return; - if (!mContextRestorer) - mContextRestorer = do_CreateInstance("@mozilla.org/timer;1"); + // If the timer was already running, don't restart it here. Instead, + // wait until the previous call is done, then fire it one more time. + // This is an optimization to prevent unnecessary cross-communication + // between threads. + if (mRobustnessTimerRunning) { + mDrawSinceRobustnessTimerSet = true; + return; + } - // As long as there's still activity, we reset the timer each time that - // this function gets called. mContextRestorer->InitWithCallback(static_cast(this), PR_MillisecondsToInterval(1000), nsITimer::TYPE_ONE_SHOT); + mRobustnessTimerRunning = true; + mDrawSinceRobustnessTimerSet = false; + } + + void TerminateRobustnessTimer() { + if (mRobustnessTimerRunning) { + mContextRestorer->Cancel(); + mRobustnessTimerRunning = false; + } } protected: @@ -504,6 +517,7 @@ protected: bool mOptionsFrozen; bool mMinCapability; bool mDisableExtensions; + bool mHasRobustness; WebGLuint mActiveTexture; WebGLenum mWebGLError; @@ -723,6 +737,8 @@ protected: nsCOMPtr mContextRestorer; bool mContextLost; bool mAllowRestore; + bool mRobustnessTimerRunning; + bool mDrawSinceRobustnessTimerSet; public: // console logging helpers diff --git a/content/canvas/src/WebGLContextGL.cpp b/content/canvas/src/WebGLContextGL.cpp index 1ebce3767f7c..d13ccb63c648 100644 --- a/content/canvas/src/WebGLContextGL.cpp +++ b/content/canvas/src/WebGLContextGL.cpp @@ -1622,8 +1622,6 @@ WebGLContext::DrawArrays(GLenum mode, WebGLint first, WebGLsizei count) if (!ValidateBuffers(&maxAllowedCount, "drawArrays")) return NS_OK; - SetupRobustnessTimer(); - CheckedInt32 checked_firstPlusCount = CheckedInt32(first) + count; if (!checked_firstPlusCount.valid()) @@ -1645,6 +1643,7 @@ WebGLContext::DrawArrays(GLenum mode, WebGLint first, WebGLsizei count) if (!DoFakeVertexAttrib0(checked_firstPlusCount.value())) return NS_OK; + SetupRobustnessTimer(); gl->fDrawArrays(mode, first, count); UndoFakeVertexAttrib0(); @@ -1675,8 +1674,6 @@ WebGLContext::DrawElements(WebGLenum mode, WebGLsizei count, WebGLenum type, Web if (count == 0) return NS_OK; - SetupRobustnessTimer(); - CheckedUint32 checked_byteCount; if (type == LOCAL_GL_UNSIGNED_SHORT) { @@ -1757,6 +1754,7 @@ WebGLContext::DrawElements(WebGLenum mode, WebGLsizei count, WebGLenum type, Web if (!DoFakeVertexAttrib0(checked_maxIndexPlusOne.value())) return NS_OK; + SetupRobustnessTimer(); gl->fDrawElements(mode, count, type, (GLvoid*) (byteOffset)); UndoFakeVertexAttrib0(); diff --git a/gfx/gl/GLContext.cpp b/gfx/gl/GLContext.cpp index 2dd768405dd7..2875b613b67f 100644 --- a/gfx/gl/GLContext.cpp +++ b/gfx/gl/GLContext.cpp @@ -71,6 +71,38 @@ const ContextFormat ContextFormat::BasicRGBA32Format(ContextFormat::BasicRGBA32) #define MAX_SYMBOL_LENGTH 128 #define MAX_SYMBOL_NAMES 5 +// should match the order of GLExtensions +static const char *sExtensionNames[] = { + "GL_EXT_framebuffer_object", + "GL_ARB_framebuffer_object", + "GL_ARB_texture_rectangle", + "GL_EXT_bgra", + "GL_EXT_texture_format_BGRA8888", + "GL_OES_depth24", + "GL_OES_depth32", + "GL_OES_stencil8", + "GL_OES_texture_npot", + "GL_OES_depth_texture", + "GL_OES_packed_depth_stencil", + "GL_IMG_read_format", + "GL_EXT_read_format_bgra", + "GL_APPLE_client_storage", + "GL_ARB_texture_non_power_of_two", + "GL_ARB_pixel_buffer_object", + "GL_ARB_ES2_compatibility", + "GL_OES_texture_float", + "GL_ARB_texture_float", + "GL_EXT_unpack_subimage", + "GL_OES_standard_derivatives", + "GL_EXT_framebuffer_blit", + "GL_ANGLE_framebuffer_blit", + "GL_EXT_framebuffer_multisample", + "GL_ANGLE_framebuffer_multisample", + "GL_OES_rgb8_rgba8", + "GL_ARB_robustness", + NULL +}; + bool LibrarySymbolLoader::OpenLibrary(const char *library) { @@ -174,8 +206,6 @@ GLContext::InitWithPrefix(const char *prefix, bool trygl) return true; } - mHasRobustness = IsExtensionSupported(ARB_robustness); - SymLoadStruct symbols[] = { { (PRFuncPtr*) &mSymbols.fActiveTexture, { "ActiveTexture", "ActiveTextureARB", NULL } }, { (PRFuncPtr*) &mSymbols.fAttachShader, { "AttachShader", "AttachShaderARB", NULL } }, @@ -327,9 +357,6 @@ GLContext::InitWithPrefix(const char *prefix, bool trygl) { mIsGLES2 ? (PRFuncPtr*) NULL : (PRFuncPtr*) &mSymbols.fUnmapBuffer, { mIsGLES2 ? NULL : "UnmapBuffer", NULL } }, - { mHasRobustness ? (PRFuncPtr*) &mSymbols.fGetGraphicsResetStatus : (PRFuncPtr*) NULL, - { mHasRobustness ? "GetGraphicsResetStatusARB" : NULL, NULL } }, - { NULL, { NULL } }, }; @@ -382,6 +409,20 @@ GLContext::InitWithPrefix(const char *prefix, bool trygl) (mSymbols.fMapBuffer && mSymbols.fUnmapBuffer), "ARB_pixel_buffer_object supported without glMapBuffer/UnmapBuffer being available!"); + if (SupportsRobustness() && IsExtensionSupported(ARB_robustness)) { + SymLoadStruct robustnessSymbols[] = { + { (PRFuncPtr*) &mSymbols.fGetGraphicsResetStatus, { "GetGraphicsResetStatusARB", NULL } }, + { NULL, { NULL } }, + }; + + if (!LoadSymbols(&robustnessSymbols[0], trygl, prefix)) { + NS_RUNTIMEABORT("GL supports ARB_robustness without supplying GetGraphicsResetStatusARB."); + mInitialized = false; + } + + mHasRobustness = true; + } + // Check for aux symbols based on extensions if (IsExtensionSupported(GLContext::ANGLE_framebuffer_blit) || IsExtensionSupported(GLContext::EXT_framebuffer_blit)) { @@ -448,38 +489,6 @@ GLContext::InitWithPrefix(const char *prefix, bool trygl) return mInitialized; } -// should match the order of GLExtensions -static const char *sExtensionNames[] = { - "GL_EXT_framebuffer_object", - "GL_ARB_framebuffer_object", - "GL_ARB_texture_rectangle", - "GL_EXT_bgra", - "GL_EXT_texture_format_BGRA8888", - "GL_OES_depth24", - "GL_OES_depth32", - "GL_OES_stencil8", - "GL_OES_texture_npot", - "GL_OES_depth_texture", - "GL_OES_packed_depth_stencil", - "GL_IMG_read_format", - "GL_EXT_read_format_bgra", - "GL_APPLE_client_storage", - "GL_ARB_texture_non_power_of_two", - "GL_ARB_pixel_buffer_object", - "GL_ARB_ES2_compatibility", - "GL_OES_texture_float", - "GL_ARB_texture_float", - "GL_EXT_unpack_subimage", - "GL_OES_standard_derivatives", - "GL_EXT_framebuffer_blit", - "GL_ANGLE_framebuffer_blit", - "GL_EXT_framebuffer_multisample", - "GL_ANGLE_framebuffer_multisample", - "GL_OES_rgb8_rgba8", - "GL_ARB_robustness", - NULL -}; - void GLContext::InitExtensions() { diff --git a/gfx/gl/GLContext.h b/gfx/gl/GLContext.h index d75d4adb9810..019b8ce2383c 100644 --- a/gfx/gl/GLContext.h +++ b/gfx/gl/GLContext.h @@ -541,6 +541,7 @@ public: mIsGLES2(false), #endif mIsGlobalSharedContext(false), + mHasRobustness(false), mVendor(-1), mDebugMode(0), mCreationFormat(aFormat), @@ -661,6 +662,12 @@ public: return mIsGLES2 || IsExtensionSupported(ARB_ES2_compatibility); } + /** + * The derived class is expected to provide information on whether or not it + * supports robustness. + */ + virtual bool SupportsRobustness() = 0; + enum { VendorIntel, VendorNVIDIA, @@ -1309,6 +1316,10 @@ public: CONTEXT_UNKNOWN_CONTEXT_RESET_ARB = 0x8255, }; + bool HasRobustness() { + return mHasRobustness; + } + protected: bool mInitialized; bool mIsOffscreen; diff --git a/gfx/gl/GLContextProviderCGL.mm b/gfx/gl/GLContextProviderCGL.mm index 3edb00467784..d4518600ea53 100644 --- a/gfx/gl/GLContextProviderCGL.mm +++ b/gfx/gl/GLContextProviderCGL.mm @@ -188,6 +188,11 @@ public: return gUseDoubleBufferedWindows; } + bool SupportsRobustness() + { + return false; + } + bool SwapBuffers() { [mContext flushBuffer]; diff --git a/gfx/gl/GLContextProviderEGL.cpp b/gfx/gl/GLContextProviderEGL.cpp index 3a5d4c148f4f..dcc6792c5658 100644 --- a/gfx/gl/GLContextProviderEGL.cpp +++ b/gfx/gl/GLContextProviderEGL.cpp @@ -764,6 +764,11 @@ public: mIsDoubleBuffered = aIsDB; } + bool SupportsRobustness() + { + return false; + } + #if defined(MOZ_X11) && defined(MOZ_EGL_XRENDER_COMPOSITE) gfxASurface* GetOffscreenPixmapSurface() { diff --git a/gfx/gl/GLContextProviderGLX.cpp b/gfx/gl/GLContextProviderGLX.cpp index c4e8d52b7329..38510a074703 100644 --- a/gfx/gl/GLContextProviderGLX.cpp +++ b/gfx/gl/GLContextProviderGLX.cpp @@ -256,15 +256,9 @@ GLXLibrary::EnsureInitialized() NS_WARNING("Texture from pixmap disabled"); } - if (HasExtension(extensionsStr, "GL_ARB_robustness")) { - if (!LibrarySymbolLoader::LoadSymbols(mOGLLibrary, symbols_robustness)) { - // We have no easy way of checking whether or not this extension - // exists, so it's best to just try to load it and accept that it - // might fail. - //NS_WARNING("Couldn't load ARB_robustness symbols"); - } else { - mHasRobustness = true; - } + if (HasExtension(extensionsStr, "GLX_ARB_create_context_robustness") && + LibrarySymbolLoader::LoadSymbols(mOGLLibrary, symbols_robustness)) { + mHasRobustness = true; } gIsATI = serverVendor && DoesVendorStringMatch(serverVendor, "ATI"); @@ -828,6 +822,11 @@ TRY_AGAIN_NO_SHARING: return mDoubleBuffered; } + bool SupportsRobustness() + { + return sGLXLibrary.HasRobustness(); + } + bool SwapBuffers() { if (!mDoubleBuffered) diff --git a/gfx/gl/GLContextProviderOSMesa.cpp b/gfx/gl/GLContextProviderOSMesa.cpp index 4290c8ba7367..32190452b3b0 100644 --- a/gfx/gl/GLContextProviderOSMesa.cpp +++ b/gfx/gl/GLContextProviderOSMesa.cpp @@ -240,6 +240,11 @@ public: } } + bool SupportsRobustness() + { + return false; + } + private: nsRefPtr mThebesSurface; PrivateOSMesaContext mContext; diff --git a/gfx/gl/GLContextProviderWGL.cpp b/gfx/gl/GLContextProviderWGL.cpp index 928f9b733e5b..7491575e08ff 100644 --- a/gfx/gl/GLContextProviderWGL.cpp +++ b/gfx/gl/GLContextProviderWGL.cpp @@ -307,6 +307,11 @@ public: return mIsDoubleBuffered; } + bool SupportsRobustness() + { + return false; + } + virtual bool SwapBuffers() { if (!mIsDoubleBuffered) return false; From 160573a7594fa2b6afd8e87381dfdf11a0c883c0 Mon Sep 17 00:00:00 2001 From: Doug Sherk Date: Fri, 18 Nov 2011 22:57:29 -0500 Subject: [PATCH 38/63] Bug 656824: fixed invalid return type on loseContext and restoreContext r=bjacob --- content/canvas/src/WebGLExtensionLoseContext.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/content/canvas/src/WebGLExtensionLoseContext.cpp b/content/canvas/src/WebGLExtensionLoseContext.cpp index 52d9dfb41296..2c7f360809fd 100644 --- a/content/canvas/src/WebGLExtensionLoseContext.cpp +++ b/content/canvas/src/WebGLExtensionLoseContext.cpp @@ -61,7 +61,7 @@ NS_IMETHODIMP WebGLExtensionLoseContext::LoseContext() { if (!mContext->LoseContext()) - return mContext->mWebGLError = LOCAL_GL_INVALID_OPERATION; + mContext->mWebGLError = LOCAL_GL_INVALID_OPERATION; return NS_OK; } @@ -70,7 +70,7 @@ NS_IMETHODIMP WebGLExtensionLoseContext::RestoreContext() { if (!mContext->RestoreContext()) - return mContext->mWebGLError = LOCAL_GL_INVALID_OPERATION; + mContext->mWebGLError = LOCAL_GL_INVALID_OPERATION; return NS_OK; } From 35e5e0bb9522b27f208ca88b840c065b450e9809 Mon Sep 17 00:00:00 2001 From: Bill McCloskey Date: Fri, 18 Nov 2011 22:35:17 -0800 Subject: [PATCH 39/63] Bug 703699 - Fix use-after-free problem with write barriers and XPConnect (r=bhackett) --- js/src/jsapi.cpp | 16 ++++++++++++++++ js/src/jsapi.h | 19 ++++++++++++++++++- js/xpconnect/src/XPCWrappedNative.cpp | 19 +++++++++++++++++-- js/xpconnect/src/XPCWrappedNativeProto.cpp | 2 +- js/xpconnect/src/XPCWrappedNativeScope.cpp | 11 ++++++++--- 5 files changed, 60 insertions(+), 7 deletions(-) diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 6d33ff74dae5..8a1c7dd594cf 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -6406,6 +6406,7 @@ JS_ModifyReference(void **ref, void *newval) thing = (void *)((uintptr_t)thing & ~7); if (!thing) return; + JS_ASSERT(!static_cast(thing)->compartment()->rt->gcRunning); uint32 kind = GetGCThingTraceKind(thing); if (kind == JSTRACE_OBJECT) JSObject::writeBarrierPre((JSObject *) thing); @@ -6422,6 +6423,14 @@ JS_UnregisterReference(void **ref) JS_ModifyReference(ref, NULL); } +JS_PUBLIC_API(void) +JS_UnregisterReferenceRT(JSRuntime *rt, void **ref) +{ + // For now we just want to trigger a write barrier. + if (!rt->gcRunning) + JS_ModifyReference(ref, NULL); +} + JS_PUBLIC_API(void) JS_RegisterValue(jsval *val) { @@ -6440,6 +6449,13 @@ JS_UnregisterValue(jsval *val) JS_ModifyValue(val, JSVAL_VOID); } +JS_PUBLIC_API(void) +JS_UnregisterValueRT(JSRuntime *rt, jsval *val) +{ + if (!rt->gcRunning) + JS_ModifyValue(val, JSVAL_VOID); +} + JS_PUBLIC_API(JSTracer *) JS_GetIncrementalGCTracer(JSRuntime *rt) { diff --git a/js/src/jsapi.h b/js/src/jsapi.h index 14e2b071a3e1..9c6aeff67101 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -2860,6 +2860,10 @@ JS_DumpHeap(JSContext *cx, FILE *fp, void* startThing, JSGCTraceKind kind, * change the value of these references. You should not change them using * assignment. * + * Only the RT versions of these functions (which take a JSRuntime argument) + * should be called during GC. Without a JSRuntime, it is not possible to know + * if the object being barriered has already been finalized. + * * To avoid the headache of using these API functions, the JSBarrieredObjectPtr * C++ class is provided--simply replace your JSObject* with a * JSBarrieredObjectPtr. It will take care of calling the registration and @@ -2878,6 +2882,9 @@ JS_ModifyReference(void **ref, void *newval); extern JS_PUBLIC_API(void) JS_UnregisterReference(void **ref); +extern JS_PUBLIC_API(void) +JS_UnregisterReferenceRT(JSRuntime *rt, void **ref); + /* These functions are for values. */ extern JS_PUBLIC_API(void) JS_RegisterValue(jsval *val); @@ -2888,6 +2895,9 @@ JS_ModifyValue(jsval *val, jsval newval); extern JS_PUBLIC_API(void) JS_UnregisterValue(jsval *val); +extern JS_PUBLIC_API(void) +JS_UnregisterValueRT(JSRuntime *rt, jsval *val); + extern JS_PUBLIC_API(JSTracer *) JS_GetIncrementalGCTracer(JSRuntime *rt); @@ -2905,7 +2915,14 @@ class HeapPtrObject HeapPtrObject(JSObject *obj) : value(obj) { JS_RegisterReference((void **) &value); } - ~HeapPtrObject() { JS_UnregisterReference((void **) &value); } + /* Always call finalize before the destructor. */ + ~HeapPtrObject() { JS_ASSERT(!value); } + + void finalize(JSRuntime *rt) { + JS_UnregisterReferenceRT(rt, (void **) &value); + value = NULL; + } + void finalize(JSContext *cx) { finalize(JS_GetRuntime(cx)); } void init(JSObject *obj) { value = obj; } diff --git a/js/xpconnect/src/XPCWrappedNative.cpp b/js/xpconnect/src/XPCWrappedNative.cpp index 050f1f7ca871..66db914874ed 100644 --- a/js/xpconnect/src/XPCWrappedNative.cpp +++ b/js/xpconnect/src/XPCWrappedNative.cpp @@ -53,6 +53,8 @@ #include "WrapperFactory.h" #include "dombindings.h" +#include "mozilla/Util.h" + bool xpc_OkToHandOutWrapper(nsWrapperCache *cache) { @@ -860,6 +862,8 @@ XPCWrappedNative::~XPCWrappedNative() Destroy(); } +static const PRWord WRAPPER_WORD_POISON = 0xa8a8a8a8; + void XPCWrappedNative::Destroy() { @@ -899,9 +903,20 @@ XPCWrappedNative::Destroy() } } - mMaybeScope = nsnull; + /* + * The only time GetRuntime() will be NULL is if Destroy is called a second + * time on a wrapped native. Since we already unregistered the pointer the + * first time, there's no need to unregister again. Unregistration is safe + * the first time because mWrapperWord isn't used afterwards. + */ + if (XPCJSRuntime *rt = GetRuntime()) { + JS_UnregisterReferenceRT(rt->GetJSRuntime(), (void **) &mWrapperWord); + mWrapperWord = WRAPPER_WORD_POISON; + } else { + MOZ_ASSERT(mWrapperWord == WRAPPER_WORD_POISON); + } - JS_UnregisterReference((void **) &mWrapperWord); + mMaybeScope = nsnull; } void diff --git a/js/xpconnect/src/XPCWrappedNativeProto.cpp b/js/xpconnect/src/XPCWrappedNativeProto.cpp index 14847982ba1e..c3e370701474 100644 --- a/js/xpconnect/src/XPCWrappedNativeProto.cpp +++ b/js/xpconnect/src/XPCWrappedNativeProto.cpp @@ -163,7 +163,7 @@ XPCWrappedNativeProto::JSProtoObjectFinalized(JSContext *cx, JSObject *obj) GetRuntime()->GetDetachedWrappedNativeProtoMap()->Remove(this); GetRuntime()->GetDyingWrappedNativeProtoMap()->Add(this); - mJSProtoObject = nsnull; + mJSProtoObject.finalize(cx); } void diff --git a/js/xpconnect/src/XPCWrappedNativeScope.cpp b/js/xpconnect/src/XPCWrappedNativeScope.cpp index 646f259e45c6..347bd972f784 100644 --- a/js/xpconnect/src/XPCWrappedNativeScope.cpp +++ b/js/xpconnect/src/XPCWrappedNativeScope.cpp @@ -318,6 +318,11 @@ XPCWrappedNativeScope::~XPCWrappedNativeScope() // XXX we should assert that we are dead or that xpconnect has shutdown // XXX might not want to do this at xpconnect shutdown time??? NS_IF_RELEASE(mComponents); + + JSRuntime *rt = mRuntime->GetJSRuntime(); + mGlobalJSObject.finalize(rt); + mPrototypeJSObject.finalize(rt); + mPrototypeJSFunction.finalize(rt); } JSObject * @@ -430,7 +435,7 @@ XPCWrappedNativeScope::FinishedMarkPhaseOfGC(JSContext* cx, XPCJSRuntime* rt) if (cur->mGlobalJSObject && JS_IsAboutToBeFinalized(cx, cur->mGlobalJSObject)) { - cur->mGlobalJSObject = nsnull; + cur->mGlobalJSObject.finalize(cx); cur->mScriptObjectPrincipal = nsnull; if (cur->GetCachedDOMPrototypes().IsInitialized()) cur->GetCachedDOMPrototypes().Clear(); @@ -445,11 +450,11 @@ XPCWrappedNativeScope::FinishedMarkPhaseOfGC(JSContext* cx, XPCJSRuntime* rt) } else { if (cur->mPrototypeJSObject && JS_IsAboutToBeFinalized(cx, cur->mPrototypeJSObject)) { - cur->mPrototypeJSObject = nsnull; + cur->mPrototypeJSObject.finalize(cx); } if (cur->mPrototypeJSFunction && JS_IsAboutToBeFinalized(cx, cur->mPrototypeJSFunction)) { - cur->mPrototypeJSFunction = nsnull; + cur->mPrototypeJSFunction.finalize(cx); } if (cur->mPrototypeNoHelper && JS_IsAboutToBeFinalized(cx, cur->mPrototypeNoHelper)) { From d7c7b9c6d5e1d8217bcd948c92b20e3ae2ff1c64 Mon Sep 17 00:00:00 2001 From: Phil Ringnalda Date: Fri, 18 Nov 2011 22:49:09 -0800 Subject: [PATCH 40/63] Back out 515736d18227 (bug 699482) on suspicion of breaking Android reftest-3 --- browser/app/blocklist.xml | 2 +- widget/public/nsIGfxInfo.idl | 11 +- widget/src/android/GfxInfo.cpp | 27 +- widget/src/android/GfxInfo.h | 4 +- widget/src/cocoa/GfxInfo.h | 4 +- widget/src/cocoa/GfxInfo.mm | 36 ++- widget/src/windows/GfxInfo.cpp | 266 ++++++++++---------- widget/src/windows/GfxInfo.h | 4 +- widget/src/xpwidgets/GfxDriverInfo.cpp | 128 ---------- widget/src/xpwidgets/GfxDriverInfo.h | 119 +++++++-- widget/src/xpwidgets/GfxInfoBase.cpp | 336 +++++++++++-------------- widget/src/xpwidgets/GfxInfoBase.h | 18 +- widget/src/xpwidgets/GfxInfoX11.cpp | 18 +- widget/src/xpwidgets/GfxInfoX11.h | 4 +- 14 files changed, 441 insertions(+), 536 deletions(-) diff --git a/browser/app/blocklist.xml b/browser/app/blocklist.xml index 2d37699d0bee..3080eac6b9df 100644 --- a/browser/app/blocklist.xml +++ b/browser/app/blocklist.xml @@ -218,4 +218,4 @@ - + \ No newline at end of file diff --git a/widget/public/nsIGfxInfo.idl b/widget/public/nsIGfxInfo.idl index 2f3f6ae17a3f..f0fea0539110 100644 --- a/widget/public/nsIGfxInfo.idl +++ b/widget/public/nsIGfxInfo.idl @@ -114,22 +114,19 @@ interface nsIGfxInfo : nsISupports /* * A set of return values from GetFeatureStatus */ - /* We don't explicitly block or discourage the feature. Which means we'll try getting it from the * hardware, and see what happens. */ const long FEATURE_NO_INFO = 1; - /* We don't know the status of the feature yet. The analysis probably hasn't finished yet. */ - const long FEATURE_STATUS_UNKNOWN = 2; /* This feature is blocked on this driver version. Updating driver will typically unblock it. */ - const long FEATURE_BLOCKED_DRIVER_VERSION = 3; + const long FEATURE_BLOCKED_DRIVER_VERSION = 2; /* This feature is blocked on this device, regardless of driver version. * Typically means we hit too many driver crashes without a good reason to hope for them to * get fixed soon. */ - const long FEATURE_BLOCKED_DEVICE = 4; + const long FEATURE_BLOCKED_DEVICE = 3; /* This feature is available and can be used, but is not suggested (e.g. shouldn't be used by default */ - const long FEATURE_DISCOURAGED = 5; + const long FEATURE_DISCOURAGED = 4; /* This feature is blocked on this OS version. */ - const long FEATURE_BLOCKED_OS_VERSION = 6; + const long FEATURE_BLOCKED_OS_VERSION = 5; /** * Ask about a feature, and return the status of that feature diff --git a/widget/src/android/GfxInfo.cpp b/widget/src/android/GfxInfo.cpp index 0d1c5f510c41..fd09ede23836 100644 --- a/widget/src/android/GfxInfo.cpp +++ b/widget/src/android/GfxInfo.cpp @@ -267,30 +267,30 @@ GfxInfo::AddOpenGLCrashReportAnnotations() #endif } -const nsTArray& +static GfxDriverInfo gDriverInfo[] = { + GfxDriverInfo() +}; + +const GfxDriverInfo* GfxInfo::GetGfxDriverInfo() { - // Nothing here yet. - //if (!mDriverInfo->Length()) { - // - //} - return *mDriverInfo; + return &gDriverInfo[0]; } nsresult GfxInfo::GetFeatureStatusImpl(PRInt32 aFeature, PRInt32 *aStatus, nsAString & aSuggestedDriverVersion, - const nsTArray& aDriverInfo, + GfxDriverInfo* aDriverInfo /* = nsnull */, OperatingSystem* aOS /* = nsnull */) { - PRInt32 status = nsIGfxInfo::FEATURE_STATUS_UNKNOWN; + PRInt32 status = nsIGfxInfo::FEATURE_NO_INFO; aSuggestedDriverVersion.SetIsVoid(true); // For now, we don't implement the downloaded blacklist. - if (aDriverInfo.Length()) { - *aStatus = nsIGfxInfo::FEATURE_NO_INFO; + if (aDriverInfo) { + *aStatus = status; return NS_OK; } @@ -319,11 +319,6 @@ GfxInfo::GetFeatureStatusImpl(PRInt32 aFeature, *aOS = os; // XXX disabled for now as this calls GetAdapterVendorID and friends, which currently crash on Android, see bug 700124 - // FIXME: if this gets fixed, the line setting *aStatus must be removed -#if 0 - return GfxInfoBase::GetFeatureStatusImpl(aFeature, aStatus, aSuggestedDriverVersion, aDriverInfo, &os); -#else - *aStatus = nsIGfxInfo::FEATURE_NO_INFO; -#endif + // return GfxInfoBase::GetFeatureStatusImpl(aFeature, aStatus, aSuggestedDriverVersion, aDriverInfo, &os); return NS_OK; } diff --git a/widget/src/android/GfxInfo.h b/widget/src/android/GfxInfo.h index d54f6ed192b4..cd964da9639c 100644 --- a/widget/src/android/GfxInfo.h +++ b/widget/src/android/GfxInfo.h @@ -83,9 +83,9 @@ protected: virtual nsresult GetFeatureStatusImpl(PRInt32 aFeature, PRInt32 *aStatus, nsAString & aSuggestedDriverVersion, - const nsTArray& aDriverInfo, + GfxDriverInfo* aDriverInfo = nsnull, OperatingSystem* aOS = nsnull); - virtual const nsTArray& GetGfxDriverInfo(); + virtual const GfxDriverInfo* GetGfxDriverInfo(); private: diff --git a/widget/src/cocoa/GfxInfo.h b/widget/src/cocoa/GfxInfo.h index d07f2637a79a..eaec9a62929c 100644 --- a/widget/src/cocoa/GfxInfo.h +++ b/widget/src/cocoa/GfxInfo.h @@ -85,9 +85,9 @@ protected: virtual nsresult GetFeatureStatusImpl(PRInt32 aFeature, PRInt32 *aStatus, nsAString & aSuggestedDriverVersion, - const nsTArray& aDriverInfo, + GfxDriverInfo* aDriverInfo = nsnull, OperatingSystem* aOS = nsnull); - virtual const nsTArray& GetGfxDriverInfo(); + virtual const GfxDriverInfo* GetGfxDriverInfo(); private: diff --git a/widget/src/cocoa/GfxInfo.mm b/widget/src/cocoa/GfxInfo.mm index 9c7ee651c9fb..bb8f18e9d91d 100644 --- a/widget/src/cocoa/GfxInfo.mm +++ b/widget/src/cocoa/GfxInfo.mm @@ -347,20 +347,30 @@ GfxInfo::AddCrashReportAnnotations() #endif } -// We don't support checking driver versions on Mac. -#define IMPLEMENT_MAC_DRIVER_BLOCKLIST(os, vendor, device, features, blockOn) \ - APPEND_TO_DRIVER_BLOCKLIST(os, vendor, device, features, blockOn, \ - DRIVER_UNKNOWN_COMPARISON, V(0,0,0,0), "") +static GfxDriverInfo gDriverInfo[] = { + // We don't support checking driver versions on Mac. + #define IMPLEMENT_MAC_DRIVER_BLOCKLIST(os, vendor, device, features, blockOn) \ + GfxDriverInfo(os, vendor, device, features, blockOn, \ + DRIVER_UNKNOWN_COMPARISON, V(0,0,0,0), ""), -const nsTArray& + // Example use of macro. + //IMPLEMENT_MAC_DRIVER_BLOCKLIST(DRIVER_OS_OS_X_10_7, + // GfxDriverInfo::vendorATI, GfxDriverInfo::allDevices, + // GfxDriverInfo::allFeatures, nsIGfxInfo::FEATURE_BLOCKED_OS_VERSION) + + // Block all ATI cards from using MSAA, except for two devices that have + // special exceptions in the GetFeatureStatusImpl() function. + IMPLEMENT_MAC_DRIVER_BLOCKLIST(DRIVER_OS_ALL, + GfxDriverInfo::vendorATI, GfxDriverInfo::allDevices, + nsIGfxInfo::FEATURE_WEBGL_MSAA, nsIGfxInfo::FEATURE_BLOCKED_OS_VERSION) + + GfxDriverInfo() +}; + +const GfxDriverInfo* GfxInfo::GetGfxDriverInfo() { - if (!mDriverInfo->Length()) { - IMPLEMENT_MAC_DRIVER_BLOCKLIST(DRIVER_OS_ALL, - GfxDriverInfo::vendorATI, GfxDriverInfo::allDevices, - nsIGfxInfo::FEATURE_WEBGL_MSAA, nsIGfxInfo::FEATURE_BLOCKED_OS_VERSION); - } - return *mDriverInfo; + return &gDriverInfo[0]; } static OperatingSystem @@ -382,14 +392,14 @@ nsresult GfxInfo::GetFeatureStatusImpl(PRInt32 aFeature, PRInt32* aStatus, nsAString& aSuggestedDriverVersion, - const nsTArray& aDriverInfo, + GfxDriverInfo* aDriverInfo /* = nsnull */, OperatingSystem* aOS /* = nsnull */) { NS_ENSURE_ARG_POINTER(aStatus); aSuggestedDriverVersion.SetIsVoid(true); - PRInt32 status = nsIGfxInfo::FEATURE_STATUS_UNKNOWN; + PRInt32 status = nsIGfxInfo::FEATURE_NO_INFO; OperatingSystem os = OSXVersionToOperatingSystem(nsToolkit::OSXVersion()); diff --git a/widget/src/windows/GfxInfo.cpp b/widget/src/windows/GfxInfo.cpp index 0123b77ffaa9..39f3f8cc6468 100644 --- a/widget/src/windows/GfxInfo.cpp +++ b/widget/src/windows/GfxInfo.cpp @@ -794,6 +794,118 @@ GfxInfo::AddCrashReportAnnotations() #endif } +static const GfxDriverInfo gDriverInfo[] = { + /* + * Notice that the first match defines the result. So always implement special cases firsts and general case last. + */ + + /* + * NVIDIA entries + */ + GfxDriverInfo( DRIVER_OS_WINDOWS_XP, + GfxDriverInfo::vendorNVIDIA, GfxDriverInfo::allDevices, + GfxDriverInfo::allFeatures, nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION, + DRIVER_LESS_THAN, V(6,14,12,5721), "257.21" ), + GfxDriverInfo( DRIVER_OS_WINDOWS_VISTA, + GfxDriverInfo::vendorNVIDIA, GfxDriverInfo::allDevices, + GfxDriverInfo::allFeatures, nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION, + DRIVER_LESS_THAN, V(8,17,12,5721), "257.21" ), + GfxDriverInfo( DRIVER_OS_WINDOWS_7, + GfxDriverInfo::vendorNVIDIA, GfxDriverInfo::allDevices, + GfxDriverInfo::allFeatures, nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION, + DRIVER_LESS_THAN, V(8,17,12,5721), "257.21" ), + + /* Disable D3D9 layers on NVIDIA 6100/6150/6200 series due to glitches + * whilst scrolling. See bugs: 612007, 644787 & 645872. + */ + GfxDriverInfo( DRIVER_OS_ALL, + GfxDriverInfo::vendorNVIDIA, (GfxDeviceFamily) deviceFamilyNvidiaBlockD3D9Layers, + nsIGfxInfo::FEATURE_DIRECT3D_9_LAYERS, nsIGfxInfo::FEATURE_BLOCKED_DEVICE, + DRIVER_LESS_THAN, GfxDriverInfo::allDriverVersions ), + + /* + * AMD/ATI entries + */ + GfxDriverInfo( DRIVER_OS_ALL, + GfxDriverInfo::vendorATI, GfxDriverInfo::allDevices, + GfxDriverInfo::allFeatures, nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION, + DRIVER_LESS_THAN, V(8,741,0,0), "10.6" ), + GfxDriverInfo( DRIVER_OS_ALL, + GfxDriverInfo::vendorAMD, GfxDriverInfo::allDevices, + GfxDriverInfo::allFeatures, nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION, + DRIVER_LESS_THAN, V(8,741,0,0), "10.6" ), + + /* OpenGL on any ATI/AMD hardware is discouraged + * See: + * bug 619773 - WebGL: Crash with blue screen : "NMI: Parity Check / Memory Parity Error" + * bugs 584403, 584404, 620924 - crashes in atioglxx + * + many complaints about incorrect rendering + */ + GfxDriverInfo( DRIVER_OS_ALL, + GfxDriverInfo::vendorATI, GfxDriverInfo::allDevices, + nsIGfxInfo::FEATURE_OPENGL_LAYERS, nsIGfxInfo::FEATURE_DISCOURAGED, + DRIVER_LESS_THAN, GfxDriverInfo::allDriverVersions ), + GfxDriverInfo( DRIVER_OS_ALL, + GfxDriverInfo::vendorATI, GfxDriverInfo::allDevices, + nsIGfxInfo::FEATURE_WEBGL_OPENGL, nsIGfxInfo::FEATURE_DISCOURAGED, + DRIVER_LESS_THAN, GfxDriverInfo::allDriverVersions ), + GfxDriverInfo( DRIVER_OS_ALL, + GfxDriverInfo::vendorAMD, GfxDriverInfo::allDevices, + nsIGfxInfo::FEATURE_OPENGL_LAYERS, nsIGfxInfo::FEATURE_DISCOURAGED, + DRIVER_LESS_THAN, GfxDriverInfo::allDriverVersions ), + GfxDriverInfo( DRIVER_OS_ALL, + GfxDriverInfo::vendorAMD, GfxDriverInfo::allDevices, + nsIGfxInfo::FEATURE_WEBGL_OPENGL, nsIGfxInfo::FEATURE_DISCOURAGED, + DRIVER_LESS_THAN, GfxDriverInfo::allDriverVersions ), + + /* + * Intel entries + */ + + /* implement the blocklist from bug 594877 + * Block all features on any drivers before this, as there's a crash when a MS Hotfix is installed. + * The crash itself is Direct2D-related, but for safety we block all features. + */ + #define IMPLEMENT_INTEL_DRIVER_BLOCKLIST(winVer, devFamily, driverVer) \ + GfxDriverInfo( winVer, \ + GfxDriverInfo::vendorIntel, (GfxDeviceFamily) devFamily, \ + GfxDriverInfo::allFeatures, nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION, \ + DRIVER_LESS_THAN, driverVer ), + + IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_XP, deviceFamilyIntelGMA500, V(6,14,11,1018)) + IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_XP, deviceFamilyIntelGMA900, V(6,14,10,4764)) + IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_XP, deviceFamilyIntelGMA950, V(6,14,10,4926)) + IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_XP, deviceFamilyIntelGMA3150, V(6,14,10,5260)) + IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_XP, deviceFamilyIntelGMAX3000, V(6,14,10,5218)) + IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_XP, deviceFamilyIntelGMAX4500HD, V(6,14,10,5284)) + + IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_VISTA, deviceFamilyIntelGMA500, V(7,14,10,1006)) + IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_VISTA, deviceFamilyIntelGMA900, GfxDriverInfo::allDriverVersions) + IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_VISTA, deviceFamilyIntelGMA950, V(7,14,10,1504)) + IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_VISTA, deviceFamilyIntelGMA3150, V(7,14,10,2124)) + IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_VISTA, deviceFamilyIntelGMAX3000, V(7,15,10,1666)) + IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_VISTA, deviceFamilyIntelGMAX4500HD, V(8,15,10,2202)) + + IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_7, deviceFamilyIntelGMA500, V(5,0,0,2026)) + IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_7, deviceFamilyIntelGMA900, GfxDriverInfo::allDriverVersions) + IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_7, deviceFamilyIntelGMA950, V(8,15,10,1930)) + IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_7, deviceFamilyIntelGMA3150, V(8,14,10,2117)) + IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_7, deviceFamilyIntelGMAX3000, V(8,15,10,1930)) + IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_7, deviceFamilyIntelGMAX4500HD, V(8,15,10,2202)) + + /* OpenGL on any Intel hardware is discouraged */ + GfxDriverInfo( DRIVER_OS_ALL, + GfxDriverInfo::vendorIntel, GfxDriverInfo::allDevices, + nsIGfxInfo::FEATURE_OPENGL_LAYERS, nsIGfxInfo::FEATURE_DISCOURAGED, + DRIVER_LESS_THAN, GfxDriverInfo::allDriverVersions ), + GfxDriverInfo( DRIVER_OS_ALL, + GfxDriverInfo::vendorIntel, GfxDriverInfo::allDevices, + nsIGfxInfo::FEATURE_WEBGL_OPENGL, nsIGfxInfo::FEATURE_DISCOURAGED, + DRIVER_LESS_THAN, GfxDriverInfo::allDriverVersions ), + + GfxDriverInfo() +}; + static OperatingSystem WindowsVersionToOperatingSystem(PRInt32 aWindowsVersion) { @@ -814,149 +926,45 @@ WindowsVersionToOperatingSystem(PRInt32 aWindowsVersion) }; } -const nsTArray& +const GfxDriverInfo* GfxInfo::GetGfxDriverInfo() { - if (!mDriverInfo->Length()) { - /* - * NVIDIA entries - */ - APPEND_TO_DRIVER_BLOCKLIST( DRIVER_OS_WINDOWS_XP, - GfxDriverInfo::vendorNVIDIA, GfxDriverInfo::allDevices, - GfxDriverInfo::allFeatures, nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION, - DRIVER_LESS_THAN, V(6,14,12,5721), "257.21" ); - APPEND_TO_DRIVER_BLOCKLIST( DRIVER_OS_WINDOWS_VISTA, - GfxDriverInfo::vendorNVIDIA, GfxDriverInfo::allDevices, - GfxDriverInfo::allFeatures, nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION, - DRIVER_LESS_THAN, V(8,17,12,5721), "257.21" ); - APPEND_TO_DRIVER_BLOCKLIST( DRIVER_OS_WINDOWS_7, - GfxDriverInfo::vendorNVIDIA, GfxDriverInfo::allDevices, - GfxDriverInfo::allFeatures, nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION, - DRIVER_LESS_THAN, V(8,17,12,5721), "257.21" ); - - /* Disable D3D9 layers on NVIDIA 6100/6150/6200 series due to glitches - * whilst scrolling. See bugs: 612007, 644787 & 645872. - */ - APPEND_TO_DRIVER_BLOCKLIST2( DRIVER_OS_ALL, - GfxDriverInfo::vendorNVIDIA, (GfxDeviceFamily) GfxDriverInfo::GetDeviceFamily(DeviceFamily::NvidiaBlockD3D9Layers), - nsIGfxInfo::FEATURE_DIRECT3D_9_LAYERS, nsIGfxInfo::FEATURE_BLOCKED_DEVICE, - DRIVER_LESS_THAN, GfxDriverInfo::allDriverVersions ); - - /* - * AMD/ATI entries - */ - APPEND_TO_DRIVER_BLOCKLIST( DRIVER_OS_ALL, - GfxDriverInfo::vendorATI, GfxDriverInfo::allDevices, - GfxDriverInfo::allFeatures, nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION, - DRIVER_LESS_THAN, V(8,741,0,0), "10.6" ); - APPEND_TO_DRIVER_BLOCKLIST( DRIVER_OS_ALL, - GfxDriverInfo::vendorAMD, GfxDriverInfo::allDevices, - GfxDriverInfo::allFeatures, nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION, - DRIVER_LESS_THAN, V(8,741,0,0), "10.6" ); - - /* OpenGL on any ATI/AMD hardware is discouraged - * See: - * bug 619773 - WebGL: Crash with blue screen : "NMI: Parity Check / Memory Parity Error" - * bugs 584403, 584404, 620924 - crashes in atioglxx - * + many complaints about incorrect rendering - */ - APPEND_TO_DRIVER_BLOCKLIST2( DRIVER_OS_ALL, - GfxDriverInfo::vendorATI, GfxDriverInfo::allDevices, - nsIGfxInfo::FEATURE_OPENGL_LAYERS, nsIGfxInfo::FEATURE_DISCOURAGED, - DRIVER_LESS_THAN, GfxDriverInfo::allDriverVersions ); - APPEND_TO_DRIVER_BLOCKLIST2( DRIVER_OS_ALL, - GfxDriverInfo::vendorATI, GfxDriverInfo::allDevices, - nsIGfxInfo::FEATURE_WEBGL_OPENGL, nsIGfxInfo::FEATURE_DISCOURAGED, - DRIVER_LESS_THAN, GfxDriverInfo::allDriverVersions ); - APPEND_TO_DRIVER_BLOCKLIST2( DRIVER_OS_ALL, - GfxDriverInfo::vendorAMD, GfxDriverInfo::allDevices, - nsIGfxInfo::FEATURE_OPENGL_LAYERS, nsIGfxInfo::FEATURE_DISCOURAGED, - DRIVER_LESS_THAN, GfxDriverInfo::allDriverVersions ); - APPEND_TO_DRIVER_BLOCKLIST2( DRIVER_OS_ALL, - GfxDriverInfo::vendorAMD, GfxDriverInfo::allDevices, - nsIGfxInfo::FEATURE_WEBGL_OPENGL, nsIGfxInfo::FEATURE_DISCOURAGED, - DRIVER_LESS_THAN, GfxDriverInfo::allDriverVersions ); - - /* - * Intel entries - */ - - /* implement the blocklist from bug 594877 - * Block all features on any drivers before this, as there's a crash when a MS Hotfix is installed. - * The crash itself is Direct2D-related, but for safety we block all features. - */ - #define IMPLEMENT_INTEL_DRIVER_BLOCKLIST(winVer, devFamily, driverVer) \ - APPEND_TO_DRIVER_BLOCKLIST2( winVer, \ - GfxDriverInfo::vendorIntel, (GfxDeviceFamily) GfxDriverInfo::GetDeviceFamily(devFamily), \ - GfxDriverInfo::allFeatures, nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION, \ - DRIVER_LESS_THAN, driverVer ) - - IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_XP, DeviceFamily::IntelGMA500, V(6,14,11,1018)); - IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_XP, DeviceFamily::IntelGMA900, V(6,14,10,4764)); - IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_XP, DeviceFamily::IntelGMA950, V(6,14,10,4926)); - IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_XP, DeviceFamily::IntelGMA3150, V(6,14,10,5260)); - IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_XP, DeviceFamily::IntelGMAX3000, V(6,14,10,5218)); - IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_XP, DeviceFamily::IntelGMAX4500HD, V(6,14,10,5284)); - - IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_VISTA, DeviceFamily::IntelGMA500, V(7,14,10,1006)); - IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_VISTA, DeviceFamily::IntelGMA900, GfxDriverInfo::allDriverVersions); - IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_VISTA, DeviceFamily::IntelGMA950, V(7,14,10,1504)); - IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_VISTA, DeviceFamily::IntelGMA3150, V(7,14,10,2124)); - IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_VISTA, DeviceFamily::IntelGMAX3000, V(7,15,10,1666)); - IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_VISTA, DeviceFamily::IntelGMAX4500HD, V(8,15,10,2202)); - - IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_7, DeviceFamily::IntelGMA500, V(5,0,0,2026)); - IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_7, DeviceFamily::IntelGMA900, GfxDriverInfo::allDriverVersions); - IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_7, DeviceFamily::IntelGMA950, V(8,15,10,1930)); - IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_7, DeviceFamily::IntelGMA3150, V(8,14,10,2117)); - IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_7, DeviceFamily::IntelGMAX3000, V(8,15,10,1930)); - IMPLEMENT_INTEL_DRIVER_BLOCKLIST(DRIVER_OS_WINDOWS_7, DeviceFamily::IntelGMAX4500HD, V(8,15,10,2202)); - - /* OpenGL on any Intel hardware is discouraged */ - APPEND_TO_DRIVER_BLOCKLIST2( DRIVER_OS_ALL, - GfxDriverInfo::vendorIntel, GfxDriverInfo::allDevices, - nsIGfxInfo::FEATURE_OPENGL_LAYERS, nsIGfxInfo::FEATURE_DISCOURAGED, - DRIVER_LESS_THAN, GfxDriverInfo::allDriverVersions ); - APPEND_TO_DRIVER_BLOCKLIST2( DRIVER_OS_ALL, - GfxDriverInfo::vendorIntel, GfxDriverInfo::allDevices, - nsIGfxInfo::FEATURE_WEBGL_OPENGL, nsIGfxInfo::FEATURE_DISCOURAGED, - DRIVER_LESS_THAN, GfxDriverInfo::allDriverVersions ); - } - return *mDriverInfo; + return &gDriverInfo[0]; } nsresult GfxInfo::GetFeatureStatusImpl(PRInt32 aFeature, PRInt32 *aStatus, nsAString & aSuggestedDriverVersion, - const nsTArray& aDriverInfo, + GfxDriverInfo* aDriverInfo /* = nsnull */, OperatingSystem* aOS /* = nsnull */) { + *aStatus = nsIGfxInfo::FEATURE_NO_INFO; aSuggestedDriverVersion.SetIsVoid(true); - PRInt32 status = nsIGfxInfo::FEATURE_STATUS_UNKNOWN; + PRInt32 status = nsIGfxInfo::FEATURE_NO_INFO; - PRUint32 adapterVendorID = 0; + PRUint32 adapterVendor = 0; PRUint32 adapterDeviceID = 0; nsAutoString adapterDriverVersionString; - if (NS_FAILED(GetAdapterVendorID(&adapterVendorID)) || + if (NS_FAILED(GetAdapterVendorID(&adapterVendor)) || NS_FAILED(GetAdapterDeviceID(&adapterDeviceID)) || NS_FAILED(GetAdapterDriverVersion(adapterDriverVersionString))) { return NS_ERROR_FAILURE; } - if (adapterVendorID != GfxDriverInfo::vendorIntel && - adapterVendorID != GfxDriverInfo::vendorNVIDIA && - adapterVendorID != GfxDriverInfo::vendorAMD && - adapterVendorID != GfxDriverInfo::vendorATI && + if (adapterVendor != GfxDriverInfo::vendorIntel && + adapterVendor != GfxDriverInfo::vendorNVIDIA && + adapterVendor != GfxDriverInfo::vendorAMD && + adapterVendor != GfxDriverInfo::vendorATI && // FIXME - these special hex values are currently used in xpcshell tests introduced by // bug 625160 patch 8/8. Maybe these tests need to be adjusted now that we're only whitelisting // intel/ati/nvidia. - adapterVendorID != 0xabcd && - adapterVendorID != 0xdcba && - adapterVendorID != 0xabab && - adapterVendorID != 0xdcdc) + adapterVendor != 0xabcd && + adapterVendor != 0xdcba && + adapterVendor != 0xabab && + adapterVendor != 0xdcdc) { *aStatus = FEATURE_BLOCKED_DEVICE; return NS_OK; @@ -966,19 +974,7 @@ GfxInfo::GetFeatureStatusImpl(PRInt32 aFeature, if (!ParseDriverVersion(adapterDriverVersionString, &driverVersion)) { return NS_ERROR_FAILURE; } - - // special-case the WinXP test slaves: they have out-of-date drivers, but we still want to - // whitelist them, actually we do know that this combination of device and driver version - // works well. - if (mWindowsVersion == gfxWindowsPlatform::kWindowsXP && - adapterVendorID == GfxDriverInfo::vendorNVIDIA && - adapterDeviceID == 0x0861 && // GeForce 9400 - driverVersion == V(6,14,11,7756)) - { - *aStatus = FEATURE_NO_INFO; - return NS_OK; - } - + if (aFeature == FEATURE_DIRECT3D_9_LAYERS && mWindowsVersion < gfxWindowsPlatform::kWindowsXP) { @@ -1002,6 +998,12 @@ GfxInfo::GetFeatureStatusImpl(PRInt32 aFeature, if (os == DRIVER_OS_WINDOWS_SERVER_2003) os = DRIVER_OS_WINDOWS_XP; + const GfxDriverInfo *info; + if (aDriverInfo) + info = aDriverInfo; + else + info = &gDriverInfo[0]; + if (mHasDriverVersionMismatch) { if (aFeature == nsIGfxInfo::FEATURE_DIRECT3D_10_LAYERS || aFeature == nsIGfxInfo::FEATURE_DIRECT3D_10_1_LAYERS || diff --git a/widget/src/windows/GfxInfo.h b/widget/src/windows/GfxInfo.h index 178e9c015e84..f193f807f197 100644 --- a/widget/src/windows/GfxInfo.h +++ b/widget/src/windows/GfxInfo.h @@ -92,9 +92,9 @@ protected: virtual nsresult GetFeatureStatusImpl(PRInt32 aFeature, PRInt32 *aStatus, nsAString & aSuggestedDriverVersion, - const nsTArray& aDriverInfo, + GfxDriverInfo* aDriverInfo = nsnull, OperatingSystem* aOS = nsnull); - virtual const nsTArray& GetGfxDriverInfo(); + virtual const GfxDriverInfo* GetGfxDriverInfo(); private: diff --git a/widget/src/xpwidgets/GfxDriverInfo.cpp b/widget/src/xpwidgets/GfxDriverInfo.cpp index 12dcc497b2d2..6a744f95ce53 100644 --- a/widget/src/xpwidgets/GfxDriverInfo.cpp +++ b/widget/src/xpwidgets/GfxDriverInfo.cpp @@ -117,131 +117,3 @@ GfxDriverInfo::~GfxDriverInfo() if (mDeleteDevices) delete[] mDevices; } - -const GfxDeviceFamily GfxDriverInfo::GetDeviceFamily(DeviceFamily id) -{ - switch (id) { - case IntelGMA500: { - static const PRUint32 intelGMA500[] = { - 0x8108, /* IntelGMA500_1 */ - 0x8109, /* IntelGMA500_2 */ - 0 - }; - return (const GfxDeviceFamily) &intelGMA500[0]; - } - case IntelGMA900: { - static const PRUint32 intelGMA900[] = { - 0x2582, /* IntelGMA900_1 */ - 0x2782, /* IntelGMA900_2 */ - 0x2592, /* IntelGMA900_3 */ - 0x2792, /* IntelGMA900_4 */ - 0 - }; - return (const GfxDeviceFamily) &intelGMA900[0]; - } - case IntelGMA950: { - static const PRUint32 intelGMA950[] = { - 0x2772, /* Intel945G_1 */ - 0x2776, /* Intel945G_2 */ - 0x27A2, /* Intel945_1 */ - 0x27A6, /* Intel945_2 */ - 0x27AE, /* Intel945_3 */ - 0 - }; - return (const GfxDeviceFamily) &intelGMA950[0]; - } - case IntelGMA3150: { - static const PRUint32 intelGMA3150[] = { - 0xA001, /* IntelGMA3150_Nettop_1 */ - 0xA002, /* IntelGMA3150_Nettop_2 */ - 0xA011, /* IntelGMA3150_Netbook_1 */ - 0xA012, /* IntelGMA3150_Netbook_2 */ - 0 - }; - return (const GfxDeviceFamily) &intelGMA3150[0]; - } - case IntelGMAX3000: { - static const PRUint32 intelGMAX3000[] = { - 0x2972, /* Intel946GZ_1 */ - 0x2973, /* Intel946GZ_2 */ - 0x2982, /* IntelG35_1 */ - 0x2983, /* IntelG35_2 */ - 0x2992, /* IntelQ965_1 */ - 0x2993, /* IntelQ965_2 */ - 0x29A2, /* IntelG965_1 */ - 0x29A3, /* IntelG965_2 */ - 0x29B2, /* IntelQ35_1 */ - 0x29B3, /* IntelQ35_2 */ - 0x29C2, /* IntelG33_1 */ - 0x29C3, /* IntelG33_2 */ - 0x29D2, /* IntelQ33_1 */ - 0x29D3, /* IntelQ33_2 */ - 0x2A02, /* IntelGL960_1 */ - 0x2A03, /* IntelGL960_2 */ - 0x2A12, /* IntelGM965_1 */ - 0x2A13, /* IntelGM965_2 */ - 0 - }; - return (const GfxDeviceFamily) &intelGMAX3000[0]; - } - case IntelGMAX4500HD: { - static const PRUint32 intelGMAX4500HD[] = { - 0x2A42, /* IntelGMA4500MHD_1 */ - 0x2A43, /* IntelGMA4500MHD_2 */ - 0x2E42, /* IntelB43_1 */ - 0x2E43, /* IntelB43_2 */ - 0x2E92, /* IntelB43_3 */ - 0x2E93, /* IntelB43_4 */ - 0x2E32, /* IntelG41_1 */ - 0x2E33, /* IntelG41_2 */ - 0x2E22, /* IntelG45_1 */ - 0x2E23, /* IntelG45_2 */ - 0x2E12, /* IntelQ45_1 */ - 0x2E13, /* IntelQ45_2 */ - 0x0042, /* IntelHDGraphics */ - 0x0046, /* IntelMobileHDGraphics */ - 0x0102, /* IntelSandyBridge_1 */ - 0x0106, /* IntelSandyBridge_2 */ - 0x0112, /* IntelSandyBridge_3 */ - 0x0116, /* IntelSandyBridge_4 */ - 0x0122, /* IntelSandyBridge_5 */ - 0x0126, /* IntelSandyBridge_6 */ - 0x010A, /* IntelSandyBridge_7 */ - 0x0080, /* IntelIvyBridge */ - 0 - }; - return (const GfxDeviceFamily) &intelGMAX4500HD[0]; - } - case NvidiaBlockD3D9Layers: { - // Glitches whilst scrolling (see bugs 612007, 644787, 645872) - static const PRUint32 nvidiaBlockD3D9Layers[] = { - 0x00f3, /* NV43 [GeForce 6200 (TM)] */ - 0x0146, /* NV43 [Geforce Go 6600TE/6200TE (TM)] */ - 0x014f, /* NV43 [GeForce 6200 (TM)] */ - 0x0161, /* NV44 [GeForce 6200 TurboCache (TM)] */ - 0x0162, /* NV44 [GeForce 6200SE TurboCache (TM)] */ - 0x0163, /* NV44 [GeForce 6200 LE (TM)] */ - 0x0164, /* NV44 [GeForce Go 6200 (TM)] */ - 0x0167, /* NV43 [GeForce Go 6200/6400 (TM)] */ - 0x0168, /* NV43 [GeForce Go 6200/6400 (TM)] */ - 0x0169, /* NV44 [GeForce 6250 (TM)] */ - 0x0222, /* NV44 [GeForce 6200 A-LE (TM)] */ - 0x0240, /* C51PV [GeForce 6150 (TM)] */ - 0x0241, /* C51 [GeForce 6150 LE (TM)] */ - 0x0244, /* C51 [Geforce Go 6150 (TM)] */ - 0x0245, /* C51 [Quadro NVS 210S/GeForce 6150LE (TM)] */ - 0x0247, /* C51 [GeForce Go 6100 (TM)] */ - 0x03d0, /* C61 [GeForce 6150SE nForce 430 (TM)] */ - 0x03d1, /* C61 [GeForce 6100 nForce 405 (TM)] */ - 0x03d2, /* C61 [GeForce 6100 nForce 400 (TM)] */ - 0x03d5, /* C61 [GeForce 6100 nForce 420 (TM)] */ - 0 - }; - return (const GfxDeviceFamily) &nvidiaBlockD3D9Layers[0]; - } - default: - NS_WARNING("Invalid device family"); - } - - return nsnull; -} diff --git a/widget/src/xpwidgets/GfxDriverInfo.h b/widget/src/xpwidgets/GfxDriverInfo.h index c446e45bbd5a..e9340a2bd867 100644 --- a/widget/src/xpwidgets/GfxDriverInfo.h +++ b/widget/src/xpwidgets/GfxDriverInfo.h @@ -43,11 +43,6 @@ #define V(a,b,c,d) GFX_DRIVER_VERSION(a,b,c,d) -#define APPEND_TO_DRIVER_BLOCKLIST(os, vendor, devices, feature, featureStatus, driverComparator, driverVersion, suggestedVersion) \ - mDriverInfo->AppendElement(GfxDriverInfo(os, vendor, devices, feature, featureStatus, driverComparator, driverVersion, suggestedVersion)) -#define APPEND_TO_DRIVER_BLOCKLIST2(os, vendor, devices, feature, featureStatus, driverComparator, driverVersion) \ - mDriverInfo->AppendElement(GfxDriverInfo(os, vendor, devices, feature, featureStatus, driverComparator, driverVersion)) - namespace mozilla { namespace widget { @@ -79,18 +74,112 @@ enum VersionComparisonOp { DRIVER_UNKNOWN_COMPARISON }; -enum DeviceFamily { - IntelGMA500, - IntelGMA900, - IntelGMA950, - IntelGMA3150, - IntelGMAX3000, - IntelGMAX4500HD, - NvidiaBlockD3D9Layers +static const PRUint32 deviceFamilyIntelGMA500[] = { + 0x8108, /* IntelGMA500_1 */ + 0x8109, /* IntelGMA500_2 */ + 0 +}; + +static const PRUint32 deviceFamilyIntelGMA900[] = { + 0x2582, /* IntelGMA900_1 */ + 0x2782, /* IntelGMA900_2 */ + 0x2592, /* IntelGMA900_3 */ + 0x2792, /* IntelGMA900_4 */ + 0 +}; + +static const PRUint32 deviceFamilyIntelGMA950[] = { + 0x2772, /* Intel945G_1 */ + 0x2776, /* Intel945G_2 */ + 0x27A2, /* Intel945_1 */ + 0x27A6, /* Intel945_2 */ + 0x27AE, /* Intel945_3 */ + 0 +}; + +static const PRUint32 deviceFamilyIntelGMA3150[] = { + 0xA001, /* IntelGMA3150_Nettop_1 */ + 0xA002, /* IntelGMA3150_Nettop_2 */ + 0xA011, /* IntelGMA3150_Netbook_1 */ + 0xA012, /* IntelGMA3150_Netbook_2 */ + 0 +}; + +static const PRUint32 deviceFamilyIntelGMAX3000[] = { + 0x2972, /* Intel946GZ_1 */ + 0x2973, /* Intel946GZ_2 */ + 0x2982, /* IntelG35_1 */ + 0x2983, /* IntelG35_2 */ + 0x2992, /* IntelQ965_1 */ + 0x2993, /* IntelQ965_2 */ + 0x29A2, /* IntelG965_1 */ + 0x29A3, /* IntelG965_2 */ + 0x29B2, /* IntelQ35_1 */ + 0x29B3, /* IntelQ35_2 */ + 0x29C2, /* IntelG33_1 */ + 0x29C3, /* IntelG33_2 */ + 0x29D2, /* IntelQ33_1 */ + 0x29D3, /* IntelQ33_2 */ + 0x2A02, /* IntelGL960_1 */ + 0x2A03, /* IntelGL960_2 */ + 0x2A12, /* IntelGM965_1 */ + 0x2A13, /* IntelGM965_2 */ + 0 +}; + +static const PRUint32 deviceFamilyIntelGMAX4500HD[] = { + 0x2A42, /* IntelGMA4500MHD_1 */ + 0x2A43, /* IntelGMA4500MHD_2 */ + 0x2E42, /* IntelB43_1 */ + 0x2E43, /* IntelB43_2 */ + 0x2E92, /* IntelB43_3 */ + 0x2E93, /* IntelB43_4 */ + 0x2E32, /* IntelG41_1 */ + 0x2E33, /* IntelG41_2 */ + 0x2E22, /* IntelG45_1 */ + 0x2E23, /* IntelG45_2 */ + 0x2E12, /* IntelQ45_1 */ + 0x2E13, /* IntelQ45_2 */ + 0x0042, /* IntelHDGraphics */ + 0x0046, /* IntelMobileHDGraphics */ + 0x0102, /* IntelSandyBridge_1 */ + 0x0106, /* IntelSandyBridge_2 */ + 0x0112, /* IntelSandyBridge_3 */ + 0x0116, /* IntelSandyBridge_4 */ + 0x0122, /* IntelSandyBridge_5 */ + 0x0126, /* IntelSandyBridge_6 */ + 0x010A, /* IntelSandyBridge_7 */ + 0x0080, /* IntelIvyBridge */ + 0 +}; + +// Glitches whilst scrolling (see bugs 612007, 644787, 645872) +static const PRUint32 deviceFamilyNvidiaBlockD3D9Layers[] = { + 0x00f3, /* NV43 [GeForce 6200 (TM)] */ + 0x0146, /* NV43 [Geforce Go 6600TE/6200TE (TM)] */ + 0x014f, /* NV43 [GeForce 6200 (TM)] */ + 0x0161, /* NV44 [GeForce 6200 TurboCache (TM)] */ + 0x0162, /* NV44 [GeForce 6200SE TurboCache (TM)] */ + 0x0163, /* NV44 [GeForce 6200 LE (TM)] */ + 0x0164, /* NV44 [GeForce Go 6200 (TM)] */ + 0x0167, /* NV43 [GeForce Go 6200/6400 (TM)] */ + 0x0168, /* NV43 [GeForce Go 6200/6400 (TM)] */ + 0x0169, /* NV44 [GeForce 6250 (TM)] */ + 0x0222, /* NV44 [GeForce 6200 A-LE (TM)] */ + 0x0240, /* C51PV [GeForce 6150 (TM)] */ + 0x0241, /* C51 [GeForce 6150 LE (TM)] */ + 0x0244, /* C51 [Geforce Go 6150 (TM)] */ + 0x0245, /* C51 [Quadro NVS 210S/GeForce 6150LE (TM)] */ + 0x0247, /* C51 [GeForce Go 6100 (TM)] */ + 0x03d0, /* C61 [GeForce 6150SE nForce 430 (TM)] */ + 0x03d1, /* C61 [GeForce 6100 nForce 405 (TM)] */ + 0x03d2, /* C61 [GeForce 6100 nForce 400 (TM)] */ + 0x03d5, /* C61 [GeForce 6100 nForce 420 (TM)] */ + 0 }; /* A zero-terminated array of devices to match, or all devices */ -typedef PRUint32* GfxDeviceFamily; +typedef PRUint32 *GfxDeviceFamily; struct GfxDriverInfo { @@ -137,8 +226,6 @@ struct GfxDriverInfo static PRUint32 vendorATI; const char *mSuggestedVersion; - - static const GfxDeviceFamily GetDeviceFamily(DeviceFamily id); }; #define GFX_DRIVER_VERSION(a,b,c,d) \ diff --git a/widget/src/xpwidgets/GfxInfoBase.cpp b/widget/src/xpwidgets/GfxInfoBase.cpp index a436cb21b231..b9609245ce47 100644 --- a/widget/src/xpwidgets/GfxInfoBase.cpp +++ b/widget/src/xpwidgets/GfxInfoBase.cpp @@ -48,7 +48,6 @@ #include "nsAutoPtr.h" #include "nsString.h" #include "mozilla/Services.h" -#include "mozilla/Observer.h" #include "nsIObserver.h" #include "nsIObserverService.h" #include "nsIDOMElement.h" @@ -61,52 +60,8 @@ #include "nsExceptionHandler.h" #endif -using namespace mozilla::widget; using namespace mozilla; -nsTArray* GfxInfoBase::mDriverInfo; -bool GfxInfoBase::mDriverInfoObserverInitialized; - -// Observes for shutdown so that the child GfxDriverInfo list is freed. -class ShutdownObserver : public nsIObserver -{ -public: - ShutdownObserver() {} - virtual ~ShutdownObserver() {} - - NS_DECL_ISUPPORTS - - NS_IMETHOD Observe(nsISupports *subject, const char *aTopic, - const PRUnichar *aData) - { - MOZ_ASSERT(strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0); - if (GfxInfoBase::mDriverInfo) { - delete GfxInfoBase::mDriverInfo; - GfxInfoBase::mDriverInfo = nsnull; - } - return NS_OK; - } -}; - -NS_IMPL_ISUPPORTS1(ShutdownObserver, nsIObserver); - -void InitGfxDriverInfoShutdownObserver() -{ - if (GfxInfoBase::mDriverInfoObserverInitialized) - return; - - GfxInfoBase::mDriverInfoObserverInitialized = true; - - nsCOMPtr observerService = services::GetObserverService(); - if (!observerService) { - NS_WARNING("Could not get observer service!"); - return; - } - - ShutdownObserver *obs = new ShutdownObserver(); - observerService->AddObserver(obs, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false); -} - extern "C" { void StoreSpline(int ax, int ay, int bx, int by, int cx, int cy, int dx, int dy); void CrashSpline(double tolerance, int ax, int ay, int bx, int by, int cx, int cy, int dx, int dy); @@ -383,8 +338,6 @@ BlacklistFeatureStatusToGfxFeatureStatus(const nsAString& aStatus) else if (aStatus == NS_LITERAL_STRING("BLOCKED_OS_VERSION")) return nsIGfxInfo::FEATURE_BLOCKED_OS_VERSION; - // Do not allow it to set STATUS_UNKNOWN. - return nsIGfxInfo::FEATURE_NO_INFO; } @@ -605,6 +558,12 @@ GfxInfoBase::Init() return NS_OK; } +static const GfxDriverInfo gDriverInfo[] = { + // No combinations that cause a crash on every OS. + GfxDriverInfo() +}; + + NS_IMETHODIMP GfxInfoBase::GetFeatureStatus(PRInt32 aFeature, PRInt32* aStatus NS_OUTPARAM) { @@ -612,145 +571,22 @@ GfxInfoBase::GetFeatureStatus(PRInt32 aFeature, PRInt32* aStatus NS_OUTPARAM) return NS_OK; nsString version; - nsTArray driverInfo; - return GetFeatureStatusImpl(aFeature, aStatus, version, driverInfo); -} - -PRInt32 -GfxInfoBase::FindBlocklistedDeviceInList(const nsTArray& info, - nsAString& aSuggestedVersion, - PRInt32 aFeature, - OperatingSystem os) -{ - PRInt32 status = nsIGfxInfo::FEATURE_STATUS_UNKNOWN; - - PRUint32 adapterVendorID = 0; - PRUint32 adapterDeviceID = 0; - nsAutoString adapterDriverVersionString; - if (NS_FAILED(GetAdapterVendorID(&adapterVendorID)) || - NS_FAILED(GetAdapterDeviceID(&adapterDeviceID)) || - NS_FAILED(GetAdapterDriverVersion(adapterDriverVersionString))) - { - return NS_OK; - } - - PRUint64 driverVersion; - ParseDriverVersion(adapterDriverVersionString, &driverVersion); - - PRUint32 i = 0; - for (; i < info.Length(); i++) { - if (info[i].mOperatingSystem != DRIVER_OS_ALL && - info[i].mOperatingSystem != os) - { - continue; - } - - if (info[i].mAdapterVendor != GfxDriverInfo::allAdapterVendors && - info[i].mAdapterVendor != adapterVendorID) { - continue; - } - - if (info[i].mDevices != GfxDriverInfo::allDevices) { - bool deviceMatches = false; - for (const PRUint32 *devices = info[i].mDevices; *devices; ++devices) { - if (*devices == adapterDeviceID) { - deviceMatches = true; - break; - } - } - - if (!deviceMatches) { - continue; - } - } - - bool match = false; - -#if !defined(XP_MACOSX) - switch (info[i].mComparisonOp) { - case DRIVER_LESS_THAN: - match = driverVersion < info[i].mDriverVersion; - break; - case DRIVER_LESS_THAN_OR_EQUAL: - match = driverVersion <= info[i].mDriverVersion; - break; - case DRIVER_GREATER_THAN: - match = driverVersion > info[i].mDriverVersion; - break; - case DRIVER_GREATER_THAN_OR_EQUAL: - match = driverVersion >= info[i].mDriverVersion; - break; - case DRIVER_EQUAL: - match = driverVersion == info[i].mDriverVersion; - break; - case DRIVER_NOT_EQUAL: - match = driverVersion != info[i].mDriverVersion; - break; - case DRIVER_BETWEEN_EXCLUSIVE: - match = driverVersion > info[i].mDriverVersion && driverVersion < info[i].mDriverVersionMax; - break; - case DRIVER_BETWEEN_INCLUSIVE: - match = driverVersion >= info[i].mDriverVersion && driverVersion <= info[i].mDriverVersionMax; - break; - case DRIVER_BETWEEN_INCLUSIVE_START: - match = driverVersion >= info[i].mDriverVersion && driverVersion < info[i].mDriverVersionMax; - break; - default: - NS_WARNING("Bogus op in GfxDriverInfo"); - break; - } -#else - // We don't care what driver version it was. We only check OS version and if - // the device matches. - match = true; -#endif - - if (match) { - if (info[i].mFeature == GfxDriverInfo::allFeatures || - info[i].mFeature == aFeature) - { - status = info[i].mFeatureStatus; - break; - } - } - } - - // Depends on Windows driver versioning. We don't pass a GfxDriverInfo object - // back to the Windows handler, so we must handle this here. -#if defined(XP_WIN) - if (status == FEATURE_BLOCKED_DRIVER_VERSION) { - if (info[i].mSuggestedVersion) { - aSuggestedVersion.AppendPrintf("%s", info[i].mSuggestedVersion); - } else if (info[i].mComparisonOp == DRIVER_LESS_THAN && - info[i].mDriverVersion != GfxDriverInfo::allDriverVersions) - { - aSuggestedVersion.AppendPrintf("%lld.%lld.%lld.%lld", - (info[i].mDriverVersion & 0xffff000000000000) >> 48, - (info[i].mDriverVersion & 0x0000ffff00000000) >> 32, - (info[i].mDriverVersion & 0x00000000ffff0000) >> 16, - (info[i].mDriverVersion & 0x000000000000ffff)); - } - } -#endif - - return status; + return GetFeatureStatusImpl(aFeature, aStatus, version); } nsresult GfxInfoBase::GetFeatureStatusImpl(PRInt32 aFeature, PRInt32* aStatus, - nsAString& aSuggestedVersion, - const nsTArray& aDriverInfo, + nsAString& aVersion, + GfxDriverInfo* aDriverInfo /* = nsnull */, OperatingSystem* aOS /* = nsnull */) { - if (*aStatus != nsIGfxInfo::FEATURE_STATUS_UNKNOWN) { + if (*aStatus != nsIGfxInfo::FEATURE_NO_INFO) { // Terminate now with the status determined by the derived type (OS-specific // code). return NS_OK; } - // If an operating system was provided by the derived GetFeatureStatusImpl, - // grab it here. Otherwise, the OS is unknown. OperatingSystem os = DRIVER_OS_UNKNOWN; if (aOS) os = *aOS; @@ -768,24 +604,137 @@ GfxInfoBase::GetFeatureStatusImpl(PRInt32 aFeature, PRUint64 driverVersion; ParseDriverVersion(adapterDriverVersionString, &driverVersion); - // Check if the device is blocked from the downloaded blocklist. If not, check - // the static list after that. This order is used so that we can later escape - // out of static blocks (i.e. if we were wrong or something was patched, we - // can back out our static block without doing a release). - InitGfxDriverInfoShutdownObserver(); - if (!mDriverInfo) - mDriverInfo = new nsTArray(); - PRInt32 status = FindBlocklistedDeviceInList(aDriverInfo, aSuggestedVersion, aFeature, os); - if (status == nsIGfxInfo::FEATURE_STATUS_UNKNOWN) { - status = FindBlocklistedDeviceInList(GetGfxDriverInfo(), aSuggestedVersion, aFeature, os); + // special-case the WinXP test slaves: they have out-of-date drivers, but we still want to + // whitelist them, actually we do know that this combination of device and driver version + // works well. + if (os == DRIVER_OS_WINDOWS_XP && + adapterVendorID == GfxDriverInfo::vendorNVIDIA && + adapterDeviceID == 0x0861 && // GeForce 9400 + driverVersion == V(6,14,11,7756)) + { + return NS_OK; } - // It's now done being processed. It's safe to set the status to NO_INFO. - if (status == nsIGfxInfo::FEATURE_STATUS_UNKNOWN) { - *aStatus = nsIGfxInfo::FEATURE_NO_INFO; - } else { - *aStatus = status; + PRInt32 status = *aStatus; + const GfxDriverInfo* info = aDriverInfo ? aDriverInfo : &gDriverInfo[0]; + // This code will operate in two modes: + // It first loops over the driver tuples stored locally in gDriverInfo, + // then loops over it a second time for the OS's specific list to check for + // all combinations that can lead to disabling a feature. + bool loopingOverOS = false; + while (true) { + if (!info->mOperatingSystem) { + if (loopingOverOS) + break; + else + { + // Mark us as looping over the OS driver tuples. + loopingOverOS = true; + // Get the GfxDriverInfo table from the OS subclass. + info = GetGfxDriverInfo(); + } + } + + if (info->mOperatingSystem != DRIVER_OS_ALL && + info->mOperatingSystem != os) + { + info++; + continue; + } + + if (info->mAdapterVendor != GfxDriverInfo::allAdapterVendors && + info->mAdapterVendor != adapterVendorID) { + info++; + continue; + } + + if (info->mDevices != GfxDriverInfo::allDevices) { + bool deviceMatches = false; + for (const PRUint32 *devices = info->mDevices; *devices; ++devices) { + if (*devices == adapterDeviceID) { + deviceMatches = true; + break; + } + } + + if (!deviceMatches) { + info++; + continue; + } + } + + bool match = false; + +#if !defined(XP_MACOSX) + switch (info->mComparisonOp) { + case DRIVER_LESS_THAN: + match = driverVersion < info->mDriverVersion; + break; + case DRIVER_LESS_THAN_OR_EQUAL: + match = driverVersion <= info->mDriverVersion; + break; + case DRIVER_GREATER_THAN: + match = driverVersion > info->mDriverVersion; + break; + case DRIVER_GREATER_THAN_OR_EQUAL: + match = driverVersion >= info->mDriverVersion; + break; + case DRIVER_EQUAL: + match = driverVersion == info->mDriverVersion; + break; + case DRIVER_NOT_EQUAL: + match = driverVersion != info->mDriverVersion; + break; + case DRIVER_BETWEEN_EXCLUSIVE: + match = driverVersion > info->mDriverVersion && driverVersion < info->mDriverVersionMax; + break; + case DRIVER_BETWEEN_INCLUSIVE: + match = driverVersion >= info->mDriverVersion && driverVersion <= info->mDriverVersionMax; + break; + case DRIVER_BETWEEN_INCLUSIVE_START: + match = driverVersion >= info->mDriverVersion && driverVersion < info->mDriverVersionMax; + break; + default: + NS_WARNING("Bogus op in GfxDriverInfo"); + break; + } +#else + // We don't care what driver version it was. We only check OS version and if + // the device matches. + match = true; +#endif + + if (match) { + if (info->mFeature == GfxDriverInfo::allFeatures || + info->mFeature == aFeature) + { + status = info->mFeatureStatus; + break; + } + } + + info++; } + + *aStatus = status; + + // Depends on Windows driver versioning. We don't pass a GfxDriverInfo object + // back to the Windows handler, so we must handle this here. +#if defined(XP_WIN) + if (status == FEATURE_BLOCKED_DRIVER_VERSION) { + if (info->mSuggestedVersion) { + aVersion.AppendPrintf("%s", info->mSuggestedVersion); + } else if (info->mComparisonOp == DRIVER_LESS_THAN && + info->mDriverVersion != GfxDriverInfo::allDriverVersions) + { + aVersion.AppendPrintf("%lld.%lld.%lld.%lld", + (info->mDriverVersion & 0xffff000000000000) >> 48, + (info->mDriverVersion & 0x0000ffff00000000) >> 32, + (info->mDriverVersion & 0x00000000ffff0000) >> 16, + (info->mDriverVersion & 0x000000000000ffff)); + } + } +#endif return NS_OK; } @@ -801,8 +750,7 @@ GfxInfoBase::GetFeatureSuggestedDriverVersion(PRInt32 aFeature, } PRInt32 status; - nsTArray driverInfo; - return GetFeatureStatusImpl(aFeature, &status, aVersion, driverInfo); + return GetFeatureStatusImpl(aFeature, &status, aVersion); } @@ -828,6 +776,10 @@ GfxInfoBase::EvaluateDownloadedBlacklist(nsTArray& aDriverInfo) 0 }; + // GetFeatureStatusImpl wants a zero-GfxDriverInfo terminated array. So, we + // append that to our list. + aDriverInfo.AppendElement(GfxDriverInfo()); + // For every feature we know about, we evaluate whether this blacklist has a // non-NO_INFO status. If it does, we set the pref we evaluate in // GetFeatureStatus above, so we don't need to hold on to this blacklist @@ -838,7 +790,7 @@ GfxInfoBase::EvaluateDownloadedBlacklist(nsTArray& aDriverInfo) nsAutoString suggestedVersion; if (NS_SUCCEEDED(GetFeatureStatusImpl(features[i], &status, suggestedVersion, - aDriverInfo))) { + aDriverInfo.Elements()))) { switch (status) { default: case nsIGfxInfo::FEATURE_NO_INFO: diff --git a/widget/src/xpwidgets/GfxInfoBase.h b/widget/src/xpwidgets/GfxInfoBase.h index 9f97aaf372d3..a5f784c1f024 100644 --- a/widget/src/xpwidgets/GfxInfoBase.h +++ b/widget/src/xpwidgets/GfxInfoBase.h @@ -86,13 +86,14 @@ public: // Ideally, Init() would be void-return, but the rules of // NS_GENERIC_FACTORY_CONSTRUCTOR_INIT require it be nsresult return. virtual nsresult Init(); + + // Gets the driver info table. Used by GfxInfoBase to check for general cases + // (while subclasses check for more specific ones). + virtual const GfxDriverInfo* GetGfxDriverInfo() = 0; // only useful on X11 NS_IMETHOD_(void) GetData() { } - static nsTArray* mDriverInfo; - static bool mDriverInfoObserverInitialized; - static void AddCollector(GfxInfoCollectorBase* collector); static void RemoveCollector(GfxInfoCollectorBase* collector); @@ -101,20 +102,11 @@ protected: virtual nsresult GetFeatureStatusImpl(PRInt32 aFeature, PRInt32* aStatus, nsAString& aSuggestedDriverVersion, - const nsTArray& aDriverInfo, + GfxDriverInfo* aDriverInfo = nsnull, OperatingSystem* aOS = nsnull); - // Gets the driver info table. Used by GfxInfoBase to check for general cases - // (while subclasses check for more specific ones). - virtual const nsTArray& GetGfxDriverInfo() = 0; - private: - virtual PRInt32 FindBlocklistedDeviceInList(const nsTArray& aDriverInfo, - nsAString& aSuggestedVersion, - PRInt32 aFeature, - OperatingSystem os); - void EvaluateDownloadedBlacklist(nsTArray& aDriverInfo); nsCString mFailures[9]; // The choice of 9 is Ehsan's diff --git a/widget/src/xpwidgets/GfxInfoX11.cpp b/widget/src/xpwidgets/GfxInfoX11.cpp index 1c7b94b2f87e..2bc377dfe9f0 100644 --- a/widget/src/xpwidgets/GfxInfoX11.cpp +++ b/widget/src/xpwidgets/GfxInfoX11.cpp @@ -246,30 +246,29 @@ static inline PRUint64 version(PRUint32 major, PRUint32 minor, PRUint32 revision return (PRUint64(major) << 32) + (PRUint64(minor) << 16) + PRUint64(revision); } -const nsTArray& +static GfxDriverInfo gDriverInfo[] = { + GfxDriverInfo() +}; + +const GfxDriverInfo* GfxInfo::GetGfxDriverInfo() { - // Nothing here yet. - //if (!mDriverInfo->Length()) { - // - //} - return *mDriverInfo; + return &gDriverInfo[0]; } nsresult GfxInfo::GetFeatureStatusImpl(PRInt32 aFeature, PRInt32 *aStatus, nsAString & aSuggestedDriverVersion, - const nsTArray& aDriverInfo, + GfxDriverInfo* aDriverInfo /* = nsnull */, OperatingSystem* aOS /* = nsnull */) { GetData(); - *aStatus = nsIGfxInfo::FEATURE_STATUS_UNKNOWN; + *aStatus = nsIGfxInfo::FEATURE_NO_INFO; aSuggestedDriverVersion.SetIsVoid(true); #ifdef MOZ_PLATFORM_MAEMO - *aStatus = nsIGfxInfo::FEATURE_NO_INFO; // on Maemo, the glxtest probe doesn't build, and we don't really need GfxInfo anyway return NS_OK; #endif @@ -292,7 +291,6 @@ GfxInfo::GetFeatureStatusImpl(PRInt32 aFeature, !strcmp(mRenderer.get(), "GeForce 9400/PCI/SSE2") && !strcmp(mVersion.get(), "3.2.0 NVIDIA 190.42")) { - *aStatus = nsIGfxInfo::FEATURE_NO_INFO; return NS_OK; } diff --git a/widget/src/xpwidgets/GfxInfoX11.h b/widget/src/xpwidgets/GfxInfoX11.h index 43690c00ca13..2525db0d98f3 100644 --- a/widget/src/xpwidgets/GfxInfoX11.h +++ b/widget/src/xpwidgets/GfxInfoX11.h @@ -84,9 +84,9 @@ protected: virtual nsresult GetFeatureStatusImpl(PRInt32 aFeature, PRInt32 *aStatus, nsAString & aSuggestedDriverVersion, - const nsTArray& aDriverInfo, + GfxDriverInfo* aDriverInfo = nsnull, OperatingSystem* aOS = nsnull); - virtual const nsTArray& GetGfxDriverInfo(); + virtual const GfxDriverInfo* GetGfxDriverInfo(); private: nsCString mVendor; From 89b6a36b037bacc67426461c6e6952e52320fb03 Mon Sep 17 00:00:00 2001 From: Robert Longson Date: Sat, 19 Nov 2011 08:53:35 +0000 Subject: [PATCH 41/63] Bug 698985 - make canvas/image-rendering-test.html more reliable. r=dholbert --- layout/reftests/canvas/image-rendering-test.html | 7 +++++-- layout/reftests/canvas/reftest.list | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/layout/reftests/canvas/image-rendering-test.html b/layout/reftests/canvas/image-rendering-test.html index ff51c0fff800..7b0861fcb272 100644 --- a/layout/reftests/canvas/image-rendering-test.html +++ b/layout/reftests/canvas/image-rendering-test.html @@ -3,13 +3,15 @@ Any copyright is dedicated to the Public Domain. http://creativecommons.org/licenses/publicdomain/ --> - + test image-rendering - + diff --git a/layout/reftests/canvas/reftest.list b/layout/reftests/canvas/reftest.list index f63a17bd4cf7..1b9a4f863f59 100644 --- a/layout/reftests/canvas/reftest.list +++ b/layout/reftests/canvas/reftest.list @@ -1,7 +1,7 @@ == default-size.html default-size-ref.html == size-1.html size-1-ref.html -fails-if(Android) == image-rendering-test.html image-rendering-ref.html # bug 698985 +== image-rendering-test.html image-rendering-ref.html == image-shadow.html image-shadow-ref.html asserts-if(cocoaWidget,0-2) == size-change-1.html size-change-1-ref.html From 6b9b01a12263a84c4991f362bb6d71f5f2fc63a5 Mon Sep 17 00:00:00 2001 From: Robert Longson Date: Sat, 19 Nov 2011 09:00:04 +0000 Subject: [PATCH 42/63] Bug 698195 - Use AfterSetAttr to process script href changes. r=dholbert --- .../svg/content/src/nsSVGScriptElement.cpp | 25 +++++++++---------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/content/svg/content/src/nsSVGScriptElement.cpp b/content/svg/content/src/nsSVGScriptElement.cpp index 3a54a32df546..e380a6dd87fe 100644 --- a/content/svg/content/src/nsSVGScriptElement.cpp +++ b/content/svg/content/src/nsSVGScriptElement.cpp @@ -90,13 +90,12 @@ public: // nsScriptElement virtual bool HasScriptContent(); - // nsSVGElement specializations: - virtual void DidChangeString(PRUint8 aAttrEnum); - // nsIContent specializations: virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent, nsIContent* aBindingParent, bool aCompileEventHandlers); + virtual nsresult AfterSetAttr(PRInt32 aNamespaceID, nsIAtom* aName, + const nsAString* aValue, bool aNotify); virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const; @@ -252,16 +251,6 @@ nsSVGScriptElement::HasScriptContent() //---------------------------------------------------------------------- // nsSVGElement methods -void -nsSVGScriptElement::DidChangeString(PRUint8 aAttrEnum) -{ - nsSVGScriptElementBase::DidChangeString(aAttrEnum); - - if (aAttrEnum == HREF) { - MaybeProcessScript(); - } -} - nsSVGElement::StringAttributesInfo nsSVGScriptElement::GetStringInfo() { @@ -289,3 +278,13 @@ nsSVGScriptElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent, return NS_OK; } +nsresult +nsSVGScriptElement::AfterSetAttr(PRInt32 aNamespaceID, nsIAtom* aName, + const nsAString* aValue, bool aNotify) +{ + if (aNamespaceID == kNameSpaceID_XLink && aName == nsGkAtoms::href) { + MaybeProcessScript(); + } + return nsSVGScriptElementBase::AfterSetAttr(aNamespaceID, aName, + aValue, aNotify); +} From 69999c8b43188bc0a9688a5114d104e99b86dfd9 Mon Sep 17 00:00:00 2001 From: Geoff Lankow Date: Sun, 20 Nov 2011 01:10:40 +1300 Subject: [PATCH 43/63] Back out changeset 453772872eeb (bug 668710) for bustage --- dom/tests/mochitest/bugs/test_bug61098.html | 2 +- testing/mochitest/jar.mn | 4 ++-- testing/mochitest/tests/SimpleTest/Makefile.in | 4 ++-- toolkit/content/tests/browser/common/Makefile.in | 1 + .../content/tests/browser/common/mockObjects.js | 0 toolkit/content/tests/browser/common/mockTransfer.js | 3 ++- 6 files changed, 8 insertions(+), 6 deletions(-) rename testing/mochitest/tests/SimpleTest/MockObjects.js => toolkit/content/tests/browser/common/mockObjects.js (100%) diff --git a/dom/tests/mochitest/bugs/test_bug61098.html b/dom/tests/mochitest/bugs/test_bug61098.html index 50be34d21947..b1c3952880ca 100644 --- a/dom/tests/mochitest/bugs/test_bug61098.html +++ b/dom/tests/mochitest/bugs/test_bug61098.html @@ -8,7 +8,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=61098 - + diff --git a/testing/mochitest/jar.mn b/testing/mochitest/jar.mn index 342f9637e5a3..fd2b0fd1d371 100644 --- a/testing/mochitest/jar.mn +++ b/testing/mochitest/jar.mn @@ -23,8 +23,8 @@ mochikit.jar: content/tests/SimpleTest/test.css (tests/SimpleTest/test.css) content/tests/SimpleTest/TestRunner.js (tests/SimpleTest/TestRunner.js) content/tests/SimpleTest/WindowSnapshot.js (tests/SimpleTest/WindowSnapshot.js) - content/tests/SimpleTest/MockObjects.js (tests/SimpleTest/MockObjects.js) - content/tests/SimpleTest/docshell_helpers.js (../../docshell/test/chrome/docshell_helpers.js) + content/tests/SimpleTest/mockObjects.js (../../toolkit/content/tests/browser/common/mockObjects.js) + content/tests/SimpleTest/docshell_helpers.js (../..//docshell/test/chrome/docshell_helpers.js) % resource mochikit %modules/ modules/MockFilePicker.jsm (MockFilePicker.jsm) diff --git a/testing/mochitest/tests/SimpleTest/Makefile.in b/testing/mochitest/tests/SimpleTest/Makefile.in index 79557523c4dd..87502e97b66a 100644 --- a/testing/mochitest/tests/SimpleTest/Makefile.in +++ b/testing/mochitest/tests/SimpleTest/Makefile.in @@ -53,8 +53,8 @@ _SIMPLETEST_FILES = MozillaLogger.js \ WindowSnapshot.js \ specialpowersAPI.js \ SpecialPowersObserverAPI.js \ - MockObjects.js \ - $(DEPTH)/docshell/test/chrome/docshell_helpers.js \ + $(DEPTH)/toolkit/content/tests/browser/common/mockObjects.js \ + $(DEPTH)/docshell/test/chrome/docshell_helpers.js \ $(NULL) libs:: $(_SIMPLETEST_FILES) diff --git a/toolkit/content/tests/browser/common/Makefile.in b/toolkit/content/tests/browser/common/Makefile.in index 333abd319c9e..9d8e2f9be1ae 100644 --- a/toolkit/content/tests/browser/common/Makefile.in +++ b/toolkit/content/tests/browser/common/Makefile.in @@ -45,6 +45,7 @@ include $(DEPTH)/config/autoconf.mk include $(topsrcdir)/config/rules.mk _COMMON_FILES = \ + mockObjects.js \ mockTransfer.js \ $(NULL) diff --git a/testing/mochitest/tests/SimpleTest/MockObjects.js b/toolkit/content/tests/browser/common/mockObjects.js similarity index 100% rename from testing/mochitest/tests/SimpleTest/MockObjects.js rename to toolkit/content/tests/browser/common/mockObjects.js diff --git a/toolkit/content/tests/browser/common/mockTransfer.js b/toolkit/content/tests/browser/common/mockTransfer.js index b0c22c90ea8a..bdcd1deeaa1e 100644 --- a/toolkit/content/tests/browser/common/mockTransfer.js +++ b/toolkit/content/tests/browser/common/mockTransfer.js @@ -36,7 +36,8 @@ Cc["@mozilla.org/moz/jssubscript-loader;1"] .getService(Ci.mozIJSSubScriptLoader) - .loadSubScript("chrome://mochikit/content/tests/SimpleTest/MockObjects.js", this); + .loadSubScript("chrome://mochitests/content/browser/toolkit/content/tests/browser/common/mockObjects.js", + this); var mockTransferCallback; From a705a3e3c625c60cd1b7aef80d6b1f5acb3644b1 Mon Sep 17 00:00:00 2001 From: Paolo Amadini Date: Sat, 19 Nov 2011 14:34:28 +0100 Subject: [PATCH 44/63] Bug 679314 - Cleanup test_download_history.js. r=mak --- .../tests/unit/test_download_history.js | 211 +++++++++--------- 1 file changed, 111 insertions(+), 100 deletions(-) diff --git a/toolkit/components/places/tests/unit/test_download_history.js b/toolkit/components/places/tests/unit/test_download_history.js index 27bc03df80c6..b6bb57eac656 100644 --- a/toolkit/components/places/tests/unit/test_download_history.js +++ b/toolkit/components/places/tests/unit/test_download_history.js @@ -2,29 +2,36 @@ http://creativecommons.org/publicdomain/zero/1.0/ */ /** - * The first part of this file runs a series of tests for the synchronous - * behavior of the nsIDownloadHistory::AddDownload function. + * This file tests the nsIDownloadHistory interface. */ -// Get services -var histsvc = Cc["@mozilla.org/browser/nav-history-service;1"]. - getService(Ci.nsINavHistoryService); -let bh = histsvc.QueryInterface(Ci.nsIBrowserHistory); -var os = Cc["@mozilla.org/observer-service;1"]. - getService(Ci.nsIObserverService); -var prefs = Cc["@mozilla.org/preferences-service;1"]. - getService(Ci.nsIPrefBranch); -var dh = Cc["@mozilla.org/browser/download-history;1"]. - getService(Ci.nsIDownloadHistory); -// Test that this nsIDownloadHistory is the one places implements. -do_check_true(dh instanceof Ci.nsINavHistoryService); +//////////////////////////////////////////////////////////////////////////////// +/// Globals + +const downloadHistory = Cc["@mozilla.org/browser/download-history;1"] + .getService(Ci.nsIDownloadHistory); + +const TEST_URI = NetUtil.newURI("http://google.com/"); +const REFERRER_URI = NetUtil.newURI("http://yahoo.com"); const NS_LINK_VISITED_EVENT_TOPIC = "link-visited"; const ENABLE_HISTORY_PREF = "places.history.enabled"; const PB_KEEP_SESSION_PREF = "browser.privatebrowsing.keep_current_session"; -var testURI = uri("http://google.com/"); -var referrerURI = uri("http://yahoo.com"); +/** + * Sets a flag when the link visited notification is received. + */ +const visitedObserver = { + topicReceived: false, + observe: function VO_observe(aSubject, aTopic, aData) + { + this.topicReceived = true; + } +}; +Services.obs.addObserver(visitedObserver, NS_LINK_VISITED_EVENT_TOPIC, false); +do_register_cleanup(function() { + Services.obs.removeObserver(visitedObserver, NS_LINK_VISITED_EVENT_TOPIC); +}); /** * Checks to see that a URI is in the database. @@ -34,31 +41,70 @@ var referrerURI = uri("http://yahoo.com"); * @param aExpected * Boolean result expected from the db lookup. */ -function uri_in_db(aURI, aExpected) { - var options = histsvc.getNewQueryOptions(); +function uri_in_db(aURI, aExpected) +{ + let options = PlacesUtils.history.getNewQueryOptions(); options.maxResults = 1; - options.resultType = options.RESULTS_AS_URI; options.includeHidden = true; - var query = histsvc.getNewQuery(); + + let query = PlacesUtils.history.getNewQuery(); query.uri = aURI; - var result = histsvc.executeQuery(query, options); - var root = result.root; + + let root = PlacesUtils.history.executeQuery(query, options).root; root.containerOpen = true; - var cc = root.childCount; + + do_check_eq(root.childCount, aExpected ? 1 : 0); + + // Close the container explicitly to free resources up earlier. root.containerOpen = false; - var checker = aExpected ? do_check_true : do_check_false; - checker(cc == 1); } -function test_dh() { - dh.addDownload(testURI, referrerURI, Date.now() * 1000); - - do_check_true(observer.topicReceived); - uri_in_db(testURI, true); - uri_in_db(referrerURI, true); +/** + * Cleanup function called by each individual test if necessary. + */ +function cleanup_and_run_next_test() +{ + visitedObserver.topicReceived = false; + waitForClearHistory(run_next_test); } -function test_dh_privateBrowsing() { +//////////////////////////////////////////////////////////////////////////////// +/// Tests + +function run_test() +{ + run_next_test(); +} + +add_test(function test_dh_is_from_places() +{ + // Test that this nsIDownloadHistory is the one places implements. + do_check_true(downloadHistory instanceof Ci.nsINavHistoryService); + + run_next_test(); +}); + +add_test(function test_dh_addDownload() +{ + // Sanity checks. + uri_in_db(TEST_URI, false); + uri_in_db(REFERRER_URI, false); + + downloadHistory.addDownload(TEST_URI, REFERRER_URI, Date.now() * 1000); + + do_check_true(visitedObserver.topicReceived); + uri_in_db(TEST_URI, true); + uri_in_db(REFERRER_URI, true); + + cleanup_and_run_next_test(); +}); + +add_test(function test_dh_privateBrowsing() +{ + // Sanity checks. + uri_in_db(TEST_URI, false); + uri_in_db(REFERRER_URI, false); + var pb = null; try { // PrivateBrowsing component is not always available to Places implementers. @@ -66,82 +112,49 @@ function test_dh_privateBrowsing() { getService(Ci.nsIPrivateBrowsingService); } catch (ex) { // Skip this test. + run_next_test(); return; } - prefs.setBoolPref(PB_KEEP_SESSION_PREF, true); + Services.prefs.setBoolPref(PB_KEEP_SESSION_PREF, true); pb.privateBrowsingEnabled = true; - dh.addDownload(testURI, referrerURI, Date.now() * 1000); + downloadHistory.addDownload(TEST_URI, REFERRER_URI, Date.now() * 1000); - do_check_false(observer.topicReceived); - uri_in_db(testURI, false); - uri_in_db(referrerURI, false); + do_check_false(visitedObserver.topicReceived); + uri_in_db(TEST_URI, false); + uri_in_db(REFERRER_URI, false); - // Cleanup pb.privateBrowsingEnabled = false; -} + cleanup_and_run_next_test(); +}); -function test_dh_disabledHistory() { - // Disable history - prefs.setBoolPref(ENABLE_HISTORY_PREF, false); +add_test(function test_dh_disabledHistory() +{ + // Sanity checks. + uri_in_db(TEST_URI, false); + uri_in_db(REFERRER_URI, false); - dh.addDownload(testURI, referrerURI, Date.now() * 1000); + // Disable history. + Services.prefs.setBoolPref(ENABLE_HISTORY_PREF, false); - do_check_false(observer.topicReceived); - uri_in_db(testURI, false); - uri_in_db(referrerURI, false); + downloadHistory.addDownload(TEST_URI, REFERRER_URI, Date.now() * 1000); - // Cleanup - prefs.setBoolPref(ENABLE_HISTORY_PREF, true); -} + do_check_false(visitedObserver.topicReceived); + uri_in_db(TEST_URI, false); + uri_in_db(REFERRER_URI, false); -var tests = [ - test_dh, - test_dh_privateBrowsing, - test_dh_disabledHistory, -]; - -var observer = { - topicReceived: false, - observe: function tlvo_observe(aSubject, aTopic, aData) - { - if (NS_LINK_VISITED_EVENT_TOPIC == aTopic) { - this.topicReceived = true; - } - } -}; -os.addObserver(observer, NS_LINK_VISITED_EVENT_TOPIC, false); - -// main -function run_test() { - while (tests.length) { - // Sanity checks - uri_in_db(testURI, false); - uri_in_db(referrerURI, false); - - (tests.shift())(); - - // Cleanup - bh.removeAllPages(); - observer.topicReceived = false; - } - - os.removeObserver(observer, NS_LINK_VISITED_EVENT_TOPIC); - - // Asynchronous part of the test. - test_dh_details(); -} + Services.prefs.setBoolPref(ENABLE_HISTORY_PREF, true); + cleanup_and_run_next_test(); +}); /** - * The second part of this file tests that nsIDownloadHistory::AddDownload saves - * the additional download details if the optional destination URL is specified. + * Tests that nsIDownloadHistory::AddDownload saves the additional download + * details if the optional destination URL is specified. */ - -function test_dh_details() +add_test(function test_dh_details() { - do_test_pending(); - - const SOURCE_URI = uri("http://example.com/test_download_history_details"); + const REMOTE_URI = NetUtil.newURI("http://localhost/"); + const SOURCE_URI = NetUtil.newURI("http://example.com/test_dh_details"); const DEST_FILE_NAME = "dest.txt"; // We must build a real, valid file URI for the destination. @@ -157,9 +170,7 @@ function test_dh_details() PlacesUtils.annotations.removeObserver(annoObserver); PlacesUtils.history.removeObserver(historyObserver); - // Cleanup. - bh.removeAllPages(); - do_test_finished(); + cleanup_and_run_next_test(); } }; @@ -210,10 +221,10 @@ function test_dh_details() PlacesUtils.history.addObserver(historyObserver, false); // Both null values and remote URIs should not cause errors. - dh.addDownload(SOURCE_URI, null, Date.now() * 1000); - dh.addDownload(SOURCE_URI, null, Date.now() * 1000, null); - dh.addDownload(SOURCE_URI, null, Date.now() * 1000, uri("http://localhost/")); + downloadHistory.addDownload(SOURCE_URI, null, Date.now() * 1000); + downloadHistory.addDownload(SOURCE_URI, null, Date.now() * 1000, null); + downloadHistory.addDownload(SOURCE_URI, null, Date.now() * 1000, REMOTE_URI); // Valid local file URIs should cause the download details to be saved. - dh.addDownload(SOURCE_URI, null, Date.now() * 1000, destFileUri); -} + downloadHistory.addDownload(SOURCE_URI, null, Date.now() * 1000, destFileUri); +}); From 00d6dd18b5dc12ad0b5dbf69faaf6d8f059cdee1 Mon Sep 17 00:00:00 2001 From: Ian Melven Date: Sat, 19 Nov 2011 14:35:03 +0100 Subject: [PATCH 45/63] Bug 642243 - Run binscope to alert us and turn the tree red when we don't use ASLR and other protection tools. r=ted --- build/win32/Makefile.in | 7 +++ build/win32/autobinscope.py | 108 ++++++++++++++++++++++++++++++++++++ 2 files changed, 115 insertions(+) create mode 100644 build/win32/autobinscope.py diff --git a/build/win32/Makefile.in b/build/win32/Makefile.in index 36d836563e5f..1fa39bb6ba3e 100644 --- a/build/win32/Makefile.in +++ b/build/win32/Makefile.in @@ -109,3 +109,10 @@ endif endif # ! MOZ_DEBUG endif # WIN32_REDIST_DIR + +# run the binscope tool to make sure the binary and all libraries +# are using all available Windows OS-level security mechanisms +check:: + $(PYTHON) $(srcdir)/autobinscope.py $(DIST)/bin/firefox.exe $(DIST)/crashreporter-symbols/ + $(PYTHON) $(srcdir)/autobinscope.py $(DIST)/bin/plugin-container.exe $(DIST)/crashreporter-symbols/ + diff --git a/build/win32/autobinscope.py b/build/win32/autobinscope.py new file mode 100644 index 000000000000..9298e88cc266 --- /dev/null +++ b/build/win32/autobinscope.py @@ -0,0 +1,108 @@ +#!/usr/bin/env python + +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# the Mozilla Foundation. +# Portions created by the Initial Developer are Copyright (C) 2011 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# imelven@mozilla.com +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# run Microsoft's Binscope tool (http://www.microsoft.com/download/en/details.aspx?id=11910) +# against a fresh Windows build. output a 'binscope.log' file with full details +# of the run and appropriate strings to integrate with the buildbots + +# from the docs : "The error code returned when running under the command line is equal +# to the number of failures the tool reported plus the number of errors. BinScope will return +# 0 only if there are no errors or failures." + +# the symbol dir should point to the symbol dir hierarchy created +# via running make buildsymbols in a windows build's objdir + +import sys +import subprocess +import os + +BINSCOPE_OUTPUT_LOGFILE = r".\binscope_xml_output.log" + +# usage +if len(sys.argv) < 3: + print """usage : autobinscope.by path_to_binary path_to_symbols [log_file_path]" + log_file_path is optional, log will be written to .\binscope_xml_output.log by default""" + sys.exit(0) + +binary_path = sys.argv[1] +symbol_path = sys.argv[2] + +if len(sys.argv) == 4: + log_file_path = sys.argv[3] +else: + log_file_path = BINSCOPE_OUTPUT_LOGFILE + +# execute binscope against the binary, using the BINSCOPE environment +# variable as the path to binscope.exe +try: + binscope_path = os.environ['BINSCOPE'] +except KeyError: + print "BINSCOPE environment variable is not set, can't check DEP/ASLR etc. status." + sys.exit(0) + +try: + proc = subprocess.Popen([binscope_path, "/target", binary_path, + "/output", log_file_path, "/sympath", symbol_path, + "/c", "ATLVersionCheck", "/c", "ATLVulnCheck", "/c", "FunctionPointersCheck", + "/c", "SharedSectionCheck", "/c", "APTCACheck", "/c", "NXCheck", + "/c", "GSCheck", "/c", "GSFunctionSafeBuffersCheck", "/c", "GSFriendlyInitCheck", + "/c", "CompilerVersionCheck", "/c", "SafeSEHCheck", "/c", "SNCheck", + "/c", "DBCheck"], stdout=subprocess.PIPE) + +except WindowsError, (errno, strerror): + if errno != 2 and errno != 3: + print "Unexpected error ! \nError " + str(errno) + " : " + strerror + "\nExiting !\n" + sys.exit(0) + else: + print "Could not locate binscope at location : %s\n" % binscope_path + print "Binscope wasn't installed or the BINSCOPE env variable wasn't set correctly, skipping this check and exiting..." + sys.exit(0) + +proc.wait() + +output = proc.communicate()[0] + +# is this a PASS or a FAIL ? +if proc.returncode != 0: + print "TEST-UNEXPECTED-FAIL | autobinscope.py | %s is missing a needed Windows protection, such as /GS or ASLR" % binary_path +else: + print "TEST-PASS | autobinscope.py | %s succeeded" % binary_path + + + From 21372f57bee419d0ff76228bd21c31af5804003d Mon Sep 17 00:00:00 2001 From: Matt Woodrow Date: Sat, 19 Nov 2011 14:36:05 +0100 Subject: [PATCH 46/63] Bug 562289 - Using a system proxy should honor socks_remote_dns pref. r=biesi --- netwerk/base/src/nsProtocolProxyService.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netwerk/base/src/nsProtocolProxyService.cpp b/netwerk/base/src/nsProtocolProxyService.cpp index 0a39c7482dfd..fc5b799116c8 100644 --- a/netwerk/base/src/nsProtocolProxyService.cpp +++ b/netwerk/base/src/nsProtocolProxyService.cpp @@ -643,7 +643,7 @@ nsProtocolProxyService::ExtractProxyInfo(const char *start, // If it's a SOCKS5 proxy, do name resolution on the server side. // We could use this with SOCKS4a servers too, but they might not // support it. - if (type == kProxyType_SOCKS) + if (type == kProxyType_SOCKS || mSOCKSProxyRemoteDNS) flags |= nsIProxyInfo::TRANSPARENT_PROXY_RESOLVES_HOST; // extract host:port From a007537ed59b4a9fc8299df2985f7cb1141ce55a Mon Sep 17 00:00:00 2001 From: Richard Marti Date: Sat, 19 Nov 2011 14:40:20 +0100 Subject: [PATCH 47/63] Bug 687968 - Highlight the whole treerow on dragging/dropping. r=dao --- toolkit/themes/winstripe/global/tree.css | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/toolkit/themes/winstripe/global/tree.css b/toolkit/themes/winstripe/global/tree.css index 67476b429906..604e75b5d2e9 100644 --- a/toolkit/themes/winstripe/global/tree.css +++ b/toolkit/themes/winstripe/global/tree.css @@ -194,10 +194,13 @@ treechildren::-moz-tree-separator { /* ::::: drop feedback ::::: */ +treechildren::-moz-tree-row(dropOn) { + background-color: Highlight; +} + tree[seltype="cell"] > treechildren::-moz-tree-cell-text(primary, dropOn), tree[seltype="text"] > treechildren::-moz-tree-cell-text(primary, dropOn), treechildren::-moz-tree-cell-text(primary, dropOn) { - background-color: Highlight; color: HighlightText; } From ba751f44257f6a3871f17e1c296ebed5da3eb2a9 Mon Sep 17 00:00:00 2001 From: Olli Pettay Date: Sat, 19 Nov 2011 20:49:17 +0200 Subject: [PATCH 48/63] Bug 703654 - Improve document's CC Describe, r=mccr8 --- content/base/src/nsDocument.cpp | 33 ++++++++++++++++++++------------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/content/base/src/nsDocument.cpp b/content/base/src/nsDocument.cpp index b69c0cfc9109..bc0e2ee7fefc 100644 --- a/content/base/src/nsDocument.cpp +++ b/content/base/src/nsDocument.cpp @@ -1782,31 +1782,38 @@ IdentifierMapEntryTraverse(nsIdentifierMapEntry *aEntry, void *aArg) } static const char* kNSURIs[] = { - " ([none])", - " (xmlns)", - " (xml)", - " (xhtml)", - " (XLink)", - " (XSLT)", - " (XBL)", - " (MathML)", - " (RDF)", - " (XUL)" + "([none])", + "(xmlns)", + "(xml)", + "(xhtml)", + "(XLink)", + "(XSLT)", + "(XBL)", + "(MathML)", + "(RDF)", + "(XUL)" }; NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsDocument) if (NS_UNLIKELY(cb.WantDebugInfo())) { char name[512]; + nsCAutoString loadedAsData; + if (tmp->IsLoadedAsData()) { + loadedAsData.AssignLiteral("data"); + } else { + loadedAsData.AssignLiteral("normal"); + } PRUint32 nsid = tmp->GetDefaultNamespaceID(); nsCAutoString uri; if (tmp->mDocumentURI) tmp->mDocumentURI->GetSpec(uri); if (nsid < ArrayLength(kNSURIs)) { - PR_snprintf(name, sizeof(name), "nsDocument%s %s", kNSURIs[nsid], - uri.get()); + PR_snprintf(name, sizeof(name), "nsDocument %s %s %s", + loadedAsData.get(), kNSURIs[nsid], uri.get()); } else { - PR_snprintf(name, sizeof(name), "nsDocument %s", uri.get()); + PR_snprintf(name, sizeof(name), "nsDocument %s %s", + loadedAsData.get(), uri.get()); } cb.DescribeRefCountedNode(tmp->mRefCnt.get(), sizeof(nsDocument), name); } From 0dbf32c021195d00f8077a8ad96122a4f76b02a1 Mon Sep 17 00:00:00 2001 From: Olli Pettay Date: Sat, 19 Nov 2011 20:50:17 +0200 Subject: [PATCH 49/63] Bug 703715 - Add Telemetry probes for sync XHR, r=sicking, taras --- content/base/src/nsXMLHttpRequest.cpp | 3 +++ toolkit/components/telemetry/TelemetryHistograms.h | 3 +++ 2 files changed, 6 insertions(+) diff --git a/content/base/src/nsXMLHttpRequest.cpp b/content/base/src/nsXMLHttpRequest.cpp index 20517e8d047a..6e880d265a39 100644 --- a/content/base/src/nsXMLHttpRequest.cpp +++ b/content/base/src/nsXMLHttpRequest.cpp @@ -103,6 +103,7 @@ #include "nsStringBuffer.h" #include "nsDOMFile.h" #include "nsIFileChannel.h" +#include "mozilla/Telemetry.h" using namespace mozilla; @@ -1485,6 +1486,8 @@ nsXMLHttpRequest::Open(const nsACString& method, const nsACString& url, // No optional arguments were passed in. Default async to true. async = true; } + Telemetry::Accumulate(Telemetry::XMLHTTPREQUEST_ASYNC_OR_SYNC, + async ? 0 : 1); NS_ENSURE_TRUE(mPrincipal, NS_ERROR_NOT_INITIALIZED); diff --git a/toolkit/components/telemetry/TelemetryHistograms.h b/toolkit/components/telemetry/TelemetryHistograms.h index 6b821ad957c1..b5053230fb34 100644 --- a/toolkit/components/telemetry/TelemetryHistograms.h +++ b/toolkit/components/telemetry/TelemetryHistograms.h @@ -250,3 +250,6 @@ HISTOGRAM(THUNDERBIRD_INDEXING_RATE_MSG_PER_S, 1, 100, 20, LINEAR, "Gloda: index HISTOGRAM(INNERWINDOWS_WITH_MUTATION_LISTENERS, 0, 1, 2, BOOLEAN, "Deleted or to-be-reused innerwindow which has had mutation event listeners.") HISTOGRAM(XUL_REFLOW_MS, 1, 3000, 10, EXPONENTIAL, "xul reflows") HISTOGRAM(XUL_INITIAL_FRAME_CONSTRUCTION, 1, 3000, 10, EXPONENTIAL, "initial xul frame construction") + +HISTOGRAM(XMLHTTPREQUEST_ASYNC_OR_SYNC, 0, 1, 2, BOOLEAN, "Type of XMLHttpRequest, async or sync") + From c97ebf6ffd211dc81e1f14476de1a8eae7a13a2a Mon Sep 17 00:00:00 2001 From: Olli Pettay Date: Sat, 19 Nov 2011 20:50:46 +0200 Subject: [PATCH 50/63] Bug 703715 - Add Telemetry probes for sync XHR, r=sicking, taras --- toolkit/components/telemetry/TelemetryHistograms.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/toolkit/components/telemetry/TelemetryHistograms.h b/toolkit/components/telemetry/TelemetryHistograms.h index b5053230fb34..e4aa8cd5b1e5 100644 --- a/toolkit/components/telemetry/TelemetryHistograms.h +++ b/toolkit/components/telemetry/TelemetryHistograms.h @@ -250,6 +250,4 @@ HISTOGRAM(THUNDERBIRD_INDEXING_RATE_MSG_PER_S, 1, 100, 20, LINEAR, "Gloda: index HISTOGRAM(INNERWINDOWS_WITH_MUTATION_LISTENERS, 0, 1, 2, BOOLEAN, "Deleted or to-be-reused innerwindow which has had mutation event listeners.") HISTOGRAM(XUL_REFLOW_MS, 1, 3000, 10, EXPONENTIAL, "xul reflows") HISTOGRAM(XUL_INITIAL_FRAME_CONSTRUCTION, 1, 3000, 10, EXPONENTIAL, "initial xul frame construction") - HISTOGRAM(XMLHTTPREQUEST_ASYNC_OR_SYNC, 0, 1, 2, BOOLEAN, "Type of XMLHttpRequest, async or sync") - From fdae5a29d85298a77f468de1baea27b088ba25d9 Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Sun, 20 Nov 2011 11:09:25 +1300 Subject: [PATCH 51/63] Fix logging message to reflect reality. Followup to bug 703197 --- layout/base/nsDocumentViewer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/layout/base/nsDocumentViewer.cpp b/layout/base/nsDocumentViewer.cpp index 932f32508702..aefa5173c76d 100644 --- a/layout/base/nsDocumentViewer.cpp +++ b/layout/base/nsDocumentViewer.cpp @@ -3594,7 +3594,7 @@ DocumentViewerImpl::Print(nsIPrintSettings* aPrintSettings, } if (!mDocument || !mDeviceContext) { - PR_PL(("Can't Print without pres shell, document etc")); + PR_PL(("Can't Print without a document and a device context")); return NS_ERROR_FAILURE; } From 88b1ae83c674e588ed744807b895fd12bbd0e009 Mon Sep 17 00:00:00 2001 From: Benoit Jacob Date: Sat, 19 Nov 2011 18:18:59 -0500 Subject: [PATCH 52/63] Bug 703917 - Upgrade ANGLE to r885 - no review This is syncing us with the upstream http://code.google.com/p/angleproject --- gfx/angle/README.mozilla | 2 +- gfx/angle/angle-intrinsic-msvc2005.patch | 2 +- gfx/angle/angle-renaming-debug.patch | 2 +- gfx/angle/angle-use-xmalloc.patch | 24 +- gfx/angle/extensions/ANGLE_texture_usage.txt | 202 ++ .../EGL_EXT_create_context_robustness.txt | 169 ++ gfx/angle/extensions/EXT_robustness.txt | 365 +++ gfx/angle/extensions/EXT_texture_storage.txt | 1090 +++++++++ gfx/angle/include/EGL/eglext.h | 8 + gfx/angle/include/GLES2/gl2ext.h | 71 + gfx/angle/src/common/version.h | 2 +- gfx/angle/src/compiler/Initialize.cpp | 2 +- gfx/angle/src/libEGL/Display.cpp | 128 +- gfx/angle/src/libEGL/Display.h | 14 +- gfx/angle/src/libEGL/Surface.cpp | 24 +- gfx/angle/src/libEGL/libEGL.cpp | 61 +- gfx/angle/src/libGLESv2/Context.cpp | 181 +- gfx/angle/src/libGLESv2/Context.h | 42 +- gfx/angle/src/libGLESv2/Fence.cpp | 4 +- gfx/angle/src/libGLESv2/Framebuffer.cpp | 63 +- gfx/angle/src/libGLESv2/Framebuffer.h | 8 +- gfx/angle/src/libGLESv2/Program.cpp | 49 +- gfx/angle/src/libGLESv2/Program.h | 4 +- gfx/angle/src/libGLESv2/Renderbuffer.cpp | 311 +-- gfx/angle/src/libGLESv2/Renderbuffer.h | 114 +- gfx/angle/src/libGLESv2/Texture.cpp | 2037 +++++++++-------- gfx/angle/src/libGLESv2/Texture.h | 295 ++- gfx/angle/src/libGLESv2/VertexDataManager.cpp | 10 +- gfx/angle/src/libGLESv2/libGLESv2.cpp | 716 ++++-- gfx/angle/src/libGLESv2/libGLESv2.def | 5 + gfx/angle/src/libGLESv2/main.cpp | 24 + gfx/angle/src/libGLESv2/main.h | 3 + gfx/angle/src/libGLESv2/utilities.cpp | 118 +- gfx/angle/src/libGLESv2/utilities.h | 23 +- 34 files changed, 4494 insertions(+), 1679 deletions(-) create mode 100644 gfx/angle/extensions/ANGLE_texture_usage.txt create mode 100644 gfx/angle/extensions/EGL_EXT_create_context_robustness.txt create mode 100644 gfx/angle/extensions/EXT_robustness.txt create mode 100644 gfx/angle/extensions/EXT_texture_storage.txt diff --git a/gfx/angle/README.mozilla b/gfx/angle/README.mozilla index da4ee3796a09..6ef512809852 100644 --- a/gfx/angle/README.mozilla +++ b/gfx/angle/README.mozilla @@ -1,6 +1,6 @@ This is the ANGLE project, from http://code.google.com/p/angleproject/ -Current revision: r809 +Current revision: r885 == Applied local patches == diff --git a/gfx/angle/angle-intrinsic-msvc2005.patch b/gfx/angle/angle-intrinsic-msvc2005.patch index 34398fd7e9e8..4788b86d8fb0 100644 --- a/gfx/angle/angle-intrinsic-msvc2005.patch +++ b/gfx/angle/angle-intrinsic-msvc2005.patch @@ -1,5 +1,5 @@ # HG changeset patch -# Parent b5604c321da4e3b5d6b0a940d18022a827061579 +# Parent d9b887da80f5bc18854fb3e5e43637c18d2a25ae diff --git a/gfx/angle/src/libGLESv2/Texture.cpp b/gfx/angle/src/libGLESv2/Texture.cpp --- a/gfx/angle/src/libGLESv2/Texture.cpp +++ b/gfx/angle/src/libGLESv2/Texture.cpp diff --git a/gfx/angle/angle-renaming-debug.patch b/gfx/angle/angle-renaming-debug.patch index 8f7c470ad967..5b6922ef0c2a 100644 --- a/gfx/angle/angle-renaming-debug.patch +++ b/gfx/angle/angle-renaming-debug.patch @@ -1,5 +1,5 @@ # HG changeset patch -# Parent 0239f15c7212413b5cffe66aee9ae5a4feb28f16 +# Parent eae39c479485f310e937d8550afc6596aec20159 diff --git a/gfx/angle/Makefile.in b/gfx/angle/Makefile.in --- a/gfx/angle/Makefile.in +++ b/gfx/angle/Makefile.in diff --git a/gfx/angle/angle-use-xmalloc.patch b/gfx/angle/angle-use-xmalloc.patch index f70cf4cfb004..f39e8eb3b0d3 100644 --- a/gfx/angle/angle-use-xmalloc.patch +++ b/gfx/angle/angle-use-xmalloc.patch @@ -1,5 +1,5 @@ # HG changeset patch -# Parent fecc64a6df53a9056b21958affad38c80ca38496 +# Parent 85ffde53712cab3c217bbbf0c1ec9b7ec2ae8ea6 diff --git a/gfx/angle/Makefile.in b/gfx/angle/Makefile.in --- a/gfx/angle/Makefile.in @@ -7,7 +7,7 @@ diff --git a/gfx/angle/Makefile.in b/gfx/angle/Makefile.in @@ -127,16 +127,18 @@ CSRCS = \ $(NULL) - DEFINES += -DANGLE_USE_NSPR -DANGLE_BUILD + DEFINES += -DANGLE_USE_NSPR -DANGLE_BUILD -DCOMPILER_IMPLEMENTATION #these defines are from ANGLE's build_angle.gyp DEFINES += -DANGLE_DISABLE_TRACE @@ -27,13 +27,13 @@ diff --git a/gfx/angle/README.mozilla b/gfx/angle/README.mozilla --- a/gfx/angle/README.mozilla +++ b/gfx/angle/README.mozilla @@ -3,16 +3,17 @@ This is the ANGLE project, from http://c - Current revision: r774 + Current revision: r885 == Applied local patches == In this order: - angle-renaming.patch - rename debug.h to compilerdebug.h to avoid conflict in our makefiles - angle-instrinsic-msvc2005.patch - work around a MSVC 2005 compile error + angle-renaming-debug.patch - rename debug.h to compilerdebug.h to avoid conflict in our makefiles + angle-intrinsic-msvc2005.patch - work around a MSVC 2005 compile error angle-limit-identifiers-to-250-chars.patch - see bug 675625 + angle-use-xmalloc.patch - see bug 680840. Can drop this patch whenever the new preprocessor lands. @@ -44,20 +44,6 @@ diff --git a/gfx/angle/README.mozilla b/gfx/angle/README.mozilla 1. Unapply patches 2. Apply diff with new ANGLE version 3. Reapply patches. -diff --git a/gfx/angle/angle-limit-identifiers-to-250-chars.patch b/gfx/angle/angle-limit-identifiers-to-250-chars.patch ---- a/gfx/angle/angle-limit-identifiers-to-250-chars.patch -+++ b/gfx/angle/angle-limit-identifiers-to-250-chars.patch -@@ -1,8 +1,10 @@ -+# HG changeset patch -+# Parent f9415c10c3ebd27856500cca7a0ee0f28a16f53c - diff --git a/gfx/angle/src/compiler/preprocessor/scanner.h b/gfx/angle/src/compiler/preprocessor/scanner.h - --- a/gfx/angle/src/compiler/preprocessor/scanner.h - +++ b/gfx/angle/src/compiler/preprocessor/scanner.h - @@ -44,17 +44,19 @@ NVIDIA HAS BEEN ADVISED OF THE POSSIBILI - // - // scanner.h - // - diff --git a/gfx/angle/src/compiler/preprocessor/atom.c b/gfx/angle/src/compiler/preprocessor/atom.c --- a/gfx/angle/src/compiler/preprocessor/atom.c +++ b/gfx/angle/src/compiler/preprocessor/atom.c diff --git a/gfx/angle/extensions/ANGLE_texture_usage.txt b/gfx/angle/extensions/ANGLE_texture_usage.txt new file mode 100644 index 000000000000..8c504237f13f --- /dev/null +++ b/gfx/angle/extensions/ANGLE_texture_usage.txt @@ -0,0 +1,202 @@ +Name + + ANGLE_texture_usage + +Name Strings + + GL_ANGLE_texture_usage + +Contributors + + Nicolas Capens, TransGaming + Daniel Koch, TransGaming + +Contact + + Daniel Koch, TransGaming (daniel 'at' transgaming.com) + +Status + + Complete + +Version + + Last Modified Date: November 10, 2011 + Version: 2 + +Number + + TBD + +Dependencies + + This extension is written against the OpenGL ES 2.0 Specification. + +Overview + + In some implementations it is advantageous to know the expected + usage of a texture before the backing storage for it is allocated. + This can help to inform the implementation's choice of format + and type of memory used for the allocation. If the usage is not + known in advance, the implementation essentially has to make a + guess as to how it will be used. If it is later proven wrong, + it may need to perform costly re-allocations and/or reformatting + of the texture data, resulting in reduced performance. + + This extension adds a texture usage flag that is specified via + the TEXTURE_USAGE_ANGLE TexParameter. This can be used to + indicate that the application knows that this texture will be + used for rendering. + +IP Status + + No known IP claims. + +New Procedures and Functions + + None + +New Tokens + + Accepted as a value for for the TexParameter{if} and + TexParameter{if}v commands and for the parameter of + GetTexParameter{if}v: + + TEXTURE_USAGE_ANGLE 0x93A2 + + Accepted as a value to for the TexParameter{if} and + to for the TexParameter{if}v commands with a of + TEXTURE_USAGE_ANGLE; returned as possible values for when + GetTexParameter{if}v is queried with a of TEXTURE_USAGE_ANGLE: + + NONE 0x0000 + FRAMEBUFFER_ATTACHMENT_ANGLE 0x93A3 + +Additions to Chapter 2 of the OpenGL ES 2.0 Specification (OpenGL ES Operation) + + None + +Additions to Chapter 3 of the OpenGL ES 2.0 Specification (Rasterization) + + Add a new row to Table 3.10 (Texture parameters and their values): + + Name | Type | Legal Values + ------------------------------------------------------------ + TEXTURE_USAGE_ANGLE | enum | NONE, FRAMEBUFFER_ATTACHMENT_ANGLE + + Add a new section 3.7.x (Texture Usage) before section 3.7.12 and + renumber the subsequent sections: + + "3.7.x Texture Usage + + Texture usage can be specified via the TEXTURE_USAGE_ANGLE value + for the argument to TexParameter{if}[v]. In order to take effect, + the texture usage must be specified before the texture contents are + defined either via TexImage2D or TexStorage2DEXT. + + The usage values can impact the layout and type of memory used for the + texture data. Specifying incorrect usage values may result in reduced + functionality and/or significantly degraded performance. + + Possible values for when is TEXTURE_USAGE_ANGLE are: + + NONE - the default. No particular usage has been specified and it is + up to the implementation to determine the usage of the texture. + Leaving the usage unspecified means that the implementation may + have to reallocate the texture data as the texture is used in + various ways. + + FRAMEBUFFER_ATTACHMENT_ANGLE - this texture will be attached to a + framebuffer object and used as a desination for rendering or blits." + + Modify section 3.7.12 (Texture State) and place the last 3 sentences + with the following: + + "Next, there are the three sets of texture properties; each consists of + the selected minification and magnification filters, the wrap modes for + and , and the usage flags. In the initial state, the value assigned + to TEXTURE_MIN_FILTER is NEAREST_MIPMAP_LINEAR, and the value for + TEXTURE_MAG_FILTER is LINEAR. and wrap modes are both set to + REPEAT. The initial value for TEXTURE_USAGE_ANGLE is NONE." + + +Additions to Chapter 4 of the OpenGL ES 2.0 Specification (Per-Fragment +Operations and the Framebuffer) + + None + +Additions to Chapter 5 of the OpenGL ES 2.0 Specification (Special +Functions): + + None + +Additions to Chapter 6 of the OpenGL ES 2.0 Specification (State and +State Requests) + + None + +Dependencies on EXT_texture_storage + + If EXT_texture_storage is not supported, omit any references to + TexStorage2DEXT. + +Errors + + If TexParameter{if} or TexParamter{if}v is called with a + of TEXTURE_USAGE_ANGLE and the value of or is not + NONE or FRAMEBUFFER_ATTACHMENT_ANGLE the error INVALID_VALUE is + generated. + +Usage Example + + /* create and bind texture */ + glGenTextures(1, &texture); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, texture); + + /* specify texture parameters */ + glTexParameteri(GL_TEXTURE_2D, GL_*, ...); /* as before */ + + /* specify that we'll be rendering to the texture */ + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_USAGE_ANGLE, GL_FRAMEBUFFER_ATTACHMENT_ANGLE); + + glTexStorage2DEXT(GL_TEXTURE_2D, levels, ...); // Allocation + for(int level = 0; level < levels; ++level) + glTexSubImage2D(GL_TEXTURE_2D, level, ...); // Initialisation + +Issues + + 1. Should there be a dynamic usage value? + + DISCUSSION: We could accept a dynamic flag to indicate that a texture will + be updated frequently. We could map this to D3D9 dynamic textures. This would + allow us to avoid creating temporary surfaces when updating the texture. + However renderable textures cannot be dynamic in D3D9, which eliminates the + primary use case for this. Furthermore, the memory usage of dynamic textures + typically increases threefold when you lock it. + + 2. Should the texture usage be an enum or a bitfield? + + UNRESOLVED. Using a bitfield would allow combination of values to be specified. + On the other hand, if combinations are really required, additional + could be added as necessary. Querying a bitfield via the GetTexParameter command + feels a bit odd. + + 3. What should happen if TEXTURE_USAGE_ANGLE is set/changed after the texture + contents have been specified? + + RESOLVED: It will have no effect. However, if the texture is redefined (for + example by TexImage2D) the new allocation will use the updated usage. + GetTexParameter is used to query the value of the TEXTURE_USAGE_ANGLE + state that was last set by TexParameter for the currently bound texture, or + the default value if it has never been set. There is no way to determine the + usage that was in effect at the time the texture was defined. + +Revision History + + Rev. Date Author Changes + ---- ----------- --------- ---------------------------------------- + 1 10 Nov 2011 dgkoch Initial revision + 2 10 Nov 2011 dgkoch Add overview + + diff --git a/gfx/angle/extensions/EGL_EXT_create_context_robustness.txt b/gfx/angle/extensions/EGL_EXT_create_context_robustness.txt new file mode 100644 index 000000000000..5b627d506856 --- /dev/null +++ b/gfx/angle/extensions/EGL_EXT_create_context_robustness.txt @@ -0,0 +1,169 @@ +Name + + EXT_create_context_robustness + +Name Strings + + EGL_EXT_create_context_robustness + +Contributors + + Daniel Koch, TransGaming + Contributors to EGL_KHR_create_context + +Contact + + Greg Roth (groth 'at' nvidia.com) + +Status + + Complete. + +Version + + Version 3, 2011/10/31 + +Number + + TBD + +Dependencies + + Requires EGL 1.4 + + Written against the EGL 1.4 specification. + + An OpenGL implementation supporting GL_ARB_robustness, an OpenGL ES + implementation supporting GL_EXT_robustness, or an implementation + supporting equivalent functionality is required. + +Overview + + This extension allows creating an OpenGL or OpenGL ES context + supporting robust buffer access behavior and a specified graphics + reset notification behavior. + +New Procedures and Functions + + None + +New Tokens + + Accepted as an attribute name in the <*attrib_list> argument to + eglCreateContext: + + EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT 0x30BF + EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT 0x3138 + + Accepted as an attribute value for EGL_CONTEXT_RESET_NOTIFICATION_- + STRATEGY_EXT in the <*attrib_list> argument to eglCreateContext: + + EGL_NO_RESET_NOTIFICATION_EXT 0x31BE + EGL_LOSE_CONTEXT_ON_RESET_EXT 0x31BF + +Additions to the EGL 1.4 Specification + + Replace section 3.7.1 "Creating Rendering Contexts" from the + fifth paragraph through the seventh paragraph: + + specifies a list of attributes for the context. The + list has the same structure as described for eglChooseConfig. If an + attribute is not specified in , then the default value + specified below is used instead. may be NULL or empty + (first attribute is EGL_NONE), in which case attributes assume their + default values as described below. Most attributes are only meaningful + for specific client APIs, and will generate an EGL_BAD_ATTRIBUTE + error when specified to create for another client API context. + + Context Versions + ---------------- + + EGL_CONTEXT_CLIENT_VERSION determines which version of an OpenGL ES + context to create. This attribute may only be specified when creating + an OpenGL ES context (e.g. when the current rendering API is + EGL_OPENGL_ES_API). An attribute value of 1 specifies creation of an + OpenGL ES 1.x context. An attribute value of 2 specifies creation of an + Open GL ES 2.x context. The default value for EGL_CONTEXT_CLIENT_VERSION + is 1. + + Context Robust Access + ------------- + + EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT indicates whether should be enabled for the OpenGL ES context. Robust buffer + access is defined in the GL_EXT_robustness extension specification, + and the resulting context must support GL_EXT_robustness and robust + buffer access as described therein. The default value of + EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT is EGL_FALSE. + + Context Reset Notification + -------------------------- + + The attribute name EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_- + EXT specifies the of the rendering + context. This attribute is only meaningful for OpenGL ES contexts, + and specifying it for other types of contexts will generate an + EGL_BAD_ATTRIBUTE error. + + Reset notification behavior is defined in the GL_EXT_robustness + extension for OpenGL ES, and the resulting context must support + GL_EXT_robustness and the specified reset strategy. The attribute + value may be either EGL_NO_RESET_NOTIFICATION_EXT or EGL_LOSE_- + CONTEXT_ON_RESET_EXT, which respectively result in disabling + delivery of reset notifications or the loss of all context state + upon reset notification as described by the GL_EXT_robustness. The + default value for EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT + is EGL_NO_RESET_NOTIFICATION_EXT. + + Add to the eglCreateContext context creation errors: + + * If does not support a client API context compatible + with the requested context flags and context reset notification + behavior (for client API types where these attributes are + supported), then an EGL_BAD_CONFIG error is generated. + + * If the reset notification behavior of and the + newly created context are different then an EGL_BAD_MATCH error is + generated. + + +Errors + + EGL_BAD_CONFIG is generated if EGL_CONTEXT_OPENGL_ROBUST_ACCESS_- + EXT is set to EGL_TRUE and no GL context supporting the GL_EXT_- + robustness extension and robust access as described therein can be + created. + + EGL_BAD_CONFIG is generated if no GL context supporting the + GL_EXT_robustness extension and the specified reset notification + behavior (the value of attribute EGL_CONTEXT_RESET_NOTIFICATION_- + STRATEGY_EXT) can be created. + + BAD_MATCH is generated if the reset notification behavior of + does not match the reset notification behavior of + the context being created. + +New State + + None + +Conformance Tests + + TBD + +Sample Code + + TBD + +Issues + + None + +Revision History + + Rev. Date Author Changes + ---- ------------ --------- ---------------------------------------- + 3 31 Oct 2011 groth Reverted to attribute for robust access. Now it's a + companion to rather than subset of KHR_create_context + 2 11 Oct 2011 groth Merged ANGLE and NV extensions. + 1 15 July 2011 groth Initial version diff --git a/gfx/angle/extensions/EXT_robustness.txt b/gfx/angle/extensions/EXT_robustness.txt new file mode 100644 index 000000000000..6f9f70563a6b --- /dev/null +++ b/gfx/angle/extensions/EXT_robustness.txt @@ -0,0 +1,365 @@ +Name + + EXT_robustness + +Name Strings + + GL_EXT_robustness + +Contributors + + Daniel Koch, TransGaming + Nicolas Capens, TransGaming + Contributors to ARB_robustness + +Contact + + Greg Roth, NVIDIA (groth 'at' nvidia.com) + +Status + + Complete. + +Version + + Version 3, 2011/10/31 + +Number + + TBD + +Dependencies + + This extension is written against the OpenGL ES 2.0 Specification + but can apply to OpenGL ES 1.1 and up. + + EGL_EXT_create_context_robustness is used to determine if a context + implementing this extension supports robust buffer access, and if it + supports reset notification. + +Overview + + Several recent trends in how OpenGL integrates into modern computer + systems have created new requirements for robustness and security + for OpenGL rendering contexts. + + Additionally GPU architectures now support hardware fault detection; + for example, video memory supporting ECC (error correcting codes) + and error detection. OpenGL contexts should be capable of recovering + from hardware faults such as uncorrectable memory errors. Along with + recovery from such hardware faults, the recovery mechanism can + also allow recovery from video memory access exceptions and system + software failures. System software failures can be due to device + changes or driver failures. + + OpenGL queries that that return (write) some number of bytes to a + buffer indicated by a pointer parameter introduce risk of buffer + overflows that might be exploitable by malware. To address this, + queries with return value sizes that are not expressed directly by + the parameters to the query itself are given additional API + functions with an additional parameter that specifies the number of + bytes in the buffer and never writing bytes beyond that limit. This + is particularly useful for multi-threaded usage of OpenGL contexts + in a "share group" where one context can change objects in ways that + can cause buffer overflows for another context's OpenGL queries. + + The original ARB_vertex_buffer_object extension includes an issue + that explicitly states program termination is allowed when + out-of-bounds vertex buffer object fetches occur. Modern graphics + hardware is capable well-defined behavior in the case of out-of- + bounds vertex buffer object fetches. Older hardware may require + extra checks to enforce well-defined (and termination free) + behavior, but this expense is warranted when processing potentially + untrusted content. + + The intent of this extension is to address some specific robustness + goals: + + * For all existing OpenGL queries, provide additional "safe" APIs + that limit data written to user pointers to a buffer size in + bytes that is an explicit additional parameter of the query. + + * Provide a mechanism for an OpenGL application to learn about + graphics resets that affect the context. When a graphics reset + occurs, the OpenGL context becomes unusable and the application + must create a new context to continue operation. Detecting a + graphics reset happens through an inexpensive query. + + * Provide an enable to guarantee that out-of-bounds buffer object + accesses by the GPU will have deterministic behavior and preclude + application instability or termination due to an incorrect buffer + access. Such accesses include vertex buffer fetches of + attributes and indices, and indexed reads of uniforms or + parameters from buffers. + +New Procedures and Functions + + enum GetGraphicsResetStatusEXT(); + + void ReadnPixelsEXT(int x, int y, sizei width, sizei height, + enum format, enum type, sizei bufSize, + void *data); + + void GetnUniformfvEXT(uint program, int location, sizei bufSize, + float *params); + void GetnUniformivEXT(uint program, int location, sizei bufSize, + int *params); + +New Tokens + + Returned by GetGraphicsResetStatusEXT: + + NO_ERROR 0x0000 + GUILTY_CONTEXT_RESET_EXT 0x8253 + INNOCENT_CONTEXT_RESET_EXT 0x8254 + UNKNOWN_CONTEXT_RESET_EXT 0x8255 + + Accepted by the parameter of GetBooleanv, GetIntegerv, + and GetFloatv: + + CONTEXT_ROBUST_ACCESS_EXT 0x90F3 + RESET_NOTIFICATION_STRATEGY_EXT 0x8256 + + Returned by GetIntegerv and related simple queries when is + RESET_NOTIFICATION_STRATEGY_EXT : + + LOSE_CONTEXT_ON_RESET_EXT 0x8252 + NO_RESET_NOTIFICATION_EXT 0x8261 + +Additions to Chapter 2 of the OpenGL ES 2.0 Specification (OpenGL ES Operation) + +Add a new subsection after 2.5 "GL Errors" and renumber subsequent +sections accordingly. + + 2.6 "Graphics Reset Recovery" + + Certain events can result in a reset of the GL context. Such a reset + causes all context state to be lost. Recovery from such events + requires recreation of all objects in the affected context. The + current status of the graphics reset state is returned by + + enum GetGraphicsResetStatusEXT(); + + The symbolic constant returned indicates if the GL context has been + in a reset state at any point since the last call to + GetGraphicsResetStatusEXT. NO_ERROR indicates that the GL context + has not been in a reset state since the last call. + GUILTY_CONTEXT_RESET_EXT indicates that a reset has been detected + that is attributable to the current GL context. + INNOCENT_CONTEXT_RESET_EXT indicates a reset has been detected that + is not attributable to the current GL context. + UNKNOWN_CONTEXT_RESET_EXT indicates a detected graphics reset whose + cause is unknown. + + If a reset status other than NO_ERROR is returned and subsequent + calls return NO_ERROR, the context reset was encountered and + completed. If a reset status is repeatedly returned, the context may + be in the process of resetting. + + Reset notification behavior is determined at context creation time, + and may be queried by calling GetIntegerv with the symbolic constant + RESET_NOTIFICATION_STRATEGY_EXT. + + If the reset notification behavior is NO_RESET_NOTIFICATION_EXT, + then the implementation will never deliver notification of reset + events, and GetGraphicsResetStatusEXT will always return + NO_ERROR[fn1]. + [fn1: In this case it is recommended that implementations should + not allow loss of context state no matter what events occur. + However, this is only a recommendation, and cannot be relied + upon by applications.] + + If the behavior is LOSE_CONTEXT_ON_RESET_EXT, a graphics reset will + result in the loss of all context state, requiring the recreation of + all associated objects. In this case GetGraphicsResetStatusEXT may + return any of the values described above. + + If a graphics reset notification occurs in a context, a notification + must also occur in all other contexts which share objects with that + context[fn2]. + [fn2: The values returned by GetGraphicsResetStatusEXT in the + different contexts may differ.] + + Add to Section 2.8 "Vertex Arrays" before subsection "Transferring + Array Elements" + + Robust buffer access is enabled by creating a context with robust + access enabled through the window system binding APIs. When enabled, + indices within the vertex array that lie outside the arrays defined + for enabled attributes result in undefined values for the + corresponding attributes, but cannot result in application failure. + Robust buffer access behavior may be queried by calling GetIntegerv + with the symbolic constant CONTEXT_ROBUST_ACCESS_EXT. + +Additions to Chapter 4 of the OpenGL ES 2.0 Specification (Per-Fragment +Operations and the Frame Buffer) + + Modify section 4.3.1 "Reading Pixels" + + Pixels are read using + + void ReadPixels(int x, int y, sizei width, sizei height, + enum format, enum type, void *data); + void ReadnPixelsEXT(int x, int y, sizei width, sizei height, + enum format, enum type, sizei bufSize, + void *data); + + Add to the description of ReadPixels: + + ReadnPixelsEXT behaves identically to ReadPixels except that it does + not write more than bytes into . If the buffer size + required to fill all the requested data is greater than an + INVALID_OPERATION error is generated and is not altered. + +Additions to Chapter 5 of the OpenGL ES 2.0 Specification (Special +Functions): + + None + +Additions to Chapter 6 of the OpenGL ES 2.0 Specification (State and +State Requests) + + Modify Section 6.1.8 "Shader and Program Queries" + + The commands + + void GetUniformfv(uint program, int location, float *params); + void GetnUniformfvEXT(uint program, int location, sizei bufSize, + float *params); + void GetUniformiv(uint program, int location, int *params); + void GetnUniformivEXT(uint program, int location, sizei bufSize, + int *params); + + return the value or values of the uniform at location + for program object in the array . Calling + GetnUniformfvEXT or GetnUniformivEXT ensures that no more than + bytes are written into . If the buffer size + required to fill all the requested data is greater than an + INVALID_OPERATION error is generated and is not altered. + ... + +Additions to The OpenGL ES Shading Language Specification, Version 1. + + Append to the third paragraph of section 4.1.9 "Arrays" + + If robust buffer access is enabled via the OpenGL ES API, such + indexing must not result in abnormal program termination. The + results are still undefined, but implementations are encouraged to + produce zero values for such accesses. + +Interactions with EGL_EXT_create_context_robustness + + If the EGL window-system binding API is used to create a context, + the EGL_EXT_create_context_robustness extension is supported, and + the attribute EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT is set to + EGL_TRUE when eglCreateContext is called, the resulting context will + perform robust buffer access as described above in section 2.8, and + the CONTEXT_ROBUST_ACCESS_EXT query will return GL_TRUE as described + above in section 6.1.5. + + If the EGL window-system binding API is used to create a context and + the EGL_EXT_create_context_robustness extension is supported, then + the value of attribute EGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_EXT + determines the reset notification behavior and the value of + RESET_NOTIFICATION_STRATEGY_EXT, as described in section 2.6. + +Errors + + ReadnPixelsEXT, GetnUniformfvEXT, and GetnUniformivEXT share all the + errors of their unsized buffer query counterparts with the addition + that INVALID_OPERATION is generated if the buffer size required to + fill all the requested data is greater than . + +New Implementation Dependent State + + Get Value Type Get Command Minimum Value Description Sec. Attribute + --------- ---- ----------- ------------- --------------------------- ----- --------- + CONTEXT_ROBUST_ACCESS_EXT B GetIntegerv - Robust access enabled 6.1.5 - + RESET_NOTIFICATION_STRATEGY_EXT Z_2 GetIntegerv See sec. 2.6 Reset notification behavior 2.6 - + +Issues + + + 1. What should this extension be called? + + RESOLVED: EXT_robustness + + Since this is intended to be a version of ARB_robustness for + OpenGL ES, it should be named accordingly. + + 2. How does this extension differ from Desktop GL's ARB_robustness? + + RESOLVED: Because EGL_EXT_create_context_robustness uses a + separate attribute to enable robust buffer access, a + corresponding query is added here. + + 3. Should we provide a context creation mechanism to enable this extension? + + RESOLVED. Yes. + + Currently, EGL_EXT_create_context_robustness provides this + mechanism via two unique attributes. These attributes differ + from those specified by KHR_create_context to allow for + differences in what functionality those attributes define. + + 4. What can cause a graphics reset? + + Either user or implementor errors may result in a graphics reset. + If the application attempts to perform a rendering that takes too long + whether due to an infinite loop in a shader or even just a rendering + operation that takes too long on the given hardware. Implementation + errors may produce badly formed hardware commands. Memory access errors + may result from user or implementor mistakes. On some systems, power + management events such as system sleep, screen saver activation, or + pre-emption may also context resets to occur. Any of these events may + result in a graphics reset event that will be detectable by the + mechanism described in this extension. + + 5. How should the application react to a reset context event? + + RESOLVED: For this extension, the application is expected to query + the reset status until NO_ERROR is returned. If a reset is encountered, + at least one *RESET* status will be returned. Once NO_ERROR is again + encountered, the application can safely destroy the old context and + create a new one. + + After a reset event, apps should not use a context for any purpose + other than determining its reset status, and then destroying it. If a + context receives a reset event, all other contexts in its share group + will also receive reset events, and should be destroyed and + recreated. + + Apps should be cautious in interpreting the GUILTY and INNOCENT reset + statuses. These are guidelines to the immediate cause of a reset, but + not guarantees of the ultimate cause. + + 6. If a graphics reset occurs in a shared context, what happens in + shared contexts? + + RESOLVED: A reset in one context will result in a reset in all other + contexts in its share group. + + 7. How can an application query for robust buffer access support, + since this is now determined at context creation time? + + RESOLVED. The application can query the value of ROBUST_ACCESS_EXT + using GetIntegerv. If true, this functionality is enabled. + + 8. How is the reset notification behavior controlled? + + RESOLVED: Reset notification behavior is determined at context + creation time using EGL/GLX/WGL/etc. mechanisms. In order that shared + objects be handled predictably, a context cannot share with + another context unless both have the same reset notification + behavior. + + +Revision History + + Rev. Date Author Changes + ---- ------------ --------- ---------------------------------------- + 3 31 Oct 2011 groth Reverted to attribute for robust access. Now it's a + companion to rather than subset of KHR_create_context + 2 11 Oct 2011 groth Merged ANGLE and NV extensions. + Convert to using flag to indicate robust access. + 1 15 July 2011 groth Initial version diff --git a/gfx/angle/extensions/EXT_texture_storage.txt b/gfx/angle/extensions/EXT_texture_storage.txt new file mode 100644 index 000000000000..6631bae11863 --- /dev/null +++ b/gfx/angle/extensions/EXT_texture_storage.txt @@ -0,0 +1,1090 @@ +Name + + EXT_texture_storage + +Name Strings + + GL_EXT_texture_storage + +Contact + + Bruce Merry (bmerry 'at' gmail.com) + Ian Romanick, Intel (ian.d.romanick 'at' intel.com) + +Contributors + + Jeremy Sandmel, Apple + Bruce Merry, ARM + Tom Olson, ARM + Benji Bowman, Imagination Technologies + Ian Romanick, Intel + Jeff Bolz, NVIDIA + Pat Brown, NVIDIA + Maurice Ribble, Qualcomm + Lingjun Chen, Qualcomm + Daniel Koch, Transgaming Inc + +Status + + Complete. + +Version + + Last Modified Date: November 11, 2011 + Author Revision: 24 + +Number + + XXX - not assigned yet + +Dependencies + + OpenGL ES 1.0, OpenGL ES 2.0 or OpenGL 1.2 is required. + + OES_texture_npot, OES_texture_cube_map, OES_texture_3D, + OES_depth_texture, OES_packed_depth_stencil, + OES_compressed_paletted_texture, OES_texture_float, OES_texture_half_float + EXT_texture_type_2_10_10_10_REV, EXT_texture_format_BGRA8888, + EXT_texture3D, OES_texture_npot, APPLE_texture_2D_limited_npot, + ARB_texture_cube_map, ARB_texture_cube_map_array, + ARB_texture_rectangle, SGIS_generate_mipmap, + EXT_direct_state_access, OES_EGL_image, WGL_ARB_render_texture, + GLX_EXT_texture_from_pixmap, and core specifications that + incorporate these extensions affect the definition of this + extension. + + This extension is written against the OpenGL 3.2 Core Profile + specification. + +Overview + + The texture image specification commands in OpenGL allow each level + to be separately specified with different sizes, formats, types and + so on, and only imposes consistency checks at draw time. This adds + overhead for implementations. + + This extension provides a mechanism for specifying the entire + structure of a texture in a single call, allowing certain + consistency checks and memory allocations to be done up front. Once + specified, the format and dimensions of the image array become + immutable, to simplify completeness checks in the implementation. + + When using this extension, it is no longer possible to supply texture + data using TexImage*. Instead, data can be uploaded using TexSubImage*, + or produced by other means (such as render-to-texture, mipmap generation, + or rendering to a sibling EGLImage). + + This extension has complicated interactions with other extensions. + The goal of most of these interactions is to ensure that a texture + is always mipmap complete (and cube complete for cubemap textures). + +IP Status + + No known IP claims + +New Procedures and Functions + + void TexStorage1DEXT(enum target, sizei levels, + enum internalformat, + sizei width); + + void TexStorage2DEXT(enum target, sizei levels, + enum internalformat, + sizei width, sizei height); + + void TexStorage3DEXT(enum target, sizei levels, + enum internalformat, + sizei width, sizei height, sizei depth); + + void TextureStorage1DEXT(uint texture, enum target, sizei levels, + enum internalformat, + sizei width); + + void TextureStorage2DEXT(uint texture, enum target, sizei levels, + enum internalformat, + sizei width, sizei height); + + void TextureStorage3DEXT(uint texture, enum target, sizei levels, + enum internalformat, + sizei width, sizei height, sizei depth); + +New Types + + None + +New Tokens + + Accepted by the parameter of GetTexParameter{if}v: + + TEXTURE_IMMUTABLE_FORMAT_EXT 0x912F + + Accepted by the parameter of TexStorage* when + implemented on OpenGL ES: + + ALPHA8_EXT 0x803C /* reuse tokens from EXT_texture */ + LUMINANCE8_EXT 0x8040 + LUMINANCE8_ALPHA8_EXT 0x8045 + + (if OES_texture_float is supported) + RGBA32F_EXT 0x8814 /* reuse tokens from ARB_texture_float */ + RGB32F_EXT 0x8815 + ALPHA32F_EXT 0x8816 + LUMINANCE32F_EXT 0x8818 + LUMINANCE_ALPHA32F_EXT 0x8819 + + (if OES_texture_half_float is supported) + RGBA16F_EXT 0x881A /* reuse tokens from ARB_texture_float */ + RGB16F_EXT 0x881B + ALPHA16F_EXT 0x881C + LUMINANCE16F_EXT 0x881E + LUMINANCE_ALPHA16F_EXT 0x881F + + (if EXT_texture_type_2_10_10_10_REV is supported) + RGB10_A2_EXT 0x8059 /* reuse tokens from EXT_texture */ + RGB10_EXT 0x8052 + + (if EXT_texture_format_BGRA8888 is supported) + BGRA8_EXT 0x93A1 + + +Additions to Chapter 2 of the OpenGL 3.2 Core Profile Specification +(OpenGL Operation) + + None + +Additions to Chapter 3 of the OpenGL 3.2 Core Profile Specification +(Rasterization) + + After section 3.8.1 (Texture Image Specification) add a new + subsection called "Immutable-format texture images": + + "An alterative set of commands is provided for specifying the + properties of all levels of a texture at once. Once a texture is + specified with such a command, the format and dimensions of all + levels becomes immutable, unless it is a proxy texture (since + otherwise it would no longer be possible to use the proxy). The + contents of the images and the parameters can still be modified. + Such a texture is referred to as an "immutable-format" texture. The + immutability status of a texture can be determined by calling + GetTexParameter with TEXTURE_IMMUTABLE_FORMAT_EXT. + + Each of the commands below is described by pseudo-code which + indicates the effect on the dimensions and format of the texture. + For all of the commands, the following apply in addition to the + pseudo-code: + + - If the default texture object is bound to , an + INVALID_OPERATION error is generated. + - If executing the pseudo-code would lead to an error, the error is + generated and the command will have no effect. + - Any existing levels that are not replaced are reset to their + initial state. + - If , , or is less than 1, the + error INVALID_VALUE is generated. + - Since no pixel data are provided, the and values + used in the pseudo-code are irrelevant; they can be considered to + be any values that are legal to use with . + - If the command is successful, TEXTURE_IMMUTABLE_FORMAT_EXT becomes + TRUE. + - If is a specific compressed texture format, then + references to TexImage* should be replaced by CompressedTexImage*, + with , and replaced by any valid and + . If there is no for which this command would have + been valid, an INVALID_OPERATION error is generated [fn: This + condition is not required for OpenGL, but is necessary for OpenGL + ES which does not support on-the-fly compression.] + - If is one of the internal formats listed in table + 3.11, an INVALID_ENUM error is generated. [fn: The corresponding table + in OpenGL ES 2.0 is table 3.8.] + + The command + + void TexStorage1DEXT(enum target, sizei levels, + enum internalformat, + sizei width); + + specifies all the levels of a one-dimensional texture (or proxy) at + the same time. It is described by the pseudo-code below: + + for (i = 0; i < levels; i++) + { + TexImage1D(target, i, internalformat, width, 0, + format, type, NULL); + width = max(1, floor(width / 2)); + } + + If is not TEXTURE_1D or PROXY_TEXTURE_1D then INVALID_ENUM + is generated. If is greater than floor(log_2(width)) + 1 + then INVALID_OPERATION is generated. + + The command + + void TexStorage2DEXT(enum target, sizei levels, + enum internalformat, + sizei width, sizei height); + + specifies all the levels of a two-dimensional, cube-map, + one-dimension array or rectangle texture (or proxy) at the same + time. The pseudo-code depends on the : + + [PROXY_]TEXTURE_2D, [PROXY_]TEXTURE_RECTANGLE or + PROXY_TEXTURE_CUBE_MAP: + + for (i = 0; i < levels; i++) + { + TexImage2D(target, i, internalformat, width, height, 0, + format, type, NULL); + width = max(1, floor(width / 2)); + height = max(1, floor(height / 2)); + } + + TEXTURE_CUBE_MAP: + + for (i = 0; i < levels; i++) + { + for face in (+X, -X, +Y, -Y, +Z, -Z) + { + TexImage2D(face, i, internalformat, width, height, 0, + format, type, NULL); + } + width = max(1, floor(width / 2)); + height = max(1, floor(height / 2)); + } + + [PROXY_]TEXTURE_1D_ARRAY: + + for (i = 0; i < levels; i++) + { + TexImage2D(target, i, internalformat, width, height, 0, + format, type, NULL); + width = max(1, floor(width / 2)); + } + + If is not one of those listed above, the error INVALID_ENUM + is generated. + + The error INVALID_OPERATION is generated if any of the following + conditions hold: + - is [PROXY_]TEXTURE_1D_ARRAY and is greater than + floor(log_2(width)) + 1 + - is not [PROXY_]TEXTURE_1D_ARRAY and is greater + than floor(log_2(max(width, height))) + 1 + + The command + + void TexStorage3DEXT(enum target, sizei levels, enum internalformat, + sizei width, sizei height, sizei depth); + + specifies all the levels of a three-dimensional, two-dimensional + array texture, or cube-map array texture (or proxy). The pseudo-code + depends on : + + [PROXY_]TEXTURE_3D: + + for (i = 0; i < levels; i++) + { + TexImage3D(target, i, internalformat, width, height, depth, 0, + format, type, NULL); + width = max(1, floor(width / 2)); + height = max(1, floor(height / 2)); + depth = max(1, floor(depth / 2)); + } + + [PROXY_]TEXTURE_2D_ARRAY, [PROXY_]TEXTURE_CUBE_MAP_ARRAY_ARB: + + for (i = 0; i < levels; i++) + { + TexImage3D(target, i, internalformat, width, height, depth, 0, + format, type, NULL); + width = max(1, floor(width / 2)); + height = max(1, floor(height / 2)); + } + + If is not one of those listed above, the error INVALID_ENUM + is generated. + + The error INVALID_OPERATION is generated if any of the following + conditions hold: + - is [PROXY_]TEXTURE_3D and is greater than + floor(log_2(max(width, height, depth))) + 1 + - is [PROXY_]TEXTURE_2D_ARRAY or + [PROXY_]TEXTURE_CUBE_MAP_ARRAY_EXT and is greater than + floor(log_2(max(width, height))) + 1 + + After a successful call to any TexStorage* command with a non-proxy + target, the value of TEXTURE_IMMUTABLE_FORMAT_EXT for this texture + object is set to TRUE, and no further changes to the dimensions or + format of the texture object may be made. Other commands may only + alter the texel values and texture parameters. Using any of the + following commands with the same texture will result in the error + INVALID_OPERATION being generated, even if it does not affect the + dimensions or format: + + - TexImage* + - CompressedTexImage* + - CopyTexImage* + - TexStorage* + + The TextureStorage* commands operate identically to the + corresponding command where "Texture" is substituted for "Tex" + except, rather than updating the current bound texture for the + texture unit indicated by the current active texture state and the + target parameter, these "Texture" commands update the texture object + named by the initial texture parameter. The error INVALID_VALUE + is generated if is zero. + " + + In section 3.8.6 (Texture Parameters), after the sentence + + "In the remainder of section 3.8, denote by lod_min, lod_max, + level_base, and level_max the values of the texture parameters + TEXTURE_MIN_LOD, TEXTURE_MAX_LOD, TEXTURE_BASE_LEVEL, and + TEXTURE_MAX_LEVEL respectively." + + add + + "However, if TEXTURE_IMMUTABLE_FORMAT_EXT is + TRUE, then level_base is clamped to the range [0, - 1] and + level_max is then clamped to the range [level_base, - 1], + where is the parameter passed the call to TexStorage* for + the texture object. + + In section 3.8.9 (Rendering feedback loops) replace all references + to TEXTURE_BASE_LEVEL by level_base. + + In section 3.8.9 (Mipmapping), replace the paragraph starting "Each + array in a mipmap is defined..." by + + "Each array in a mipmap is defined using TexImage3D, TexImage2D, + CopyTexImage2D, TexImage1D, CopyTexImage1D, or by functions that are + defined in terms of these functions. Level-of-detail numbers proceed + from level_base for the original texel array through the maximum + level p, with each unit increase indicating an array of half the + dimensions of the previous one (rounded down to the next integer if + fractional) as already described. For immutable-format textures, + p is one less than the parameter passed to TexStorage*; + otherwise p = floor(log_2(maxsize)) + level_base. All arrays from + level_base through q = min(p, level_max) must be defined, as + discussed in section 3.8.12." + + In section 3.8.12 (Texture Completeness), modify the last sentence + to avoid refering to level_base and level_max: + + "An implementation may allow a texture image array of level 1 or + greater to be created only if a mipmap complete set of image arrays + consistent with the requested array can be supported where the + values of TEXTURE_BASE_LEVEL and TEXTURE_MAX_LEVEL are 0 and 1000 + respectively." + + Modify section 3.8.13 (Texture State and Proxy State) to add the new + state: + + "Each set consists of ..., and a boolean flag indicating whether the + format and dimensions of the texture are immutable." + + Add + "The initial value of TEXTURE_IMMUTABLE_FORMAT_EXT is FALSE." + +Additions to Chapter 4 of the OpenGL 3.2 Core Profile Specification +(Per-Fragment Operations and the Frame Buffer) + + None + +Additions to Chapter 5 of the OpenGL 3.2 Compatibility Profile Specification +(Special Functions) + + In section 5.4.1 (Commands Not Usable in Display Lists), add + TexStorage* to the list of commands that cannot be used. + +Additions to Chapter 6 of the OpenGL 3.2 Core Profile Specification +(State and State Requests) + + Replace the following statement in 6.1.3 (Enumerated Queries): + + " must be one of the symbolic values in table 3.10." + + with + + " must be TEXTURE_IMMUTABLE_FORMAT_EXT or one of the symbolic + values in table 3.22." + +Additions to the AGL/EGL/GLX/WGL Specifications + + None + +Additions to OES_compressed_ETC1_RGB8_texture + + Add the following to the additions to Chapter 3: + + "Since ETC1 images are easily edited along 4x4 texel boundaries, the + limitations on CompressedTexSubImage2D are relaxed. + CompressedTexSubImage2D will result in an INVALID_OPERATION error + only if one of the following conditions occurs: + + * is not a multiple of four, and plus is not + equal to the texture width; + + * is not a multiple of four, and plus is + not equal to the texture height; or + + * or is not a multiple of four. + + Remove CompressedTexSubImage2D from this error: + + "INVALID_OPERATION is generated by CompressedTexSubImage2D, + TexSubImage2D, or CopyTexSubImage2D if the texture image + bound to has internal format ETC1_RGB8_OES." + + Add the following error: + + "INVALID_OPERATION is generated by CompressedTexSubImage2D + if the region to be modified is not aligned to block boundaries + (refer to the extension text for details)." + +Additions to AMD_compressed_ATC_texture and AMD_compressed_3DC_texture: + + Apply the same changes as for OES_compressed_ETC1_RGB8_texture + above, substituting the appropriate internal format tokens from + these extensions. + +Dependencies on EXT_direct_state_access + + If EXT_direct_state_access is not present, references to + TextureStorage* should be ignored. + +Dependencies on OpenGL ES + + On OpenGL ES without extensions introducing TEXTURE_MAX_LEVEL, + mipmapped textures specified with TexStorage are required to have a + full set of mipmaps. If TEXTURE_MAX_LEVEL is not supported, this + extension is modified as follows: + + - Where an upper bound is placed on in this extension (i.e. + the maximum number of mipmap levels for a texture of the given + target and dimensions), an INVALID_OPERATION error is generated if + is neither 1 nor this upper bound. + - q (the effective maximum number of levels) is redefined to clamp + to the number of levels present in immutable-format textures. + + OpenGL ES does not accept sized internal formats (e.g., RGBA8) and + instead derives an internal format from the and + parameters of TexImage2D. Since TexStorage* does not specify texel + data, the API doesn't include and parameters. + On an OpenGL ES implementation, the values in the + column in the tables below are accepted as + parameters, and base internal formats are not accepted. The + TexImage* calls in the TexStorage* pseudocode are modified so that + the , and parameters are + taken from the , and columns (respectively) + in the tables below, according to the + specified in the TexStorage* command. + + + ---------------- -------- ------ + RGB565 RGB UNSIGNED_SHORT_5_6_5 + RGBA4 RGBA UNSIGNED_SHORT_4_4_4_4 + RGB5_A1 RGBA UNSIGNED_SHORT_5_5_5_1 + RGB8_OES RGB UNSIGNED_BYTE + RGBA8_OES RGBA UNSIGNED_BYTE + LUMINANCE8_ALPHA8_EXT LUMINANCE_ALPHA UNSIGNED_BYTE + LUMINANCE8_EXT LUMINANCE UNSIGNED_BYTE + ALPHA8_EXT ALPHA UNSIGNED_BYTE + + If OES_depth_texture is supported: + + + ---------------- -------- ------ + DEPTH_COMPONENT16_OES DEPTH_COMPONENT UNSIGNED_SHORT + DEPTH_COMPONENT32_OES DEPTH_COMPONENT UNSIGNED_INT + + If OES_packed_depth_stencil is supported: + + + ---------------- -------- ------ + DEPTH24_STENCIL8_OES DEPTH_STENCIL_OES UNSIGNED_INT + + If OES_texture_float is supported: + + + ---------------- -------- ------ + RGBA32F_EXT RGBA FLOAT + RGB32F_EXT RGB FLOAT + LUMINANCE_ALPHA32F_EXT LUMINANCE_ALPHA FLOAT + LUMINANCE32F_EXT LUMINANCE FLOAT + ALPHA32F_EXT ALPHA FLOAT + + If OES_texture_half_float is supported: + + + ---------------- -------- ------ + RGBA16F_EXT RGBA HALF_FLOAT_OES + RGB16F_EXT RGB HALF_FLOAT_OES + LUMINANCE_ALPHA16F_EXT LUMINANCE_ALPHA HALF_FLOAT_OES + LUMINANCE16F_EXT LUMINANCE HALF_FLOAT_OES + ALPHA16F_EXT ALPHA HALF_FLOAT_OES + + If EXT_texture_type_2_10_10_10_REV is supported: + + + ---------------- -------- ------ + RGB10_A2_EXT RGBA UNSIGNED_INT_2_10_10_10_REV_EXT + RGB10_EXT RGB UNSIGNED_INT_2_10_10_10_REV_EXT + + If EXT_texture_format_BGRA8888 is supported: + + + ---------------- -------- ------ + BGRA8_EXT BGRA_EXT UNSIGNED_BYTE + + +Dependencies on texture targets + + If a particular texture target is not supported by the + implementation, passing it as a to TexStorage* will + generate an INVALID_ENUM error. If as a result, any of the commands + defined in this extension would no longer have any valid , + all references to the command should be ignored. + + In particular, note that OpenGL ES 1.x/2.0 do not have proxy textures, + 1D textures, or 3D textures, and thus only the TexStorage2DEXT + entry point is required. If OES_texture_3D is supported, the + TexStorage3DEXT entry point is also required. + +Dependencies on OES_texture_npot + + If OpenGL ES 2.0 or APPLE_texture_2D_limited_npot is present but + OES_texture_npot is not present, then INVALID_OPERATION is + generated by TexStorage* and TexStorage3DEXT if is + not one and , or is not a power of + two. + +Dependencies on WGL_ARB_render_texture, GLX_EXT_texture_from_pixmap, EGL +1.4 and GL_OES_EGL_image + + The commands eglBindTexImage, wglBindTexImageARB, glXBindTexImageEXT or + EGLImageTargetTexture2DOES are not permitted on an immutable-format + texture. + They will generate the following errors: + - EGLImageTargetTexture2DOES: INVALID_OPERATION + - eglBindTexImage: EGL_BAD_MATCH + - wglBindTexImage: ERROR_INVALID_OPERATION + - glXBindTexImageEXT: BadMatch + +Dependencies on OES_compressed_paletted_texture + + The compressed texture formats exposed by + OES_compressed_paletted_texture are not supported by TexStorage*. + Passing one of these tokens to TexStorage* will generate an + INVALID_ENUM error. + +Errors + + Note that dependencies above modify the errors. + + If TexStorage* is called with a , , or + parameter that is less than one, then the error + INVALID_VALUE is generated. + + If the parameter to TexStorage1DEXT is not + [PROXY_]TEXTURE_1D, then the error INVALID_ENUM is generated. + + If the parameter to TexStorage2DEXT is not + [PROXY_]TEXTURE_2D, [PROXY_]TEXTURE_CUBE_MAP, + [PROXY_]TEXTURE_RECTANGLE or [PROXY_]TEXTURE_1D_ARRAY, then the + error INVALID_ENUM is generated. + + If the parameter to TexStorage3DEXT is not + [PROXY_]TEXTURE_3D, [PROXY_]TEXTURE_2D_ARRAY or + [PROXY_]TEXTURE_CUBE_MAP_ARRAY then the error INVALID_ENUM is + generated. + + If the parameter to TexStorage* is greater than the + -specific value listed below then the error + INVALID_OPERATION is generated: + [PROXY_]TEXTURE_{1D,1D_ARRAY}: + floor(log_2(width)) + 1 + [PROXY_]TEXTURE_{2D,2D_ARRAY,CUBE_MAP,CUBE_MAP_ARRAY}: + floor(log_2(max(width, height))) + 1 + [PROXY_]TEXTURE_3D: + floor(log_2(max(width, height, depth))) + 1 + [PROXY_]TEXTURE_RECTANGLE: + 1 + + If the default texture object is bound to the passed to + TexStorage*, then the error INVALID_OPERATION is generated. + + If the parameter to TextureStorage* does not match the + dimensionality of , then the error INVALID_OPERATION is + generated. + + If the parameter to TextureStorage* is zero, then the + INVALID_VALUE is generated. + + If any pseudo-code listed in this extension would generate an error, + then that error is generated. + + Calling any of the following functions on a texture for which + TEXTURE_IMMUTABLE_FORMAT_EXT is TRUE will generate an + INVALID_OPERATION error: + - TexImage* + - CompressedTexImage* + - CopyTexImage* + +New State + + Additions to Table 6.8 Textures (state per texture object) + + Initial + Get Value Type Get Command Value Description Sec. + --------- ---- ----------- ------- ----------- ---- + TEXTURE_IMMUTABLE_FORMAT_EXT B GetTexParameter FALSE Size and format immutable 2.6 + +New Implementation Dependent State + + None + +Issues + + 1. What should this extension be called? + + RESOLVED: EXT_texture_storage is chosen for consistency with the + glRenderbufferStorage entry point. + + 2. Should TexStorage* accept a border parameter? + + RESOLVED: no. + + DISCUSSION: Currently it does not, since borders are a deprecated + feature which is not supported by all hardware. Users of the + compatibility profile can continue to use the existing texture + specification functions, but there is an argument that users of + compatibility profile may also want to use this extension. + + 3. What is the correct error when specifies a partial + mipmap pyramid for OpenGL ES? + + RESOLVED: INVALID_OPERATION, since it is an interaction between + parameters rather than a single value being invalid. It also makes + sense to relax this condition for desktop GL where it makes sense to + use a truncated pyramid with TEXTURE_MAX_LEVEL. + + 4. Should use of these entry-points make the metadata (format and + dimensions) immutable? + + RESOLVED: Yes. + + DISCUSSION: The benefits of knowing metadata can't change will + probably outweigh the extra cost of checking the + TEXTURE_IMMUTABLE_FORMAT_EXT flag on each texture specification + call. + + 5. Should it be legal to completely replace the texture using a new call + to TexStorage*? + + RESOLVED. It will not be allowed. + + DISCUSSION: This is useful to invalidate all levels of a texture. + Allowing the metadata to be changed here seems easier than trying to + define a portable definition of what it means to change the metadata + (e.g. what if you used an unsized internal format the first time and + the corresponding sized internal format the second time, or vice + versa)? + + However, while this is largely similar to deleting the old texture + object and replacing it with a new one, it does lose some of the + advantages of immutability. Specifically, because doing so does not + reset bindings, it doesn't allow a migration path to an API that + validates the texture format at bind time. + + 6. Should it be legal to use TexImage* after TexStorage* if it doesn't + affect the metadata? + + RESOLVED: No. + + DISCUSSION: A potential use case is to allow a single level of a + texture to be invalidated using a NULL pointer. However, as noted + above it is non-trivial to determine what constitutes a change. + + 7. How does this extension interact with APPLE_texture_2D_limited_npot? + + RESOLVED. APPLE_texture_2D_limited_npot is equivalent to the NPOT + support in OpenGL ES 2.0. + + 8. Should this extension be written to work with desktop OpenGL? + + RESOLVED: Yes. + + DISCUSSION: There has been been interest and it will future-proof it + against further additions to OpenGL ES. + + 9. Which texture targets should be supported? + + RESOLVED. All targets except multisample and buffer textures are + supported. + + Initially all targets except TEXTURE_BUFFER were supported. It was + noted that the entrypoints for multisample targets added no useful + functionality, since multisample textures have no completeness + checks beyond being non-empty. + + Rectangle textures have completeness checks to prevent filtering of + integer textures. However, since we decided to only force mipmap + completeness, this becomes less useful. + + 10. Should this extension support proxy textures? + + RESOLVED: Yes. + + DISCUSSION: It should be orthogonal. + + 11. Are the and parameters necessary? + + RESOLVED. No, they will be removed. + + DISCUSSION: For OpenGL ES the type parameter was necessary to + determine the precision of the texture, but this can be solved by + having these functions accept sized internal formats (which are + already accepted by renderbuffers). + + 12. Should it be legal to make the default texture (id 0) + immutable-format? + + RESOLVED: No. + + DISCUSSION: This would make it impossible to restore the context to + it's default state, which is deemed undesirable. There is no good + reason not to use named texture objects. + + 13. Should we try to guarantee that textures made through this path + will always be complete? + + RESOLVED: It should be guaranteed that the texture will be mipmap + complete. + + DISCUSSION: Future separation between images and samplers will still + allow users to create combinations that are invalid, but + constraining the simple cases will make these APIs easier to use for + beginners. + + 14. Should these functions use a EXT_direct_state_access approach to + specifying the texture objects? + + UNRESOLVED. + + DISCUSSION: as a standalone extension, no DSA-like functions will be + added. However, interactions with EXT_direct_state_access and + ARB_direct_state_access need to be resolved. + + 15. Should these functions accept generic compressed formats? + + RESOLVED: Yes. Note that the spec language will need to be modified + to allow this for ES, since the pseudocode is written in terms of + TexImage2D, which does not allow compressed texture formats in ES. + See also issues 23 and 27. + + 16. How should completeness be forced when TEXTURE_MAX_LEVEL is not + present? + + RESOLVED. The maximum level q will be redefined to clamp to the + highest level available. + + DISCUSSION: A single-level texture can be made complete either by + making it mipmap complete (by setting TEXTURE_MAX_LEVEL to 0) or by + turning off mipmapping (by choose an appropriate minification + filter). + + Some options: + + A: Specify that TexStorage* changes the default minification filter + for OpenGL ES. This makes it awkward to add TEXTURE_MAX_LEVEL + support to OpenGL ES later, since switching to match GL would break + compatibility. The two mechanisms also do not give identical + results, since the magnification threshold depends on the + minification filter. + + B: Specify that the texture behaves as though TEXTURE_MAX_LEVEL were + zero. To specify this properly probably requires fairly intrusive + changes to the OpenGL ES full specification to add back all the + language relating to the max level. It also does not solve the + similar problem of what to do with NPOT textures; and it may have + hardware impacts due to the change in the min/mag crossover. + + C: Specify that TexStorage* changes the default minification filter + for all implementations when a single-level texture is specified. + This may be slightly counter-intuitive to desktop GL users, but will + give consistent behaviour across variants of GL and avoids changing + the functional behaviour of this extension based on the presence or + absence of some other feature. + + Currently B is specified. This has potential hardware implications + for OpenGL ES because of the effect of the minification filter on + the min/mag crossover. However, C has potential hardware implications + for OpenGL due to the separation of texture and sampler state. + + 17. How should completeness be forced when only ES2-style NPOT is + available? + + RESOLVED. It is not worth trying to do this, in light of issue 13. + + Previous revisions of this extension overrode the minification + filter and wrap modes, but that is no longer the case. Since + OES_texture_npot removes the caveats on NPOT textures anyway, it + might not be worth trying to "fix" this. + + 18. For OpenGL ES, how do the new sized internal formats interact + with OES_required_internal_format? + + RESOLVED. + + If OES_required_internal_format is not present, then the + parameter is intended merely to indicate what the + corresponding and would have been, had TexImage* + been used instead. If OES_required_internal_format is present, then + it is intended that the will be interpreted as if + it had been passed directly to TexImage*. + + 19. Should there be some hinting mechanism to indicate whether data + is coming immediately or later? + + RESOLVED. No parameter is needed. An extension can be added to provide + a TexParameter value which is latched at TexStorage time. + + DISCUSSION: Some members felt that this would be useful so that they + could defer allocation when suitable, particularly if higher- + resolution images will be streamed in later; or to choose a memory + type or layout appropriate to the usage. However, implementation + experience with BufferData is that developers frequently provide + wrong values and implementations have to guess anyway. + + One option suggested was the parameter currently passed to + BufferData. Another option was to set it with TexParameter. + + 20. How should this extension interact with + EGLImageTargetTexture2DOES, eglBindTexImage, glXBindTexImage and + wglBindTexImage? + + RESOLVED. These functions will not be permitted after glTexStorage*. + + Several options are possible: + + A) Disallow these functions. + B) Allow them, but have them reset the TEXTURE_IMMUTABLE_FORMAT_EXT + flag. + C) Allow them unconditionally. + + C would violate the design principle that the dimensions and format + of the mipmap array are immutable. B does not so much modify the + dimension and formats as replace them with an entirely different + set. + + 21. Should there be a single function for specifying 1D, 2D and 3D + targets? + + RESOLVED. No, we will stick with existing precedent. + + 22. Is it possible to use GenerateMipmap with an incomplete mipmap + pyramid? + + RESOLVED. Yes, because the effective max level is limited to the + levels that were specified, and so GenerateMipmap does not generate + any new levels. + + However, to make automatic mipmap generation work, it is necessary + to redefine p rather than q, since automatic mipmap generation + ignores the max level. + + 23. How should this extension interact with + OES_compressed_paletted_texture? + + RESOLVED. Paletted textures will not be permitted, and will + generate INVALID_ENUM. + + DISCUSSION: OES_compressed_paletted_texture supplies all the mipmaps + in a single function call, with the palette specified once. That's + incompatible with the upload model in this extension. + + 24. How can ETC1 textures be used with this extension? + + RESOLVED. Add language in this extension to allow subregion uploads + for ETC1. + + DISCUSSION: GL_OES_compressed_ETC1_RGB8_texture doesn't allow + CompressedTexSubImage*, so it would be impossible to use this + extension with ETC1. This is seen as an oversight in the ETC1 + extension. While it cannot be fixed in that extension (since it is + already shipping), this extension can add that capability. + + 25. Should any other compressed formats be similarly modified? + + RESOLVED. Yes, AMD_compressed_ATC_texture and + AMD_compressed_3DC_texture can be modified similarly to ETC1 + (Maurice Ribble indicated that both formats use 4x4 blocks). Desktop + OpenGL requires that whole-image replacement is supported for any + compressed texture format, and the OpenGL ES extensions + EXT_texture_compression_dxt1 and IMG_texture_compression_pvrtc + already allow whole-image replacement, so it is not necessary to + modify them to be used with this extension. + + 26. Should these commands be permitted in display lists? + + RESOLVED. No. + + DISCUSSION: Display lists are most useful for repeating commands, + and TexStorage* commands cannot be repeated because the first call + makes the format immutable. + + 27. Should these commands accept unsized internal formats? + + RESOLVED: No, for both OpenGL and OpenGL ES. + + DISCUSSION: normally the parameter to TexImage* can serve as + a hint to select a sized format (and in OpenGL ES, this is the only + mechanism available); since TexStorage* does not have a + parameter, the implementation has no information on which to base a + decision. + +Revision History + + Revision 24, 2011/11/11 (dgkoch) + - Mark complete. Clarify ES clarifications. + + Revision 23, 2011/11/10 (dgkoch) + - Add GLES clarifcations and interactions with more GLES extensions + + Revision 22, 2011/11/10 (bmerry) + - Update my contact details + + Revision 21, 2011/07/25 (bmerry) + - Remove dangling references to MultiTexStorage in Errors section + + Revision 20, 2011/07/21 (bmerry) + - Remove dangling reference to in Errors section + + Revision 19, 2011/05/02 (Jon Leech) + - Assign enum value + + Revision 18, 2011/01/24 (bmerry) + - Disallow unsized internal formats (oversight in revision 17). + + Revision 17, 2011/01/24 (bmerry) + - Added and resolved issue 26. + - Split issue 27 out from issue 15. + - Disallow TexStorage* in display lists. + - Use the term "immutable-format" consistently (bug 7281). + + Revision 16, 2010/11/23 (bmerry) + - Disallowed TexStorage on an immutable-format texture + (resolves issue 5). + - Deleted MultiTexStorage* commands (other DSA functions still + unresolved). + - Some minor wording changes suggested by Pat Brown (bug 7002). + + Revision 15, 2010/11/09 (bmerry) + - Reopened issue 5. + - Reopened issue 14, pending stabilisation of + ARB_direct_state_access. + - Marked issue 9 resolved, pending any objections. + - Fix references to no object being bound (was meant to refer to + the default object). + - Adding missing pseudocode for TEXTURE_1D_ARRAY. + - Corrected TEXTURE_2D_ARRAY -> TEXTURE_1D_ARRAY in error checks. + - Changed "levels... are removed" to "levels... are reset to their + init state", since desktop GL has per-level state apart from the + texels. + - Miscellaneous wording fixes. + + Revision 14, 2010/09/25 (bmerry) + - Add issues 24-25 and alterations to + OES_compressed_ETC1_RGB8_texture, AMD_compressed_ATC_texture and + AMD_compressed_3DC_texture. + + Revision 13, 2010/09/19 (bmerry) + - Two typo fixes from Daniel Koch + + Revision 12, 2010/09/18 (bmerry) + - Changed resolution to issue 20 + - Added and resolved issue 23 + - Added explanation of how to upload data (in overview) + - Added spec language to implement resolution to issue 15 + + Revision 11, 2010/07/21 (bmerry) + - Resolved issue 16 + - Reopen issue 20 + - Fix some typos + + Revision 10, 2010/07/15 (bmerry) + - Update some issues to match core text + - Resolved issue 17 + + Revision 9, 2010/05/24 (bmerry) + - Marked issue 2 as resolved + - Resolved issue 19 (as no change) + - Resolved issue 20 + - Add issues 21-22 + - Add in spec language to forbid use on default textures + - Redefine level_base, level_max to be clamped forms of + TEXTURE_BASE_LEVEL/TEXTURE_MAX_LEVEL when using immutable + textures + - Redefine p to also be clamped to the provided levels for + immutable textures, to support automatic mipmap generation + - Removed multisample functions + - Removed language stating that texture parameters were reset to + defaults + + Revision 8, 2010/05/18 (bmerry) + - Added issue about EGLimage + - Marked issue 14 as resolved + + Revision 7, 2010/05/04 (bmerry) + - Removed some lingering , parameters to the new + functions that should have been removed in revision 4 + - Trivial typo fixes + + Revision 6, 2010/02/18 (bmerry) + - Resolved issues 5, 6 and 18 + - Added MultiTexStorage* functions for DSA interaction + - Added error for texture-target mismatch in DSA + - Allowed TexStorage* to be called again + + Revision 5, 2010/01/25 (bmerry) + - Added to contributors list + - Require OpenGL 1.2, to simplify interactions with + TEXTURE_BASE_LEVEL/TEXTURE_MAX_LEVEL and CLAMP_TO_EDGE + - Change default wrap modes to always be CLAMP_TO_EDGE + - Change default filters to always be NEAREST + - Moved language about generating new levels into an interaction, + since it can only happen on OpenGL ES + - Added interaction with EXT_direct_state_access + - Added extra for GL ES when OES_depth_texture, + OES_packed_depth_stencil and EXT_texture_type_2_10_10_10_REV are + present. + - Minor non-functional wording fixes and typos + - Resolved issue 16 + - Added issues 17-19 + + Revision 4, 2010/01/13 (bmerry) + - Changed suffix from ARM to EXT + - Added list of contributors + - Added language to force the texture to always be complete + - Removed and arguments + - Added issues 14-16 + - Reopened issue 2 + - Reformatted issues to separate resolution and discussion + - Resolved issues 1, 9 and 11-13 + - Fixed the max number of levels in a cube map array + + Revision 3, 2009/12/17 (bmerry) + - Added missing vendor suffix to TEXTURE_IMMUTABLE_FORMAT_ARM + - Rewritten to against desktop OpenGL + - Added prototypes for 1D and multisample storage functions + - Added issues 8-13 + + Revision 2, 2009/08/20 (bmerry) + - Resolved issue 2 (no border parameter) + - Resolved issue 4 (metadata becomes immutable) + - Added interaction with OES_texture_cube_map + - Added error if width != height in a cube map + - Added issues 5-7 + + Revision 1, 2009/05/06 (bmerry) + - First draft diff --git a/gfx/angle/include/EGL/eglext.h b/gfx/angle/include/EGL/eglext.h index e2ac233fe0b1..2d4ab2235046 100644 --- a/gfx/angle/include/EGL/eglext.h +++ b/gfx/angle/include/EGL/eglext.h @@ -318,6 +318,14 @@ typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYSURFACEPOINTERANGLEPROC) (EGLDisplay #define EGL_COVERAGE_SAMPLE_RESOLVE_NONE_NV 0x3133 #endif +#ifndef EGL_EXT_create_context_robustness +#define EGL_EXT_create_context_robustness 1 +#define EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT 0x30BF +#define EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT 0x3138 +#define EGL_NO_RESET_NOTIFICATION_EXT 0x31BE +#define EGL_LOSE_CONTEXT_ON_RESET_EXT 0x31BF +#endif + #if KHRONOS_SUPPORT_INT64 /* EGLTimeKHR requires 64-bit uint support */ #ifndef EGL_NV_system_time #define EGL_NV_system_time 1 diff --git a/gfx/angle/include/GLES2/gl2ext.h b/gfx/angle/include/GLES2/gl2ext.h index b95a58df101f..42602fb2e6b5 100644 --- a/gfx/angle/include/GLES2/gl2ext.h +++ b/gfx/angle/include/GLES2/gl2ext.h @@ -222,6 +222,12 @@ typedef void* GLeglImageOES; #define GL_TRANSLATED_SHADER_SOURCE_LENGTH_ANGLE 0x93A0 #endif +/* GL_ANGLE_texture_usage */ +#ifndef GL_ANGLE_texture_usage +#define GL_TEXTURE_USAGE_ANGLE 0x93A2 +#define GL_FRAMEBUFFER_ATTACHMENT_ANGLE 0x93A3 +#endif + /*------------------------------------------------------------------------* * APPLE extension tokens *------------------------------------------------------------------------*/ @@ -325,6 +331,42 @@ typedef void* GLeglImageOES; #define GL_UNPACK_SKIP_PIXELS 0x0CF4 #endif +/* GL_EXT_robustness */ +#ifndef GL_EXT_robustness +#define GL_GUILTY_CONTEXT_RESET_EXT 0x8253 +#define GL_INNOCENT_CONTEXT_RESET_EXT 0x8254 +#define GL_UNKNOWN_CONTEXT_RESET_EXT 0x8255 +#define GL_CONTEXT_ROBUST_ACCESS_EXT 0x90F3 +#define GL_RESET_NOTIFICATION_STRATEGY_EXT 0x8256 +#define GL_LOSE_CONTEXT_ON_RESET_EXT 0x8252 +#define GL_NO_RESET_NOTIFICATION_EXT 0x8261 +#endif + +/* GL_EXT_texture_storage */ +#ifndef GL_EXT_texture_storage +#define GL_TEXTURE_IMMUTABLE_FORMAT_EXT 0x912F +#define GL_ALPHA8_EXT 0x803C +#define GL_LUMINANCE8_EXT 0x8040 +#define GL_LUMINANCE8_ALPHA8_EXT 0x8045 +/* OES_texture_float dependent internal formats */ +#define GL_RGBA32F_EXT 0x8814 /* reuse tokens from ARB_texture_float */ +#define GL_RGB32F_EXT 0x8815 +#define GL_ALPHA32F_EXT 0x8816 +#define GL_LUMINANCE32F_EXT 0x8818 +#define GL_LUMINANCE_ALPHA32F_EXT 0x8819 +/* OES_texture_half_float dependent internal formats */ +#define GL_RGBA16F_EXT 0x881A /* reuse tokens from ARB_texture_float */ +#define GL_RGB16F_EXT 0x881B +#define GL_ALPHA16F_EXT 0x881C +#define GL_LUMINANCE16F_EXT 0x881E +#define GL_LUMINANCE_ALPHA16F_EXT 0x881F +/* EXT_texture_type_2_10_10_10_REV dependent internal formats */ +#define GL_RGB10_A2_EXT 0x8059 /* reuse tokens from EXT_texture */ +#define GL_RGB10_EXT 0x8052 +/* EXT_texture_format_BGRA8888 dependent internal formats */ +#define GL_BGRA8_EXT 0x93A1 +#endif + /*------------------------------------------------------------------------* * DMP extension tokens *------------------------------------------------------------------------*/ @@ -824,6 +866,11 @@ GL_APICALL void GL_APIENTRY glGetTranslatedShaderSourceANGLE (GLuint shader, GLs typedef void (GL_APIENTRYP PFNGLGETTRANSLATEDSHADERSOURCEANGLEPROC) (GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* source); #endif +/* GL_ANGLE_texture_usage */ +#ifndef GL_ANGLE_texture_usage +#define GL_ANGLE_texture_usage 1 +#endif + /*------------------------------------------------------------------------* * APPLE extension functions *------------------------------------------------------------------------*/ @@ -931,6 +978,30 @@ typedef void (GL_APIENTRYP PFNGLMULTIDRAWELEMENTSEXTPROC) (GLenum mode, const GL #define GL_EXT_unpack_subimage 1 #endif +/* GL_EXT_robustness */ +#ifndef GL_EXT_robustness +#define GL_EXT_robustness 1 +#ifdef GL_GLEXT_PROTOTYPES +GL_APICALL GLenum GL_APIENTRY glGetGraphicsResetStatusEXT (void); +GL_APICALL void GL_APIENTRY glReadnPixelsEXT (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, GLvoid *data); +GL_APICALL void GL_APIENTRY glGetnUniformfvEXT (GLuint program, GLint location, GLsizei bufSize, GLfloat *params); +GL_APICALL void GL_APIENTRY glGetnUniformivEXT (GLuint program, GLint location, GLsizei bufSize, GLint *params); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef GLenum (GL_APIENTRYP PFNGLGETGRAPHICSRESETSTATUSEXTPROC) (void); +typedef void (GL_APIENTRYP PFNGLREADNPIXELSEXTPROC) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, GLvoid *data); +typedef void (GL_APIENTRYP PFNGLGETNUNIFORMFVEXTPROC) (GLuint program, GLint location, GLsizei bufSize, GLfloat *params); +typedef void (GL_APIENTRYP PFNGLGETNUNIFORMIVEXTPROC) (GLuint program, GLint location, GLsizei bufSize, GLint *params); +#endif + +/* GL_EXT_texture_storage */ +#ifndef GL_EXT_texture_storage +#define GL_EXT_texture_storage 1 +#ifdef GL_GLEXT_PROTOTYPES +GL_APICALL void GL_APIENTRY TexStorage2DEXT (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (GL_APIENTRYP PFNGLTEXSTORAGE2DEXT) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); +#endif + /*------------------------------------------------------------------------* * DMP extension functions *------------------------------------------------------------------------*/ diff --git a/gfx/angle/src/common/version.h b/gfx/angle/src/common/version.h index 6b04fb060372..14f0f7705c1e 100644 --- a/gfx/angle/src/common/version.h +++ b/gfx/angle/src/common/version.h @@ -1,7 +1,7 @@ #define MAJOR_VERSION 0 #define MINOR_VERSION 0 #define BUILD_VERSION 0 -#define BUILD_REVISION 809 +#define BUILD_REVISION 885 #define STRINGIFY(x) #x #define MACRO_STRINGIFY(x) STRINGIFY(x) diff --git a/gfx/angle/src/compiler/Initialize.cpp b/gfx/angle/src/compiler/Initialize.cpp index e0e1db94eb8b..8c3a44953ae1 100644 --- a/gfx/angle/src/compiler/Initialize.cpp +++ b/gfx/angle/src/compiler/Initialize.cpp @@ -624,7 +624,7 @@ void IdentifyBuiltIns(ShShaderType type, ShShaderSpec spec, switch(type) { case SH_FRAGMENT_SHADER: { // Set up gl_FragData. The array size. - TType fragData(EbtFloat, EbpMedium, EvqFragColor, 4, false, true); + TType fragData(EbtFloat, EbpMedium, EvqFragData, 4, false, true); fragData.setArraySize(resources.MaxDrawBuffers); symbolTable.insert(*new TVariable(NewPoolTString("gl_FragData"), fragData)); } diff --git a/gfx/angle/src/libEGL/Display.cpp b/gfx/angle/src/libEGL/Display.cpp index 7e6f264a1661..aa975f7bce7b 100644 --- a/gfx/angle/src/libEGL/Display.cpp +++ b/gfx/angle/src/libEGL/Display.cpp @@ -88,6 +88,7 @@ Display::Display(EGLNativeDisplayType displayId, HDC deviceContext, bool softwar mMaxSwapInterval = 1; mSoftwareDevice = software; mDisplayId = displayId; + mDeviceLost = false; } Display::~Display() @@ -304,7 +305,7 @@ void Display::terminate() if (mDevice) { // If the device is lost, reset it first to prevent leaving the driver in an unstable state - if (isDeviceLost()) + if (testDeviceLost()) { resetDevice(); } @@ -457,23 +458,44 @@ bool Display::createDevice() bool Display::resetDevice() { D3DPRESENT_PARAMETERS presentParameters = getDefaultPresentParameters(); - HRESULT result; - - do - { - Sleep(0); // Give the graphics driver some CPU time - result = mDevice->Reset(&presentParameters); + HRESULT result = D3D_OK; + bool lost = testDeviceLost(); + int attempts = 3; + + while (lost && attempts > 0) + { + if (mDeviceEx) + { + Sleep(500); // Give the graphics driver some CPU time + result = mDeviceEx->ResetEx(&presentParameters, NULL); + } + else + { + result = mDevice->TestCooperativeLevel(); + + while (result == D3DERR_DEVICELOST) + { + Sleep(100); // Give the graphics driver some CPU time + result = mDevice->TestCooperativeLevel(); + } + + if (result == D3DERR_DEVICENOTRESET) + { + result = mDevice->Reset(&presentParameters); + } + } + + lost = testDeviceLost(); + attempts --; } - while (result == D3DERR_DEVICELOST); if (FAILED(result)) { + ERR("Reset/ResetEx failed multiple times: 0x%08X", result); return error(EGL_BAD_ALLOC, false); } - ASSERT(SUCCEEDED(result)); - return true; } @@ -515,7 +537,8 @@ EGLSurface Display::createWindowSurface(HWND window, EGLConfig config, const EGL return error(EGL_BAD_ALLOC, EGL_NO_SURFACE); } - if (isDeviceLost()) { + if (testDeviceLost()) + { if (!restoreLostDevice()) return EGL_NO_SURFACE; } @@ -627,7 +650,8 @@ EGLSurface Display::createOffscreenSurface(EGLConfig config, HANDLE shareHandle, return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); } - if (isDeviceLost()) { + if (testDeviceLost()) + { if (!restoreLostDevice()) return EGL_NO_SURFACE; } @@ -645,7 +669,7 @@ EGLSurface Display::createOffscreenSurface(EGLConfig config, HANDLE shareHandle, return success(surface); } -EGLContext Display::createContext(EGLConfig configHandle, const gl::Context *shareContext) +EGLContext Display::createContext(EGLConfig configHandle, const gl::Context *shareContext, bool notifyResets, bool robustAccess) { if (!mDevice) { @@ -654,7 +678,7 @@ EGLContext Display::createContext(EGLConfig configHandle, const gl::Context *sha return NULL; } } - else if (isDeviceLost()) // Lost device + else if (testDeviceLost()) // Lost device { if (!restoreLostDevice()) return NULL; @@ -662,14 +686,21 @@ EGLContext Display::createContext(EGLConfig configHandle, const gl::Context *sha const egl::Config *config = mConfigSet.get(configHandle); - gl::Context *context = glCreateContext(config, shareContext); + gl::Context *context = glCreateContext(config, shareContext, notifyResets, robustAccess); mContextSet.insert(context); + mDeviceLost = false; return context; } bool Display::restoreLostDevice() { + for (ContextSet::iterator ctx = mContextSet.begin(); ctx != mContextSet.end(); ctx++) + { + if ((*ctx)->isResetNotificationEnabled()) + return false; // If reset notifications have been requested, application must delete all contexts first + } + // Release surface resources to make the Reset() succeed for (SurfaceSet::iterator surface = mSurfaceSet.begin(); surface != mSurfaceSet.end(); surface++) { @@ -703,6 +734,21 @@ void Display::destroyContext(gl::Context *context) mContextSet.erase(context); } +void Display::notifyDeviceLost() +{ + for (ContextSet::iterator context = mContextSet.begin(); context != mContextSet.end(); context++) + { + (*context)->markContextLost(); + } + mDeviceLost = true; + error(EGL_CONTEXT_LOST); +} + +bool Display::isDeviceLost() +{ + return mDeviceLost; +} + bool Display::isInitialized() const { return mD3d9 != NULL && mConfigSet.size() > 0; @@ -769,13 +815,13 @@ D3DADAPTER_IDENTIFIER9 *Display::getAdapterIdentifier() return &mAdapterIdentifier; } -bool Display::isDeviceLost() +bool Display::testDeviceLost() { if (mDeviceEx) { return FAILED(mDeviceEx->CheckDeviceState(NULL)); } - else if(mDevice) + else if (mDevice) { return FAILED(mDevice->TestCooperativeLevel()); } @@ -783,6 +829,29 @@ bool Display::isDeviceLost() return false; // No device yet, so no reset required } +bool Display::testDeviceResettable() +{ + HRESULT status = D3D_OK; + + if (mDeviceEx) + { + status = mDeviceEx->CheckDeviceState(NULL); + } + else if (mDevice) + { + status = mDevice->TestCooperativeLevel(); + } + + switch (status) + { + case D3DERR_DEVICENOTRESET: + case D3DERR_DEVICEHUNG: + return true; + default: + return false; + } +} + void Display::getMultiSampleSupport(D3DFORMAT format, bool *multiSampleArray) { for (int multiSampleIndex = 0; multiSampleIndex <= D3DMULTISAMPLE_16_SAMPLES; multiSampleIndex++) @@ -818,7 +887,7 @@ bool Display::getDXT5TextureSupport() return SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0, D3DRTYPE_TEXTURE, D3DFMT_DXT5)); } -bool Display::getFloatTextureSupport(bool *filtering, bool *renderable) +bool Display::getFloat32TextureSupport(bool *filtering, bool *renderable) { D3DDISPLAYMODE currentDisplayMode; mD3d9->GetAdapterDisplayMode(mAdapter, ¤tDisplayMode); @@ -846,7 +915,7 @@ bool Display::getFloatTextureSupport(bool *filtering, bool *renderable) } } -bool Display::getHalfFloatTextureSupport(bool *filtering, bool *renderable) +bool Display::getFloat16TextureSupport(bool *filtering, bool *renderable) { D3DDISPLAYMODE currentDisplayMode; mD3d9->GetAdapterDisplayMode(mAdapter, ¤tDisplayMode); @@ -907,6 +976,23 @@ D3DPOOL Display::getBufferPool(DWORD usage) const return D3DPOOL_DEFAULT; } +D3DPOOL Display::getTexturePool(bool renderable) const +{ + if (mD3d9Ex != NULL) + { + return D3DPOOL_DEFAULT; + } + else + { + if (!renderable) + { + return D3DPOOL_MANAGED; + } + } + + return D3DPOOL_DEFAULT; +} + bool Display::getEventQuerySupport() { IDirect3DQuery9 *query; @@ -948,6 +1034,10 @@ void Display::initExtensionString() mExtensionString = ""; + // Multi-vendor (EXT) extensions + mExtensionString += "EGL_EXT_create_context_robustness "; + + // ANGLE-specific extensions if (isd3d9ex) { mExtensionString += "EGL_ANGLE_d3d_share_handle_client_buffer "; } diff --git a/gfx/angle/src/libEGL/Display.h b/gfx/angle/src/libEGL/Display.h index 5ceb6b4f2ccb..67e3d7da295e 100644 --- a/gfx/angle/src/libEGL/Display.h +++ b/gfx/angle/src/libEGL/Display.h @@ -44,7 +44,7 @@ class Display EGLSurface createWindowSurface(HWND window, EGLConfig config, const EGLint *attribList); EGLSurface createOffscreenSurface(EGLConfig config, HANDLE shareHandle, const EGLint *attribList); - EGLContext createContext(EGLConfig configHandle, const gl::Context *shareContext); + EGLContext createContext(EGLConfig configHandle, const gl::Context *shareContext, bool notifyResets, bool robustAccess); void destroySurface(egl::Surface *surface); void destroyContext(gl::Context *context); @@ -61,19 +61,24 @@ class Display virtual IDirect3DDevice9 *getDevice(); virtual D3DCAPS9 getDeviceCaps(); virtual D3DADAPTER_IDENTIFIER9 *getAdapterIdentifier(); - bool isDeviceLost(); + virtual bool testDeviceLost(); + virtual bool testDeviceResettable(); virtual void getMultiSampleSupport(D3DFORMAT format, bool *multiSampleArray); virtual bool getDXT1TextureSupport(); virtual bool getDXT3TextureSupport(); virtual bool getDXT5TextureSupport(); virtual bool getEventQuerySupport(); - virtual bool getFloatTextureSupport(bool *filtering, bool *renderable); - virtual bool getHalfFloatTextureSupport(bool *filtering, bool *renderable); + virtual bool getFloat32TextureSupport(bool *filtering, bool *renderable); + virtual bool getFloat16TextureSupport(bool *filtering, bool *renderable); virtual bool getLuminanceTextureSupport(); virtual bool getLuminanceAlphaTextureSupport(); virtual bool getVertexTextureSupport() const; virtual bool getNonPower2TextureSupport() const; virtual D3DPOOL getBufferPool(DWORD usage) const; + virtual D3DPOOL getTexturePool(bool renderable) const; + + virtual void notifyDeviceLost(); + bool isDeviceLost(); bool isD3d9ExDevice() { return mD3d9Ex != NULL; } const char *getExtensionString() const; @@ -114,6 +119,7 @@ class Display typedef std::set ContextSet; ContextSet mContextSet; + bool mDeviceLost; bool createDevice(); bool resetDevice(); diff --git a/gfx/angle/src/libEGL/Surface.cpp b/gfx/angle/src/libEGL/Surface.cpp index 6bc5b4d82e86..65ab96510ce0 100644 --- a/gfx/angle/src/libEGL/Surface.cpp +++ b/gfx/angle/src/libEGL/Surface.cpp @@ -106,7 +106,7 @@ bool Surface::initialize() result = DwmSetPresentParameters(mWindow, &presentParams); if (FAILED(result)) - ERR("Unable to set present parameters: %081X", result); + ERR("Unable to set present parameters: 0x%08X", result); } } @@ -250,11 +250,20 @@ bool Surface::resetSwapChain(int backbufferWidth, int backbufferHeight) if (FAILED(result)) { - ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_INVALIDCALL); + ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_INVALIDCALL || result == D3DERR_DEVICELOST); ERR("Could not create additional swap chains or offscreen surfaces: %08lX", result); release(); - return error(EGL_BAD_ALLOC, false); + + if(isDeviceLostError(result)) + { + mDisplay->notifyDeviceLost(); + return false; + } + else + { + return error(EGL_BAD_ALLOC, false); + } } if (mConfig->mDepthStencilFormat != D3DFMT_UNKNOWN) @@ -268,7 +277,7 @@ bool Surface::resetSwapChain(int backbufferWidth, int backbufferHeight) { ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_INVALIDCALL); - ERR("Could not create depthstencil surface for new swap chain: %08lX", result); + ERR("Could not create depthstencil surface for new swap chain: 0x%08X", result); release(); return error(EGL_BAD_ALLOC, false); } @@ -413,14 +422,15 @@ bool Surface::swap() HRESULT result = mSwapChain->Present(NULL, NULL, NULL, NULL, 0); - if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_DRIVERINTERNALERROR) + if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY) { return error(EGL_BAD_ALLOC, false); } - if (result == D3DERR_DEVICELOST || result == D3DERR_DEVICEHUNG || result == D3DERR_DEVICEREMOVED) + if (isDeviceLostError(result)) { - return error(EGL_CONTEXT_LOST, false); + mDisplay->notifyDeviceLost(); + return false; } ASSERT(SUCCEEDED(result)); diff --git a/gfx/angle/src/libEGL/libEGL.cpp b/gfx/angle/src/libEGL/libEGL.cpp index 89986e66edd0..4878350a85e5 100644 --- a/gfx/angle/src/libEGL/libEGL.cpp +++ b/gfx/angle/src/libEGL/libEGL.cpp @@ -715,7 +715,10 @@ EGLBoolean __stdcall eglBindTexImage(EGLDisplay dpy, EGLSurface surface, EGLint return error(EGL_BAD_MATCH, EGL_FALSE); } - glBindTexImage(eglSurface); + if (!glBindTexImage(eglSurface)) + { + return error(EGL_BAD_MATCH, EGL_FALSE); + } return success(EGL_TRUE); } @@ -814,16 +817,34 @@ EGLContext __stdcall eglCreateContext(EGLDisplay dpy, EGLConfig config, EGLConte { // Get the requested client version (default is 1) and check it is two. EGLint client_version = 1; + bool reset_notification = false; + bool robust_access = false; + if (attrib_list) { for (const EGLint* attribute = attrib_list; attribute[0] != EGL_NONE; attribute += 2) { - if (attribute[0] == EGL_CONTEXT_CLIENT_VERSION) + switch (attribute[0]) { + case EGL_CONTEXT_CLIENT_VERSION: client_version = attribute[1]; - } - else - { + break; + case EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT: + if (attribute[1] == EGL_TRUE) + { + return error(EGL_BAD_CONFIG, EGL_NO_CONTEXT); // Unimplemented + robust_access = true; + } + else if (attribute[1] != EGL_FALSE) + return error(EGL_BAD_ATTRIBUTE, EGL_NO_CONTEXT); + break; + case EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT: + if (attribute[1] == EGL_LOSE_CONTEXT_ON_RESET_EXT) + reset_notification = true; + else if (attribute[1] != EGL_NO_RESET_NOTIFICATION_EXT) + return error(EGL_BAD_ATTRIBUTE, EGL_NO_CONTEXT); + break; + default: return error(EGL_BAD_ATTRIBUTE, EGL_NO_CONTEXT); } } @@ -834,6 +855,11 @@ EGLContext __stdcall eglCreateContext(EGLDisplay dpy, EGLConfig config, EGLConte return error(EGL_BAD_CONFIG, EGL_NO_CONTEXT); } + if (share_context && static_cast(share_context)->isResetNotificationEnabled() != reset_notification) + { + return error(EGL_BAD_MATCH, EGL_NO_CONTEXT); + } + egl::Display *display = static_cast(dpy); if (!validateConfig(display, config)) @@ -841,9 +867,12 @@ EGLContext __stdcall eglCreateContext(EGLDisplay dpy, EGLConfig config, EGLConte return EGL_NO_CONTEXT; } - EGLContext context = display->createContext(config, static_cast(share_context)); + EGLContext context = display->createContext(config, static_cast(share_context), reset_notification, robust_access); - return success(context); + if (context) + return success(context); + else + return error(EGL_CONTEXT_LOST, EGL_NO_CONTEXT); } catch(std::bad_alloc&) { @@ -895,7 +924,13 @@ EGLBoolean __stdcall eglMakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface gl::Context *context = static_cast(ctx); IDirect3DDevice9 *device = display->getDevice(); - if (!device || display->isDeviceLost()) + if (!device || display->testDeviceLost()) + { + display->notifyDeviceLost(); + return EGL_FALSE; + } + + if (display->isDeviceLost()) { return error(EGL_CONTEXT_LOST, EGL_FALSE); } @@ -1077,6 +1112,11 @@ EGLBoolean __stdcall eglSwapBuffers(EGLDisplay dpy, EGLSurface surface) return EGL_FALSE; } + if (display->isDeviceLost()) + { + return error(EGL_CONTEXT_LOST, EGL_FALSE); + } + if (surface == EGL_NO_SURFACE) { return error(EGL_BAD_SURFACE, EGL_FALSE); @@ -1109,6 +1149,11 @@ EGLBoolean __stdcall eglCopyBuffers(EGLDisplay dpy, EGLSurface surface, EGLNativ return EGL_FALSE; } + if (display->isDeviceLost()) + { + return error(EGL_CONTEXT_LOST, EGL_FALSE); + } + UNIMPLEMENTED(); // FIXME return success(0); diff --git a/gfx/angle/src/libGLESv2/Context.cpp b/gfx/angle/src/libGLESv2/Context.cpp index 409bcce3303b..2bd651f7c61a 100644 --- a/gfx/angle/src/libGLESv2/Context.cpp +++ b/gfx/angle/src/libGLESv2/Context.cpp @@ -38,8 +38,10 @@ namespace namespace gl { -Context::Context(const egl::Config *config, const gl::Context *shareContext) : mConfig(config) +Context::Context(const egl::Config *config, const gl::Context *shareContext, bool notifyResets, bool robustAccess) : mConfig(config) { + ASSERT(robustAccess == false); // Unimplemented + mDisplay = NULL; mDevice = NULL; @@ -158,6 +160,10 @@ Context::Context(const egl::Config *config, const gl::Context *shareContext) : m mInvalidFramebufferOperation = false; mHasBeenCurrent = false; + mContextLost = false; + mResetStatus = GL_NO_ERROR; + mResetStrategy = (notifyResets ? GL_LOSE_CONTEXT_ON_RESET_EXT : GL_NO_RESET_NOTIFICATION_EXT); + mRobustAccess = robustAccess; mSupportsDXT1Textures = false; mSupportsDXT3Textures = false; @@ -290,8 +296,8 @@ void Context::makeCurrent(egl::Display *display, egl::Surface *surface) mSupportsDXT1Textures = mDisplay->getDXT1TextureSupport(); mSupportsDXT3Textures = mDisplay->getDXT3TextureSupport(); mSupportsDXT5Textures = mDisplay->getDXT5TextureSupport(); - mSupportsFloatTextures = mDisplay->getFloatTextureSupport(&mSupportsFloatLinearFilter, &mSupportsFloatRenderableTextures); - mSupportsHalfFloatTextures = mDisplay->getHalfFloatTextureSupport(&mSupportsHalfFloatLinearFilter, &mSupportsHalfFloatRenderableTextures); + mSupportsFloat32Textures = mDisplay->getFloat32TextureSupport(&mSupportsFloat32LinearFilter, &mSupportsFloat32RenderableTextures); + mSupportsFloat16Textures = mDisplay->getFloat16TextureSupport(&mSupportsFloat16LinearFilter, &mSupportsFloat16RenderableTextures); mSupportsLuminanceTextures = mDisplay->getLuminanceTextureSupport(); mSupportsLuminanceAlphaTextures = mDisplay->getLuminanceAlphaTextureSupport(); @@ -389,6 +395,18 @@ void Context::markAllStateDirty() mCachedCurrentProgram = NULL; } +void Context::markContextLost() +{ + if (mResetStrategy == GL_LOSE_CONTEXT_ON_RESET_EXT) + mResetStatus = GL_UNKNOWN_CONTEXT_RESET_EXT; + mContextLost = true; +} + +bool Context::isContextLost() +{ + return mContextLost; +} + void Context::setClearColor(float red, float green, float blue, float alpha) { mState.colorClearValue.red = red; @@ -1158,24 +1176,25 @@ bool Context::getBooleanv(GLenum pname, GLboolean *params) { switch (pname) { - case GL_SHADER_COMPILER: *params = GL_TRUE; break; - case GL_SAMPLE_COVERAGE_INVERT: *params = mState.sampleCoverageInvert; break; - case GL_DEPTH_WRITEMASK: *params = mState.depthMask; break; + case GL_SHADER_COMPILER: *params = GL_TRUE; break; + case GL_SAMPLE_COVERAGE_INVERT: *params = mState.sampleCoverageInvert; break; + case GL_DEPTH_WRITEMASK: *params = mState.depthMask; break; case GL_COLOR_WRITEMASK: params[0] = mState.colorMaskRed; params[1] = mState.colorMaskGreen; params[2] = mState.colorMaskBlue; params[3] = mState.colorMaskAlpha; break; - case GL_CULL_FACE: *params = mState.cullFace; break; - case GL_POLYGON_OFFSET_FILL: *params = mState.polygonOffsetFill; break; - case GL_SAMPLE_ALPHA_TO_COVERAGE: *params = mState.sampleAlphaToCoverage; break; - case GL_SAMPLE_COVERAGE: *params = mState.sampleCoverage; break; - case GL_SCISSOR_TEST: *params = mState.scissorTest; break; - case GL_STENCIL_TEST: *params = mState.stencilTest; break; - case GL_DEPTH_TEST: *params = mState.depthTest; break; - case GL_BLEND: *params = mState.blend; break; - case GL_DITHER: *params = mState.dither; break; + case GL_CULL_FACE: *params = mState.cullFace; break; + case GL_POLYGON_OFFSET_FILL: *params = mState.polygonOffsetFill; break; + case GL_SAMPLE_ALPHA_TO_COVERAGE: *params = mState.sampleAlphaToCoverage; break; + case GL_SAMPLE_COVERAGE: *params = mState.sampleCoverage; break; + case GL_SCISSOR_TEST: *params = mState.scissorTest; break; + case GL_STENCIL_TEST: *params = mState.stencilTest; break; + case GL_DEPTH_TEST: *params = mState.depthTest; break; + case GL_BLEND: *params = mState.blend; break; + case GL_DITHER: *params = mState.dither; break; + case GL_CONTEXT_ROBUST_ACCESS_EXT: *params = mRobustAccess ? GL_TRUE : GL_FALSE; break; default: return false; } @@ -1375,7 +1394,7 @@ bool Context::getIntegerv(GLenum pname, GLint *params) case GL_ALPHA_BITS: { gl::Framebuffer *framebuffer = getDrawFramebuffer(); - gl::Colorbuffer *colorbuffer = framebuffer->getColorbuffer(); + gl::Renderbuffer *colorbuffer = framebuffer->getColorbuffer(); if (colorbuffer) { @@ -1396,7 +1415,7 @@ bool Context::getIntegerv(GLenum pname, GLint *params) case GL_DEPTH_BITS: { gl::Framebuffer *framebuffer = getDrawFramebuffer(); - gl::DepthStencilbuffer *depthbuffer = framebuffer->getDepthbuffer(); + gl::Renderbuffer *depthbuffer = framebuffer->getDepthbuffer(); if (depthbuffer) { @@ -1411,7 +1430,7 @@ bool Context::getIntegerv(GLenum pname, GLint *params) case GL_STENCIL_BITS: { gl::Framebuffer *framebuffer = getDrawFramebuffer(); - gl::DepthStencilbuffer *stencilbuffer = framebuffer->getStencilbuffer(); + gl::Renderbuffer *stencilbuffer = framebuffer->getStencilbuffer(); if (stencilbuffer) { @@ -1445,6 +1464,9 @@ bool Context::getIntegerv(GLenum pname, GLint *params) *params = mState.samplerTexture[TEXTURE_CUBE][mState.activeSampler].id(); } break; + case GL_RESET_NOTIFICATION_STRATEGY_EXT: + *params = mResetStrategy; + break; default: return false; } @@ -1534,6 +1556,7 @@ bool Context::getQueryParameterInfo(GLenum pname, GLenum *type, unsigned int *nu case GL_IMPLEMENTATION_COLOR_READ_FORMAT: case GL_TEXTURE_BINDING_2D: case GL_TEXTURE_BINDING_CUBE_MAP: + case GL_RESET_NOTIFICATION_STRATEGY_EXT: { *type = GL_INT; *numParams = 1; @@ -1577,6 +1600,7 @@ bool Context::getQueryParameterInfo(GLenum pname, GLenum *type, unsigned int *nu case GL_DEPTH_TEST: case GL_BLEND: case GL_DITHER: + case GL_CONTEXT_ROBUST_ACCESS_EXT: { *type = GL_BOOL; *numParams = 1; @@ -1730,7 +1754,7 @@ bool Context::applyRenderTarget(bool ignoreViewport) return false; // Nothing to render } - if (!mViewportInitialized || memcmp(&viewport, &mSetViewport, sizeof mSetViewport) != 0) + if (renderTargetChanged || !mViewportInitialized || memcmp(&viewport, &mSetViewport, sizeof mSetViewport) != 0) { mDevice->SetViewport(&viewport); mSetViewport = viewport; @@ -1911,7 +1935,7 @@ void Context::applyState(GLenum drawMode) } // get the maximum size of the stencil ref - gl::DepthStencilbuffer *stencilbuffer = framebufferObject->getStencilbuffer(); + gl::Renderbuffer *stencilbuffer = framebufferObject->getStencilbuffer(); GLuint maxStencil = (1 << stencilbuffer->getStencilSize()) - 1; mDevice->SetRenderState(adjustedFrontFace == GL_CCW ? D3DRS_STENCILWRITEMASK : D3DRS_CCW_STENCILWRITEMASK, mState.stencilWritemask); @@ -1978,7 +2002,7 @@ void Context::applyState(GLenum drawMode) { if (mState.polygonOffsetFill) { - gl::DepthStencilbuffer *depthbuffer = framebufferObject->getDepthbuffer(); + gl::Renderbuffer *depthbuffer = framebufferObject->getDepthbuffer(); if (depthbuffer) { mDevice->SetRenderState(D3DRS_SLOPESCALEDEPTHBIAS, *((DWORD*)&mState.polygonOffsetFactor)); @@ -2127,13 +2151,13 @@ void Context::applyTextures(SamplerType type) Texture *texture = getSamplerTexture(textureUnit, textureType); - if (appliedTextureSerial[samplerIndex] != texture->getSerial() || texture->isDirtyParameter() || texture->isDirtyImage()) + if (appliedTextureSerial[samplerIndex] != texture->getTextureSerial() || texture->hasDirtyParameters() || texture->hasDirtyImages()) { IDirect3DBaseTexture9 *d3dTexture = texture->getTexture(); if (d3dTexture) { - if (appliedTextureSerial[samplerIndex] != texture->getSerial() || texture->isDirtyParameter()) + if (appliedTextureSerial[samplerIndex] != texture->getTextureSerial() || texture->hasDirtyParameters()) { GLenum wrapS = texture->getWrapS(); GLenum wrapT = texture->getWrapT(); @@ -2150,7 +2174,7 @@ void Context::applyTextures(SamplerType type) mDevice->SetSamplerState(d3dSampler, D3DSAMP_MIPFILTER, d3dMipFilter); } - if (appliedTextureSerial[samplerIndex] != texture->getSerial() || texture->isDirtyImage()) + if (appliedTextureSerial[samplerIndex] != texture->getTextureSerial() || texture->hasDirtyImages()) { mDevice->SetTexture(d3dSampler, d3dTexture); } @@ -2160,7 +2184,7 @@ void Context::applyTextures(SamplerType type) mDevice->SetTexture(d3dSampler, getIncompleteTexture(textureType)->getTexture()); } - appliedTextureSerial[samplerIndex] = texture->getSerial(); + appliedTextureSerial[samplerIndex] = texture->getTextureSerial(); texture->resetDirty(); } } @@ -2184,7 +2208,8 @@ void Context::applyTextures(SamplerType type) } } -void Context::readPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels) +void Context::readPixels(GLint x, GLint y, GLsizei width, GLsizei height, + GLenum format, GLenum type, GLsizei *bufSize, void* pixels) { Framebuffer *framebuffer = getReadFramebuffer(); @@ -2198,6 +2223,17 @@ void Context::readPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum return error(GL_INVALID_OPERATION); } + GLsizei outputPitch = ComputePitch(width, format, type, mState.packAlignment); + // sized query sanity check + if (bufSize) + { + int requiredSize = outputPitch * height; + if (requiredSize > *bufSize) + { + return error(GL_INVALID_OPERATION); + } + } + IDirect3DSurface9 *renderTarget = framebuffer->getRenderTarget(); if (!renderTarget) @@ -2229,18 +2265,16 @@ void Context::readPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum { systemSurface->Release(); - switch (result) - { - // It turns out that D3D will sometimes produce more error - // codes than those documented. - case D3DERR_DRIVERINTERNALERROR: - case D3DERR_DEVICELOST: - case D3DERR_DEVICEHUNG: + // It turns out that D3D will sometimes produce more error + // codes than those documented. + if (checkDeviceLost(result)) return error(GL_OUT_OF_MEMORY); - default: + else + { UNREACHABLE(); - return; // No sensible error to generate + return; } + } D3DLOCKED_RECT lock; @@ -2264,7 +2298,6 @@ void Context::readPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum unsigned char *dest = (unsigned char*)pixels; unsigned short *dest16 = (unsigned short*)pixels; int inputPitch = -lock.Pitch; - GLsizei outputPitch = ComputePitch(width, format, type, mState.packAlignment); for (int j = 0; j < rect.bottom - rect.top; j++) { @@ -2826,7 +2859,7 @@ void Context::sync(bool block) eventQuery->Release(); - if (result == D3DERR_DEVICELOST) + if (checkDeviceLost(result)) { error(GL_OUT_OF_MEMORY); } @@ -2994,6 +3027,36 @@ GLenum Context::getError() return GL_NO_ERROR; } +GLenum Context::getResetStatus() +{ + if (mResetStatus == GL_NO_ERROR) + { + bool lost = mDisplay->testDeviceLost(); + + if (lost) + { + mDisplay->notifyDeviceLost(); // Sets mResetStatus + } + } + + GLenum status = mResetStatus; + + if (mResetStatus != GL_NO_ERROR) + { + if (mDisplay->testDeviceResettable()) + { + mResetStatus = GL_NO_ERROR; + } + } + + return status; +} + +bool Context::isResetNotificationEnabled() +{ + return (mResetStrategy == GL_LOSE_CONTEXT_ON_RESET_EXT); +} + bool Context::supportsShaderModel3() const { return mSupportsShaderModel3; @@ -3068,34 +3131,34 @@ bool Context::supportsDXT5Textures() const return mSupportsDXT5Textures; } -bool Context::supportsFloatTextures() const +bool Context::supportsFloat32Textures() const { - return mSupportsFloatTextures; + return mSupportsFloat32Textures; } -bool Context::supportsFloatLinearFilter() const +bool Context::supportsFloat32LinearFilter() const { - return mSupportsFloatLinearFilter; + return mSupportsFloat32LinearFilter; } -bool Context::supportsFloatRenderableTextures() const +bool Context::supportsFloat32RenderableTextures() const { - return mSupportsFloatRenderableTextures; + return mSupportsFloat32RenderableTextures; } -bool Context::supportsHalfFloatTextures() const +bool Context::supportsFloat16Textures() const { - return mSupportsHalfFloatTextures; + return mSupportsFloat16Textures; } -bool Context::supportsHalfFloatLinearFilter() const +bool Context::supportsFloat16LinearFilter() const { - return mSupportsHalfFloatLinearFilter; + return mSupportsFloat16LinearFilter; } -bool Context::supportsHalfFloatRenderableTextures() const +bool Context::supportsFloat16RenderableTextures() const { - return mSupportsHalfFloatRenderableTextures; + return mSupportsFloat16RenderableTextures; } int Context::getMaximumRenderbufferDimension() const @@ -3344,19 +3407,19 @@ void Context::initExtensionString() mExtensionString += "GL_OES_rgb8_rgba8 "; mExtensionString += "GL_OES_standard_derivatives "; - if (supportsHalfFloatTextures()) + if (supportsFloat16Textures()) { mExtensionString += "GL_OES_texture_half_float "; } - if (supportsHalfFloatLinearFilter()) + if (supportsFloat16LinearFilter()) { mExtensionString += "GL_OES_texture_half_float_linear "; } - if (supportsFloatTextures()) + if (supportsFloat32Textures()) { mExtensionString += "GL_OES_texture_float "; } - if (supportsFloatLinearFilter()) + if (supportsFloat32LinearFilter()) { mExtensionString += "GL_OES_texture_float_linear "; } @@ -3368,6 +3431,7 @@ void Context::initExtensionString() // Multi-vendor (EXT) extensions mExtensionString += "GL_EXT_read_format_bgra "; + mExtensionString += "GL_EXT_robustness "; if (supportsDXT1Textures()) { @@ -3375,6 +3439,7 @@ void Context::initExtensionString() } mExtensionString += "GL_EXT_texture_format_BGRA8888 "; + mExtensionString += "GL_EXT_texture_storage "; // ANGLE-specific extensions mExtensionString += "GL_ANGLE_framebuffer_blit "; @@ -3391,6 +3456,8 @@ void Context::initExtensionString() { mExtensionString += "GL_ANGLE_texture_compression_dxt5 "; } + + mExtensionString += "GL_ANGLE_texture_usage "; mExtensionString += "GL_ANGLE_translated_shader_source "; // Other vendor-specific extensions @@ -3616,8 +3683,8 @@ void Context::blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1 if (mask & (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)) { - DepthStencilbuffer *readDSBuffer = NULL; - DepthStencilbuffer *drawDSBuffer = NULL; + Renderbuffer *readDSBuffer = NULL; + Renderbuffer *drawDSBuffer = NULL; // We support OES_packed_depth_stencil, and do not support a separately attached depth and stencil buffer, so if we have // both a depth and stencil buffer, it will be the same buffer. @@ -3805,9 +3872,9 @@ void VertexDeclarationCache::markStateDirty() extern "C" { -gl::Context *glCreateContext(const egl::Config *config, const gl::Context *shareContext) +gl::Context *glCreateContext(const egl::Config *config, const gl::Context *shareContext, bool notifyResets, bool robustAccess) { - return new gl::Context(config, shareContext); + return new gl::Context(config, shareContext, notifyResets, robustAccess); } void glDestroyContext(gl::Context *context) diff --git a/gfx/angle/src/libGLESv2/Context.h b/gfx/angle/src/libGLESv2/Context.h index f5398766dff3..07584dda3f5b 100644 --- a/gfx/angle/src/libGLESv2/Context.h +++ b/gfx/angle/src/libGLESv2/Context.h @@ -258,7 +258,7 @@ class VertexDeclarationCache class Context { public: - Context(const egl::Config *config, const gl::Context *shareContext); + Context(const egl::Config *config, const gl::Context *shareContext, bool notifyResets, bool robustAccess); ~Context(); @@ -266,6 +266,9 @@ class Context void markAllStateDirty(); + virtual void markContextLost(); + bool isContextLost(); + // State manipulation void setClearColor(float red, float green, float blue, float alpha); @@ -417,7 +420,7 @@ class Context bool getQueryParameterInfo(GLenum pname, GLenum *type, unsigned int *numParams); - void readPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels); + void readPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei *bufSize, void* pixels); void clear(GLbitfield mask); void drawArrays(GLenum mode, GLint first, GLsizei count); void drawElements(GLenum mode, GLsizei count, GLenum type, const void *indices); @@ -434,6 +437,8 @@ class Context void recordInvalidFramebufferOperation(); GLenum getError(); + GLenum getResetStatus(); + virtual bool isResetNotificationEnabled(); bool supportsShaderModel3() const; int getMaximumVaryingVectors() const; @@ -452,12 +457,12 @@ class Context bool supportsDXT1Textures() const; bool supportsDXT3Textures() const; bool supportsDXT5Textures() const; - bool supportsFloatTextures() const; - bool supportsFloatLinearFilter() const; - bool supportsFloatRenderableTextures() const; - bool supportsHalfFloatTextures() const; - bool supportsHalfFloatLinearFilter() const; - bool supportsHalfFloatRenderableTextures() const; + bool supportsFloat32Textures() const; + bool supportsFloat32LinearFilter() const; + bool supportsFloat32RenderableTextures() const; + bool supportsFloat16Textures() const; + bool supportsFloat16LinearFilter() const; + bool supportsFloat16RenderableTextures() const; bool supportsLuminanceTextures() const; bool supportsLuminanceAlphaTextures() const; bool supports32bitIndices() const; @@ -531,7 +536,12 @@ class Context bool mOutOfMemory; bool mInvalidFramebufferOperation; + // Current/lost context flags bool mHasBeenCurrent; + bool mContextLost; + GLenum mResetStatus; + GLenum mResetStrategy; + bool mRobustAccess; unsigned int mAppliedTextureSerialPS[MAX_TEXTURE_IMAGE_UNITS]; unsigned int mAppliedTextureSerialVS[MAX_VERTEX_TEXTURE_IMAGE_UNITS_VTF]; @@ -562,12 +572,12 @@ class Context bool mSupportsDXT1Textures; bool mSupportsDXT3Textures; bool mSupportsDXT5Textures; - bool mSupportsFloatTextures; - bool mSupportsFloatLinearFilter; - bool mSupportsFloatRenderableTextures; - bool mSupportsHalfFloatTextures; - bool mSupportsHalfFloatLinearFilter; - bool mSupportsHalfFloatRenderableTextures; + bool mSupportsFloat32Textures; + bool mSupportsFloat32LinearFilter; + bool mSupportsFloat32RenderableTextures; + bool mSupportsFloat16Textures; + bool mSupportsFloat16LinearFilter; + bool mSupportsFloat16RenderableTextures; bool mSupportsLuminanceTextures; bool mSupportsLuminanceAlphaTextures; bool mSupports32bitIndices; @@ -600,12 +610,12 @@ class Context extern "C" { // Exported functions for use by EGL -gl::Context *glCreateContext(const egl::Config *config, const gl::Context *shareContext); +gl::Context *glCreateContext(const egl::Config *config, const gl::Context *shareContext, bool notifyResets, bool robustAccess); void glDestroyContext(gl::Context *context); void glMakeCurrent(gl::Context *context, egl::Display *display, egl::Surface *surface); gl::Context *glGetCurrentContext(); __eglMustCastToProperFunctionPointerType __stdcall glGetProcAddress(const char *procname); -void __stdcall glBindTexImage(egl::Surface *surface); +bool __stdcall glBindTexImage(egl::Surface *surface); } #endif // INCLUDE_CONTEXT_H_ diff --git a/gfx/angle/src/libGLESv2/Fence.cpp b/gfx/angle/src/libGLESv2/Fence.cpp index 7fbcb6ad34db..96a3cc9f58bf 100644 --- a/gfx/angle/src/libGLESv2/Fence.cpp +++ b/gfx/angle/src/libGLESv2/Fence.cpp @@ -65,7 +65,7 @@ GLboolean Fence::testFence() HRESULT result = mQuery->GetData(NULL, 0, D3DGETDATA_FLUSH); - if (result == D3DERR_DEVICELOST) + if (checkDeviceLost(result)) { return error(GL_OUT_OF_MEMORY, GL_TRUE); } @@ -110,7 +110,7 @@ void Fence::getFenceiv(GLenum pname, GLint *params) HRESULT result = mQuery->GetData(NULL, 0, 0); - if (result == D3DERR_DEVICELOST) + if (checkDeviceLost(result)) { params[0] = GL_TRUE; return error(GL_OUT_OF_MEMORY); diff --git a/gfx/angle/src/libGLESv2/Framebuffer.cpp b/gfx/angle/src/libGLESv2/Framebuffer.cpp index 3858e2694f05..00f7f98cea35 100644 --- a/gfx/angle/src/libGLESv2/Framebuffer.cpp +++ b/gfx/angle/src/libGLESv2/Framebuffer.cpp @@ -181,46 +181,19 @@ unsigned int Framebuffer::getStencilbufferSerial() return 0; } -Colorbuffer *Framebuffer::getColorbuffer() +Renderbuffer *Framebuffer::getColorbuffer() { - Renderbuffer *rb = mColorbufferPointer.get(); - - if (rb != NULL && rb->isColorbuffer()) - { - return static_cast(rb->getStorage()); - } - else - { - return NULL; - } + return mColorbufferPointer.get(); } -DepthStencilbuffer *Framebuffer::getDepthbuffer() +Renderbuffer *Framebuffer::getDepthbuffer() { - Renderbuffer *rb = mDepthbufferPointer.get(); - - if (rb != NULL && rb->isDepthbuffer()) - { - return static_cast(rb->getStorage()); - } - else - { - return NULL; - } + return mDepthbufferPointer.get(); } -DepthStencilbuffer *Framebuffer::getStencilbuffer() +Renderbuffer *Framebuffer::getStencilbuffer() { - Renderbuffer *rb = mStencilbufferPointer.get(); - - if (rb != NULL && rb->isStencilbuffer()) - { - return static_cast(rb->getStorage()); - } - else - { - return NULL; - } + return mStencilbufferPointer.get(); } GLenum Framebuffer::getColorbufferType() @@ -257,7 +230,7 @@ bool Framebuffer::hasStencil() { if (mStencilbufferType != GL_NONE) { - DepthStencilbuffer *stencilbufferObject = getStencilbuffer(); + Renderbuffer *stencilbufferObject = getStencilbuffer(); if (stencilbufferObject) { @@ -276,7 +249,7 @@ GLenum Framebuffer::completeness() if (mColorbufferType != GL_NONE) { - Colorbuffer *colorbuffer = getColorbuffer(); + Renderbuffer *colorbuffer = getColorbuffer(); if (!colorbuffer) { @@ -302,8 +275,8 @@ GLenum Framebuffer::completeness() return GL_FRAMEBUFFER_UNSUPPORTED; } - if ((colorbuffer->getType() == GL_FLOAT && !getContext()->supportsFloatRenderableTextures()) || - (colorbuffer->getType() == GL_HALF_FLOAT_OES && !getContext()->supportsHalfFloatRenderableTextures())) + if ((dx2es::IsFloat32Format(colorbuffer->getD3DFormat()) && !getContext()->supportsFloat32RenderableTextures()) || + (dx2es::IsFloat16Format(colorbuffer->getD3DFormat()) && !getContext()->supportsFloat16RenderableTextures())) { return GL_FRAMEBUFFER_UNSUPPORTED; } @@ -324,8 +297,8 @@ GLenum Framebuffer::completeness() return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT; } - DepthStencilbuffer *depthbuffer = NULL; - DepthStencilbuffer *stencilbuffer = NULL; + Renderbuffer *depthbuffer = NULL; + Renderbuffer *stencilbuffer = NULL; if (mDepthbufferType != GL_NONE) { @@ -418,17 +391,17 @@ GLenum Framebuffer::completeness() return GL_FRAMEBUFFER_COMPLETE; } -DefaultFramebuffer::DefaultFramebuffer(Colorbuffer *color, DepthStencilbuffer *depthStencil) +DefaultFramebuffer::DefaultFramebuffer(Colorbuffer *colorbuffer, DepthStencilbuffer *depthStencil) { - mColorbufferType = GL_RENDERBUFFER; - mDepthbufferType = (depthStencil->getDepthSize() != 0) ? GL_RENDERBUFFER : GL_NONE; - mStencilbufferType = (depthStencil->getStencilSize() != 0) ? GL_RENDERBUFFER : GL_NONE; - - mColorbufferPointer.set(new Renderbuffer(0, color)); + mColorbufferPointer.set(new Renderbuffer(0, colorbuffer)); Renderbuffer *depthStencilRenderbuffer = new Renderbuffer(0, depthStencil); mDepthbufferPointer.set(depthStencilRenderbuffer); mStencilbufferPointer.set(depthStencilRenderbuffer); + + mColorbufferType = GL_RENDERBUFFER; + mDepthbufferType = (depthStencilRenderbuffer->getDepthSize() != 0) ? GL_RENDERBUFFER : GL_NONE; + mStencilbufferType = (depthStencilRenderbuffer->getStencilSize() != 0) ? GL_RENDERBUFFER : GL_NONE; } int Framebuffer::getSamples() diff --git a/gfx/angle/src/libGLESv2/Framebuffer.h b/gfx/angle/src/libGLESv2/Framebuffer.h index cf51658dd477..874cf94cb502 100644 --- a/gfx/angle/src/libGLESv2/Framebuffer.h +++ b/gfx/angle/src/libGLESv2/Framebuffer.h @@ -46,9 +46,9 @@ class Framebuffer unsigned int getDepthbufferSerial(); unsigned int getStencilbufferSerial(); - Colorbuffer *getColorbuffer(); - DepthStencilbuffer *getDepthbuffer(); - DepthStencilbuffer *getStencilbuffer(); + Renderbuffer *getColorbuffer(); + Renderbuffer *getDepthbuffer(); + Renderbuffer *getStencilbuffer(); GLenum getColorbufferType(); GLenum getDepthbufferType(); @@ -82,7 +82,7 @@ class Framebuffer class DefaultFramebuffer : public Framebuffer { public: - DefaultFramebuffer(Colorbuffer *color, DepthStencilbuffer *depthStencil); + DefaultFramebuffer(Colorbuffer *colorbuffer, DepthStencilbuffer *depthStencil); virtual GLenum completeness(); diff --git a/gfx/angle/src/libGLESv2/Program.cpp b/gfx/angle/src/libGLESv2/Program.cpp index 60cd4f202ac8..e1f3132021cd 100644 --- a/gfx/angle/src/libGLESv2/Program.cpp +++ b/gfx/angle/src/libGLESv2/Program.cpp @@ -36,7 +36,7 @@ std::string str(int i) Uniform::Uniform(GLenum type, const std::string &_name, unsigned int arraySize) : type(type), _name(_name), name(Program::undecorateUniform(_name)), arraySize(arraySize) { - int bytes = UniformTypeSize(type) * arraySize; + int bytes = UniformInternalSize(type) * arraySize; data = new unsigned char[bytes]; memset(data, 0, bytes); dirty = true; @@ -560,7 +560,7 @@ void transposeMatrix(T *target, const GLfloat *value) { for (int y = 0; y < copyHeight; y++) { - target[x * targetWidth + y] = value[y * srcWidth + x]; + target[x * targetWidth + y] = (T)value[y * srcWidth + x]; } } // clear unfilled right side @@ -568,7 +568,7 @@ void transposeMatrix(T *target, const GLfloat *value) { for (int x = srcWidth; x < targetWidth; x++) { - target[y * targetWidth + x] = 0; + target[y * targetWidth + x] = (T)0; } } // clear unfilled bottom. @@ -576,7 +576,7 @@ void transposeMatrix(T *target, const GLfloat *value) { for (int x = 0; x < targetWidth; x++) { - target[y * targetWidth + x] = 0; + target[y * targetWidth + x] = (T)0; } } } @@ -911,7 +911,7 @@ bool Program::setUniform4iv(GLint location, GLsizei count, const GLint *v) return true; } -bool Program::getUniformfv(GLint location, GLfloat *params) +bool Program::getUniformfv(GLint location, GLsizei *bufSize, GLfloat *params) { if (location < 0 || location >= (int)mUniformIndex.size()) { @@ -920,6 +920,16 @@ bool Program::getUniformfv(GLint location, GLfloat *params) Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; + // sized queries -- ensure the provided buffer is large enough + if (bufSize) + { + int requiredBytes = UniformExternalSize(targetUniform->type); + if (*bufSize < requiredBytes) + { + return false; + } + } + switch (targetUniform->type) { case GL_FLOAT_MAT2: @@ -933,7 +943,7 @@ bool Program::getUniformfv(GLint location, GLfloat *params) break; default: { - unsigned int count = UniformComponentCount(targetUniform->type); + unsigned int count = UniformExternalComponentCount(targetUniform->type); unsigned int internalCount = UniformInternalComponentCount(targetUniform->type); switch (UniformComponentType(targetUniform->type)) @@ -970,7 +980,7 @@ bool Program::getUniformfv(GLint location, GLfloat *params) return true; } -bool Program::getUniformiv(GLint location, GLint *params) +bool Program::getUniformiv(GLint location, GLsizei *bufSize, GLint *params) { if (location < 0 || location >= (int)mUniformIndex.size()) { @@ -979,6 +989,16 @@ bool Program::getUniformiv(GLint location, GLint *params) Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; + // sized queries -- ensure the provided buffer is large enough + if (bufSize) + { + int requiredBytes = UniformExternalSize(targetUniform->type); + if (*bufSize < requiredBytes) + { + return false; + } + } + switch (targetUniform->type) { case GL_FLOAT_MAT2: @@ -998,7 +1018,7 @@ bool Program::getUniformiv(GLint location, GLint *params) break; default: { - unsigned int count = UniformComponentCount(targetUniform->type); + unsigned int count = UniformExternalComponentCount(targetUniform->type); unsigned int internalCount = UniformInternalComponentCount(targetUniform->type); switch (UniformComponentType(targetUniform->type)) @@ -1834,10 +1854,15 @@ bool Program::defineUniform(const D3DXHANDLE &constantHandle, const D3DXCONSTANT { if (constantDescription.RegisterSet == D3DXRS_SAMPLER) { - for (unsigned int samplerIndex = constantDescription.RegisterIndex; samplerIndex < constantDescription.RegisterIndex + constantDescription.RegisterCount; samplerIndex++) + for (unsigned int i = 0; i < constantDescription.RegisterCount; i++) { - if (mConstantTablePS->GetConstantByName(NULL, constantDescription.Name) != NULL) + D3DXHANDLE psConstant = mConstantTablePS->GetConstantByName(NULL, constantDescription.Name); + D3DXHANDLE vsConstant = mConstantTableVS->GetConstantByName(NULL, constantDescription.Name); + + if (psConstant) { + unsigned int samplerIndex = mConstantTablePS->GetSamplerIndex(psConstant) + i; + if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS) { mSamplersPS[samplerIndex].active = true; @@ -1852,8 +1877,10 @@ bool Program::defineUniform(const D3DXHANDLE &constantHandle, const D3DXCONSTANT } } - if (mConstantTableVS->GetConstantByName(NULL, constantDescription.Name) != NULL) + if (vsConstant) { + unsigned int samplerIndex = mConstantTableVS->GetSamplerIndex(vsConstant) + i; + if (samplerIndex < getContext()->getMaximumVertexTextureImageUnits()) { mSamplersVS[samplerIndex].active = true; diff --git a/gfx/angle/src/libGLESv2/Program.h b/gfx/angle/src/libGLESv2/Program.h index 793bbf777f28..462f4e15cd14 100644 --- a/gfx/angle/src/libGLESv2/Program.h +++ b/gfx/angle/src/libGLESv2/Program.h @@ -98,8 +98,8 @@ class Program bool setUniform3iv(GLint location, GLsizei count, const GLint *v); bool setUniform4iv(GLint location, GLsizei count, const GLint *v); - bool getUniformfv(GLint location, GLfloat *params); - bool getUniformiv(GLint location, GLint *params); + bool getUniformfv(GLint location, GLsizei *bufSize, GLfloat *params); + bool getUniformiv(GLint location, GLsizei *bufSize, GLint *params); GLint getDxDepthRangeLocation() const; GLint getDxDepthLocation() const; diff --git a/gfx/angle/src/libGLESv2/Renderbuffer.cpp b/gfx/angle/src/libGLESv2/Renderbuffer.cpp index ace8d7b9043d..a39c4ad7150d 100644 --- a/gfx/angle/src/libGLESv2/Renderbuffer.cpp +++ b/gfx/angle/src/libGLESv2/Renderbuffer.cpp @@ -18,103 +18,175 @@ namespace gl { unsigned int RenderbufferStorage::mCurrentSerial = 1; -Renderbuffer::Renderbuffer(GLuint id, RenderbufferStorage *storage) : RefCountObject(id) +RenderbufferInterface::RenderbufferInterface() { - ASSERT(storage != NULL); - mStorage = storage; +} + +GLuint RenderbufferInterface::getRedSize() const +{ + return dx2es::GetRedSize(getD3DFormat()); +} + +GLuint RenderbufferInterface::getGreenSize() const +{ + return dx2es::GetGreenSize(getD3DFormat()); +} + +GLuint RenderbufferInterface::getBlueSize() const +{ + return dx2es::GetBlueSize(getD3DFormat()); +} + +GLuint RenderbufferInterface::getAlphaSize() const +{ + return dx2es::GetAlphaSize(getD3DFormat()); +} + +GLuint RenderbufferInterface::getDepthSize() const +{ + return dx2es::GetDepthSize(getD3DFormat()); +} + +GLuint RenderbufferInterface::getStencilSize() const +{ + return dx2es::GetStencilSize(getD3DFormat()); +} + +RenderbufferTexture::RenderbufferTexture(Texture *texture, GLenum target) : mTexture(texture), mTarget(target) +{ +} + +RenderbufferTexture::~RenderbufferTexture() +{ +} + +IDirect3DSurface9 *RenderbufferTexture::getRenderTarget() +{ + return mTexture->getRenderTarget(mTarget); +} + +IDirect3DSurface9 *RenderbufferTexture::getDepthStencil() +{ + return NULL; +} + +GLsizei RenderbufferTexture::getWidth() const +{ + return mTexture->getWidth(); +} + +GLsizei RenderbufferTexture::getHeight() const +{ + return mTexture->getHeight(); +} + +GLenum RenderbufferTexture::getInternalFormat() const +{ + return mTexture->getInternalFormat(); +} + +D3DFORMAT RenderbufferTexture::getD3DFormat() const +{ + return mTexture->getD3DFormat(); +} + +GLsizei RenderbufferTexture::getSamples() const +{ + return 0; +} + +unsigned int RenderbufferTexture::getSerial() const +{ + return mTexture->getRenderTargetSerial(mTarget); +} + +Renderbuffer::Renderbuffer(GLuint id, RenderbufferInterface *instance) : RefCountObject(id) +{ + ASSERT(instance != NULL); + mInstance = instance; } Renderbuffer::~Renderbuffer() { - delete mStorage; -} - -bool Renderbuffer::isColorbuffer() const -{ - return mStorage->isColorbuffer(); -} - -bool Renderbuffer::isDepthbuffer() const -{ - return mStorage->isDepthbuffer(); -} - -bool Renderbuffer::isStencilbuffer() const -{ - return mStorage->isStencilbuffer(); + delete mInstance; } IDirect3DSurface9 *Renderbuffer::getRenderTarget() { - return mStorage->getRenderTarget(); + return mInstance->getRenderTarget(); } IDirect3DSurface9 *Renderbuffer::getDepthStencil() { - return mStorage->getDepthStencil(); + return mInstance->getDepthStencil(); } GLsizei Renderbuffer::getWidth() const { - return mStorage->getWidth(); + return mInstance->getWidth(); } GLsizei Renderbuffer::getHeight() const { - return mStorage->getHeight(); + return mInstance->getHeight(); } GLenum Renderbuffer::getInternalFormat() const { - return mStorage->getInternalFormat(); + return mInstance->getInternalFormat(); +} + +D3DFORMAT Renderbuffer::getD3DFormat() const +{ + return mInstance->getD3DFormat(); } GLuint Renderbuffer::getRedSize() const { - return mStorage->getRedSize(); + return mInstance->getRedSize(); } GLuint Renderbuffer::getGreenSize() const { - return mStorage->getGreenSize(); + return mInstance->getGreenSize(); } GLuint Renderbuffer::getBlueSize() const { - return mStorage->getBlueSize(); + return mInstance->getBlueSize(); } GLuint Renderbuffer::getAlphaSize() const { - return mStorage->getAlphaSize(); + return mInstance->getAlphaSize(); } GLuint Renderbuffer::getDepthSize() const { - return mStorage->getDepthSize(); + return mInstance->getDepthSize(); } GLuint Renderbuffer::getStencilSize() const { - return mStorage->getStencilSize(); + return mInstance->getStencilSize(); } GLsizei Renderbuffer::getSamples() const { - return mStorage->getSamples(); + return mInstance->getSamples(); } unsigned int Renderbuffer::getSerial() const { - return mStorage->getSerial(); + return mInstance->getSerial(); } void Renderbuffer::setStorage(RenderbufferStorage *newStorage) { ASSERT(newStorage != NULL); - delete mStorage; - mStorage = newStorage; + delete mInstance; + mInstance = newStorage; } RenderbufferStorage::RenderbufferStorage() : mSerial(issueSerial()) @@ -130,21 +202,6 @@ RenderbufferStorage::~RenderbufferStorage() { } -bool RenderbufferStorage::isColorbuffer() const -{ - return false; -} - -bool RenderbufferStorage::isDepthbuffer() const -{ - return false; -} - -bool RenderbufferStorage::isStencilbuffer() const -{ - return false; -} - IDirect3DSurface9 *RenderbufferStorage::getRenderTarget() { return NULL; @@ -170,34 +227,9 @@ GLenum RenderbufferStorage::getInternalFormat() const return mInternalFormat; } -GLuint RenderbufferStorage::getRedSize() const +D3DFORMAT RenderbufferStorage::getD3DFormat() const { - return dx2es::GetRedSize(getD3DFormat()); -} - -GLuint RenderbufferStorage::getGreenSize() const -{ - return dx2es::GetGreenSize(getD3DFormat()); -} - -GLuint RenderbufferStorage::getBlueSize() const -{ - return dx2es::GetBlueSize(getD3DFormat()); -} - -GLuint RenderbufferStorage::getAlphaSize() const -{ - return dx2es::GetAlphaSize(getD3DFormat()); -} - -GLuint RenderbufferStorage::getDepthSize() const -{ - return dx2es::GetDepthSize(getD3DFormat()); -} - -GLuint RenderbufferStorage::getStencilSize() const -{ - return dx2es::GetStencilSize(getD3DFormat()); + return mD3DFormat; } GLsizei RenderbufferStorage::getSamples() const @@ -205,11 +237,6 @@ GLsizei RenderbufferStorage::getSamples() const return mSamples; } -D3DFORMAT RenderbufferStorage::getD3DFormat() const -{ - return mD3DFormat; -} - unsigned int RenderbufferStorage::getSerial() const { return mSerial; @@ -220,7 +247,14 @@ unsigned int RenderbufferStorage::issueSerial() return mCurrentSerial++; } -Colorbuffer::Colorbuffer(IDirect3DSurface9 *renderTarget) : mRenderTarget(renderTarget), mTexture(NULL) +unsigned int RenderbufferStorage::issueCubeSerials() +{ + unsigned int firstSerial = mCurrentSerial; + mCurrentSerial += 6; + return firstSerial; +} + +Colorbuffer::Colorbuffer(IDirect3DSurface9 *renderTarget) : mRenderTarget(renderTarget) { if (renderTarget) { @@ -237,21 +271,7 @@ Colorbuffer::Colorbuffer(IDirect3DSurface9 *renderTarget) : mRenderTarget(render } } -Colorbuffer::Colorbuffer(Texture *texture, GLenum target) : mRenderTarget(NULL), mTexture(texture), mTarget(target) -{ - if (texture) - { - mWidth = texture->getWidth(); - mHeight = texture->getHeight(); - mInternalFormat = texture->getInternalFormat(); - mD3DFormat = texture->getD3DFormat(); - mSamples = 0; - - mRenderTarget = texture->getRenderTarget(target); - } -} - -Colorbuffer::Colorbuffer(int width, int height, GLenum format, GLsizei samples) : mRenderTarget(NULL), mTexture(NULL) +Colorbuffer::Colorbuffer(int width, int height, GLenum format, GLsizei samples) : mRenderTarget(NULL) { IDirect3DDevice9 *device = getDevice(); @@ -295,71 +315,11 @@ Colorbuffer::~Colorbuffer() } } -GLsizei Colorbuffer::getWidth() const -{ - if (mTexture) - { - return mTexture->getWidth(); - } - - return mWidth; -} - -GLsizei Colorbuffer::getHeight() const -{ - if (mTexture) - { - return mTexture->getHeight(); - } - - return mHeight; -} - -GLenum Colorbuffer::getInternalFormat() const -{ - if (mTexture) - { - return mTexture->getInternalFormat(); - } - - return mInternalFormat; -} - -GLenum Colorbuffer::getType() const -{ - if (mTexture) - { - return mTexture->getType(); - } - - return GL_UNSIGNED_BYTE; -} - -D3DFORMAT Colorbuffer::getD3DFormat() const -{ - if (mTexture) - { - return mTexture->getD3DFormat(); - } - - return mD3DFormat; -} - -bool Colorbuffer::isColorbuffer() const -{ - return true; -} - IDirect3DSurface9 *Colorbuffer::getRenderTarget() { - if (mTexture) + if (mRenderTarget) { - if (mRenderTarget) - { - mRenderTarget->Release(); - } - - mRenderTarget = mTexture->getRenderTarget(mTarget); + mRenderTarget->AddRef(); } return mRenderTarget; @@ -427,16 +387,6 @@ DepthStencilbuffer::~DepthStencilbuffer() } } -bool DepthStencilbuffer::isDepthbuffer() const -{ - return true; -} - -bool DepthStencilbuffer::isStencilbuffer() const -{ - return true; -} - IDirect3DSurface9 *DepthStencilbuffer::getDepthStencil() { return mDepthStencil; @@ -454,7 +404,7 @@ Depthbuffer::Depthbuffer(IDirect3DSurface9 *depthStencil) : DepthStencilbuffer(d Depthbuffer::Depthbuffer(int width, int height, GLsizei samples) : DepthStencilbuffer(width, height, samples) { - if (getDepthStencil()) + if (mDepthStencil) { mInternalFormat = GL_DEPTH_COMPONENT16; // If the renderbuffer parameters are queried, the calling function // will expect one of the valid renderbuffer formats for use in @@ -466,16 +416,6 @@ Depthbuffer::~Depthbuffer() { } -bool Depthbuffer::isDepthbuffer() const -{ - return true; -} - -bool Depthbuffer::isStencilbuffer() const -{ - return false; -} - Stencilbuffer::Stencilbuffer(IDirect3DSurface9 *depthStencil) : DepthStencilbuffer(depthStencil) { if (depthStencil) @@ -488,7 +428,7 @@ Stencilbuffer::Stencilbuffer(IDirect3DSurface9 *depthStencil) : DepthStencilbuff Stencilbuffer::Stencilbuffer(int width, int height, GLsizei samples) : DepthStencilbuffer(width, height, samples) { - if (getDepthStencil()) + if (mDepthStencil) { mInternalFormat = GL_STENCIL_INDEX8; // If the renderbuffer parameters are queried, the calling function // will expect one of the valid renderbuffer formats for use in @@ -500,13 +440,4 @@ Stencilbuffer::~Stencilbuffer() { } -bool Stencilbuffer::isDepthbuffer() const -{ - return false; -} - -bool Stencilbuffer::isStencilbuffer() const -{ - return true; -} } diff --git a/gfx/angle/src/libGLESv2/Renderbuffer.h b/gfx/angle/src/libGLESv2/Renderbuffer.h index 5cf829c70ab5..e854775d9295 100644 --- a/gfx/angle/src/libGLESv2/Renderbuffer.h +++ b/gfx/angle/src/libGLESv2/Renderbuffer.h @@ -22,38 +22,86 @@ namespace gl { class Texture; +class Colorbuffer; +class DepthStencilbuffer; + +class RenderbufferInterface +{ + public: + RenderbufferInterface(); + + virtual ~RenderbufferInterface() {}; + + virtual IDirect3DSurface9 *getRenderTarget() = 0; + virtual IDirect3DSurface9 *getDepthStencil() = 0; + + virtual GLsizei getWidth() const = 0; + virtual GLsizei getHeight() const = 0; + virtual GLenum getInternalFormat() const = 0; + virtual D3DFORMAT getD3DFormat() const = 0; + virtual GLsizei getSamples() const = 0; + + GLuint getRedSize() const; + GLuint getGreenSize() const; + GLuint getBlueSize() const; + GLuint getAlphaSize() const; + GLuint getDepthSize() const; + GLuint getStencilSize() const; + + virtual unsigned int getSerial() const = 0; + + private: + DISALLOW_COPY_AND_ASSIGN(RenderbufferInterface); +}; + +class RenderbufferTexture : public RenderbufferInterface +{ + public: + RenderbufferTexture(Texture *texture, GLenum target); + + virtual ~RenderbufferTexture(); + + IDirect3DSurface9 *getRenderTarget(); + IDirect3DSurface9 *getDepthStencil(); + + virtual GLsizei getWidth() const; + virtual GLsizei getHeight() const; + virtual GLenum getInternalFormat() const; + virtual D3DFORMAT getD3DFormat() const; + virtual GLsizei getSamples() const; + + virtual unsigned int getSerial() const; + + private: + DISALLOW_COPY_AND_ASSIGN(RenderbufferTexture); + + Texture *mTexture; + GLenum mTarget; +}; // A class derived from RenderbufferStorage is created whenever glRenderbufferStorage // is called. The specific concrete type depends on whether the internal format is // colour depth, stencil or packed depth/stencil. -class RenderbufferStorage +class RenderbufferStorage : public RenderbufferInterface { public: RenderbufferStorage(); virtual ~RenderbufferStorage() = 0; - virtual bool isColorbuffer() const; - virtual bool isDepthbuffer() const; - virtual bool isStencilbuffer() const; - virtual IDirect3DSurface9 *getRenderTarget(); virtual IDirect3DSurface9 *getDepthStencil(); virtual GLsizei getWidth() const; virtual GLsizei getHeight() const; virtual GLenum getInternalFormat() const; - GLuint getRedSize() const; - GLuint getGreenSize() const; - GLuint getBlueSize() const; - GLuint getAlphaSize() const; - GLuint getDepthSize() const; - GLuint getStencilSize() const; + virtual D3DFORMAT getD3DFormat() const; virtual GLsizei getSamples() const; - virtual D3DFORMAT getD3DFormat() const; + virtual unsigned int getSerial() const; - unsigned int getSerial() const; + static unsigned int issueSerial(); + static unsigned int issueCubeSerials(); protected: GLsizei mWidth; @@ -65,26 +113,20 @@ class RenderbufferStorage private: DISALLOW_COPY_AND_ASSIGN(RenderbufferStorage); - static unsigned int issueSerial(); - const unsigned int mSerial; static unsigned int mCurrentSerial; }; // Renderbuffer implements the GL renderbuffer object. -// It's only a proxy for a RenderbufferStorage instance; the internal object +// It's only a proxy for a RenderbufferInterface instance; the internal object // can change whenever glRenderbufferStorage is called. class Renderbuffer : public RefCountObject { public: - Renderbuffer(GLuint id, RenderbufferStorage *storage); + Renderbuffer(GLuint id, RenderbufferInterface *storage); - ~Renderbuffer(); - - bool isColorbuffer() const; - bool isDepthbuffer() const; - bool isStencilbuffer() const; + virtual ~Renderbuffer(); IDirect3DSurface9 *getRenderTarget(); IDirect3DSurface9 *getDepthStencil(); @@ -104,40 +146,27 @@ class Renderbuffer : public RefCountObject unsigned int getSerial() const; void setStorage(RenderbufferStorage *newStorage); - RenderbufferStorage *getStorage() { return mStorage; } private: DISALLOW_COPY_AND_ASSIGN(Renderbuffer); - RenderbufferStorage *mStorage; + RenderbufferInterface *mInstance; }; class Colorbuffer : public RenderbufferStorage { public: explicit Colorbuffer(IDirect3DSurface9 *renderTarget); - Colorbuffer(Texture *texture, GLenum target); Colorbuffer(GLsizei width, GLsizei height, GLenum format, GLsizei samples); virtual ~Colorbuffer(); - virtual bool isColorbuffer() const; - virtual IDirect3DSurface9 *getRenderTarget(); - virtual GLsizei getWidth() const; - virtual GLsizei getHeight() const; - virtual GLenum getInternalFormat() const; - virtual GLenum getType() const; - - virtual D3DFORMAT getD3DFormat() const; - private: DISALLOW_COPY_AND_ASSIGN(Colorbuffer); IDirect3DSurface9 *mRenderTarget; - Texture *mTexture; - GLenum mTarget; }; class DepthStencilbuffer : public RenderbufferStorage @@ -148,14 +177,13 @@ class DepthStencilbuffer : public RenderbufferStorage ~DepthStencilbuffer(); - virtual bool isDepthbuffer() const; - virtual bool isStencilbuffer() const; - virtual IDirect3DSurface9 *getDepthStencil(); + protected: + IDirect3DSurface9 *mDepthStencil; + private: DISALLOW_COPY_AND_ASSIGN(DepthStencilbuffer); - IDirect3DSurface9 *mDepthStencil; }; class Depthbuffer : public DepthStencilbuffer @@ -166,9 +194,6 @@ class Depthbuffer : public DepthStencilbuffer virtual ~Depthbuffer(); - virtual bool isDepthbuffer() const; - virtual bool isStencilbuffer() const; - private: DISALLOW_COPY_AND_ASSIGN(Depthbuffer); }; @@ -181,9 +206,6 @@ class Stencilbuffer : public DepthStencilbuffer virtual ~Stencilbuffer(); - virtual bool isDepthbuffer() const; - virtual bool isStencilbuffer() const; - private: DISALLOW_COPY_AND_ASSIGN(Stencilbuffer); }; diff --git a/gfx/angle/src/libGLESv2/Texture.cpp b/gfx/angle/src/libGLESv2/Texture.cpp index de3f1c08e66b..fbaf869594cd 100644 --- a/gfx/angle/src/libGLESv2/Texture.cpp +++ b/gfx/angle/src/libGLESv2/Texture.cpp @@ -33,22 +33,131 @@ namespace gl { -unsigned int Texture::mCurrentSerial = 1; +unsigned int TextureStorage::mCurrentTextureSerial = 1; -Texture::Image::Image() - : width(0), height(0), dirty(false), surface(NULL), format(GL_NONE), type(GL_UNSIGNED_BYTE) +Image::Image() { + mWidth = 0; + mHeight = 0; + mFormat = GL_NONE; + mType = GL_UNSIGNED_BYTE; + + mSurface = NULL; + + mDirty = false; + mManaged = false; } -Texture::Image::~Image() +Image::~Image() { - if (surface) + if (mSurface) { - surface->Release(); + mSurface->Release(); } } -bool Texture::Image::isRenderable() const +bool Image::redefine(GLenum format, GLsizei width, GLsizei height, GLenum type, bool forceRelease) +{ + if (mWidth != width || + mHeight != height || + mFormat != format || + mType != type || + forceRelease) + { + mWidth = width; + mHeight = height; + mFormat = format; + mType = type; + + if (mSurface) + { + mSurface->Release(); + mSurface = NULL; + } + + return true; + } + + return false; +} + +void Image::createSurface() +{ + if(mSurface) + { + return; + } + + IDirect3DTexture9 *newTexture = NULL; + IDirect3DSurface9 *newSurface = NULL; + + if (mWidth != 0 && mHeight != 0) + { + int levelToFetch = 0; + GLsizei requestWidth = mWidth; + GLsizei requestHeight = mHeight; + if (IsCompressed(mFormat) && (mWidth % 4 != 0 || mHeight % 4 != 0)) + { + bool isMult4 = false; + int upsampleCount = 0; + while (!isMult4) + { + requestWidth <<= 1; + requestHeight <<= 1; + upsampleCount++; + if (requestWidth % 4 == 0 && requestHeight % 4 == 0) + { + isMult4 = true; + } + } + levelToFetch = upsampleCount; + } + + HRESULT result = getDevice()->CreateTexture(requestWidth, requestHeight, levelToFetch + 1, NULL, getD3DFormat(), + D3DPOOL_SYSTEMMEM, &newTexture, NULL); + + if (FAILED(result)) + { + ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); + ERR("Creating image surface failed."); + return error(GL_OUT_OF_MEMORY); + } + + newTexture->GetSurfaceLevel(levelToFetch, &newSurface); + newTexture->Release(); + } + + mSurface = newSurface; + mDirty = false; +} + +HRESULT Image::lock(D3DLOCKED_RECT *lockedRect, const RECT *rect) +{ + createSurface(); + + HRESULT result = D3DERR_INVALIDCALL; + + if (mSurface) + { + result = mSurface->LockRect(lockedRect, rect, 0); + ASSERT(SUCCEEDED(result)); + + mDirty = true; + } + + return result; +} + +void Image::unlock() +{ + if (mSurface) + { + HRESULT result = mSurface->UnlockRect(); + ASSERT(SUCCEEDED(result)); + } +} + +bool Image::isRenderable() const { switch(getD3DFormat()) { @@ -70,40 +179,40 @@ bool Texture::Image::isRenderable() const return false; } -D3DFORMAT Texture::Image::getD3DFormat() const +D3DFORMAT Image::getD3DFormat() const { - if (format == GL_COMPRESSED_RGB_S3TC_DXT1_EXT || - format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT) + if (mFormat == GL_COMPRESSED_RGB_S3TC_DXT1_EXT || + mFormat == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT) { return D3DFMT_DXT1; } - else if (format == GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE) + else if (mFormat == GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE) { return D3DFMT_DXT3; } - else if (format == GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE) + else if (mFormat == GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE) { return D3DFMT_DXT5; } - else if (type == GL_FLOAT) + else if (mType == GL_FLOAT) { return D3DFMT_A32B32G32R32F; } - else if (type == GL_HALF_FLOAT_OES) + else if (mType == GL_HALF_FLOAT_OES) { return D3DFMT_A16B16G16R16F; } - else if (type == GL_UNSIGNED_BYTE) + else if (mType == GL_UNSIGNED_BYTE) { - if (format == GL_LUMINANCE && getContext()->supportsLuminanceTextures()) + if (mFormat == GL_LUMINANCE && getContext()->supportsLuminanceTextures()) { return D3DFMT_L8; } - else if (format == GL_LUMINANCE_ALPHA && getContext()->supportsLuminanceAlphaTextures()) + else if (mFormat == GL_LUMINANCE_ALPHA && getContext()->supportsLuminanceAlphaTextures()) { return D3DFMT_A8L8; } - else if (format == GL_RGB) + else if (mFormat == GL_RGB) { return D3DFMT_X8R8G8B8; } @@ -114,243 +223,155 @@ D3DFORMAT Texture::Image::getD3DFormat() const return D3DFMT_A8R8G8B8; } -Texture::Texture(GLuint id) : RefCountObject(id), mSerial(issueSerial()) +IDirect3DSurface9 *Image::getSurface() { - mMinFilter = GL_NEAREST_MIPMAP_LINEAR; - mMagFilter = GL_LINEAR; - mWrapS = GL_REPEAT; - mWrapT = GL_REPEAT; - mDirtyParameter = true; - - mDirtyImage = true; - - mIsRenderable = false; + createSurface(); + + return mSurface; } -Texture::~Texture() +void Image::setManagedSurface(IDirect3DSurface9 *surface) { -} - -Blit *Texture::getBlitter() -{ - Context *context = getContext(); - return context->getBlitter(); -} - -// Returns true on successful filter state update (valid enum parameter) -bool Texture::setMinFilter(GLenum filter) -{ - switch (filter) + if (mSurface) { - case GL_NEAREST: - case GL_LINEAR: - case GL_NEAREST_MIPMAP_NEAREST: - case GL_LINEAR_MIPMAP_NEAREST: - case GL_NEAREST_MIPMAP_LINEAR: - case GL_LINEAR_MIPMAP_LINEAR: - { - if (mMinFilter != filter) - { - mMinFilter = filter; - mDirtyParameter = true; - } - return true; - } - default: - return false; + D3DXLoadSurfaceFromSurface(surface, NULL, NULL, mSurface, NULL, NULL, D3DX_FILTER_BOX, 0); + mSurface->Release(); } + + mSurface = surface; + mManaged = true; } -// Returns true on successful filter state update (valid enum parameter) -bool Texture::setMagFilter(GLenum filter) +void Image::updateSurface(IDirect3DSurface9 *destSurface, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height) { - switch (filter) + IDirect3DSurface9 *sourceSurface = getSurface(); + + if (sourceSurface != destSurface) { - case GL_NEAREST: - case GL_LINEAR: + RECT rect = transformPixelRect(xoffset, yoffset, width, height, mHeight); + + if (mManaged) { - if (mMagFilter != filter) - { - mMagFilter = filter; - mDirtyParameter = true; - } - return true; + HRESULT result = D3DXLoadSurfaceFromSurface(destSurface, NULL, &rect, sourceSurface, NULL, &rect, D3DX_FILTER_BOX, 0); + ASSERT(SUCCEEDED(result)); } - default: - return false; - } -} - -// Returns true on successful wrap state update (valid enum parameter) -bool Texture::setWrapS(GLenum wrap) -{ - switch (wrap) - { - case GL_REPEAT: - case GL_CLAMP_TO_EDGE: - case GL_MIRRORED_REPEAT: + else { - if (mWrapS != wrap) - { - mWrapS = wrap; - mDirtyParameter = true; - } - return true; + POINT point = {rect.left, rect.top}; + HRESULT result = getDevice()->UpdateSurface(sourceSurface, &rect, destSurface, &point); + ASSERT(SUCCEEDED(result)); } - default: - return false; } } -// Returns true on successful wrap state update (valid enum parameter) -bool Texture::setWrapT(GLenum wrap) -{ - switch (wrap) - { - case GL_REPEAT: - case GL_CLAMP_TO_EDGE: - case GL_MIRRORED_REPEAT: - { - if (mWrapT != wrap) - { - mWrapT = wrap; - mDirtyParameter = true; - } - return true; - } - default: - return false; - } -} - -GLenum Texture::getMinFilter() const -{ - return mMinFilter; -} - -GLenum Texture::getMagFilter() const -{ - return mMagFilter; -} - -GLenum Texture::getWrapS() const -{ - return mWrapS; -} - -GLenum Texture::getWrapT() const -{ - return mWrapT; -} - // Store the pixel rectangle designated by xoffset,yoffset,width,height with pixels stored as format/type at input // into the target pixel rectangle at output with outputPitch bytes in between each line. -void Texture::loadImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, - GLint unpackAlignment, const void *input, size_t outputPitch, void *output, D3DSURFACE_DESC *description) const +void Image::loadData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum type, + GLint unpackAlignment, const void *input, size_t outputPitch, void *output) const { - GLsizei inputPitch = -ComputePitch(width, format, type, unpackAlignment); + GLsizei inputPitch = -ComputePitch(width, mFormat, type, unpackAlignment); input = ((char*)input) - inputPitch * (height - 1); switch (type) { case GL_UNSIGNED_BYTE: - switch (format) + switch (mFormat) { case GL_ALPHA: - loadAlphaImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); + loadAlphaData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); break; case GL_LUMINANCE: - loadLuminanceImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output, description->Format == D3DFMT_L8); + loadLuminanceData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output, getD3DFormat() == D3DFMT_L8); break; case GL_LUMINANCE_ALPHA: - loadLuminanceAlphaImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output, description->Format == D3DFMT_A8L8); + loadLuminanceAlphaData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output, getD3DFormat() == D3DFMT_A8L8); break; case GL_RGB: - loadRGBUByteImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); + loadRGBUByteData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); break; case GL_RGBA: if (supportsSSE2()) { - loadRGBAUByteImageDataSSE2(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); + loadRGBAUByteDataSSE2(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); } else { - loadRGBAUByteImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); + loadRGBAUByteData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); } break; case GL_BGRA_EXT: - loadBGRAImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); + loadBGRAData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); break; default: UNREACHABLE(); } break; case GL_UNSIGNED_SHORT_5_6_5: - switch (format) + switch (mFormat) { case GL_RGB: - loadRGB565ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); + loadRGB565Data(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); break; default: UNREACHABLE(); } break; case GL_UNSIGNED_SHORT_4_4_4_4: - switch (format) + switch (mFormat) { case GL_RGBA: - loadRGBA4444ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); + loadRGBA4444Data(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); break; default: UNREACHABLE(); } break; case GL_UNSIGNED_SHORT_5_5_5_1: - switch (format) + switch (mFormat) { case GL_RGBA: - loadRGBA5551ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); + loadRGBA5551Data(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); break; default: UNREACHABLE(); } break; case GL_FLOAT: - switch (format) + switch (mFormat) { // float textures are converted to RGBA, not BGRA, as they're stored that way in D3D case GL_ALPHA: - loadAlphaFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); + loadAlphaFloatData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); break; case GL_LUMINANCE: - loadLuminanceFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); + loadLuminanceFloatData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); break; case GL_LUMINANCE_ALPHA: - loadLuminanceAlphaFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); + loadLuminanceAlphaFloatData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); break; case GL_RGB: - loadRGBFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); + loadRGBFloatData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); break; case GL_RGBA: - loadRGBAFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); + loadRGBAFloatData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); break; default: UNREACHABLE(); } break; case GL_HALF_FLOAT_OES: - switch (format) + switch (mFormat) { // float textures are converted to RGBA, not BGRA, as they're stored that way in D3D case GL_ALPHA: - loadAlphaHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); + loadAlphaHalfFloatData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); break; case GL_LUMINANCE: - loadLuminanceHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); + loadLuminanceHalfFloatData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); break; case GL_LUMINANCE_ALPHA: - loadLuminanceAlphaHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); + loadLuminanceAlphaHalfFloatData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); break; case GL_RGB: - loadRGBHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); + loadRGBHalfFloatData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); break; case GL_RGBA: - loadRGBAHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); + loadRGBAHalfFloatData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); break; default: UNREACHABLE(); } @@ -359,8 +380,8 @@ void Texture::loadImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei } } -void Texture::loadAlphaImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) const +void Image::loadAlphaData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const { const unsigned char *source = NULL; unsigned char *dest = NULL; @@ -379,8 +400,8 @@ void Texture::loadAlphaImageData(GLint xoffset, GLint yoffset, GLsizei width, GL } } -void Texture::loadAlphaFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) const +void Image::loadAlphaFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const { const float *source = NULL; float *dest = NULL; @@ -399,8 +420,8 @@ void Texture::loadAlphaFloatImageData(GLint xoffset, GLint yoffset, GLsizei widt } } -void Texture::loadAlphaHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) const +void Image::loadAlphaHalfFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const { const unsigned short *source = NULL; unsigned short *dest = NULL; @@ -419,8 +440,8 @@ void Texture::loadAlphaHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei } } -void Texture::loadLuminanceImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output, bool native) const +void Image::loadLuminanceData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output, bool native) const { const int destBytesPerPixel = native? 1: 4; const unsigned char *source = NULL; @@ -448,8 +469,8 @@ void Texture::loadLuminanceImageData(GLint xoffset, GLint yoffset, GLsizei width } } -void Texture::loadLuminanceFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) const +void Image::loadLuminanceFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const { const float *source = NULL; float *dest = NULL; @@ -468,8 +489,8 @@ void Texture::loadLuminanceFloatImageData(GLint xoffset, GLint yoffset, GLsizei } } -void Texture::loadLuminanceHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) const +void Image::loadLuminanceHalfFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const { const unsigned short *source = NULL; unsigned short *dest = NULL; @@ -488,8 +509,8 @@ void Texture::loadLuminanceHalfFloatImageData(GLint xoffset, GLint yoffset, GLsi } } -void Texture::loadLuminanceAlphaImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output, bool native) const +void Image::loadLuminanceAlphaData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output, bool native) const { const int destBytesPerPixel = native? 2: 4; const unsigned char *source = NULL; @@ -517,8 +538,8 @@ void Texture::loadLuminanceAlphaImageData(GLint xoffset, GLint yoffset, GLsizei } } -void Texture::loadLuminanceAlphaFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) const +void Image::loadLuminanceAlphaFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const { const float *source = NULL; float *dest = NULL; @@ -537,8 +558,8 @@ void Texture::loadLuminanceAlphaFloatImageData(GLint xoffset, GLint yoffset, GLs } } -void Texture::loadLuminanceAlphaHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) const +void Image::loadLuminanceAlphaHalfFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const { const unsigned short *source = NULL; unsigned short *dest = NULL; @@ -557,8 +578,8 @@ void Texture::loadLuminanceAlphaHalfFloatImageData(GLint xoffset, GLint yoffset, } } -void Texture::loadRGBUByteImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) const +void Image::loadRGBUByteData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const { const unsigned char *source = NULL; unsigned char *dest = NULL; @@ -577,8 +598,8 @@ void Texture::loadRGBUByteImageData(GLint xoffset, GLint yoffset, GLsizei width, } } -void Texture::loadRGB565ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) const +void Image::loadRGB565Data(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const { const unsigned short *source = NULL; unsigned char *dest = NULL; @@ -598,8 +619,8 @@ void Texture::loadRGB565ImageData(GLint xoffset, GLint yoffset, GLsizei width, G } } -void Texture::loadRGBFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) const +void Image::loadRGBFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const { const float *source = NULL; float *dest = NULL; @@ -618,8 +639,8 @@ void Texture::loadRGBFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, } } -void Texture::loadRGBHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) const +void Image::loadRGBHalfFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const { const unsigned short *source = NULL; unsigned short *dest = NULL; @@ -638,8 +659,8 @@ void Texture::loadRGBHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei wi } } -void Texture::loadRGBAUByteImageDataSSE2(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) const +void Image::loadRGBAUByteDataSSE2(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const { const unsigned int *source = NULL; unsigned int *dest = NULL; @@ -680,8 +701,8 @@ void Texture::loadRGBAUByteImageDataSSE2(GLint xoffset, GLint yoffset, GLsizei w } } -void Texture::loadRGBAUByteImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) const +void Image::loadRGBAUByteData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const { const unsigned int *source = NULL; unsigned int *dest = NULL; @@ -698,8 +719,8 @@ void Texture::loadRGBAUByteImageData(GLint xoffset, GLint yoffset, GLsizei width } } -void Texture::loadRGBA4444ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) const +void Image::loadRGBA4444Data(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const { const unsigned short *source = NULL; unsigned char *dest = NULL; @@ -719,8 +740,8 @@ void Texture::loadRGBA4444ImageData(GLint xoffset, GLint yoffset, GLsizei width, } } -void Texture::loadRGBA5551ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) const +void Image::loadRGBA5551Data(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const { const unsigned short *source = NULL; unsigned char *dest = NULL; @@ -740,8 +761,8 @@ void Texture::loadRGBA5551ImageData(GLint xoffset, GLint yoffset, GLsizei width, } } -void Texture::loadRGBAFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) const +void Image::loadRGBAFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const { const float *source = NULL; float *dest = NULL; @@ -754,8 +775,8 @@ void Texture::loadRGBAFloatImageData(GLint xoffset, GLint yoffset, GLsizei width } } -void Texture::loadRGBAHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) const +void Image::loadRGBAHalfFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const { const unsigned char *source = NULL; unsigned char *dest = NULL; @@ -768,8 +789,8 @@ void Texture::loadRGBAHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei w } } -void Texture::loadBGRAImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) const +void Image::loadBGRAData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const { const unsigned char *source = NULL; unsigned char *dest = NULL; @@ -782,18 +803,18 @@ void Texture::loadBGRAImageData(GLint xoffset, GLint yoffset, GLsizei width, GLs } } -void Texture::loadCompressedImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) const { +void Image::loadCompressedData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const { switch (getD3DFormat()) { case D3DFMT_DXT1: - loadDXT1ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); + loadDXT1Data(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); break; case D3DFMT_DXT3: - loadDXT3ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); + loadDXT3Data(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); break; case D3DFMT_DXT5: - loadDXT5ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); + loadDXT5Data(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output); break; } } @@ -908,8 +929,8 @@ static void FlipCopyDXT5BlockHalf(const unsigned int* source, unsigned int* dest FlipCopyDXT1BlockHalf(source + 2, dest + 2); } -void Texture::loadDXT1ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) const +void Image::loadDXT1Data(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const { ASSERT(xoffset % 4 == 0); ASSERT(yoffset % 4 == 0); @@ -956,8 +977,8 @@ void Texture::loadDXT1ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLs } } -void Texture::loadDXT3ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) const +void Image::loadDXT3Data(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const { ASSERT(xoffset % 4 == 0); ASSERT(yoffset % 4 == 0); @@ -1006,8 +1027,8 @@ void Texture::loadDXT3ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLs } } -void Texture::loadDXT5ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) const +void Image::loadDXT5Data(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const { ASSERT(xoffset % 4 == 0); ASSERT(yoffset % 4 == 0); @@ -1056,212 +1077,9 @@ void Texture::loadDXT5ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLs } } -void Texture::createSurface(Image *image) -{ - IDirect3DTexture9 *newTexture = NULL; - IDirect3DSurface9 *newSurface = NULL; - - if (image->width != 0 && image->height != 0) - { - int levelToFetch = 0; - GLsizei requestWidth = image->width; - GLsizei requestHeight = image->height; - if (IsCompressed(image->format) && (image->width % 4 != 0 || image->height % 4 != 0)) - { - bool isMult4 = false; - int upsampleCount = 0; - while (!isMult4) - { - requestWidth <<= 1; - requestHeight <<= 1; - upsampleCount++; - if (requestWidth % 4 == 0 && requestHeight % 4 == 0) - { - isMult4 = true; - } - } - levelToFetch = upsampleCount; - } - - HRESULT result = getDevice()->CreateTexture(requestWidth, requestHeight, levelToFetch + 1, NULL, image->getD3DFormat(), - D3DPOOL_SYSTEMMEM, &newTexture, NULL); - - if (FAILED(result)) - { - ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); - return error(GL_OUT_OF_MEMORY); - } - - newTexture->GetSurfaceLevel(levelToFetch, &newSurface); - newTexture->Release(); - } - - if (image->surface) - { - image->surface->Release(); - } - - image->surface = newSurface; -} - -void Texture::setImage(GLint unpackAlignment, const void *pixels, Image *image) -{ - createSurface(image); - - if (pixels != NULL && image->surface != NULL) - { - D3DSURFACE_DESC description; - image->surface->GetDesc(&description); - - D3DLOCKED_RECT locked; - HRESULT result = image->surface->LockRect(&locked, NULL, 0); - - ASSERT(SUCCEEDED(result)); - - if (SUCCEEDED(result)) - { - loadImageData(0, 0, image->width, image->height, image->format, image->type, unpackAlignment, pixels, locked.Pitch, locked.pBits, &description); - image->surface->UnlockRect(); - } - - image->dirty = true; - mDirtyImage = true; - } -} - -void Texture::setCompressedImage(GLsizei imageSize, const void *pixels, Image *image) -{ - createSurface(image); - - if (pixels != NULL && image->surface != NULL) - { - D3DLOCKED_RECT locked; - HRESULT result = image->surface->LockRect(&locked, NULL, 0); - - ASSERT(SUCCEEDED(result)); - - if (SUCCEEDED(result)) - { - int inputPitch = ComputeCompressedPitch(image->width, image->format); - int inputSize = ComputeCompressedSize(image->width, image->height, image->format); - loadCompressedImageData(0, 0, image->width, image->height, -inputPitch, static_cast(pixels) + inputSize - inputPitch, locked.Pitch, locked.pBits); - image->surface->UnlockRect(); - } - - image->dirty = true; - mDirtyImage = true; - } -} - -bool Texture::subImage(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, Image *image) -{ - if (width + xoffset > image->width || height + yoffset > image->height) - { - error(GL_INVALID_VALUE); - return false; - } - - if (IsCompressed(image->format)) - { - error(GL_INVALID_OPERATION); - return false; - } - - if (format != image->format) - { - error(GL_INVALID_OPERATION); - return false; - } - - if (!image->surface) - { - createSurface(image); - } - - if (pixels != NULL && image->surface != NULL) - { - D3DSURFACE_DESC description; - image->surface->GetDesc(&description); - - D3DLOCKED_RECT locked; - HRESULT result = image->surface->LockRect(&locked, NULL, 0); - - ASSERT(SUCCEEDED(result)); - - if (SUCCEEDED(result)) - { - loadImageData(xoffset, transformPixelYOffset(yoffset, height, image->height), width, height, format, type, unpackAlignment, pixels, locked.Pitch, locked.pBits, &description); - image->surface->UnlockRect(); - } - - image->dirty = true; - mDirtyImage = true; - } - - return true; -} - -bool Texture::subImageCompressed(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels, Image *image) -{ - if (width + xoffset > image->width || height + yoffset > image->height) - { - error(GL_INVALID_VALUE); - return false; - } - - if (format != getInternalFormat()) - { - error(GL_INVALID_OPERATION); - return false; - } - - if (!image->surface) - { - createSurface(image); - } - - if (pixels != NULL && image->surface != NULL) - { - RECT updateRegion; - updateRegion.left = xoffset; - updateRegion.right = xoffset + width; - updateRegion.bottom = yoffset + height; - updateRegion.top = yoffset; - - D3DLOCKED_RECT locked; - HRESULT result = image->surface->LockRect(&locked, &updateRegion, 0); - - ASSERT(SUCCEEDED(result)); - - if (SUCCEEDED(result)) - { - int inputPitch = ComputeCompressedPitch(width, format); - int inputSize = ComputeCompressedSize(width, height, format); - loadCompressedImageData(xoffset, transformPixelYOffset(yoffset, height, image->height), width, height, -inputPitch, static_cast(pixels) + inputSize - inputPitch, locked.Pitch, locked.pBits); - image->surface->UnlockRect(); - } - - image->dirty = true; - mDirtyImage = true; - } - - return true; -} - // This implements glCopyTex[Sub]Image2D for non-renderable internal texture formats and incomplete textures -void Texture::copyToImage(Image *image, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, IDirect3DSurface9 *renderTarget) +void Image::copy(GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, IDirect3DSurface9 *renderTarget) { - if (!image->surface) - { - createSurface(image); - - if (!image->surface) - { - ERR("Failed to create an image surface."); - return error(GL_OUT_OF_MEMORY); - } - } - IDirect3DDevice9 *device = getDevice(); IDirect3DSurface9 *renderTargetData = NULL; D3DSURFACE_DESC description; @@ -1285,12 +1103,12 @@ void Texture::copyToImage(Image *image, GLint xoffset, GLint yoffset, GLint x, G } RECT sourceRect = transformPixelRect(x, y, width, height, description.Height); - int destYOffset = transformPixelYOffset(yoffset, height, image->height); + int destYOffset = transformPixelYOffset(yoffset, height, mHeight); RECT destRect = {xoffset, destYOffset, xoffset + width, destYOffset + height}; - if (image->isRenderable()) + if (isRenderable()) { - result = D3DXLoadSurfaceFromSurface(image->surface, NULL, &destRect, renderTargetData, NULL, &sourceRect, D3DX_FILTER_BOX, 0); + result = D3DXLoadSurfaceFromSurface(getSurface(), NULL, &destRect, renderTargetData, NULL, &sourceRect, D3DX_FILTER_BOX, 0); if (FAILED(result)) { @@ -1312,7 +1130,7 @@ void Texture::copyToImage(Image *image, GLint xoffset, GLint yoffset, GLint x, G } D3DLOCKED_RECT destLock = {0}; - result = image->surface->LockRect(&destLock, &destRect, 0); + result = lock(&destLock, &destRect); if (FAILED(result)) { @@ -1331,7 +1149,7 @@ void Texture::copyToImage(Image *image, GLint xoffset, GLint yoffset, GLint x, G { case D3DFMT_X8R8G8B8: case D3DFMT_A8R8G8B8: - switch(image->getD3DFormat()) + switch(getD3DFormat()) { case D3DFMT_L8: for(int y = 0; y < height; y++) @@ -1363,7 +1181,7 @@ void Texture::copyToImage(Image *image, GLint xoffset, GLint yoffset, GLint x, G } break; case D3DFMT_R5G6B5: - switch(image->getD3DFormat()) + switch(getD3DFormat()) { case D3DFMT_L8: for(int y = 0; y < height; y++) @@ -1383,7 +1201,7 @@ void Texture::copyToImage(Image *image, GLint xoffset, GLint yoffset, GLint x, G } break; case D3DFMT_A1R5G5B5: - switch(image->getD3DFormat()) + switch(getD3DFormat()) { case D3DFMT_L8: for(int y = 0; y < height; y++) @@ -1421,19 +1239,302 @@ void Texture::copyToImage(Image *image, GLint xoffset, GLint yoffset, GLint x, G } } - image->surface->UnlockRect(); + unlock(); renderTargetData->UnlockRect(); } renderTargetData->Release(); - image->dirty = true; - mDirtyImage = true; + mDirty = true; +} + +TextureStorage::TextureStorage(bool renderable) + : mRenderable(renderable), mManaged(getDisplay()->getBufferPool(renderable) == D3DPOOL_MANAGED), mTextureSerial(issueTextureSerial()) +{ +} + +TextureStorage::~TextureStorage() +{ +} + +bool TextureStorage::isRenderable() const +{ + return mRenderable; +} + +bool TextureStorage::isManaged() const +{ + return mManaged; +} + +unsigned int TextureStorage::getTextureSerial() const +{ + return mTextureSerial; +} + +unsigned int TextureStorage::issueTextureSerial() +{ + return mCurrentTextureSerial++; +} + +Texture::Texture(GLuint id) : RefCountObject(id) +{ + mMinFilter = GL_NEAREST_MIPMAP_LINEAR; + mMagFilter = GL_LINEAR; + mWrapS = GL_REPEAT; + mWrapT = GL_REPEAT; + mDirtyParameters = true; + mUsage = GL_NONE; + + mDirtyImages = true; + + mImmutable = false; +} + +Texture::~Texture() +{ +} + +// Returns true on successful filter state update (valid enum parameter) +bool Texture::setMinFilter(GLenum filter) +{ + switch (filter) + { + case GL_NEAREST: + case GL_LINEAR: + case GL_NEAREST_MIPMAP_NEAREST: + case GL_LINEAR_MIPMAP_NEAREST: + case GL_NEAREST_MIPMAP_LINEAR: + case GL_LINEAR_MIPMAP_LINEAR: + { + if (mMinFilter != filter) + { + mMinFilter = filter; + mDirtyParameters = true; + } + return true; + } + default: + return false; + } +} + +// Returns true on successful filter state update (valid enum parameter) +bool Texture::setMagFilter(GLenum filter) +{ + switch (filter) + { + case GL_NEAREST: + case GL_LINEAR: + { + if (mMagFilter != filter) + { + mMagFilter = filter; + mDirtyParameters = true; + } + return true; + } + default: + return false; + } +} + +// Returns true on successful wrap state update (valid enum parameter) +bool Texture::setWrapS(GLenum wrap) +{ + switch (wrap) + { + case GL_REPEAT: + case GL_CLAMP_TO_EDGE: + case GL_MIRRORED_REPEAT: + { + if (mWrapS != wrap) + { + mWrapS = wrap; + mDirtyParameters = true; + } + return true; + } + default: + return false; + } +} + +// Returns true on successful wrap state update (valid enum parameter) +bool Texture::setWrapT(GLenum wrap) +{ + switch (wrap) + { + case GL_REPEAT: + case GL_CLAMP_TO_EDGE: + case GL_MIRRORED_REPEAT: + { + if (mWrapT != wrap) + { + mWrapT = wrap; + mDirtyParameters = true; + } + return true; + } + default: + return false; + } +} + +// Returns true on successful usage state update (valid enum parameter) +bool Texture::setUsage(GLenum usage) +{ + switch (usage) + { + case GL_NONE: + case GL_FRAMEBUFFER_ATTACHMENT_ANGLE: + mUsage = usage; + return true; + default: + return false; + } +} + +GLenum Texture::getMinFilter() const +{ + return mMinFilter; +} + +GLenum Texture::getMagFilter() const +{ + return mMagFilter; +} + +GLenum Texture::getWrapS() const +{ + return mWrapS; +} + +GLenum Texture::getWrapT() const +{ + return mWrapT; +} + +GLenum Texture::getUsage() const +{ + return mUsage; +} + +void Texture::setImage(GLint unpackAlignment, const void *pixels, Image *image) +{ + if (pixels != NULL) + { + D3DLOCKED_RECT locked; + HRESULT result = image->lock(&locked, NULL); + + if (SUCCEEDED(result)) + { + image->loadData(0, 0, image->getWidth(), image->getHeight(), image->getType(), unpackAlignment, pixels, locked.Pitch, locked.pBits); + image->unlock(); + } + + mDirtyImages = true; + } +} + +void Texture::setCompressedImage(GLsizei imageSize, const void *pixels, Image *image) +{ + if (pixels != NULL) + { + D3DLOCKED_RECT locked; + HRESULT result = image->lock(&locked, NULL); + + if (SUCCEEDED(result)) + { + int inputPitch = ComputeCompressedPitch(image->getWidth(), image->getFormat()); + int inputSize = ComputeCompressedSize(image->getWidth(), image->getHeight(), image->getFormat()); + image->loadCompressedData(0, 0, image->getWidth(), image->getHeight(), -inputPitch, static_cast(pixels) + inputSize - inputPitch, locked.Pitch, locked.pBits); + image->unlock(); + } + + mDirtyImages = true; + } +} + +bool Texture::subImage(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, Image *image) +{ + if (width + xoffset > image->getWidth() || height + yoffset > image->getHeight()) + { + error(GL_INVALID_VALUE); + return false; + } + + if (IsCompressed(image->getFormat())) + { + error(GL_INVALID_OPERATION); + return false; + } + + if (format != image->getFormat()) + { + error(GL_INVALID_OPERATION); + return false; + } + + if (pixels != NULL) + { + D3DLOCKED_RECT locked; + HRESULT result = image->lock(&locked, NULL); + + if (SUCCEEDED(result)) + { + image->loadData(xoffset, transformPixelYOffset(yoffset, height, image->getHeight()), width, height, type, unpackAlignment, pixels, locked.Pitch, locked.pBits); + image->unlock(); + } + + mDirtyImages = true; + } + + return true; +} + +bool Texture::subImageCompressed(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels, Image *image) +{ + if (width + xoffset > image->getWidth() || height + yoffset > image->getHeight()) + { + error(GL_INVALID_VALUE); + return false; + } + + if (format != getInternalFormat()) + { + error(GL_INVALID_OPERATION); + return false; + } + + if (pixels != NULL) + { + RECT updateRegion; + updateRegion.left = xoffset; + updateRegion.right = xoffset + width; + updateRegion.bottom = yoffset + height; + updateRegion.top = yoffset; + + D3DLOCKED_RECT locked; + HRESULT result = image->lock(&locked, &updateRegion); + + if (SUCCEEDED(result)) + { + int inputPitch = ComputeCompressedPitch(width, format); + int inputSize = ComputeCompressedSize(width, height, format); + image->loadCompressedData(xoffset, transformPixelYOffset(yoffset, height, image->getHeight()), width, height, -inputPitch, static_cast(pixels) + inputSize - inputPitch, locked.Pitch, locked.pBits); + image->unlock(); + } + + mDirtyImages = true; + } + + return true; } IDirect3DBaseTexture9 *Texture::getTexture() { - if (!isComplete()) + if (!isSamplerComplete()) { return NULL; } @@ -1448,32 +1549,44 @@ IDirect3DBaseTexture9 *Texture::getTexture() return getBaseTexture(); } -bool Texture::isDirtyParameter() const +bool Texture::hasDirtyParameters() const { - return mDirtyParameter; + return mDirtyParameters; } -bool Texture::isDirtyImage() const +bool Texture::hasDirtyImages() const { - return mDirtyImage; + return mDirtyImages; } void Texture::resetDirty() { - mDirtyParameter = false; - mDirtyImage = false; + mDirtyParameters = false; + mDirtyImages = false; } -unsigned int Texture::getSerial() const +unsigned int Texture::getTextureSerial() const { - return mSerial; + TextureStorage *texture = getStorage(); + return texture ? texture->getTextureSerial() : 0; } -GLint Texture::creationLevels(GLsizei width, GLsizei height, GLint maxlevel) const +unsigned int Texture::getRenderTargetSerial(GLenum target) const +{ + TextureStorage *texture = getStorage(); + return texture ? texture->getRenderTargetSerial(target) : 0; +} + +bool Texture::isImmutable() const +{ + return mImmutable; +} + +GLint Texture::creationLevels(GLsizei width, GLsizei height) const { if ((isPow2(width) && isPow2(height)) || getContext()->supportsNonPower2Texture()) { - return maxlevel; + return 0; // Maximum number of levels } else { @@ -1482,9 +1595,9 @@ GLint Texture::creationLevels(GLsizei width, GLsizei height, GLint maxlevel) con } } -GLint Texture::creationLevels(GLsizei size, GLint maxlevel) const +GLint Texture::creationLevels(GLsizei size) const { - return creationLevels(size, size, maxlevel); + return creationLevels(size, size); } int Texture::levelCount() const @@ -1492,9 +1605,87 @@ int Texture::levelCount() const return getBaseTexture() ? getBaseTexture()->GetLevelCount() : 0; } -unsigned int Texture::issueSerial() +Blit *Texture::getBlitter() { - return mCurrentSerial++; + Context *context = getContext(); + return context->getBlitter(); +} + +bool Texture::copyToRenderTarget(IDirect3DSurface9 *dest, IDirect3DSurface9 *source, bool fromManaged) +{ + if (source && dest) + { + HRESULT result; + + if (fromManaged) + { + result = D3DXLoadSurfaceFromSurface(dest, NULL, NULL, source, NULL, NULL, D3DX_FILTER_BOX, 0); + } + else + { + egl::Display *display = getDisplay(); + IDirect3DDevice9 *device = display->getDevice(); + + display->endScene(); + result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE); + } + + if (FAILED(result)) + { + ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); + return false; + } + } + + return true; +} + +TextureStorage2D::TextureStorage2D(IDirect3DTexture9 *surfaceTexture) : TextureStorage(true), mRenderTargetSerial(RenderbufferStorage::issueSerial()) +{ + mTexture = surfaceTexture; +} + +TextureStorage2D::TextureStorage2D(int levels, D3DFORMAT format, int width, int height, bool renderable) : TextureStorage(renderable), mRenderTargetSerial(RenderbufferStorage::issueSerial()) +{ + egl::Display *display = getDisplay(); + IDirect3DDevice9 *device = display->getDevice(); + + mTexture = NULL; + HRESULT result = device->CreateTexture(width, height, levels, renderable ? D3DUSAGE_RENDERTARGET : 0, format, display->getTexturePool(renderable), &mTexture, NULL); + + if (FAILED(result)) + { + ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); + error(GL_OUT_OF_MEMORY); + } +} + +TextureStorage2D::~TextureStorage2D() +{ + mTexture->Release(); +} + +IDirect3DSurface9 *TextureStorage2D::getSurfaceLevel(int level) +{ + IDirect3DSurface9 *surface = NULL; + + if (mTexture) + { + HRESULT result = mTexture->GetSurfaceLevel(level, &surface); + ASSERT(SUCCEEDED(result)); + } + + return surface; +} + +IDirect3DBaseTexture9 *TextureStorage2D::getBaseTexture() const +{ + return mTexture; +} + +unsigned int TextureStorage2D::getRenderTargetSerial(GLenum target) const +{ + return mRenderTargetSerial; } Texture2D::Texture2D(GLuint id) : Texture(id) @@ -1507,12 +1698,9 @@ Texture2D::~Texture2D() { mColorbufferProxy.set(NULL); - if (mTexture) - { - mTexture->Release(); - mTexture = NULL; - } - + delete mTexture; + mTexture = NULL; + if (mSurface) { mSurface->setBoundTexture(NULL); @@ -1527,22 +1715,22 @@ GLenum Texture2D::getTarget() const GLsizei Texture2D::getWidth() const { - return mImageArray[0].width; + return mImageArray[0].getWidth(); } GLsizei Texture2D::getHeight() const { - return mImageArray[0].height; + return mImageArray[0].getHeight(); } GLenum Texture2D::getInternalFormat() const { - return mImageArray[0].format; + return mImageArray[0].getFormat(); } GLenum Texture2D::getType() const { - return mImageArray[0].type; + return mImageArray[0].getType(); } D3DFORMAT Texture2D::getD3DFormat() const @@ -1550,66 +1738,36 @@ D3DFORMAT Texture2D::getD3DFormat() const return mImageArray[0].getD3DFormat(); } -void Texture2D::redefineTexture(GLint level, GLenum format, GLsizei width, GLsizei height, GLenum type, bool forceRedefine) +void Texture2D::redefineImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLenum type) { - GLsizei textureWidth = mImageArray[0].width; - GLsizei textureHeight = mImageArray[0].height; - GLenum textureFormat = mImageArray[0].format; - GLenum textureType = mImageArray[0].type; + releaseTexImage(); - mImageArray[level].width = width; - mImageArray[level].height = height; - mImageArray[level].format = format; - mImageArray[level].type = type; + bool redefined = mImageArray[level].redefine(format, width, height, type, false); - if (!mTexture) - { - return; - } - - bool widthOkay = (textureWidth >> level == width) || (textureWidth >> level == 0 && width == 1); - bool heightOkay = (textureHeight >> level == height) || (textureHeight >> level == 0 && height == 1); - bool textureOkay = (widthOkay && heightOkay && textureFormat == format && textureType == type); - - if (!textureOkay || forceRedefine || mSurface) // Purge all the levels and the texture. + if (mTexture && redefined) { for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) { - if (mImageArray[i].surface != NULL) - { - mImageArray[i].surface->Release(); - mImageArray[i].surface = NULL; - mImageArray[i].dirty = true; - } + mImageArray[i].markDirty(); } - if (mTexture != NULL) - { - mTexture->Release(); - mTexture = NULL; - mDirtyImage = true; - mIsRenderable = false; - } - - if (mSurface) - { - mSurface->setBoundTexture(NULL); - mSurface = NULL; - } - - mColorbufferProxy.set(NULL); + delete mTexture; + mTexture = NULL; + mDirtyImages = true; } } void Texture2D::setImage(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels) { - redefineTexture(level, format, width, height, type, false); + redefineImage(level, format, width, height, type); Texture::setImage(unpackAlignment, pixels, &mImageArray[level]); } void Texture2D::bindTexImage(egl::Surface *surface) { + releaseTexImage(); + GLenum format; switch(surface->getFormat()) @@ -1625,56 +1783,58 @@ void Texture2D::bindTexImage(egl::Surface *surface) return; } - redefineTexture(0, format, surface->getWidth(), surface->getHeight(), GL_UNSIGNED_BYTE, true); + mImageArray[0].redefine(format, surface->getWidth(), surface->getHeight(), GL_UNSIGNED_BYTE, true); - IDirect3DTexture9 *texture = surface->getOffscreenTexture(); + delete mTexture; + mTexture = new TextureStorage2D(surface->getOffscreenTexture()); - mTexture = texture; - mDirtyImage = true; - mIsRenderable = true; + mDirtyImages = true; mSurface = surface; mSurface->setBoundTexture(this); } void Texture2D::releaseTexImage() { - redefineTexture(0, GL_RGB, 0, 0, GL_UNSIGNED_BYTE, true); + if (mSurface) + { + mSurface->setBoundTexture(NULL); + mSurface = NULL; + + if (mTexture) + { + delete mTexture; + mTexture = NULL; + } + + for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) + { + mImageArray[i].redefine(GL_RGBA, 0, 0, GL_UNSIGNED_BYTE, true); + } + } } void Texture2D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels) { - redefineTexture(level, format, width, height, GL_UNSIGNED_BYTE, false); + redefineImage(level, format, width, height, GL_UNSIGNED_BYTE); Texture::setCompressedImage(imageSize, pixels, &mImageArray[level]); } void Texture2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height) { - ASSERT(mImageArray[level].surface != NULL); + ASSERT(mImageArray[level].getSurface() != NULL); if (level < levelCount()) { - IDirect3DSurface9 *destLevel = NULL; - HRESULT result = mTexture->GetSurfaceLevel(level, &destLevel); + IDirect3DSurface9 *destLevel = mTexture->getSurfaceLevel(level); - ASSERT(SUCCEEDED(result)); - - if (SUCCEEDED(result)) + if (destLevel) { Image *image = &mImageArray[level]; - - RECT sourceRect = transformPixelRect(xoffset, yoffset, width, height, image->height);; - - POINT destPoint; - destPoint.x = sourceRect.left; - destPoint.y = sourceRect.top; - - result = getDevice()->UpdateSurface(image->surface, &sourceRect, destLevel, &destPoint); - ASSERT(SUCCEEDED(result)); + image->updateSurface(destLevel, xoffset, yoffset, width, height); destLevel->Release(); - - image->dirty = false; + image->markClean(); } } } @@ -1705,20 +1865,21 @@ void Texture2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei return error(GL_OUT_OF_MEMORY); } - redefineTexture(level, format, width, height, GL_UNSIGNED_BYTE, false); + redefineImage(level, format, width, height, GL_UNSIGNED_BYTE); if (!mImageArray[level].isRenderable()) { - copyToImage(&mImageArray[level], 0, 0, x, y, width, height, renderTarget); + mImageArray[level].copy(0, 0, x, y, width, height, renderTarget); + mDirtyImages = true; } else { - if (!mTexture || !mIsRenderable) + if (!mTexture || !mTexture->isRenderable()) { convertToRenderTarget(); } - updateTexture(); + mImageArray[level].markClean(); if (width != 0 && height != 0 && level < levelCount()) { @@ -1728,20 +1889,24 @@ void Texture2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth()); sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight()); - GLint destYOffset = transformPixelYOffset(0, height, mImageArray[level].height); + GLint destYOffset = transformPixelYOffset(0, height, mImageArray[level].getHeight()); - IDirect3DSurface9 *dest; - HRESULT hr = mTexture->GetSurfaceLevel(level, &dest); + IDirect3DSurface9 *dest = mTexture->getSurfaceLevel(level); - getBlitter()->copy(source->getRenderTarget(), sourceRect, format, 0, destYOffset, dest); - dest->Release(); + if (dest) + { + getBlitter()->copy(renderTarget, sourceRect, format, 0, destYOffset, dest); + dest->Release(); + } } } + + renderTarget->Release(); } void Texture2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source) { - if (xoffset + width > mImageArray[level].width || yoffset + height > mImageArray[level].height) + if (xoffset + width > mImageArray[level].getWidth() || yoffset + height > mImageArray[level].getHeight()) { return error(GL_INVALID_VALUE); } @@ -1754,15 +1919,14 @@ void Texture2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yo return error(GL_OUT_OF_MEMORY); } - redefineTexture(level, mImageArray[level].format, mImageArray[level].width, mImageArray[level].height, GL_UNSIGNED_BYTE, false); - - if (!mImageArray[level].isRenderable() || (!mTexture && !isComplete())) + if (!mImageArray[level].isRenderable() || (!mTexture && !isSamplerComplete())) { - copyToImage(&mImageArray[level], xoffset, yoffset, x, y, width, height, renderTarget); + mImageArray[level].copy(xoffset, yoffset, x, y, width, height, renderTarget); + mDirtyImages = true; } else { - if (!mTexture || !mIsRenderable) + if (!mTexture || !mTexture->isRenderable()) { convertToRenderTarget(); } @@ -1777,22 +1941,48 @@ void Texture2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yo sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth()); sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight()); - GLint destYOffset = transformPixelYOffset(yoffset, height, mImageArray[level].height); + GLint destYOffset = transformPixelYOffset(yoffset, height, mImageArray[level].getHeight()); - IDirect3DSurface9 *dest; - HRESULT hr = mTexture->GetSurfaceLevel(level, &dest); + IDirect3DSurface9 *dest = mTexture->getSurfaceLevel(level); - getBlitter()->copy(source->getRenderTarget(), sourceRect, mImageArray[0].format, xoffset, destYOffset, dest); - dest->Release(); + if (dest) + { + getBlitter()->copy(renderTarget, sourceRect, mImageArray[0].getFormat(), xoffset, destYOffset, dest); + dest->Release(); + } } } + + renderTarget->Release(); +} + +void Texture2D::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height) +{ + GLenum format = gl::ExtractFormat(internalformat); + GLenum type = gl::ExtractType(internalformat); + + delete mTexture; + mTexture = new TextureStorage2D(levels, mImageArray[0].getD3DFormat(), width, height, mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE); + mImmutable = true; + + for (int level = 0; level < levels; level++) + { + mImageArray[level].redefine(format, width, height, type, true); + width = std::max(1, width >> 1); + height = std::max(1, height >> 1); + } + + for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) + { + mImageArray[level].redefine(GL_NONE, 0, 0, GL_UNSIGNED_BYTE, true); + } } -// Tests for GL texture object completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81. -bool Texture2D::isComplete() const +// Tests for 2D texture sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 85. +bool Texture2D::isSamplerComplete() const { - GLsizei width = mImageArray[0].width; - GLsizei height = mImageArray[0].height; + GLsizei width = mImageArray[0].getWidth(); + GLsizei height = mImageArray[0].getHeight(); if (width <= 0 || height <= 0) { @@ -1813,11 +2003,11 @@ bool Texture2D::isComplete() const case GL_LINEAR_MIPMAP_LINEAR: mipmapping = true; break; - default: UNREACHABLE(); + default: UNREACHABLE(); } - if ((getInternalFormat() == GL_FLOAT && !getContext()->supportsFloatLinearFilter()) || - (getInternalFormat() == GL_HALF_FLOAT_OES && !getContext()->supportsHalfFloatLinearFilter())) + if ((getInternalFormat() == GL_FLOAT && !getContext()->supportsFloat32LinearFilter()) || + (getInternalFormat() == GL_HALF_FLOAT_OES && !getContext()->supportsFloat16LinearFilter())) { if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST)) { @@ -1825,9 +2015,9 @@ bool Texture2D::isComplete() const } } - bool npot = getContext()->supportsNonPower2Texture(); + bool npotSupport = getContext()->supportsNonPower2Texture(); - if (!npot) + if (!npotSupport) { if ((getWrapS() != GL_CLAMP_TO_EDGE && !isPow2(width)) || (getWrapT() != GL_CLAMP_TO_EDGE && !isPow2(height))) @@ -1838,7 +2028,7 @@ bool Texture2D::isComplete() const if (mipmapping) { - if (!npot) + if (!npotSupport) { if (!isPow2(width) || !isPow2(height)) { @@ -1846,29 +2036,53 @@ bool Texture2D::isComplete() const } } - int q = log2(std::max(width, height)); - - for (int level = 1; level <= q; level++) + if (!isMipmapComplete()) { - if (mImageArray[level].format != mImageArray[0].format) - { - return false; - } + return false; + } + } - if (mImageArray[level].type != mImageArray[0].type) - { - return false; - } + return true; +} - if (mImageArray[level].width != std::max(1, width >> level)) - { - return false; - } +// Tests for 2D texture (mipmap) completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81. +bool Texture2D::isMipmapComplete() const +{ + if (isImmutable()) + { + return true; + } - if (mImageArray[level].height != std::max(1, height >> level)) - { - return false; - } + GLsizei width = mImageArray[0].getWidth(); + GLsizei height = mImageArray[0].getHeight(); + + if (width <= 0 || height <= 0) + { + return false; + } + + int q = log2(std::max(width, height)); + + for (int level = 1; level <= q; level++) + { + if (mImageArray[level].getFormat() != mImageArray[0].getFormat()) + { + return false; + } + + if (mImageArray[level].getType() != mImageArray[0].getType()) + { + return false; + } + + if (mImageArray[level].getWidth() != std::max(1, width >> level)) + { + return false; + } + + if (mImageArray[level].getHeight() != std::max(1, height >> level)) + { + return false; } } @@ -1882,183 +2096,117 @@ bool Texture2D::isCompressed() const IDirect3DBaseTexture9 *Texture2D::getBaseTexture() const { - return mTexture; + return mTexture ? mTexture->getBaseTexture() : NULL; } // Constructs a Direct3D 9 texture resource from the texture images void Texture2D::createTexture() { - IDirect3DDevice9 *device = getDevice(); + GLsizei width = mImageArray[0].getWidth(); + GLsizei height = mImageArray[0].getHeight(); + GLint levels = creationLevels(width, height); D3DFORMAT format = mImageArray[0].getD3DFormat(); - GLint levels = creationLevels(mImageArray[0].width, mImageArray[0].height, 0); + bool renderable = (mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE); - IDirect3DTexture9 *texture = NULL; - HRESULT result = device->CreateTexture(mImageArray[0].width, mImageArray[0].height, levels, 0, format, D3DPOOL_DEFAULT, &texture, NULL); - - if (FAILED(result)) + delete mTexture; + mTexture = new TextureStorage2D(levels, format, width, height, renderable); + + if (mTexture->isManaged()) { - ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); - return error(GL_OUT_OF_MEMORY); + int levels = levelCount(); + + for (int level = 0; level < levels; level++) + { + IDirect3DSurface9 *surface = mTexture->getSurfaceLevel(level); + mImageArray[level].setManagedSurface(surface); + } } - if (mTexture) - { - mTexture->Release(); - } - - mTexture = texture; - mDirtyImage = true; - mIsRenderable = false; + mDirtyImages = true; } void Texture2D::updateTexture() { - IDirect3DDevice9 *device = getDevice(); - int levels = levelCount(); for (int level = 0; level < levels; level++) { - if (mImageArray[level].surface && mImageArray[level].dirty) + Image *image = &mImageArray[level]; + + if (image->isDirty()) { - IDirect3DSurface9 *levelSurface = NULL; - HRESULT result = mTexture->GetSurfaceLevel(level, &levelSurface); - - ASSERT(SUCCEEDED(result)); - - if (SUCCEEDED(result)) - { - result = device->UpdateSurface(mImageArray[level].surface, NULL, levelSurface, NULL); - ASSERT(SUCCEEDED(result)); - - levelSurface->Release(); - - mImageArray[level].dirty = false; - } + commitRect(level, 0, 0, mImageArray[level].getWidth(), mImageArray[level].getHeight()); } } } void Texture2D::convertToRenderTarget() { - IDirect3DTexture9 *texture = NULL; + TextureStorage2D *newTexture = NULL; - if (mImageArray[0].width != 0 && mImageArray[0].height != 0) + if (mImageArray[0].getWidth() != 0 && mImageArray[0].getHeight() != 0) { - egl::Display *display = getDisplay(); - IDirect3DDevice9 *device = getDevice(); + GLsizei width = mImageArray[0].getWidth(); + GLsizei height = mImageArray[0].getHeight(); + GLint levels = creationLevels(width, height); D3DFORMAT format = mImageArray[0].getD3DFormat(); - GLint levels = creationLevels(mImageArray[0].width, mImageArray[0].height, 0); - HRESULT result = device->CreateTexture(mImageArray[0].width, mImageArray[0].height, levels, D3DUSAGE_RENDERTARGET, format, D3DPOOL_DEFAULT, &texture, NULL); - - if (FAILED(result)) - { - ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); - return error(GL_OUT_OF_MEMORY); - } + newTexture = new TextureStorage2D(levels, format, width, height, true); if (mTexture != NULL) { int levels = levelCount(); for (int i = 0; i < levels; i++) { - IDirect3DSurface9 *source; - result = mTexture->GetSurfaceLevel(i, &source); + IDirect3DSurface9 *source = mTexture->getSurfaceLevel(i); + IDirect3DSurface9 *dest = newTexture->getSurfaceLevel(i); - if (FAILED(result)) - { - ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); - - texture->Release(); - - return error(GL_OUT_OF_MEMORY); + if (!copyToRenderTarget(dest, source, mTexture->isManaged())) + { + delete newTexture; + source->Release(); + dest->Release(); + return error(GL_OUT_OF_MEMORY); } - IDirect3DSurface9 *dest; - result = texture->GetSurfaceLevel(i, &dest); - - if (FAILED(result)) - { - ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); - - texture->Release(); - source->Release(); - - return error(GL_OUT_OF_MEMORY); - } - - display->endScene(); - result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE); - - if (FAILED(result)) - { - ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); - - texture->Release(); - source->Release(); - dest->Release(); - - return error(GL_OUT_OF_MEMORY); - } - - source->Release(); - dest->Release(); + if (source) source->Release(); + if (dest) dest->Release(); } } } - if (mTexture != NULL) - { - mTexture->Release(); - } + delete mTexture; + mTexture = newTexture; - mTexture = texture; - mDirtyImage = true; - mIsRenderable = true; + mDirtyImages = true; } void Texture2D::generateMipmaps() { if (!getContext()->supportsNonPower2Texture()) { - if (!isPow2(mImageArray[0].width) || !isPow2(mImageArray[0].height)) + if (!isPow2(mImageArray[0].getWidth()) || !isPow2(mImageArray[0].getHeight())) { return error(GL_INVALID_OPERATION); } } // Purge array levels 1 through q and reset them to represent the generated mipmap levels. - unsigned int q = log2(std::max(mImageArray[0].width, mImageArray[0].height)); + unsigned int q = log2(std::max(mImageArray[0].getWidth(), mImageArray[0].getHeight())); for (unsigned int i = 1; i <= q; i++) { - if (mImageArray[i].surface != NULL) - { - mImageArray[i].surface->Release(); - mImageArray[i].surface = NULL; - } - - mImageArray[i].width = std::max(mImageArray[0].width >> i, 1); - mImageArray[i].height = std::max(mImageArray[0].height >> i, 1); - mImageArray[i].format = mImageArray[0].format; - mImageArray[i].type = mImageArray[0].type; + redefineImage(i, mImageArray[0].getFormat(), + std::max(mImageArray[0].getWidth() >> i, 1), + std::max(mImageArray[0].getHeight() >> i, 1), + mImageArray[0].getType()); } - if (mIsRenderable) + if (mTexture && mTexture->isRenderable()) { - if (mTexture == NULL) - { - ERR(" failed because mTexture was null."); - return; - } - for (unsigned int i = 1; i <= q; i++) { - IDirect3DSurface9 *upper = NULL; - IDirect3DSurface9 *lower = NULL; - - mTexture->GetSurfaceLevel(i-1, &upper); - mTexture->GetSurfaceLevel(i, &lower); + IDirect3DSurface9 *upper = mTexture->getSurfaceLevel(i - 1); + IDirect3DSurface9 *lower = mTexture->getSurfaceLevel(i); if (upper != NULL && lower != NULL) { @@ -2068,26 +2216,24 @@ void Texture2D::generateMipmaps() if (upper != NULL) upper->Release(); if (lower != NULL) lower->Release(); - mImageArray[i].dirty = false; + mImageArray[i].markClean(); } } else { for (unsigned int i = 1; i <= q; i++) { - createSurface(&mImageArray[i]); - - if (mImageArray[i].surface == NULL) + if (mImageArray[i].getSurface() == NULL) { return error(GL_OUT_OF_MEMORY); } - if (FAILED(D3DXLoadSurfaceFromSurface(mImageArray[i].surface, NULL, NULL, mImageArray[i - 1].surface, NULL, NULL, D3DX_FILTER_BOX, 0))) + if (FAILED(D3DXLoadSurfaceFromSurface(mImageArray[i].getSurface(), NULL, NULL, mImageArray[i - 1].getSurface(), NULL, NULL, D3DX_FILTER_BOX, 0))) { ERR(" failed to load filter %d to %d.", i - 1, i); } - mImageArray[i].dirty = true; + mImageArray[i].markDirty(); } } } @@ -2101,7 +2247,7 @@ Renderbuffer *Texture2D::getRenderbuffer(GLenum target) if (mColorbufferProxy.get() == NULL) { - mColorbufferProxy.set(new Renderbuffer(id(), new Colorbuffer(this, target))); + mColorbufferProxy.set(new Renderbuffer(id(), new RenderbufferTexture(this, target))); } return mColorbufferProxy.get(); @@ -2111,7 +2257,7 @@ IDirect3DSurface9 *Texture2D::getRenderTarget(GLenum target) { ASSERT(target == GL_TEXTURE_2D); - if (!mIsRenderable) + if (!mTexture || !mTexture->isRenderable()) { convertToRenderTarget(); } @@ -2123,10 +2269,55 @@ IDirect3DSurface9 *Texture2D::getRenderTarget(GLenum target) updateTexture(); - IDirect3DSurface9 *renderTarget = NULL; - mTexture->GetSurfaceLevel(0, &renderTarget); + return mTexture->getSurfaceLevel(0); +} - return renderTarget; +TextureStorage *Texture2D::getStorage() const +{ + return mTexture; +} + +TextureStorageCubeMap::TextureStorageCubeMap(int levels, D3DFORMAT format, int size, bool renderable) : TextureStorage(renderable), mFirstRenderTargetSerial(RenderbufferStorage::issueCubeSerials()) +{ + egl::Display *display = getDisplay(); + IDirect3DDevice9 *device = display->getDevice(); + + mTexture = NULL; + HRESULT result = device->CreateCubeTexture(size, levels, renderable ? D3DUSAGE_RENDERTARGET : 0, format, display->getTexturePool(renderable), &mTexture, NULL); + + if (FAILED(result)) + { + ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); + error(GL_OUT_OF_MEMORY); + } +} + +TextureStorageCubeMap::~TextureStorageCubeMap() +{ + mTexture->Release(); +} + +IDirect3DSurface9 *TextureStorageCubeMap::getCubeMapSurface(GLenum faceTarget, int level) +{ + IDirect3DSurface9 *surface = NULL; + + if (mTexture) + { + HRESULT result = mTexture->GetCubeMapSurface(es2dx::ConvertCubeFace(faceTarget), level, &surface); + ASSERT(SUCCEEDED(result)); + } + + return surface; +} + +IDirect3DBaseTexture9 *TextureStorageCubeMap::getBaseTexture() const +{ + return mTexture; +} + +unsigned int TextureStorageCubeMap::getRenderTargetSerial(GLenum target) const +{ + return mFirstRenderTargetSerial + TextureCubeMap::faceIndex(target); } TextureCubeMap::TextureCubeMap(GLuint id) : Texture(id) @@ -2141,11 +2332,8 @@ TextureCubeMap::~TextureCubeMap() mFaceProxies[i].set(NULL); } - if (mTexture) - { - mTexture->Release(); - mTexture = NULL; - } + delete mTexture; + mTexture = NULL; } GLenum TextureCubeMap::getTarget() const @@ -2155,22 +2343,22 @@ GLenum TextureCubeMap::getTarget() const GLsizei TextureCubeMap::getWidth() const { - return mImageArray[0][0].width; + return mImageArray[0][0].getWidth(); } GLsizei TextureCubeMap::getHeight() const { - return mImageArray[0][0].height; + return mImageArray[0][0].getHeight(); } GLenum TextureCubeMap::getInternalFormat() const { - return mImageArray[0][0].format; + return mImageArray[0][0].getFormat(); } GLenum TextureCubeMap::getType() const { - return mImageArray[0][0].type; + return mImageArray[0][0].getType(); } D3DFORMAT TextureCubeMap::getD3DFormat() const @@ -2210,37 +2398,27 @@ void TextureCubeMap::setImageNegZ(GLint level, GLsizei width, GLsizei height, GL void TextureCubeMap::setCompressedImage(GLenum face, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels) { - redefineTexture(faceIndex(face), level, format, width, height, GL_UNSIGNED_BYTE); + redefineImage(faceIndex(face), level, format, width, height, GL_UNSIGNED_BYTE); Texture::setCompressedImage(imageSize, pixels, &mImageArray[faceIndex(face)][level]); } -void TextureCubeMap::commitRect(GLenum faceTarget, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height) +void TextureCubeMap::commitRect(int face, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height) { - int face = faceIndex(faceTarget); - ASSERT(mImageArray[face][level].surface != NULL); + ASSERT(mImageArray[face][level].getSurface() != NULL); if (level < levelCount()) { - IDirect3DSurface9 *destLevel = getCubeMapSurface(faceTarget, level); + IDirect3DSurface9 *destLevel = mTexture->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level); ASSERT(destLevel != NULL); if (destLevel != NULL) { Image *image = &mImageArray[face][level]; - - RECT sourceRect = transformPixelRect(xoffset, yoffset, width, height, image->height);; - - POINT destPoint; - destPoint.x = sourceRect.left; - destPoint.y = sourceRect.top; - - HRESULT result = getDevice()->UpdateSurface(image->surface, &sourceRect, destLevel, &destPoint); - ASSERT(SUCCEEDED(result)); + image->updateSurface(destLevel, xoffset, yoffset, width, height); destLevel->Release(); - - image->dirty = false; + image->markClean(); } } } @@ -2249,7 +2427,7 @@ void TextureCubeMap::subImage(GLenum target, GLint level, GLint xoffset, GLint y { if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[faceIndex(target)][level])) { - commitRect(target, level, xoffset, yoffset, width, height); + commitRect(faceIndex(target), level, xoffset, yoffset, width, height); } } @@ -2257,19 +2435,14 @@ void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffse { if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[faceIndex(target)][level])) { - commitRect(target, level, xoffset, yoffset, width, height); + commitRect(faceIndex(target), level, xoffset, yoffset, width, height); } } -// Tests for GL texture object completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81. -bool TextureCubeMap::isComplete() const +// Tests for cube map sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 86. +bool TextureCubeMap::isSamplerComplete() const { - int size = mImageArray[0][0].width; - - if (size <= 0) - { - return false; - } + int size = mImageArray[0][0].getWidth(); bool mipmapping; @@ -2288,16 +2461,8 @@ bool TextureCubeMap::isComplete() const default: UNREACHABLE(); } - for (int face = 0; face < 6; face++) - { - if (mImageArray[face][0].width != size || mImageArray[face][0].height != size) - { - return false; - } - } - - if ((getInternalFormat() == GL_FLOAT && !getContext()->supportsFloatLinearFilter()) || - (getInternalFormat() == GL_HALF_FLOAT_OES && !getContext()->supportsHalfFloatLinearFilter())) + if ((getInternalFormat() == GL_FLOAT && !getContext()->supportsFloat32LinearFilter()) || + (getInternalFormat() == GL_HALF_FLOAT_OES && !getContext()->supportsFloat16LinearFilter())) { if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST)) { @@ -2305,48 +2470,87 @@ bool TextureCubeMap::isComplete() const } } - bool npot = getContext()->supportsNonPower2Texture(); - - if (!npot) + if (!isPow2(size) && !getContext()->supportsNonPower2Texture()) { - if ((getWrapS() != GL_CLAMP_TO_EDGE || getWrapT() != GL_CLAMP_TO_EDGE) && !isPow2(size)) + if (getWrapS() != GL_CLAMP_TO_EDGE || getWrapT() != GL_CLAMP_TO_EDGE || mipmapping) { return false; } } - if (mipmapping) + if (!mipmapping) { - if (!npot) + if (!isCubeComplete()) { - if (!isPow2(size)) + return false; + } + } + else + { + if (!isMipmapCubeComplete()) // Also tests for isCubeComplete() + { + return false; + } + } + + return true; +} + +// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81. +bool TextureCubeMap::isCubeComplete() const +{ + if (mImageArray[0][0].getWidth() <= 0 || mImageArray[0][0].getHeight() != mImageArray[0][0].getWidth()) + { + return false; + } + + for (unsigned int face = 1; face < 6; face++) + { + if (mImageArray[face][0].getWidth() != mImageArray[0][0].getWidth() || + mImageArray[face][0].getWidth() != mImageArray[0][0].getHeight() || + mImageArray[face][0].getFormat() != mImageArray[0][0].getFormat() || + mImageArray[face][0].getType() != mImageArray[0][0].getType()) + { + return false; + } + } + + return true; +} + +bool TextureCubeMap::isMipmapCubeComplete() const +{ + if (isImmutable()) + { + return true; + } + + if (!isCubeComplete()) + { + return false; + } + + GLsizei size = mImageArray[0][0].getWidth(); + + int q = log2(size); + + for (int face = 0; face < 6; face++) + { + for (int level = 1; level <= q; level++) + { + if (mImageArray[face][level].getFormat() != mImageArray[0][0].getFormat()) { return false; } - } - int q = log2(size); - - for (int face = 0; face < 6; face++) - { - for (int level = 1; level <= q; level++) + if (mImageArray[face][level].getType() != mImageArray[0][0].getType()) { - if (mImageArray[face][level].format != mImageArray[0][0].format) - { - return false; - } + return false; + } - if (mImageArray[face][level].type != mImageArray[0][0].type) - { - return false; - } - - if (mImageArray[face][level].width != std::max(1, size >> level)) - { - return false; - } - - ASSERT(mImageArray[face][level].height == mImageArray[face][level].width); + if (mImageArray[face][level].getWidth() != std::max(1, size >> level)) + { + return false; } } } @@ -2361,39 +2565,39 @@ bool TextureCubeMap::isCompressed() const IDirect3DBaseTexture9 *TextureCubeMap::getBaseTexture() const { - return mTexture; + return mTexture ? mTexture->getBaseTexture() : NULL; } // Constructs a Direct3D 9 texture resource from the texture images, or returns an existing one void TextureCubeMap::createTexture() { - IDirect3DDevice9 *device = getDevice(); + GLsizei size = mImageArray[0][0].getWidth(); + GLint levels = creationLevels(size, 0); D3DFORMAT format = mImageArray[0][0].getD3DFormat(); - GLint levels = creationLevels(mImageArray[0][0].width, 0); + bool renderable = (mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE); - IDirect3DCubeTexture9 *texture = NULL; - HRESULT result = device->CreateCubeTexture(mImageArray[0][0].width, levels, 0, format, D3DPOOL_DEFAULT, &texture, NULL); + delete mTexture; + mTexture = new TextureStorageCubeMap(levels, format, size, renderable); - if (FAILED(result)) + if (mTexture->isManaged()) { - ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); - return error(GL_OUT_OF_MEMORY); - } + int levels = levelCount(); - if (mTexture) - { - mTexture->Release(); + for (int face = 0; face < 6; face++) + { + for (int level = 0; level < levels; level++) + { + IDirect3DSurface9 *surface = mTexture->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level); + mImageArray[face][level].setManagedSurface(surface); + } + } } - - mTexture = texture; - mDirtyImage = true; - mIsRenderable = false; + + mDirtyImages = true; } void TextureCubeMap::updateTexture() { - IDirect3DDevice9 *device = getDevice(); - for (int face = 0; face < 6; face++) { int levels = levelCount(); @@ -2401,20 +2605,9 @@ void TextureCubeMap::updateTexture() { Image *image = &mImageArray[face][level]; - if (image->surface && image->dirty) + if (image->isDirty()) { - IDirect3DSurface9 *levelSurface = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level); - ASSERT(levelSurface != NULL); - - if (levelSurface != NULL) - { - HRESULT result = device->UpdateSurface(image->surface, NULL, levelSurface, NULL); - ASSERT(SUCCEEDED(result)); - - levelSurface->Release(); - - image->dirty = false; - } + commitRect(face, level, 0, 0, image->getWidth(), image->getHeight()); } } } @@ -2422,89 +2615,53 @@ void TextureCubeMap::updateTexture() void TextureCubeMap::convertToRenderTarget() { - IDirect3DCubeTexture9 *texture = NULL; + TextureStorageCubeMap *newTexture = NULL; - if (mImageArray[0][0].width != 0) + if (mImageArray[0][0].getWidth() != 0) { - egl::Display *display = getDisplay(); - IDirect3DDevice9 *device = getDevice(); + GLsizei size = mImageArray[0][0].getWidth(); + GLint levels = creationLevels(size, 0); D3DFORMAT format = mImageArray[0][0].getD3DFormat(); - GLint levels = creationLevels(mImageArray[0][0].width, 0); - HRESULT result = device->CreateCubeTexture(mImageArray[0][0].width, levels, D3DUSAGE_RENDERTARGET, format, D3DPOOL_DEFAULT, &texture, NULL); - - if (FAILED(result)) - { - ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); - return error(GL_OUT_OF_MEMORY); - } + newTexture = new TextureStorageCubeMap(levels, format, size, true); if (mTexture != NULL) { + egl::Display *display = getDisplay(); + IDirect3DDevice9 *device = display->getDevice(); + int levels = levelCount(); for (int f = 0; f < 6; f++) { for (int i = 0; i < levels; i++) { - IDirect3DSurface9 *source; - result = mTexture->GetCubeMapSurface(static_cast(f), i, &source); + IDirect3DSurface9 *source = mTexture->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i); + IDirect3DSurface9 *dest = newTexture->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i); - if (FAILED(result)) + if (!copyToRenderTarget(dest, source, mTexture->isManaged())) { - ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); - - texture->Release(); - - return error(GL_OUT_OF_MEMORY); + delete newTexture; + source->Release(); + dest->Release(); + return error(GL_OUT_OF_MEMORY); } - IDirect3DSurface9 *dest; - result = texture->GetCubeMapSurface(static_cast(f), i, &dest); - - if (FAILED(result)) - { - ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); - - texture->Release(); - source->Release(); - - return error(GL_OUT_OF_MEMORY); - } - - display->endScene(); - result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE); - - if (FAILED(result)) - { - ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); - - texture->Release(); - source->Release(); - dest->Release(); - - return error(GL_OUT_OF_MEMORY); - } - - source->Release(); - dest->Release(); + if (source) source->Release(); + if (dest) dest->Release(); } } } } - if (mTexture != NULL) - { - mTexture->Release(); - } + delete mTexture; + mTexture = newTexture; - mTexture = texture; - mDirtyImage = true; - mIsRenderable = true; + mDirtyImages = true; } void TextureCubeMap::setImage(int faceIndex, GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels) { - redefineTexture(faceIndex, level, format, width, height, type); + redefineImage(faceIndex, level, format, width, height, type); Texture::setImage(unpackAlignment, pixels, &mImageArray[faceIndex][level]); } @@ -2520,48 +2677,24 @@ unsigned int TextureCubeMap::faceIndex(GLenum face) return face - GL_TEXTURE_CUBE_MAP_POSITIVE_X; } -void TextureCubeMap::redefineTexture(int face, GLint level, GLenum format, GLsizei width, GLsizei height, GLenum type) +void TextureCubeMap::redefineImage(int face, GLint level, GLenum format, GLsizei width, GLsizei height, GLenum type) { - GLsizei textureWidth = mImageArray[0][0].width; - GLsizei textureHeight = mImageArray[0][0].height; - GLenum textureFormat = mImageArray[0][0].format; - GLenum textureType = mImageArray[0][0].type; + bool redefined = mImageArray[face][level].redefine(format, width, height, type, false); - mImageArray[face][level].width = width; - mImageArray[face][level].height = height; - mImageArray[face][level].format = format; - mImageArray[face][level].type = type; - - if (!mTexture) - { - return; - } - - bool sizeOkay = (textureWidth >> level == width); - bool textureOkay = (sizeOkay && textureFormat == format && textureType == type); - - if (!textureOkay) // Purge all the levels and the texture. + if (mTexture && redefined) { for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) { for (int f = 0; f < 6; f++) { - if (mImageArray[f][i].surface != NULL) - { - mImageArray[f][i].surface->Release(); - mImageArray[f][i].surface = NULL; - mImageArray[f][i].dirty = true; - } + mImageArray[f][i].markDirty(); } } - if (mTexture != NULL) - { - mTexture->Release(); - mTexture = NULL; - mDirtyImage = true; - mIsRenderable = false; - } + delete mTexture; + mTexture = NULL; + + mDirtyImages = true; } } @@ -2576,20 +2709,21 @@ void TextureCubeMap::copyImage(GLenum target, GLint level, GLenum format, GLint } unsigned int faceindex = faceIndex(target); - redefineTexture(faceindex, level, format, width, height, GL_UNSIGNED_BYTE); + redefineImage(faceindex, level, format, width, height, GL_UNSIGNED_BYTE); if (!mImageArray[faceindex][level].isRenderable()) { - copyToImage(&mImageArray[faceindex][level], 0, 0, x, y, width, height, renderTarget); + mImageArray[faceindex][level].copy(0, 0, x, y, width, height, renderTarget); + mDirtyImages = true; } else { - if (!mTexture || !mIsRenderable) + if (!mTexture || !mTexture->isRenderable()) { convertToRenderTarget(); } - updateTexture(); + mImageArray[faceindex][level].markClean(); ASSERT(width == height); @@ -2601,34 +2735,24 @@ void TextureCubeMap::copyImage(GLenum target, GLint level, GLenum format, GLint sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth()); sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight()); - GLint destYOffset = transformPixelYOffset(0, height, mImageArray[faceindex][level].width); + GLint destYOffset = transformPixelYOffset(0, height, mImageArray[faceindex][level].getWidth()); - IDirect3DSurface9 *dest = getCubeMapSurface(target, level); + IDirect3DSurface9 *dest = mTexture->getCubeMapSurface(target, level); - getBlitter()->copy(source->getRenderTarget(), sourceRect, format, 0, destYOffset, dest); - dest->Release(); + if (dest) + { + getBlitter()->copy(renderTarget, sourceRect, format, 0, destYOffset, dest); + dest->Release(); + } } } -} -IDirect3DSurface9 *TextureCubeMap::getCubeMapSurface(GLenum face, unsigned int level) -{ - if (mTexture == NULL) - { - UNREACHABLE(); - return NULL; - } - - IDirect3DSurface9 *surface = NULL; - - HRESULT hr = mTexture->GetCubeMapSurface(es2dx::ConvertCubeFace(face), level, &surface); - - return (SUCCEEDED(hr)) ? surface : NULL; + renderTarget->Release(); } void TextureCubeMap::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source) { - GLsizei size = mImageArray[faceIndex(target)][level].width; + GLsizei size = mImageArray[faceIndex(target)][level].getWidth(); if (xoffset + width > size || yoffset + height > size) { @@ -2644,15 +2768,15 @@ void TextureCubeMap::copySubImage(GLenum target, GLint level, GLint xoffset, GLi } unsigned int faceindex = faceIndex(target); - redefineTexture(faceindex, level, mImageArray[faceindex][level].format, mImageArray[faceindex][level].width, mImageArray[faceindex][level].height, GL_UNSIGNED_BYTE); - - if (!mImageArray[faceindex][level].isRenderable() || (!mTexture && !isComplete())) + + if (!mImageArray[faceindex][level].isRenderable() || (!mTexture && !isSamplerComplete())) { - copyToImage(&mImageArray[faceindex][level], 0, 0, x, y, width, height, renderTarget); + mImageArray[faceindex][level].copy(0, 0, x, y, width, height, renderTarget); + mDirtyImages = true; } else { - if (!mTexture || !mIsRenderable) + if (!mTexture || !mTexture->isRenderable()) { convertToRenderTarget(); } @@ -2667,33 +2791,46 @@ void TextureCubeMap::copySubImage(GLenum target, GLint level, GLint xoffset, GLi sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth()); sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight()); - GLint destYOffset = transformPixelYOffset(yoffset, height, mImageArray[faceindex][level].width); + GLint destYOffset = transformPixelYOffset(yoffset, height, mImageArray[faceindex][level].getWidth()); - IDirect3DSurface9 *dest = getCubeMapSurface(target, level); + IDirect3DSurface9 *dest = mTexture->getCubeMapSurface(target, level); - getBlitter()->copy(source->getRenderTarget(), sourceRect, mImageArray[0][0].format, xoffset, destYOffset, dest); - dest->Release(); + if (dest) + { + getBlitter()->copy(renderTarget, sourceRect, mImageArray[0][0].getFormat(), xoffset, destYOffset, dest); + dest->Release(); + } } } + + renderTarget->Release(); } -bool TextureCubeMap::isCubeComplete() const +void TextureCubeMap::storage(GLsizei levels, GLenum internalformat, GLsizei size) { - if (mImageArray[0][0].width == 0) - { - return false; - } + GLenum format = gl::ExtractFormat(internalformat); + GLenum type = gl::ExtractType(internalformat); - for (unsigned int f = 1; f < 6; f++) + delete mTexture; + mTexture = new TextureStorageCubeMap(levels, mImageArray[0][0].getD3DFormat(), size, mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE); + mImmutable = true; + + for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) { - if (mImageArray[f][0].width != mImageArray[0][0].width - || mImageArray[f][0].format != mImageArray[0][0].format) + for (int face = 0; face < 6; face++) { - return false; + mImageArray[face][level].redefine(format, size, size, type, true); + size = std::max(1, size >> 1); } } - return true; + for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) + { + for (int face = 0; face < 6; face++) + { + mImageArray[face][level].redefine(GL_NONE, 0, 0, GL_UNSIGNED_BYTE, true); + } + } } void TextureCubeMap::generateMipmaps() @@ -2705,44 +2842,33 @@ void TextureCubeMap::generateMipmaps() if (!getContext()->supportsNonPower2Texture()) { - if (!isPow2(mImageArray[0][0].width)) + if (!isPow2(mImageArray[0][0].getWidth())) { return error(GL_INVALID_OPERATION); } } // Purge array levels 1 through q and reset them to represent the generated mipmap levels. - unsigned int q = log2(mImageArray[0][0].width); + unsigned int q = log2(mImageArray[0][0].getWidth()); for (unsigned int f = 0; f < 6; f++) { for (unsigned int i = 1; i <= q; i++) { - if (mImageArray[f][i].surface != NULL) - { - mImageArray[f][i].surface->Release(); - mImageArray[f][i].surface = NULL; - } - - mImageArray[f][i].width = std::max(mImageArray[f][0].width >> i, 1); - mImageArray[f][i].height = mImageArray[f][i].width; - mImageArray[f][i].format = mImageArray[f][0].format; - mImageArray[f][i].type = mImageArray[f][0].type; + redefineImage(f, i, mImageArray[f][0].getFormat(), + std::max(mImageArray[f][0].getWidth() >> i, 1), + std::max(mImageArray[f][0].getWidth() >> i, 1), + mImageArray[f][0].getType()); } } - if (mIsRenderable) + if (mTexture && mTexture->isRenderable()) { - if (mTexture == NULL) - { - return; - } - for (unsigned int f = 0; f < 6; f++) { for (unsigned int i = 1; i <= q; i++) { - IDirect3DSurface9 *upper = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i-1); - IDirect3DSurface9 *lower = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i); + IDirect3DSurface9 *upper = mTexture->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i-1); + IDirect3DSurface9 *lower = mTexture->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i); if (upper != NULL && lower != NULL) { @@ -2752,7 +2878,7 @@ void TextureCubeMap::generateMipmaps() if (upper != NULL) upper->Release(); if (lower != NULL) lower->Release(); - mImageArray[f][i].dirty = false; + mImageArray[f][i].markClean(); } } } @@ -2762,18 +2888,17 @@ void TextureCubeMap::generateMipmaps() { for (unsigned int i = 1; i <= q; i++) { - createSurface(&mImageArray[f][i]); - if (mImageArray[f][i].surface == NULL) + if (mImageArray[f][i].getSurface() == NULL) { return error(GL_OUT_OF_MEMORY); } - if (FAILED(D3DXLoadSurfaceFromSurface(mImageArray[f][i].surface, NULL, NULL, mImageArray[f][i - 1].surface, NULL, NULL, D3DX_FILTER_BOX, 0))) + if (FAILED(D3DXLoadSurfaceFromSurface(mImageArray[f][i].getSurface(), NULL, NULL, mImageArray[f][i - 1].getSurface(), NULL, NULL, D3DX_FILTER_BOX, 0))) { ERR(" failed to load filter %d to %d.", i - 1, i); } - mImageArray[f][i].dirty = true; + mImageArray[f][i].markDirty(); } } } @@ -2790,7 +2915,7 @@ Renderbuffer *TextureCubeMap::getRenderbuffer(GLenum target) if (mFaceProxies[face].get() == NULL) { - mFaceProxies[face].set(new Renderbuffer(id(), new Colorbuffer(this, target))); + mFaceProxies[face].set(new Renderbuffer(id(), new RenderbufferTexture(this, target))); } return mFaceProxies[face].get(); @@ -2800,7 +2925,7 @@ IDirect3DSurface9 *TextureCubeMap::getRenderTarget(GLenum target) { ASSERT(IsCubemapTextureTarget(target)); - if (!mIsRenderable) + if (!mTexture || !mTexture->isRenderable()) { convertToRenderTarget(); } @@ -2812,10 +2937,12 @@ IDirect3DSurface9 *TextureCubeMap::getRenderTarget(GLenum target) updateTexture(); - IDirect3DSurface9 *renderTarget = NULL; - mTexture->GetCubeMapSurface(es2dx::ConvertCubeFace(target), 0, &renderTarget); - - return renderTarget; + return mTexture->getCubeMapSurface(target, 0); } +TextureStorage *TextureCubeMap::getStorage() const +{ + return mTexture; } + +} \ No newline at end of file diff --git a/gfx/angle/src/libGLESv2/Texture.h b/gfx/angle/src/libGLESv2/Texture.h index 95045b8fbedf..93374e8f3fcf 100644 --- a/gfx/angle/src/libGLESv2/Texture.h +++ b/gfx/angle/src/libGLESv2/Texture.h @@ -43,6 +43,126 @@ enum IMPLEMENTATION_MAX_TEXTURE_LEVELS = 15 // 1+log2 of MAX_TEXTURE_SIZE }; +class Image +{ + public: + Image(); + ~Image(); + + bool redefine(GLenum format, GLsizei width, GLsizei height, GLenum type, bool forceRelease); + void markDirty() {mDirty = true;} + void markClean() {mDirty = false;} + + HRESULT lock(D3DLOCKED_RECT *lockedRect, const RECT *rect); + void unlock(); + + bool isRenderable() const; + D3DFORMAT getD3DFormat() const; + + GLsizei getWidth() const {return mWidth;} + GLsizei getHeight() const {return mHeight;} + GLenum getFormat() const {return mFormat;} + GLenum getType() const {return mType;} + bool isDirty() const {return mSurface && mDirty;} + IDirect3DSurface9 *getSurface(); + + void setManagedSurface(IDirect3DSurface9 *surface); + void updateSurface(IDirect3DSurface9 *dest, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height); + + void loadData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum type, + GLint unpackAlignment, const void *input, std::size_t outputPitch, void *output) const; + + void loadAlphaData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + void loadAlphaFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + void loadAlphaHalfFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + void loadLuminanceData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output, bool native) const; + void loadLuminanceFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + void loadLuminanceHalfFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + void loadLuminanceAlphaData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output, bool native) const; + void loadLuminanceAlphaFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + void loadLuminanceAlphaHalfFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + void loadRGBUByteData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + void loadRGB565Data(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + void loadRGBFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + void loadRGBHalfFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + void loadRGBAUByteDataSSE2(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + void loadRGBAUByteData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + void loadRGBA4444Data(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + void loadRGBA5551Data(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + void loadRGBAFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + void loadRGBAHalfFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + void loadBGRAData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + void loadCompressedData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + void loadDXT1Data(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + void loadDXT3Data(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + void loadDXT5Data(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + + void copy(GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, IDirect3DSurface9 *renderTarget); + + private: + DISALLOW_COPY_AND_ASSIGN(Image); + + void createSurface(); + + GLsizei mWidth; + GLsizei mHeight; + GLenum mFormat; + GLenum mType; + + bool mDirty; + bool mManaged; + + IDirect3DSurface9 *mSurface; +}; + +class TextureStorage +{ + public: + explicit TextureStorage(bool renderable); + + virtual ~TextureStorage(); + + bool isRenderable() const; + bool isManaged() const; + unsigned int getTextureSerial() const; + virtual unsigned int getRenderTargetSerial(GLenum target) const = 0; + + private: + DISALLOW_COPY_AND_ASSIGN(TextureStorage); + + const bool mRenderable; + const bool mManaged; + + const unsigned int mTextureSerial; + static unsigned int issueTextureSerial(); + + static unsigned int mCurrentTextureSerial; +}; + class Texture : public RefCountObject { public: @@ -56,11 +176,13 @@ class Texture : public RefCountObject bool setMagFilter(GLenum filter); bool setWrapS(GLenum wrap); bool setWrapT(GLenum wrap); + bool setUsage(GLenum usage); GLenum getMinFilter() const; GLenum getMagFilter() const; GLenum getWrapS() const; GLenum getWrapT() const; + GLenum getUsage() const; virtual GLsizei getWidth() const = 0; virtual GLsizei getHeight() const = 0; @@ -68,7 +190,7 @@ class Texture : public RefCountObject virtual GLenum getType() const = 0; virtual D3DFORMAT getD3DFormat() const = 0; - virtual bool isComplete() const = 0; + virtual bool isSamplerComplete() const = 0; virtual bool isCompressed() const = 0; IDirect3DBaseTexture9 *getTexture(); @@ -77,43 +199,26 @@ class Texture : public RefCountObject virtual void generateMipmaps() = 0; virtual void copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source) = 0; - bool isDirtyParameter() const; - bool isDirtyImage() const; + bool hasDirtyParameters() const; + bool hasDirtyImages() const; void resetDirty(); - unsigned int getSerial() const; + unsigned int getTextureSerial() const; + unsigned int getRenderTargetSerial(GLenum target) const; + + bool isImmutable() const; static const GLuint INCOMPLETE_TEXTURE_ID = static_cast(-1); // Every texture takes an id at creation time. The value is arbitrary because it is never registered with the resource manager. protected: - friend class Colorbuffer; - - // Helper structure representing a single image layer - struct Image - { - Image(); - ~Image(); - - bool isRenderable() const; - D3DFORMAT getD3DFormat() const; - - GLsizei width; - GLsizei height; - GLenum format; - GLenum type; - - bool dirty; - - IDirect3DSurface9 *surface; - }; + friend class RenderbufferTexture; void setImage(GLint unpackAlignment, const void *pixels, Image *image); bool subImage(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, Image *image); void setCompressedImage(GLsizei imageSize, const void *pixels, Image *image); bool subImageCompressed(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels, Image *image); - void copyToImage(Image *image, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, IDirect3DSurface9 *renderTarget); - GLint creationLevels(GLsizei width, GLsizei height, GLint maxlevel) const; - GLint creationLevels(GLsizei size, GLint maxlevel) const; + GLint creationLevels(GLsizei width, GLsizei height) const; + GLint creationLevels(GLsizei size) const; virtual IDirect3DBaseTexture9 *getBaseTexture() const = 0; virtual void createTexture() = 0; @@ -121,82 +226,46 @@ class Texture : public RefCountObject virtual void convertToRenderTarget() = 0; virtual IDirect3DSurface9 *getRenderTarget(GLenum target) = 0; - void createSurface(Image *image); - - Blit *getBlitter(); - int levelCount() const; + static Blit *getBlitter(); + static bool copyToRenderTarget(IDirect3DSurface9 *dest, IDirect3DSurface9 *source, bool fromManaged); + GLenum mMinFilter; GLenum mMagFilter; GLenum mWrapS; GLenum mWrapT; - bool mDirtyParameter; + bool mDirtyParameters; + GLenum mUsage; - bool mDirtyImage; + bool mDirtyImages; - bool mIsRenderable; + bool mImmutable; private: DISALLOW_COPY_AND_ASSIGN(Texture); - void loadImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, - GLint unpackAlignment, const void *input, std::size_t outputPitch, void *output, D3DSURFACE_DESC *description) const; + virtual TextureStorage *getStorage() const = 0; +}; - void loadAlphaImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) const; - void loadAlphaFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) const; - void loadAlphaHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) const; - void loadLuminanceImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output, bool native) const; - void loadLuminanceFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) const; - void loadLuminanceHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) const; - void loadLuminanceAlphaImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output, bool native) const; - void loadLuminanceAlphaFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) const; - void loadLuminanceAlphaHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) const; - void loadRGBUByteImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) const; - void loadRGB565ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) const; - void loadRGBFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) const; - void loadRGBHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) const; - void loadRGBAUByteImageDataSSE2(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) const; - void loadRGBAUByteImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) const; - void loadRGBA4444ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) const; - void loadRGBA5551ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) const; - void loadRGBAFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) const; - void loadRGBAHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) const; - void loadBGRAImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) const; - void loadCompressedImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) const; - void loadDXT1ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) const; - void loadDXT3ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) const; - void loadDXT5ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - int inputPitch, const void *input, size_t outputPitch, void *output) const; +class TextureStorage2D : public TextureStorage +{ + public: + explicit TextureStorage2D(IDirect3DTexture9 *surfaceTexture); + TextureStorage2D(int levels, D3DFORMAT format, int width, int height, bool renderable); - static unsigned int issueSerial(); + virtual ~TextureStorage2D(); - const unsigned int mSerial; + IDirect3DSurface9 *getSurfaceLevel(int level); + IDirect3DBaseTexture9 *getBaseTexture() const; - static unsigned int mCurrentSerial; + virtual unsigned int getRenderTargetSerial(GLenum target) const; + + private: + DISALLOW_COPY_AND_ASSIGN(TextureStorage2D); + + IDirect3DTexture9 *mTexture; + const unsigned int mRenderTargetSerial; }; class Texture2D : public Texture @@ -219,9 +288,10 @@ class Texture2D : public Texture void subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels); void subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels); void copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source); - void copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source); + virtual void copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source); + void storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); - virtual bool isComplete() const; + virtual bool isSamplerComplete() const; virtual bool isCompressed() const; virtual void bindTexImage(egl::Surface *surface); virtual void releaseTexImage(); @@ -238,18 +308,40 @@ class Texture2D : public Texture virtual void updateTexture(); virtual void convertToRenderTarget(); virtual IDirect3DSurface9 *getRenderTarget(GLenum target); + virtual TextureStorage *getStorage() const; - void redefineTexture(GLint level, GLenum format, GLsizei width, GLsizei height, GLenum type, bool force); + bool isMipmapComplete() const; + + void redefineImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLenum type); void commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height); Image mImageArray[IMPLEMENTATION_MAX_TEXTURE_LEVELS]; - IDirect3DTexture9 *mTexture; + TextureStorage2D *mTexture; egl::Surface *mSurface; BindingPointer mColorbufferProxy; }; +class TextureStorageCubeMap : public TextureStorage +{ + public: + TextureStorageCubeMap(int levels, D3DFORMAT format, int size, bool renderable); + + virtual ~TextureStorageCubeMap(); + + IDirect3DSurface9 *getCubeMapSurface(GLenum faceTarget, int level); + IDirect3DBaseTexture9 *getBaseTexture() const; + + virtual unsigned int getRenderTargetSerial(GLenum target) const; + + private: + DISALLOW_COPY_AND_ASSIGN(TextureStorageCubeMap); + + IDirect3DCubeTexture9 *mTexture; + const unsigned int mFirstRenderTargetSerial; +}; + class TextureCubeMap : public Texture { public: @@ -278,14 +370,17 @@ class TextureCubeMap : public Texture void subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels); void copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source); virtual void copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source); + void storage(GLsizei levels, GLenum internalformat, GLsizei size); - virtual bool isComplete() const; + virtual bool isSamplerComplete() const; virtual bool isCompressed() const; virtual void generateMipmaps(); virtual Renderbuffer *getRenderbuffer(GLenum target); + static unsigned int faceIndex(GLenum face); + private: DISALLOW_COPY_AND_ASSIGN(TextureCubeMap); @@ -294,25 +389,21 @@ class TextureCubeMap : public Texture virtual void updateTexture(); virtual void convertToRenderTarget(); virtual IDirect3DSurface9 *getRenderTarget(GLenum target); - - // face is one of the GL_TEXTURE_CUBE_MAP_* enumerants. - // Returns NULL if the call underlying Direct3D call fails. - IDirect3DSurface9 *getCubeMapSurface(GLenum face, unsigned int level); - - static unsigned int faceIndex(GLenum face); + virtual TextureStorage *getStorage() const; bool isCubeComplete() const; + bool isMipmapCubeComplete() const; void setImage(int faceIndex, GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels); - void commitRect(GLenum faceTarget, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height); - void redefineTexture(int faceIndex, GLint level, GLenum format, GLsizei width, GLsizei height, GLenum type); + void commitRect(int faceIndex, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height); + void redefineImage(int faceIndex, GLint level, GLenum format, GLsizei width, GLsizei height, GLenum type); Image mImageArray[6][IMPLEMENTATION_MAX_TEXTURE_LEVELS]; - IDirect3DCubeTexture9 *mTexture; + TextureStorageCubeMap *mTexture; BindingPointer mFaceProxies[6]; }; } -#endif // LIBGLESV2_TEXTURE_H_ +#endif // LIBGLESV2_TEXTURE_H_ \ No newline at end of file diff --git a/gfx/angle/src/libGLESv2/VertexDataManager.cpp b/gfx/angle/src/libGLESv2/VertexDataManager.cpp index d0245ef2c949..698d8b9bd45a 100644 --- a/gfx/angle/src/libGLESv2/VertexDataManager.cpp +++ b/gfx/angle/src/libGLESv2/VertexDataManager.cpp @@ -29,6 +29,12 @@ namespace gl { unsigned int VertexBuffer::mCurrentSerial = 1; +int elementsInBuffer(const VertexAttribute &attribute, int size) +{ + int stride = attribute.stride(); + return (size - attribute.mOffset % stride + (stride - attribute.typeSize())) / stride; +} + VertexDataManager::VertexDataManager(Context *context, IDirect3DDevice9 *device) : mContext(context), mDevice(device) { for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++) @@ -137,7 +143,7 @@ GLenum VertexDataManager::prepareVertexData(GLint start, GLsizei count, Translat { if (staticBuffer->size() == 0) { - int totalCount = buffer->size() / attribs[i].stride(); + int totalCount = elementsInBuffer(attribs[i], buffer->size()); staticBuffer->addRequiredSpace(spaceRequired(attribs[i], totalCount)); } else if (staticBuffer->lookupAttribute(attribs[i]) == -1) @@ -216,7 +222,7 @@ GLenum VertexDataManager::prepareVertexData(GLint start, GLsizei count, Translat if (streamOffset == -1) { // Convert the entire buffer - int totalCount = buffer->size() / attribs[i].stride(); + int totalCount = elementsInBuffer(attribs[i], buffer->size()); int startIndex = attribs[i].mOffset / attribs[i].stride(); streamOffset = writeAttributeData(staticBuffer, -startIndex, totalCount, attribs[i]); diff --git a/gfx/angle/src/libGLESv2/libGLESv2.cpp b/gfx/angle/src/libGLESv2/libGLESv2.cpp index 8296f8f27124..f94b085e08b5 100644 --- a/gfx/angle/src/libGLESv2/libGLESv2.cpp +++ b/gfx/angle/src/libGLESv2/libGLESv2.cpp @@ -53,6 +53,46 @@ bool validImageSize(GLint level, GLsizei width, GLsizei height) return false; } +// check for combinations of format and type that are valid for ReadPixels +bool validReadFormatType(GLenum format, GLenum type) +{ + switch (format) + { + case GL_RGBA: + switch (type) + { + case GL_UNSIGNED_BYTE: + break; + default: + return false; + } + break; + case GL_BGRA_EXT: + switch (type) + { + case GL_UNSIGNED_BYTE: + case GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT: + case GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT: + break; + default: + return false; + } + break; + case gl::IMPLEMENTATION_COLOR_READ_FORMAT: + switch (type) + { + case gl::IMPLEMENTATION_COLOR_READ_TYPE: + break; + default: + return false; + } + break; + default: + return false; + } + return true; +} + extern "C" { @@ -62,7 +102,7 @@ void __stdcall glActiveTexture(GLenum texture) try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -86,7 +126,7 @@ void __stdcall glAttachShader(GLuint program, GLuint shader) try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -140,7 +180,7 @@ void __stdcall glBindAttribLocation(GLuint program, GLuint index, const GLchar* return error(GL_INVALID_VALUE); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -178,7 +218,7 @@ void __stdcall glBindBuffer(GLenum target, GLuint buffer) try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -212,7 +252,7 @@ void __stdcall glBindFramebuffer(GLenum target, GLuint framebuffer) return error(GL_INVALID_ENUM); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -244,7 +284,7 @@ void __stdcall glBindRenderbuffer(GLenum target, GLuint renderbuffer) return error(GL_INVALID_ENUM); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -263,7 +303,7 @@ void __stdcall glBindTexture(GLenum target, GLuint texture) try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -300,7 +340,7 @@ void __stdcall glBlendColor(GLclampf red, GLclampf green, GLclampf blue, GLclamp try { - gl::Context* context = gl::getContext(); + gl::Context* context = gl::getNonLostContext(); if (context) { @@ -344,7 +384,7 @@ void __stdcall glBlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha) return error(GL_INVALID_ENUM); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -467,7 +507,7 @@ void __stdcall glBlendFuncSeparate(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha return error(GL_INVALID_OPERATION); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -502,7 +542,7 @@ void __stdcall glBufferData(GLenum target, GLsizeiptr size, const GLvoid* data, return error(GL_INVALID_ENUM); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -551,7 +591,7 @@ void __stdcall glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, return; } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -599,7 +639,7 @@ GLenum __stdcall glCheckFramebufferStatus(GLenum target) return error(GL_INVALID_ENUM, 0); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -630,7 +670,7 @@ void __stdcall glClear(GLbitfield mask) try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -650,7 +690,7 @@ void __stdcall glClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclamp try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -669,7 +709,7 @@ void __stdcall glClearDepthf(GLclampf depth) try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -688,7 +728,7 @@ void __stdcall glClearStencil(GLint s) try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -708,7 +748,7 @@ void __stdcall glColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboo try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -727,7 +767,7 @@ void __stdcall glCompileShader(GLuint shader) try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -784,7 +824,7 @@ void __stdcall glCompressedTexImage2D(GLenum target, GLint level, GLenum interna return error(GL_INVALID_VALUE); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -860,6 +900,11 @@ void __stdcall glCompressedTexImage2D(GLenum target, GLint level, GLenum interna return error(GL_INVALID_OPERATION); } + if (texture->isImmutable()) + { + return error(GL_INVALID_OPERATION); + } + texture->setCompressedImage(level, internalformat, width, height, imageSize, data); } else @@ -871,6 +916,11 @@ void __stdcall glCompressedTexImage2D(GLenum target, GLint level, GLenum interna return error(GL_INVALID_OPERATION); } + if (texture->isImmutable()) + { + return error(GL_INVALID_OPERATION); + } + switch (target) { case GL_TEXTURE_CUBE_MAP_POSITIVE_X: @@ -929,7 +979,7 @@ void __stdcall glCompressedTexSubImage2D(GLenum target, GLint level, GLint xoffs return; } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -1046,10 +1096,15 @@ void __stdcall glCopyTexImage2D(GLenum target, GLint level, GLenum internalforma return error(GL_INVALID_VALUE); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { + if (level > context->getMaximumTextureLevel()) + { + return error(GL_INVALID_VALUE); + } + switch (target) { case GL_TEXTURE_2D: @@ -1092,7 +1147,7 @@ void __stdcall glCopyTexImage2D(GLenum target, GLint level, GLenum internalforma return error(GL_INVALID_OPERATION); } - gl::Colorbuffer *source = framebuffer->getColorbuffer(); + gl::Renderbuffer *source = framebuffer->getColorbuffer(); GLenum colorbufferFormat = source->getInternalFormat(); // [OpenGL ES 2.0.24] table 3.9 @@ -1175,6 +1230,11 @@ void __stdcall glCopyTexImage2D(GLenum target, GLint level, GLenum internalforma return error(GL_INVALID_OPERATION); } + if (texture->isImmutable()) + { + return error(GL_INVALID_OPERATION); + } + texture->copyImage(level, internalformat, x, y, width, height, framebuffer); } else if (gl::IsCubemapTextureTarget(target)) @@ -1186,6 +1246,11 @@ void __stdcall glCopyTexImage2D(GLenum target, GLint level, GLenum internalforma return error(GL_INVALID_OPERATION); } + if (texture->isImmutable()) + { + return error(GL_INVALID_OPERATION); + } + texture->copyImage(target, level, internalformat, x, y, width, height, framebuffer); } else UNREACHABLE(); @@ -1225,7 +1290,7 @@ void __stdcall glCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GL return; } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -1246,7 +1311,7 @@ void __stdcall glCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GL return error(GL_INVALID_OPERATION); } - gl::Colorbuffer *source = framebuffer->getColorbuffer(); + gl::Renderbuffer *source = framebuffer->getColorbuffer(); GLenum colorbufferFormat = source->getInternalFormat(); gl::Texture *texture = NULL; @@ -1328,7 +1393,7 @@ GLuint __stdcall glCreateProgram(void) try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -1349,7 +1414,7 @@ GLuint __stdcall glCreateShader(GLenum type) try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -1383,7 +1448,7 @@ void __stdcall glCullFace(GLenum mode) case GL_BACK: case GL_FRONT_AND_BACK: { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -1412,7 +1477,7 @@ void __stdcall glDeleteBuffers(GLsizei n, const GLuint* buffers) return error(GL_INVALID_VALUE); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -1439,7 +1504,7 @@ void __stdcall glDeleteFencesNV(GLsizei n, const GLuint* fences) return error(GL_INVALID_VALUE); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -1466,7 +1531,7 @@ void __stdcall glDeleteFramebuffers(GLsizei n, const GLuint* framebuffers) return error(GL_INVALID_VALUE); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -1496,7 +1561,7 @@ void __stdcall glDeleteProgram(GLuint program) return; } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -1532,7 +1597,7 @@ void __stdcall glDeleteRenderbuffers(GLsizei n, const GLuint* renderbuffers) return error(GL_INVALID_VALUE); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -1559,7 +1624,7 @@ void __stdcall glDeleteShader(GLuint shader) return; } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -1595,7 +1660,7 @@ void __stdcall glDeleteTextures(GLsizei n, const GLuint* textures) return error(GL_INVALID_VALUE); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -1635,7 +1700,7 @@ void __stdcall glDepthFunc(GLenum func) return error(GL_INVALID_ENUM); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -1654,7 +1719,7 @@ void __stdcall glDepthMask(GLboolean flag) try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -1673,7 +1738,7 @@ void __stdcall glDepthRangef(GLclampf zNear, GLclampf zFar) try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -1692,7 +1757,7 @@ void __stdcall glDetachShader(GLuint program, GLuint shader) try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -1745,7 +1810,7 @@ void __stdcall glDisable(GLenum cap) try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -1782,7 +1847,7 @@ void __stdcall glDisableVertexAttribArray(GLuint index) return error(GL_INVALID_VALUE); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -1806,7 +1871,7 @@ void __stdcall glDrawArrays(GLenum mode, GLint first, GLsizei count) return error(GL_INVALID_VALUE); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -1831,7 +1896,7 @@ void __stdcall glDrawElements(GLenum mode, GLsizei count, GLenum type, const GLv return error(GL_INVALID_VALUE); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -1865,7 +1930,7 @@ void __stdcall glEnable(GLenum cap) try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -1902,7 +1967,7 @@ void __stdcall glEnableVertexAttribArray(GLuint index) return error(GL_INVALID_VALUE); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -1921,7 +1986,7 @@ void __stdcall glFinishFenceNV(GLuint fence) try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -1947,7 +2012,7 @@ void __stdcall glFinish(void) try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -1966,7 +2031,7 @@ void __stdcall glFlush(void) try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -1992,7 +2057,7 @@ void __stdcall glFramebufferRenderbuffer(GLenum target, GLenum attachment, GLenu return error(GL_INVALID_ENUM); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -2058,7 +2123,7 @@ void __stdcall glFramebufferTexture2D(GLenum target, GLenum attachment, GLenum t return error(GL_INVALID_ENUM); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -2154,7 +2219,7 @@ void __stdcall glFrontFace(GLenum mode) case GL_CW: case GL_CCW: { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -2183,7 +2248,7 @@ void __stdcall glGenBuffers(GLsizei n, GLuint* buffers) return error(GL_INVALID_VALUE); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -2205,7 +2270,7 @@ void __stdcall glGenerateMipmap(GLenum target) try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -2250,7 +2315,7 @@ void __stdcall glGenFencesNV(GLsizei n, GLuint* fences) return error(GL_INVALID_VALUE); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -2277,7 +2342,7 @@ void __stdcall glGenFramebuffers(GLsizei n, GLuint* framebuffers) return error(GL_INVALID_VALUE); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -2304,7 +2369,7 @@ void __stdcall glGenRenderbuffers(GLsizei n, GLuint* renderbuffers) return error(GL_INVALID_VALUE); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -2331,7 +2396,7 @@ void __stdcall glGenTextures(GLsizei n, GLuint* textures) return error(GL_INVALID_VALUE); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -2360,7 +2425,7 @@ void __stdcall glGetActiveAttrib(GLuint program, GLuint index, GLsizei bufsize, return error(GL_INVALID_VALUE); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -2405,7 +2470,7 @@ void __stdcall glGetActiveUniform(GLuint program, GLuint index, GLsizei bufsize, return error(GL_INVALID_VALUE); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -2449,7 +2514,7 @@ void __stdcall glGetAttachedShaders(GLuint program, GLsizei maxcount, GLsizei* c return error(GL_INVALID_VALUE); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -2482,7 +2547,7 @@ int __stdcall glGetAttribLocation(GLuint program, const GLchar* name) try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -2523,7 +2588,7 @@ void __stdcall glGetBooleanv(GLenum pname, GLboolean* params) try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -2586,7 +2651,7 @@ void __stdcall glGetBufferParameteriv(GLenum target, GLenum pname, GLint* params try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -2635,7 +2700,10 @@ GLenum __stdcall glGetError(void) if (context) { - return context->getError(); + if (context->isContextLost()) + return GL_OUT_OF_MEMORY; + else + return context->getError(); } return GL_NO_ERROR; @@ -2648,7 +2716,7 @@ void __stdcall glGetFenceivNV(GLuint fence, GLenum pname, GLint *params) try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -2674,7 +2742,7 @@ void __stdcall glGetFloatv(GLenum pname, GLfloat* params) try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -2735,7 +2803,7 @@ void __stdcall glGetFramebufferAttachmentParameteriv(GLenum target, GLenum attac try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -2847,13 +2915,34 @@ void __stdcall glGetFramebufferAttachmentParameteriv(GLenum target, GLenum attac } } +GLenum __stdcall glGetGraphicsResetStatusEXT(void) +{ + EVENT("()"); + + try + { + gl::Context *context = gl::getContext(); + + if (context) + { + return context->getResetStatus(); + } + + return GL_NO_ERROR; + } + catch(std::bad_alloc&) + { + return GL_OUT_OF_MEMORY; + } +} + void __stdcall glGetIntegerv(GLenum pname, GLint* params) { EVENT("(GLenum pname = 0x%X, GLint* params = 0x%0.8p)", pname, params); try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -2918,7 +3007,7 @@ void __stdcall glGetProgramiv(GLuint program, GLenum pname, GLint* params) try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -2981,7 +3070,7 @@ void __stdcall glGetProgramInfoLog(GLuint program, GLsizei bufsize, GLsizei* len return error(GL_INVALID_VALUE); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -3007,7 +3096,7 @@ void __stdcall glGetRenderbufferParameteriv(GLenum target, GLenum pname, GLint* try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -3061,7 +3150,7 @@ void __stdcall glGetShaderiv(GLuint shader, GLenum pname, GLint* params) try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -3115,7 +3204,7 @@ void __stdcall glGetShaderInfoLog(GLuint shader, GLsizei bufsize, GLsizei* lengt return error(GL_INVALID_VALUE); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -3192,7 +3281,7 @@ void __stdcall glGetShaderSource(GLuint shader, GLsizei bufsize, GLsizei* length return error(GL_INVALID_VALUE); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -3224,7 +3313,7 @@ void __stdcall glGetTranslatedShaderSourceANGLE(GLuint shader, GLsizei bufsize, return error(GL_INVALID_VALUE); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -3250,7 +3339,7 @@ const GLubyte* __stdcall glGetString(GLenum name) try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); switch (name) { @@ -3282,7 +3371,7 @@ void __stdcall glGetTexParameterfv(GLenum target, GLenum pname, GLfloat* params) try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -3314,6 +3403,12 @@ void __stdcall glGetTexParameterfv(GLenum target, GLenum pname, GLfloat* params) case GL_TEXTURE_WRAP_T: *params = (GLfloat)texture->getWrapT(); break; + case GL_TEXTURE_IMMUTABLE_FORMAT_EXT: + *params = (GLfloat)(texture->isImmutable() ? GL_TRUE : GL_FALSE); + break; + case GL_TEXTURE_USAGE_ANGLE: + *params = (GLfloat)texture->getUsage(); + break; default: return error(GL_INVALID_ENUM); } @@ -3331,7 +3426,7 @@ void __stdcall glGetTexParameteriv(GLenum target, GLenum pname, GLint* params) try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -3363,6 +3458,12 @@ void __stdcall glGetTexParameteriv(GLenum target, GLenum pname, GLint* params) case GL_TEXTURE_WRAP_T: *params = texture->getWrapT(); break; + case GL_TEXTURE_IMMUTABLE_FORMAT_EXT: + *params = texture->isImmutable() ? GL_TRUE : GL_FALSE; + break; + case GL_TEXTURE_USAGE_ANGLE: + *params = texture->getUsage(); + break; default: return error(GL_INVALID_ENUM); } @@ -3374,13 +3475,19 @@ void __stdcall glGetTexParameteriv(GLenum target, GLenum pname, GLint* params) } } -void __stdcall glGetUniformfv(GLuint program, GLint location, GLfloat* params) +void __stdcall glGetnUniformfvEXT(GLuint program, GLint location, GLsizei bufSize, GLfloat* params) { - EVENT("(GLuint program = %d, GLint location = %d, GLfloat* params = 0x%0.8p)", program, location, params); + EVENT("(GLuint program = %d, GLint location = %d, GLsizei bufSize = %d, GLfloat* params = 0x%0.8p)", + program, location, bufSize, params); try { - gl::Context *context = gl::getContext(); + if (bufSize < 0) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -3396,7 +3503,7 @@ void __stdcall glGetUniformfv(GLuint program, GLint location, GLfloat* params) return error(GL_INVALID_OPERATION); } - if (!programObject->getUniformfv(location, params)) + if (!programObject->getUniformfv(location, &bufSize, params)) { return error(GL_INVALID_OPERATION); } @@ -3408,13 +3515,53 @@ void __stdcall glGetUniformfv(GLuint program, GLint location, GLfloat* params) } } -void __stdcall glGetUniformiv(GLuint program, GLint location, GLint* params) +void __stdcall glGetUniformfv(GLuint program, GLint location, GLfloat* params) { - EVENT("(GLuint program = %d, GLint location = %d, GLint* params = 0x%0.8p)", program, location, params); + EVENT("(GLuint program = %d, GLint location = %d, GLfloat* params = 0x%0.8p)", program, location, params); try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (program == 0) + { + return error(GL_INVALID_VALUE); + } + + gl::Program *programObject = context->getProgram(program); + + if (!programObject || !programObject->isLinked()) + { + return error(GL_INVALID_OPERATION); + } + + if (!programObject->getUniformfv(location, NULL, params)) + { + return error(GL_INVALID_OPERATION); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glGetnUniformivEXT(GLuint program, GLint location, GLsizei bufSize, GLint* params) +{ + EVENT("(GLuint program = %d, GLint location = %d, GLsizei bufSize = %d, GLint* params = 0x%0.8p)", + program, location, bufSize, params); + + try + { + if (bufSize < 0) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -3435,7 +3582,46 @@ void __stdcall glGetUniformiv(GLuint program, GLint location, GLint* params) return error(GL_INVALID_OPERATION); } - if (!programObject->getUniformiv(location, params)) + if (!programObject->getUniformiv(location, &bufSize, params)) + { + return error(GL_INVALID_OPERATION); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glGetUniformiv(GLuint program, GLint location, GLint* params) +{ + EVENT("(GLuint program = %d, GLint location = %d, GLint* params = 0x%0.8p)", program, location, params); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (program == 0) + { + return error(GL_INVALID_VALUE); + } + + gl::Program *programObject = context->getProgram(program); + + if (!programObject || !programObject->isLinked()) + { + return error(GL_INVALID_OPERATION); + } + + if (!programObject) + { + return error(GL_INVALID_OPERATION); + } + + if (!programObject->getUniformiv(location, NULL, params)) { return error(GL_INVALID_OPERATION); } @@ -3453,7 +3639,7 @@ int __stdcall glGetUniformLocation(GLuint program, const GLchar* name) try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (strstr(name, "gl_") == name) { @@ -3498,7 +3684,7 @@ void __stdcall glGetVertexAttribfv(GLuint index, GLenum pname, GLfloat* params) try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -3551,7 +3737,7 @@ void __stdcall glGetVertexAttribiv(GLuint index, GLenum pname, GLint* params) try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -3605,7 +3791,7 @@ void __stdcall glGetVertexAttribPointerv(GLuint index, GLenum pname, GLvoid** po try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -3644,7 +3830,7 @@ void __stdcall glHint(GLenum target, GLenum mode) return error(GL_INVALID_ENUM); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); switch (target) { case GL_GENERATE_MIPMAP_HINT: @@ -3669,7 +3855,7 @@ GLboolean __stdcall glIsBuffer(GLuint buffer) try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context && buffer) { @@ -3695,7 +3881,7 @@ GLboolean __stdcall glIsEnabled(GLenum cap) try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -3729,7 +3915,7 @@ GLboolean __stdcall glIsFenceNV(GLuint fence) try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -3757,7 +3943,7 @@ GLboolean __stdcall glIsFramebuffer(GLuint framebuffer) try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context && framebuffer) { @@ -3783,7 +3969,7 @@ GLboolean __stdcall glIsProgram(GLuint program) try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context && program) { @@ -3809,7 +3995,7 @@ GLboolean __stdcall glIsRenderbuffer(GLuint renderbuffer) try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context && renderbuffer) { @@ -3835,7 +4021,7 @@ GLboolean __stdcall glIsShader(GLuint shader) try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context && shader) { @@ -3861,7 +4047,7 @@ GLboolean __stdcall glIsTexture(GLuint texture) try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context && texture) { @@ -3892,7 +4078,7 @@ void __stdcall glLineWidth(GLfloat width) return error(GL_INVALID_VALUE); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -3911,7 +4097,7 @@ void __stdcall glLinkProgram(GLuint program) try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -3944,7 +4130,7 @@ void __stdcall glPixelStorei(GLenum pname, GLint param) try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -3985,7 +4171,7 @@ void __stdcall glPolygonOffset(GLfloat factor, GLfloat units) try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -3998,7 +4184,41 @@ void __stdcall glPolygonOffset(GLfloat factor, GLfloat units) } } -void __stdcall glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid* pixels) +void __stdcall glReadnPixelsEXT(GLint x, GLint y, GLsizei width, GLsizei height, + GLenum format, GLenum type, GLsizei bufSize, + GLvoid *data) +{ + EVENT("(GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d, " + "GLenum format = 0x%X, GLenum type = 0x%X, GLsizei bufSize = 0x%d, GLvoid *data = 0x%0.8p)", + x, y, width, height, format, type, bufSize, data); + + try + { + if (width < 0 || height < 0 || bufSize < 0) + { + return error(GL_INVALID_VALUE); + } + + if (!validReadFormatType(format, type)) + { + return error(GL_INVALID_OPERATION); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + context->readPixels(x, y, width, height, format, type, &bufSize, data); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, + GLenum format, GLenum type, GLvoid* pixels) { EVENT("(GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d, " "GLenum format = 0x%X, GLenum type = 0x%X, GLvoid* pixels = 0x%0.8p)", @@ -4011,46 +4231,16 @@ void __stdcall glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLe return error(GL_INVALID_VALUE); } - switch (format) + if (!validReadFormatType(format, type)) { - case GL_RGBA: - switch (type) - { - case GL_UNSIGNED_BYTE: - break; - default: - return error(GL_INVALID_OPERATION); - } - break; - case GL_BGRA_EXT: - switch (type) - { - case GL_UNSIGNED_BYTE: - case GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT: - case GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT: - break; - default: - return error(GL_INVALID_OPERATION); - } - break; - case gl::IMPLEMENTATION_COLOR_READ_FORMAT: - switch (type) - { - case gl::IMPLEMENTATION_COLOR_READ_TYPE: - break; - default: - return error(GL_INVALID_OPERATION); - } - break; - default: return error(GL_INVALID_OPERATION); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { - context->readPixels(x, y, width, height, format, type, pixels); + context->readPixels(x, y, width, height, format, type, NULL, pixels); } } catch(std::bad_alloc&) @@ -4098,7 +4288,7 @@ void __stdcall glRenderbufferStorageMultisampleANGLE(GLenum target, GLsizei samp return error(GL_INVALID_VALUE); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -4155,7 +4345,7 @@ void __stdcall glSampleCoverage(GLclampf value, GLboolean invert) try { - gl::Context* context = gl::getContext(); + gl::Context* context = gl::getNonLostContext(); if (context) { @@ -4179,7 +4369,7 @@ void __stdcall glSetFenceNV(GLuint fence, GLenum condition) return error(GL_INVALID_ENUM); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -4210,7 +4400,7 @@ void __stdcall glScissor(GLint x, GLint y, GLsizei width, GLsizei height) return error(GL_INVALID_VALUE); } - gl::Context* context = gl::getContext(); + gl::Context* context = gl::getNonLostContext(); if (context) { @@ -4252,7 +4442,7 @@ void __stdcall glShaderSource(GLuint shader, GLsizei count, const GLchar** strin return error(GL_INVALID_VALUE); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -4315,7 +4505,7 @@ void __stdcall glStencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint return error(GL_INVALID_ENUM); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -4357,7 +4547,7 @@ void __stdcall glStencilMaskSeparate(GLenum face, GLuint mask) return error(GL_INVALID_ENUM); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -4445,7 +4635,7 @@ void __stdcall glStencilOpSeparate(GLenum face, GLenum fail, GLenum zfail, GLenu return error(GL_INVALID_ENUM); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -4472,7 +4662,7 @@ GLboolean __stdcall glTestFenceNV(GLuint fence) try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -4576,10 +4766,15 @@ void __stdcall glTexImage2D(GLenum target, GLint level, GLint internalformat, GL return error(GL_INVALID_VALUE); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { + if (level > context->getMaximumTextureLevel()) + { + return error(GL_INVALID_VALUE); + } + switch (target) { case GL_TEXTURE_2D: @@ -4648,14 +4843,14 @@ void __stdcall glTexImage2D(GLenum target, GLint level, GLint internalformat, GL if (type == GL_FLOAT) { - if (!context->supportsFloatTextures()) + if (!context->supportsFloat32Textures()) { return error(GL_INVALID_ENUM); } } else if (type == GL_HALF_FLOAT_OES) { - if (!context->supportsHalfFloatTextures()) + if (!context->supportsFloat16Textures()) { return error(GL_INVALID_ENUM); } @@ -4670,6 +4865,11 @@ void __stdcall glTexImage2D(GLenum target, GLint level, GLint internalformat, GL return error(GL_INVALID_OPERATION); } + if (texture->isImmutable()) + { + return error(GL_INVALID_OPERATION); + } + texture->setImage(level, width, height, format, type, context->getUnpackAlignment(), pixels); } else @@ -4681,6 +4881,11 @@ void __stdcall glTexImage2D(GLenum target, GLint level, GLint internalformat, GL return error(GL_INVALID_OPERATION); } + if (texture->isImmutable()) + { + return error(GL_INVALID_OPERATION); + } + switch (target) { case GL_TEXTURE_CUBE_MAP_POSITIVE_X: @@ -4728,7 +4933,7 @@ void __stdcall glTexParameteri(GLenum target, GLenum pname, GLint param) try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -4772,6 +4977,12 @@ void __stdcall glTexParameteri(GLenum target, GLenum pname, GLint param) return error(GL_INVALID_ENUM); } break; + case GL_TEXTURE_USAGE_ANGLE: + if (!texture->setUsage((GLenum)param)) + { + return error(GL_INVALID_ENUM); + } + break; default: return error(GL_INVALID_ENUM); } @@ -4788,6 +4999,137 @@ void __stdcall glTexParameteriv(GLenum target, GLenum pname, const GLint* params glTexParameteri(target, pname, *params); } +void __stdcall glTexStorage2DEXT(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height) +{ + EVENT("(GLenum target = 0x%X, GLsizei levels = %d, GLenum internalformat = 0x%X, GLsizei width = %d, GLsizei height = %d)", + target, levels, internalformat, width, height); + + try + { + if (target != GL_TEXTURE_2D && target != GL_TEXTURE_CUBE_MAP) + { + return error(GL_INVALID_ENUM); + } + + if (width < 1 || height < 1 || levels < 1) + { + return error(GL_INVALID_VALUE); + } + + if (target == GL_TEXTURE_CUBE_MAP && width != height) + { + return error(GL_INVALID_VALUE); + } + + if (levels != 1 && levels != gl::log2(std::max(width, height)) + 1) + { + return error(GL_INVALID_OPERATION); + } + + GLenum format = gl::ExtractFormat(internalformat); + GLenum type = gl::ExtractType(internalformat); + + if (format == GL_NONE || type == GL_NONE) + { + return error(GL_INVALID_ENUM); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (levels != 1 && !context->supportsNonPower2Texture()) + { + if (!gl::isPow2(width) || !gl::isPow2(height)) + { + return error(GL_INVALID_OPERATION); + } + } + + switch (internalformat) + { + case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: + if (!context->supportsDXT1Textures()) + { + return error(GL_INVALID_ENUM); + } + break; + case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: + if (!context->supportsDXT3Textures()) + { + return error(GL_INVALID_ENUM); + } + break; + case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: + if (!context->supportsDXT5Textures()) + { + return error(GL_INVALID_ENUM); + } + break; + case GL_RGBA32F_EXT: + case GL_RGB32F_EXT: + case GL_ALPHA32F_EXT: + case GL_LUMINANCE32F_EXT: + case GL_LUMINANCE_ALPHA32F_EXT: + if (!context->supportsFloat32Textures()) + { + return error(GL_INVALID_ENUM); + } + break; + case GL_RGBA16F_EXT: + case GL_RGB16F_EXT: + case GL_ALPHA16F_EXT: + case GL_LUMINANCE16F_EXT: + case GL_LUMINANCE_ALPHA16F_EXT: + if (!context->supportsFloat16Textures()) + { + return error(GL_INVALID_ENUM); + } + break; + } + + if (target == GL_TEXTURE_2D) + { + gl::Texture2D *texture = context->getTexture2D(); + + if (!texture || texture->id() == 0) + { + return error(GL_INVALID_OPERATION); + } + + if (texture->isImmutable()) + { + return error(GL_INVALID_OPERATION); + } + + texture->storage(levels, internalformat, width, height); + } + else if (target == GL_TEXTURE_CUBE_MAP) + { + gl::TextureCubeMap *texture = context->getTextureCubeMap(); + + if (!texture || texture->id() == 0) + { + return error(GL_INVALID_OPERATION); + } + + if (texture->isImmutable()) + { + return error(GL_INVALID_OPERATION); + } + + texture->storage(levels, internalformat, width); + } + else UNREACHABLE(); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + void __stdcall glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid* pixels) { @@ -4823,7 +5165,7 @@ void __stdcall glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint return; } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -4834,14 +5176,14 @@ void __stdcall glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint if (format == GL_FLOAT) { - if (!context->supportsFloatTextures()) + if (!context->supportsFloat32Textures()) { return error(GL_INVALID_ENUM); } } else if (format == GL_HALF_FLOAT_OES) { - if (!context->supportsHalfFloatTextures()) + if (!context->supportsFloat16Textures()) { return error(GL_INVALID_ENUM); } @@ -4912,7 +5254,7 @@ void __stdcall glUniform1fv(GLint location, GLsizei count, const GLfloat* v) return; } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -4956,7 +5298,7 @@ void __stdcall glUniform1iv(GLint location, GLsizei count, const GLint* v) return; } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -5002,7 +5344,7 @@ void __stdcall glUniform2fv(GLint location, GLsizei count, const GLfloat* v) return; } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -5048,7 +5390,7 @@ void __stdcall glUniform2iv(GLint location, GLsizei count, const GLint* v) return; } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -5094,7 +5436,7 @@ void __stdcall glUniform3fv(GLint location, GLsizei count, const GLfloat* v) return; } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -5140,7 +5482,7 @@ void __stdcall glUniform3iv(GLint location, GLsizei count, const GLint* v) return; } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -5186,7 +5528,7 @@ void __stdcall glUniform4fv(GLint location, GLsizei count, const GLfloat* v) return; } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -5232,7 +5574,7 @@ void __stdcall glUniform4iv(GLint location, GLsizei count, const GLint* v) return; } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -5272,7 +5614,7 @@ void __stdcall glUniformMatrix2fv(GLint location, GLsizei count, GLboolean trans return; } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -5312,7 +5654,7 @@ void __stdcall glUniformMatrix3fv(GLint location, GLsizei count, GLboolean trans return; } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -5352,7 +5694,7 @@ void __stdcall glUniformMatrix4fv(GLint location, GLsizei count, GLboolean trans return; } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -5381,7 +5723,7 @@ void __stdcall glUseProgram(GLuint program) try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -5419,7 +5761,7 @@ void __stdcall glValidateProgram(GLuint program) try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -5457,7 +5799,7 @@ void __stdcall glVertexAttrib1f(GLuint index, GLfloat x) return error(GL_INVALID_VALUE); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -5482,7 +5824,7 @@ void __stdcall glVertexAttrib1fv(GLuint index, const GLfloat* values) return error(GL_INVALID_VALUE); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -5507,7 +5849,7 @@ void __stdcall glVertexAttrib2f(GLuint index, GLfloat x, GLfloat y) return error(GL_INVALID_VALUE); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -5532,7 +5874,7 @@ void __stdcall glVertexAttrib2fv(GLuint index, const GLfloat* values) return error(GL_INVALID_VALUE); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -5557,7 +5899,7 @@ void __stdcall glVertexAttrib3f(GLuint index, GLfloat x, GLfloat y, GLfloat z) return error(GL_INVALID_VALUE); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -5582,7 +5924,7 @@ void __stdcall glVertexAttrib3fv(GLuint index, const GLfloat* values) return error(GL_INVALID_VALUE); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -5607,7 +5949,7 @@ void __stdcall glVertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z, G return error(GL_INVALID_VALUE); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -5632,7 +5974,7 @@ void __stdcall glVertexAttrib4fv(GLuint index, const GLfloat* values) return error(GL_INVALID_VALUE); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -5681,7 +6023,7 @@ void __stdcall glVertexAttribPointer(GLuint index, GLint size, GLenum type, GLbo return error(GL_INVALID_VALUE); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -5705,7 +6047,7 @@ void __stdcall glViewport(GLint x, GLint y, GLsizei width, GLsizei height) return error(GL_INVALID_VALUE); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -5747,7 +6089,7 @@ void __stdcall glBlitFramebufferANGLE(GLint srcX0, GLint srcY0, GLint srcX1, GLi return error(GL_INVALID_OPERATION); } - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { @@ -5805,6 +6147,11 @@ __eglMustCastToProperFunctionPointerType __stdcall glGetProcAddress(const char * {"glFinishFenceNV", (__eglMustCastToProperFunctionPointerType)glFinishFenceNV}, {"glSetFenceNV", (__eglMustCastToProperFunctionPointerType)glSetFenceNV}, {"glGetTranslatedShaderSourceANGLE", (__eglMustCastToProperFunctionPointerType)glGetTranslatedShaderSourceANGLE}, + {"glTexStorage2DEXT", (__eglMustCastToProperFunctionPointerType)glTexStorage2DEXT}, + {"glGetGraphicsResetStatusEXT", (__eglMustCastToProperFunctionPointerType)glGetGraphicsResetStatusEXT}, + {"glReadnPixelsEXT", (__eglMustCastToProperFunctionPointerType)glReadnPixelsEXT}, + {"glGetnUniformfvEXT", (__eglMustCastToProperFunctionPointerType)glGetnUniformfvEXT}, + {"glGetnUniformivEXT", (__eglMustCastToProperFunctionPointerType)glGetnUniformivEXT}, }; for (int ext = 0; ext < sizeof(glExtensions) / sizeof(Extension); ext++) @@ -5818,19 +6165,26 @@ __eglMustCastToProperFunctionPointerType __stdcall glGetProcAddress(const char * return NULL; } -void __stdcall glBindTexImage(egl::Surface *surface) +// Non-public functions used by EGL + +bool __stdcall glBindTexImage(egl::Surface *surface) { EVENT("(egl::Surface* surface = 0x%0.8p)", surface); try { - gl::Context *context = gl::getContext(); + gl::Context *context = gl::getNonLostContext(); if (context) { gl::Texture2D *textureObject = context->getTexture2D(); + if (textureObject->isImmutable()) + { + return false; + } + if (textureObject) { textureObject->bindTexImage(surface); @@ -5839,8 +6193,10 @@ void __stdcall glBindTexImage(egl::Surface *surface) } catch(std::bad_alloc&) { - return error(GL_OUT_OF_MEMORY); + return error(GL_OUT_OF_MEMORY, false); } + + return true; } } diff --git a/gfx/angle/src/libGLESv2/libGLESv2.def b/gfx/angle/src/libGLESv2/libGLESv2.def index 4793f75fbb14..2173f74fbd5f 100644 --- a/gfx/angle/src/libGLESv2/libGLESv2.def +++ b/gfx/angle/src/libGLESv2/libGLESv2.def @@ -155,6 +155,11 @@ EXPORTS glSetFenceNV @156 glTestFenceNV @157 glGetTranslatedShaderSourceANGLE @159 + glTexStorage2DEXT @160 + glGetGraphicsResetStatusEXT @161 + glReadnPixelsEXT @162 + glGetnUniformfvEXT @163 + glGetnUniformivEXT @164 ; EGL dependencies glCreateContext @144 NONAME diff --git a/gfx/angle/src/libGLESv2/main.cpp b/gfx/angle/src/libGLESv2/main.cpp index ad1156309c40..affab7a62a5d 100644 --- a/gfx/angle/src/libGLESv2/main.cpp +++ b/gfx/angle/src/libGLESv2/main.cpp @@ -7,6 +7,7 @@ // main.cpp: DLL entry point and management of thread-local data. #include "libGLESv2/main.h" +#include "libGLESv2/utilities.h" #include "common/debug.h" #include "libEGL/Surface.h" @@ -93,6 +94,16 @@ Context *getContext() return current->context; } +Context *getNonLostContext() +{ + Context *context = getContext(); + + if (context && !context->isContextLost()) + return context; + + return NULL; +} + egl::Display *getDisplay() { Current *current = (Current*)TlsGetValue(currentTLS); @@ -106,6 +117,19 @@ IDirect3DDevice9 *getDevice() return display->getDevice(); } + +bool checkDeviceLost(HRESULT errorCode) +{ + egl::Display *display = NULL; + + if (isDeviceLostError(errorCode)) + { + display = gl::getDisplay(); + display->notifyDeviceLost(); + return true; + } + return false; +} } // Records an error code diff --git a/gfx/angle/src/libGLESv2/main.h b/gfx/angle/src/libGLESv2/main.h index 7f9c8807b80c..504848aa6587 100644 --- a/gfx/angle/src/libGLESv2/main.h +++ b/gfx/angle/src/libGLESv2/main.h @@ -29,9 +29,12 @@ struct Current void makeCurrent(Context *context, egl::Display *display, egl::Surface *surface); Context *getContext(); +Context *getNonLostContext(); egl::Display *getDisplay(); IDirect3DDevice9 *getDevice(); + +bool checkDeviceLost(HRESULT errorCode); } void error(GLenum errorCode); diff --git a/gfx/angle/src/libGLESv2/utilities.cpp b/gfx/angle/src/libGLESv2/utilities.cpp index 3dba89987d32..6dc419c7ad50 100644 --- a/gfx/angle/src/libGLESv2/utilities.cpp +++ b/gfx/angle/src/libGLESv2/utilities.cpp @@ -20,7 +20,8 @@ namespace gl { -int UniformComponentCount(GLenum type) +// This is how much data the application expects for a uniform +int UniformExternalComponentCount(GLenum type) { switch (type) { @@ -125,7 +126,7 @@ size_t UniformComponentSize(GLenum type) { switch(type) { - case GL_BOOL: return sizeof(GLboolean); + case GL_BOOL: return sizeof(GLint); case GL_FLOAT: return sizeof(GLfloat); case GL_INT: return sizeof(GLint); default: UNREACHABLE(); @@ -134,11 +135,16 @@ size_t UniformComponentSize(GLenum type) return 0; } -size_t UniformTypeSize(GLenum type) +size_t UniformInternalSize(GLenum type) { return UniformComponentSize(UniformComponentType(type)) * UniformInternalComponentCount(type); } +size_t UniformExternalSize(GLenum type) +{ + return UniformComponentSize(UniformComponentType(type)) * UniformExternalComponentCount(type); +} + int VariableRowCount(GLenum type) { switch (type) @@ -374,6 +380,68 @@ bool CheckTextureFormatType(GLenum format, GLenum type) } } +GLenum ExtractFormat(GLenum internalformat) +{ + switch (internalformat) + { + case GL_RGB565: return GL_RGB; + case GL_RGBA4: return GL_RGBA; + case GL_RGB5_A1: return GL_RGBA; + case GL_RGB8_OES: return GL_RGB; + case GL_RGBA8_OES: return GL_RGBA; + case GL_LUMINANCE8_ALPHA8_EXT: return GL_LUMINANCE_ALPHA; + case GL_LUMINANCE8_EXT: return GL_LUMINANCE; + case GL_ALPHA8_EXT: return GL_ALPHA; + case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: return GL_COMPRESSED_RGB_S3TC_DXT1_EXT; + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: return GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; + case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: return GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE; + case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: return GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE; + case GL_RGBA32F_EXT: return GL_RGBA; + case GL_RGB32F_EXT: return GL_RGB; + case GL_ALPHA32F_EXT: return GL_ALPHA; + case GL_LUMINANCE32F_EXT: return GL_LUMINANCE; + case GL_LUMINANCE_ALPHA32F_EXT: return GL_LUMINANCE_ALPHA; + case GL_RGBA16F_EXT: return GL_RGBA; + case GL_RGB16F_EXT: return GL_RGB; + case GL_ALPHA16F_EXT: return GL_ALPHA; + case GL_LUMINANCE16F_EXT: return GL_LUMINANCE; + case GL_LUMINANCE_ALPHA16F_EXT: return GL_LUMINANCE_ALPHA; + case GL_BGRA8_EXT: return GL_BGRA_EXT; + default: return GL_NONE; // Unsupported + } +} + +GLenum ExtractType(GLenum internalformat) +{ + switch (internalformat) + { + case GL_RGB565: return GL_UNSIGNED_SHORT_5_6_5; + case GL_RGBA4: return GL_UNSIGNED_SHORT_4_4_4_4; + case GL_RGB5_A1: return GL_UNSIGNED_SHORT_5_5_5_1; + case GL_RGB8_OES: return GL_UNSIGNED_BYTE; + case GL_RGBA8_OES: return GL_UNSIGNED_BYTE; + case GL_LUMINANCE8_ALPHA8_EXT: return GL_UNSIGNED_BYTE; + case GL_LUMINANCE8_EXT: return GL_UNSIGNED_BYTE; + case GL_ALPHA8_EXT: return GL_UNSIGNED_BYTE; + case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: return GL_UNSIGNED_BYTE; + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: return GL_UNSIGNED_BYTE; + case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: return GL_UNSIGNED_BYTE; + case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: return GL_UNSIGNED_BYTE; + case GL_RGBA32F_EXT: return GL_FLOAT; + case GL_RGB32F_EXT: return GL_FLOAT; + case GL_ALPHA32F_EXT: return GL_FLOAT; + case GL_LUMINANCE32F_EXT: return GL_FLOAT; + case GL_LUMINANCE_ALPHA32F_EXT: return GL_FLOAT; + case GL_RGBA16F_EXT: return GL_HALF_FLOAT_OES; + case GL_RGB16F_EXT: return GL_HALF_FLOAT_OES; + case GL_ALPHA16F_EXT: return GL_HALF_FLOAT_OES; + case GL_LUMINANCE16F_EXT: return GL_HALF_FLOAT_OES; + case GL_LUMINANCE_ALPHA16F_EXT: return GL_HALF_FLOAT_OES; + case GL_BGRA8_EXT: return GL_UNSIGNED_BYTE; + default: return GL_NONE; // Unsupported + } +} + bool IsColorRenderable(GLenum internalformat) { switch (internalformat) @@ -853,6 +921,50 @@ unsigned int GetDepthSize(D3DFORMAT depthFormat) } } +bool IsFloat32Format(D3DFORMAT surfaceFormat) +{ + switch(surfaceFormat) + { + case D3DFMT_R16F: + case D3DFMT_G16R16F: + case D3DFMT_A16B16G16R16F: + return false; + case D3DFMT_R32F: + case D3DFMT_G32R32F: + case D3DFMT_A32B32G32R32F: + return true; + case D3DFMT_A8R8G8B8: + case D3DFMT_X8R8G8B8: + case D3DFMT_A1R5G5B5: + case D3DFMT_R5G6B5: + return false; + default: UNREACHABLE(); + } + return false; +} + +bool IsFloat16Format(D3DFORMAT surfaceFormat) +{ + switch(surfaceFormat) + { + case D3DFMT_R16F: + case D3DFMT_G16R16F: + case D3DFMT_A16B16G16R16F: + return true; + case D3DFMT_R32F: + case D3DFMT_G32R32F: + case D3DFMT_A32B32G32R32F: + return false; + case D3DFMT_A8R8G8B8: + case D3DFMT_X8R8G8B8: + case D3DFMT_A1R5G5B5: + case D3DFMT_R5G6B5: + return false; + default: UNREACHABLE(); + } + return false; +} + GLsizei GetSamplesFromMultisampleType(D3DMULTISAMPLE_TYPE type) { if (type == D3DMULTISAMPLE_NONMASKABLE) diff --git a/gfx/angle/src/libGLESv2/utilities.h b/gfx/angle/src/libGLESv2/utilities.h index f6b964c45565..735fa503de36 100644 --- a/gfx/angle/src/libGLESv2/utilities.h +++ b/gfx/angle/src/libGLESv2/utilities.h @@ -21,10 +21,11 @@ namespace gl struct Color; -int UniformComponentCount(GLenum type); +int UniformExternalComponentCount(GLenum type); int UniformInternalComponentCount(GLenum type); GLenum UniformComponentType(GLenum type); -size_t UniformTypeSize(GLenum type); +size_t UniformInternalSize(GLenum type); +size_t UniformExternalSize(GLenum type); int VariableRowCount(GLenum type); int VariableColumnCount(GLenum type); @@ -38,6 +39,8 @@ bool IsCompressed(GLenum format); bool IsCubemapTextureTarget(GLenum target); bool IsTextureTarget(GLenum target); bool CheckTextureFormatType(GLenum format, GLenum type); +GLenum ExtractFormat(GLenum internalformat); +GLenum ExtractType(GLenum internalformat); bool IsColorRenderable(GLenum internalformat); bool IsDepthRenderable(GLenum internalformat); @@ -74,6 +77,8 @@ GLuint GetGreenSize(D3DFORMAT colorFormat); GLuint GetBlueSize(D3DFORMAT colorFormat); GLuint GetDepthSize(D3DFORMAT depthFormat); GLuint GetStencilSize(D3DFORMAT stencilFormat); +bool IsFloat32Format(D3DFORMAT surfaceFormat); +bool IsFloat16Format(D3DFORMAT surfaceFormat); GLsizei GetSamplesFromMultisampleType(D3DMULTISAMPLE_TYPE type); @@ -85,4 +90,18 @@ GLenum ConvertDepthStencilFormat(D3DFORMAT format); std::string getTempPath(); void writeFile(const char* path, const void* data, size_t size); +inline bool isDeviceLostError(HRESULT errorCode) +{ + switch (errorCode) + { + case D3DERR_DRIVERINTERNALERROR: + case D3DERR_DEVICELOST: + case D3DERR_DEVICEHUNG: + case D3DERR_DEVICEREMOVED: + return true; + default: + return false; + } +}; + #endif // LIBGLESV2_UTILITIES_H From cf5d2ca6fee0d93cd22ddaac6076bcd7ade4838a Mon Sep 17 00:00:00 2001 From: Oleg Romashin Date: Sun, 20 Nov 2011 02:31:56 +0000 Subject: [PATCH 53/63] Bug 703382 maemo fast startup resources not found after directory path change. r=mfinkle --- mobile/xul/app/Makefile.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mobile/xul/app/Makefile.in b/mobile/xul/app/Makefile.in index f7ab6448f264..46d8b1ad0677 100644 --- a/mobile/xul/app/Makefile.in +++ b/mobile/xul/app/Makefile.in @@ -188,7 +188,7 @@ endif # SKIP_COPY_XULRUNNER ifeq ($(MOZ_PLATFORM_MAEMO),6) $(NSINSTALL) -D $(DIST)/bin/res/drawable - cp $(topsrcdir)/mobile/app/maemo/* $(DIST)/bin/res/drawable/ + cp $(srcdir)/maemo/* $(DIST)/bin/res/drawable/ cp $(topsrcdir)/$(MOZ_BRANDING_DIRECTORY)/content/favicon32.png $(DIST)/bin/res/drawable/ endif $(NSINSTALL) -D $(DIST)/bin/chrome/icons/default From 2a71dac724dc6fe861110f74c2426a0e3813a167 Mon Sep 17 00:00:00 2001 From: Benoit Girard Date: Sun, 20 Nov 2011 02:31:56 +0000 Subject: [PATCH 54/63] Bug 703449 - Add 'browser.dom.window.dump.enabled' pref to profiles; r=bz --- modules/libpref/src/init/all.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/modules/libpref/src/init/all.js b/modules/libpref/src/init/all.js index 0461c700b0eb..89025986aa46 100644 --- a/modules/libpref/src/init/all.js +++ b/modules/libpref/src/init/all.js @@ -3366,3 +3366,6 @@ pref("layout.3d-transforms.enabled", true); // Battery API pref("dom.battery.enabled", true); + +// enable JS dump() function. +pref("browser.dom.window.dump.enabled", false); From c4c355f05e7d66293e72507d00f0533af9fe2399 Mon Sep 17 00:00:00 2001 From: Brad Lassey Date: Sat, 19 Nov 2011 23:08:27 -0500 Subject: [PATCH 55/63] bug 703815 - Click to activate message is displayed even if plugins are disabled r=dougt --- content/base/src/nsObjectLoadingContent.cpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/content/base/src/nsObjectLoadingContent.cpp b/content/base/src/nsObjectLoadingContent.cpp index a6968acffb65..ac8ce4086556 100644 --- a/content/base/src/nsObjectLoadingContent.cpp +++ b/content/base/src/nsObjectLoadingContent.cpp @@ -107,6 +107,7 @@ static PRLogModuleInfo* gObjectLog = PR_NewLogModule("objlc"); #ifdef ANDROID #include "nsXULAppAPI.h" +#include "mozilla/Preferences.h" #endif class nsAsyncInstantiateEvent : public nsRunnable { @@ -1066,11 +1067,7 @@ nsObjectLoadingContent::ObjectState() const case eType_Image: return ImageState(); case eType_Plugin: -#ifdef ANDROID - if (XRE_GetProcessType() == GeckoProcessType_Content) - return NS_EVENT_STATE_TYPE_CLICK_TO_PLAY; -#endif - case eType_Document: + case eType_Document: // These are OK. If documents start to load successfully, they display // something, and are thus not broken in this sense. The same goes for // plugins. @@ -1966,8 +1963,10 @@ nsObjectLoadingContent::GetPluginSupportState(nsIContent* aContent, nsObjectLoadingContent::GetPluginDisabledState(const nsCString& aContentType) { #ifdef ANDROID - if (XRE_GetProcessType() == GeckoProcessType_Content) - return ePluginClickToPlay; + // if plugins are disabled, don't show the click to play message + if (!mozilla::Preferences::GetBool("plugin.disable", false) && + XRE_GetProcessType() == GeckoProcessType_Content) + return ePluginClickToPlay; #endif nsCOMPtr pluginHostCOM(do_GetService(MOZ_PLUGIN_HOST_CONTRACTID)); nsPluginHost *pluginHost = static_cast(pluginHostCOM.get()); From 7eb2828513f960de07402662d24113ae74ac44a8 Mon Sep 17 00:00:00 2001 From: "julian.reschke@gmx.de" Date: Sun, 20 Nov 2011 11:13:40 +0000 Subject: [PATCH 56/63] Bug 703015 - Revert change for bug 651185 - allow double-quotes for RFC 2231/5987 encoding again; r=bz --- netwerk/mime/nsMIMEHeaderParamImpl.cpp | 2 +- netwerk/test/unit/test_MIME_params.js | 9 +++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/netwerk/mime/nsMIMEHeaderParamImpl.cpp b/netwerk/mime/nsMIMEHeaderParamImpl.cpp index 527bf823e5db..ed595df17a1e 100644 --- a/netwerk/mime/nsMIMEHeaderParamImpl.cpp +++ b/netwerk/mime/nsMIMEHeaderParamImpl.cpp @@ -354,7 +354,7 @@ nsMIMEHeaderParamImpl::DoParameterInternal(const char *aHeaderValue, // CaseB and start of CaseC: requires charset and optional language // in quotes (quotes required even if lang is blank) - if (!needUnquote && (caseB || (caseCorDStart && acceptContinuations))) + if (caseB || (caseCorDStart && acceptContinuations)) { if (caseCorDStart) { if (nextContinuation++ != 0) diff --git a/netwerk/test/unit/test_MIME_params.js b/netwerk/test/unit/test_MIME_params.js index f4bea599aa5c..fa547b029130 100644 --- a/netwerk/test/unit/test_MIME_params.js +++ b/netwerk/test/unit/test_MIME_params.js @@ -224,14 +224,19 @@ var tests = [ "attachment", ""], // Bug 651185: double quotes around 2231/5987 encoded param - + // Change reverted to backwards compat issues with various web services, + // such as OWA (Bug 703015), plus similar problems in Thunderbird. If this + // is tried again in the future, email probably needs to be special-cased. + // sanity check ["attachment; filename*=utf-8''%41", "attachment", "A"], // the actual bug ["attachment; filename*=" + DQUOTE + "utf-8''%41" + DQUOTE, - "attachment", Cr.NS_ERROR_INVALID_ARG], + "attachment", "A"], + // previously with the fix for 651185: + // "attachment", Cr.NS_ERROR_INVALID_ARG], // Bug 670333: Content-Disposition parser does not require presence of "=" // in params From d2a6b6d8eb794e6a6a173a6d740f51e0349c7f8f Mon Sep 17 00:00:00 2001 From: Atul Aggarwal Date: Sun, 20 Nov 2011 11:13:40 +0000 Subject: [PATCH 57/63] Bug 691113 - Improving error thrown when ; is missing from interface definition; r=khuey --- xpcom/idl-parser/xpidl.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/xpcom/idl-parser/xpidl.py b/xpcom/idl-parser/xpidl.py index f25ceb4b1d76..98f9de457442 100644 --- a/xpcom/idl-parser/xpidl.py +++ b/xpcom/idl-parser/xpidl.py @@ -1442,8 +1442,11 @@ class IDLParser(object): p[0].insert(0, p[1]) def p_error(self, t): - location = Location(self.lexer, t.lineno, t.lexpos) - raise IDLError("invalid syntax", location) + if not t: + raise IDLError("Syntax Error at end of file. Possibly due to missing semicolon(;), braces(}) or both", None) + else: + location = Location(self.lexer, t.lineno, t.lexpos) + raise IDLError("invalid syntax", location) def __init__(self, outputdir=''): self._doccomments = [] From b4f153aee884dcaafbd84496f7416c175bf976cf Mon Sep 17 00:00:00 2001 From: Rafael Avila de Espindola Date: Sun, 20 Nov 2011 11:13:40 +0000 Subject: [PATCH 58/63] Bug 696404 - Finalize statements in profile-before-change; r=mak --- .../components/satchel/nsFormAutoComplete.js | 11 +++++---- toolkit/components/satchel/nsFormHistory.js | 24 +++++++++++++++---- 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/toolkit/components/satchel/nsFormAutoComplete.js b/toolkit/components/satchel/nsFormAutoComplete.js index 4cfe0a2af8b2..524eacd7977b 100644 --- a/toolkit/components/satchel/nsFormAutoComplete.js +++ b/toolkit/components/satchel/nsFormAutoComplete.js @@ -84,9 +84,9 @@ FormAutoComplete.prototype = { this._timeGroupingSize = this._prefBranch.getIntPref("timeGroupingSize") * 1000 * 1000; this._expireDays = this._prefBranch.getIntPref("expire_days"); - this._dbStmts = []; + this._dbStmts = {}; - Services.obs.addObserver(this.observer, "xpcom-shutdown", true); + Services.obs.addObserver(this.observer, "profile-before-change", true); }, observer : { @@ -129,8 +129,11 @@ FormAutoComplete.prototype = { default: self.log("Oops! Pref not handled, change ignored."); } - } else if (topic == "xpcom-shutdown") { - self._dbStmts = null; + } else if (topic == "profile-before-change") { + for each (let stmt in self._dbStmts) { + stmt.finalize(); + } + self._dbStmts = {}; self.__formHistory = null; } } diff --git a/toolkit/components/satchel/nsFormHistory.js b/toolkit/components/satchel/nsFormHistory.js index 540393a3146d..f95c16a64b04 100644 --- a/toolkit/components/satchel/nsFormHistory.js +++ b/toolkit/components/satchel/nsFormHistory.js @@ -137,6 +137,7 @@ FormHistory.prototype = { this.messageManager.addMessageListener("FormHistory:FormSubmitEntries", this); // Add observers + Services.obs.addObserver(this, "profile-before-change", true); Services.obs.addObserver(this, "idle-daily", true); Services.obs.addObserver(this, "formhistory-expire-now", true); }, @@ -402,6 +403,9 @@ FormHistory.prototype = { case "formhistory-expire-now": this.expireOldEntries(); break; + case "profile-before-change": + this._dbFinalize(); + break; default: this.log("Oops! Unexpected notification: " + topic); break; @@ -862,6 +866,18 @@ FormHistory.prototype = { } }, + /** + * _dbFinalize + * + * Finalize all statements to allow closing the connection correctly. + */ + _dbFinalize : function FH__dbFinalize() { + // FIXME (bug 696486): close the connection in here. + for each (let stmt in this.dbStmts) { + stmt.finalize(); + } + this.dbStmts = {}; + }, /* * dbCleanup @@ -881,13 +897,11 @@ FormHistory.prototype = { storage.backupDatabaseFile(this.dbFile, backupFile); } - // Finalize all statements to free memory, avoid errors later - for each (let stmt in this.dbStmts) - stmt.finalize(); - this.dbStmts = []; + this._dbFinalize(); // Close the connection, ignore 'already closed' error - try { this.dbConnection.close() } catch(e) {} + // FIXME (bug 696483): we should reportError in here. + try { this.dbConnection.close(); } catch(e) {} this.dbFile.remove(false); } }; From 2aa0696362a781ad8e1744546759001ff5941edd Mon Sep 17 00:00:00 2001 From: Andrew Date: Sun, 20 Nov 2011 11:13:40 +0000 Subject: [PATCH 59/63] Bug 466626 - Make nsStyleLinkElement::ParseLinkTypes return a bitmask; r=roc --- content/base/src/nsContentSink.cpp | 14 ++++----- content/base/src/nsStyleLinkElement.cpp | 29 +++++++++++++++---- content/base/src/nsStyleLinkElement.h | 10 +++++-- .../html/content/src/nsHTMLLinkElement.cpp | 12 ++++---- .../html/document/src/nsHTMLContentSink.cpp | 10 +++---- content/xml/document/src/nsXMLContentSink.cpp | 10 +++---- parser/html/nsHtml5TreeOpExecutor.cpp | 10 +++---- 7 files changed, 54 insertions(+), 41 deletions(-) diff --git a/content/base/src/nsContentSink.cpp b/content/base/src/nsContentSink.cpp index 78e29e1afb7b..6ce3a9141910 100644 --- a/content/base/src/nsContentSink.cpp +++ b/content/base/src/nsContentSink.cpp @@ -819,9 +819,7 @@ nsContentSink::ProcessLink(nsIContent* aElement, const nsSubstring& aRel, const nsSubstring& aTitle, const nsSubstring& aType, const nsSubstring& aMedia) { - // XXX seems overkill to generate this string array - nsTArray linkTypes; - nsStyleLinkElement::ParseLinkTypes(aRel, linkTypes); + PRUint32 linkTypes = nsStyleLinkElement::ParseLinkTypes(aRel); // The link relation may apply to a different resource, specified // in the anchor parameter. For the link relations supported so far, @@ -831,22 +829,22 @@ nsContentSink::ProcessLink(nsIContent* aElement, return NS_OK; } - bool hasPrefetch = linkTypes.Contains(NS_LITERAL_STRING("prefetch")); + bool hasPrefetch = linkTypes & PREFETCH; // prefetch href if relation is "next" or "prefetch" - if (hasPrefetch || linkTypes.Contains(NS_LITERAL_STRING("next"))) { + if (hasPrefetch || (linkTypes & NEXT)) { PrefetchHref(aHref, aElement, hasPrefetch); } - if ((!aHref.IsEmpty()) && linkTypes.Contains(NS_LITERAL_STRING("dns-prefetch"))) { + if (!aHref.IsEmpty() && (linkTypes & DNS_PREFETCH)) { PrefetchDNS(aHref); } // is it a stylesheet link? - if (!linkTypes.Contains(NS_LITERAL_STRING("stylesheet"))) { + if (!(linkTypes & STYLESHEET)) { return NS_OK; } - bool isAlternate = linkTypes.Contains(NS_LITERAL_STRING("alternate")); + bool isAlternate = linkTypes & ALTERNATE; return ProcessStyleLink(aElement, aHref, isAlternate, aTitle, aType, aMedia); } diff --git a/content/base/src/nsStyleLinkElement.cpp b/content/base/src/nsStyleLinkElement.cpp index 512b5b04f289..5e9585647731 100644 --- a/content/base/src/nsStyleLinkElement.cpp +++ b/content/base/src/nsStyleLinkElement.cpp @@ -153,24 +153,40 @@ nsStyleLinkElement::SetLineNumber(PRUint32 aLineNumber) mLineNumber = aLineNumber; } -void nsStyleLinkElement::ParseLinkTypes(const nsAString& aTypes, - nsTArray& aResult) +PRUint32 ToLinkMask(const nsAString& aLink) +{ + if (aLink.EqualsLiteral("prefetch")) + return PREFETCH; + else if (aLink.EqualsLiteral("dns-prefetch")) + return DNS_PREFETCH; + else if (aLink.EqualsLiteral("stylesheet")) + return STYLESHEET; + else if (aLink.EqualsLiteral("next")) + return NEXT; + else if (aLink.EqualsLiteral("alternate")) + return ALTERNATE; + else + return 0; +} + +PRUint32 nsStyleLinkElement::ParseLinkTypes(const nsAString& aTypes) { + PRUint32 linkMask = 0; nsAString::const_iterator start, done; aTypes.BeginReading(start); aTypes.EndReading(done); if (start == done) - return; + return linkMask; nsAString::const_iterator current(start); bool inString = !nsCRT::IsAsciiSpace(*current); nsAutoString subString; - + while (current != done) { if (nsCRT::IsAsciiSpace(*current)) { if (inString) { ToLowerCase(Substring(start, current), subString); - aResult.AppendElement(subString); + linkMask |= ToLinkMask(subString); inString = false; } } @@ -184,8 +200,9 @@ void nsStyleLinkElement::ParseLinkTypes(const nsAString& aTypes, } if (inString) { ToLowerCase(Substring(start, current), subString); - aResult.AppendElement(subString); + linkMask |= ToLinkMask(subString); } + return linkMask; } NS_IMETHODIMP diff --git a/content/base/src/nsStyleLinkElement.h b/content/base/src/nsStyleLinkElement.h index 9158a630abc7..12a85adcd75a 100644 --- a/content/base/src/nsStyleLinkElement.h +++ b/content/base/src/nsStyleLinkElement.h @@ -53,6 +53,12 @@ #include "nsIURI.h" #include "nsTArray.h" +#define PREFETCH 0x00000001 +#define DNS_PREFETCH 0x00000002 +#define STYLESHEET 0x00000004 +#define NEXT 0x00000008 +#define ALTERNATE 0x00000010 + class nsIDocument; class nsStyleLinkElement : public nsIDOMLinkStyle, @@ -80,8 +86,8 @@ public: virtual void OverrideBaseURI(nsIURI* aNewBaseURI); virtual void SetLineNumber(PRUint32 aLineNumber); - static void ParseLinkTypes(const nsAString& aTypes, nsTArray& aResult); - + static PRUint32 ParseLinkTypes(const nsAString& aTypes); + void UpdateStyleSheetInternal() { UpdateStyleSheetInternal(nsnull); } protected: /** diff --git a/content/html/content/src/nsHTMLLinkElement.cpp b/content/html/content/src/nsHTMLLinkElement.cpp index f21ceb58a62b..9242339ec4e3 100644 --- a/content/html/content/src/nsHTMLLinkElement.cpp +++ b/content/html/content/src/nsHTMLLinkElement.cpp @@ -307,9 +307,8 @@ nsHTMLLinkElement::SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName, bool dropSheet = false; if (aNameSpaceID == kNameSpaceID_None && aName == nsGkAtoms::rel && GetStyleSheet()) { - nsAutoTArray linkTypes; - nsStyleLinkElement::ParseLinkTypes(aValue, linkTypes); - dropSheet = !linkTypes.Contains(NS_LITERAL_STRING("stylesheet")); + PRUint32 linkTypes = nsStyleLinkElement::ParseLinkTypes(aValue); + dropSheet = !(linkTypes & STYLESHEET); } UpdateStyleSheetInternal(nsnull, @@ -413,11 +412,10 @@ nsHTMLLinkElement::GetStyleSheetInfo(nsAString& aTitle, *aIsAlternate = false; nsAutoString rel; - nsAutoTArray linkTypes; GetAttr(kNameSpaceID_None, nsGkAtoms::rel, rel); - nsStyleLinkElement::ParseLinkTypes(rel, linkTypes); + PRUint32 linkTypes = nsStyleLinkElement::ParseLinkTypes(rel); // Is it a stylesheet link? - if (!linkTypes.Contains(NS_LITERAL_STRING("stylesheet"))) { + if (!(linkTypes & STYLESHEET)) { return; } @@ -427,7 +425,7 @@ nsHTMLLinkElement::GetStyleSheetInfo(nsAString& aTitle, aTitle.Assign(title); // If alternate, does it have title? - if (linkTypes.Contains(NS_LITERAL_STRING("alternate"))) { + if (linkTypes & ALTERNATE) { if (aTitle.IsEmpty()) { // alternates must have title return; } else { diff --git a/content/html/document/src/nsHTMLContentSink.cpp b/content/html/document/src/nsHTMLContentSink.cpp index 82788a7173ec..f95491dec9ae 100644 --- a/content/html/document/src/nsHTMLContentSink.cpp +++ b/content/html/document/src/nsHTMLContentSink.cpp @@ -2644,18 +2644,16 @@ HTMLContentSink::ProcessLINKTag(const nsIParserNode& aNode) nsAutoString relVal; element->GetAttr(kNameSpaceID_None, nsGkAtoms::rel, relVal); if (!relVal.IsEmpty()) { - // XXX seems overkill to generate this string array - nsAutoTArray linkTypes; - nsStyleLinkElement::ParseLinkTypes(relVal, linkTypes); - bool hasPrefetch = linkTypes.Contains(NS_LITERAL_STRING("prefetch")); - if (hasPrefetch || linkTypes.Contains(NS_LITERAL_STRING("next"))) { + PRUint32 linkTypes = nsStyleLinkElement::ParseLinkTypes(relVal); + bool hasPrefetch = linkTypes & PREFETCH; + if (hasPrefetch || (linkTypes & NEXT)) { nsAutoString hrefVal; element->GetAttr(kNameSpaceID_None, nsGkAtoms::href, hrefVal); if (!hrefVal.IsEmpty()) { PrefetchHref(hrefVal, element, hasPrefetch); } } - if (linkTypes.Contains(NS_LITERAL_STRING("dns-prefetch"))) { + if (linkTypes & DNS_PREFETCH) { nsAutoString hrefVal; element->GetAttr(kNameSpaceID_None, nsGkAtoms::href, hrefVal); if (!hrefVal.IsEmpty()) { diff --git a/content/xml/document/src/nsXMLContentSink.cpp b/content/xml/document/src/nsXMLContentSink.cpp index c5af9edc15e2..1aa97b4626e3 100644 --- a/content/xml/document/src/nsXMLContentSink.cpp +++ b/content/xml/document/src/nsXMLContentSink.cpp @@ -646,18 +646,16 @@ nsXMLContentSink::CloseElement(nsIContent* aContent) nsAutoString relVal; aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::rel, relVal); if (!relVal.IsEmpty()) { - // XXX seems overkill to generate this string array - nsAutoTArray linkTypes; - nsStyleLinkElement::ParseLinkTypes(relVal, linkTypes); - bool hasPrefetch = linkTypes.Contains(NS_LITERAL_STRING("prefetch")); - if (hasPrefetch || linkTypes.Contains(NS_LITERAL_STRING("next"))) { + PRUint32 linkTypes = nsStyleLinkElement::ParseLinkTypes(relVal); + bool hasPrefetch = linkTypes & PREFETCH; + if (hasPrefetch || (linkTypes & NEXT)) { nsAutoString hrefVal; aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::href, hrefVal); if (!hrefVal.IsEmpty()) { PrefetchHref(hrefVal, aContent, hasPrefetch); } } - if (linkTypes.Contains(NS_LITERAL_STRING("dns-prefetch"))) { + if (linkTypes & DNS_PREFETCH) { nsAutoString hrefVal; aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::href, hrefVal); if (!hrefVal.IsEmpty()) { diff --git a/parser/html/nsHtml5TreeOpExecutor.cpp b/parser/html/nsHtml5TreeOpExecutor.cpp index 3f3b3405b180..c46872f2aee6 100644 --- a/parser/html/nsHtml5TreeOpExecutor.cpp +++ b/parser/html/nsHtml5TreeOpExecutor.cpp @@ -345,18 +345,16 @@ nsHtml5TreeOpExecutor::UpdateStyleSheet(nsIContent* aElement) nsAutoString relVal; aElement->GetAttr(kNameSpaceID_None, nsGkAtoms::rel, relVal); if (!relVal.IsEmpty()) { - // XXX seems overkill to generate this string array - nsAutoTArray linkTypes; - nsStyleLinkElement::ParseLinkTypes(relVal, linkTypes); - bool hasPrefetch = linkTypes.Contains(NS_LITERAL_STRING("prefetch")); - if (hasPrefetch || linkTypes.Contains(NS_LITERAL_STRING("next"))) { + PRUint32 linkTypes = nsStyleLinkElement::ParseLinkTypes(relVal); + bool hasPrefetch = linkTypes & PREFETCH; + if (hasPrefetch || (linkTypes & NEXT)) { nsAutoString hrefVal; aElement->GetAttr(kNameSpaceID_None, nsGkAtoms::href, hrefVal); if (!hrefVal.IsEmpty()) { PrefetchHref(hrefVal, aElement, hasPrefetch); } } - if (linkTypes.Contains(NS_LITERAL_STRING("dns-prefetch"))) { + if (linkTypes & DNS_PREFETCH) { nsAutoString hrefVal; aElement->GetAttr(kNameSpaceID_None, nsGkAtoms::href, hrefVal); if (!hrefVal.IsEmpty()) { From 7d052329680c1b91b6501984203620d0074af624 Mon Sep 17 00:00:00 2001 From: Atul Aggarwal Date: Sun, 20 Nov 2011 11:18:26 +0000 Subject: [PATCH 60/63] Bug 701666 - Removing TxObject define and Double typedef from xslt. r=Ms2ger --- content/xslt/src/base/txCore.h | 6 ----- content/xslt/src/base/txDouble.cpp | 22 ++++++++--------- content/xslt/src/base/txList.h | 2 +- content/xslt/src/xml/txDOM.h | 2 +- content/xslt/src/xpath/txCoreFunctionCall.cpp | 24 +++++++++---------- content/xslt/src/xpath/txExprParser.cpp | 2 +- content/xslt/src/xpath/txLiteralExpr.cpp | 2 +- content/xslt/src/xpath/txNodeSet.cpp | 2 +- content/xslt/src/xpath/txNodeSetAdaptor.cpp | 2 +- content/xslt/src/xpath/txNumberExpr.cpp | 18 +++++++------- content/xslt/src/xpath/txNumberResult.cpp | 4 ++-- content/xslt/src/xpath/txStringResult.cpp | 2 +- content/xslt/src/xpath/txUnionNodeTest.cpp | 2 +- content/xslt/src/xslt/txEXSLTFunctions.cpp | 12 +++++----- .../src/xslt/txFormatNumberFunctionCall.cpp | 8 +++---- content/xslt/src/xslt/txInstructions.h | 2 +- content/xslt/src/xslt/txNodeSorter.cpp | 14 +++++------ content/xslt/src/xslt/txNodeSorter.h | 8 +++---- content/xslt/src/xslt/txRtfHandler.cpp | 2 +- content/xslt/src/xslt/txStylesheet.cpp | 4 ++-- content/xslt/src/xslt/txStylesheet.h | 2 +- .../src/xslt/txStylesheetCompileHandlers.cpp | 10 ++++---- .../xslt/src/xslt/txStylesheetCompiler.cpp | 6 ++--- content/xslt/src/xslt/txStylesheetCompiler.h | 6 ++--- .../xslt/src/xslt/txXPathResultComparator.cpp | 12 +++++----- .../xslt/src/xslt/txXPathResultComparator.h | 16 ++++++------- content/xslt/src/xslt/txXSLTNumber.cpp | 6 ++--- content/xslt/src/xslt/txXSLTPatterns.cpp | 2 +- 28 files changed, 97 insertions(+), 103 deletions(-) diff --git a/content/xslt/src/base/txCore.h b/content/xslt/src/base/txCore.h index 9d76cb5fd3ca..f1c97909e96a 100644 --- a/content/xslt/src/base/txCore.h +++ b/content/xslt/src/base/txCore.h @@ -106,10 +106,4 @@ public: static double toDouble(const nsAString& aStr); }; -// XXX These should go away eventually. -#define TxObject txObject -typedef txDouble Double; - -// XXX - #endif diff --git a/content/xslt/src/base/txDouble.cpp b/content/xslt/src/base/txDouble.cpp index 3e97a47869c7..0e67650ae03d 100644 --- a/content/xslt/src/base/txDouble.cpp +++ b/content/xslt/src/base/txDouble.cpp @@ -50,20 +50,20 @@ */ //-- Initialize Double related constants -const dpun Double::NaN = DOUBLE_NaN; +const dpun txDouble::NaN = DOUBLE_NaN; #ifdef IS_BIG_ENDIAN -const dpun Double::POSITIVE_INFINITY = {{DOUBLE_HI32_EXPMASK, 0}}; -const dpun Double::NEGATIVE_INFINITY = {{DOUBLE_HI32_EXPMASK | DOUBLE_HI32_SIGNBIT, 0}}; +const dpun txDouble::POSITIVE_INFINITY = {{DOUBLE_HI32_EXPMASK, 0}}; +const dpun txDouble::NEGATIVE_INFINITY = {{DOUBLE_HI32_EXPMASK | DOUBLE_HI32_SIGNBIT, 0}}; #else -const dpun Double::POSITIVE_INFINITY = {{0, DOUBLE_HI32_EXPMASK}}; -const dpun Double::NEGATIVE_INFINITY = {{0, DOUBLE_HI32_EXPMASK | DOUBLE_HI32_SIGNBIT}}; +const dpun txDouble::POSITIVE_INFINITY = {{0, DOUBLE_HI32_EXPMASK}}; +const dpun txDouble::NEGATIVE_INFINITY = {{0, DOUBLE_HI32_EXPMASK | DOUBLE_HI32_SIGNBIT}}; #endif /* * Determines whether the given double represents positive or negative * inifinity */ -bool Double::isInfinite(double aDbl) +bool txDouble::isInfinite(double aDbl) { return ((DOUBLE_HI32(aDbl) & ~DOUBLE_HI32_SIGNBIT) == DOUBLE_HI32_EXPMASK && !DOUBLE_LO32(aDbl)); @@ -72,7 +72,7 @@ bool Double::isInfinite(double aDbl) /* * Determines whether the given double is NaN */ -bool Double::isNaN(double aDbl) +bool txDouble::isNaN(double aDbl) { return DOUBLE_IS_NaN(aDbl); } @@ -80,7 +80,7 @@ bool Double::isNaN(double aDbl) /* * Determines whether the given double is negative */ -bool Double::isNeg(double aDbl) +bool txDouble::isNeg(double aDbl) { return (DOUBLE_HI32(aDbl) & DOUBLE_HI32_SIGNBIT) != 0; } @@ -170,7 +170,7 @@ public: { if (mState == eIllegal || mBuffer.IsEmpty() || (mBuffer.Length() == 1 && mBuffer[0] == '.')) { - return Double::NaN; + return txDouble::NaN; } return mSign*PR_strtod(mBuffer.get(), 0); } @@ -189,7 +189,7 @@ private: } mSign; }; -double Double::toDouble(const nsAString& aSrc) +double txDouble::toDouble(const nsAString& aSrc) { txStringToDouble sink; nsAString::const_iterator fromBegin, fromEnd; @@ -202,7 +202,7 @@ double Double::toDouble(const nsAString& aSrc) * The result into the destination String. * @return the given dest string */ -void Double::toString(double aValue, nsAString& aDest) +void txDouble::toString(double aValue, nsAString& aDest) { // check for special cases diff --git a/content/xslt/src/base/txList.h b/content/xslt/src/base/txList.h index 924404fb934d..8a4f418baf8c 100644 --- a/content/xslt/src/base/txList.h +++ b/content/xslt/src/base/txList.h @@ -46,7 +46,7 @@ class txListIterator; /** * Represents an ordered list of Object pointers. Modeled after a Java 2 List. **/ -class txList : public TxObject { +class txList : public txObject { friend class txListIterator; diff --git a/content/xslt/src/xml/txDOM.h b/content/xslt/src/xml/txDOM.h index edfbd41d3343..7b0a3504b702 100644 --- a/content/xslt/src/xml/txDOM.h +++ b/content/xslt/src/xml/txDOM.h @@ -82,7 +82,7 @@ class ProcessingInstruction; // Abstract Class defining the interface for a Node. See NodeDefinition below // for the actual implementation of the WC3 node. // -class Node : public TxObject +class Node : public txObject { public: //Node type constants diff --git a/content/xslt/src/xpath/txCoreFunctionCall.cpp b/content/xslt/src/xpath/txCoreFunctionCall.cpp index 19aa26a31397..796af8a766d3 100644 --- a/content/xslt/src/xpath/txCoreFunctionCall.cpp +++ b/content/xslt/src/xpath/txCoreFunctionCall.cpp @@ -396,8 +396,8 @@ txCoreFunctionCall::evaluate(txIEvalContext* aContext, txAExprResult** aResult) NS_ENSURE_SUCCESS(rv, rv); // check for NaN or +/-Inf - if (Double::isNaN(start) || - Double::isInfinite(start) || + if (txDouble::isNaN(start) || + txDouble::isInfinite(start) || start >= src.Length() + 0.5) { aContext->recycler()->getEmptyStringResult(aResult); @@ -412,7 +412,7 @@ txCoreFunctionCall::evaluate(txIEvalContext* aContext, txAExprResult** aResult) NS_ENSURE_SUCCESS(rv, rv); end += start; - if (Double::isNaN(end) || end < 0) { + if (txDouble::isNaN(end) || end < 0) { aContext->recycler()->getEmptyStringResult(aResult); return NS_OK; @@ -546,7 +546,7 @@ txCoreFunctionCall::evaluate(txIEvalContext* aContext, txAExprResult** aResult) nsAutoString resultStr; txXPathNodeUtils::appendNodeValue(aContext->getContextNode(), resultStr); - res = Double::toDouble(resultStr); + res = txDouble::toDouble(resultStr); } return aContext->recycler()->getNumberResult(res, aResult); } @@ -556,8 +556,8 @@ txCoreFunctionCall::evaluate(txIEvalContext* aContext, txAExprResult** aResult) rv = evaluateToNumber(mParams[0], aContext, &dbl); NS_ENSURE_SUCCESS(rv, rv); - if (!Double::isNaN(dbl) && !Double::isInfinite(dbl)) { - if (Double::isNeg(dbl) && dbl >= -0.5) { + if (!txDouble::isNaN(dbl) && !txDouble::isInfinite(dbl)) { + if (txDouble::isNeg(dbl) && dbl >= -0.5) { dbl *= 0; } else { @@ -573,9 +573,9 @@ txCoreFunctionCall::evaluate(txIEvalContext* aContext, txAExprResult** aResult) rv = evaluateToNumber(mParams[0], aContext, &dbl); NS_ENSURE_SUCCESS(rv, rv); - if (!Double::isNaN(dbl) && - !Double::isInfinite(dbl) && - !(dbl == 0 && Double::isNeg(dbl))) { + if (!txDouble::isNaN(dbl) && + !txDouble::isInfinite(dbl) && + !(dbl == 0 && txDouble::isNeg(dbl))) { dbl = floor(dbl); } @@ -587,8 +587,8 @@ txCoreFunctionCall::evaluate(txIEvalContext* aContext, txAExprResult** aResult) rv = evaluateToNumber(mParams[0], aContext, &dbl); NS_ENSURE_SUCCESS(rv, rv); - if (!Double::isNaN(dbl) && !Double::isInfinite(dbl)) { - if (Double::isNeg(dbl) && dbl > -1) { + if (!txDouble::isNaN(dbl) && !txDouble::isInfinite(dbl)) { + if (txDouble::isNeg(dbl) && dbl > -1) { dbl *= 0; } else { @@ -610,7 +610,7 @@ txCoreFunctionCall::evaluate(txIEvalContext* aContext, txAExprResult** aResult) for (i = 0; i < nodes->size(); ++i) { nsAutoString resultStr; txXPathNodeUtils::appendNodeValue(nodes->get(i), resultStr); - res += Double::toDouble(resultStr); + res += txDouble::toDouble(resultStr); } return aContext->recycler()->getNumberResult(res, aResult); } diff --git a/content/xslt/src/xpath/txExprParser.cpp b/content/xslt/src/xpath/txExprParser.cpp index 222a1f5178b4..d9c970b6db45 100644 --- a/content/xslt/src/xpath/txExprParser.cpp +++ b/content/xslt/src/xpath/txExprParser.cpp @@ -419,7 +419,7 @@ txExprParser::createFilterOrStep(txExprLexer& lexer, txIParseContext* aContext, break; case Token::NUMBER: { - expr = new txLiteralExpr(Double::toDouble(tok->Value())); + expr = new txLiteralExpr(txDouble::toDouble(tok->Value())); break; } default: diff --git a/content/xslt/src/xpath/txLiteralExpr.cpp b/content/xslt/src/xpath/txLiteralExpr.cpp index 37b0fb342673..a8d1dff82916 100644 --- a/content/xslt/src/xpath/txLiteralExpr.cpp +++ b/content/xslt/src/xpath/txLiteralExpr.cpp @@ -103,7 +103,7 @@ txLiteralExpr::toString(nsAString& aStr) } case txAExprResult::NUMBER: { - Double::toString(mValue->numberValue(), aStr); + txDouble::toString(mValue->numberValue(), aStr); return; } case txAExprResult::STRING: diff --git a/content/xslt/src/xpath/txNodeSet.cpp b/content/xslt/src/xpath/txNodeSet.cpp index c52bba0285b7..828dac4be875 100644 --- a/content/xslt/src/xpath/txNodeSet.cpp +++ b/content/xslt/src/xpath/txNodeSet.cpp @@ -501,7 +501,7 @@ txNodeSet::numberValue() nsAutoString str; stringValue(str); - return Double::toDouble(str); + return txDouble::toDouble(str); } void diff --git a/content/xslt/src/xpath/txNodeSetAdaptor.cpp b/content/xslt/src/xpath/txNodeSetAdaptor.cpp index 5f7b4f8ed943..82681dc58f90 100644 --- a/content/xslt/src/xpath/txNodeSetAdaptor.cpp +++ b/content/xslt/src/xpath/txNodeSetAdaptor.cpp @@ -86,7 +86,7 @@ txNodeSetAdaptor::ItemAsNumber(PRUint32 aIndex, double *aResult) nsAutoString result; txXPathNodeUtils::appendNodeValue(NodeSet()->get(aIndex), result); - *aResult = Double::toDouble(result); + *aResult = txDouble::toDouble(result); return NS_OK; } diff --git a/content/xslt/src/xpath/txNumberExpr.cpp b/content/xslt/src/xpath/txNumberExpr.cpp index 531db5ff54b2..6f12240952ed 100644 --- a/content/xslt/src/xpath/txNumberExpr.cpp +++ b/content/xslt/src/xpath/txNumberExpr.cpp @@ -70,16 +70,16 @@ txNumberExpr::evaluate(txIEvalContext* aContext, txAExprResult** aResult) if (rightDbl == 0) { #if defined(XP_WIN) /* XXX MSVC miscompiles such that (NaN == 0) */ - if (Double::isNaN(rightDbl)) - result = Double::NaN; + if (txDouble::isNaN(rightDbl)) + result = txDouble::NaN; else #endif - if (leftDbl == 0 || Double::isNaN(leftDbl)) - result = Double::NaN; - else if (Double::isNeg(leftDbl) ^ Double::isNeg(rightDbl)) - result = Double::NEGATIVE_INFINITY; + if (leftDbl == 0 || txDouble::isNaN(leftDbl)) + result = txDouble::NaN; + else if (txDouble::isNeg(leftDbl) ^ txDouble::isNeg(rightDbl)) + result = txDouble::NEGATIVE_INFINITY; else - result = Double::POSITIVE_INFINITY; + result = txDouble::POSITIVE_INFINITY; } else result = leftDbl / rightDbl; @@ -87,12 +87,12 @@ txNumberExpr::evaluate(txIEvalContext* aContext, txAExprResult** aResult) case MODULUS: if (rightDbl == 0) { - result = Double::NaN; + result = txDouble::NaN; } else { #if defined(XP_WIN) /* Workaround MS fmod bug where 42 % (1/0) => NaN, not 42. */ - if (!Double::isInfinite(leftDbl) && Double::isInfinite(rightDbl)) + if (!txDouble::isInfinite(leftDbl) && txDouble::isInfinite(rightDbl)) result = leftDbl; else #endif diff --git a/content/xslt/src/xpath/txNumberResult.cpp b/content/xslt/src/xpath/txNumberResult.cpp index edea4c3ab49b..d1df4334a5c1 100644 --- a/content/xslt/src/xpath/txNumberResult.cpp +++ b/content/xslt/src/xpath/txNumberResult.cpp @@ -67,7 +67,7 @@ short NumberResult::getResultType() { void NumberResult::stringValue(nsString& aResult) { - Double::toString(value, aResult); + txDouble::toString(value, aResult); } const nsString* @@ -80,7 +80,7 @@ bool NumberResult::booleanValue() { // OG+ // As per the XPath spec, the boolean value of a number is true if and only if // it is neither positive 0 nor negative 0 nor NaN - return (bool)(value != 0.0 && !Double::isNaN(value)); + return (bool)(value != 0.0 && !txDouble::isNaN(value)); // OG- } //-- booleanValue diff --git a/content/xslt/src/xpath/txStringResult.cpp b/content/xslt/src/xpath/txStringResult.cpp index a1d1362afb70..396bdb580ebc 100644 --- a/content/xslt/src/xpath/txStringResult.cpp +++ b/content/xslt/src/xpath/txStringResult.cpp @@ -84,6 +84,6 @@ bool StringResult::booleanValue() { } //-- booleanValue double StringResult::numberValue() { - return Double::toDouble(mValue); + return txDouble::toDouble(mValue); } //-- numberValue diff --git a/content/xslt/src/xpath/txUnionNodeTest.cpp b/content/xslt/src/xpath/txUnionNodeTest.cpp index c94edafea895..4398c734c929 100644 --- a/content/xslt/src/xpath/txUnionNodeTest.cpp +++ b/content/xslt/src/xpath/txUnionNodeTest.cpp @@ -58,7 +58,7 @@ double txUnionNodeTest::getDefaultPriority() { NS_ERROR("Don't call getDefaultPriority on txUnionPattern"); - return Double::NaN; + return txDouble::NaN; } bool diff --git a/content/xslt/src/xslt/txEXSLTFunctions.cpp b/content/xslt/src/xslt/txEXSLTFunctions.cpp index 235fe5bba46f..fd8ccced5f6f 100644 --- a/content/xslt/src/xslt/txEXSLTFunctions.cpp +++ b/content/xslt/src/xslt/txEXSLTFunctions.cpp @@ -611,7 +611,7 @@ txEXSLTFunctionCall::evaluate(txIEvalContext *aContext, if (nodes->isEmpty()) { return aContext->recycler()-> - getNumberResult(Double::NaN, aResult); + getNumberResult(txDouble::NaN, aResult); } bool findMax = mType == MAX; @@ -622,9 +622,9 @@ txEXSLTFunctionCall::evaluate(txIEvalContext *aContext, for (i = 0; i < len; ++i) { nsAutoString str; txXPathNodeUtils::appendNodeValue(nodes->get(i), str); - double val = Double::toDouble(str); - if (Double::isNaN(val)) { - res = Double::NaN; + double val = txDouble::toDouble(str); + if (txDouble::isNaN(val)) { + res = txDouble::NaN; break; } @@ -661,8 +661,8 @@ txEXSLTFunctionCall::evaluate(txIEvalContext *aContext, nsAutoString str; const txXPathNode& node = nodes->get(i); txXPathNodeUtils::appendNodeValue(node, str); - double val = Double::toDouble(str); - if (Double::isNaN(val)) { + double val = txDouble::toDouble(str); + if (txDouble::isNaN(val)) { resultSet->clear(); break; } diff --git a/content/xslt/src/xslt/txFormatNumberFunctionCall.cpp b/content/xslt/src/xslt/txFormatNumberFunctionCall.cpp index 131e3daac8e6..21764251a4f7 100644 --- a/content/xslt/src/xslt/txFormatNumberFunctionCall.cpp +++ b/content/xslt/src/xslt/txFormatNumberFunctionCall.cpp @@ -112,16 +112,16 @@ txFormatNumberFunctionCall::evaluate(txIEvalContext* aContext, } // Special cases - if (Double::isNaN(value)) { + if (txDouble::isNaN(value)) { return aContext->recycler()->getStringResult(format->mNaN, aResult); } - if (value == Double::POSITIVE_INFINITY) { + if (value == txDouble::POSITIVE_INFINITY) { return aContext->recycler()->getStringResult(format->mInfinity, aResult); } - if (value == Double::NEGATIVE_INFINITY) { + if (value == txDouble::NEGATIVE_INFINITY) { nsAutoString res; res.Append(format->mMinusSign); res.Append(format->mInfinity); @@ -143,7 +143,7 @@ txFormatNumberFunctionCall::evaluate(txIEvalContext* aContext, // Get right subexpression inQuote = false; - if (Double::isNeg(value)) { + if (txDouble::isNeg(value)) { while (pos < formatLen && (inQuote || formatStr.CharAt(pos) != format->mPatternSeparator)) { diff --git a/content/xslt/src/xslt/txInstructions.h b/content/xslt/src/xslt/txInstructions.h index 6215e1ab345c..80b22bfc6e88 100644 --- a/content/xslt/src/xslt/txInstructions.h +++ b/content/xslt/src/xslt/txInstructions.h @@ -51,7 +51,7 @@ class nsIAtom; class txExecutionState; -class txInstruction : public TxObject +class txInstruction : public txObject { public: txInstruction() diff --git a/content/xslt/src/xslt/txNodeSorter.cpp b/content/xslt/src/xslt/txNodeSorter.cpp index 94489d105d77..3d4ed74ca12e 100644 --- a/content/xslt/src/xslt/txNodeSorter.cpp +++ b/content/xslt/src/xslt/txNodeSorter.cpp @@ -180,8 +180,8 @@ txNodeSorter::sortNodeSet(txNodeSet* aNodes, txExecutionState* aEs, PRUint32 len = static_cast(aNodes->size()); // Limit resource use to something sane. - PRUint32 itemSize = sizeof(PRUint32) + mNKeys * sizeof(TxObject*); - if (mNKeys > (PR_UINT32_MAX - sizeof(PRUint32)) / sizeof(TxObject*) || + PRUint32 itemSize = sizeof(PRUint32) + mNKeys * sizeof(txObject*); + if (mNKeys > (PR_UINT32_MAX - sizeof(PRUint32)) / sizeof(txObject*) || len >= PR_UINT32_MAX / itemSize) { return NS_ERROR_OUT_OF_MEMORY; } @@ -190,13 +190,13 @@ txNodeSorter::sortNodeSet(txNodeSet* aNodes, txExecutionState* aEs, NS_ENSURE_TRUE(mem, NS_ERROR_OUT_OF_MEMORY); PRUint32* indexes = static_cast(mem); - TxObject** sortValues = reinterpret_cast(indexes + len); + txObject** sortValues = reinterpret_cast(indexes + len); PRUint32 i; for (i = 0; i < len; ++i) { indexes[i] = i; } - memset(sortValues, 0, len * mNKeys * sizeof(TxObject*)); + memset(sortValues, 0, len * mNKeys * sizeof(txObject*)); // Sort the indexarray SortData sortData; @@ -248,9 +248,9 @@ txNodeSorter::compareNodes(const void* aIndexA, const void* aIndexB, txListIterator iter(&sortData->mNodeSorter->mSortKeys); PRUint32 indexA = *static_cast(aIndexA); PRUint32 indexB = *static_cast(aIndexB); - TxObject** sortValuesA = sortData->mSortValues + + txObject** sortValuesA = sortData->mSortValues + indexA * sortData->mNodeSorter->mNKeys; - TxObject** sortValuesB = sortData->mSortValues + + txObject** sortValuesB = sortData->mSortValues + indexB * sortData->mNodeSorter->mNKeys; unsigned int i; @@ -280,7 +280,7 @@ txNodeSorter::compareNodes(const void* aIndexA, const void* aIndexB, //static bool -txNodeSorter::calcSortValue(TxObject*& aSortValue, SortKey* aKey, +txNodeSorter::calcSortValue(txObject*& aSortValue, SortKey* aKey, SortData* aSortData, PRUint32 aNodeIndex) { aSortData->mContext->setPosition(aNodeIndex + 1); // position is 1-based diff --git a/content/xslt/src/xslt/txNodeSorter.h b/content/xslt/src/xslt/txNodeSorter.h index 0a7756d66f38..5fff6cc40f51 100644 --- a/content/xslt/src/xslt/txNodeSorter.h +++ b/content/xslt/src/xslt/txNodeSorter.h @@ -46,7 +46,7 @@ class Expr; class txExecutionState; class txNodeSet; -class TxObject; +class txObject; class txXPathResultComparator; class txIEvalContext; class txNodeSetContext; @@ -72,7 +72,7 @@ private: { txNodeSorter* mNodeSorter; txNodeSetContext* mContext; - TxObject** mSortValues; + txObject** mSortValues; nsresult mRv; }; struct SortKey @@ -83,8 +83,8 @@ private: static int compareNodes(const void* aIndexA, const void* aIndexB, void* aSortData); - static bool calcSortValue(TxObject*& aSortValue, SortKey* aKey, - SortData* aSortData, PRUint32 aNodeIndex); + static bool calcSortValue(txObject*& aSortValue, SortKey* aKey, + SortData* aSortData, PRUint32 aNodeIndex); txList mSortKeys; unsigned int mNKeys; }; diff --git a/content/xslt/src/xslt/txRtfHandler.cpp b/content/xslt/src/xslt/txRtfHandler.cpp index e7e7cdfba9fb..d009a8ae1ea1 100644 --- a/content/xslt/src/xslt/txRtfHandler.cpp +++ b/content/xslt/src/xslt/txRtfHandler.cpp @@ -77,7 +77,7 @@ double txResultTreeFragment::numberValue() return 0; } - return Double::toDouble(mBuffer->mStringValue); + return txDouble::toDouble(mBuffer->mStringValue); } nsresult txResultTreeFragment::flushToHandler(txAXMLEventHandler* aHandler) diff --git a/content/xslt/src/xslt/txStylesheet.cpp b/content/xslt/src/xslt/txStylesheet.cpp index d87ff3e7e54d..5eba528cb3bd 100644 --- a/content/xslt/src/xslt/txStylesheet.cpp +++ b/content/xslt/src/xslt/txStylesheet.cpp @@ -442,9 +442,9 @@ txStylesheet::addTemplate(txTemplateItem* aTemplate, PRUint32 unionPos = 1; // only used when unionPattern is set while (simple) { double priority = aTemplate->mPrio; - if (Double::isNaN(priority)) { + if (txDouble::isNaN(priority)) { priority = simple->getDefaultPriority(); - NS_ASSERTION(!Double::isNaN(priority), + NS_ASSERTION(!txDouble::isNaN(priority), "simple pattern without default priority"); } diff --git a/content/xslt/src/xslt/txStylesheet.h b/content/xslt/src/xslt/txStylesheet.h index 05825efb42fb..9221a8526173 100644 --- a/content/xslt/src/xslt/txStylesheet.h +++ b/content/xslt/src/xslt/txStylesheet.h @@ -128,7 +128,7 @@ public: ImportFrame* mFirstNotImported; }; - class GlobalVariable : public TxObject { + class GlobalVariable : public txObject { public: GlobalVariable(nsAutoPtr aExpr, nsAutoPtr aFirstInstruction, diff --git a/content/xslt/src/xslt/txStylesheetCompileHandlers.cpp b/content/xslt/src/xslt/txStylesheetCompileHandlers.cpp index e68e2a1baa8c..1c4e02dd20c7 100644 --- a/content/xslt/src/xslt/txStylesheetCompileHandlers.cpp +++ b/content/xslt/src/xslt/txStylesheetCompileHandlers.cpp @@ -303,7 +303,7 @@ getNumberAttr(txStylesheetAttr* aAttributes, txStylesheetCompilerState& aState, double& aNumber) { - aNumber = Double::NaN; + aNumber = txDouble::NaN; txStylesheetAttr* attr = nsnull; nsresult rv = getStyleAttr(aAttributes, aAttrCount, kNameSpaceID_None, aName, aRequired, &attr); @@ -311,8 +311,8 @@ getNumberAttr(txStylesheetAttr* aAttributes, return rv; } - aNumber = Double::toDouble(attr->mValue); - if (Double::isNaN(aNumber) && (aRequired || !aState.fcp())) { + aNumber = txDouble::toDouble(attr->mValue); + if (txDouble::isNaN(aNumber) && (aRequired || !aState.fcp())) { // XXX ErrorReport: number parse failure return NS_ERROR_XSLT_PARSE_FAILURE; } @@ -552,7 +552,7 @@ txFnStartLREStylesheet(PRInt32 aNamespaceID, NS_ENSURE_SUCCESS(rv, rv); txExpandedName nullExpr; - double prio = Double::NaN; + double prio = txDouble::NaN; nsAutoPtr match(new txRootPattern()); NS_ENSURE_TRUE(match, NS_ERROR_OUT_OF_MEMORY); @@ -1145,7 +1145,7 @@ txFnStartTemplate(PRInt32 aNamespaceID, aState, mode); NS_ENSURE_SUCCESS(rv, rv); - double prio = Double::NaN; + double prio = txDouble::NaN; rv = getNumberAttr(aAttributes, aAttrCount, nsGkAtoms::priority, false, aState, prio); NS_ENSURE_SUCCESS(rv, rv); diff --git a/content/xslt/src/xslt/txStylesheetCompiler.cpp b/content/xslt/src/xslt/txStylesheetCompiler.cpp index bf1b90e094c6..aca2bb3d83c6 100644 --- a/content/xslt/src/xslt/txStylesheetCompiler.cpp +++ b/content/xslt/src/xslt/txStylesheetCompiler.cpp @@ -688,15 +688,15 @@ txStylesheetCompilerState::popChooseGotoList() } nsresult -txStylesheetCompilerState::pushObject(TxObject* aObject) +txStylesheetCompilerState::pushObject(txObject* aObject) { return mObjectStack.push(aObject); } -TxObject* +txObject* txStylesheetCompilerState::popObject() { - return static_cast(mObjectStack.pop()); + return static_cast(mObjectStack.pop()); } nsresult diff --git a/content/xslt/src/xslt/txStylesheetCompiler.h b/content/xslt/src/xslt/txStylesheetCompiler.h index 475ac23f2f2d..d08df11af227 100644 --- a/content/xslt/src/xslt/txStylesheetCompiler.h +++ b/content/xslt/src/xslt/txStylesheetCompiler.h @@ -60,7 +60,7 @@ class txPushNewContext; class txStylesheetCompiler; class txInScopeVariable; -class txElementContext : public TxObject +class txElementContext : public txObject { public: txElementContext(const nsAString& aBaseURI); @@ -122,8 +122,8 @@ public: void popSorter(); nsresult pushChooseGotoList(); void popChooseGotoList(); - nsresult pushObject(TxObject* aObject); - TxObject* popObject(); + nsresult pushObject(txObject* aObject); + txObject* popObject(); nsresult pushPtr(void* aPtr); void* popPtr(); diff --git a/content/xslt/src/xslt/txXPathResultComparator.cpp b/content/xslt/src/xslt/txXPathResultComparator.cpp index 6fa50c5a5635..179181e03571 100644 --- a/content/xslt/src/xslt/txXPathResultComparator.cpp +++ b/content/xslt/src/xslt/txXPathResultComparator.cpp @@ -129,7 +129,7 @@ txResultStringComparator::createSortableValue(Expr *aExpr, return NS_OK; } -int txResultStringComparator::compareValues(TxObject* aVal1, TxObject* aVal2) +int txResultStringComparator::compareValues(txObject* aVal1, txObject* aVal2) { StringValue* strval1 = (StringValue*)aVal1; StringValue* strval2 = (StringValue*)aVal2; @@ -223,7 +223,7 @@ txResultNumberComparator::txResultNumberComparator(bool aAscending) nsresult txResultNumberComparator::createSortableValue(Expr *aExpr, txIEvalContext *aContext, - TxObject *&aResult) + txObject *&aResult) { nsAutoPtr numval(new NumberValue); if (!numval) { @@ -241,15 +241,15 @@ txResultNumberComparator::createSortableValue(Expr *aExpr, return NS_OK; } -int txResultNumberComparator::compareValues(TxObject* aVal1, TxObject* aVal2) +int txResultNumberComparator::compareValues(txObject* aVal1, txObject* aVal2) { double dval1 = ((NumberValue*)aVal1)->mVal; double dval2 = ((NumberValue*)aVal2)->mVal; - if (Double::isNaN(dval1)) - return Double::isNaN(dval2) ? 0 : -mAscending; + if (txDouble::isNaN(dval1)) + return txDouble::isNaN(dval2) ? 0 : -mAscending; - if (Double::isNaN(dval2)) + if (txDouble::isNaN(dval2)) return mAscending; if (dval1 == dval2) diff --git a/content/xslt/src/xslt/txXPathResultComparator.h b/content/xslt/src/xslt/txXPathResultComparator.h index c70e72d69b04..6c3f0f49fa66 100644 --- a/content/xslt/src/xslt/txXPathResultComparator.h +++ b/content/xslt/src/xslt/txXPathResultComparator.h @@ -62,13 +62,13 @@ public: * Compares two XPath results. Returns -1 if val1 < val2, * 1 if val1 > val2 and 0 if val1 == val2. */ - virtual int compareValues(TxObject* val1, TxObject* val2) = 0; + virtual int compareValues(txObject* val1, txObject* val2) = 0; /* * Create a sortable value. */ virtual nsresult createSortableValue(Expr *aExpr, txIEvalContext *aContext, - TxObject *&aResult) = 0; + txObject *&aResult) = 0; }; /* @@ -80,9 +80,9 @@ public: txResultStringComparator(bool aAscending, bool aUpperFirst, const nsAFlatString& aLanguage); - int compareValues(TxObject* aVal1, TxObject* aVal2); + int compareValues(txObject* aVal1, txObject* aVal2); nsresult createSortableValue(Expr *aExpr, txIEvalContext *aContext, - TxObject *&aResult); + txObject *&aResult); private: nsCOMPtr mCollation; nsresult init(const nsAFlatString& aLanguage); @@ -92,7 +92,7 @@ private: PRUint32* aLength); int mSorting; - class StringValue : public TxObject + class StringValue : public txObject { public: StringValue(); @@ -112,14 +112,14 @@ class txResultNumberComparator : public txXPathResultComparator public: txResultNumberComparator(bool aAscending); - int compareValues(TxObject* aVal1, TxObject* aVal2); + int compareValues(txObject* aVal1, txObject* aVal2); nsresult createSortableValue(Expr *aExpr, txIEvalContext *aContext, - TxObject *&aResult); + txObject *&aResult); private: int mAscending; - class NumberValue : public TxObject + class NumberValue : public txObject { public: double mVal; diff --git a/content/xslt/src/xslt/txXSLTNumber.cpp b/content/xslt/src/xslt/txXSLTNumber.cpp index 3056f277bc94..dd337bc3bbc7 100644 --- a/content/xslt/src/xslt/txXSLTNumber.cpp +++ b/content/xslt/src/xslt/txXSLTNumber.cpp @@ -122,9 +122,9 @@ txXSLTNumber::getValueList(Expr* aValueExpr, txPattern* aCountPattern, double value = result->numberValue(); - if (Double::isInfinite(value) || Double::isNaN(value) || + if (txDouble::isInfinite(value) || txDouble::isNaN(value) || value < 0.5) { - Double::toString(value, aValueString); + txDouble::toString(value, aValueString); return NS_OK; } @@ -318,7 +318,7 @@ txXSLTNumber::getCounters(Expr* aGroupSize, Expr* aGroupSeparator, rv = aGroupSize->evaluateToString(aContext, sizeStr); NS_ENSURE_SUCCESS(rv, rv); - double size = Double::toDouble(sizeStr); + double size = txDouble::toDouble(sizeStr); groupSize = (PRInt32)size; if ((double)groupSize != size) { groupSize = 0; diff --git a/content/xslt/src/xslt/txXSLTPatterns.cpp b/content/xslt/src/xslt/txXSLTPatterns.cpp index cc54ff17917c..4cf02a603711 100644 --- a/content/xslt/src/xslt/txXSLTPatterns.cpp +++ b/content/xslt/src/xslt/txXSLTPatterns.cpp @@ -54,7 +54,7 @@ double txUnionPattern::getDefaultPriority() { NS_ERROR("Don't call getDefaultPriority on txUnionPattern"); - return Double::NaN; + return txDouble::NaN; } /* From 9bae3e2359624e12a1dbaced1904d8c8818c2d42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9-Luc?= Date: Sun, 20 Nov 2011 11:18:27 +0000 Subject: [PATCH 61/63] Bug 702107 - Geolocation Service broken because of access token. r=dougt --- dom/system/NetworkGeolocationProvider.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dom/system/NetworkGeolocationProvider.js b/dom/system/NetworkGeolocationProvider.js index 612888afd898..7f7bef8e18ce 100755 --- a/dom/system/NetworkGeolocationProvider.js +++ b/dom/system/NetworkGeolocationProvider.js @@ -203,7 +203,7 @@ WifiGeoPositionProvider.prototype = { let accessToken = this.getAccessTokenForURL(providerUrlBase); if (accessToken !== "") - providerUrl = providerUrl + "&access_token="+access_token; + providerUrl = providerUrl + "&access_token="+accessToken; function sort(a, b) { return b.signal - a.signal; From 675d93816fcd8dff22e10b82f848bdb20e91b5ae Mon Sep 17 00:00:00 2001 From: Joey Armstrong Date: Sun, 20 Nov 2011 11:18:27 +0000 Subject: [PATCH 62/63] Bug 687511 - make-makefile enhancements; r=khuey,coop --- build/Makefile.in | 1 + build/autoconf/make-makefile | 496 +++++++++------ build/autoconf/make-makefile.excl | 5 + build/autoconf/makemakefile.pm | 745 +++++++++++++++++++++++ build/autoconf/test/Makefile.in | 94 +++ build/autoconf/test/data/mf.notokens | 4 + build/autoconf/test/data/mf.notokens.exp | 4 + build/autoconf/test/make-makefile.excl | 8 + build/autoconf/test/make-makefile.tpl | 436 +++++++++++++ build/autoconf/test/makemakefile.tpm | 519 ++++++++++++++++ build/autoconf/test/runtest | 95 +++ js/src/build/autoconf/make-makefile | 496 +++++++++------ js/src/build/autoconf/make-makefile.excl | 5 + js/src/build/autoconf/makemakefile.pm | 745 +++++++++++++++++++++++ 14 files changed, 3311 insertions(+), 342 deletions(-) create mode 100644 build/autoconf/make-makefile.excl create mode 100644 build/autoconf/makemakefile.pm create mode 100644 build/autoconf/test/Makefile.in create mode 100644 build/autoconf/test/data/mf.notokens create mode 100644 build/autoconf/test/data/mf.notokens.exp create mode 100644 build/autoconf/test/make-makefile.excl create mode 100644 build/autoconf/test/make-makefile.tpl create mode 100644 build/autoconf/test/makemakefile.tpm create mode 100644 build/autoconf/test/runtest create mode 100644 js/src/build/autoconf/make-makefile.excl create mode 100644 js/src/build/autoconf/makemakefile.pm diff --git a/build/Makefile.in b/build/Makefile.in index 6642ba80e405..62c4d1372c49 100644 --- a/build/Makefile.in +++ b/build/Makefile.in @@ -56,6 +56,7 @@ endif DIRS += pgo ifdef ENABLE_TESTS + DIRS += autoconf/test ifeq (android,$(MOZ_WIDGET_TOOLKIT)) DIRS += mobile/sutagent/android \ mobile/sutagent/android/watcher \ diff --git a/build/autoconf/make-makefile b/build/autoconf/make-makefile index 94a5497da559..1f08aec1c923 100755 --- a/build/autoconf/make-makefile +++ b/build/autoconf/make-makefile @@ -1,4 +1,4 @@ -#! /usr/bin/env perl +#!/usr/bin/env perl # ***** BEGIN LICENSE BLOCK ***** # Version: MPL 1.1/GPL 2.0/LGPL 2.1 # @@ -16,10 +16,12 @@ # # The Initial Developer of the Original Code is # Netscape Communications Corporation. -# Portions created by the Initial Developer are Copyright (C) 1999 +# Portions created by the Initial Developer are Copyright (C) 1999-2011 # the Initial Developer. All Rights Reserved. # # Contributor(s): +# Steve Lamm +# Joey Armstrong # # Alternatively, the contents of this file may be used under the terms of # either of the GNU General Public License Version 2 or later (the "GPL"), @@ -35,29 +37,81 @@ # # ***** END LICENSE BLOCK ***** -# make-makefiles - Quickly create Makefiles for subdirectories. -# Also, creates any needed subdirectories. -# -# usage: make-makefiles [ -t -p -d ] [ | /Makefile ] ... +##----------------------------## +##---] CORE/CPAN INCLUDES [---## +##----------------------------## +use strict; +use warnings; +use Getopt::Long; -# Send comments, improvements, bugs to Steve Lamm (slamm@netscape.com). +use Benchmark; +use Cwd; +use File::Basename; +use File::Copy; +use File::Path qw{mkpath}; -#$debug = 1; +##-------------------## +##---] EXPORTS [---## +##-------------------## +our $VERSION = qw(2.0); -if ($^O eq 'msys') { - $pwdcmd = 'pwd -W'; +##--------------------## +##---] INCLUDES [---## +##--------------------## + +############################################################## +# pymake: special case path handling for windows cmd shell. +# if invoked by cmd.exe and msys-perl is in play +# $0 may contain a drive letter +# modules use-or-expect msys/unix paths +# adjust $0 => C:/foo => /c/foo so string tests and +# manipulation can by applied properly. +############################################################## +sub BEGIN +{ + if ($^O eq 'msys' && $ENV{PATH} =~ m!\w:/!) + { + $0 =~ s!^(\w):!/$1!; + } + eval 'use FindBin'; + die $@ if ($@); } -else { - $pwdcmd = 'pwd'; + +use lib $FindBin::Bin; +use makemakefile; + +##-------------------## +##---] GLOBALS [---## +##-------------------## +my %argv; + +my $t0 = Benchmark->new(); +sub END +{ + if ($argv{bench}) + { + my $t1 = Benchmark->new(); + my $delta = timediff($t1, $t0); + print STDERR timestr($delta), "\n"; + } } +##----------------## +##---] MAIN [---## +##----------------## +umask 0; + +my $debug = $argv{debug} || 0; + +my $pwdcmd = ($^O eq 'msys') ? 'pwd -W' : 'pwd'; + # Determine various tree path variables # -($topsrcdir, $ptopsrcdir, $depth, @makefiles) = parse_arguments(@ARGV); +my ($topsrcdir, $ptopsrcdir, $depth, @makefiles) = parse_arguments(@ARGV); -$object_fullpath = `$pwdcmd`; +my $object_fullpath = `$pwdcmd`; # Cwd::getcwd() chdir $depth; -$object_root = `$pwdcmd`; +my $object_root = `$pwdcmd`; # Cwd::getcwd() chomp $object_fullpath; chomp $object_root; @@ -65,24 +119,23 @@ chomp $object_root; # 'make-makefile' was called. For example, if make-makefile was # called from "mozilla/gfx/src", then $source_subdir would be # "gfx/src/". -$source_subdir = "$object_fullpath/"; +my $source_subdir = "$object_fullpath/"; my $quoted_object_root = quotemeta($object_root); $source_subdir =~ s|^$quoted_object_root/||; # Prefix makefiles with $source_subdir so that paths # will be relative to the top of the object tree. # -for $makefile (@makefiles) { +my $makefile; +for $makefile (@makefiles) { # dead code ? $makefile = "$source_subdir$makefile"; } -create_directories(@makefiles); - # Find the path to the source directory based on how 'make-makefile' # was invoked. The path is either relative to the object directory # or an absolute path. -$given_srcdir = find_srcdir($topsrcdir, $depth); -$pgiven_srcdir = find_srcdir($ptopsrcdir, $depth); +my $given_srcdir = find_srcdir($topsrcdir, $depth); +my $pgiven_srcdir = find_srcdir($ptopsrcdir, $depth); if ($debug) { warn "object_fullpath = $object_fullpath\n"; @@ -92,18 +145,21 @@ if ($debug) { warn "given_srcdir = $given_srcdir\n"; } -@unhandled = update_makefiles($given_srcdir, $pgiven_srcdir, @makefiles); +my @errors; +my @unhandled = update_makefiles_legacy($given_srcdir, $pgiven_srcdir, @makefiles); +push(@errors, $@) if ($@); run_config_status(@unhandled); +push(@errors, $@) if ($@ && $argv{'no-warnings'}); + +exit scalar(@errors); # end of Main ############################################################ -sub dirname { - return $_[0] =~ /(.*)\/.*/ ? "$1" : '.'; -} - +########################################################################### # find_depth: Pull the value of DEPTH out of a Makefile (or Makefile.in) +########################################################################### sub find_depth { my $depth = ''; open(MAKEFILE, "<$_[0]") || die "Unable to open $_[0]: $!\n"; @@ -116,39 +172,115 @@ sub find_depth { return $depth; } +########################################################################### +## Intent: Parse command line arguments and assign values +########################################################################### sub parse_arguments { my @args = @_; - my $depth = ''; - my $topsrcdir = ''; - my $ptopsrcdir; my @makefiles = (); - while (1) { - if ($args[0] eq '-d') { - $depth = $args[1]; - shift @args; - shift @args; - } elsif ($args[0] eq '-t') { - $topsrcdir = $args[1]; - shift @args; - shift @args; - } elsif ($args[0] eq '-p') { - $ptopsrcdir = $args[1]; - shift @args; - shift @args; - } else { - last; - } + my @arglist = qw(badtokens! bench + chdir=s + debug + depth|d=s + enhanced + obj=s top|t=s ptop|p=s + src=s dst=s + ); + unless(GetOptions(\%argv, @arglist)) + { + my $script = join('/', $FindBin::RealBin, $FindBin::Script); + system("perldoc $script $depth, obj=>$obj, top=>$top}); + if ($@) + { + push(@errors, $@); + } + elsif ($rc eq 'badtokens') + { + push(@unhandled, $mf); + } + } + + run_config_status(@unhandled); + push(@errors, $@) if ($@ && $argv{'no-warnings'}); + exit scalar(@errors); + } + + + my $depth = $argv{depth} || ''; + if (! $depth) + { + foreach my $fyl (@args) + { + if (my $tmp = find_depth($fyl)) + { + $depth = $tmp; + last; + } + } + } + + if (! $depth) { # Use $(DEPTH) in the Makefile or Makefile.in to determine the depth if (-e "Makefile.in") { $depth = find_depth("Makefile.in"); @@ -166,34 +298,21 @@ sub parse_arguments { # Build the list of makefiles to generate # @makefiles = (); - my $makefile; - foreach $makefile (@args) { - $makefile =~ s/\.in$//; - $makefile =~ s/\/$//; - $makefile =~ /Makefile$/ - or $makefile =~ /^\.\// - or $makefile .= "/Makefile"; + while (@args) + { + next unless my $makefile = shift @args; + $makefile =~ s/\.in$//; + $makefile =~ s/\/$//; + $makefile =~ /Makefile$/ + or $makefile =~ /^\.\// + or $makefile .= "/Makefile"; push @makefiles, "$makefile"; } - @makefiles = "Makefile" unless @args; + @makefiles = "Makefile" unless @makefiles; return ($topsrcdir, $ptopsrcdir, $depth, @makefiles); } - -# Create all the directories at once. -# This can be much faster than calling mkdir() for each one. -sub create_directories { - my @makefiles = @_; - my @dirs = (); - my $ac_file; - foreach $ac_file (@makefiles) { - push @dirs, dirname($ac_file); - } - # Call mkdir with the directories sorted by subdir count (how many /'s) - system "mkdir -p ". join(' ', map("\"$_\"", @dirs)) if @dirs; -} - # Find the top of the source directory # (Assuming that the executable is in $top_srcdir/build/autoconf) sub find_srcdir { @@ -214,111 +333,146 @@ sub find_srcdir { return $ac_given_srcdir; } -# Output the makefiles. -# -sub update_makefiles { - my ($ac_given_srcdir, $pac_given_srcdir, @makefiles) = @_; - my @unhandled=(); +1; +########################################################################### +## perldoc +########################################################################### +__END__ - my $ac_file; - foreach $ac_file (@makefiles) { - my $ac_file_in = "$ac_given_srcdir/${ac_file}.in"; - my $ac_dir = dirname($ac_file); - my $ac_dots = ''; - my $ac_dir_suffix = ''; - my $srcdir = '.'; - my $top_srcdir = '.'; +=head1 NAME - # Determine $srcdir and $top_srcdir - # - if ($ac_dir ne '.') { - $ac_dir_suffix = "/$ac_dir"; - $ac_dir_suffix =~ s%^/\./%/%; - $ac_dots = $ac_dir_suffix; - # Remove .. components from the provided dir suffix, and - # also the forward path components they were reversing. - my $backtracks = $ac_dots =~ s%\.\.(/|$)%%g; - while ($backtracks--) { - $ac_dots =~ s%/[^/]*%%; - } - $ac_dots =~ s%/[^/]*%../%g; - } - if ($ac_given_srcdir eq '.') { - if ($ac_dots ne '') { - $top_srcdir = $ac_dots; - $top_srcdir =~ s%/$%%; - } - } elsif ($pac_given_srcdir =~ m%^/% or $pac_given_srcdir =~ m%^.:/%) { - $srcdir = "$pac_given_srcdir$ac_dir_suffix"; - $top_srcdir = "$pac_given_srcdir"; - } else { - if ($debug) { - print "ac_dots = $ac_dots\n"; - print "ac_dir_suffix = $ac_dir_suffix\n"; - } - $srcdir = "$ac_dots$ac_given_srcdir$ac_dir_suffix"; - $top_srcdir = "$ac_dots$ac_given_srcdir"; - } +make-makefile - Generate a Makefile from a F template - if ($debug) { - print "ac_dir = $ac_dir\n"; - print "ac_file = $ac_file\n"; - print "ac_file_in = $ac_file_in\n"; - print "srcdir = $srcdir\n"; - print "top_srcdir = $top_srcdir\n"; - print "cwd = " . `$pwdcmd` . "\n"; - } +=head1 SYNOPSIS - # Copy the file and make substitutions. - # @srcdir@ -> value of $srcdir - # @top_srcdir@ -> value of $top_srcdir - # - if (-e $ac_file) { - next if -M _ < -M $ac_file_in; # Next if Makefile is up-to-date. - warn "updating $ac_file\n"; - } else { - warn "creating $ac_file\n"; - } +make-makefile [--top t] [--obj o] [--depth d] foo/bar/Makefile.in tans/fans/Makefile foo/bar - open INFILE, "<$ac_file_in" or do { - warn "$0: Cannot read $ac_file_in: No such file or directory\n"; - next; - }; - open OUTFILE, ">$ac_file" or do { - warn "$0: Unable to create $ac_file\n"; - next; - }; +=head1 DESCRIPTION - while () { - #if (/\@[_a-zA-Z]*\@.*\@[_a-zA-Z]*\@/) { - # #warn "Two defines on a line:$ac_file:$.:$_"; - # push @unhandled, $ac_file; - # last; - #} +Given options and makefile path arguments determine path to the template +F beneath a source directory and path to generated F +beneath $MOZ_OBJDIR. DEPTH from destination directory to the 'root' will +also be determined. F will be read in, template strings of the +gorm @token@ will be replaced with derived values and a generated makefile +will be written out as F. - s/\@srcdir\@/$srcdir/g; - s/\@top_srcdir\@/$top_srcdir/g; +Makefile DEPTH= can be determined in a few different ways: + o The string C may be embedded within F. + o Search parent directories for F and use it to assign the child. - if (/\@[_a-zA-Z]*\@/) { - #warn "Unknown variable:$ac_file:$.:$_"; - push @unhandled, $ac_file; - last; - } - print OUTFILE; - } - close INFILE; - close OUTFILE; - } - return @unhandled; -} -sub run_config_status { - my @unhandled = @_; +=head2 Option List - # Run config.status with any unhandled files. - # - if (@unhandled) { - $ENV{CONFIG_FILES}= join ' ', @unhandled; - system "./config.status"; - } -} +=over 4 + +=item --chdir + +Move to this directory before doing anything else + +=item -d, --depth + +Explicitly specify the relative path from directory containing Makefile.in +to the top sandbox directory. memory/makefile, DEPTH=../.., js/src/config, DEPTH=.. + +=item --enhanced + +Use alternate/simplified path construction when options --top and --obj are +passed. This feature will be used by container makefiles to support makefile +generation while cd'd into the sandbox top directory. + +=item -t, --top + +Path the root of a development sandbox. + +=item --obj + +Path to object directory where generated makefile will be written ($MOZ_OBJDIR). + +=item --ptop + +Print top source dir + +=back + + +=head2 Options List DEBUG + +=over 4 + +=item --bench + +Enable script benchmarking, report elapsed runtime. + +=item --debug + +Enable script debug mode. + +=back + + +=head2 Options List --NO- + +=over 4 + +=item --no-badtokens (wip) + +Handle unexpanded @token@ makefile tokens as an error condition. +Do not rely on system(config.status) to externally supply values. + +=item --no-excludes + +Ignore file entries on the exclusion list, generate everything. + +=item --no-warnings + +Warnings are handled as an error condition. + +=back + + +=head2 Examples + +=over 4 + +=item * make-makefile -t /mozilla/nightly -d . memory/mozalloc + +cd $MOZ_OBJDIR; +--top and --depth are explicitly set for generting memory/mozalloc/Makefile. + +=item * make-makefile -t /mozilla/nightly -d ../../../.. html5lib_tree_construction/Makefile + +cd $MOZ_OBJDIR/parser/htmlparser/tests/mochitest + +--top and --depth are explicitly set for generting a makefile from within +a subdirectory of $MOZ_OBJDIR + +=item * make-makefile --top /mozilla/nightly --obj /mozilla/nightly/obj memory/mozalloc + +With --top and --obj explicitly set generate $MOZ_OBJDIR/memory/mozalloc/Makefile +while sitting in the sandbox root. + +=back + + +=head2 Work In Progress + +=over 4 + +=item --no-badtokens + +Fail on unexpanded @foo@ makefile tokens. Any tokens that can be expanded +directly by make-makefile will avoid config.status shell overhead. + +=item Depth from delta(--obj, --top) + +If DEPTH= has not been embedded within a makefile the value could +be set directly if --top and --obj are specified and the paths overlap. + +=back + + +=head1 SEE ALSO + +L + +=cut diff --git a/build/autoconf/make-makefile.excl b/build/autoconf/make-makefile.excl new file mode 100644 index 000000000000..25ab32dd267e --- /dev/null +++ b/build/autoconf/make-makefile.excl @@ -0,0 +1,5 @@ +########################################################################### +## Intent: Exclusion list for container make builds +########################################################################### + +# EOF diff --git a/build/autoconf/makemakefile.pm b/build/autoconf/makemakefile.pm new file mode 100644 index 000000000000..6eafbce4fcaa --- /dev/null +++ b/build/autoconf/makemakefile.pm @@ -0,0 +1,745 @@ +package makemakefile; + +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1999-2011 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Steve Lamm +# Joey Armstrong +# +# Alternatively, the contents of this file may be used under the terms of +# either of the GNU General Public License Version 2 or later (the "GPL"), +# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +##----------------------------## +##---] CORE/CPAN INCLUDES [---## +##----------------------------## +use strict; +use warnings; +# use feature 'state'; 5.10+ not available everywhere + +##-------------------## +##---] EXPORTS [---## +##-------------------## +our $VERSION = qw(2.0); +use Exporter; +our @ISA = qw(Exporter); +our @EXPORT = qw(dirname_legacy + getConfig getDepth getRelPath getObjDir getTopDir mkdirr + getExclusions + run_config_status + updateMakefiles + update_makefiles_legacy + ); + +##--------------------## +##---] INCLUDES [---## +##--------------------## +use Cwd; +use Cwd qw{abs_path}; +use FindBin; +use File::Basename; +use File::Copy; + +##-------------------## +##---] GLOBALS [---## +##-------------------## +umask 0; +my $cwd = Cwd::abs_path('.'); +my %argv; + + +########################################################################### +## Intent: Helper function, retrieve contents of a file with error checking +## ----------------------------------------------------------------------- +## Args: +## scalar path to input file +## Returns: +## array contents of the given file +## $@ set on error +########################################################################### +sub cat +{ + my $fyl = shift || ''; + $@ = ''; + my @data; + + local *FYL; + if (!open(FYL, $fyl)) + { + $@ = "open($fyl) failed: $!"; + } + else + { + @data = ; + close(FYL); + } + return @data; +} # cat + +########################################################################### +## Intent: Return directory path for a given argument +## ----------------------------------------------------------------------- +## ----------------------------------------------------------------------- +## Todo: +## o Check if function can be replaced by File::Basename::dirname() +########################################################################### +sub dirname_legacy +{ + my $str = (@_ && defined($_[0])) ? shift : ''; + return $str =~ /(.*)\/.*/ ? "$1" : '.'; +} + +########################################################################### +## Intent: Given a list of makefile paths recursively create all +## directories between file and the root +## ----------------------------------------------------------------------- +## Args: +## array A list of makefiles +## fargs Function arguments +## mode Filesystem mode used for directory creation +## Returns: +## $@ Set on error +## 0 on success +## ----------------------------------------------------------------------- +## Note: +## Reporting directory creation can be enabled by the --verbose +## command line argument. +########################################################################### +sub mkdirr +{ + my %fargs = (@_ && ref($_[$#_])) ? %{ (pop) } : (); + my $mode = $fargs{mode} || 0755; + my $verbose = $main::argv{verbose} || 0; + $@ = '' unless ($fargs{recursive}); + $fargs{recursive} = 1; + + my @errors; + push(@errors, $@) if ($@); + foreach my $path (@_) + { + (my $dir = $path) =~ s%/?Makefile[^/]*$%%o; + next unless (length($dir)); + next if (-e $dir); + mkdirr( dirname($dir), \%fargs); + eval{ File::Path::mkpath($dir, $verbose, 0755); }; + push(@errors, $@) if ($@); + } + $@ = join("\n", @errors); + return $@ ? 0 : 1; +} # mkdirr + +########################################################################### +## Intent: Read in configure values and return a hash of key/value pairs +## ----------------------------------------------------------------------- +## Args: +## fargs Function arguments +## reset clear value storage and repopulate +## Returns: +## hash configure data to use for makefile substitutions +## ----------------------------------------------------------------------- +## Todo: wrapper for reading config* and run_config_status +########################################################################### +my %_CONFIG_; # todo: state %config; w/5.10 +sub getConfig +{ + my %fargs = (@_ && ref($_[$#_]) eq 'HASH') ? %{ (pop) } : (); + if ($fargs{reset}) + { + %_CONFIG_ = (); + shift; + } + + #my $ac_file_in = "$ac_given_srcdir/${ac_file}.in"; + #my $ac_dir = dirname_legacy($ac_file); + #my $ac_dots = ''; + #my $ac_dir_suffix = ''; + #my $srcdir = '.'; + #my $top_srcdir = '.'; + unless (%_CONFIG_) + { + while (@_) + { + my ($k, $v) = splice(@_, 0, 2); + $_CONFIG_{$k} = $v; + } + } + + return %_CONFIG_; +} # getConfig + +########################################################################### +## Intent: Determine path depth between leaf and root directory. +## o DEPTH= may be set by makefile content +## o DEPTH= may be set by Makefile in a parent +## o Manually determine by relpath form leaf to sandbox top +## ----------------------------------------------------------------------- +## Args: +## scalar Path to makefile or directory to determine DEPTH for +## Returns: +## scalar Relative path from leaf to root directory +## ----------------------------------------------------------------------- +########################################################################### +sub getDepth($) +{ + my $fyl = shift || ''; + + my @path = split(m%/%o, $fyl); + pop(@path) if ('Makefile' eq substr($path[$#path], 0, 8)); + my $depth; + my @depth; + + my $top = getTopDir(); + my @top = split(m%/%o, $top); + my @pathNoTop = @path; + splice(@pathNoTop, 0, scalar(@top)); + + SEARCH: + while (@path) + { + ## Search for a file containing DEPTH=../.. + foreach my $fyl ( qw{Makefile.in Makefile} ) + { + my $path = join('/', @path, $fyl); + local *FYL; + if (!open(FYL, $path)) {} # NOP + elsif (my @tmp = map{ /^\s*DEPTH\s*=\s*([\.\/]+)/o ? $1 : () } ) + { + $depth = join('/', @depth, shift @tmp); + last SEARCH; + } + close(FYL); + } + pop @path; + pop @pathNoTop; + + if (0 == scalar(@pathNoTop)) + { + $depth = join('/', @depth); + last; + } + + ## Construct path manually + push(@depth, '..'); + } + return $depth; +} # getDepth + +########################################################################### +## Intent: Read in the exclusion file +########################################################################### +sub getExclusions +{ + my $file = shift || ''; + + return () if ($main::argv{'no-exclusions'}); + + my %exclude; + if ($file) + { + my @data = cat($file); + foreach (@data) + { + next unless ($_); + next if (/^\s*\#/o); + next unless (m%/%); + chomp; + $exclude{$_}++; + } + } + return %exclude; +} # getExclusions + +########################################################################### +## Intent: Given the path to a makefile beneath either src or obj +## derive the relative path prefix between makefile and root. +########################################################################### +sub getRelPath +{ + my $path0 = shift; + my $abspath; + + # Determine type and orientation + my $name = basename($path0); + my $haveMF = ($name eq 'Makefile.in') ? 1 + : ($name eq 'Makefile') ? -1 + : 0 + ; + + #################################################### + ## Prep work: form a relative path with ../ removed + #################################################### + my $top = getTopDir(); + my $obj = getObjDir(); + ## If the same Makefile will be created alongside Makefile.in + my $topQM = quotemeta($top); + my $objQM = quotemeta($obj); + + if ('..' eq substr($path0, 0, 2)) + { + my @cwd = split(m%/%, $cwd); + my @pth = split(m%/%, $path0); + while (@pth && $pth[0] eq '..') + { + pop(@cwd); + shift @pth; + } + $path0 = join('/', @cwd, @pth); + $abspath = $path0; + } + + if ('/' eq substr($path0, 0, 1)) + { + $path0 =~ s%^$objQM\/?%%; + $path0 =~ s%^$topQM\/?%%; + } + + ####################################################################### + ## Build a list of directories to search. Input source will be one + ## of path to Makefile.in, path to Makefile, directory, file within + ## a directory or relative path from cwd. + ####################################################################### + my @subdirs; + my $path = (0 == $haveMF) ? $path0 : dirname($path0); + push(@subdirs, $path); # containing directory + push(@subdirs, dirname($path)) if (0 == $haveMF && -f $path); # Arg is file within a directory + push(@subdirs, $cwd); # relative to pwd + + # obj - path to generated makefile + # top - path to Makefile.in source template + my @prefixes = ('/' ne substr($path0, 0, 1)) + ? (&getTopDir, &getObjDir) + : () + ; + + ON_SAFARI: + for my $prefix (@prefixes) + { + next unless ($prefix); # no command line not passed + foreach my $subdir (@subdirs) + { + foreach my $mf ('Makefile.in', 'Makefile') + { + my $path = join('/', $prefix, $subdir, $mf); + if (-e $path) + { + $name = $mf; + $haveMF = ($mf eq 'Makefile.in') ? 1 : -1; + $abspath = $path; + last ON_SAFARI; + } + } + } + } + + ####################################################################### + ## Generated makefile does not yet exist or path is invalid. + ## Should this conditon be handled to detect non-existent Makefile.in: + ## Makefile.am => Makefile.in => Makefile but Makefile.in + ####################################################################### + if (!$abspath && -1 == $haveMF && $obj) + { + $abspath = ('/' eq substr($path0, 0, 1)) + ? $path0 + : join('/', $obj, $path0) + ; + } + + ######################################################## + ## If --top and/or --obj specified extract relative path + ######################################################## + my $relpath; + if (! $abspath) + { + # Error, fall through + } + elsif (1 == $haveMF) # Makefile.in + { + ## err w/o --top + (my $tmp = $abspath) =~ s%^$topQM/?%%; + $relpath = dirname($tmp) unless ($tmp eq $abspath); + } + elsif (-1 == $haveMF) # Makefile + { + ## err w/o --obj + (my $tmp = $abspath) =~ s%^$objQM/?%%; + $relpath = dirname($tmp) unless ($tmp eq $abspath); + } + + $relpath ||= ''; + $relpath =~ s%/./%/%og; # filter ./ + + $@ = ($relpath) ? '' : "ERROR($path0): Unable to locate sources"; + return $relpath || ''; +} # getRelPath + +########################################################################### +## Intent: Determine sandbox root from script startup directory +## ----------------------------------------------------------------------- +## Args: +## _set_ optional, if passed use the given value as path +## _reset_ clear cached directory path to reassign +## Returns: +## scalar - absolute path to the sandbox root directory +## ----------------------------------------------------------------------- +########################################################################### +my $gtd_dir; +sub getTopDir +{ + if (@_) # testing override + { + $gtd_dir = abs_path($_[1] || '.') if ($_[0] eq '_set_'); + $gtd_dir = '' if ($_[0] eq '_reset_'); + } + + unless ($gtd_dir) + { + ## Set by command line + if ($main::argv{top}) + { + $gtd_dir = $main::argv{top}; + } + else + { + my $path = abs_path($FindBin::RealBin); + my @path = split(m%/%o, $path); + ## --2 memory/mozalloc/Makefile.in + ## --3 was this for FindBin::Script ? + splice(@path, -2); + $gtd_dir = join('/', @path); + } + } + return $gtd_dir; +} # getTopDir + +########################################################################### +## Intent: Determine path to MOZ_OBJDIR/object directory +## ----------------------------------------------------------------------- +## Args: +## _set_ optional testing arg, if passed re-compute cached value +## Returns: +## scalar - absolute path to the sandbox object directory +## ----------------------------------------------------------------------- +########################################################################### +my $god_dir; +sub getObjDir +{ + if (@_) # testing override + { + if ($_[0] eq '_reset_') + { + $god_dir = ''; + shift; + } + elsif ($_[0] eq '_set_') + { + shift; + my $path = $_[0] || '.'; + $god_dir = abs_path($path); + shift; + } + } + + ## extract $obj from given path + unless ($god_dir) + { + if ($main::argv{obj}) + { + $god_dir = $main::argv{obj}; + } + elsif (@_ && 'Makefile' eq substr($_, -8)) + { + $god_dir = abs_path(shift); + } + else # assume we are sitting in moz_objdir + { + $god_dir = abs_path('.'); + } + } + + return $god_dir; +} # getObjDir + +########################################################################### +## Intent: Generate Makefile from a given Makefile.in template +## ----------------------------------------------------------------------- +## Args: +## scalar Relative path to a directory containing a makefile +## fargs Hash ref of function arguments. +## obj Absolute path to MOZ_OBJ/a destination directory +## top Absolute path to the sandbox root +## Returns: +## $@ Set on error +## scalar +## 1 True if the makefile was updated +## 0 Otherwise +## badtokens - If the makefile contains unexpandable @token@ strings +## ----------------------------------------------------------------------- +########################################################################### +sub updateMakefiles +{ + my %fargs = (@_ && ref($_[$#_])) ? %{ (pop) } : (); + local $_; + $@ = ''; + + my $top = $fargs{top}; + my $obj = $fargs{obj}; + + my $relpath = shift || ''; + my $src = join('/', $top, $relpath, 'Makefile.in'); + my $depth = getDepth($src); + + my @src = cat($src); + return 0 if ($@); + + my $dst = join('/', $obj, $relpath, 'Makefile'); + my @dst = cat($dst); + $@ = ''; + + my $dstD = dirname($dst); + mkdirr($dstD); + return 0 if ($@); + + my %data = + ( getConfig(), + depth => $depth, + srcdir => join('/', $top, $relpath), + top_srcdir => $top, + ); + + my $line = 0; + my @data; + while (scalar @src) + { + $line++; + $_ = shift(@src); + + ## Expand embedded @foo@ + while (/\@[^\@\s\$]+\@/go) + { + my $end = pos($_); + my $val = $&; + my $len = length($val); + $val =~ s/^\@\s*//o; + $val =~ s/\s*\@$//o; + + ## Identify expansions to see if we can avoid shell overhead + if (!defined $data{$val} && !$argv{'no-badtokens'}) + { + if (1) # warnings + { + print STDERR "WARNING: token $val not defined\n"; + print STDERR " line $line, src: $src\n"; + } + return 'badtokens'; + } + + # Insert $(error txt) makefile macros for invalid tokens + my $val1 = defined($data{$val}) + ? $data{$val} + : "\$(error $FindBin::Script: variable ${val} is undefined)" + ; + substr($_, ($end-$len), $len, $val1); + } + push(@data, $_); + } + + if (("@data" eq "@dst") && scalar(@data)) + { + print "Skipping up2date makefile: $dst\n" if ($argv{verbose}); + } + else + { + my $action = (scalar @dst) ? 'Updating' : 'Creating'; + print "$action makefile: $dst\n"; + + my $tmp = join('.', $dst, "tmp_$$"); + if (!open(FYL, "> $tmp")) + { + $@ = "open($tmp) failed: $!"; + } + else + { + print FYL @data; + close(FYL); + + ## Install the new makefile + File::Copy::move($tmp, $dst) + || ($@ = "move($tmp, $dst) failed: $!"); + } + } + + return $@ ? 0 : 1; +} # updateMakefiles + +# Output the makefiles. +# +sub update_makefiles_legacy { + my ($ac_given_srcdir, $pac_given_srcdir, @makefiles) = @_; + my $debug = $main::argv{debug} || 0; + my $pwdcmd = ($^O eq 'msys') ? 'pwd -W' : 'pwd'; + my @unhandled=(); + + my @warn; + + my $ac_file; + foreach $ac_file (@makefiles) { + my $ac_file_in = "$ac_given_srcdir/${ac_file}.in"; + my $ac_dir = dirname_legacy($ac_file); + my $ac_dots = ''; + my $ac_dir_suffix = ''; + my $srcdir = '.'; + my $top_srcdir = '.'; + + # Determine $srcdir and $top_srcdir + # + if ($ac_dir ne '.') { + $ac_dir_suffix = "/$ac_dir"; + $ac_dir_suffix =~ s%^/\./%/%; + $ac_dots = $ac_dir_suffix; + # Remove .. components from the provided dir suffix, and + # also the forward path components they were reversing. + my $backtracks = $ac_dots =~ s%\.\.(/|$)%%g; + while ($backtracks--) { + $ac_dots =~ s%/[^/]*%%; + } + $ac_dots =~ s%/[^/]*%../%g; + } + if ($ac_given_srcdir eq '.') { + if ($ac_dots ne '') { + $top_srcdir = $ac_dots; + $top_srcdir =~ s%/$%%; + } + } elsif ($pac_given_srcdir =~ m%^/% or $pac_given_srcdir =~ m%^.:/%) { + $srcdir = "$pac_given_srcdir$ac_dir_suffix"; + $top_srcdir = "$pac_given_srcdir"; + } else { + if ($debug) { + print "ac_dots = $ac_dots\n"; + print "ac_dir_suffix = $ac_dir_suffix\n"; + } + $srcdir = "$ac_dots$ac_given_srcdir$ac_dir_suffix"; + $top_srcdir = "$ac_dots$ac_given_srcdir"; + } + + if ($debug) { + print "ac_dir = $ac_dir\n"; + print "ac_file = $ac_file\n"; + print "ac_file_in = $ac_file_in\n"; + print "srcdir = $srcdir\n"; + print "top_srcdir = $top_srcdir\n"; + print "cwd = " . `$pwdcmd` . "\n"; + } + + # Copy the file and make substitutions. + # @srcdir@ -> value of $srcdir + # @top_srcdir@ -> value of $top_srcdir + # + if (-e $ac_file) { + next if -M _ < -M $ac_file_in; # Next if Makefile is up-to-date. + warn "updating $ac_file\n"; + } else { + warn "creating $ac_file\n"; + } + + mkdirr(dirname($ac_file)); + + open INFILE, "<$ac_file_in" or do { + warn "$0: Cannot read $ac_file_in: No such file or directory\n"; + next; + }; + open OUTFILE, ">$ac_file" or do { + warn "$0: Unable to create $ac_file\n"; + next; + }; + + while () { + s/\@srcdir\@/$srcdir/g; + s/\@top_srcdir\@/$top_srcdir/g; + + if (/\@[_a-zA-Z]*\@/) { + #warn "Unknown variable:$ac_file:$.:$_"; + push @unhandled, $ac_file; + last; + } + print OUTFILE; + } + close INFILE; + close OUTFILE; + } + return @unhandled; +} # update_makefiles_legacy + +########################################################################### +## Intent: Invoke config.status for unknown makefiles to create +## directory hierarchy for the tree. +## ----------------------------------------------------------------------- +## Args: +## array an optional list of makefiles to process +## Returns: +## 0 on success +## $# set on error +## ----------------------------------------------------------------------- +## Note: Is this function needed anymore ? Undefined tokens should fail +## at time of expansion rather than having to source config.status. +## Also config.status could be parsed to define values and avoide the +## shell overhead altogether. +########################################################################### +sub run_config_status { + my @unhandled = @_; + + # Run config.status with any unhandled files. + # + my @errors; + if (@unhandled) { + local $ENV{CONFIG_FILES}= join ' ', @unhandled; + + my $conf = 'config.status'; + if (! -e $conf) # legacy behavior, warn rather than err + { + my $cwd = cwd(); + my $err = "$FindBin::Script ERROR: Config file $conf does not exist, cwd=$cwd"; + push(@errors, $err); + } + elsif (0 != system("./config.status")) + { + my $cwd = cwd(); + push(@errors, "config.status failed \$?=$?, \$!=$!, cwd: $cwd"); + } + } + $@ = join("\n", @errors); + + ## Legacy behavior: config.status problems are not fatal {yet}. + ## Display warning since caller will not be calling die. + warn $@ if ($@ && $argv{'no-warnings'}); + return $@ ? 1 : 0; +} + +1; diff --git a/build/autoconf/test/Makefile.in b/build/autoconf/test/Makefile.in new file mode 100644 index 000000000000..f1621ba7c48d --- /dev/null +++ b/build/autoconf/test/Makefile.in @@ -0,0 +1,94 @@ +# -*- makefile -*- +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is Mozilla Foundation. +# Portions created by the Initial Developer are Copyright (C) 2011 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Joey Armstrong +# +# Alternatively, the contents of this file may be used under the terms of +# either of the GNU General Public License Version 2 or later (the "GPL"), +# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk +include $(topsrcdir)/config/rules.mk + +################################################## +## Gather a list of tests, generate timestamp deps +################################################## +TS=.ts +ifneq (,$(findstring check,$(MAKECMDGOALS))) + allsrc = $(wildcard $(srcdir)/*) + tests2run = $(notdir $(filter %.tpl,$(allsrc))) + tests2run += $(notdir $(filter %.tpm,$(allsrc))) + check_targets += $(addprefix $(TS)/,$(tests2run)) +endif + +all_nop: # export, libs and tools are not needed + +check:: $(TS) $(check_targets) + +############################################# +# Only invoke tests when sources have changed +############################################# +$(TS)/%: $(srcdir)/% + $(PERL) $(srcdir)/runtest $< + @touch $@ + +parent = $(patsubst %/,%,$(dir $(srcdir))) +$(TS)/make-makefile.tpl: \ + $(srcdir)/make-makefile.tpl\ + $(parent)/makemakefile.pm\ + $(NULL) + $(PERL) $(srcdir)/runtest $< + @touch $@ + +$(TS)/makemakefile.tpm: \ + $(srcdir)/makemakefile.tpm \ + $(parent)/makemakefile.pm \ + $(NULL) + $(PERL) $(srcdir)/runtest $< + @touch $@ + +##################################################### +## Extra dep needed to synchronize parallel execution +##################################################### +$(TS): $(TS)/.done +$(TS)/.done: + $(MKDIR) -p $(dir $@) + touch $@ + +GARBAGE_DIRS += $(TS) + +# EOF diff --git a/build/autoconf/test/data/mf.notokens b/build/autoconf/test/data/mf.notokens new file mode 100644 index 000000000000..6fc504413177 --- /dev/null +++ b/build/autoconf/test/data/mf.notokens @@ -0,0 +1,4 @@ +jsautocfg.h: jscpucfg$(HOST_BIN_SUFFIX) + @$(RM) $@ jsautocfg.tmp + ./jscpucfg > jsautocfg.tmp + mv jsautocfg.tmp $@ diff --git a/build/autoconf/test/data/mf.notokens.exp b/build/autoconf/test/data/mf.notokens.exp new file mode 100644 index 000000000000..6fc504413177 --- /dev/null +++ b/build/autoconf/test/data/mf.notokens.exp @@ -0,0 +1,4 @@ +jsautocfg.h: jscpucfg$(HOST_BIN_SUFFIX) + @$(RM) $@ jsautocfg.tmp + ./jscpucfg > jsautocfg.tmp + mv jsautocfg.tmp $@ diff --git a/build/autoconf/test/make-makefile.excl b/build/autoconf/test/make-makefile.excl new file mode 100644 index 000000000000..e65b133454b8 --- /dev/null +++ b/build/autoconf/test/make-makefile.excl @@ -0,0 +1,8 @@ +########################################################################### +## Intent: Exclusion list for container make builds +########################################################################### + +/dev/null +/foo/bar +/a/b/c +/a/b/d diff --git a/build/autoconf/test/make-makefile.tpl b/build/autoconf/test/make-makefile.tpl new file mode 100644 index 000000000000..22108d238636 --- /dev/null +++ b/build/autoconf/test/make-makefile.tpl @@ -0,0 +1,436 @@ +#!/usr/bin/env perl +########################################################################### +## Intent: Unit test to verify make-makefile.tpl +########################################################################### + +##----------------------------## +##---] CORE/CPAN INCLUDES [---## +##----------------------------## +use strict; +use warnings; +#use feature 'state'; # 5.10+ not installed everywhere +use Getopt::Long; + +use Cwd; +use Cwd qw{abs_path}; +use File::Basename; +use File::Copy; +use File::Path; +use File::Temp qw{ tempdir }; + +use Test; +sub BEGIN { plan tests => 4 }; +my @workdirs; +sub END { system("/bin/rm -fr @workdirs"); } # cleanup behind interrupts + +##-------------------## +##---] EXPORTS [---## +##-------------------## +use FindBin; +our $VERSION = qw(1.0); + +##------------------## +##---] INCLUDES [---## +##------------------## +use FindBin; +use lib "$FindBin::RealBin/.."; +use makemakefile; + +##-------------------## +##---] GLOBALS [---## +##-------------------## +my %argv; + +########################################################################### +## Intent: Create a temp sandbox populated with sources +## ----------------------------------------------------------------------- +## Args: +## array a list of file paths to copy +## Returns: +## $@ set on error +## scalar path to scratch sandbox +## ----------------------------------------------------------------------- +########################################################################### +my $root; # state $root not available +sub createSandbox +{ + my @errors; + + unless ($root) + { + my @tmp = split(m%/%, $FindBin::RealBin); + splice(@tmp, -3); + $root = join('/', @tmp); + } + + my $work = tempdir(); + push(@workdirs, $work); + my @dirs = map{ join('/', $work, dirname($_)) } @_; + mkdirr(@dirs); + push(@errors, "createSandbox: $@") if ($@); + + foreach (@_) + { + ## Copy sources into the temp source directory + my $src = join('/', $root, $_); + my $dst = join('/', $work, $_); + unless (copy($src, $dst)) + { + push(@errors, "copy($src, $dst) failed: $!"); + } + } + print STDERR "createSandbox: $work\n" if ($main::argv{debug}); + $@ = join('', map{ "$_\n" } @errors); + $work; +} # createSandbox + +########################################################################### +## Intent: wrapper to run the make-makefile command. +## ----------------------------------------------------------------------- +## Args: +## array command line arguments passed to make-makefile +## Returns: +## array command output +## $@ set by shell exit status, empty string on success +## $? command shell exit status +########################################################################### +my $mm; # state $mm not available +sub makemakefile +{ + my %fargs = (@_ && ref($_[$#_])) ? %{ (pop) } : (); + $mm ||= join('/', dirname($FindBin::Bin), 'make-makefile'); # cmd in parent of test/ + my $cmd = join(' ', $mm, @_); + print "RUNNING: $cmd\n" if ($fargs{debug}); + my @out = `$cmd 2>&1`; + print STDERR map{ "out> $_" } @out if ($argv{verbose}); + $@ = (0 == $?) ? '' : "Command failed: $cmd\n@out"; + @out; +} # makemakefile + +########################################################################### +## Intent: Helper function, display the contents of a given sandbox +## ----------------------------------------------------------------------- +## Args: +## scalar Path to sandbox +## Returns: +## none +## ----------------------------------------------------------------------- +########################################################################### +sub find_ls +{ + my $path = shift || ''; + + # Assuming dot contributes to cryptic problems + die "find_ls: a path is required" unless ($path); + + my $cmd = "find $path -ls"; + print "\nRunning: $cmd\n"; + print '=' x 75, "\n"; + print `$cmd`; +} # myls + +########################################################################### +## Intent: Verify make-makefile is able to digest paths and generate +## makefiles when object directory is a child of top. +########################################################################### +sub check_makemakefile +{ + my $work = createSandbox + ( + 'memory/mozalloc/Makefile.in', + 'toolkit/system/windowsproxy/Makefile.in', + 'toolkit/crashreporter/google-breakpad/src/client/Makefile.in', + ); + + + my $workdir = createSandbox(); + my $top = $workdir; + chdir $top; + + my $objA = 'obj-arch-dir'; + my $obj = join('/', $top, $objA); + + # getTopDir() + local $main::argv{top} = $work; + local $main::argv{obj} = $obj; + getObjDir('_reset_'); + + my @root = split(m%/%, $FindBin::RealBin); + splice(@root, -3); + my $root = join('/', @root); + my @args = + ( + + [ + banner => "--top and --obj are impled, generate Makefile", + rel => 'memory/mozalloc', + cmd => join(' ', + '--top', $top, + '--obj', $obj, + 'memory/mozalloc/Makefile', + ), + ], + + [ + banner => "--top and abs(obj) passed", + rel => "toolkit/system/windowsproxy", + cmd => join(' ', + '--top', $top, + "$obj/toolkit/system/windowsproxy/Makefile", + ), + exp => "$obj/toolkit/system/windowsproxy/Makefile", + skip => 1, # + ], + + + [ + banner => "--obj and abs(top) passed", + rel => "toolkit/crashreporter/google-breakpad/src/client", + cmd => join(' ', + '--obj', $obj, + "$top/toolkit/crashreporter/google-breakpad/src/client/Makefile.in", + ), + exp => "$top/toolkit/crashreporter/google-breakpad/src/client/Makefile.in", + skip => 1, # + ], + + ); + + foreach (@args) + { + my %rec = @{ $_ }; + next if ($rec{skip}); + next unless ($rec{rel}); + + my $srcR = join('/', $top, $rec{rel}); + my $dstR = join('/', $obj, $rec{rel}); + + my $src = join('/', $top, $rec{rel}, 'Makefile.in'); + my $dst = join('/', $obj, $rec{rel}, 'Makefile'); + + # Use distinct sources to avoid cleanup overhead between tests + die "Test source already used: $dstR" if (-d $dstR); + + ## Copy sources into the temp source directory + my $rootR = join('/', $root, $rec{rel}); + my $rootS = join('/', $root, $rec{rel}, 'Makefile.in'); + File::Path::mkpath($srcR, 0, 0700); + copy($rootS, $src) or die "copy($rootS, $src) failed: $!"; + + die "source does not exist: $src" unless (-e $src); + + ###################### + ## Generate and verify + ###################### + print STDERR "RUNNING: $rec{banner}\n" if ($argv{debug}); + my @errs; + makemakefile('--enhanced', $rec{cmd}, {verbose=>1}); + if ($@) + { + push(@errs, "\$@ should not be set: $@\n"); + } + elsif (! -e $dst) + { + push(@errs, "Generated makefile does not exist: $dst, banner: $rec{banner}\n"); + } + + ok(scalar(@errs), 0, "Errors detected:\n" . join(" $_", @errs)); + find_ls($top) if (@errs); + } + +} # check_makemakefile + +########################################################################### +## Intent: Verify make-makefile is able to digest paths and generate +## makefiles when top/MOZ_OBJDIR are not parent/child directories +## --------------------------------------------------------------------------- +## Args: +## none +## Returns: +## none +## --------------------------------------------------------------------------- +########################################################################### +sub check_makemakefile_distinct +{ + my $workdir = createSandbox(); +# my $workdir = tempdir(); + + ############################################### + ## Now update when top/obj are not parent/child + ############################################### + my $top = join('/', $workdir, 'top'); + my $obj = join('/', $workdir, 'obj'); + + $main::argv{top} = $top; + $main::argv{obj} = $obj; # test afterward, using undef ? + + my @sbxroot = split(m%/%, $FindBin::RealBin); + splice(@sbxroot, -2); + my $sbxroot = join('/', @sbxroot); + + ## Copy in a makefile template to to convert + File::Path::mkpath(["$top/memory/mozalloc"], 0, 0700); + copy("$sbxroot/memory/mozalloc/Makefile.in", "$top/memory/mozalloc/Makefile.in"); + + + # work/memory/mozalloc/Makefile.in + + my @args = + ( + [ + banner => '--top and --obj are distinct [1]', + cmd => "--obj $obj memory/mozalloc/Makefile", + exp => "$obj/memory/mozalloc/Makefile", + ], + + [ + banner => "--top and --obj are distinct [2]", + cmd => "--top $top memory/mozalloc/Makefile.in", + exp => "$obj/memory/mozalloc/Makefile", + skip => 1, # test problem: top != obj + ], + + [ + banner => "--top and --obj are distinct [3]", + cmd => join(' ', + "--top $top", + "--obj $obj", + "memory/mozalloc/Makefile.in", + ), + exp => "$obj/memory/mozalloc/Makefile", + skip => 1, # test problem: top != obj + ], + ); + + + foreach (@args) + { + my %rec = @{ $_ }; + print STDERR "banner: $rec{banner}\n" if ($argv{debug}); + next if $rec{skip}; + + unlink $rec{exp}; + makemakefile('--enhanced', $rec{cmd}); + + my @errs; + if ($@) + { + push(@errs, "\$@ should not be set: $@\n"); + } + elsif (! -e $rec{exp}) + { + push(@errs, "Makefile does not exist: $rec{exp}\n"); + } + ok(scalar(@errs), 0, "Errors detected:\n" . join(" $_", @errs)); + } + +} # check_makemakefile_distinct + +########################################################################### +## Intent: Verify legacy behavior, invoke make-makefile when cwd is +## a subdirectory beneath MOZ_OBJDIR. +## ----------------------------------------------------------------------- +## Args: +## none +## Returns: +## none +## ----------------------------------------------------------------------- +########################################################################### +sub check_makemakefile_legacy +{ + my $work = createSandbox + ( + 'memory/mozalloc/Makefile.in', + 'parser/htmlparser/tests/mochitest/html5lib_tree_construction/Makefile.in', + ); + + my $obj = join('/', $work, 'obj'); + mkdir $obj; + + my @args = + ( + { + banner => '-t path -d dot', + cwd => $obj, + cmd => "-t $work -d . memory/mozalloc/Makefile", + exp => "$obj/memory/mozalloc/Makefile", + skip => 0, + }, + + { + banner => '-t path -d relpath', + cwd => join('/', $obj, 'parser/htmlparser/tests/mochitest'), + cmd => "-t $work -d ../../../.. html5lib_tree_construction/Makefile", + exp => "$obj/parser/htmlparser/tests/mochitest/html5lib_tree_construction/Makefile", + skip => 0, + }, + ); + + foreach (@args) + { + my %rec = %{ $_ }; + next if ($rec{skip}); + + ## make-make while sitting in $objdir + mkdirr($rec{cwd}); + chdir $rec{cwd} || die "chdir $rec{cwd} failed; $!"; + + makemakefile($rec{cmd}); + my @errs; + if ($@) + { + push(@errs, "make-makefile $rec{cmd} failed: $@"); + } + elsif (! -e $rec{exp}) + { + push(@errs, "generated makefile does not exist: $rec{exp}"); + } + ok(scalar(@errs), 0, "Errors detected: @errs"); + find_ls($work) if (@errs); + } + chdir $FindBin::RealBin; +} # check_makemakefile_legacy + +########################################################################### +## Intent: Smoke tests for the unittests module +########################################################################### +sub smoke +{ + print STDERR "Running test: smoke()\n" if ($argv{debug}); +} # smoke() + +########################################################################### +## Intent: Intitialize global test objects and consts +########################################################################### +sub init +{ + print "Running: init()\n" if ($argv{debug}); +# testplan(24, 0); +} # init() + +##----------------## +##---] MAIN [---## +##----------------## +unless(GetOptions(\%argv, + qw( + debug|d + manual + test=s@ + verbose + ))) +{ + print "USAGE: $0\n"; + print " --debug Enable script debug mode\n"; + print " --manual Also run disabled tests\n"; + print " --smoke Run smoke tests then exit\n"; + print " --test Run a list of tests by function name\n"; + print " --verbose Enable script verbose mode\n"; + exit 1; +} + +init(); +smoke(); + +check_makemakefile(); +check_makemakefile_distinct(); +check_makemakefile_legacy(); diff --git a/build/autoconf/test/makemakefile.tpm b/build/autoconf/test/makemakefile.tpm new file mode 100644 index 000000000000..efc99f20e97c --- /dev/null +++ b/build/autoconf/test/makemakefile.tpm @@ -0,0 +1,519 @@ +#!/usr/bin/env perl +########################################################################### +## Intent: Unit test to verify the makemakefile.pm module +########################################################################### + +##----------------------------## +##---] CORE/CPAN INCLUDES [---## +##----------------------------## +use strict; +use warnings; +#use feature 'state'; +use Getopt::Long; + +use FindBin; +use Cwd qw{abs_path}; +use File::Basename; +use File::Compare; +use File::Copy; +use File::Temp qw{tempdir}; + +use Test; +sub BEGIN { plan tests => 36 }; +my @workdirs; +sub END { system("/bin/rm -fr @workdirs"); } # cleanup behind interrupts + +##-------------------## +##---] EXPORTS [---## +##-------------------## +our $VERSION = qw(1.0); + +##------------------## +##---] INCLUDES [---## +##------------------## +use FindBin; +use lib "$FindBin::RealBin/.."; +use makemakefile; + +##-------------------## +##---] GLOBALS [---## +##-------------------## +my %argv; + +########################################################################### +## Intent: Create a temp sandbox populated with sources +## ----------------------------------------------------------------------- +## Args: +## array files to copy into the temporary sandbox +## Returns: +## $@ set on error +## array +## top - path to temp sandbox root +## obj - path to temp sandbox moz_obj directory +## ----------------------------------------------------------------------- +########################################################################### +my $_root_; # state $root +sub createSandbox +{ +# state $root; + my @errors; + + unless ($_root_) + { + my @tmp = split(m%/%, $FindBin::RealBin); + splice(@tmp, -3); + $_root_ = join('/', @tmp); + } + + my $work = tempdir(CLEANUP=>1); + push(@workdirs, $work); + my @dirs = map{ join('/', $work, dirname($_)) } @_; + mkdirr(@dirs); + push(@errors, "createSandbox: $@") if ($@); + + foreach (@_) + { + ## Copy sources into the temp source directory + my $src = join('/', $_root_, $_); + my $dst = join('/', $work, $_); + unless (copy($src, $dst)) + { + push(@errors, "copy($src, $dst) failed: $!"); + } + } + print STDERR "createSandbox: $work\n" if ($main::argv{debug}); + $@ = join('', map{ "$_\n" } @errors); + $work; +} # createSandbox + +########################################################################### +## Intent: Verify legacy dirname function +########################################################################### +sub check_dirname_legacy +{ + print "Running: check_dirname_legacy\n" if ($main::argv{debug}); + + foreach ( + ['/dev/null', '/dev'], + ['/foo/bar/Makefile', '/foo/bar'], + ) + { + my ($src, $exp) = @{ $_ }; + my $dir = dirname_legacy($src); + ok($dir, $exp, "dirname_legacy($src) failed"); + } + + my $path = dirname_legacy(undef); + ok($path ? 1 : 0, 1, "dirname('') should expand to cwd"); +} # check_dirname_legacy + +########################################################################### +## Intent: Verify topdir lookup function +########################################################################### +sub check_getTopDir +{ + print "Running: check_getTopDir\n" if ($main::argv{debug}); + + my $path = getTopDir(); + + ## Unit test is special, cmd not invoked from the same directory + ## as the makemakefile.pm module. + ok($path ? 1 : 0, 1, "getTopDir failed"); + ok(-d $path ? 1 : 0, 1, "getTopDir: directory $path does not exist"); + ok($FindBin::RealBin =~ m%$path/% ? 1 : 0, 1, 'Invalid topdir path'); + ok(-e "$path/client.mk" ? 1 : 0, 1, "client.mk not found in $path"); +} # check_getTopDir + +########################################################################### +## Intent: Verify objdir lookup function +########################################################################### +sub check_getObjDir +{ + print "Running: check_getObjDir\n" if ($main::argv{debug}); + local $main::argv{obj} = '/bin'; + my $path = getObjDir('_reset_'); + ok($path ? 1 : 0, 1, "getObjDir failed"); + ok(-d $path ? 1 : 0, 1, "getObjDir: directory $path does not exist"); + + my $top = getTopDir(); + $main::argv{obj} = join('/', $top, 'browser'); # use existing path so file can be resolved + my $obj = getObjDir('_reset_'); + ok($top ne $obj ? 1 : 0, 1, "top and object directory paths should not match"); + + ## If we fail for /bin use here getObjDir() was not reset + my $client = join('/', $obj, '..', 'client.mk'); + ok(-e $client ? 1 : 0, 1, "client.mk not found in parent of $path, $client"); + getObjDir('_set_'); # clear cached value and recompute + + foreach my $file ("$top/memory/mozalloc/Makefile") + { + my $obj = getObjDir('_reset_', $file); + ok($obj ne $file ? 1 : 0, 1, "getObjDir($file) failed") + } +} # check_getObjDir + +########################################################################### +## Intent: Verify rel-path-to-root/getdepth function +########################################################################### +sub check_getDepth +{ + my @tmp = split(m%/%o, $FindBin::Bin); + splice(@tmp, -3); + my $root = abs_path( join('/', @tmp) ); + + my %data = + ( + $root => '.', + join('/', $root, 'netwerk/Makefile.in') => '..', + + join('/', $root, 'browser/components/privatebrowsing/test/browser/Makefile.in') => '../../../../..', + join('/', $root, 'browser/components/privatebrowsing/test/browser/') => '../../../../..', + join('/', $root, 'browser/components/privatebrowsing/test/browser') => '../../../../..', + join('/', $root, 'browser/components/privatebrowsing/test') => '../../../..', + ); + + while (my($k, $v) = each %data) + { + my $depth = makemakefile::getDepth($k); + ok($depth, $v, "getDepth($k) failed"); + } +} # check_getDepth + +########################################################################### +## Intent: Verify reading the exclusion file +########################################################################### +sub check_getExclusions +{ + my $cfg = join('/', $FindBin::RealBin, 'make-makefile.excl'); + my %excl = getExclusions($cfg); + ok($@, '', '$@ should not be set'); + + my @excl = sort keys %excl; + ok(scalar @excl, 4, "Exclusion file is invalid: \@excl=@excl"); +} # check_getExclusions + +########################################################################### +## Intent: Verify rel-path-to-root function +## ----------------------------------------------------------------------- +## Args: +## none +## Returns: +## none +## ----------------------------------------------------------------------- +## Note: +## String test only, top and obj paths are bogus for this test +########################################################################### +sub check_getRelPath +{ + my @tmp = split(m%/%o, $FindBin::Bin); + splice(@tmp, -3); + my $root = abs_path( join('/', @tmp) ); + my $obj0 = 'obj-arch'; + my $obj = join('/', $root, $obj0); + + local $main::argv{top} = $root; + local $main::argv{obj} = $obj; + getTopDir('_reset_'); + getObjDir('_set_', $obj); + + ## Cannot test relative paths with objdir beneath /tmp + ## Commented paths are needed for full test coverage + ## but are not currently supported by all module functions. + my %data = + ( + # Relative - path correct for build directory but + 'profile/dirserviceprovider/public/Makefile.in' => 'profile/dirserviceprovider/public', + + join('/', $root, 'profile/dirserviceprovider/public/Makefile.in') => 'profile/dirserviceprovider/public', + + # File search + 'profile/dirserviceprovider/public' => 'profile/dirserviceprovider/public', + + # cwd + cleanup + # '../../../profile/dirserviceprovider/public/Makefile.in' => 'profile/dirserviceprovider/public', +# "../../../${obj0}/profile/dirserviceprovider/public/Makefile.in" => 'profile/dirserviceprovider/public', + + ## Special case: This could be handled but permutations of non-existent files, non-overlapping paths + ## and relative paths containing partial subdirectories will compilicate the logic. Wait until needed. + ## Relative path: $root + obj + subdir +# "${obj0}/profile/dirserviceprovider/public/Makefile" => 'profile/dirserviceprovider/public', + join('/', $obj, 'profile/dirserviceprovider/public/Makefile') => 'profile/dirserviceprovider/public', + + # $RealBin, -d ../../.. + # top and obj not subdirectories of each other: /foo/x, /bar/y + ); + + while (my($k, $v) = each %data) + { + my $dir = getRelPath($k); + ok($@, '', '$@ should not be set'); + ok($dir, $v, "ERROR[$k]: exp[$v] != found=[$dir]"); + } + + + my $top = '/tmp/foo'; + my $tmp = '/tmp/bar'; + local $main::argv{top} = $tmp; + local $main::argv{obj} = $obj; + + %data = + ( +# "$top/profile/dirserviceprovider/public/Makefile.in" => 'profile/dirserviceprovider/public', + "$obj/profile/dirserviceprovider/public/Makefile" => 'profile/dirserviceprovider/public', + ); + + while (my($k, $v) = each %data) + { + my $dir = getRelPath($k); + ok($dir, $v, "ERROR[$k]: exp[$v] != found=[$dir]"); + } +} # check_getRelPath + +########################################################################### +## Intent: Verify rel-path-to-root directory creation +########################################################################### +sub check_mkdirr +{ + if (-w '/bin') # cygwin may be writable + { + ok(1, 1, 'bogus test to maintain count'); + } else { + mkdirr('/bin/invalid/Makefile'); + ok($@ ? 1 : 0, 1, '$@ should be set'); + } + + my $work = createSandbox(); + my @paths = map{ join('/', $work, $_, 'Makefile.in') } qw (xyz/abc foo/bar a/b/c/d/e); + mkdirr(@paths); + ok($@ ? 1 : 0, 0, '$@ should not be set'); + + push(@paths, '/bin'); + + my @errors; + foreach (@paths) + { + my $dir = dirname($_); + next if (-d $dir); + push(@errors, "mkdirr($dir) failed\n"); + } + ok(scalar @errors, 0, "Errors detected: @errors"); +} # check_mkdirr + +########################################################################### +## Intent: Verify permutations for system("config.status") +########################################################################### +sub check_run_config_status +{ + print STDERR "Running: check_run_config_status()\n" + if ($main::argv{debug}); + + my $work = createSandbox(); + chdir $work; + run_config_status(); + ok($@ ? 1 : 0, '$@ should be set, config.status does not exist'); + + my $cfg = join('/', $work, 'config.status'); + local *CFG; + open(CFG, "> $cfg") && close(CFG); + run_config_status(); + ok($@, qr/config.status failed/, '$@ should be set, config.status is not executabl'); + + open(CFG, "> $cfg"); + print CFG join("\n", + '#!/bin/sh', + '', + 'true', + ''); + close(CFG); + chmod 0555, $cfg; + run_config_status(); + ok($@, qr/config.status failed/, '$@ should not be set'); + +} # check_run_config_status + +########################################################################### +## Intent: Verify makefile generation by legacy make-makefile functions +## o make-makefile -t /x/y -d .. +########################################################################### +sub check_update_makefiles_legacy +{ + print STDERR "Running: check_update_makefiles_legacy()\n" + if ($main::argv{debug}); + + return unless ($argv{legacy}); + print STDERR "check_update_makefiles_legacy: not yet implemented\n"; + +} # check_update_makefiles_legacy + +########################################################################### +## Intent: Verify updateMakefiles() +## o a makefile is generated when none exists. +## o a makefile will only be updated when the templates changes. +## o existing makefiles will be updated when the template changes. +## o @foo@ tokens have been expanded +########################################################################### +sub check_updateMakefiles +{ + my @errors; + + print STDERR "Running: check_updateMakefiles()\n" + if ($main::argv{debug}); + + my $mf = 'memory/mozalloc/Makefile.in'; + + my $work = createSandbox($mf); + my $obj = join('/', $work, 'obj'); + my %args = + ( + top => $work, + obj => $obj, + ); + + my $mf_src = join('/', $work, 'memory/mozalloc/Makefile.in'); + my $mf_dst = join('/', $obj, 'memory/mozalloc/Makefile'); + + updateMakefiles('memory/mozalloc', \%args); + my $tlm0 = (stat $mf_dst)[9] || 0; + ok(-e $mf_dst ? 1 : 0, 1, "failed to generate makefile: $mf_dst"); + + ############################# + ## Regeneration will be a nop + ############################# + updateMakefiles('memory/mozalloc', \%args); + my $tlm1 = (stat $mf_dst)[9] || -1; + ok($tlm1, $tlm0, "makefile should not have been modified"); + + ##################################################### + ## Modify template to verify makefile will regenerate + ##################################################### + local *MF; + if (open(MF, ">> $mf_src")) + { + print MF map{ "# MODIFIED MAKEFILE\n" } 0..4; + close(MF); + } + updateMakefiles('memory/mozalloc', \%args); + my @data = makemakefile::cat($mf_dst); + ## Check content to avoid a silly 'sleep [n]' call here + ok(grep(/^\# MODIFIED MAKEFILE/o, @data) ? 1 : 0, + 1, + "template modified, makefile should have regenerated"); + + ## VERIFY template expansion + my @gen = makemakefile::cat($mf_dst); + push(@errors, $@) if ($@); + + foreach (@gen) + { + if (/\@[^\@]+\@/o) + { + push(@errors, join("\n", + "Unexpanded template string detected [$_]", + "Makefile: $mf_src", + )); + last; + + } + } + + ok(scalar(@errors), 0, "Errors detected: @errors"); +} # check_updateMakefiles + +########################################################################### +## Intent: Verify makefile generation by updateMakefiles() when +## command line arguments --top and --obj were passed. +########################################################################### +sub check_updateMakefilesByTopObj +{ + my @errors; + + print STDERR "Running: check_updateMakefilesByTopObj()\n" + if ($main::argv{debug}); + + my $work = createSandbox(); + my %args = + ( + top => $work, + obj => $work, + ); + + ## Grab a list of makefile templates to generate + my @all = glob('data/mf.*'); + my @src = map{ /\.exp$/o ? () : $_ } @all; + + foreach my $src (@src) + { + my $dst = join('/', $work, 'Makefile'); + unlink $dst; + copy($src, "$work/Makefile.in"); + updateMakefiles('.', \%args); + ok($@, '', '$@ should not be set'); + + my @dst = makemakefile::cat($dst); + + my $exp = join('.', $src, 'exp'); + my @exp = makemakefile::cat($exp); + ok("@dst", "@exp", "updateMakefile($dst) failed"); + } + return; +} # check_updateMakefilesByTopObj + +########################################################################### +## Intent: Smoke tests for the unittests module +########################################################################### +sub smoke +{ + print STDERR "Running test: smoke()\n" if ($argv{debug}); +} # smoke() + +########################################################################### +## Intent: Intitialize global test objects and consts +########################################################################### +sub init +{ + print "Running: init()\n" if ($argv{debug}); +# testplan(24, 0); + + my @path = split(m%/%, $FindBin::RealBin); + splice(@path, -3); + my $top = join('/', @path); + ## Top set based on make-makefile startup directory so adjust for test/ use + getTopDir('_set_', $top); + +} # init() + +##----------------## +##---] MAIN [---## +##----------------## +unless(GetOptions(\%argv, + qw( + debug|d + manual + test=s@ + verbose + ))) +{ + print "USAGE: $0\n"; + print " --debug Enable script debug mode\n"; + print " --manual Also run disabled tests\n"; + print " --smoke Run smoke tests then exit\n"; + print " --test Run a list of tests by function name\n"; + print " --verbose Enable script verbose mode\n"; + exit 1; +} + +init(); +smoke(); + +check_dirname_legacy(); + +check_getTopDir(); +check_getObjDir(); +check_getDepth(); +check_getExclusions(); +check_getRelPath(); +check_mkdirr(); + +check_updateMakefiles(); +check_update_makefiles_legacy(); +check_updateMakefilesByTopObj(); diff --git a/build/autoconf/test/runtest b/build/autoconf/test/runtest new file mode 100644 index 000000000000..3a53b0682bcc --- /dev/null +++ b/build/autoconf/test/runtest @@ -0,0 +1,95 @@ +#!/usr/bin/env perl +########################################################################### +## Intent: +## Test::Harness is a testing wrapper that will process output +## from Test.pm module tests. Sumarize results, report stats +## and exit with overall status for the testing suites. +## +## Run testing suite: +## % make clean test +## % perl runtest +## +## Run Individual tests +## % perl tUtils0 +########################################################################### + +##----------------------------## +##---] CORE/CPAN INCLUDES [---## +##----------------------------## +use strict; +use warnings; +use Getopt::Long; + +use Test::Harness; + +##-------------------## +##---] EXPORTS [---## +##-------------------## +our $VERSION = qw(1.0); +use FindBin; + +##-------------------## +##---] GLOBALS [---## +##-------------------## +my %argv; + +##----------------## +##---] MAIN [---## +##----------------## +unless(GetOptions(\%argv, + qw(debug|d) + )) +{ + print "Usage: $0\n"; + print " --debug Enable debug mode\n"; + exit 1; +} + +if (2 > $Test::Harness::VERSION) +{ + print "Unit tests will not be run, Test::Harness is too old\n" + if ($argv{debug}); + exit 0; +} + + +my @tests; + +######################################## +## Gather a list of tests if none passed +######################################## +unless (@tests = @ARGV) +{ + local *D; + opendir(D, '.'); + while($_ = readdir(D)) { + next unless /.t\S+$/; + next if (/\.ts$/); + push(@tests, $_); + } + closedir(D); +} + +############################################### +## Glob a list of tests when directories passed +############################################### +my @tmp; +foreach (@tests) +{ + local *D; + if (-d $_ && (my $dir = $_)) + { + opendir(D, $_) || die "opendir(D) failed: $!"; + my @tests = grep(/\.t[^\.\s]+/o, readdir(D)); + closedir(D); + push(@tmp, map{ join('/', $dir, $_); } @tests); + } else { + push(@tmp, $_); + } +} +@tests = @tmp; + +print "$0: @ARGV\n" if ($argv{debug}); +runtests(@tests); + +# EOF diff --git a/js/src/build/autoconf/make-makefile b/js/src/build/autoconf/make-makefile index 94a5497da559..1f08aec1c923 100644 --- a/js/src/build/autoconf/make-makefile +++ b/js/src/build/autoconf/make-makefile @@ -1,4 +1,4 @@ -#! /usr/bin/env perl +#!/usr/bin/env perl # ***** BEGIN LICENSE BLOCK ***** # Version: MPL 1.1/GPL 2.0/LGPL 2.1 # @@ -16,10 +16,12 @@ # # The Initial Developer of the Original Code is # Netscape Communications Corporation. -# Portions created by the Initial Developer are Copyright (C) 1999 +# Portions created by the Initial Developer are Copyright (C) 1999-2011 # the Initial Developer. All Rights Reserved. # # Contributor(s): +# Steve Lamm +# Joey Armstrong # # Alternatively, the contents of this file may be used under the terms of # either of the GNU General Public License Version 2 or later (the "GPL"), @@ -35,29 +37,81 @@ # # ***** END LICENSE BLOCK ***** -# make-makefiles - Quickly create Makefiles for subdirectories. -# Also, creates any needed subdirectories. -# -# usage: make-makefiles [ -t -p -d ] [ | /Makefile ] ... +##----------------------------## +##---] CORE/CPAN INCLUDES [---## +##----------------------------## +use strict; +use warnings; +use Getopt::Long; -# Send comments, improvements, bugs to Steve Lamm (slamm@netscape.com). +use Benchmark; +use Cwd; +use File::Basename; +use File::Copy; +use File::Path qw{mkpath}; -#$debug = 1; +##-------------------## +##---] EXPORTS [---## +##-------------------## +our $VERSION = qw(2.0); -if ($^O eq 'msys') { - $pwdcmd = 'pwd -W'; +##--------------------## +##---] INCLUDES [---## +##--------------------## + +############################################################## +# pymake: special case path handling for windows cmd shell. +# if invoked by cmd.exe and msys-perl is in play +# $0 may contain a drive letter +# modules use-or-expect msys/unix paths +# adjust $0 => C:/foo => /c/foo so string tests and +# manipulation can by applied properly. +############################################################## +sub BEGIN +{ + if ($^O eq 'msys' && $ENV{PATH} =~ m!\w:/!) + { + $0 =~ s!^(\w):!/$1!; + } + eval 'use FindBin'; + die $@ if ($@); } -else { - $pwdcmd = 'pwd'; + +use lib $FindBin::Bin; +use makemakefile; + +##-------------------## +##---] GLOBALS [---## +##-------------------## +my %argv; + +my $t0 = Benchmark->new(); +sub END +{ + if ($argv{bench}) + { + my $t1 = Benchmark->new(); + my $delta = timediff($t1, $t0); + print STDERR timestr($delta), "\n"; + } } +##----------------## +##---] MAIN [---## +##----------------## +umask 0; + +my $debug = $argv{debug} || 0; + +my $pwdcmd = ($^O eq 'msys') ? 'pwd -W' : 'pwd'; + # Determine various tree path variables # -($topsrcdir, $ptopsrcdir, $depth, @makefiles) = parse_arguments(@ARGV); +my ($topsrcdir, $ptopsrcdir, $depth, @makefiles) = parse_arguments(@ARGV); -$object_fullpath = `$pwdcmd`; +my $object_fullpath = `$pwdcmd`; # Cwd::getcwd() chdir $depth; -$object_root = `$pwdcmd`; +my $object_root = `$pwdcmd`; # Cwd::getcwd() chomp $object_fullpath; chomp $object_root; @@ -65,24 +119,23 @@ chomp $object_root; # 'make-makefile' was called. For example, if make-makefile was # called from "mozilla/gfx/src", then $source_subdir would be # "gfx/src/". -$source_subdir = "$object_fullpath/"; +my $source_subdir = "$object_fullpath/"; my $quoted_object_root = quotemeta($object_root); $source_subdir =~ s|^$quoted_object_root/||; # Prefix makefiles with $source_subdir so that paths # will be relative to the top of the object tree. # -for $makefile (@makefiles) { +my $makefile; +for $makefile (@makefiles) { # dead code ? $makefile = "$source_subdir$makefile"; } -create_directories(@makefiles); - # Find the path to the source directory based on how 'make-makefile' # was invoked. The path is either relative to the object directory # or an absolute path. -$given_srcdir = find_srcdir($topsrcdir, $depth); -$pgiven_srcdir = find_srcdir($ptopsrcdir, $depth); +my $given_srcdir = find_srcdir($topsrcdir, $depth); +my $pgiven_srcdir = find_srcdir($ptopsrcdir, $depth); if ($debug) { warn "object_fullpath = $object_fullpath\n"; @@ -92,18 +145,21 @@ if ($debug) { warn "given_srcdir = $given_srcdir\n"; } -@unhandled = update_makefiles($given_srcdir, $pgiven_srcdir, @makefiles); +my @errors; +my @unhandled = update_makefiles_legacy($given_srcdir, $pgiven_srcdir, @makefiles); +push(@errors, $@) if ($@); run_config_status(@unhandled); +push(@errors, $@) if ($@ && $argv{'no-warnings'}); + +exit scalar(@errors); # end of Main ############################################################ -sub dirname { - return $_[0] =~ /(.*)\/.*/ ? "$1" : '.'; -} - +########################################################################### # find_depth: Pull the value of DEPTH out of a Makefile (or Makefile.in) +########################################################################### sub find_depth { my $depth = ''; open(MAKEFILE, "<$_[0]") || die "Unable to open $_[0]: $!\n"; @@ -116,39 +172,115 @@ sub find_depth { return $depth; } +########################################################################### +## Intent: Parse command line arguments and assign values +########################################################################### sub parse_arguments { my @args = @_; - my $depth = ''; - my $topsrcdir = ''; - my $ptopsrcdir; my @makefiles = (); - while (1) { - if ($args[0] eq '-d') { - $depth = $args[1]; - shift @args; - shift @args; - } elsif ($args[0] eq '-t') { - $topsrcdir = $args[1]; - shift @args; - shift @args; - } elsif ($args[0] eq '-p') { - $ptopsrcdir = $args[1]; - shift @args; - shift @args; - } else { - last; - } + my @arglist = qw(badtokens! bench + chdir=s + debug + depth|d=s + enhanced + obj=s top|t=s ptop|p=s + src=s dst=s + ); + unless(GetOptions(\%argv, @arglist)) + { + my $script = join('/', $FindBin::RealBin, $FindBin::Script); + system("perldoc $script $depth, obj=>$obj, top=>$top}); + if ($@) + { + push(@errors, $@); + } + elsif ($rc eq 'badtokens') + { + push(@unhandled, $mf); + } + } + + run_config_status(@unhandled); + push(@errors, $@) if ($@ && $argv{'no-warnings'}); + exit scalar(@errors); + } + + + my $depth = $argv{depth} || ''; + if (! $depth) + { + foreach my $fyl (@args) + { + if (my $tmp = find_depth($fyl)) + { + $depth = $tmp; + last; + } + } + } + + if (! $depth) { # Use $(DEPTH) in the Makefile or Makefile.in to determine the depth if (-e "Makefile.in") { $depth = find_depth("Makefile.in"); @@ -166,34 +298,21 @@ sub parse_arguments { # Build the list of makefiles to generate # @makefiles = (); - my $makefile; - foreach $makefile (@args) { - $makefile =~ s/\.in$//; - $makefile =~ s/\/$//; - $makefile =~ /Makefile$/ - or $makefile =~ /^\.\// - or $makefile .= "/Makefile"; + while (@args) + { + next unless my $makefile = shift @args; + $makefile =~ s/\.in$//; + $makefile =~ s/\/$//; + $makefile =~ /Makefile$/ + or $makefile =~ /^\.\// + or $makefile .= "/Makefile"; push @makefiles, "$makefile"; } - @makefiles = "Makefile" unless @args; + @makefiles = "Makefile" unless @makefiles; return ($topsrcdir, $ptopsrcdir, $depth, @makefiles); } - -# Create all the directories at once. -# This can be much faster than calling mkdir() for each one. -sub create_directories { - my @makefiles = @_; - my @dirs = (); - my $ac_file; - foreach $ac_file (@makefiles) { - push @dirs, dirname($ac_file); - } - # Call mkdir with the directories sorted by subdir count (how many /'s) - system "mkdir -p ". join(' ', map("\"$_\"", @dirs)) if @dirs; -} - # Find the top of the source directory # (Assuming that the executable is in $top_srcdir/build/autoconf) sub find_srcdir { @@ -214,111 +333,146 @@ sub find_srcdir { return $ac_given_srcdir; } -# Output the makefiles. -# -sub update_makefiles { - my ($ac_given_srcdir, $pac_given_srcdir, @makefiles) = @_; - my @unhandled=(); +1; +########################################################################### +## perldoc +########################################################################### +__END__ - my $ac_file; - foreach $ac_file (@makefiles) { - my $ac_file_in = "$ac_given_srcdir/${ac_file}.in"; - my $ac_dir = dirname($ac_file); - my $ac_dots = ''; - my $ac_dir_suffix = ''; - my $srcdir = '.'; - my $top_srcdir = '.'; +=head1 NAME - # Determine $srcdir and $top_srcdir - # - if ($ac_dir ne '.') { - $ac_dir_suffix = "/$ac_dir"; - $ac_dir_suffix =~ s%^/\./%/%; - $ac_dots = $ac_dir_suffix; - # Remove .. components from the provided dir suffix, and - # also the forward path components they were reversing. - my $backtracks = $ac_dots =~ s%\.\.(/|$)%%g; - while ($backtracks--) { - $ac_dots =~ s%/[^/]*%%; - } - $ac_dots =~ s%/[^/]*%../%g; - } - if ($ac_given_srcdir eq '.') { - if ($ac_dots ne '') { - $top_srcdir = $ac_dots; - $top_srcdir =~ s%/$%%; - } - } elsif ($pac_given_srcdir =~ m%^/% or $pac_given_srcdir =~ m%^.:/%) { - $srcdir = "$pac_given_srcdir$ac_dir_suffix"; - $top_srcdir = "$pac_given_srcdir"; - } else { - if ($debug) { - print "ac_dots = $ac_dots\n"; - print "ac_dir_suffix = $ac_dir_suffix\n"; - } - $srcdir = "$ac_dots$ac_given_srcdir$ac_dir_suffix"; - $top_srcdir = "$ac_dots$ac_given_srcdir"; - } +make-makefile - Generate a Makefile from a F template - if ($debug) { - print "ac_dir = $ac_dir\n"; - print "ac_file = $ac_file\n"; - print "ac_file_in = $ac_file_in\n"; - print "srcdir = $srcdir\n"; - print "top_srcdir = $top_srcdir\n"; - print "cwd = " . `$pwdcmd` . "\n"; - } +=head1 SYNOPSIS - # Copy the file and make substitutions. - # @srcdir@ -> value of $srcdir - # @top_srcdir@ -> value of $top_srcdir - # - if (-e $ac_file) { - next if -M _ < -M $ac_file_in; # Next if Makefile is up-to-date. - warn "updating $ac_file\n"; - } else { - warn "creating $ac_file\n"; - } +make-makefile [--top t] [--obj o] [--depth d] foo/bar/Makefile.in tans/fans/Makefile foo/bar - open INFILE, "<$ac_file_in" or do { - warn "$0: Cannot read $ac_file_in: No such file or directory\n"; - next; - }; - open OUTFILE, ">$ac_file" or do { - warn "$0: Unable to create $ac_file\n"; - next; - }; +=head1 DESCRIPTION - while () { - #if (/\@[_a-zA-Z]*\@.*\@[_a-zA-Z]*\@/) { - # #warn "Two defines on a line:$ac_file:$.:$_"; - # push @unhandled, $ac_file; - # last; - #} +Given options and makefile path arguments determine path to the template +F beneath a source directory and path to generated F +beneath $MOZ_OBJDIR. DEPTH from destination directory to the 'root' will +also be determined. F will be read in, template strings of the +gorm @token@ will be replaced with derived values and a generated makefile +will be written out as F. - s/\@srcdir\@/$srcdir/g; - s/\@top_srcdir\@/$top_srcdir/g; +Makefile DEPTH= can be determined in a few different ways: + o The string C may be embedded within F. + o Search parent directories for F and use it to assign the child. - if (/\@[_a-zA-Z]*\@/) { - #warn "Unknown variable:$ac_file:$.:$_"; - push @unhandled, $ac_file; - last; - } - print OUTFILE; - } - close INFILE; - close OUTFILE; - } - return @unhandled; -} -sub run_config_status { - my @unhandled = @_; +=head2 Option List - # Run config.status with any unhandled files. - # - if (@unhandled) { - $ENV{CONFIG_FILES}= join ' ', @unhandled; - system "./config.status"; - } -} +=over 4 + +=item --chdir + +Move to this directory before doing anything else + +=item -d, --depth + +Explicitly specify the relative path from directory containing Makefile.in +to the top sandbox directory. memory/makefile, DEPTH=../.., js/src/config, DEPTH=.. + +=item --enhanced + +Use alternate/simplified path construction when options --top and --obj are +passed. This feature will be used by container makefiles to support makefile +generation while cd'd into the sandbox top directory. + +=item -t, --top + +Path the root of a development sandbox. + +=item --obj + +Path to object directory where generated makefile will be written ($MOZ_OBJDIR). + +=item --ptop + +Print top source dir + +=back + + +=head2 Options List DEBUG + +=over 4 + +=item --bench + +Enable script benchmarking, report elapsed runtime. + +=item --debug + +Enable script debug mode. + +=back + + +=head2 Options List --NO- + +=over 4 + +=item --no-badtokens (wip) + +Handle unexpanded @token@ makefile tokens as an error condition. +Do not rely on system(config.status) to externally supply values. + +=item --no-excludes + +Ignore file entries on the exclusion list, generate everything. + +=item --no-warnings + +Warnings are handled as an error condition. + +=back + + +=head2 Examples + +=over 4 + +=item * make-makefile -t /mozilla/nightly -d . memory/mozalloc + +cd $MOZ_OBJDIR; +--top and --depth are explicitly set for generting memory/mozalloc/Makefile. + +=item * make-makefile -t /mozilla/nightly -d ../../../.. html5lib_tree_construction/Makefile + +cd $MOZ_OBJDIR/parser/htmlparser/tests/mochitest + +--top and --depth are explicitly set for generting a makefile from within +a subdirectory of $MOZ_OBJDIR + +=item * make-makefile --top /mozilla/nightly --obj /mozilla/nightly/obj memory/mozalloc + +With --top and --obj explicitly set generate $MOZ_OBJDIR/memory/mozalloc/Makefile +while sitting in the sandbox root. + +=back + + +=head2 Work In Progress + +=over 4 + +=item --no-badtokens + +Fail on unexpanded @foo@ makefile tokens. Any tokens that can be expanded +directly by make-makefile will avoid config.status shell overhead. + +=item Depth from delta(--obj, --top) + +If DEPTH= has not been embedded within a makefile the value could +be set directly if --top and --obj are specified and the paths overlap. + +=back + + +=head1 SEE ALSO + +L + +=cut diff --git a/js/src/build/autoconf/make-makefile.excl b/js/src/build/autoconf/make-makefile.excl new file mode 100644 index 000000000000..25ab32dd267e --- /dev/null +++ b/js/src/build/autoconf/make-makefile.excl @@ -0,0 +1,5 @@ +########################################################################### +## Intent: Exclusion list for container make builds +########################################################################### + +# EOF diff --git a/js/src/build/autoconf/makemakefile.pm b/js/src/build/autoconf/makemakefile.pm new file mode 100644 index 000000000000..6eafbce4fcaa --- /dev/null +++ b/js/src/build/autoconf/makemakefile.pm @@ -0,0 +1,745 @@ +package makemakefile; + +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1999-2011 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Steve Lamm +# Joey Armstrong +# +# Alternatively, the contents of this file may be used under the terms of +# either of the GNU General Public License Version 2 or later (the "GPL"), +# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +##----------------------------## +##---] CORE/CPAN INCLUDES [---## +##----------------------------## +use strict; +use warnings; +# use feature 'state'; 5.10+ not available everywhere + +##-------------------## +##---] EXPORTS [---## +##-------------------## +our $VERSION = qw(2.0); +use Exporter; +our @ISA = qw(Exporter); +our @EXPORT = qw(dirname_legacy + getConfig getDepth getRelPath getObjDir getTopDir mkdirr + getExclusions + run_config_status + updateMakefiles + update_makefiles_legacy + ); + +##--------------------## +##---] INCLUDES [---## +##--------------------## +use Cwd; +use Cwd qw{abs_path}; +use FindBin; +use File::Basename; +use File::Copy; + +##-------------------## +##---] GLOBALS [---## +##-------------------## +umask 0; +my $cwd = Cwd::abs_path('.'); +my %argv; + + +########################################################################### +## Intent: Helper function, retrieve contents of a file with error checking +## ----------------------------------------------------------------------- +## Args: +## scalar path to input file +## Returns: +## array contents of the given file +## $@ set on error +########################################################################### +sub cat +{ + my $fyl = shift || ''; + $@ = ''; + my @data; + + local *FYL; + if (!open(FYL, $fyl)) + { + $@ = "open($fyl) failed: $!"; + } + else + { + @data = ; + close(FYL); + } + return @data; +} # cat + +########################################################################### +## Intent: Return directory path for a given argument +## ----------------------------------------------------------------------- +## ----------------------------------------------------------------------- +## Todo: +## o Check if function can be replaced by File::Basename::dirname() +########################################################################### +sub dirname_legacy +{ + my $str = (@_ && defined($_[0])) ? shift : ''; + return $str =~ /(.*)\/.*/ ? "$1" : '.'; +} + +########################################################################### +## Intent: Given a list of makefile paths recursively create all +## directories between file and the root +## ----------------------------------------------------------------------- +## Args: +## array A list of makefiles +## fargs Function arguments +## mode Filesystem mode used for directory creation +## Returns: +## $@ Set on error +## 0 on success +## ----------------------------------------------------------------------- +## Note: +## Reporting directory creation can be enabled by the --verbose +## command line argument. +########################################################################### +sub mkdirr +{ + my %fargs = (@_ && ref($_[$#_])) ? %{ (pop) } : (); + my $mode = $fargs{mode} || 0755; + my $verbose = $main::argv{verbose} || 0; + $@ = '' unless ($fargs{recursive}); + $fargs{recursive} = 1; + + my @errors; + push(@errors, $@) if ($@); + foreach my $path (@_) + { + (my $dir = $path) =~ s%/?Makefile[^/]*$%%o; + next unless (length($dir)); + next if (-e $dir); + mkdirr( dirname($dir), \%fargs); + eval{ File::Path::mkpath($dir, $verbose, 0755); }; + push(@errors, $@) if ($@); + } + $@ = join("\n", @errors); + return $@ ? 0 : 1; +} # mkdirr + +########################################################################### +## Intent: Read in configure values and return a hash of key/value pairs +## ----------------------------------------------------------------------- +## Args: +## fargs Function arguments +## reset clear value storage and repopulate +## Returns: +## hash configure data to use for makefile substitutions +## ----------------------------------------------------------------------- +## Todo: wrapper for reading config* and run_config_status +########################################################################### +my %_CONFIG_; # todo: state %config; w/5.10 +sub getConfig +{ + my %fargs = (@_ && ref($_[$#_]) eq 'HASH') ? %{ (pop) } : (); + if ($fargs{reset}) + { + %_CONFIG_ = (); + shift; + } + + #my $ac_file_in = "$ac_given_srcdir/${ac_file}.in"; + #my $ac_dir = dirname_legacy($ac_file); + #my $ac_dots = ''; + #my $ac_dir_suffix = ''; + #my $srcdir = '.'; + #my $top_srcdir = '.'; + unless (%_CONFIG_) + { + while (@_) + { + my ($k, $v) = splice(@_, 0, 2); + $_CONFIG_{$k} = $v; + } + } + + return %_CONFIG_; +} # getConfig + +########################################################################### +## Intent: Determine path depth between leaf and root directory. +## o DEPTH= may be set by makefile content +## o DEPTH= may be set by Makefile in a parent +## o Manually determine by relpath form leaf to sandbox top +## ----------------------------------------------------------------------- +## Args: +## scalar Path to makefile or directory to determine DEPTH for +## Returns: +## scalar Relative path from leaf to root directory +## ----------------------------------------------------------------------- +########################################################################### +sub getDepth($) +{ + my $fyl = shift || ''; + + my @path = split(m%/%o, $fyl); + pop(@path) if ('Makefile' eq substr($path[$#path], 0, 8)); + my $depth; + my @depth; + + my $top = getTopDir(); + my @top = split(m%/%o, $top); + my @pathNoTop = @path; + splice(@pathNoTop, 0, scalar(@top)); + + SEARCH: + while (@path) + { + ## Search for a file containing DEPTH=../.. + foreach my $fyl ( qw{Makefile.in Makefile} ) + { + my $path = join('/', @path, $fyl); + local *FYL; + if (!open(FYL, $path)) {} # NOP + elsif (my @tmp = map{ /^\s*DEPTH\s*=\s*([\.\/]+)/o ? $1 : () } ) + { + $depth = join('/', @depth, shift @tmp); + last SEARCH; + } + close(FYL); + } + pop @path; + pop @pathNoTop; + + if (0 == scalar(@pathNoTop)) + { + $depth = join('/', @depth); + last; + } + + ## Construct path manually + push(@depth, '..'); + } + return $depth; +} # getDepth + +########################################################################### +## Intent: Read in the exclusion file +########################################################################### +sub getExclusions +{ + my $file = shift || ''; + + return () if ($main::argv{'no-exclusions'}); + + my %exclude; + if ($file) + { + my @data = cat($file); + foreach (@data) + { + next unless ($_); + next if (/^\s*\#/o); + next unless (m%/%); + chomp; + $exclude{$_}++; + } + } + return %exclude; +} # getExclusions + +########################################################################### +## Intent: Given the path to a makefile beneath either src or obj +## derive the relative path prefix between makefile and root. +########################################################################### +sub getRelPath +{ + my $path0 = shift; + my $abspath; + + # Determine type and orientation + my $name = basename($path0); + my $haveMF = ($name eq 'Makefile.in') ? 1 + : ($name eq 'Makefile') ? -1 + : 0 + ; + + #################################################### + ## Prep work: form a relative path with ../ removed + #################################################### + my $top = getTopDir(); + my $obj = getObjDir(); + ## If the same Makefile will be created alongside Makefile.in + my $topQM = quotemeta($top); + my $objQM = quotemeta($obj); + + if ('..' eq substr($path0, 0, 2)) + { + my @cwd = split(m%/%, $cwd); + my @pth = split(m%/%, $path0); + while (@pth && $pth[0] eq '..') + { + pop(@cwd); + shift @pth; + } + $path0 = join('/', @cwd, @pth); + $abspath = $path0; + } + + if ('/' eq substr($path0, 0, 1)) + { + $path0 =~ s%^$objQM\/?%%; + $path0 =~ s%^$topQM\/?%%; + } + + ####################################################################### + ## Build a list of directories to search. Input source will be one + ## of path to Makefile.in, path to Makefile, directory, file within + ## a directory or relative path from cwd. + ####################################################################### + my @subdirs; + my $path = (0 == $haveMF) ? $path0 : dirname($path0); + push(@subdirs, $path); # containing directory + push(@subdirs, dirname($path)) if (0 == $haveMF && -f $path); # Arg is file within a directory + push(@subdirs, $cwd); # relative to pwd + + # obj - path to generated makefile + # top - path to Makefile.in source template + my @prefixes = ('/' ne substr($path0, 0, 1)) + ? (&getTopDir, &getObjDir) + : () + ; + + ON_SAFARI: + for my $prefix (@prefixes) + { + next unless ($prefix); # no command line not passed + foreach my $subdir (@subdirs) + { + foreach my $mf ('Makefile.in', 'Makefile') + { + my $path = join('/', $prefix, $subdir, $mf); + if (-e $path) + { + $name = $mf; + $haveMF = ($mf eq 'Makefile.in') ? 1 : -1; + $abspath = $path; + last ON_SAFARI; + } + } + } + } + + ####################################################################### + ## Generated makefile does not yet exist or path is invalid. + ## Should this conditon be handled to detect non-existent Makefile.in: + ## Makefile.am => Makefile.in => Makefile but Makefile.in + ####################################################################### + if (!$abspath && -1 == $haveMF && $obj) + { + $abspath = ('/' eq substr($path0, 0, 1)) + ? $path0 + : join('/', $obj, $path0) + ; + } + + ######################################################## + ## If --top and/or --obj specified extract relative path + ######################################################## + my $relpath; + if (! $abspath) + { + # Error, fall through + } + elsif (1 == $haveMF) # Makefile.in + { + ## err w/o --top + (my $tmp = $abspath) =~ s%^$topQM/?%%; + $relpath = dirname($tmp) unless ($tmp eq $abspath); + } + elsif (-1 == $haveMF) # Makefile + { + ## err w/o --obj + (my $tmp = $abspath) =~ s%^$objQM/?%%; + $relpath = dirname($tmp) unless ($tmp eq $abspath); + } + + $relpath ||= ''; + $relpath =~ s%/./%/%og; # filter ./ + + $@ = ($relpath) ? '' : "ERROR($path0): Unable to locate sources"; + return $relpath || ''; +} # getRelPath + +########################################################################### +## Intent: Determine sandbox root from script startup directory +## ----------------------------------------------------------------------- +## Args: +## _set_ optional, if passed use the given value as path +## _reset_ clear cached directory path to reassign +## Returns: +## scalar - absolute path to the sandbox root directory +## ----------------------------------------------------------------------- +########################################################################### +my $gtd_dir; +sub getTopDir +{ + if (@_) # testing override + { + $gtd_dir = abs_path($_[1] || '.') if ($_[0] eq '_set_'); + $gtd_dir = '' if ($_[0] eq '_reset_'); + } + + unless ($gtd_dir) + { + ## Set by command line + if ($main::argv{top}) + { + $gtd_dir = $main::argv{top}; + } + else + { + my $path = abs_path($FindBin::RealBin); + my @path = split(m%/%o, $path); + ## --2 memory/mozalloc/Makefile.in + ## --3 was this for FindBin::Script ? + splice(@path, -2); + $gtd_dir = join('/', @path); + } + } + return $gtd_dir; +} # getTopDir + +########################################################################### +## Intent: Determine path to MOZ_OBJDIR/object directory +## ----------------------------------------------------------------------- +## Args: +## _set_ optional testing arg, if passed re-compute cached value +## Returns: +## scalar - absolute path to the sandbox object directory +## ----------------------------------------------------------------------- +########################################################################### +my $god_dir; +sub getObjDir +{ + if (@_) # testing override + { + if ($_[0] eq '_reset_') + { + $god_dir = ''; + shift; + } + elsif ($_[0] eq '_set_') + { + shift; + my $path = $_[0] || '.'; + $god_dir = abs_path($path); + shift; + } + } + + ## extract $obj from given path + unless ($god_dir) + { + if ($main::argv{obj}) + { + $god_dir = $main::argv{obj}; + } + elsif (@_ && 'Makefile' eq substr($_, -8)) + { + $god_dir = abs_path(shift); + } + else # assume we are sitting in moz_objdir + { + $god_dir = abs_path('.'); + } + } + + return $god_dir; +} # getObjDir + +########################################################################### +## Intent: Generate Makefile from a given Makefile.in template +## ----------------------------------------------------------------------- +## Args: +## scalar Relative path to a directory containing a makefile +## fargs Hash ref of function arguments. +## obj Absolute path to MOZ_OBJ/a destination directory +## top Absolute path to the sandbox root +## Returns: +## $@ Set on error +## scalar +## 1 True if the makefile was updated +## 0 Otherwise +## badtokens - If the makefile contains unexpandable @token@ strings +## ----------------------------------------------------------------------- +########################################################################### +sub updateMakefiles +{ + my %fargs = (@_ && ref($_[$#_])) ? %{ (pop) } : (); + local $_; + $@ = ''; + + my $top = $fargs{top}; + my $obj = $fargs{obj}; + + my $relpath = shift || ''; + my $src = join('/', $top, $relpath, 'Makefile.in'); + my $depth = getDepth($src); + + my @src = cat($src); + return 0 if ($@); + + my $dst = join('/', $obj, $relpath, 'Makefile'); + my @dst = cat($dst); + $@ = ''; + + my $dstD = dirname($dst); + mkdirr($dstD); + return 0 if ($@); + + my %data = + ( getConfig(), + depth => $depth, + srcdir => join('/', $top, $relpath), + top_srcdir => $top, + ); + + my $line = 0; + my @data; + while (scalar @src) + { + $line++; + $_ = shift(@src); + + ## Expand embedded @foo@ + while (/\@[^\@\s\$]+\@/go) + { + my $end = pos($_); + my $val = $&; + my $len = length($val); + $val =~ s/^\@\s*//o; + $val =~ s/\s*\@$//o; + + ## Identify expansions to see if we can avoid shell overhead + if (!defined $data{$val} && !$argv{'no-badtokens'}) + { + if (1) # warnings + { + print STDERR "WARNING: token $val not defined\n"; + print STDERR " line $line, src: $src\n"; + } + return 'badtokens'; + } + + # Insert $(error txt) makefile macros for invalid tokens + my $val1 = defined($data{$val}) + ? $data{$val} + : "\$(error $FindBin::Script: variable ${val} is undefined)" + ; + substr($_, ($end-$len), $len, $val1); + } + push(@data, $_); + } + + if (("@data" eq "@dst") && scalar(@data)) + { + print "Skipping up2date makefile: $dst\n" if ($argv{verbose}); + } + else + { + my $action = (scalar @dst) ? 'Updating' : 'Creating'; + print "$action makefile: $dst\n"; + + my $tmp = join('.', $dst, "tmp_$$"); + if (!open(FYL, "> $tmp")) + { + $@ = "open($tmp) failed: $!"; + } + else + { + print FYL @data; + close(FYL); + + ## Install the new makefile + File::Copy::move($tmp, $dst) + || ($@ = "move($tmp, $dst) failed: $!"); + } + } + + return $@ ? 0 : 1; +} # updateMakefiles + +# Output the makefiles. +# +sub update_makefiles_legacy { + my ($ac_given_srcdir, $pac_given_srcdir, @makefiles) = @_; + my $debug = $main::argv{debug} || 0; + my $pwdcmd = ($^O eq 'msys') ? 'pwd -W' : 'pwd'; + my @unhandled=(); + + my @warn; + + my $ac_file; + foreach $ac_file (@makefiles) { + my $ac_file_in = "$ac_given_srcdir/${ac_file}.in"; + my $ac_dir = dirname_legacy($ac_file); + my $ac_dots = ''; + my $ac_dir_suffix = ''; + my $srcdir = '.'; + my $top_srcdir = '.'; + + # Determine $srcdir and $top_srcdir + # + if ($ac_dir ne '.') { + $ac_dir_suffix = "/$ac_dir"; + $ac_dir_suffix =~ s%^/\./%/%; + $ac_dots = $ac_dir_suffix; + # Remove .. components from the provided dir suffix, and + # also the forward path components they were reversing. + my $backtracks = $ac_dots =~ s%\.\.(/|$)%%g; + while ($backtracks--) { + $ac_dots =~ s%/[^/]*%%; + } + $ac_dots =~ s%/[^/]*%../%g; + } + if ($ac_given_srcdir eq '.') { + if ($ac_dots ne '') { + $top_srcdir = $ac_dots; + $top_srcdir =~ s%/$%%; + } + } elsif ($pac_given_srcdir =~ m%^/% or $pac_given_srcdir =~ m%^.:/%) { + $srcdir = "$pac_given_srcdir$ac_dir_suffix"; + $top_srcdir = "$pac_given_srcdir"; + } else { + if ($debug) { + print "ac_dots = $ac_dots\n"; + print "ac_dir_suffix = $ac_dir_suffix\n"; + } + $srcdir = "$ac_dots$ac_given_srcdir$ac_dir_suffix"; + $top_srcdir = "$ac_dots$ac_given_srcdir"; + } + + if ($debug) { + print "ac_dir = $ac_dir\n"; + print "ac_file = $ac_file\n"; + print "ac_file_in = $ac_file_in\n"; + print "srcdir = $srcdir\n"; + print "top_srcdir = $top_srcdir\n"; + print "cwd = " . `$pwdcmd` . "\n"; + } + + # Copy the file and make substitutions. + # @srcdir@ -> value of $srcdir + # @top_srcdir@ -> value of $top_srcdir + # + if (-e $ac_file) { + next if -M _ < -M $ac_file_in; # Next if Makefile is up-to-date. + warn "updating $ac_file\n"; + } else { + warn "creating $ac_file\n"; + } + + mkdirr(dirname($ac_file)); + + open INFILE, "<$ac_file_in" or do { + warn "$0: Cannot read $ac_file_in: No such file or directory\n"; + next; + }; + open OUTFILE, ">$ac_file" or do { + warn "$0: Unable to create $ac_file\n"; + next; + }; + + while () { + s/\@srcdir\@/$srcdir/g; + s/\@top_srcdir\@/$top_srcdir/g; + + if (/\@[_a-zA-Z]*\@/) { + #warn "Unknown variable:$ac_file:$.:$_"; + push @unhandled, $ac_file; + last; + } + print OUTFILE; + } + close INFILE; + close OUTFILE; + } + return @unhandled; +} # update_makefiles_legacy + +########################################################################### +## Intent: Invoke config.status for unknown makefiles to create +## directory hierarchy for the tree. +## ----------------------------------------------------------------------- +## Args: +## array an optional list of makefiles to process +## Returns: +## 0 on success +## $# set on error +## ----------------------------------------------------------------------- +## Note: Is this function needed anymore ? Undefined tokens should fail +## at time of expansion rather than having to source config.status. +## Also config.status could be parsed to define values and avoide the +## shell overhead altogether. +########################################################################### +sub run_config_status { + my @unhandled = @_; + + # Run config.status with any unhandled files. + # + my @errors; + if (@unhandled) { + local $ENV{CONFIG_FILES}= join ' ', @unhandled; + + my $conf = 'config.status'; + if (! -e $conf) # legacy behavior, warn rather than err + { + my $cwd = cwd(); + my $err = "$FindBin::Script ERROR: Config file $conf does not exist, cwd=$cwd"; + push(@errors, $err); + } + elsif (0 != system("./config.status")) + { + my $cwd = cwd(); + push(@errors, "config.status failed \$?=$?, \$!=$!, cwd: $cwd"); + } + } + $@ = join("\n", @errors); + + ## Legacy behavior: config.status problems are not fatal {yet}. + ## Display warning since caller will not be calling die. + warn $@ if ($@ && $argv{'no-warnings'}); + return $@ ? 1 : 0; +} + +1; From 764e833c1a121f2b84ed4f24297f44224b057b37 Mon Sep 17 00:00:00 2001 From: Oleg Romashin Date: Sun, 20 Nov 2011 08:49:48 -0500 Subject: [PATCH 63/63] Bug 618765 - unbind VBO required in order to share GL context with toolkit. r=matt.woodrow --- gfx/layers/opengl/LayerManagerOGL.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gfx/layers/opengl/LayerManagerOGL.cpp b/gfx/layers/opengl/LayerManagerOGL.cpp index 69b4c116f0c9..1e1949e78df2 100644 --- a/gfx/layers/opengl/LayerManagerOGL.cpp +++ b/gfx/layers/opengl/LayerManagerOGL.cpp @@ -809,6 +809,7 @@ LayerManagerOGL::Render() if (mTarget) { CopyToTarget(); + mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0); return; } @@ -818,6 +819,7 @@ LayerManagerOGL::Render() if (mGLContext->IsDoubleBuffered()) { mGLContext->SwapBuffers(); + mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0); return; }