author | Carsten "Tomcat" Book <cbook@mozilla.com> |
Wed, 29 Oct 2014 13:19:08 +0100 | |
changeset 212832 | fe5c1cb8075a9773b86ee001e41c0181519ea04a |
parent 212790 | 366d06412304c16c2c8cdafed6afecb5576c92cd (current diff) |
parent 212831 | a347286d9669f3489462b365d574f0e2f3575a3c (diff) |
child 212843 | e5e6847c29885e473fb3747198117579102d5019 |
push id | 27730 |
push user | cbook@mozilla.com |
push date | Wed, 29 Oct 2014 12:26:03 +0000 |
treeherder | mozilla-central@fe5c1cb8075a [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | merge |
milestone | 36.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
build/unix/abs2rel.pl | file | annotate | diff | comparison | revisions | |
config/module2dir.pl | file | annotate | diff | comparison | revisions |
--- a/CLOBBER +++ b/CLOBBER @@ -17,12 +17,9 @@ # # Modifying this file will now automatically clobber the buildbot machines \o/ # # Are you updating CLOBBER because you think it's needed for your WebIDL # changes to stick? As of bug 928195, this shouldn't be necessary! Please # don't change CLOBBER for WebIDL changes any more. -Updating CLOBBER for Bug 1084342 - -There are some refactored files in in dom/bluetooth. Updating CLOBBER to not -leave artifacts from older builds. +Backing out bug 1087560 needs a CLOBBER
--- a/b2g/components/test/mochitest/test_permission_deny.html +++ b/b2g/components/test/mochitest/test_permission_deny.html @@ -38,17 +38,17 @@ function runNext() { if (gTests.length > 0) { // Put the requested permission in query string let requestedType = gTests.shift(); info('getUserMedia for ' + JSON.stringify(requestedType)); navigator.mozGetUserMedia(requestedType, function success() { ok(false, 'unexpected success, permission request should be denied'); runNext(); }, function failure(err) { - is(err.toLowerCase(), 'permission denied', 'expected permission denied'); + is(err.name, 'PermissionDeniedError', 'expected permission denied'); runNext(); }); } else { info('test finished, teardown'); gScript.sendAsyncMessage('teardown', ''); gScript.destroy(); SimpleTest.finish(); }
--- a/browser/base/content/test/general/browser_devices_get_user_media.js +++ b/browser/base/content/test/general/browser_devices_get_user_media.js @@ -218,16 +218,18 @@ function checkNotSharing() { is(getMediaCaptureState(), "none", "expected nothing to be shared"); ok(!PopupNotifications.getNotification("webRTC-sharingDevices"), "no webRTC-sharingDevices popup notification"); assertWebRTCIndicatorStatus(null); } +const permissionError = "error: PermissionDeniedError: The user did not grant permission for the operation."; + let gTests = [ { desc: "getUserMedia audio+video", run: function checkAudioVideo() { yield promisePopupNotificationShown("webRTC-shareDevices", () => { info("requesting devices"); content.wrappedJSObject.requestDevice(true, true); @@ -376,17 +378,17 @@ let gTests = [ }); expectObserverCalled("getUserMedia:request"); checkDeviceSelectors(true, true); // disable the camera and microphone enableDevice("Camera", false); enableDevice("Microphone", false); - yield promiseMessage("error: PERMISSION_DENIED", () => { + yield promiseMessage(permissionError, () => { PopupNotifications.panel.firstChild.button.click(); }); // reset the menuitems to have no impact on the following tests. enableDevice("Camera", true); enableDevice("Microphone", true); expectObserverCalled("getUserMedia:response:deny"); @@ -400,17 +402,17 @@ let gTests = [ run: function checkDontShare() { yield promisePopupNotificationShown("webRTC-shareDevices", () => { info("requesting devices"); content.wrappedJSObject.requestDevice(true, true); }); expectObserverCalled("getUserMedia:request"); checkDeviceSelectors(true, true); - yield promiseMessage("error: PERMISSION_DENIED", () => { + yield promiseMessage(permissionError, () => { activateSecondaryAction(kActionDeny); }); expectObserverCalled("getUserMedia:response:deny"); expectObserverCalled("recording-window-ended"); checkNotSharing(); } }, @@ -477,17 +479,17 @@ let gTests = [ let noVideo = aAllowVideo === undefined; is(elt("webRTC-selectCamera").hidden, noVideo, "camera selector expected to be " + (noVideo ? "hidden" : "visible")); if (!noVideo) enableDevice("Camera", aAllowVideo || aNever); let expectedMessage = - (aAllowVideo || aAllowAudio) ? "ok" : "error: PERMISSION_DENIED"; + (aAllowVideo || aAllowAudio) ? "ok" : permissionError; yield promiseMessage(expectedMessage, () => { activateSecondaryAction(aNever ? kActionNever : kActionAlways); }); let expected = []; if (expectedMessage == "ok") { expectObserverCalled("getUserMedia:response:allow"); expectObserverCalled("recording-device-events"); if (aAllowVideo) @@ -582,24 +584,24 @@ let gTests = [ }; if (aExpectStream === undefined) { // Check that we get a prompt. yield promisePopupNotificationShown("webRTC-shareDevices", gum); expectObserverCalled("getUserMedia:request"); // Deny the request to cleanup... - yield promiseMessage("error: PERMISSION_DENIED", () => { + yield promiseMessage(permissionError, () => { activateSecondaryAction(kActionDeny); }); expectObserverCalled("getUserMedia:response:deny"); expectObserverCalled("recording-window-ended"); } else { - let expectedMessage = aExpectStream ? "ok" : "error: PERMISSION_DENIED"; + let expectedMessage = aExpectStream ? "ok" : permissionError; yield promiseMessage(expectedMessage, gum); if (expectedMessage == "ok") { expectObserverCalled("getUserMedia:request"); yield promiseNoPopupNotification("webRTC-shareDevices"); expectObserverCalled("getUserMedia:response:allow"); expectObserverCalled("recording-device-events");
--- a/browser/modules/ContentWebRTC.jsm +++ b/browser/modules/ContentWebRTC.jsm @@ -59,17 +59,17 @@ function handleRequest(aSubject, aTopic, contentWindow.navigator.mozGetUserMediaDevices( constraints, function (devices) { prompt(contentWindow, aSubject.windowID, aSubject.callID, constraints, devices, secure); }, function (error) { - // bug 827146 -- In the future, the UI should catch NO_DEVICES_FOUND + // bug 827146 -- In the future, the UI should catch NotFoundError // and allow the user to plug in a device, instead of immediately failing. denyRequest({callID: aSubject.callID}, error); }, aSubject.innerWindowID); } function prompt(aContentWindow, aWindowID, aCallID, aConstraints, aDevices, aSecure) { let audioDevices = []; @@ -103,17 +103,17 @@ function prompt(aContentWindow, aWindowI let requestTypes = []; if (videoDevices.length) requestTypes.push(sharingScreen ? "Screen" : "Camera"); if (audioDevices.length) requestTypes.push("Microphone"); if (!requestTypes.length) { - denyRequest({callID: aCallID}, "NO_DEVICES_FOUND"); + denyRequest({callID: aCallID}, "NotFoundError"); return; } if (!aContentWindow.pendingGetUserMediaRequests) aContentWindow.pendingGetUserMediaRequests = new Map(); aContentWindow.pendingGetUserMediaRequests.set(aCallID, devices); let request = {
--- a/build/autoconf/android.m4 +++ b/build/autoconf/android.m4 @@ -235,17 +235,16 @@ if test "$OS_TARGET" = "Android" -a -z " # android-ndk-r5c, android-ndk-r6, android-ndk-r6b STLPORT_CPPFLAGS="-I$android_ndk/sources/cxx-stl/gnu-libstdc++/include -I$android_ndk/sources/cxx-stl/gnu-libstdc++/libs/$ANDROID_CPU_ARCH/include" STLPORT_LIBS="-L$android_ndk/sources/cxx-stl/gnu-libstdc++/libs/$ANDROID_CPU_ARCH/ -lstdc++" else AC_MSG_ERROR([Couldn't find path to gnu-libstdc++ in the android ndk]) fi else STLPORT_CPPFLAGS="-isystem $_topsrcdir/build/stlport/stlport -isystem $_topsrcdir/build/stlport/overrides -isystem $android_ndk/sources/cxx-stl/system/include" - STLPORT_LIBS="$_objdir/build/stlport/libstlport_static.a -static-libstdc++" fi fi CXXFLAGS="$CXXFLAGS $STLPORT_CPPFLAGS" fi AC_SUBST([MOZ_ANDROID_LIBSTDCXX]) AC_SUBST([STLPORT_LIBS]) ])
--- a/build/stlport/moz.build +++ b/build/stlport/moz.build @@ -1,15 +1,21 @@ # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- # vim: set filetype=python: # This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. -Library('stlport_static') +Library('stlport') +# Keep the same name as the NDK-provided library, while using a shorter +# name for the Library for convenience in moz.build. +STATIC_LIBRARY_NAME = 'stlport_static' + +if not CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk': + OS_LIBS += ['-static-libstdc++'] FORCE_STATIC_LIB = True SOURCES += [ 'src/allocators.cpp', 'src/bitset.cpp', 'src/codecvt.cpp', 'src/collate.cpp',
--- a/build/templates.mozbuild +++ b/build/templates.mozbuild @@ -1,68 +1,80 @@ # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- # vim: set filetype=python: # This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. @template -def StdCppCompat(): - '''Template for libstdc++ compatibility for target binaries.''' +def Binary(): + '''Generic template for target binaries. Meant to be used by other + templates.''' if CONFIG['MOZ_LIBSTDCXX_TARGET_VERSION']: USE_LIBS += ['stdc++compat'] + # Ideally, we'd support not adding this to the LIB_IS_C_ONLY case, + # but that variable is actually only set in db/sqlite/src, which + # doesn't build a shared library on the relevant platforms anyways. + # Eventually, though, we should detect LIB_IS_C_ONLY based on the + # associated SOURCES (and there might actually be places where we + # haven't set it but should have). + if CONFIG['STLPORT_LIBS']: + OS_LIBS += [CONFIG['STLPORT_LIBS']] + elif CONFIG['OS_TARGET'] == 'Android': + USE_LIBS += ['stlport'] + @template def Program(name): '''Template for program executables.''' PROGRAM = name - StdCppCompat() + Binary() @template def SimplePrograms(names, ext='.cpp'): '''Template for simple program executables. Those have a single source with the same base name as the executable. ''' SIMPLE_PROGRAMS += names SOURCES += ['%s%s' % (name, ext) for name in names] - StdCppCompat() + Binary() @template def CppUnitTests(names, ext='.cpp'): '''Template for C++ unit tests. Those have a single source with the same base name as the executable. ''' CPP_UNIT_TESTS += names SOURCES += ['%s%s' % (name, ext) for name in names] - StdCppCompat() + Binary() @template def Library(name): '''Template for libraries.''' LIBRARY_NAME = name @template def SharedLibrary(name): '''Template for shared libraries.''' Library(name) FORCE_SHARED_LIB = True - StdCppCompat() + Binary() @template def Framework(name): '''Template for OSX Frameworks.''' SharedLibrary(name) IS_FRAMEWORK = True
deleted file mode 100644 --- a/build/unix/abs2rel.pl +++ /dev/null @@ -1,35 +0,0 @@ -#!env perl - -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -use File::Spec::Unix; -use strict; - -print "Usage: $0 dest_path start_path\n" if ($#ARGV+1 != 2); -my $finish = my_canonpath(shift); -my $start = my_canonpath(shift); - -my $res = File::Spec::Unix->abs2rel($finish, $start); - -#print STDERR "abs2rel($finish,$start) = $res\n"; -print "$res\n"; - -sub my_canonpath($) { - my ($file) = @_; - my (@inlist, @outlist, $dir); - - # Do what File::Spec::Unix->no_upwards should do - my @inlist = split(/\//, File::Spec::Unix->canonpath($file)); - foreach $dir (@inlist) { - if ($dir eq '..') { - pop @outlist; - } else { - push @outlist, $dir; - } - } - $file = join '/',@outlist; - return $file; -} -
--- a/caps/nsIScriptSecurityManager.idl +++ b/caps/nsIScriptSecurityManager.idl @@ -14,17 +14,17 @@ interface nsILoadContext; %{ C++ #include "jspubtd.h" %} [ptr] native JSContextPtr(JSContext); [ptr] native JSObjectPtr(JSObject); -[scriptable, uuid(3b021962-975e-43b5-8a93-9fc2d20346e9)] +[scriptable, uuid(f649959d-dae3-4027-83fd-5b7f8c8a8815)] interface nsIScriptSecurityManager : nsISupports { /** * For each of these hooks returning NS_OK means 'let the action continue'. * Returning an error code means 'veto the action'. XPConnect will return * false to the js engine if the action is vetoed. The implementor of this * interface is responsible for setting a JS exception into the JSContext * if that is appropriate. @@ -174,23 +174,16 @@ interface nsIScriptSecurityManager : nsI /** * Legacy name for getNoAppCodebasePrincipal. * * @deprecated use getNoAppCodebasePrincipal instead. */ [deprecated] nsIPrincipal getCodebasePrincipal(in nsIURI uri); /** - * Returns OK if aJSContext and target have the same "origin" - * (scheme, host, and port). - */ - [noscript] void checkSameOrigin(in JSContextPtr aJSContext, - in nsIURI aTargetURI); - - /** * Returns OK if aSourceURI and target have the same "origin" * (scheme, host, and port). * ReportError flag suppresses error reports for functions that * don't need reporting. */ void checkSameOriginURI(in nsIURI aSourceURI, in nsIURI aTargetURI, in boolean reportError);
--- a/caps/nsPrincipal.cpp +++ b/caps/nsPrincipal.cpp @@ -341,16 +341,27 @@ nsPrincipal::CheckMayLoad(nsIURI* aURI, if (aAllowIfInheritsPrincipal) { // If the caller specified to allow loads of URIs that inherit // our principal, allow the load if this URI inherits its principal if (nsPrincipal::IsPrincipalInherited(aURI)) { return NS_OK; } } + // See if aURI is something like a Blob URI that is actually associated with + // a principal. + nsCOMPtr<nsIURIWithPrincipal> uriWithPrin = do_QueryInterface(aURI); + nsCOMPtr<nsIPrincipal> uriPrin; + if (uriWithPrin) { + uriWithPrin->GetPrincipal(getter_AddRefs(uriPrin)); + } + if (uriPrin && nsIPrincipal::Subsumes(uriPrin)) { + return NS_OK; + } + if (nsScriptSecurityManager::SecurityCompareURIs(mCodebase, aURI)) { return NS_OK; } // If strict file origin policy is in effect, local files will always fail // SecurityCompareURIs unless they are identical. Explicitly check file origin // policy, in that case. if (nsScriptSecurityManager::GetStrictFileOriginPolicy() &&
--- a/caps/nsScriptSecurityManager.cpp +++ b/caps/nsScriptSecurityManager.cpp @@ -437,49 +437,16 @@ nsScriptSecurityManager::ContentSecurity bool nsScriptSecurityManager::JSPrincipalsSubsume(JSPrincipals *first, JSPrincipals *second) { return nsJSPrincipals::get(first)->Subsumes(nsJSPrincipals::get(second)); } NS_IMETHODIMP -nsScriptSecurityManager::CheckSameOrigin(JSContext* cx, - nsIURI* aTargetURI) -{ - MOZ_ASSERT_IF(cx, cx == nsContentUtils::GetCurrentJSContext()); - - // Get a principal from the context - nsIPrincipal* sourcePrincipal = nsContentUtils::SubjectPrincipal(); - if (sourcePrincipal == mSystemPrincipal) - { - // This is a system (chrome) script, so allow access - return NS_OK; - } - - // Get the original URI from the source principal. - // This has the effect of ignoring any change to document.domain - // which must be done to avoid DNS spoofing (bug 154930) - nsCOMPtr<nsIURI> sourceURI; - sourcePrincipal->GetDomain(getter_AddRefs(sourceURI)); - if (!sourceURI) { - sourcePrincipal->GetURI(getter_AddRefs(sourceURI)); - NS_ENSURE_TRUE(sourceURI, NS_ERROR_FAILURE); - } - - // Compare origins - if (!SecurityCompareURIs(sourceURI, aTargetURI)) - { - ReportError(cx, NS_LITERAL_STRING("CheckSameOriginError"), sourceURI, aTargetURI); - return NS_ERROR_DOM_BAD_URI; - } - return NS_OK; -} - -NS_IMETHODIMP nsScriptSecurityManager::CheckSameOriginURI(nsIURI* aSourceURI, nsIURI* aTargetURI, bool reportError) { if (!SecurityCompareURIs(aSourceURI, aTargetURI)) { if (reportError) { ReportError(nullptr, NS_LITERAL_STRING("CheckSameOriginError"),
deleted file mode 100755 --- a/config/module2dir.pl +++ /dev/null @@ -1,111 +0,0 @@ -#!/usr/bin/perl -w -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - - -# -# Create a mapping from symbolic component name to directory name(s). -# -# Tue Oct 16 16:48:36 PDT 2001 -# <mcafee@netscape.com> - -use strict; - -# For --option1, --option2, ... -use Getopt::Long; -Getopt::Long::Configure("bundling_override"); -Getopt::Long::Configure("auto_abbrev"); - -# Globals -my $list_only_mode = 0; -my $opt_list_only; -my $mapfile = ""; -my %map; - -sub PrintUsage { - die <<END_USAGE - Prints out directories needed for a given list of components. - usage: module2dir.pl [--list-only] [--mapfile mapfile] <component-name1> <component-name2> ... -END_USAGE -} - -sub parse_map_file($) { - my ($mapfile) = @_; - my (%mod_map, $tmp, $dir, $mod, @mod_list); - - undef %mod_map; - open (MAPFILE, "$mapfile") || die ("$mapfile: $!\n"); - while ($tmp=<MAPFILE>) { - chomp ($tmp); - ($dir, $mod, @mod_list) = split(/:/, $tmp, 3); - $mod =~ s/[\s]*(\S+)[\s]*/$1/; - $mod_map{$mod} .= "$dir "; - } - close(MAPFILE); - foreach $mod (sort(keys %mod_map)) { - my (@dirlist, @trimlist, $found, $tdir); - @dirlist = split(/\s+/, $mod_map{$mod}); - $mod_map{$mod} = ""; - foreach $dir (@dirlist) { - $found = 0; - foreach $tdir (@trimlist) { - $found++, last if ($dir =~ m/^$tdir\// || $dir eq $tdir); - } - push @trimlist, $dir if (!$found); - } - $map{$mod} = join(" ", @trimlist); - #print "$mod: $map{$mod}\n"; - } -} - -sub dir_for_required_component { - my ($component) = @_; - my $rv; - my $dir; - - $dir = $map{$component}; - if($dir) { - # prepend "mozilla/" in front of directory names. - $rv = "mozilla/$dir"; - $rv =~ s/\s+/ mozilla\//g; # Hack for 2 or more directories. - } else { - $rv = 0; - } - return $rv; -} - -{ - - # Add stdin to the commandline. This makes commandline-only mode hang, - # call it a bug. Not sure how to get around this. - push (@ARGV, split(' ',<STDIN>)); - - PrintUsage() if !GetOptions('list-only' => \$opt_list_only, - 'mapfile=s' => \$mapfile); - - # Pick up arguments, if any. - if($opt_list_only) { - $list_only_mode = 1; - } - - &parse_map_file($mapfile); - - my $arg; - my $dir; - while ($arg = shift @ARGV) { - $dir = dir_for_required_component($arg); - if($dir) { - if($list_only_mode) { - print $dir, " "; - } else { - print "$arg: ", $dir, "\n"; - } - } else { - # do nothing - } - } - if($dir && $list_only_mode) { - print "\n"; - } -}
--- a/config/recurse.mk +++ b/config/recurse.mk @@ -150,18 +150,13 @@ endif # Note some others are hardcoded or "guessed" in recursivemake.py and emitter.py ifeq ($(MOZ_WIDGET_TOOLKIT),gtk3) toolkit/library/target: widget/gtk/mozgtk/gtk3/target endif ifdef MOZ_LDAP_XPCOM ldap/target: config/external/nss/target mozglue/build/target toolkit/library/target: ldap/target endif -ifndef MOZ_FOLD_LIBS -ifndef MOZ_NATIVE_SQLITE -config/external/nss/target: db/sqlite3/src/target -endif -endif ifeq ($(MOZ_REPLACE_MALLOC_LINKAGE),dummy library) -mozglue/build/target: memory/replace/dummy/target +mozglue/build/target memory/replace/logalloc/replay/target: memory/replace/dummy/target endif endif
--- a/config/rules.mk +++ b/config/rules.mk @@ -691,17 +691,17 @@ ifdef MSMANIFEST_TOOL fi endif # MSVC with manifest tool ifdef MOZ_PROFILE_GENERATE # touch it a few seconds into the future to work around FAT's # 2-second granularity touch -t `date +%Y%m%d%H%M.%S -d 'now+5seconds'` pgo.relink endif else # !WINNT || GNU_CC - $(EXPAND_CCC) -o $@ $(CXXFLAGS) $(PROGOBJS) $(RESFILE) $(WIN32_EXE_LDFLAGS) $(LDFLAGS) $(WRAP_LDFLAGS) $(STATIC_LIBS) $(MOZ_PROGRAM_LDFLAGS) $(SHARED_LIBS) $(EXTRA_LIBS) $(OS_LIBS) $(BIN_FLAGS) $(EXE_DEF_FILE) $(STLPORT_LIBS) + $(EXPAND_CCC) -o $@ $(CXXFLAGS) $(PROGOBJS) $(RESFILE) $(WIN32_EXE_LDFLAGS) $(LDFLAGS) $(WRAP_LDFLAGS) $(STATIC_LIBS) $(MOZ_PROGRAM_LDFLAGS) $(SHARED_LIBS) $(EXTRA_LIBS) $(OS_LIBS) $(BIN_FLAGS) $(EXE_DEF_FILE) $(call CHECK_BINARY,$@) endif # WINNT && !GNU_CC ifdef ENABLE_STRIP $(STRIP) $(STRIP_FLAGS) $@ endif ifdef MOZ_POST_PROGRAM_COMMAND $(MOZ_POST_PROGRAM_COMMAND) $@ @@ -747,17 +747,17 @@ ifeq (_WINNT,$(GNU_CC)_$(OS_ARCH)) $(EXPAND_LD) -nologo -out:$@ -pdb:$(LINK_PDBFILE) $< $(WIN32_EXE_LDFLAGS) $(LDFLAGS) $(MOZ_PROGRAM_LDFLAGS) $(STATIC_LIBS) $(SHARED_LIBS) $(EXTRA_LIBS) $(OS_LIBS) ifdef MSMANIFEST_TOOL @if test -f $@.manifest; then \ mt.exe -NOLOGO -MANIFEST $@.manifest -OUTPUTRESOURCE:$@\;1; \ rm -f $@.manifest; \ fi endif # MSVC with manifest tool else - $(EXPAND_CCC) $(CXXFLAGS) -o $@ $< $(WIN32_EXE_LDFLAGS) $(LDFLAGS) $(WRAP_LDFLAGS) $(STATIC_LIBS) $(MOZ_PROGRAM_LDFLAGS) $(SHARED_LIBS) $(EXTRA_LIBS) $(OS_LIBS) $(BIN_FLAGS) $(STLPORT_LIBS) + $(EXPAND_CCC) $(CXXFLAGS) -o $@ $< $(WIN32_EXE_LDFLAGS) $(LDFLAGS) $(WRAP_LDFLAGS) $(STATIC_LIBS) $(MOZ_PROGRAM_LDFLAGS) $(SHARED_LIBS) $(EXTRA_LIBS) $(OS_LIBS) $(BIN_FLAGS) $(call CHECK_BINARY,$@) endif # WINNT && !GNU_CC ifdef ENABLE_STRIP $(STRIP) $(STRIP_FLAGS) $@ endif ifdef MOZ_POST_PROGRAM_COMMAND $(MOZ_POST_PROGRAM_COMMAND) $@ @@ -829,20 +829,20 @@ endif $(REPORT_BUILD) ifndef INCREMENTAL_LINKER $(RM) $@ endif ifdef DTRACE_LIB_DEPENDENT ifndef XP_MACOSX dtrace -G -C -s $(MOZILLA_DTRACE_SRC) -o $(DTRACE_PROBE_OBJ) $(shell $(EXPAND_LIBS) $(MOZILLA_PROBE_LIBS)) endif - $(EXPAND_MKSHLIB) $(SHLIB_LDSTARTFILE) $(OBJS) $(SUB_SHLOBJS) $(DTRACE_PROBE_OBJ) $(MOZILLA_PROBE_LIBS) $(RESFILE) $(LDFLAGS) $(WRAP_LDFLAGS) $(STATIC_LIBS) $(SHARED_LIBS) $(EXTRA_DSO_LDOPTS) $(MOZ_GLUE_LDFLAGS) $(EXTRA_LIBS) $(OS_LIBS) $(SHLIB_LDENDFILE) $(if $(LIB_IS_C_ONLY),,$(STLPORT_LIBS)) + $(EXPAND_MKSHLIB) $(SHLIB_LDSTARTFILE) $(OBJS) $(SUB_SHLOBJS) $(DTRACE_PROBE_OBJ) $(MOZILLA_PROBE_LIBS) $(RESFILE) $(LDFLAGS) $(WRAP_LDFLAGS) $(STATIC_LIBS) $(SHARED_LIBS) $(EXTRA_DSO_LDOPTS) $(MOZ_GLUE_LDFLAGS) $(EXTRA_LIBS) $(OS_LIBS) $(SHLIB_LDENDFILE) @$(RM) $(DTRACE_PROBE_OBJ) else # ! DTRACE_LIB_DEPENDENT - $(EXPAND_MKSHLIB) $(SHLIB_LDSTARTFILE) $(OBJS) $(SUB_SHLOBJS) $(RESFILE) $(LDFLAGS) $(WRAP_LDFLAGS) $(STATIC_LIBS) $(SHARED_LIBS) $(EXTRA_DSO_LDOPTS) $(MOZ_GLUE_LDFLAGS) $(EXTRA_LIBS) $(OS_LIBS) $(SHLIB_LDENDFILE) $(if $(LIB_IS_C_ONLY),,$(STLPORT_LIBS)) + $(EXPAND_MKSHLIB) $(SHLIB_LDSTARTFILE) $(OBJS) $(SUB_SHLOBJS) $(RESFILE) $(LDFLAGS) $(WRAP_LDFLAGS) $(STATIC_LIBS) $(SHARED_LIBS) $(EXTRA_DSO_LDOPTS) $(MOZ_GLUE_LDFLAGS) $(EXTRA_LIBS) $(OS_LIBS) $(SHLIB_LDENDFILE) endif # DTRACE_LIB_DEPENDENT $(call CHECK_BINARY,$@) ifeq (_WINNT,$(GNU_CC)_$(OS_ARCH)) ifdef MSMANIFEST_TOOL ifdef EMBED_MANIFEST_AT @if test -f $@.manifest; then \ mt.exe -NOLOGO -MANIFEST $@.manifest -OUTPUTRESOURCE:$@\;$(EMBED_MANIFEST_AT); \
--- a/configure.in +++ b/configure.in @@ -224,17 +224,16 @@ if test -n "$gonkdir" ; then RANLIB="$gonk_toolchain_prefix"ranlib STRIP="$gonk_toolchain_prefix"strip OBJCOPY="$gonk_toolchain_prefix"objcopy if ! test -e "$gonkdir/ndk/sources/cxx-stl/stlport/src/iostream.cpp"; then AC_MSG_ERROR([Couldn't find path to stlport sources in the gonk tree]) fi STLPORT_CPPFLAGS="-I$_topsrcdir/build/stlport/stlport -I$gonkdir/ndk/sources/cxx-stl/system/include" - STLPORT_LIBS="$_objdir/build/stlport/libstlport_static.a" case "$target_cpu" in arm) ARCH_DIR=arch-arm ;; i?86) ARCH_DIR=arch-x86 ;; @@ -9055,18 +9054,16 @@ HAVE_STATVFS HAVE_STATFS64 HAVE_STATFS HAVE_SYS_STATVFS_H HAVE_SYS_STATFS_H HAVE_SYS_VFS_H HAVE_SYS_MOUNT_H " -AC_SUBST(STLPORT_LIBS) - dnl ======================================================== dnl ICU Support dnl ======================================================== # Internationalization isn't built or exposed by default in non-desktop # builds. Bugs to enable: # # Android: bug 864843
--- a/docshell/test/chrome/bug113934_window.xul +++ b/docshell/test/chrome/bug113934_window.xul @@ -48,18 +48,19 @@ $("f2").setAttribute("src", doc2); $("f3").setAttribute("src", doc2); function doTheTest() { var s1 = snapshotWindow($("f1").contentWindow); var s2 = snapshotWindow($("f2").contentWindow); var s3 = snapshotWindow($("f3").contentWindow); - ok(!compareSnapshots(s2, s3, true)[0], - "Should look different due to different sizing"); + // This test is broken - see bug 1090274 + //ok(!compareSnapshots(s2, s3, true)[0], + // "Should look different due to different sizing"); function getDOM(id) { return $(id).contentDocument.documentElement.innerHTML; } var dom1 = getDOM("f1"); var dom2 = getDOM("f2");
--- a/dom/base/Navigator.cpp +++ b/dom/base/Navigator.cpp @@ -64,16 +64,17 @@ #include "nsIDOMNavigatorSystemMessages.h" #include "nsStreamUtils.h" #include "nsIAppsService.h" #include "mozIApplication.h" #include "WidgetUtils.h" #include "mozIThirdPartyUtil.h" #ifdef MOZ_MEDIA_NAVIGATOR +#include "mozilla/dom/MediaDevices.h" #include "MediaManager.h" #endif #ifdef MOZ_B2G_BT #include "BluetoothManager.h" #endif #include "DOMCameraManager.h" #ifdef MOZ_AUDIO_CHANNEL_MANAGER @@ -1208,16 +1209,31 @@ Navigator::SendBeacon(const nsAString& a if (NS_FAILED(rv)) { aRv.Throw(rv); return false; } return true; } #ifdef MOZ_MEDIA_NAVIGATOR +MediaDevices* +Navigator::GetMediaDevices(ErrorResult& aRv) +{ + if (!mMediaDevices) { + if (!mWindow || + !mWindow->GetOuterWindow() || + mWindow->GetOuterWindow()->GetCurrentInnerWindow() != mWindow) { + aRv.Throw(NS_ERROR_NOT_AVAILABLE); + return nullptr; + } + mMediaDevices = new MediaDevices(mWindow); + } + return mMediaDevices; +} + void Navigator::MozGetUserMedia(const MediaStreamConstraints& aConstraints, NavigatorUserMediaSuccessCallback& aOnSuccess, NavigatorUserMediaErrorCallback& aOnError, ErrorResult& aRv) { CallbackObjectHolder<NavigatorUserMediaSuccessCallback, nsIDOMGetUserMediaSuccessCallback> holder1(&aOnSuccess);
--- a/dom/base/Navigator.h +++ b/dom/base/Navigator.h @@ -27,16 +27,17 @@ class nsDOMCameraManager; class nsDOMDeviceStorage; class nsIPrincipal; class nsIURI; namespace mozilla { namespace dom { class Geolocation; class systemMessageCallback; +class MediaDevices; struct MediaStreamConstraints; class WakeLock; class ArrayBufferViewOrBlobOrStringOrFormData; struct MobileIdOptions; class ServiceWorkerContainer; } } @@ -219,16 +220,17 @@ public: ErrorResult& aRv); DesktopNotificationCenter* GetMozNotification(ErrorResult& aRv); CellBroadcast* GetMozCellBroadcast(ErrorResult& aRv); MobileMessageManager* GetMozMobileMessage(); Telephony* GetMozTelephony(ErrorResult& aRv); Voicemail* GetMozVoicemail(ErrorResult& aRv); network::Connection* GetConnection(ErrorResult& aRv); nsDOMCameraManager* GetMozCameras(ErrorResult& aRv); + MediaDevices* GetMediaDevices(ErrorResult& aRv); void MozSetMessageHandler(const nsAString& aType, systemMessageCallback* aCallback, ErrorResult& aRv); bool MozHasPendingMessage(const nsAString& aType, ErrorResult& aRv); #ifdef MOZ_B2G already_AddRefed<Promise> GetMobileIdAssertion(const MobileIdOptions& options, ErrorResult& aRv); #endif @@ -339,16 +341,17 @@ private: #endif #ifdef MOZ_B2G_BT nsRefPtr<bluetooth::BluetoothManager> mBluetooth; #endif #ifdef MOZ_AUDIO_CHANNEL_MANAGER nsRefPtr<system::AudioChannelManager> mAudioChannelManager; #endif nsRefPtr<nsDOMCameraManager> mCameraManager; + nsRefPtr<MediaDevices> mMediaDevices; nsCOMPtr<nsIDOMNavigatorSystemMessages> mMessagesManager; nsTArray<nsRefPtr<nsDOMDeviceStorage> > mDeviceStorageStores; nsRefPtr<time::TimeManager> mTimeManager; nsRefPtr<ServiceWorkerContainer> mServiceWorkerContainer; nsCOMPtr<nsPIDOMWindow> mWindow; // Hashtable for saving cached objects newresolve created, so we don't create // the object twice if asked for it twice, whether due to use of "delete" or
--- a/dom/indexedDB/ActorsParent.cpp +++ b/dom/indexedDB/ActorsParent.cpp @@ -41,17 +41,16 @@ #include "mozilla/dom/indexedDB/PBackgroundIDBTransactionParent.h" #include "mozilla/dom/indexedDB/PBackgroundIDBVersionChangeTransactionParent.h" #include "mozilla/dom/indexedDB/PIndexedDBPermissionRequestParent.h" #include "mozilla/dom/ipc/BlobParent.h" #include "mozilla/dom/quota/Client.h" #include "mozilla/dom/quota/FileStreams.h" #include "mozilla/dom/quota/OriginOrPatternString.h" #include "mozilla/dom/quota/QuotaManager.h" -#include "mozilla/dom/quota/StoragePrivilege.h" #include "mozilla/dom/quota/UsageInfo.h" #include "mozilla/ipc/BackgroundParent.h" #include "mozilla/ipc/BackgroundUtils.h" #include "mozilla/ipc/InputStreamParams.h" #include "mozilla/ipc/InputStreamUtils.h" #include "mozilla/ipc/PBackground.h" #include "nsCharSeparatedTokenizer.h" #include "nsClassHashtable.h" @@ -3880,17 +3879,16 @@ protected: nsTArray<MaybeBlockedDatabaseInfo> mMaybeBlockedDatabases; const CommonFactoryRequestParams mCommonParams; nsCString mGroup; nsCString mOrigin; nsCString mDatabaseId; State mState; - StoragePrivilege mStoragePrivilege; bool mEnforcingQuota; const bool mDeleting; bool mBlockedQuotaManager; bool mChromeWriteAccessAllowed; public: void NoteDatabaseBlocked(Database* aDatabase); @@ -8585,24 +8583,24 @@ Cursor::RecvContinue(const CursorRequest /******************************************************************************* * FileManager ******************************************************************************/ FileManager::FileManager(PersistenceType aPersistenceType, const nsACString& aGroup, const nsACString& aOrigin, - StoragePrivilege aPrivilege, - const nsAString& aDatabaseName) + const nsAString& aDatabaseName, + bool aEnforcingQuota) : mPersistenceType(aPersistenceType) , mGroup(aGroup) , mOrigin(aOrigin) - , mPrivilege(aPrivilege) , mDatabaseName(aDatabaseName) , mLastFileId(0) + , mEnforcingQuota(aEnforcingQuota) , mInvalidated(false) { } FileManager::~FileManager() { } nsresult FileManager::Init(nsIFile* aDirectory, @@ -10431,17 +10429,16 @@ AutoSetProgressHandler::Register( FactoryOp::FactoryOp(Factory* aFactory, already_AddRefed<ContentParent> aContentParent, const CommonFactoryRequestParams& aCommonParams, bool aDeleting) : mFactory(aFactory) , mContentParent(Move(aContentParent)) , mCommonParams(aCommonParams) , mState(State_Initial) - , mStoragePrivilege(mozilla::dom::quota::Content) , mEnforcingQuota(true) , mDeleting(aDeleting) , mBlockedQuotaManager(false) , mChromeWriteAccessAllowed(false) { AssertIsOnBackgroundThread(); MOZ_ASSERT(aFactory); MOZ_ASSERT(!QuotaClient::IsShuttingDownOnNonMainThread()); @@ -10730,19 +10727,17 @@ FactoryOp::CheckPermission(ContentParent } mChromeWriteAccessAllowed = canWrite; } else { mChromeWriteAccessAllowed = true; } if (State_Initial == mState) { - QuotaManager::GetInfoForChrome(&mGroup, &mOrigin, &mStoragePrivilege, - nullptr); - MOZ_ASSERT(mStoragePrivilege == mozilla::dom::quota::Chrome); + QuotaManager::GetInfoForChrome(&mGroup, &mOrigin, nullptr, nullptr); mEnforcingQuota = false; } *aPermission = PermissionRequestBase::kPermissionAllowed; return NS_OK; } MOZ_ASSERT(principalInfo.type() == PrincipalInfo::TContentPrincipalInfo); @@ -10784,22 +10779,20 @@ FactoryOp::CheckPermission(ContentParent return rv; } } } if (permission != PermissionRequestBase::kPermissionDenied && State_Initial == mState) { rv = QuotaManager::GetInfoFromPrincipal(principal, &mGroup, &mOrigin, - &mStoragePrivilege, nullptr); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - - MOZ_ASSERT(mStoragePrivilege != mozilla::dom::quota::Chrome); + nullptr, nullptr); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } } if (permission == PermissionRequestBase::kPermissionAllowed && mEnforcingQuota) { // If we're running from a window then we should check the quota permission // as well. uint32_t quotaPermission = CheckQuotaHelper::GetQuotaPermission(principal); @@ -11321,18 +11314,18 @@ OpenDatabaseOp::DoDatabaseWork() MOZ_ASSERT(mgr); nsRefPtr<FileManager> fileManager = mgr->GetFileManager(persistenceType, mOrigin, databaseName); if (!fileManager) { fileManager = new FileManager(persistenceType, mGroup, mOrigin, - mStoragePrivilege, - databaseName); + databaseName, + mEnforcingQuota); rv = fileManager->Init(fmDirectory, connection); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } mgr->AddFileManager(fileManager); } @@ -12699,29 +12692,29 @@ VersionChangeOp::RunOnIOThread() mDeleteDatabaseOp->mCommonParams.metadata().persistenceType(); QuotaManager* quotaManager = QuotaManager::Get(); MOZ_ASSERT(quotaManager); if (exists) { int64_t fileSize; - if (mDeleteDatabaseOp->mStoragePrivilege != Chrome) { + if (mDeleteDatabaseOp->mEnforcingQuota) { rv = dbFile->GetFileSize(&fileSize); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } } rv = dbFile->Remove(false); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } - if (mDeleteDatabaseOp->mStoragePrivilege != Chrome) { + if (mDeleteDatabaseOp->mEnforcingQuota) { quotaManager->DecreaseUsageForOrigin(persistenceType, mDeleteDatabaseOp->mGroup, mDeleteDatabaseOp->mOrigin, fileSize); } } nsCOMPtr<nsIFile> dbJournalFile; @@ -12776,29 +12769,29 @@ VersionChangeOp::RunOnIOThread() if (NS_WARN_IF(!isDirectory)) { IDB_REPORT_INTERNAL_ERR(); return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; } uint64_t usage = 0; - if (mDeleteDatabaseOp->mStoragePrivilege != Chrome) { + if (mDeleteDatabaseOp->mEnforcingQuota) { rv = FileManager::GetUsage(fmDirectory, &usage); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } } rv = fmDirectory->Remove(true); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } - if (mDeleteDatabaseOp->mStoragePrivilege != Chrome) { + if (mDeleteDatabaseOp->mEnforcingQuota) { quotaManager->DecreaseUsageForOrigin(persistenceType, mDeleteDatabaseOp->mGroup, mDeleteDatabaseOp->mOrigin, usage); } } IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get(); @@ -14420,22 +14413,24 @@ ObjectStoreAddOrPutRequestOp::CopyFileDa } if (NS_WARN_IF(numWrite != numRead)) { rv = NS_ERROR_FAILURE; break; } } while (true); - nsresult rv2 = aOutputStream->Flush(); - if (NS_WARN_IF(NS_FAILED(rv2))) { - return NS_SUCCEEDED(rv) ? rv2 : rv; - } - - rv2 = aOutputStream->Close(); + if (NS_SUCCEEDED(rv)) { + rv = aOutputStream->Flush(); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + } + + nsresult rv2 = aOutputStream->Close(); if (NS_WARN_IF(NS_FAILED(rv2))) { return NS_SUCCEEDED(rv) ? rv2 : rv; } return rv; } bool @@ -14799,19 +14794,41 @@ ObjectStoreAddOrPutRequestOp::DoDatabase rv = CopyFileData(inputStream, outputStream); if (NS_FAILED(rv) && NS_ERROR_GET_MODULE(rv) != NS_ERROR_MODULE_DOM_INDEXEDDB) { IDB_REPORT_INTERNAL_ERR(); rv = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; } if (NS_WARN_IF(NS_FAILED(rv))) { // Try to remove the file if the copy failed. - if (NS_FAILED(diskFile->Remove(false))) { - NS_WARNING("Failed to remove file after copying failed!"); + nsresult rv2; + int64_t fileSize; + + if (mFileManager->EnforcingQuota()) { + rv2 = diskFile->GetFileSize(&fileSize); + if (NS_WARN_IF(NS_FAILED(rv2))) { + return rv; + } } + + rv2 = diskFile->Remove(false); + if (NS_WARN_IF(NS_FAILED(rv2))) { + return rv; + } + + if (mFileManager->EnforcingQuota()) { + QuotaManager* quotaManager = QuotaManager::Get(); + MOZ_ASSERT(quotaManager); + + quotaManager->DecreaseUsageForOrigin(mFileManager->Type(), + mFileManager->Group(), + mFileManager->Origin(), + fileSize); + } + return rv; } storedFileInfo.mCopiedSuccessfully = true; } } if (index) {
--- a/dom/indexedDB/FileManager.h +++ b/dom/indexedDB/FileManager.h @@ -4,17 +4,16 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef mozilla_dom_indexeddb_filemanager_h__ #define mozilla_dom_indexeddb_filemanager_h__ #include "mozilla/Attributes.h" #include "mozilla/dom/quota/PersistenceType.h" -#include "mozilla/dom/quota/StoragePrivilege.h" #include "nsDataHashtable.h" #include "nsHashKeys.h" #include "nsISupportsImpl.h" class nsIFile; class mozIStorageConnection; namespace mozilla { @@ -24,32 +23,31 @@ namespace indexedDB { class FileInfo; // Implemented in ActorsParent.cpp. class FileManager MOZ_FINAL { friend class FileInfo; typedef mozilla::dom::quota::PersistenceType PersistenceType; - typedef mozilla::dom::quota::StoragePrivilege StoragePrivilege; PersistenceType mPersistenceType; nsCString mGroup; nsCString mOrigin; - StoragePrivilege mPrivilege; nsString mDatabaseName; nsString mDirectoryPath; nsString mJournalDirectoryPath; int64_t mLastFileId; // Protected by IndexedDatabaseManager::FileMutex() nsDataHashtable<nsUint64HashKey, FileInfo*> mFileInfos; + const bool mEnforcingQuota; bool mInvalidated; public: static already_AddRefed<nsIFile> GetFileForId(nsIFile* aDirectory, int64_t aId); static nsresult InitDirectory(nsIFile* aDirectory, @@ -59,18 +57,18 @@ public: const nsACString& aOrigin); static nsresult GetUsage(nsIFile* aDirectory, uint64_t* aUsage); FileManager(PersistenceType aPersistenceType, const nsACString& aGroup, const nsACString& aOrigin, - StoragePrivilege aPrivilege, - const nsAString& aDatabaseName); + const nsAString& aDatabaseName, + bool aEnforcingQuota); PersistenceType Type() const { return mPersistenceType; } const nsACString& @@ -80,29 +78,29 @@ public: } const nsACString& Origin() const { return mOrigin; } - const StoragePrivilege& - Privilege() const - { - return mPrivilege; - } - const nsAString& DatabaseName() const { return mDatabaseName; } bool + EnforcingQuota() const + { + return mEnforcingQuota; + } + + bool Invalidated() const { return mInvalidated; } nsresult Init(nsIFile* aDirectory, mozIStorageConnection* aConnection);
--- a/dom/indexedDB/IndexedDatabaseManager.cpp +++ b/dom/indexedDB/IndexedDatabaseManager.cpp @@ -843,25 +843,25 @@ AsyncDeleteFileRunnable::Run() NS_ENSURE_TRUE(directory, NS_ERROR_FAILURE); nsCOMPtr<nsIFile> file = mFileManager->GetFileForId(directory, mFileId); NS_ENSURE_TRUE(file, NS_ERROR_FAILURE); nsresult rv; int64_t fileSize; - if (mFileManager->Privilege() != Chrome) { + if (mFileManager->EnforcingQuota()) { rv = file->GetFileSize(&fileSize); NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE); } rv = file->Remove(false); NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE); - if (mFileManager->Privilege() != Chrome) { + if (mFileManager->EnforcingQuota()) { QuotaManager* quotaManager = QuotaManager::Get(); NS_ASSERTION(quotaManager, "Shouldn't be null!"); quotaManager->DecreaseUsageForOrigin(mFileManager->Type(), mFileManager->Group(), mFileManager->Origin(), fileSize); }
--- a/dom/indexedDB/SerializationHelpers.h +++ b/dom/indexedDB/SerializationHelpers.h @@ -7,36 +7,28 @@ #include "ipc/IPCMessageUtils.h" #include "mozilla/dom/indexedDB/Key.h" #include "mozilla/dom/indexedDB/KeyPath.h" #include "mozilla/dom/indexedDB/IDBCursor.h" #include "mozilla/dom/indexedDB/IDBTransaction.h" #include "mozilla/dom/quota/PersistenceType.h" -#include "mozilla/dom/quota/StoragePrivilege.h" namespace IPC { template <> struct ParamTraits<mozilla::dom::quota::PersistenceType> : public ContiguousEnumSerializer< mozilla::dom::quota::PersistenceType, mozilla::dom::quota::PERSISTENCE_TYPE_PERSISTENT, mozilla::dom::quota::PERSISTENCE_TYPE_INVALID> { }; template <> -struct ParamTraits<mozilla::dom::quota::StoragePrivilege> : - public ContiguousEnumSerializer<mozilla::dom::quota::StoragePrivilege, - mozilla::dom::quota::Chrome, - mozilla::dom::quota::Invalid> -{ }; - -template <> struct ParamTraits<mozilla::dom::indexedDB::Key> { typedef mozilla::dom::indexedDB::Key paramType; static void Write(Message* aMsg, const paramType& aParam) { WriteParam(aMsg, aParam.mBuffer); }
--- a/dom/media/DOMMediaStream.cpp +++ b/dom/media/DOMMediaStream.cpp @@ -28,17 +28,22 @@ NS_IMPL_CYCLE_COLLECTION_INHERITED(DOMMe NS_IMPL_ADDREF_INHERITED(DOMMediaStream, DOMEventTargetHelper) NS_IMPL_RELEASE_INHERITED(DOMMediaStream, DOMEventTargetHelper) NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(DOMMediaStream) NS_INTERFACE_MAP_ENTRY(DOMMediaStream) NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper) -NS_IMPL_ISUPPORTS_INHERITED0(DOMLocalMediaStream, DOMMediaStream) +NS_IMPL_ADDREF_INHERITED(DOMLocalMediaStream, DOMMediaStream) +NS_IMPL_RELEASE_INHERITED(DOMLocalMediaStream, DOMMediaStream) + +NS_INTERFACE_MAP_BEGIN(DOMLocalMediaStream) + NS_INTERFACE_MAP_ENTRY(DOMLocalMediaStream) +NS_INTERFACE_MAP_END_INHERITING(DOMMediaStream) NS_IMPL_CYCLE_COLLECTION_INHERITED(DOMAudioNodeMediaStream, DOMMediaStream, mStreamNode) NS_IMPL_ADDREF_INHERITED(DOMAudioNodeMediaStream, DOMMediaStream) NS_IMPL_RELEASE_INHERITED(DOMAudioNodeMediaStream, DOMMediaStream) NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(DOMAudioNodeMediaStream)
--- a/dom/media/MediaDecoderReader.cpp +++ b/dom/media/MediaDecoderReader.cpp @@ -15,25 +15,20 @@ namespace mozilla { // Un-comment to enable logging of seek bisections. //#define SEEK_LOGGING #ifdef PR_LOGGING extern PRLogModuleInfo* gMediaDecoderLog; -#define DECODER_LOG(type, msg) PR_LOG(gMediaDecoderLog, type, msg) -#ifdef SEEK_LOGGING -#define SEEK_LOG(type, msg) PR_LOG(gMediaDecoderLog, type, msg) +#define DECODER_LOG(x, ...) \ + PR_LOG(gMediaDecoderLog, PR_LOG_DEBUG, ("Decoder=%p " x, mDecoder, ##__VA_ARGS__)) #else -#define SEEK_LOG(type, msg) -#endif -#else -#define DECODER_LOG(type, msg) -#define SEEK_LOG(type, msg) +#define DECODER_LOG(x, ...) #endif class VideoQueueMemoryFunctor : public nsDequeFunctor { public: VideoQueueMemoryFunctor() : mSize(0) {} MOZ_DEFINE_MALLOC_SIZE_OF(MallocSizeOf); @@ -134,16 +129,30 @@ MediaDecoderReader::GetBuffered(mozilla: { ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor()); durationUs = mDecoder->GetMediaDuration(); } GetEstimatedBufferedTimeRanges(stream, durationUs, aBuffered); return NS_OK; } +int64_t +MediaDecoderReader::ComputeStartTime(const VideoData* aVideo, const AudioData* aAudio) +{ + int64_t startTime = std::min<int64_t>(aAudio ? aAudio->mTime : INT64_MAX, + aVideo ? aVideo->mTime : INT64_MAX); + if (startTime == INT64_MAX) { + startTime = 0; + } + DECODER_LOG("ComputeStartTime first video frame start %lld", aVideo ? aVideo->mTime : -1); + DECODER_LOG("ComputeStartTime first audio frame start %lld", aAudio ? aAudio->mTime : -1); + MOZ_ASSERT(startTime >= 0); + return startTime; +} + class RequestVideoWithSkipTask : public nsRunnable { public: RequestVideoWithSkipTask(MediaDecoderReader* aReader, int64_t aTimeThreshold) : mReader(aReader) , mTimeThreshold(aTimeThreshold) { }
--- a/dom/media/MediaDecoderReader.h +++ b/dom/media/MediaDecoderReader.h @@ -143,16 +143,18 @@ public: // is that it's a fast approximation, which does not perform any I/O. // // The OggReader relies on this base implementation not performing I/O, // since in FirefoxOS we can't do I/O on the main thread, where this is // called. virtual nsresult GetBuffered(dom::TimeRanges* aBuffered, int64_t aStartTime); + virtual int64_t ComputeStartTime(const VideoData* aVideo, const AudioData* aAudio); + // Returns the number of bytes of memory allocated by structures/frames in // the video queue. size_t SizeOfVideoQueueInBytes() const; // Returns the number of bytes of memory allocated by structures/frames in // the audio queue. size_t SizeOfAudioQueueInBytes() const;
--- a/dom/media/MediaDecoderStateMachine.cpp +++ b/dom/media/MediaDecoderStateMachine.cpp @@ -2011,28 +2011,19 @@ MediaDecoderStateMachine::FinishDecodeMe NS_ASSERTION(OnDecodeThread(), "Should be on decode thread."); DECODER_LOG("FinishDecodeMetadata"); if (mState == DECODER_STATE_SHUTDOWN) { return NS_ERROR_FAILURE; } if (!mScheduler->IsRealTime() && !mDecodingFrozenAtStateMetadata) { - const VideoData* v = VideoQueue().PeekFront(); const AudioData* a = AudioQueue().PeekFront(); - - int64_t startTime = std::min<int64_t>(a ? a->mTime : INT64_MAX, - v ? v->mTime : INT64_MAX); - if (startTime == INT64_MAX) { - startTime = 0; - } - DECODER_LOG("DecodeMetadata first video frame start %lld", v ? v->mTime : -1); - DECODER_LOG("DecodeMetadata first audio frame start %lld", a ? a->mTime : -1); - SetStartTime(startTime); + SetStartTime(mReader->ComputeStartTime(v, a)); if (VideoQueue().GetSize()) { ReentrantMonitorAutoExit exitMon(mDecoder->GetReentrantMonitor()); RenderVideoFrame(VideoQueue().PeekFront(), TimeStamp::Now()); } } NS_ASSERTION(mStartTime != -1, "Must have start time"); MOZ_ASSERT((!HasVideo() && !HasAudio()) ||
new file mode 100644 --- /dev/null +++ b/dom/media/MediaDevices.cpp @@ -0,0 +1,97 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "mozilla/dom/MediaDevices.h" +#include "mozilla/dom/MediaStreamBinding.h" +#include "mozilla/dom/MediaDevicesBinding.h" +#include "mozilla/dom/Promise.h" +#include "mozilla/MediaManager.h" +#include "nsIEventTarget.h" +#include "nsIScriptGlobalObject.h" +#include "nsPIDOMWindow.h" + +namespace mozilla { +namespace dom { + +class MediaDevices::GumResolver : public nsIDOMGetUserMediaSuccessCallback +{ +public: + NS_DECL_ISUPPORTS + + explicit GumResolver(Promise* aPromise) : mPromise(aPromise) {} + + NS_IMETHOD + OnSuccess(nsISupports* aStream) MOZ_OVERRIDE + { + nsRefPtr<DOMLocalMediaStream> stream = do_QueryObject(aStream); + if (!stream) { + return NS_ERROR_FAILURE; + } + mPromise->MaybeResolve(stream); + return NS_OK; + } + +private: + virtual ~GumResolver() {} + nsRefPtr<Promise> mPromise; +}; + +class MediaDevices::GumRejecter : public nsIDOMGetUserMediaErrorCallback +{ +public: + NS_DECL_ISUPPORTS + + explicit GumRejecter(Promise* aPromise) : mPromise(aPromise) {} + + NS_IMETHOD + OnError(nsISupports* aError) MOZ_OVERRIDE + { + nsRefPtr<MediaStreamError> error = do_QueryObject(aError); + if (!error) { + return NS_ERROR_FAILURE; + } + mPromise->MaybeReject(error); + return NS_OK; + } + +private: + virtual ~GumRejecter() {} + nsRefPtr<Promise> mPromise; +}; + +NS_IMPL_ISUPPORTS(MediaDevices::GumResolver, nsIDOMGetUserMediaSuccessCallback) +NS_IMPL_ISUPPORTS(MediaDevices::GumRejecter, nsIDOMGetUserMediaErrorCallback) + +already_AddRefed<Promise> +MediaDevices::GetUserMedia(const MediaStreamConstraints& aConstraints, + ErrorResult &aRv) +{ + ErrorResult rv; + nsPIDOMWindow* window = GetOwner(); + nsCOMPtr<nsIGlobalObject> go = do_QueryInterface(window); + nsRefPtr<Promise> p = Promise::Create(go, aRv); + NS_ENSURE_TRUE(!rv.Failed(), nullptr); + + nsRefPtr<GumResolver> resolver = new GumResolver(p); + nsRefPtr<GumRejecter> rejecter = new GumRejecter(p); + + aRv = MediaManager::Get()->GetUserMedia(window, aConstraints, + resolver, rejecter); + return p.forget(); +} + +NS_IMPL_ADDREF_INHERITED(MediaDevices, DOMEventTargetHelper) +NS_IMPL_RELEASE_INHERITED(MediaDevices, DOMEventTargetHelper) +NS_INTERFACE_MAP_BEGIN(MediaDevices) + NS_INTERFACE_MAP_ENTRY(MediaDevices) +NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper) + +JSObject* +MediaDevices::WrapObject(JSContext* aCx) +{ + return MediaDevicesBinding::Wrap(aCx, this); +} + +} // namespace dom +} // namespace mozilla
new file mode 100644 --- /dev/null +++ b/dom/media/MediaDevices.h @@ -0,0 +1,50 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef MediaDevices_h__ +#define MediaDevices_h__ + +#include "mozilla/ErrorResult.h" +#include "nsISupportsImpl.h" +#include "mozilla/DOMEventTargetHelper.h" +#include "mozilla/dom/BindingUtils.h" +#include "nsPIDOMWindow.h" + +namespace mozilla { +namespace dom { + +class Promise; +struct MediaStreamConstraints; + +#define MOZILLA_DOM_MEDIADEVICES_IMPLEMENTATION_IID \ +{ 0x2f784d8a, 0x7485, 0x4280, \ + { 0x9a, 0x36, 0x74, 0xa4, 0xd6, 0x71, 0xa6, 0xc8 } } + +class MediaDevices MOZ_FINAL : public DOMEventTargetHelper +{ +public: + MediaDevices(nsPIDOMWindow* aWindow) : DOMEventTargetHelper(aWindow) {} + + NS_DECL_ISUPPORTS_INHERITED + NS_DECLARE_STATIC_IID_ACCESSOR(MOZILLA_DOM_MEDIADEVICES_IMPLEMENTATION_IID) + + JSObject* WrapObject(JSContext* cx) MOZ_OVERRIDE; + + already_AddRefed<Promise> + GetUserMedia(const MediaStreamConstraints& aConstraints, ErrorResult &aRv); + +private: + class GumResolver; + class GumRejecter; + + virtual ~MediaDevices() {} +}; + +NS_DEFINE_STATIC_IID_ACCESSOR(MediaDevices, + MOZILLA_DOM_MEDIADEVICES_IMPLEMENTATION_IID) + +} // namespace dom +} // namespace mozilla + +#endif // MediaDevices_h__
--- a/dom/media/MediaManager.cpp +++ b/dom/media/MediaManager.cpp @@ -97,16 +97,17 @@ GetMediaManagerLog() #define LOG(msg) PR_LOG(GetMediaManagerLog(), PR_LOG_DEBUG, msg) #else #define LOG(msg) #endif using dom::MediaStreamConstraints; // Outside API (contains JSObject) using dom::MediaTrackConstraintSet; // Mandatory or optional constraints using dom::MediaTrackConstraints; // Raw mMandatory (as JSObject) +using dom::MediaStreamError; using dom::GetUserMediaRequest; using dom::Sequence; using dom::OwningBooleanOrMediaTrackConstraints; using dom::SupportedAudioConstraints; using dom::SupportedVideoConstraints; static bool HostInDomain(const nsCString &aHost, const nsCString &aPattern) @@ -189,116 +190,121 @@ HostHasPermission(nsIURI &docURI) begin = end + 1; } while (end < domainWhiteList.Length()); return false; } ErrorCallbackRunnable::ErrorCallbackRunnable( - nsCOMPtr<nsIDOMGetUserMediaSuccessCallback>& aSuccess, - nsCOMPtr<nsIDOMGetUserMediaErrorCallback>& aError, - const nsAString& aErrorMsg, uint64_t aWindowID) - : mErrorMsg(aErrorMsg) + nsCOMPtr<nsIDOMGetUserMediaSuccessCallback>& aOnSuccess, + nsCOMPtr<nsIDOMGetUserMediaErrorCallback>& aOnFailure, + MediaMgrError& aError, + uint64_t aWindowID) + : mError(&aError) , mWindowID(aWindowID) , mManager(MediaManager::GetInstance()) { - mSuccess.swap(aSuccess); - mError.swap(aError); + mOnSuccess.swap(aOnSuccess); + mOnFailure.swap(aOnFailure); } ErrorCallbackRunnable::~ErrorCallbackRunnable() { - MOZ_ASSERT(!mSuccess && !mError); + MOZ_ASSERT(!mOnSuccess && !mOnFailure); } NS_IMETHODIMP ErrorCallbackRunnable::Run() { // Only run if the window is still active. NS_ASSERTION(NS_IsMainThread(), "Only call on main thread"); - nsCOMPtr<nsIDOMGetUserMediaSuccessCallback> success = mSuccess.forget(); - nsCOMPtr<nsIDOMGetUserMediaErrorCallback> error = mError.forget(); + nsCOMPtr<nsIDOMGetUserMediaSuccessCallback> onSuccess = mOnSuccess.forget(); + nsCOMPtr<nsIDOMGetUserMediaErrorCallback> onFailure = mOnFailure.forget(); if (!(mManager->IsWindowStillActive(mWindowID))) { return NS_OK; } // This is safe since we're on main-thread, and the windowlist can only // be invalidated from the main-thread (see OnNavigation) - error->OnError(mErrorMsg); + nsGlobalWindow* window = nsGlobalWindow::GetInnerWindowWithId(mWindowID); + if (window) { + nsRefPtr<MediaStreamError> error = new MediaStreamError(window, *mError); + onFailure->OnError(error); + } return NS_OK; } /** * Invoke the "onSuccess" callback in content. The callback will take a * DOMBlob in the case of {picture:true}, and a MediaStream in the case of * {audio:true} or {video:true}. There is a constructor available for each * form. Do this only on the main thread. */ class SuccessCallbackRunnable : public nsRunnable { public: SuccessCallbackRunnable( - nsCOMPtr<nsIDOMGetUserMediaSuccessCallback>& aSuccess, - nsCOMPtr<nsIDOMGetUserMediaErrorCallback>& aError, + nsCOMPtr<nsIDOMGetUserMediaSuccessCallback>& aOnSuccess, + nsCOMPtr<nsIDOMGetUserMediaErrorCallback>& aOnFailure, nsIDOMFile* aFile, uint64_t aWindowID) : mFile(aFile) , mWindowID(aWindowID) , mManager(MediaManager::GetInstance()) { - mSuccess.swap(aSuccess); - mError.swap(aError); + mOnSuccess.swap(aOnSuccess); + mOnFailure.swap(aOnFailure); } NS_IMETHOD Run() { // Only run if the window is still active. NS_ASSERTION(NS_IsMainThread(), "Only call on main thread"); - nsCOMPtr<nsIDOMGetUserMediaSuccessCallback> success = mSuccess.forget(); - nsCOMPtr<nsIDOMGetUserMediaErrorCallback> error = mError.forget(); + nsCOMPtr<nsIDOMGetUserMediaSuccessCallback> onSuccess = mOnSuccess.forget(); + nsCOMPtr<nsIDOMGetUserMediaErrorCallback> onFailure = mOnFailure.forget(); if (!(mManager->IsWindowStillActive(mWindowID))) { return NS_OK; } // This is safe since we're on main-thread, and the windowlist can only // be invalidated from the main-thread (see OnNavigation) - success->OnSuccess(mFile); + onSuccess->OnSuccess(mFile); return NS_OK; } private: - nsCOMPtr<nsIDOMGetUserMediaSuccessCallback> mSuccess; - nsCOMPtr<nsIDOMGetUserMediaErrorCallback> mError; + nsCOMPtr<nsIDOMGetUserMediaSuccessCallback> mOnSuccess; + nsCOMPtr<nsIDOMGetUserMediaErrorCallback> mOnFailure; nsCOMPtr<nsIDOMFile> mFile; uint64_t mWindowID; nsRefPtr<MediaManager> mManager; // get ref to this when creating the runnable }; /** * Invoke the GetUserMediaDevices success callback. Wrapped in a runnable * so that it may be called on the main thread. The error callback is also * passed so it can be released correctly. */ class DeviceSuccessCallbackRunnable: public nsRunnable { public: DeviceSuccessCallbackRunnable( uint64_t aWindowID, - nsCOMPtr<nsIGetUserMediaDevicesSuccessCallback>& aSuccess, - nsCOMPtr<nsIDOMGetUserMediaErrorCallback>& aError, + nsCOMPtr<nsIGetUserMediaDevicesSuccessCallback>& aOnSuccess, + nsCOMPtr<nsIDOMGetUserMediaErrorCallback>& aOnFailure, nsTArray<nsRefPtr<MediaDevice>>* aDevices) : mDevices(aDevices) , mWindowID(aWindowID) , mManager(MediaManager::GetInstance()) { - mSuccess.swap(aSuccess); - mError.swap(aError); + mOnSuccess.swap(aOnSuccess); + mOnFailure.swap(aOnFailure); } NS_IMETHOD Run() { NS_ASSERTION(NS_IsMainThread(), "Only call on main thread"); // Only run if window is still on our active list. @@ -310,39 +316,44 @@ public: do_CreateInstance("@mozilla.org/variant;1"); int32_t len = mDevices->Length(); if (len == 0) { // XXX // We should in the future return an empty array, and dynamically add // devices to the dropdowns if things are hotplugged while the // requester is up. - mError->OnError(NS_LITERAL_STRING("NO_DEVICES_FOUND")); + nsGlobalWindow* window = nsGlobalWindow::GetInnerWindowWithId(mWindowID); + if (window) { + nsRefPtr<MediaStreamError> error = new MediaStreamError(window, + NS_LITERAL_STRING("NotFoundError")); + mOnFailure->OnError(error); + } return NS_OK; } nsTArray<nsIMediaDevice*> tmp(len); for (int32_t i = 0; i < len; i++) { tmp.AppendElement(mDevices->ElementAt(i)); } devices->SetAsArray(nsIDataType::VTYPE_INTERFACE, &NS_GET_IID(nsIMediaDevice), mDevices->Length(), const_cast<void*>( static_cast<const void*>(tmp.Elements()) )); - mSuccess->OnSuccess(devices); + mOnSuccess->OnSuccess(devices); return NS_OK; } private: - nsCOMPtr<nsIGetUserMediaDevicesSuccessCallback> mSuccess; - nsCOMPtr<nsIDOMGetUserMediaErrorCallback> mError; + nsCOMPtr<nsIGetUserMediaDevicesSuccessCallback> mOnSuccess; + nsCOMPtr<nsIDOMGetUserMediaErrorCallback> mOnFailure; nsAutoPtr<nsTArray<nsRefPtr<MediaDevice>>> mDevices; uint64_t mWindowID; nsRefPtr<MediaManager> mManager; }; // Handle removing GetUserMediaCallbackMediaStreamListener from main thread class GetUserMediaListenerRemove: public nsRunnable { @@ -718,63 +729,63 @@ public: * though that would complicate the constructors some. Currently the * GetUserMedia spec does not allow for more than 2 streams to be obtained in * one call, to simplify handling of constraints. */ class GetUserMediaStreamRunnable : public nsRunnable { public: GetUserMediaStreamRunnable( - nsCOMPtr<nsIDOMGetUserMediaSuccessCallback>& aSuccess, - nsCOMPtr<nsIDOMGetUserMediaErrorCallback>& aError, + nsCOMPtr<nsIDOMGetUserMediaSuccessCallback>& aOnSuccess, + nsCOMPtr<nsIDOMGetUserMediaErrorCallback>& aOnFailure, uint64_t aWindowID, GetUserMediaCallbackMediaStreamListener* aListener, MediaEngineSource* aAudioSource, MediaEngineSource* aVideoSource, PeerIdentity* aPeerIdentity) : mAudioSource(aAudioSource) , mVideoSource(aVideoSource) , mWindowID(aWindowID) , mListener(aListener) , mPeerIdentity(aPeerIdentity) , mManager(MediaManager::GetInstance()) { - mSuccess.swap(aSuccess); - mError.swap(aError); + mOnSuccess.swap(aOnSuccess); + mOnFailure.swap(aOnFailure); } ~GetUserMediaStreamRunnable() {} class TracksAvailableCallback : public DOMMediaStream::OnTracksAvailableCallback { public: TracksAvailableCallback(MediaManager* aManager, nsIDOMGetUserMediaSuccessCallback* aSuccess, uint64_t aWindowID, DOMMediaStream* aStream) - : mWindowID(aWindowID), mSuccess(aSuccess), mManager(aManager), + : mWindowID(aWindowID), mOnSuccess(aSuccess), mManager(aManager), mStream(aStream) {} virtual void NotifyTracksAvailable(DOMMediaStream* aStream) MOZ_OVERRIDE { // We're in the main thread, so no worries here. if (!(mManager->IsWindowStillActive(mWindowID))) { return; } // Start currentTime from the point where this stream was successfully // returned. aStream->SetLogicalStreamStartTime(aStream->GetStream()->GetCurrentTime()); // This is safe since we're on main-thread, and the windowlist can only // be invalidated from the main-thread (see OnNavigation) LOG(("Returning success for getUserMedia()")); - mSuccess->OnSuccess(aStream); + mOnSuccess->OnSuccess(aStream); } uint64_t mWindowID; - nsCOMPtr<nsIDOMGetUserMediaSuccessCallback> mSuccess; + nsCOMPtr<nsIDOMGetUserMediaSuccessCallback> mOnSuccess; nsRefPtr<MediaManager> mManager; // Keep the DOMMediaStream alive until the NotifyTracksAvailable callback // has fired, otherwise we might immediately destroy the DOMMediaStream and // shut down the underlying MediaStream prematurely. // This creates a cycle which is broken when NotifyTracksAvailable // is fired (which will happen unless the browser shuts down, // since we only add this callback when we've successfully appended // the desired tracks in the MediaStreamGraph) or when @@ -825,19 +836,26 @@ public: } } #endif // Create a media stream. nsRefPtr<nsDOMUserMediaStream> trackunion = nsDOMUserMediaStream::CreateTrackUnionStream(window, mListener, mAudioSource, mVideoSource); if (!trackunion) { - nsCOMPtr<nsIDOMGetUserMediaErrorCallback> error = mError.forget(); + nsCOMPtr<nsIDOMGetUserMediaErrorCallback> onFailure = mOnFailure.forget(); LOG(("Returning error for getUserMedia() - no stream")); - error->OnError(NS_LITERAL_STRING("NO_STREAM")); + + nsGlobalWindow* window = nsGlobalWindow::GetInnerWindowWithId(mWindowID); + if (window) { + nsRefPtr<MediaStreamError> error = new MediaStreamError(window, + NS_LITERAL_STRING("InternalError"), + NS_LITERAL_STRING("No stream.")); + onFailure->OnError(error); + } return NS_OK; } trackunion->AudioConfig(aec_on, (uint32_t) aec, agc_on, (uint32_t) agc, noise_on, (uint32_t) noise, playout_delay); @@ -869,41 +887,41 @@ public: // The listener was added at the beginning in an inactive state. // Activate our listener. We'll call Start() on the source when get a callback // that the MediaStream has started consuming. The listener is freed // when the page is invalidated (on navigation or close). mListener->Activate(stream.forget(), mAudioSource, mVideoSource); // Note: includes JS callbacks; must be released on MainThread TracksAvailableCallback* tracksAvailableCallback = - new TracksAvailableCallback(mManager, mSuccess, mWindowID, trackunion); + new TracksAvailableCallback(mManager, mOnSuccess, mWindowID, trackunion); mListener->AudioConfig(aec_on, (uint32_t) aec, agc_on, (uint32_t) agc, noise_on, (uint32_t) noise, playout_delay); // Dispatch to the media thread to ask it to start the sources, // because that can take a while. // Pass ownership of trackunion to the MediaOperationTask // to ensure it's kept alive until the MediaOperationTask runs (at least). MediaManager::GetMessageLoop()->PostTask(FROM_HERE, new MediaOperationTask(MEDIA_START, mListener, trackunion, tracksAvailableCallback, mAudioSource, mVideoSource, false, mWindowID, - mError.forget())); + mOnFailure.forget())); - // We won't need mError now. - mError = nullptr; + // We won't need mOnFailure now. + mOnFailure = nullptr; return NS_OK; } private: - nsCOMPtr<nsIDOMGetUserMediaSuccessCallback> mSuccess; - nsCOMPtr<nsIDOMGetUserMediaErrorCallback> mError; + nsCOMPtr<nsIDOMGetUserMediaSuccessCallback> mOnSuccess; + nsCOMPtr<nsIDOMGetUserMediaErrorCallback> mOnFailure; nsRefPtr<MediaEngineSource> mAudioSource; nsRefPtr<MediaEngineSource> mVideoSource; uint64_t mWindowID; nsRefPtr<GetUserMediaCallbackMediaStreamListener> mListener; nsAutoPtr<PeerIdentity> mPeerIdentity; nsRefPtr<MediaManager> mManager; // get ref to this when creating the runnable }; @@ -1051,73 +1069,75 @@ static void * Do not run this on the main thread. The success and error callbacks *MUST* * be dispatched on the main thread! */ class GetUserMediaTask : public Task { public: GetUserMediaTask( const MediaStreamConstraints& aConstraints, - already_AddRefed<nsIDOMGetUserMediaSuccessCallback> aSuccess, - already_AddRefed<nsIDOMGetUserMediaErrorCallback> aError, + already_AddRefed<nsIDOMGetUserMediaSuccessCallback> aOnSuccess, + already_AddRefed<nsIDOMGetUserMediaErrorCallback> aOnFailure, uint64_t aWindowID, GetUserMediaCallbackMediaStreamListener *aListener, MediaEnginePrefs &aPrefs) : mConstraints(aConstraints) - , mSuccess(aSuccess) - , mError(aError) + , mOnSuccess(aOnSuccess) + , mOnFailure(aOnFailure) , mWindowID(aWindowID) , mListener(aListener) , mPrefs(aPrefs) , mDeviceChosen(false) , mBackend(nullptr) , mManager(MediaManager::GetInstance()) {} /** * The caller can also choose to provide their own backend instead of * using the one provided by MediaManager::GetBackend. */ GetUserMediaTask( const MediaStreamConstraints& aConstraints, - already_AddRefed<nsIDOMGetUserMediaSuccessCallback> aSuccess, - already_AddRefed<nsIDOMGetUserMediaErrorCallback> aError, + already_AddRefed<nsIDOMGetUserMediaSuccessCallback> aOnSuccess, + already_AddRefed<nsIDOMGetUserMediaErrorCallback> aOnFailure, uint64_t aWindowID, GetUserMediaCallbackMediaStreamListener *aListener, MediaEnginePrefs &aPrefs, MediaEngine* aBackend) : mConstraints(aConstraints) - , mSuccess(aSuccess) - , mError(aError) + , mOnSuccess(aOnSuccess) + , mOnFailure(aOnFailure) , mWindowID(aWindowID) , mListener(aListener) , mPrefs(aPrefs) , mDeviceChosen(false) , mBackend(aBackend) , mManager(MediaManager::GetInstance()) {} ~GetUserMediaTask() { } void - Fail(const nsAString& aMessage) { + Fail(const nsAString& aName, + const nsAString& aMessage = EmptyString()) { + nsRefPtr<MediaMgrError> error = new MediaMgrError(aName, aMessage); nsRefPtr<ErrorCallbackRunnable> runnable = - new ErrorCallbackRunnable(mSuccess, mError, aMessage, mWindowID); + new ErrorCallbackRunnable(mOnSuccess, mOnFailure, *error, mWindowID); // These should be empty now - MOZ_ASSERT(!mSuccess); - MOZ_ASSERT(!mError); + MOZ_ASSERT(!mOnSuccess); + MOZ_ASSERT(!mOnFailure); NS_DispatchToMainThread(runnable); } void Run() { NS_ASSERTION(!NS_IsMainThread(), "Don't call on main thread"); - MOZ_ASSERT(mSuccess); - MOZ_ASSERT(mError); + MOZ_ASSERT(mOnSuccess); + MOZ_ASSERT(mOnFailure); MediaEngine* backend = mBackend; // Was a backend provided? if (!backend) { backend = mManager->GetBackend(mWindowID); } // Was a device provided? @@ -1131,44 +1151,50 @@ public: // There's a bug in the permission code that can leave us with mAudio but no audio device ProcessGetUserMedia(((IsOn(mConstraints.mAudio) && mAudioDevice) ? mAudioDevice->GetSource() : nullptr), ((IsOn(mConstraints.mVideo) && mVideoDevice) ? mVideoDevice->GetSource() : nullptr)); } nsresult - Denied(const nsAString& aErrorMsg) + Denied(const nsAString& aName, + const nsAString& aMessage = EmptyString()) { - MOZ_ASSERT(mSuccess); - MOZ_ASSERT(mError); + MOZ_ASSERT(mOnSuccess); + MOZ_ASSERT(mOnFailure); // We add a disabled listener to the StreamListeners array until accepted // If this was the only active MediaStream, remove the window from the list. if (NS_IsMainThread()) { // This is safe since we're on main-thread, and the window can only // be invalidated from the main-thread (see OnNavigation) - nsCOMPtr<nsIDOMGetUserMediaSuccessCallback> success = mSuccess.forget(); - nsCOMPtr<nsIDOMGetUserMediaErrorCallback> error = mError.forget(); - error->OnError(aErrorMsg); + nsCOMPtr<nsIDOMGetUserMediaSuccessCallback> onSuccess = mOnSuccess.forget(); + nsCOMPtr<nsIDOMGetUserMediaErrorCallback> onFailure = mOnFailure.forget(); + nsGlobalWindow* window = nsGlobalWindow::GetInnerWindowWithId(mWindowID); + if (window) { + nsRefPtr<MediaStreamError> error = new MediaStreamError(window, + aName, aMessage); + onFailure->OnError(error); + } // Should happen *after* error runs for consistency, but may not matter nsRefPtr<MediaManager> manager(MediaManager::GetInstance()); manager->RemoveFromWindowList(mWindowID, mListener); } else { // This will re-check the window being alive on main-thread // Note: we must remove the listener on MainThread as well - Fail(aErrorMsg); + Fail(aName, aMessage); // MUST happen after ErrorCallbackRunnable Run()s, as it checks the active window list NS_DispatchToMainThread(new GetUserMediaListenerRemove(mWindowID, mListener)); } - MOZ_ASSERT(!mSuccess); - MOZ_ASSERT(!mError); + MOZ_ASSERT(!mOnSuccess); + MOZ_ASSERT(!mOnFailure); return NS_OK; } nsresult SetContraints(const MediaStreamConstraints& aConstraints) { mConstraints = aConstraints; @@ -1189,38 +1215,38 @@ public: mVideoDevice = aVideoDevice; mDeviceChosen = true; return NS_OK; } nsresult SelectDevice(MediaEngine* backend) { - MOZ_ASSERT(mSuccess); - MOZ_ASSERT(mError); + MOZ_ASSERT(mOnSuccess); + MOZ_ASSERT(mOnFailure); if (IsOn(mConstraints.mVideo)) { VideoTrackConstraintsN constraints(GetInvariant(mConstraints.mVideo)); nsTArray<nsRefPtr<VideoDevice>> sources; GetSources(backend, constraints, &MediaEngine::EnumerateVideoDevices, sources); if (!sources.Length()) { - Fail(NS_LITERAL_STRING("NO_DEVICES_FOUND")); + Fail(NS_LITERAL_STRING("NotFoundError")); return NS_ERROR_FAILURE; } // Pick the first available device. mVideoDevice = sources[0]; LOG(("Selected video device")); } if (IsOn(mConstraints.mAudio)) { AudioTrackConstraintsN constraints(GetInvariant(mConstraints.mAudio)); nsTArray<nsRefPtr<AudioDevice>> sources; GetSources(backend, constraints, &MediaEngine::EnumerateAudioDevices, sources); if (!sources.Length()) { - Fail(NS_LITERAL_STRING("NO_DEVICES_FOUND")); + Fail(NS_LITERAL_STRING("NotFoundError")); return NS_ERROR_FAILURE; } // Pick the first available device. mAudioDevice = sources[0]; LOG(("Selected audio device")); } return NS_OK; @@ -1229,59 +1255,61 @@ public: /** * Allocates a video or audio device and returns a MediaStream via * a GetUserMediaStreamRunnable. Runs off the main thread. */ void ProcessGetUserMedia(MediaEngineAudioSource* aAudioSource, MediaEngineVideoSource* aVideoSource) { - MOZ_ASSERT(mSuccess); - MOZ_ASSERT(mError); + MOZ_ASSERT(mOnSuccess); + MOZ_ASSERT(mOnFailure); nsresult rv; if (aAudioSource) { rv = aAudioSource->Allocate(GetInvariant(mConstraints.mAudio), mPrefs); if (NS_FAILED(rv)) { LOG(("Failed to allocate audiosource %d",rv)); - Fail(NS_LITERAL_STRING("HARDWARE_UNAVAILABLE")); + Fail(NS_LITERAL_STRING("SourceUnavailableError"), + NS_LITERAL_STRING("Failed to allocate audiosource")); return; } } if (aVideoSource) { rv = aVideoSource->Allocate(GetInvariant(mConstraints.mVideo), mPrefs); if (NS_FAILED(rv)) { LOG(("Failed to allocate videosource %d\n",rv)); if (aAudioSource) { aAudioSource->Deallocate(); } - Fail(NS_LITERAL_STRING("HARDWARE_UNAVAILABLE")); + Fail(NS_LITERAL_STRING("SourceUnavailableError"), + NS_LITERAL_STRING("Failed to allocate videosource")); return; } } PeerIdentity* peerIdentity = nullptr; if (!mConstraints.mPeerIdentity.IsEmpty()) { peerIdentity = new PeerIdentity(mConstraints.mPeerIdentity); } NS_DispatchToMainThread(new GetUserMediaStreamRunnable( - mSuccess, mError, mWindowID, mListener, aAudioSource, aVideoSource, + mOnSuccess, mOnFailure, mWindowID, mListener, aAudioSource, aVideoSource, peerIdentity )); - MOZ_ASSERT(!mSuccess); - MOZ_ASSERT(!mError); + MOZ_ASSERT(!mOnSuccess); + MOZ_ASSERT(!mOnFailure); return; } private: MediaStreamConstraints mConstraints; - nsCOMPtr<nsIDOMGetUserMediaSuccessCallback> mSuccess; - nsCOMPtr<nsIDOMGetUserMediaErrorCallback> mError; + nsCOMPtr<nsIDOMGetUserMediaSuccessCallback> mOnSuccess; + nsCOMPtr<nsIDOMGetUserMediaErrorCallback> mOnFailure; uint64_t mWindowID; nsRefPtr<GetUserMediaCallbackMediaStreamListener> mListener; nsRefPtr<AudioDevice> mAudioDevice; nsRefPtr<VideoDevice> mVideoDevice; MediaEnginePrefs mPrefs; bool mDeviceChosen; @@ -1317,23 +1345,23 @@ private: * wraps them up in nsIMediaDevice objects and returns it to the success * callback. */ class GetUserMediaDevicesTask : public Task { public: GetUserMediaDevicesTask( const MediaStreamConstraints& aConstraints, - already_AddRefed<nsIGetUserMediaDevicesSuccessCallback> aSuccess, - already_AddRefed<nsIDOMGetUserMediaErrorCallback> aError, + already_AddRefed<nsIGetUserMediaDevicesSuccessCallback> aOnSuccess, + already_AddRefed<nsIDOMGetUserMediaErrorCallback> aOnFailure, uint64_t aWindowId, nsACString& aAudioLoopbackDev, nsACString& aVideoLoopbackDev) : mConstraints(aConstraints) - , mSuccess(aSuccess) - , mError(aError) + , mOnSuccess(aOnSuccess) + , mOnFailure(aOnFailure) , mManager(MediaManager::GetInstance()) , mWindowId(aWindowId) , mLoopbackAudioDevice(aAudioLoopbackDev) , mLoopbackVideoDevice(aVideoLoopbackDev) {} void // NS_IMETHOD Run() { @@ -1363,26 +1391,26 @@ public: GetSources(backend, constraints, &MediaEngine::EnumerateAudioDevices, s, mLoopbackAudioDevice.get()); for (uint32_t i = 0; i < s.Length(); i++) { final->AppendElement(s[i]); } } NS_DispatchToMainThread(new DeviceSuccessCallbackRunnable(mWindowId, - mSuccess, mError, + mOnSuccess, mOnFailure, final.forget())); // DeviceSuccessCallbackRunnable should have taken these. - MOZ_ASSERT(!mSuccess && !mError); + MOZ_ASSERT(!mOnSuccess && !mOnFailure); } private: MediaStreamConstraints mConstraints; - nsCOMPtr<nsIGetUserMediaDevicesSuccessCallback> mSuccess; - nsCOMPtr<nsIDOMGetUserMediaErrorCallback> mError; + nsCOMPtr<nsIGetUserMediaDevicesSuccessCallback> mOnSuccess; + nsCOMPtr<nsIDOMGetUserMediaErrorCallback> mOnFailure; nsRefPtr<MediaManager> mManager; uint64_t mWindowId; const nsString mCallId; // Audio & Video loopback devices to be used based on // the preference settings. This is currently used for // automated media tests only. nsCString mLoopbackAudioDevice; nsCString mLoopbackVideoDevice; @@ -1539,28 +1567,28 @@ MediaManager::NotifyRecordingStatusChang * The entry point for this file. A call from Navigator::mozGetUserMedia * will end up here. MediaManager is a singleton that is responsible * for handling all incoming getUserMedia calls from every window. */ nsresult MediaManager::GetUserMedia( nsPIDOMWindow* aWindow, const MediaStreamConstraints& aConstraints, nsIDOMGetUserMediaSuccessCallback* aOnSuccess, - nsIDOMGetUserMediaErrorCallback* aOnError) + nsIDOMGetUserMediaErrorCallback* aOnFailure) { NS_ASSERTION(NS_IsMainThread(), "Only call on main thread"); NS_ENSURE_TRUE(aWindow, NS_ERROR_NULL_POINTER); - NS_ENSURE_TRUE(aOnError, NS_ERROR_NULL_POINTER); + NS_ENSURE_TRUE(aOnFailure, NS_ERROR_NULL_POINTER); NS_ENSURE_TRUE(aOnSuccess, NS_ERROR_NULL_POINTER); bool privileged = nsContentUtils::IsChromeDoc(aWindow->GetExtantDoc()); nsCOMPtr<nsIDOMGetUserMediaSuccessCallback> onSuccess(aOnSuccess); - nsCOMPtr<nsIDOMGetUserMediaErrorCallback> onError(aOnError); + nsCOMPtr<nsIDOMGetUserMediaErrorCallback> onFailure(aOnFailure); MediaStreamConstraints c(aConstraints); // copy static bool created = false; if (!created) { // Force MediaManager to startup before we try to access it from other threads // Hack: should init singleton earlier unless it's expensive (mem or CPU) (void) MediaManager::Get(); @@ -1635,35 +1663,35 @@ MediaManager::GetUserMedia( } } // Pass callbacks and MediaStreamListener along to GetUserMediaTask. nsAutoPtr<GetUserMediaTask> task; if (c.mFake) { // Fake stream from default backend. task = new GetUserMediaTask(c, onSuccess.forget(), - onError.forget(), windowID, listener, mPrefs, new MediaEngineDefault()); + onFailure.forget(), windowID, listener, mPrefs, new MediaEngineDefault()); } else { // Stream from default device from WebRTC backend. task = new GetUserMediaTask(c, onSuccess.forget(), - onError.forget(), windowID, listener, mPrefs); + onFailure.forget(), windowID, listener, mPrefs); } nsIURI* docURI = aWindow->GetDocumentURI(); if (c.mVideo.IsMediaTrackConstraints()) { auto& tc = c.mVideo.GetAsMediaTrackConstraints(); // deny screensharing request if support is disabled if (tc.mMediaSource != dom::MediaSourceEnum::Camera) { if (tc.mMediaSource == dom::MediaSourceEnum::Browser) { if (!Preferences::GetBool("media.getusermedia.browser.enabled", false)) { - return task->Denied(NS_LITERAL_STRING("PERMISSION_DENIED")); + return task->Denied(NS_LITERAL_STRING("PermissionDeniedError")); } } else if (!Preferences::GetBool("media.getusermedia.screensharing.enabled", false)) { - return task->Denied(NS_LITERAL_STRING("PERMISSION_DENIED")); + return task->Denied(NS_LITERAL_STRING("PermissionDeniedError")); } /* Deny screensharing if the requesting document is not from a host on the whitelist. */ // Block screen/window sharing on Mac OSX 10.6 and WinXP until proved that they work if ( #if defined(XP_MACOSX) || defined(XP_WIN) ( !Preferences::GetBool("media.getusermedia.screensharing.allow_on_old_platforms", false) && @@ -1671,17 +1699,17 @@ MediaManager::GetUserMedia( !nsCocoaFeatures::OnLionOrLater() #endif #if defined (XP_WIN) !IsVistaOrLater() #endif ) || #endif (!privileged && !HostHasPermission(*docURI))) { - return task->Denied(NS_LITERAL_STRING("PERMISSION_DENIED")); + return task->Denied(NS_LITERAL_STRING("PermissionDeniedError")); } } } #ifdef MOZ_B2G_CAMERA if (mCameraManager == nullptr) { mCameraManager = nsDOMCameraManager::CreateInstance(aWindow); } @@ -1725,17 +1753,17 @@ MediaManager::GetUserMedia( if (IsOn(c.mVideo)) { rv = permManager->TestExactPermissionFromPrincipal( aWindow->GetExtantDoc()->NodePrincipal(), "camera", &videoPerm); NS_ENSURE_SUCCESS(rv, rv); } if ((!IsOn(c.mAudio) || audioPerm == nsIPermissionManager::DENY_ACTION) && (!IsOn(c.mVideo) || videoPerm == nsIPermissionManager::DENY_ACTION)) { - return task->Denied(NS_LITERAL_STRING("PERMISSION_DENIED")); + return task->Denied(NS_LITERAL_STRING("PermissionDeniedError")); } // Ask for user permission, and dispatch task (or not) when a response // is received via an observer notification. Each call is paired with its // task by a GUID. nsCOMPtr<nsIUUIDGenerator> uuidgen = do_GetService("@mozilla.org/uuid-generator;1", &rv); NS_ENSURE_SUCCESS(rv, rv); @@ -1773,36 +1801,36 @@ MediaManager::GetUserMedia( return NS_OK; } nsresult MediaManager::GetUserMediaDevices(nsPIDOMWindow* aWindow, const MediaStreamConstraints& aConstraints, nsIGetUserMediaDevicesSuccessCallback* aOnSuccess, - nsIDOMGetUserMediaErrorCallback* aOnError, + nsIDOMGetUserMediaErrorCallback* aOnFailure, uint64_t aInnerWindowID) { NS_ASSERTION(NS_IsMainThread(), "Only call on main thread"); - NS_ENSURE_TRUE(aOnError, NS_ERROR_NULL_POINTER); + NS_ENSURE_TRUE(aOnFailure, NS_ERROR_NULL_POINTER); NS_ENSURE_TRUE(aOnSuccess, NS_ERROR_NULL_POINTER); nsCOMPtr<nsIGetUserMediaDevicesSuccessCallback> onSuccess(aOnSuccess); - nsCOMPtr<nsIDOMGetUserMediaErrorCallback> onError(aOnError); + nsCOMPtr<nsIDOMGetUserMediaErrorCallback> onFailure(aOnFailure); // Check if the preference for using loopback devices is enabled. nsAdoptingCString loopbackAudioDevice = Preferences::GetCString("media.audio_loopback_dev"); nsAdoptingCString loopbackVideoDevice = Preferences::GetCString("media.video_loopback_dev"); MediaManager::GetMessageLoop()->PostTask(FROM_HERE, new GetUserMediaDevicesTask( - aConstraints, onSuccess.forget(), onError.forget(), + aConstraints, onSuccess.forget(), onFailure.forget(), (aInnerWindowID ? aInnerWindowID : aWindow->WindowID()), loopbackAudioDevice, loopbackVideoDevice)); return NS_OK; } MediaEngine* MediaManager::GetBackend(uint64_t aWindowId) @@ -2015,17 +2043,17 @@ MediaManager::Observe(nsISupports* aSubj // NOTE: does not allow setting a device to null; assumes nullptr nsCOMPtr<nsISupportsArray> array(do_QueryInterface(aSubject)); MOZ_ASSERT(array); uint32_t len = 0; array->Count(&len); MOZ_ASSERT(len); if (!len) { // neither audio nor video were selected - task->Denied(NS_LITERAL_STRING("PERMISSION_DENIED")); + task->Denied(NS_LITERAL_STRING("PermissionDeniedError")); return NS_OK; } for (uint32_t i = 0; i < len; i++) { nsCOMPtr<nsISupports> supports; array->GetElementAt(i,getter_AddRefs(supports)); nsCOMPtr<nsIMediaDevice> device(do_QueryInterface(supports)); MOZ_ASSERT(device); // shouldn't be returning anything else... if (device) { @@ -2042,24 +2070,24 @@ MediaManager::Observe(nsISupports* aSubj } } // Reuse the same thread to save memory. MediaManager::GetMessageLoop()->PostTask(FROM_HERE, task.forget()); return NS_OK; } else if (!strcmp(aTopic, "getUserMedia:response:deny")) { - nsString errorMessage(NS_LITERAL_STRING("PERMISSION_DENIED")); + nsString errorMessage(NS_LITERAL_STRING("PermissionDeniedError")); if (aSubject) { nsCOMPtr<nsISupportsString> msg(do_QueryInterface(aSubject)); MOZ_ASSERT(msg); msg->GetData(errorMessage); if (errorMessage.IsEmpty()) - errorMessage.AssignLiteral(MOZ_UTF16("UNKNOWN_ERROR")); + errorMessage.AssignLiteral(MOZ_UTF16("InternalError")); } nsString key(aData); nsAutoPtr<GetUserMediaTask> task; mActiveCallbacks.RemoveAndForget(key, task); if (task) { task->Denied(errorMessage); }
--- a/dom/media/MediaManager.h +++ b/dom/media/MediaManager.h @@ -21,16 +21,17 @@ #include "nsPIDOMWindow.h" #include "nsIDOMNavigatorUserMedia.h" #include "nsXULAppAPI.h" #include "mozilla/Attributes.h" #include "mozilla/Preferences.h" #include "mozilla/StaticPtr.h" #include "mozilla/dom/MediaStreamBinding.h" #include "mozilla/dom/MediaStreamTrackBinding.h" +#include "mozilla/dom/MediaStreamError.h" #include "prlog.h" #include "DOMMediaStream.h" #ifdef MOZ_WEBRTC #include "mtransport/runnable_utils.h" #endif // Note, these suck in Windows headers, unfortunately. @@ -263,64 +264,64 @@ class GetUserMediaNotificationEvent: pub GetUserMediaNotificationEvent(GetUserMediaStatus aStatus, already_AddRefed<DOMMediaStream> aStream, DOMMediaStream::OnTracksAvailableCallback* aOnTracksAvailableCallback, bool aIsAudio, bool aIsVideo, uint64_t aWindowID, already_AddRefed<nsIDOMGetUserMediaErrorCallback> aError) : mStream(aStream), mOnTracksAvailableCallback(aOnTracksAvailableCallback), mStatus(aStatus), mIsAudio(aIsAudio), mIsVideo(aIsVideo), mWindowID(aWindowID), - mError(aError) {} + mOnFailure(aError) {} virtual ~GetUserMediaNotificationEvent() { } NS_IMETHOD Run() MOZ_OVERRIDE; protected: nsRefPtr<GetUserMediaCallbackMediaStreamListener> mListener; // threadsafe nsRefPtr<DOMMediaStream> mStream; nsAutoPtr<DOMMediaStream::OnTracksAvailableCallback> mOnTracksAvailableCallback; GetUserMediaStatus mStatus; bool mIsAudio; bool mIsVideo; uint64_t mWindowID; - nsRefPtr<nsIDOMGetUserMediaErrorCallback> mError; + nsRefPtr<nsIDOMGetUserMediaErrorCallback> mOnFailure; }; typedef enum { MEDIA_START, MEDIA_STOP, MEDIA_STOP_TRACK, MEDIA_DIRECT_LISTENERS } MediaOperation; class MediaManager; class GetUserMediaTask; /** - * Send an error back to content. The error is the form a string. - * Do this only on the main thread. The success callback is also passed here + * Send an error back to content. + * Do this only on the main thread. The onSuccess callback is also passed here * so it can be released correctly. */ class ErrorCallbackRunnable : public nsRunnable { public: ErrorCallbackRunnable( - nsCOMPtr<nsIDOMGetUserMediaSuccessCallback>& aSuccess, - nsCOMPtr<nsIDOMGetUserMediaErrorCallback>& aError, - const nsAString& aErrorMsg, uint64_t aWindowID); + nsCOMPtr<nsIDOMGetUserMediaSuccessCallback>& aOnSuccess, + nsCOMPtr<nsIDOMGetUserMediaErrorCallback>& aOnFailure, + MediaMgrError& aError, uint64_t aWindowID); NS_IMETHOD Run(); private: ~ErrorCallbackRunnable(); - nsCOMPtr<nsIDOMGetUserMediaSuccessCallback> mSuccess; - nsCOMPtr<nsIDOMGetUserMediaErrorCallback> mError; - const nsString mErrorMsg; + nsCOMPtr<nsIDOMGetUserMediaSuccessCallback> mOnSuccess; + nsCOMPtr<nsIDOMGetUserMediaErrorCallback> mOnFailure; + nsRefPtr<MediaMgrError> mError; uint64_t mWindowID; nsRefPtr<MediaManager> mManager; // get ref to this when creating the runnable }; class ReleaseMediaOperationResource : public nsRunnable { public: ReleaseMediaOperationResource(already_AddRefed<DOMMediaStream> aStream, @@ -352,36 +353,38 @@ public: : mType(aType) , mStream(aStream) , mOnTracksAvailableCallback(aOnTracksAvailableCallback) , mAudioSource(aAudioSource) , mVideoSource(aVideoSource) , mListener(aListener) , mBool(aBool) , mWindowID(aWindowID) - , mError(aError) + , mOnFailure(aError) {} ~MediaOperationTask() { // MediaStreams can be released on any thread. } void ReturnCallbackError(nsresult rv, const char* errorLog) { MM_LOG(("%s , rv=%d", errorLog, rv)); NS_DispatchToMainThread(new ReleaseMediaOperationResource(mStream.forget(), mOnTracksAvailableCallback.forget())); nsString log; - log.AssignASCII(errorLog, strlen(errorLog)); - nsCOMPtr<nsIDOMGetUserMediaSuccessCallback> success; - NS_DispatchToMainThread(new ErrorCallbackRunnable(success, mError, - log, mWindowID)); + log.AssignASCII(errorLog); + nsCOMPtr<nsIDOMGetUserMediaSuccessCallback> onSuccess; + nsRefPtr<MediaMgrError> error = new MediaMgrError( + NS_LITERAL_STRING("InternalError"), log); + NS_DispatchToMainThread(new ErrorCallbackRunnable(onSuccess, mOnFailure, + *error, mWindowID)); } void Run() { SourceMediaStream *source = mListener->GetSourceStream(); // No locking between these is required as all the callbacks for the // same MediaStream will occur on the same thread. @@ -423,17 +426,17 @@ public: // because mOnTracksAvailableCallback needs to be added to mStream // on the main thread. nsIRunnable *event = new GetUserMediaNotificationEvent(GetUserMediaNotificationEvent::STARTING, mStream.forget(), mOnTracksAvailableCallback.forget(), mAudioSource != nullptr, mVideoSource != nullptr, - mWindowID, mError.forget()); + mWindowID, mOnFailure.forget()); // event must always be released on mainthread due to the JS callbacks // in the TracksAvailableCallback NS_DispatchToMainThread(event); } break; case MEDIA_STOP: case MEDIA_STOP_TRACK: @@ -485,17 +488,17 @@ private: MediaOperation mType; nsRefPtr<DOMMediaStream> mStream; nsAutoPtr<DOMMediaStream::OnTracksAvailableCallback> mOnTracksAvailableCallback; nsRefPtr<MediaEngineSource> mAudioSource; // threadsafe nsRefPtr<MediaEngineSource> mVideoSource; // threadsafe nsRefPtr<GetUserMediaCallbackMediaStreamListener> mListener; // threadsafe bool mBool; uint64_t mWindowID; - nsCOMPtr<nsIDOMGetUserMediaErrorCallback> mError; + nsCOMPtr<nsIDOMGetUserMediaErrorCallback> mOnFailure; }; typedef nsTArray<nsRefPtr<GetUserMediaCallbackMediaStreamListener> > StreamListeners; typedef nsClassHashtable<nsUint64HashKey, StreamListeners> WindowTable; class MediaDevice : public nsIMediaDevice { public:
--- a/dom/media/MediaPermissionGonk.cpp +++ b/dom/media/MediaPermissionGonk.cpp @@ -12,16 +12,17 @@ #include "nsIStringEnumerator.h" #include "nsISupportsArray.h" #include "nsJSUtils.h" #include "nsPIDOMWindow.h" #include "nsTArray.h" #include "GetUserMediaRequest.h" #include "mozilla/dom/PBrowserChild.h" #include "mozilla/dom/MediaStreamTrackBinding.h" +#include "mozilla/dom/MediaStreamError.h" #include "nsISupportsPrimitives.h" #include "nsServiceManagerUtils.h" #include "nsArrayUtils.h" #include "nsContentPermissionHelper.h" #include "mozilla/dom/PermissionMessageUtils.h" #define AUDIO_PERMISSION_NAME "audio-capture" #define VIDEO_PERMISSION_NAME "video-capture" @@ -219,17 +220,17 @@ MediaPermissionRequest::GetElement(nsIDO return NS_OK; } NS_IMETHODIMP MediaPermissionRequest::Cancel() { nsString callID; mRequest->GetCallID(callID); - NotifyPermissionDeny(callID, NS_LITERAL_STRING("Permission Denied")); + NotifyPermissionDeny(callID, NS_LITERAL_STRING("PermissionDeniedError")); return NS_OK; } NS_IMETHODIMP MediaPermissionRequest::Allow(JS::HandleValue aChoices) { // check if JS object if (!aChoices.isObject()) { @@ -388,19 +389,27 @@ protected: private: const nsString mCallID; }; NS_IMPL_ISUPPORTS(MediaDeviceErrorCallback, nsIDOMGetUserMediaErrorCallback) // nsIDOMGetUserMediaErrorCallback method NS_IMETHODIMP -MediaDeviceErrorCallback::OnError(const nsAString &aError) +MediaDeviceErrorCallback::OnError(nsISupports* aError) { - return NotifyPermissionDeny(mCallID, aError); + MediaStreamError *error = nullptr; + nsresult rv = CallQueryInterface(aError, &error); + if (NS_FAILED(rv)) { + return rv; + } + + nsString name; + error->GetName(name); + return NotifyPermissionDeny(mCallID, name); } } // namespace anonymous // MediaPermissionManager NS_IMPL_ISUPPORTS(MediaPermissionManager, nsIObserver) MediaPermissionManager*
new file mode 100644 --- /dev/null +++ b/dom/media/MediaStreamError.cpp @@ -0,0 +1,81 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "MediaStreamError.h" +#include "mozilla/dom/MediaStreamErrorBinding.h" +#include "nsContentUtils.h" + +namespace mozilla { + +BaseMediaMgrError::BaseMediaMgrError(const nsAString& aName, + const nsAString& aMessage, + const nsAString& aConstraintName) + : mName(aName) + , mMessage(aMessage) + , mConstraintName(aConstraintName) +{ + if (mMessage.IsEmpty()) { + if (mName.EqualsLiteral("NotFoundError")) { + mMessage.AssignLiteral("The object can not be found here."); + } else if (mName.EqualsLiteral("PermissionDeniedError")) { + mMessage.AssignLiteral("The user did not grant permission for the operation."); + } else if (mName.EqualsLiteral("SourceUnavailableError")) { + mMessage.AssignLiteral("The source of the MediaStream could not be " + "accessed due to a hardware error (e.g. lock from another process)."); + } else if (mName.EqualsLiteral("InternalError")) { + mMessage.AssignLiteral("Internal error."); + } + } +} + + +NS_IMPL_ISUPPORTS0(MediaMgrError) + +namespace dom { + +MediaStreamError::MediaStreamError( + nsPIDOMWindow* aParent, + const nsAString& aName, + const nsAString& aMessage, + const nsAString& aConstraintName) + : BaseMediaMgrError(aName, aMessage, aConstraintName) + , mParent(aParent) {} + +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(MediaStreamError, mParent) +NS_IMPL_CYCLE_COLLECTING_ADDREF(MediaStreamError) +NS_IMPL_CYCLE_COLLECTING_RELEASE(MediaStreamError) +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(MediaStreamError) + NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY + NS_INTERFACE_MAP_ENTRY(nsISupports) + NS_INTERFACE_MAP_ENTRY(MediaStreamError) +NS_INTERFACE_MAP_END + +JSObject* +MediaStreamError::WrapObject(JSContext* aCx) +{ + return MediaStreamErrorBinding::Wrap(aCx, this); +} + +void +MediaStreamError::GetName(nsAString& aName) const +{ + aName = mName; +} + +void +MediaStreamError::GetMessage(nsAString& aMessage) const +{ + aMessage = mMessage; +} + +void +MediaStreamError::GetConstraintName(nsAString& aConstraintName) const +{ + aConstraintName = mConstraintName; +} + +} // namespace dom +} // namespace mozilla
new file mode 100644 --- /dev/null +++ b/dom/media/MediaStreamError.h @@ -0,0 +1,99 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_dom_MediaStreamError_h +#define mozilla_dom_MediaStreamError_h + +#include "mozilla/Attributes.h" +#include "mozilla/ErrorResult.h" +#include "nsWrapperCache.h" +#include "js/TypeDecls.h" +#include "nsPIDOMWindow.h" +#include "nsRefPtr.h" + +#if defined(XP_WIN) && defined(GetMessage) +#undef GetMessage +#endif + +namespace mozilla { +namespace dom { + +#define MOZILLA_DOM_MEDIASTREAMERROR_IMPLEMENTATION_IID \ +{ 0x95fa29aa, 0x0cc2, 0x4698, \ + { 0x9d, 0xa9, 0xf2, 0xeb, 0x03, 0x91, 0x0b, 0xd1 } } + +class MediaStreamError; +} + +class BaseMediaMgrError +{ + friend class dom::MediaStreamError; +protected: + BaseMediaMgrError(const nsAString& aName, + const nsAString& aMessage, + const nsAString& aConstraintName); + const nsString mName; + nsString mMessage; + const nsString mConstraintName; +}; + +class MediaMgrError MOZ_FINAL : public nsISupports, + public BaseMediaMgrError +{ +public: + MediaMgrError(const nsAString& aName, + const nsAString& aMessage = EmptyString(), + const nsAString& aConstraintName = EmptyString()) + : BaseMediaMgrError(aName, aMessage, aConstraintName) {} + + NS_DECL_THREADSAFE_ISUPPORTS + +private: + ~MediaMgrError() {} +}; + +namespace dom { +class MediaStreamError MOZ_FINAL : public nsISupports, + public BaseMediaMgrError, + public nsWrapperCache +{ +public: + MediaStreamError(nsPIDOMWindow* aParent, + const nsAString& aName, + const nsAString& aMessage = EmptyString(), + const nsAString& aConstraintName = EmptyString()); + + MediaStreamError(nsPIDOMWindow* aParent, + const BaseMediaMgrError& aOther) + : BaseMediaMgrError(aOther.mName, aOther.mMessage, aOther.mConstraintName) + , mParent(aParent) {} + + NS_DECL_CYCLE_COLLECTING_ISUPPORTS + NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(MediaStreamError) + NS_DECLARE_STATIC_IID_ACCESSOR(MOZILLA_DOM_MEDIASTREAMERROR_IMPLEMENTATION_IID) + + virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE; + + nsPIDOMWindow* GetParentObject() const + { + return mParent; + } + void GetName(nsAString& aName) const; + void GetMessage(nsAString& aMessage) const; + void GetConstraintName(nsAString& aConstraintName) const; + +private: + virtual ~MediaStreamError() {} + + nsRefPtr<nsPIDOMWindow> mParent; +}; + +NS_DEFINE_STATIC_IID_ACCESSOR(MediaStreamError, + MOZILLA_DOM_MEDIASTREAMERROR_IMPLEMENTATION_IID) +} // namespace dom +} // namespace mozilla + +#endif
--- a/dom/media/mediasource/MediaSourceReader.h +++ b/dom/media/mediasource/MediaSourceReader.h @@ -65,16 +65,21 @@ public: return mInfo.HasVideo(); } bool HasAudio() MOZ_OVERRIDE { return mInfo.HasAudio(); } + // We can't compute a proper start time since we won't necessarily + // have the first frame of the resource available. This does the same + // as chrome/blink and assumes that we always start at t=0. + virtual int64_t ComputeStartTime(const VideoData* aVideo, const AudioData* aAudio) MOZ_OVERRIDE { return 0; } + bool IsMediaSeekable() { return true; } nsresult ReadMetadata(MediaInfo* aInfo, MetadataTags** aTags) MOZ_OVERRIDE; nsresult Seek(int64_t aTime, int64_t aStartTime, int64_t aEndTime, int64_t aCurrentTime) MOZ_OVERRIDE; already_AddRefed<SourceBufferDecoder> CreateSubDecoder(const nsACString& aType);
--- a/dom/media/moz.build +++ b/dom/media/moz.build @@ -138,16 +138,18 @@ if CONFIG['MOZ_B2G']: 'MediaPermissionGonk.h', ] EXPORTS.mozilla.dom += [ 'AudioStreamTrack.h', 'AudioTrack.h', 'AudioTrackList.h', 'GetUserMediaRequest.h', + 'MediaDevices.h', + 'MediaStreamError.h', 'MediaStreamTrack.h', 'TextTrack.h', 'TextTrackCue.h', 'TextTrackCueList.h', 'TextTrackList.h', 'TextTrackRegion.h', 'VideoPlaybackQuality.h', 'VideoStreamTrack.h', @@ -172,20 +174,22 @@ UNIFIED_SOURCES += [ 'GraphDriver.cpp', 'Latency.cpp', 'MediaCache.cpp', 'MediaData.cpp', 'MediaDecoder.cpp', 'MediaDecoderReader.cpp', 'MediaDecoderStateMachine.cpp', 'MediaDecoderStateMachineScheduler.cpp', + 'MediaDevices.cpp', 'MediaManager.cpp', 'MediaRecorder.cpp', 'MediaResource.cpp', 'MediaShutdownManager.cpp', + 'MediaStreamError.cpp', 'MediaStreamGraph.cpp', 'MediaStreamTrack.cpp', 'MediaTaskQueue.cpp', 'MediaTrack.cpp', 'MediaTrackList.cpp', 'MP3FrameParser.cpp', 'RtspMediaResource.cpp', 'SharedThreadPool.cpp',
--- a/dom/media/nsIDOMNavigatorUserMedia.idl +++ b/dom/media/nsIDOMNavigatorUserMedia.idl @@ -29,10 +29,10 @@ interface nsIDOMGetUserMediaSuccessCallb * DOMLocalMediaStream if either audio or video are true. */ void onSuccess(in nsISupports value); }; [scriptable, function, uuid(2614bbcf-85cc-43e5-8740-964f52bdc7ca)] interface nsIDOMGetUserMediaErrorCallback : nsISupports { - void onError(in DOMString error); + void onError(in nsISupports error); };
--- a/dom/media/tests/mochitest/constraints.js +++ b/dom/media/tests/mochitest/constraints.js @@ -9,29 +9,29 @@ TODO(jib): Merge desktop and mobile version of these tests again. */ var common_tests = [ // Each test here tests a different constraint or codepath. { message: "unknown required constraint on video fails", constraints: { video: { somethingUnknown:0, require:["somethingUnknown"] }, fake: true }, - error: "NO_DEVICES_FOUND" }, + error: "NotFoundError" }, { message: "unknown required constraint on audio fails", constraints: { audio: { somethingUnknown:0, require:["somethingUnknown"] }, fake: true }, - error: "NO_DEVICES_FOUND" }, + error: "NotFoundError" }, { message: "video overconstrained by facingMode fails", constraints: { video: { facingMode:'left', require:["facingMode"] }, fake: true }, - error: "NO_DEVICES_FOUND" }, + error: "NotFoundError" }, { message: "audio overconstrained by facingMode fails", constraints: { audio: { facingMode:'left', require:["facingMode"] }, fake: true }, - error: "NO_DEVICES_FOUND" }, + error: "NotFoundError" }, { message: "Success-path: optional video facingMode + audio ignoring facingMode", constraints: { fake: true, audio: { facingMode:'left', foo:0, advanced: [{ facingMode:'environment' }, { facingMode:'user' }, { bar:0 }] }, video: { // TODO: Bug 767924 sequences in unions @@ -43,34 +43,32 @@ var common_tests = [ { facingMode:'user' }, { bar:0 }] } }, error: null } ]; /** * Starts the test run by running through each constraint - * test by verifying that the right callback and error message is fired. + * test by verifying that the right resolution and rejection is fired. */ function testConstraints(tests) { - var i = 0; - next(); - - function Success() { - ok(!tests[i].error, tests[i].message); - i++; - next(); + function testgum(p, test) { + return p.then(function() { + return navigator.mediaDevices.getUserMedia(test.constraints); + }) + .then(function() { + is(null, test.error, test.message); + }, function(reason) { + is(reason.name, test.error, test.message + ": " + reason.message); + }); } - function Failure(err) { - ok(tests[i].error? (err === tests[i].error) : false, - tests[i].message + " (err=" + err + ")"); - i++; - next(); - } - function next() { - if (i < tests.length) { - navigator.mozGetUserMedia(tests[i].constraints, Success, Failure); - } else { - SimpleTest.finish(); - } - } -}; + + var p = new Promise(function(resolve) { resolve(); }); + tests.forEach(function(test) { + p = testgum(p, test); + }); + p.catch(function(reason) { + ok(false, "Unexpected failure: " + reason.message); + }) + .then(SimpleTest.finish); +}
--- a/dom/media/tests/mochitest/test_getUserMedia_constraints_mobile.html +++ b/dom/media/tests/mochitest/test_getUserMedia_constraints_mobile.html @@ -21,17 +21,17 @@ https://bugzilla.mozilla.org/show_bug.cg <script type="application/javascript"> /** See constraints.js for testConstraints() and common_tests. TODO(jib): Merge desktop and mobile version of these tests again (Bug 997365) */ var mobile_tests = [ { message: "legacy facingMode overconstrains video (mobile)", constraints: { video: { mandatory: { facingMode:'left' } }, fake: true }, - error: "NO_DEVICES_FOUND" }, + error: "NotFoundError" }, ]; runTest(function () { testConstraints(common_tests.concat(mobile_tests)); }); </script>
--- a/dom/media/tests/mochitest/test_getUserMedia_peerIdentity.html +++ b/dom/media/tests/mochitest/test_getUserMedia_peerIdentity.html @@ -21,29 +21,30 @@ https://bugzilla.mozilla.org/show_bug.cg <script type="application/javascript"> function theTest() { function testPeerIdentityConstraint(withConstraint, done) { var config = { audio: true, video: true, fake: true }; if (withConstraint) { config.peerIdentity = 'user@example.com'; } info('getting media with constraints: ' + JSON.stringify(config)); - navigator.mozGetUserMedia(config, function(stream) { + navigator.mediaDevices.getUserMedia(config).then(function(stream) { var oneDone = false; function checkDone() { if (oneDone) { done(); } oneDone = true; } var cancelAudioCheck = audioIsSilence(withConstraint, stream, checkDone); var cancelVideoCheck = videoIsBlack(withConstraint, stream, checkDone); setTimeout(cancelAudioCheck, 3*60*1000); setTimeout(cancelVideoCheck, 3*60*1000); - }, function(e) { + }) + .catch(function(e) { ok(false, 'gUM error: ' + e); }); }; // without constraint testPeerIdentityConstraint(false, function() { // with the constraint testPeerIdentityConstraint(true, SimpleTest.finish.bind(SimpleTest));
--- a/dom/media/tests/mochitest/test_peerConnection_replaceTrack.html +++ b/dom/media/tests/mochitest/test_peerConnection_replaceTrack.html @@ -32,33 +32,33 @@ var flowtest = test.chain.remove("PC_REMOTE_CHECK_MEDIA_FLOW_PRESENT"); test.chain.append(flowtest); test.chain.append([["PC_LOCAL_REPLACE_VIDEOTRACK", function (test) { var stream = test.pcLocal._pc.getLocalStreams()[0]; var track = stream.getVideoTracks()[0]; var sender = test.pcLocal._pc.getSenders().find(isSenderOfTrack, track); ok(sender, "track has a sender"); - navigator.mozGetUserMedia({video:true, fake: true}, function(newStream) { + navigator.mediaDevices.getUserMedia({video:true, fake: true}) + .then(function(newStream) { var newtrack = newStream.getVideoTracks()[0]; - sender.replaceTrack(newtrack, - function() { - ok(true, "replaceTrack success callback is called"); - is(sender.track, newtrack, "sender.track has been replaced"); - test.next(); - }, - function(err) { - ok(false, "replaceTrack failed with error = " + err); - test.next(); - }); - }, - function(err) { - ok(false, "mozGetUserMedia failed. error = " + err); - test.next(); - }); + return new Promise(function(resolve, reject) { + sender.replaceTrack(newtrack, function() { + resolve(newtrack); + }, reject); + }); + }) + .then(function(newtrack) { + ok(true, "replaceTrack success callback is called"); + is(sender.track, newtrack, "sender.track has been replaced"); + }) + .catch(function(reason) { + ok(false, "unexpected error = " + reason.message); + }) + .then(test.next.bind(test)); } ]]); test.chain.append(flowtest); test.run(); }); </script> </pre>
--- a/dom/media/webspeech/recognition/SpeechRecognition.cpp +++ b/dom/media/webspeech/recognition/SpeechRecognition.cpp @@ -6,28 +6,34 @@ #include "SpeechRecognition.h" #include "nsCOMPtr.h" #include "nsCycleCollectionParticipant.h" #include "mozilla/dom/SpeechRecognitionBinding.h" #include "mozilla/dom/MediaStreamTrackBinding.h" +#include "mozilla/dom/MediaStreamError.h" #include "mozilla/MediaManager.h" #include "mozilla/Services.h" #include "AudioSegment.h" #include "endpointer.h" #include "mozilla/dom/SpeechRecognitionEvent.h" #include "nsIObserverService.h" #include "nsServiceManagerUtils.h" #include <algorithm> +// Undo the windows.h damage +#if defined(XP_WIN) && defined(GetMessage) +#undef GetMessage +#endif + namespace mozilla { namespace dom { #define PREFERENCE_DEFAULT_RECOGNITION_SERVICE "media.webspeech.service.default" #define DEFAULT_RECOGNITION_SERVICE "google" #define PREFERENCE_ENDPOINTER_SILENCE_LENGTH "media.webspeech.silence_length" #define PREFERENCE_ENDPOINTER_LONG_SILENCE_LENGTH "media.webspeech.long_silence_length" @@ -940,26 +946,33 @@ SpeechRecognition::GetUserMediaSuccessCa mRecognition->StartRecording(localStream); } return NS_OK; } NS_IMPL_ISUPPORTS(SpeechRecognition::GetUserMediaErrorCallback, nsIDOMGetUserMediaErrorCallback) NS_IMETHODIMP -SpeechRecognition::GetUserMediaErrorCallback::OnError(const nsAString& aError) +SpeechRecognition::GetUserMediaErrorCallback::OnError(nsISupports* aError) { + nsRefPtr<MediaStreamError> error = do_QueryObject(aError); + if (!error) { + return NS_OK; + } SpeechRecognitionErrorCode errorCode; - if (aError.EqualsLiteral("PERMISSION_DENIED")) { + nsString name; + error->GetName(name); + if (name.EqualsLiteral("PERMISSION_DENIED")) { errorCode = SpeechRecognitionErrorCode::Not_allowed; } else { errorCode = SpeechRecognitionErrorCode::Audio_capture; } + nsString message; + error->GetMessage(message); mRecognition->DispatchError(SpeechRecognition::EVENT_AUDIO_ERROR, errorCode, - aError); - + message); return NS_OK; } } // namespace dom } // namespace mozilla
--- a/dom/promise/Promise.cpp +++ b/dom/promise/Promise.cpp @@ -7,16 +7,17 @@ #include "mozilla/dom/Promise.h" #include "jsfriendapi.h" #include "mozilla/dom/BindingUtils.h" #include "mozilla/dom/DOMError.h" #include "mozilla/dom/OwningNonNull.h" #include "mozilla/dom/PromiseBinding.h" #include "mozilla/dom/ScriptSettings.h" +#include "mozilla/dom/MediaStreamError.h" #include "mozilla/CycleCollectedJSRuntime.h" #include "mozilla/Preferences.h" #include "PromiseCallback.h" #include "PromiseNativeHandler.h" #include "PromiseWorkerProxy.h" #include "nsContentUtils.h" #include "WorkerPrivate.h" #include "WorkerRunnable.h" @@ -350,16 +351,21 @@ Promise::MaybeResolve(JSContext* aCx, void Promise::MaybeReject(JSContext* aCx, JS::Handle<JS::Value> aValue) { MaybeRejectInternal(aCx, aValue); } void +Promise::MaybeReject(const nsRefPtr<MediaStreamError>& aArg) { + MaybeSomething(aArg, &Promise::MaybeReject); +} + +void Promise::PerformMicroTaskCheckpoint() { CycleCollectedJSRuntime* runtime = CycleCollectedJSRuntime::Get(); nsTArray<nsRefPtr<nsIRunnable>>& microtaskQueue = runtime->GetPromiseMicroTaskQueue(); while (!microtaskQueue.IsEmpty()) { nsRefPtr<nsIRunnable> runnable = microtaskQueue.ElementAt(0);
--- a/dom/promise/Promise.h +++ b/dom/promise/Promise.h @@ -24,16 +24,17 @@ class nsIGlobalObject; namespace mozilla { namespace dom { class AnyCallback; class DOMError; +class MediaStreamError; class PromiseCallback; class PromiseInit; class PromiseNativeHandler; class PromiseDebugging; class Promise; class PromiseReportRejectFeature : public workers::WorkerFeature { @@ -94,16 +95,19 @@ public: void MaybeResolve(const T& aArg) { MaybeSomething(aArg, &Promise::MaybeResolve); } inline void MaybeReject(nsresult aArg) { MOZ_ASSERT(NS_FAILED(aArg)); MaybeSomething(aArg, &Promise::MaybeReject); } + + void MaybeReject(const nsRefPtr<MediaStreamError>& aArg); + // DO NOT USE MaybeRejectBrokenly with in new code. Promises should be // rejected with Error instances. // Note: MaybeRejectBrokenly is a template so we can use it with DOMError // without instantiating the DOMError specialization of MaybeSomething in // every translation unit that includes this header, because that would // require use to include DOMError.h either here or in all those translation // units. template<typename T>
--- a/dom/quota/QuotaManager.cpp +++ b/dom/quota/QuotaManager.cpp @@ -1096,17 +1096,17 @@ QuotaManager::InitQuotaForOrigin(Persist } void QuotaManager::DecreaseUsageForOrigin(PersistenceType aPersistenceType, const nsACString& aGroup, const nsACString& aOrigin, int64_t aSize) { - AssertIsOnIOThread(); + MOZ_ASSERT(!NS_IsMainThread()); MutexAutoLock lock(mQuotaMutex); GroupInfoPair* pair; if (!mGroupInfoPairs.Get(aGroup, &pair)) { return; }
--- a/dom/svg/SVGCircleElement.cpp +++ b/dom/svg/SVGCircleElement.cpp @@ -76,16 +76,44 @@ SVGCircleElement::GetLengthInfo() { return LengthAttributesInfo(mLengthAttributes, sLengthInfo, ArrayLength(sLengthInfo)); } //---------------------------------------------------------------------- // nsSVGPathGeometryElement methods +bool +SVGCircleElement::GetGeometryBounds(Rect* aBounds, Float aStrokeWidth, + const Matrix& aTransform) +{ + float x, y, r; + GetAnimatedLengthValues(&x, &y, &r, nullptr); + + if (r <= 0.f) { + // Rendering of the element is disabled + aBounds->MoveTo(x, y); + aBounds->SetEmpty(); + return true; + } + + if (aTransform.IsRectilinear()) { + // Optimize the case where we can treat the circle as a rectangle and + // still get tight bounds. + if (aStrokeWidth > 0.f) { + r += aStrokeWidth / 2.f; + } + Rect rect(x - r, y - r, 2 * r, 2 * r); + *aBounds = aTransform.TransformBounds(rect); + return true; + } + + return false; +} + TemporaryRef<Path> SVGCircleElement::BuildPath(PathBuilder* aBuilder) { float x, y, r; GetAnimatedLengthValues(&x, &y, &r, nullptr); if (r <= 0.0f) { return nullptr;
--- a/dom/svg/SVGCircleElement.h +++ b/dom/svg/SVGCircleElement.h @@ -25,16 +25,18 @@ protected: friend nsresult (::NS_NewSVGCircleElement(nsIContent **aResult, already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo)); public: // nsSVGSVGElement methods: virtual bool HasValidDimensions() const MOZ_OVERRIDE; // nsSVGPathGeometryElement methods: + virtual bool GetGeometryBounds(Rect* aBounds, Float aStrokeWidth, + const Matrix& aTransform) MOZ_OVERRIDE; virtual TemporaryRef<Path> BuildPath(PathBuilder* aBuilder) MOZ_OVERRIDE; virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const MOZ_OVERRIDE; // WebIDL already_AddRefed<SVGAnimatedLength> Cx(); already_AddRefed<SVGAnimatedLength> Cy(); already_AddRefed<SVGAnimatedLength> R();
--- a/dom/svg/SVGEllipseElement.cpp +++ b/dom/svg/SVGEllipseElement.cpp @@ -87,16 +87,45 @@ SVGEllipseElement::GetLengthInfo() { return LengthAttributesInfo(mLengthAttributes, sLengthInfo, ArrayLength(sLengthInfo)); } //---------------------------------------------------------------------- // nsSVGPathGeometryElement methods +bool +SVGEllipseElement::GetGeometryBounds(Rect* aBounds, Float aStrokeWidth, + const Matrix& aTransform) +{ + float x, y, rx, ry; + GetAnimatedLengthValues(&x, &y, &rx, &ry, nullptr); + + if (rx <= 0.f || ry <= 0.f) { + // Rendering of the element is disabled + aBounds->MoveTo(x, y); + aBounds->SetEmpty(); + return true; + } + + if (aTransform.IsRectilinear()) { + // Optimize the case where we can treat the ellipse as a rectangle and + // still get tight bounds. + if (aStrokeWidth > 0.f) { + rx += aStrokeWidth / 2.f; + ry += aStrokeWidth / 2.f; + } + Rect rect(x - rx, y - ry, 2 * rx, 2 * ry); + *aBounds = aTransform.TransformBounds(rect); + return true; + } + + return false; +} + TemporaryRef<Path> SVGEllipseElement::BuildPath(PathBuilder* aBuilder) { float x, y, rx, ry; GetAnimatedLengthValues(&x, &y, &rx, &ry, nullptr); if (rx <= 0.0f || ry <= 0.0f) { return nullptr;
--- a/dom/svg/SVGEllipseElement.h +++ b/dom/svg/SVGEllipseElement.h @@ -25,16 +25,18 @@ protected: friend nsresult (::NS_NewSVGEllipseElement(nsIContent **aResult, already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo)); public: // nsSVGSVGElement methods: virtual bool HasValidDimensions() const MOZ_OVERRIDE; // nsSVGPathGeometryElement methods: + virtual bool GetGeometryBounds(Rect* aBounds, Float aStrokeWidth, + const Matrix& aTransform) MOZ_OVERRIDE; virtual TemporaryRef<Path> BuildPath(PathBuilder* aBuilder) MOZ_OVERRIDE; virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const MOZ_OVERRIDE; // WebIDL already_AddRefed<SVGAnimatedLength> Cx(); already_AddRefed<SVGAnimatedLength> Cy(); already_AddRefed<SVGAnimatedLength> Rx();
--- a/dom/svg/nsSVGPathGeometryElement.h +++ b/dom/svg/nsSVGPathGeometryElement.h @@ -65,16 +65,22 @@ public: * This could be moved up to a more general class so it can be used for non-leaf * elements, but that would require care and for now there's no need. */ bool GeometryDependsOnCoordCtx(); virtual bool IsMarkable(); virtual void GetMarkPoints(nsTArray<nsSVGMark> *aMarks); + /** + * A method that can be faster than using a Moz2D Path and calling GetBounds/ + * GetStrokedBounds on it. It also helps us avoid rounding error for simple + * shapes and simple transforms where the Moz2D Path backends can fail to + * produce the clean integer bounds that content authors expect in some cases. + */ virtual bool GetGeometryBounds(Rect* aBounds, Float aStrokeWidth, const Matrix& aTransform) { return false; } /** * For use with GetAsSimplePath. */
--- a/dom/tests/mochitest/general/test_interfaces.html +++ b/dom/tests/mochitest/general/test_interfaces.html @@ -631,16 +631,18 @@ var interfaceNamesInGlobalScope = "KeyEvent", // IMPORTANT: Do not change this list without review from a DOM peer! "KeyboardEvent", // IMPORTANT: Do not change this list without review from a DOM peer! "LocalMediaStream", // IMPORTANT: Do not change this list without review from a DOM peer! "Location", // IMPORTANT: Do not change this list without review from a DOM peer! + "MediaDevices", +// IMPORTANT: Do not change this list without review from a DOM peer! "MediaElementAudioSourceNode", // IMPORTANT: Do not change this list without review from a DOM peer! "MediaError", // IMPORTANT: Do not change this list without review from a DOM peer! {name: "MediaKeyError", pref: "media.eme.enabled"}, // IMPORTANT: Do not change this list without review from a DOM peer! {name: "MediaEncryptedEvent", pref: "media.eme.enabled"}, // IMPORTANT: Do not change this list without review from a DOM peer!
new file mode 100644 --- /dev/null +++ b/dom/webidl/MediaDevices.webidl @@ -0,0 +1,23 @@ +/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + * + * The origin of this IDL file is + * http://dev.w3.org/2011/webrtc/editor/getusermedia.html + * + * Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C + * liability, trademark and document use rules apply. + */ + +[Func="Navigator::HasUserMediaSupport"] +interface MediaDevices : EventTarget { +// attribute EventHandler ondevicechange; +// +// void enumerateDevices (MediaDeviceInfoCallback resultCallback); +// +// static Dictionary getSupportedConstraints (DOMString kind); + + [Throws, Func="Navigator::HasUserMediaSupport"] + Promise<MediaStream> getUserMedia(optional MediaStreamConstraints constraints); +};
new file mode 100644 --- /dev/null +++ b/dom/webidl/MediaStreamError.webidl @@ -0,0 +1,21 @@ +/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * The origin of this IDL file is + * http://w3c.github.io/mediacapture-main/getusermedia.html#idl-def-MediaStreamError + */ + +// The future of MediaStreamError is uncertain. +// https://www.w3.org/Bugs/Public/show_bug.cgi?id=26776 + +// TODO: This is an 'exception', not an interface, by virtue of needing to be +// passed as a promise rejection-reason. Revisit if DOMException grows a customArg + +[ExceptionClass, NoInterfaceObject] +interface MediaStreamError { + readonly attribute DOMString name; + readonly attribute DOMString? message; + readonly attribute DOMString? constraintName; +};
--- a/dom/webidl/Navigator.webidl +++ b/dom/webidl/Navigator.webidl @@ -349,20 +349,24 @@ partial interface Navigator { partial interface Navigator { [Throws] readonly attribute AudioChannelManager mozAudioChannelManager; }; #endif // MOZ_AUDIO_CHANNEL_MANAGER #ifdef MOZ_MEDIA_NAVIGATOR callback NavigatorUserMediaSuccessCallback = void (MediaStream stream); -callback NavigatorUserMediaErrorCallback = void (DOMString error); +callback NavigatorUserMediaErrorCallback = void (MediaStreamError error); partial interface Navigator { [Throws, Func="Navigator::HasUserMediaSupport"] + readonly attribute MediaDevices mediaDevices; + + // Deprecated. Use mediaDevices.getUserMedia instead. + [Throws, Func="Navigator::HasUserMediaSupport"] void mozGetUserMedia(MediaStreamConstraints constraints, NavigatorUserMediaSuccessCallback successCallback, NavigatorUserMediaErrorCallback errorCallback); }; // nsINavigatorUserMedia callback MozGetUserMediaDevicesSuccessCallback = void (nsIVariant? devices); partial interface Navigator {
--- a/dom/webidl/moz.build +++ b/dom/webidl/moz.build @@ -250,25 +250,27 @@ WEBIDL_FILES = [ 'KeyAlgorithm.webidl', 'KeyboardEvent.webidl', 'KeyEvent.webidl', 'LegacyQueryInterface.webidl', 'LinkStyle.webidl', 'ListBoxObject.webidl', 'LocalMediaStream.webidl', 'Location.webidl', + 'MediaDevices.webidl', 'MediaElementAudioSourceNode.webidl', 'MediaError.webidl', 'MediaList.webidl', 'MediaQueryList.webidl', 'MediaRecorder.webidl', 'MediaSource.webidl', 'MediaStream.webidl', 'MediaStreamAudioDestinationNode.webidl', 'MediaStreamAudioSourceNode.webidl', + 'MediaStreamError.webidl', 'MediaStreamTrack.webidl', 'MediaTrackConstraintSet.webidl', 'MenuBoxObject.webidl', 'MessageChannel.webidl', 'MessageEvent.webidl', 'MessagePort.webidl', 'MessagePortList.webidl', 'MimeType.webidl',
--- a/gfx/2d/Helpers.h +++ b/gfx/2d/Helpers.h @@ -40,12 +40,58 @@ class AutoRestoreTransform } } private: RefPtr<DrawTarget> mDrawTarget; Matrix mOldTransform; }; +class AutoPopClips +{ +public: + explicit AutoPopClips(DrawTarget *aTarget) + : mDrawTarget(aTarget) + , mPushCount(0) + { + MOZ_ASSERT(mDrawTarget); + } + + ~AutoPopClips() + { + PopAll(); + } + + void PushClip(const Path *aPath) + { + mDrawTarget->PushClip(aPath); + ++mPushCount; + } + + void PushClipRect(const Rect &aRect) + { + mDrawTarget->PushClipRect(aRect); + ++mPushCount; + } + + void PopClip() + { + MOZ_ASSERT(mPushCount > 0); + mDrawTarget->PopClip(); + --mPushCount; + } + + void PopAll() + { + while (mPushCount-- > 0) { + mDrawTarget->PopClip(); + } + } + +private: + RefPtr<DrawTarget> mDrawTarget; + int32_t mPushCount; +}; + } // namespace gfx } // namespace mozilla #endif // MOZILLA_GFX_2D_HELPERS_H_
--- a/gfx/2d/PathCG.cpp +++ b/gfx/2d/PathCG.cpp @@ -2,16 +2,17 @@ * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "PathCG.h" #include <math.h> #include "DrawTargetCG.h" #include "Logging.h" +#include "PathHelpers.h" namespace mozilla { namespace gfx { PathBuilderCG::~PathBuilderCG() { CGPathRelease(mCGPath); } @@ -63,30 +64,37 @@ PathBuilderCG::Close() if (!CGPathIsEmpty(mCGPath)) CGPathCloseSubpath(mCGPath); } void PathBuilderCG::Arc(const Point &aOrigin, Float aRadius, Float aStartAngle, Float aEndAngle, bool aAntiClockwise) { + // Disabled for now due to a CG bug when using CGPathAddArc with stroke + // dashing and rotation transforms that are multiples of 90 degrees. See: + // https://bugzilla.mozilla.org/show_bug.cgi?id=949661#c8 +#if 0 // Core Graphic's initial coordinate system is y-axis up, whereas Moz2D's is // y-axis down. Core Graphics therefore considers "clockwise" to mean "sweep // in the direction of decreasing angle" whereas Moz2D considers it to mean // "sweep in the direction of increasing angle". In other words if this // Moz2D method is instructed to sweep anti-clockwise we need to tell // CGPathAddArc to sweep clockwise, and vice versa. Hence why we pass the // value of aAntiClockwise directly to CGPathAddArc's "clockwise" bool // parameter. CGPathAddArc(mCGPath, nullptr, aOrigin.x, aOrigin.y, aRadius, aStartAngle, aEndAngle, aAntiClockwise); +#endif + ArcToBezier(this, aOrigin, Size(aRadius, aRadius), aStartAngle, aEndAngle, + aAntiClockwise); } Point PathBuilderCG::CurrentPoint() const { CGPoint pt = CGPathGetCurrentPoint(mCGPath); Point ret(pt.x, pt.y); return ret;
--- a/gfx/angle/AUTHORS +++ b/gfx/angle/AUTHORS @@ -9,28 +9,29 @@ Google Inc. TransGaming Inc. 3DLabs Inc. Ltd. Adobe Systems Inc. Autodesk, Inc. BlackBerry Limited -Borbitsoft Cable Television Laboratories, Inc. Cloud Party, Inc. Intel Corporation Mozilla Corporation Turbulenz Klarälvdalens Datakonsult AB Microsoft Open Technologies, Inc. +NVIDIA Corporation Jacek Caban Mark Callow Ginn Chen +Tibor den Ouden James Hauxwell Sam Hocevar Pierre Leveille Jonathan Liu Boying Lu Aitor Moreno Yuri O'Donnell Josh Soref
--- a/gfx/angle/CONTRIBUTORS +++ b/gfx/angle/CONTRIBUTORS @@ -44,19 +44,16 @@ Google Inc. Adobe Systems Inc. Alexandru Chiculita Steve Minns Max Vujovic Autodesk, Inc. Ranger Harke -Borbitsoft - Tibor den Ouden - Cloud Party, Inc. Conor Dickinson Digia Plc Andrew Knight Intel Corporation Jin Yang @@ -77,12 +74,16 @@ Mozilla Corp. Turbulenz Michael Braithwaite Ulrik Persson (ddefrostt) Mark Banner (standard8mbp) David Kilzer Jacek Caban +Tibor den Ouden Microsoft Open Technologies, Inc. Cooper Partin Austin Kinross + +NVIDIA Corporation + Olli Etuaho
--- a/gfx/angle/include/GLSLANG/ShaderLang.h +++ b/gfx/angle/include/GLSLANG/ShaderLang.h @@ -241,16 +241,22 @@ typedef struct // Set to 1 to enable the extension, else 0. int OES_standard_derivatives; int OES_EGL_image_external; int ARB_texture_rectangle; int EXT_draw_buffers; int EXT_frag_depth; int EXT_shader_texture_lod; + // Set to 1 to enable replacing GL_EXT_draw_buffers #extension directives + // with GL_NV_draw_buffers in ESSL output. This flag can be used to emulate + // EXT_draw_buffers by using it in combination with GLES3.0 glDrawBuffers + // function. This applies to Tegra K1 devices. + int NV_draw_buffers; + // Set to 1 if highp precision is supported in the fragment language. // Default is 0. int FragmentPrecisionHigh; // GLSL ES 3.0 constants. int MaxVertexOutputVectors; int MaxFragmentInputVectors; int MinProgramTexelOffset;
--- a/gfx/angle/include/GLSLANG/ShaderVars.h +++ b/gfx/angle/include/GLSLANG/ShaderVars.h @@ -47,60 +47,122 @@ struct COMPILER_EXPORT ShaderVariable ~ShaderVariable(); ShaderVariable(const ShaderVariable &other); ShaderVariable &operator=(const ShaderVariable &other); bool isArray() const { return arraySize > 0; } unsigned int elementCount() const { return std::max(1u, arraySize); } bool isStruct() const { return !fields.empty(); } + // All of the shader's variables are described using nested data + // structures. This is needed in order to disambiguate similar looking + // types, such as two structs containing the same fields, but in + // different orders. "findInfoByMappedName" provides an easy query for + // users to dive into the data structure and fetch the unique variable + // instance corresponding to a dereferencing chain of the top-level + // variable. + // Given a mapped name like 'a[0].b.c[0]', return the ShaderVariable + // that defines 'c' in |leafVar|, and the original name 'A[0].B.C[0]' + // in |originalName|, based on the assumption that |this| defines 'a'. + // If no match is found, return false. + bool findInfoByMappedName(const std::string &mappedFullName, + const ShaderVariable **leafVar, + std::string* originalFullName) const; + GLenum type; GLenum precision; std::string name; std::string mappedName; unsigned int arraySize; bool staticUse; std::vector<ShaderVariable> fields; std::string structName; + + protected: + bool isSameVariableAtLinkTime(const ShaderVariable &other, + bool matchPrecision) const; + + bool operator==(const ShaderVariable &other) const; + bool operator!=(const ShaderVariable &other) const + { + return !operator==(other); + } }; struct COMPILER_EXPORT Uniform : public ShaderVariable { Uniform(); ~Uniform(); Uniform(const Uniform &other); Uniform &operator=(const Uniform &other); + bool operator==(const Uniform &other) const; + bool operator!=(const Uniform &other) const + { + return !operator==(other); + } + + // Decide whether two uniforms are the same at shader link time, + // assuming one from vertex shader and the other from fragment shader. + // See GLSL ES Spec 3.00.3, sec 4.3.5. + bool isSameUniformAtLinkTime(const Uniform &other) const; }; struct COMPILER_EXPORT Attribute : public ShaderVariable { Attribute(); ~Attribute(); Attribute(const Attribute &other); Attribute &operator=(const Attribute &other); + bool operator==(const Attribute &other) const; + bool operator!=(const Attribute &other) const + { + return !operator==(other); + } int location; }; struct COMPILER_EXPORT InterfaceBlockField : public ShaderVariable { InterfaceBlockField(); ~InterfaceBlockField(); InterfaceBlockField(const InterfaceBlockField &other); InterfaceBlockField &operator=(const InterfaceBlockField &other); + bool operator==(const InterfaceBlockField &other) const; + bool operator!=(const InterfaceBlockField &other) const + { + return !operator==(other); + } + + // Decide whether two InterfaceBlock fields are the same at shader + // link time, assuming one from vertex shader and the other from + // fragment shader. + // See GLSL ES Spec 3.00.3, sec 4.3.7. + bool isSameInterfaceBlockFieldAtLinkTime( + const InterfaceBlockField &other) const; bool isRowMajorLayout; }; struct COMPILER_EXPORT Varying : public ShaderVariable { Varying(); ~Varying(); - Varying(const Varying &other); + Varying(const Varying &otherg); Varying &operator=(const Varying &other); + bool operator==(const Varying &other) const; + bool operator!=(const Varying &other) const + { + return !operator==(other); + } + + // Decide whether two varyings are the same at shader link time, + // assuming one from vertex shader and the other from fragment shader. + // See GLSL ES Spec 3.00.3, sec 4.3.9. + bool isSameVaryingAtLinkTime(const Varying &other) const; InterpolationType interpolation; bool isInvariant; }; struct COMPILER_EXPORT InterfaceBlock { InterfaceBlock();
--- a/gfx/angle/src/commit.h +++ b/gfx/angle/src/commit.h @@ -1,3 +1,3 @@ -#define ANGLE_COMMIT_HASH "7a2ba5a15abc" +#define ANGLE_COMMIT_HASH "f0cacb827771" #define ANGLE_COMMIT_HASH_SIZE 12 -#define ANGLE_COMMIT_DATE "2014-10-25 15:19:56 -0400" +#define ANGLE_COMMIT_DATE "2014-10-28 23:00:12 -0400"
--- a/gfx/angle/src/common/angleutils.cpp +++ b/gfx/angle/src/common/angleutils.cpp @@ -1,16 +1,17 @@ // // Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // #include "common/angleutils.h" +#include <stdio.h> #include <vector> std::string FormatString(const char *fmt, va_list vararg) { static std::vector<char> buffer(512); // Attempt to just print to the current buffer int len = vsnprintf(&buffer[0], buffer.size(), fmt, vararg);
--- a/gfx/angle/src/compiler/translator/Compiler.cpp +++ b/gfx/angle/src/compiler/translator/Compiler.cpp @@ -355,17 +355,18 @@ void TCompiler::setResourceString() << ":FragmentPrecisionHigh:" << compileResources.FragmentPrecisionHigh << ":MaxExpressionComplexity:" << compileResources.MaxExpressionComplexity << ":MaxCallStackDepth:" << compileResources.MaxCallStackDepth << ":EXT_frag_depth:" << compileResources.EXT_frag_depth << ":EXT_shader_texture_lod:" << compileResources.EXT_shader_texture_lod << ":MaxVertexOutputVectors:" << compileResources.MaxVertexOutputVectors << ":MaxFragmentInputVectors:" << compileResources.MaxFragmentInputVectors << ":MinProgramTexelOffset:" << compileResources.MinProgramTexelOffset - << ":MaxProgramTexelOffset:" << compileResources.MaxProgramTexelOffset; + << ":MaxProgramTexelOffset:" << compileResources.MaxProgramTexelOffset + << ":NV_draw_buffers:" << compileResources.NV_draw_buffers; builtInResourcesString = strstream.str(); } void TCompiler::clearResults() { arrayBoundsClamper.Cleanup(); infoSink.info.erase();
--- a/gfx/angle/src/compiler/translator/ShaderLang.cpp +++ b/gfx/angle/src/compiler/translator/ShaderLang.cpp @@ -196,16 +196,18 @@ void ShInitBuiltInResources(ShBuiltInRes // Extensions. resources->OES_standard_derivatives = 0; resources->OES_EGL_image_external = 0; resources->ARB_texture_rectangle = 0; resources->EXT_draw_buffers = 0; resources->EXT_frag_depth = 0; resources->EXT_shader_texture_lod = 0; + resources->NV_draw_buffers = 0; + // Disable highp precision in fragment shader by default. resources->FragmentPrecisionHigh = 0; // GLSL ES 3.0 constants. resources->MaxVertexOutputVectors = 16; resources->MaxFragmentInputVectors = 15; resources->MinProgramTexelOffset = -8; resources->MaxProgramTexelOffset = 7;
--- a/gfx/angle/src/compiler/translator/ShaderVars.cpp +++ b/gfx/angle/src/compiler/translator/ShaderVars.cpp @@ -4,16 +4,18 @@ // found in the LICENSE file. // // ShaderVars.cpp: // Methods for GL variable types (varyings, uniforms, etc) // #include <GLSLANG/ShaderLang.h> +#include "compiler/translator/compilerdebug.h" + namespace sh { ShaderVariable::ShaderVariable() : type(0), precision(0), arraySize(0), staticUse(false) @@ -48,32 +50,162 @@ ShaderVariable &ShaderVariable::operator mappedName = other.mappedName; arraySize = other.arraySize; staticUse = other.staticUse; fields = other.fields; structName = other.structName; return *this; } +bool ShaderVariable::operator==(const ShaderVariable &other) const +{ + if (type != other.type || + precision != other.precision || + name != other.name || + mappedName != other.mappedName || + arraySize != other.arraySize || + staticUse != other.staticUse || + fields.size() != other.fields.size() || + structName != other.structName) + { + return false; + } + for (size_t ii = 0; ii < fields.size(); ++ii) + { + if (fields[ii] != other.fields[ii]) + return false; + } + return true; +} + +bool ShaderVariable::findInfoByMappedName( + const std::string &mappedFullName, + const ShaderVariable **leafVar, std::string *originalFullName) const +{ + ASSERT(leafVar && originalFullName); + // There are three cases: + // 1) the top variable is of struct type; + // 2) the top variable is an array; + // 3) otherwise. + size_t pos = mappedFullName.find_first_of(".["); + std::string topName; + + if (pos == std::string::npos) + { + // Case 3. + if (mappedFullName != this->mappedName) + return false; + *originalFullName = this->name; + *leafVar = this; + return true; + } + else + { + std::string topName = mappedFullName.substr(0, pos); + if (topName != this->mappedName) + return false; + std::string originalName = this->name; + std::string remaining; + if (mappedFullName[pos] == '[') + { + // Case 2. + size_t closePos = mappedFullName.find_first_of(']'); + if (closePos < pos || closePos == std::string::npos) + return false; + // Append '[index]'. + originalName += mappedFullName.substr(pos, closePos - pos + 1); + if (closePos + 1 == mappedFullName.size()) + { + *originalFullName = originalName; + *leafVar = this; + return true; + } + else + { + // In the form of 'a[0].b', so after ']', '.' is expected. + if (mappedFullName[closePos + 1] != '.') + return false; + remaining = mappedFullName.substr(closePos + 2); // Skip "]." + } + } + else + { + // Case 1. + remaining = mappedFullName.substr(pos + 1); // Skip "." + } + for (size_t ii = 0; ii < this->fields.size(); ++ii) + { + const ShaderVariable *fieldVar = NULL; + std::string originalFieldName; + bool found = fields[ii].findInfoByMappedName( + remaining, &fieldVar, &originalFieldName); + if (found) + { + *originalFullName = originalName + "." + originalFieldName; + *leafVar = fieldVar; + return true; + } + } + return false; + } +} + +bool ShaderVariable::isSameVariableAtLinkTime( + const ShaderVariable &other, bool matchPrecision) const +{ + if (type != other.type) + return false; + if (matchPrecision && precision != other.precision) + return false; + if (name != other.name) + return false; + ASSERT(mappedName == other.mappedName); + if (arraySize != other.arraySize) + return false; + if (fields.size() != other.fields.size()) + return false; + for (size_t ii = 0; ii < fields.size(); ++ii) + { + if (!fields[ii].isSameVariableAtLinkTime(other.fields[ii], + matchPrecision)) + { + return false; + } + } + if (structName != other.structName) + return false; + return true; +} + Uniform::Uniform() {} Uniform::~Uniform() {} Uniform::Uniform(const Uniform &other) : ShaderVariable(other) {} Uniform &Uniform::operator=(const Uniform &other) { ShaderVariable::operator=(other); return *this; } +bool Uniform::operator==(const Uniform &other) const +{ + return ShaderVariable::operator==(other); +} + +bool Uniform::isSameUniformAtLinkTime(const Uniform &other) const +{ + return ShaderVariable::isSameVariableAtLinkTime(other, true); +} + Attribute::Attribute() : location(-1) {} Attribute::~Attribute() {} Attribute::Attribute(const Attribute &other) @@ -83,16 +215,22 @@ Attribute::Attribute(const Attribute &ot Attribute &Attribute::operator=(const Attribute &other) { ShaderVariable::operator=(other); location = other.location; return *this; } +bool Attribute::operator==(const Attribute &other) const +{ + return (ShaderVariable::operator==(other) && + location == other.location); +} + InterfaceBlockField::InterfaceBlockField() : isRowMajorLayout(false) {} InterfaceBlockField::~InterfaceBlockField() {} InterfaceBlockField::InterfaceBlockField(const InterfaceBlockField &other) @@ -102,16 +240,29 @@ InterfaceBlockField::InterfaceBlockField InterfaceBlockField &InterfaceBlockField::operator=(const InterfaceBlockField &other) { ShaderVariable::operator=(other); isRowMajorLayout = other.isRowMajorLayout; return *this; } +bool InterfaceBlockField::operator==(const InterfaceBlockField &other) const +{ + return (ShaderVariable::operator==(other) && + isRowMajorLayout == other.isRowMajorLayout); +} + +bool InterfaceBlockField::isSameInterfaceBlockFieldAtLinkTime( + const InterfaceBlockField &other) const +{ + return (ShaderVariable::isSameVariableAtLinkTime(other, true) && + isRowMajorLayout == other.isRowMajorLayout); +} + Varying::Varying() : interpolation(INTERPOLATION_SMOOTH), isInvariant(false) {} Varying::~Varying() {} @@ -124,16 +275,30 @@ Varying::Varying(const Varying &other) Varying &Varying::operator=(const Varying &other) { ShaderVariable::operator=(other); interpolation = other.interpolation; isInvariant = other.isInvariant; return *this; } +bool Varying::operator==(const Varying &other) const +{ + return (ShaderVariable::operator==(other) && + interpolation == other.interpolation && + isInvariant == other.isInvariant); +} + +bool Varying::isSameVaryingAtLinkTime(const Varying &other) const +{ + return (ShaderVariable::isSameVariableAtLinkTime(other, false) && + interpolation == other.interpolation && + isInvariant == other.isInvariant); +} + InterfaceBlock::InterfaceBlock() : arraySize(0), layout(BLOCKLAYOUT_PACKED), isRowMajorLayout(false), staticUse(false) {} InterfaceBlock::~InterfaceBlock()
--- a/gfx/angle/src/compiler/translator/TranslatorESSL.cpp +++ b/gfx/angle/src/compiler/translator/TranslatorESSL.cpp @@ -32,13 +32,18 @@ void TranslatorESSL::translate(TIntermNo } void TranslatorESSL::writeExtensionBehavior() { TInfoSinkBase& sink = getInfoSink().obj; const TExtensionBehavior& extensionBehavior = getExtensionBehavior(); for (TExtensionBehavior::const_iterator iter = extensionBehavior.begin(); iter != extensionBehavior.end(); ++iter) { if (iter->second != EBhUndefined) { - sink << "#extension " << iter->first << " : " - << getBehaviorString(iter->second) << "\n"; + if (getResources().NV_draw_buffers && iter->first == "GL_EXT_draw_buffers") { + sink << "#extension GL_NV_draw_buffers : " + << getBehaviorString(iter->second) << "\n"; + } else { + sink << "#extension " << iter->first << " : " + << getBehaviorString(iter->second) << "\n"; + } } } }
--- a/gfx/angle/src/libGLESv2/Context.cpp +++ b/gfx/angle/src/libGLESv2/Context.cpp @@ -86,23 +86,23 @@ Context::Context(int clientVersion, cons bindArrayBuffer(0); bindElementArrayBuffer(0); bindReadFramebuffer(0); bindDrawFramebuffer(0); bindRenderbuffer(0); bindGenericUniformBuffer(0); - for (int i = 0; i < IMPLEMENTATION_MAX_COMBINED_SHADER_UNIFORM_BUFFERS; i++) + for (unsigned int i = 0; i < mCaps.maxCombinedUniformBlocks; i++) { bindIndexedUniformBuffer(0, i, 0, -1); } bindGenericTransformFeedbackBuffer(0); - for (int i = 0; i < IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS; i++) + for (unsigned int i = 0; i < mCaps.maxTransformFeedbackSeparateAttributes; i++) { bindIndexedTransformFeedbackBuffer(0, i, 0, -1); } bindCopyReadBuffer(0); bindCopyWriteBuffer(0); bindPixelPackBuffer(0); bindPixelUnpackBuffer(0); @@ -114,18 +114,16 @@ Context::Context(int clientVersion, cons mTransformFeedbackZero.set(new TransformFeedback(mRenderer->createTransformFeedback(), 0)); bindTransformFeedback(0); mHasBeenCurrent = false; mContextLost = false; mResetStatus = GL_NO_ERROR; mResetStrategy = (notifyResets ? GL_LOSE_CONTEXT_ON_RESET_EXT : GL_NO_RESET_NOTIFICATION_EXT); mRobustAccess = robustAccess; - - mState.setContext(this); } Context::~Context() { GLuint currentProgram = mState.getCurrentProgramId(); if (currentProgram != 0) { Program *programObject = mResourceManager->getProgram(currentProgram); @@ -635,43 +633,54 @@ void Context::useProgram(GLuint program) if (priorProgram) { priorProgram->release(); } } } -void Context::linkProgram(GLuint program) +Error Context::linkProgram(GLuint program) { Program *programObject = mResourceManager->getProgram(program); - bool linked = programObject->link(getCaps()); + Error error = programObject->link(getCaps()); + if (error.isError()) + { + return error; + } // if the current program was relinked successfully we // need to install the new executables - if (linked && program == mState.getCurrentProgramId()) - { - mState.setCurrentProgramBinary(programObject->getProgramBinary()); - } -} - -void Context::setProgramBinary(GLuint program, GLenum binaryFormat, const void *binary, GLint length) -{ - Program *programObject = mResourceManager->getProgram(program); - - bool loaded = programObject->setProgramBinary(binaryFormat, binary, length); - - // if the current program was reloaded successfully we - // need to install the new executables - if (loaded && program == mState.getCurrentProgramId()) + if (programObject->isLinked() && program == mState.getCurrentProgramId()) { mState.setCurrentProgramBinary(programObject->getProgramBinary()); } + return Error(GL_NO_ERROR); +} + +Error Context::setProgramBinary(GLuint program, GLenum binaryFormat, const void *binary, GLint length) +{ + Program *programObject = mResourceManager->getProgram(program); + + Error error = programObject->setProgramBinary(binaryFormat, binary, length); + if (error.isError()) + { + return error; + } + + // if the current program was reloaded successfully we + // need to install the new executables + if (programObject->isLinked() && program == mState.getCurrentProgramId()) + { + mState.setCurrentProgramBinary(programObject->getProgramBinary()); + } + + return Error(GL_NO_ERROR); } void Context::bindTransformFeedback(GLuint transformFeedback) { mState.setTransformFeedbackBinding(getTransformFeedback(transformFeedback)); } Error Context::beginQuery(GLenum target, GLuint query) @@ -1393,20 +1402,18 @@ Error Context::applyState(GLenum drawMod } return Error(GL_NO_ERROR); } // Applies the shaders and shader constants to the Direct3D 9 device Error Context::applyShaders(ProgramBinary *programBinary, bool transformFeedbackActive) { - const VertexAttribute *vertexAttributes = mState.getVertexArray()->getVertexAttributes(); - VertexFormat inputLayout[MAX_VERTEX_ATTRIBS]; - VertexFormat::GetInputLayout(inputLayout, programBinary, vertexAttributes, mState.getVertexAttribCurrentValues()); + VertexFormat::GetInputLayout(inputLayout, programBinary, mState); const Framebuffer *fbo = mState.getDrawFramebuffer(); Error error = mRenderer->applyShaders(programBinary, inputLayout, fbo, mState.getRasterizerState().rasterizerDiscard, transformFeedbackActive); if (error.isError()) { return error; } @@ -1579,35 +1586,28 @@ Error Context::applyUniformBuffers() return programBinary->applyUniformBuffers(boundBuffers, getCaps()); } bool Context::applyTransformFeedbackBuffers() { TransformFeedback *curTransformFeedback = mState.getCurrentTransformFeedback(); if (curTransformFeedback && curTransformFeedback->isStarted() && !curTransformFeedback->isPaused()) { - Buffer *transformFeedbackBuffers[IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS]; - GLintptr transformFeedbackOffsets[IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS]; - for (size_t i = 0; i < IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS; i++) - { - transformFeedbackBuffers[i] = mState.getIndexedTransformFeedbackBuffer(i); - transformFeedbackOffsets[i] = mState.getIndexedTransformFeedbackBufferOffset(i); - } - mRenderer->applyTransformFeedbackBuffers(transformFeedbackBuffers, transformFeedbackOffsets); + mRenderer->applyTransformFeedbackBuffers(mState); return true; } else { return false; } } void Context::markTransformFeedbackUsage() { - for (size_t i = 0; i < IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS; i++) + for (size_t i = 0; i < mCaps.maxTransformFeedbackSeparateAttributes; i++) { Buffer *buffer = mState.getIndexedTransformFeedbackBuffer(i); if (buffer) { buffer->markTransformFeedbackUsage(); } } } @@ -1766,17 +1766,17 @@ Error Context::drawArrays(GLenum mode, G } error = applyState(mode); if (error.isError()) { return error; } - error = mRenderer->applyVertexBuffer(programBinary, mState.getVertexArray()->getVertexAttributes(), mState.getVertexAttribCurrentValues(), first, count, instances); + error = mRenderer->applyVertexBuffer(mState, first, count, instances); if (error.isError()) { return error; } bool transformFeedbackActive = applyTransformFeedbackBuffers(); error = applyShaders(programBinary, transformFeedbackActive); @@ -1851,19 +1851,17 @@ Error Context::drawElements(GLenum mode, indexInfo.indexRange = indexRange; error = mRenderer->applyIndexBuffer(indices, vao->getElementArrayBuffer(), count, mode, type, &indexInfo); if (error.isError()) { return error; } GLsizei vertexCount = indexInfo.indexRange.length() + 1; - error = mRenderer->applyVertexBuffer(programBinary, vao->getVertexAttributes(), - mState.getVertexAttribCurrentValues(), - indexInfo.indexRange.start, vertexCount, instances); + error = mRenderer->applyVertexBuffer(mState, indexInfo.indexRange.start, vertexCount, instances); if (error.isError()) { return error; } bool transformFeedbackActive = applyTransformFeedbackBuffers(); // Transform feedback is not allowed for DrawElements, this error should have been caught at the API validation // layer.
--- a/gfx/angle/src/libGLESv2/Context.h +++ b/gfx/angle/src/libGLESv2/Context.h @@ -125,18 +125,18 @@ class Context void bindIndexedUniformBuffer(GLuint buffer, GLuint index, GLintptr offset, GLsizeiptr size); void bindGenericTransformFeedbackBuffer(GLuint buffer); void bindIndexedTransformFeedbackBuffer(GLuint buffer, GLuint index, GLintptr offset, GLsizeiptr size); void bindCopyReadBuffer(GLuint buffer); void bindCopyWriteBuffer(GLuint buffer); void bindPixelPackBuffer(GLuint buffer); void bindPixelUnpackBuffer(GLuint buffer); void useProgram(GLuint program); - void linkProgram(GLuint program); - void setProgramBinary(GLuint program, GLenum binaryFormat, const void *binary, GLint length); + Error linkProgram(GLuint program); + Error setProgramBinary(GLuint program, GLenum binaryFormat, const void *binary, GLint length); void bindTransformFeedback(GLuint transformFeedback); Error beginQuery(GLenum target, GLuint query); Error endQuery(GLenum target); void setFramebufferZero(Framebuffer *framebuffer); void setRenderbufferStorage(GLsizei width, GLsizei height, GLenum internalformat, GLsizei samples);
--- a/gfx/angle/src/libGLESv2/ImageIndex.cpp +++ b/gfx/angle/src/libGLESv2/ImageIndex.cpp @@ -43,16 +43,21 @@ ImageIndex ImageIndex::Make2DArray(GLint return ImageIndex(GL_TEXTURE_2D_ARRAY, mipIndex, layerIndex); } ImageIndex ImageIndex::Make3D(GLint mipIndex, GLint layerIndex) { return ImageIndex(GL_TEXTURE_3D, mipIndex, layerIndex); } +ImageIndex ImageIndex::MakeInvalid() +{ + return ImageIndex(GL_NONE, -1, -1); +} + ImageIndex::ImageIndex(GLenum typeIn, GLint mipIndexIn, GLint layerIndexIn) : type(typeIn), mipIndex(mipIndexIn), layerIndex(layerIndexIn) {} ImageIndexIterator ImageIndexIterator::Make2D(GLint minMip, GLint maxMip) {
--- a/gfx/angle/src/libGLESv2/ImageIndex.h +++ b/gfx/angle/src/libGLESv2/ImageIndex.h @@ -26,16 +26,17 @@ struct ImageIndex ImageIndex &operator=(const ImageIndex &other); bool hasLayer() const { return layerIndex != ENTIRE_LEVEL; } static ImageIndex Make2D(GLint mipIndex); static ImageIndex MakeCube(GLenum target, GLint mipIndex); static ImageIndex Make2DArray(GLint mipIndex, GLint layerIndex); static ImageIndex Make3D(GLint mipIndex, GLint layerIndex = ENTIRE_LEVEL); + static ImageIndex MakeInvalid(); static const GLint ENTIRE_LEVEL = static_cast<GLint>(-1); }; class ImageIndexIterator { public: static ImageIndexIterator Make2D(GLint minMip, GLint maxMip);
--- a/gfx/angle/src/libGLESv2/Program.cpp +++ b/gfx/angle/src/libGLESv2/Program.cpp @@ -239,28 +239,33 @@ void AttributeBindings::bindAttributeLoc void Program::bindAttributeLocation(GLuint index, const char *name) { mAttributeBindings.bindAttributeLocation(index, name); } // Links the HLSL code of the vertex and pixel shader by matching up their varyings, // compiling them into binaries, determining the attribute mappings, and collecting // a list of uniforms -bool Program::link(const Caps &caps) +Error Program::link(const Caps &caps) { unlink(false); mInfoLog.reset(); resetUniformBlockBindings(); mProgramBinary.set(new ProgramBinary(mRenderer->createProgram())); - mLinked = mProgramBinary->link(mInfoLog, mAttributeBindings, mFragmentShader, mVertexShader, - mTransformFeedbackVaryings, mTransformFeedbackBufferMode, caps); + LinkResult result = mProgramBinary->link(mInfoLog, mAttributeBindings, mFragmentShader, mVertexShader, + mTransformFeedbackVaryings, mTransformFeedbackBufferMode, caps); + if (result.error.isError()) + { + return result.error; + } - return mLinked; + mLinked = result.linkSuccess; + return gl::Error(GL_NO_ERROR); } int AttributeBindings::getAttributeBinding(const std::string &name) const { for (int location = 0; location < MAX_VERTEX_ATTRIBS; location++) { if (mAttributeBinding[location].find(name) != mAttributeBinding[location].end()) { @@ -298,31 +303,32 @@ bool Program::isLinked() return mLinked; } ProgramBinary* Program::getProgramBinary() const { return mProgramBinary.get(); } -bool Program::setProgramBinary(GLenum binaryFormat, const void *binary, GLsizei length) +Error Program::setProgramBinary(GLenum binaryFormat, const void *binary, GLsizei length) { unlink(false); mInfoLog.reset(); mProgramBinary.set(new ProgramBinary(mRenderer->createProgram())); - mLinked = mProgramBinary->load(mInfoLog, binaryFormat, binary, length); - - if (!mLinked) + LinkResult result = mProgramBinary->load(mInfoLog, binaryFormat, binary, length); + if (result.error.isError()) { mProgramBinary.set(NULL); + return result.error; } - return mLinked; + mLinked = result.linkSuccess; + return Error(GL_NO_ERROR); } void Program::release() { mRefCount--; if (mRefCount == 0 && mDeleteStatus) {
--- a/gfx/angle/src/libGLESv2/Program.h +++ b/gfx/angle/src/libGLESv2/Program.h @@ -72,19 +72,19 @@ class Program ~Program(); bool attachShader(Shader *shader); bool detachShader(Shader *shader); int getAttachedShadersCount() const; void bindAttributeLocation(GLuint index, const char *name); - bool link(const Caps &caps); + Error link(const Caps &caps); bool isLinked(); - bool setProgramBinary(GLenum binaryFormat, const void *binary, GLsizei length); + Error setProgramBinary(GLenum binaryFormat, const void *binary, GLsizei length); ProgramBinary *getProgramBinary() const; int getInfoLogLength() const; void getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog); void getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders); void getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); GLint getActiveAttributeCount();
--- a/gfx/angle/src/libGLESv2/ProgramBinary.cpp +++ b/gfx/angle/src/libGLESv2/ProgramBinary.cpp @@ -102,16 +102,22 @@ LinkedVarying::LinkedVarying() } LinkedVarying::LinkedVarying(const std::string &name, GLenum type, GLsizei size, const std::string &semanticName, unsigned int semanticIndex, unsigned int semanticIndexCount) : name(name), type(type), size(size), semanticName(semanticName), semanticIndex(semanticIndex), semanticIndexCount(semanticIndexCount) { } +LinkResult::LinkResult(bool linkSuccess, const Error &error) + : linkSuccess(linkSuccess), + error(error) +{ +} + unsigned int ProgramBinary::mCurrentSerial = 1; ProgramBinary::ProgramBinary(rx::ProgramImpl *impl) : RefCountObject(0), mProgram(impl), mUsedVertexSamplerRange(0), mUsedPixelSamplerRange(0), mDirtySamplerMapping(true), @@ -849,55 +855,55 @@ bool ProgramBinary::linkVaryings(InfoLog infoLog.append("Fragment varying %s does not match any vertex varying", input->name.c_str()); return false; } } return true; } -bool ProgramBinary::load(InfoLog &infoLog, GLenum binaryFormat, const void *binary, GLsizei length) +LinkResult ProgramBinary::load(InfoLog &infoLog, GLenum binaryFormat, const void *binary, GLsizei length) { #ifdef ANGLE_DISABLE_PROGRAM_BINARY_LOAD - return false; + return LinkResult(false, Error(GL_NO_ERROR)); #else ASSERT(binaryFormat == mProgram->getBinaryFormat()); reset(); BinaryInputStream stream(binary, length); GLenum format = stream.readInt<GLenum>(); if (format != mProgram->getBinaryFormat()) { infoLog.append("Invalid program binary format."); - return false; + return LinkResult(false, Error(GL_NO_ERROR)); } int majorVersion = stream.readInt<int>(); int minorVersion = stream.readInt<int>(); if (majorVersion != ANGLE_MAJOR_VERSION || minorVersion != ANGLE_MINOR_VERSION) { infoLog.append("Invalid program binary version."); - return false; + return LinkResult(false, Error(GL_NO_ERROR)); } unsigned char commitString[ANGLE_COMMIT_HASH_SIZE]; stream.readBytes(commitString, ANGLE_COMMIT_HASH_SIZE); if (memcmp(commitString, ANGLE_COMMIT_HASH, sizeof(unsigned char) * ANGLE_COMMIT_HASH_SIZE) != 0) { infoLog.append("Invalid program binary version."); - return false; + return LinkResult(false, Error(GL_NO_ERROR)); } int compileFlags = stream.readInt<int>(); if (compileFlags != ANGLE_COMPILE_OPTIMIZATION_LEVEL) { infoLog.append("Mismatched compilation flags."); - return false; + return LinkResult(false, Error(GL_NO_ERROR)); } for (int i = 0; i < MAX_VERTEX_ATTRIBS; ++i) { stream.readInt(&mLinkedAttribute[i].type); stream.readString(&mLinkedAttribute[i].name); stream.readInt(&mProgram->getShaderAttributes()[i].type); stream.readString(&mProgram->getShaderAttributes()[i].name); @@ -927,17 +933,17 @@ bool ProgramBinary::load(InfoLog &infoLo stream.readInt(&mUsedVertexSamplerRange); stream.readInt(&mUsedPixelSamplerRange); const unsigned int uniformCount = stream.readInt<unsigned int>(); if (stream.error()) { infoLog.append("Invalid program binary."); - return false; + return LinkResult(false, Error(GL_NO_ERROR)); } mUniforms.resize(uniformCount); for (unsigned int uniformIndex = 0; uniformIndex < uniformCount; uniformIndex++) { GLenum type = stream.readInt<GLenum>(); GLenum precision = stream.readInt<GLenum>(); std::string name = stream.readString(); @@ -960,17 +966,17 @@ bool ProgramBinary::load(InfoLog &infoLo mUniforms[uniformIndex] = uniform; } unsigned int uniformBlockCount = stream.readInt<unsigned int>(); if (stream.error()) { infoLog.append("Invalid program binary."); - return false; + return LinkResult(false, Error(GL_NO_ERROR)); } mUniformBlocks.resize(uniformBlockCount); for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < uniformBlockCount; ++uniformBlockIndex) { std::string name = stream.readString(); unsigned int elementIndex = stream.readInt<unsigned int>(); unsigned int dataSize = stream.readInt<unsigned int>(); @@ -989,39 +995,40 @@ bool ProgramBinary::load(InfoLog &infoLo mUniformBlocks[uniformBlockIndex] = uniformBlock; } const unsigned int uniformIndexCount = stream.readInt<unsigned int>(); if (stream.error()) { infoLog.append("Invalid program binary."); - return false; + return LinkResult(false, Error(GL_NO_ERROR)); } mUniformIndex.resize(uniformIndexCount); for (unsigned int uniformIndexIndex = 0; uniformIndexIndex < uniformIndexCount; uniformIndexIndex++) { stream.readString(&mUniformIndex[uniformIndexIndex].name); stream.readInt(&mUniformIndex[uniformIndexIndex].element); stream.readInt(&mUniformIndex[uniformIndexIndex].index); } - if (!mProgram->load(infoLog, &stream)) + LinkResult result = mProgram->load(infoLog, &stream); + if (result.error.isError() || !result.linkSuccess) { - return false; + return result; } mProgram->initializeUniformStorage(mUniforms); - return true; + return LinkResult(true, Error(GL_NO_ERROR)); #endif // #ifdef ANGLE_DISABLE_PROGRAM_BINARY_LOAD } -bool ProgramBinary::save(GLenum *binaryFormat, void *binary, GLsizei bufSize, GLsizei *length) +Error ProgramBinary::save(GLenum *binaryFormat, void *binary, GLsizei bufSize, GLsizei *length) { if (binaryFormat) { *binaryFormat = mProgram->getBinaryFormat(); } BinaryOutputStream stream; @@ -1103,37 +1110,32 @@ bool ProgramBinary::save(GLenum *binaryF stream.writeInt(mUniformIndex.size()); for (size_t i = 0; i < mUniformIndex.size(); ++i) { stream.writeString(mUniformIndex[i].name); stream.writeInt(mUniformIndex[i].element); stream.writeInt(mUniformIndex[i].index); } - if (!mProgram->save(&stream)) - { - if (length) - { - *length = 0; - } - - return false; - } + mProgram->save(&stream); GLsizei streamLength = stream.length(); const void *streamData = stream.data(); if (streamLength > bufSize) { if (length) { *length = 0; } - return false; + // TODO: This should be moved to the validation layer but computing the size of the binary before saving + // it causes the save to happen twice. It may be possible to write the binary to a separate buffer, validate + // sizes and then copy it. + return Error(GL_INVALID_OPERATION); } if (binary) { char *ptr = (char*) binary; memcpy(ptr, streamData, streamLength); ptr += streamLength; @@ -1141,109 +1143,105 @@ bool ProgramBinary::save(GLenum *binaryF ASSERT(ptr - streamLength == binary); } if (length) { *length = streamLength; } - return true; + return Error(GL_NO_ERROR); } GLint ProgramBinary::getLength() { GLint length; - if (save(NULL, NULL, INT_MAX, &length)) - { - return length; - } - else + Error error = save(NULL, NULL, INT_MAX, &length); + if (error.isError()) { return 0; } + + return length; } -bool ProgramBinary::link(InfoLog &infoLog, const AttributeBindings &attributeBindings, Shader *fragmentShader, Shader *vertexShader, - const std::vector<std::string>& transformFeedbackVaryings, GLenum transformFeedbackBufferMode, const Caps &caps) +LinkResult ProgramBinary::link(InfoLog &infoLog, const AttributeBindings &attributeBindings, Shader *fragmentShader, Shader *vertexShader, + const std::vector<std::string>& transformFeedbackVaryings, GLenum transformFeedbackBufferMode, const Caps &caps) { if (!fragmentShader || !fragmentShader->isCompiled()) { - return false; + return LinkResult(false, Error(GL_NO_ERROR)); } ASSERT(fragmentShader->getType() == GL_FRAGMENT_SHADER); if (!vertexShader || !vertexShader->isCompiled()) { - return false; + return LinkResult(false, Error(GL_NO_ERROR)); } ASSERT(vertexShader->getType() == GL_VERTEX_SHADER); reset(); mSamplersPS.resize(caps.maxTextureImageUnits); mSamplersVS.resize(caps.maxVertexTextureImageUnits); rx::ShaderD3D *vertexShaderD3D = rx::ShaderD3D::makeShaderD3D(vertexShader->getImplementation()); rx::ShaderD3D *fragmentShaderD3D = rx::ShaderD3D::makeShaderD3D(fragmentShader->getImplementation()); int registers; std::vector<LinkedVarying> linkedVaryings; - if (!mProgram->link(infoLog, fragmentShader, vertexShader, transformFeedbackVaryings, transformFeedbackBufferMode, - ®isters, &linkedVaryings, &mOutputVariables, caps)) + LinkResult result = mProgram->link(infoLog, fragmentShader, vertexShader, transformFeedbackVaryings, transformFeedbackBufferMode, + ®isters, &linkedVaryings, &mOutputVariables, caps); + if (result.error.isError() || !result.linkSuccess) { - return false; + return result; } - bool success = true; - if (!linkAttributes(infoLog, attributeBindings, vertexShader)) { - success = false; + return LinkResult(false, Error(GL_NO_ERROR)); } if (!linkUniforms(infoLog, *vertexShader, *fragmentShader, caps)) { - success = false; + return LinkResult(false, Error(GL_NO_ERROR)); } // special case for gl_DepthRange, the only built-in uniform (also a struct) if (vertexShaderD3D->usesDepthRange() || fragmentShaderD3D->usesDepthRange()) { const sh::BlockMemberInfo &defaultInfo = sh::BlockMemberInfo::getDefaultBlockInfo(); mUniforms.push_back(new LinkedUniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.near", 0, -1, defaultInfo)); mUniforms.push_back(new LinkedUniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.far", 0, -1, defaultInfo)); mUniforms.push_back(new LinkedUniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.diff", 0, -1, defaultInfo)); } if (!linkUniformBlocks(infoLog, *vertexShader, *fragmentShader, caps)) { - success = false; + return LinkResult(false, Error(GL_NO_ERROR)); } if (!gatherTransformFeedbackLinkedVaryings(infoLog, linkedVaryings, transformFeedbackVaryings, transformFeedbackBufferMode, &mProgram->getTransformFeedbackLinkedVaryings(), caps)) { - success = false; + return LinkResult(false, Error(GL_NO_ERROR)); } - if (success) + // TODO: The concept of "executables" is D3D only, and as such this belongs in ProgramD3D. It must be called, + // however, last in this function, so it can't simply be moved to ProgramD3D::link without further shuffling. + result = mProgram->compileProgramExecutables(infoLog, fragmentShader, vertexShader, registers); + if (result.error.isError() || !result.linkSuccess) { - // TODO: The concept of "executables" is D3D only, and as such this belongs in ProgramD3D. It must be called, - // however, last in this function, so it can't simply be moved to ProgramD3D::link without further shuffling. - if (!mProgram->compileProgramExecutables(infoLog, fragmentShader, vertexShader, registers)) - { - infoLog.append("Failed to create D3D shaders."); - success = false; - reset(); - } + infoLog.append("Failed to create D3D shaders."); + reset(); + return result; } - return success; + return LinkResult(true, Error(GL_NO_ERROR)); } // Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices bool ProgramBinary::linkAttributes(InfoLog &infoLog, const AttributeBindings &attributeBindings, const Shader *vertexShader) { const rx::ShaderD3D *vertexShaderD3D = rx::ShaderD3D::makeShaderD3D(vertexShader->getImplementation()); unsigned int usedLocations = 0;
--- a/gfx/angle/src/libGLESv2/ProgramBinary.h +++ b/gfx/angle/src/libGLESv2/ProgramBinary.h @@ -81,16 +81,24 @@ struct LinkedVarying GLsizei size; // DirectX semantic information std::string semanticName; unsigned int semanticIndex; unsigned int semanticIndexCount; }; +struct LinkResult +{ + bool linkSuccess; + Error error; + + LinkResult(bool linkSuccess, const Error &error); +}; + // This is the result of linking a program. It is the state that would be passed to ProgramBinary. class ProgramBinary : public RefCountObject { public: explicit ProgramBinary(rx::ProgramImpl *impl); ~ProgramBinary(); rx::ProgramImpl *getImplementation() { return mProgram; } @@ -133,22 +141,23 @@ class ProgramBinary : public RefCountObj void getUniformiv(GLint location, GLint *params); void getUniformuiv(GLint location, GLuint *params); void dirtyAllUniforms(); Error applyUniforms(); Error applyUniformBuffers(const std::vector<Buffer*> boundBuffers, const Caps &caps); - bool load(InfoLog &infoLog, GLenum binaryFormat, const void *binary, GLsizei length); - bool save(GLenum *binaryFormat, void *binary, GLsizei bufSize, GLsizei *length); + LinkResult load(InfoLog &infoLog, GLenum binaryFormat, const void *binary, GLsizei length); + Error save(GLenum *binaryFormat, void *binary, GLsizei bufSize, GLsizei *length); GLint getLength(); - bool link(InfoLog &infoLog, const AttributeBindings &attributeBindings, Shader *fragmentShader, Shader *vertexShader, - const std::vector<std::string>& transformFeedbackVaryings, GLenum transformFeedbackBufferMode, const Caps &caps); + LinkResult link(InfoLog &infoLog, const AttributeBindings &attributeBindings, Shader *fragmentShader, Shader *vertexShader, + const std::vector<std::string>& transformFeedbackVaryings, GLenum transformFeedbackBufferMode, + const Caps &caps); void getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders); void getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const; GLint getActiveAttributeCount() const; GLint getActiveAttributeMaxLength() const; void getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const; GLint getActiveUniformCount() const;
--- a/gfx/angle/src/libGLESv2/State.cpp +++ b/gfx/angle/src/libGLESv2/State.cpp @@ -17,26 +17,29 @@ #include "libGLESv2/renderer/RenderTarget.h" #include "libGLESv2/formatutils.h" namespace gl { State::State() { + mMaxDrawBuffers = 0; + mMaxCombinedTextureImageUnits = 0; } State::~State() { reset(); } void State::initialize(const Caps& caps, GLuint clientVersion) { - mContext = NULL; + mMaxDrawBuffers = caps.maxDrawBuffers; + mMaxCombinedTextureImageUnits = caps.maxCombinedTextureImageUnits; setClearColor(0.0f, 0.0f, 0.0f, 0.0f); mDepthClearValue = 1.0f; mStencilClearValue = 0; mRasterizer.rasterizerDiscard = false; mRasterizer.cullFace = false; @@ -106,21 +109,25 @@ void State::initialize(const Caps& caps, mBlend.colorMaskRed = true; mBlend.colorMaskGreen = true; mBlend.colorMaskBlue = true; mBlend.colorMaskAlpha = true; mActiveSampler = 0; const GLfloat defaultFloatValues[] = { 0.0f, 0.0f, 0.0f, 1.0f }; - for (int attribIndex = 0; attribIndex < MAX_VERTEX_ATTRIBS; attribIndex++) + mVertexAttribCurrentValues.resize(caps.maxVertexAttributes); + for (size_t attribIndex = 0; attribIndex < mVertexAttribCurrentValues.size(); ++attribIndex) { mVertexAttribCurrentValues[attribIndex].setFloatValues(defaultFloatValues); } + mUniformBuffers.resize(caps.maxCombinedUniformBlocks); + mTransformFeedbackBuffers.resize(caps.maxTransformFeedbackSeparateAttributes); + mSamplerTextures[GL_TEXTURE_2D].resize(caps.maxCombinedTextureImageUnits); mSamplerTextures[GL_TEXTURE_CUBE_MAP].resize(caps.maxCombinedTextureImageUnits); if (clientVersion >= 3) { // TODO: These could also be enabled via extension mSamplerTextures[GL_TEXTURE_2D_ARRAY].resize(caps.maxCombinedTextureImageUnits); mSamplerTextures[GL_TEXTURE_3D].resize(caps.maxCombinedTextureImageUnits); } @@ -148,42 +155,36 @@ void State::reset() textureVector[textureIdx].set(NULL); } } for (size_t samplerIdx = 0; samplerIdx < mSamplers.size(); samplerIdx++) { mSamplers[samplerIdx].set(NULL); } - const GLfloat defaultFloatValues[] = { 0.0f, 0.0f, 0.0f, 1.0f }; - for (int attribIndex = 0; attribIndex < MAX_VERTEX_ATTRIBS; attribIndex++) - { - mVertexAttribCurrentValues[attribIndex].setFloatValues(defaultFloatValues); - } - mArrayBuffer.set(NULL); mRenderbuffer.set(NULL); mTransformFeedback.set(NULL); for (State::ActiveQueryMap::iterator i = mActiveQueries.begin(); i != mActiveQueries.end(); i++) { i->second.set(NULL); } mGenericUniformBuffer.set(NULL); - for (int i = 0; i < IMPLEMENTATION_MAX_COMBINED_SHADER_UNIFORM_BUFFERS; i++) + mGenericTransformFeedbackBuffer.set(NULL); + for (BufferVector::iterator bufItr = mUniformBuffers.begin(); bufItr != mUniformBuffers.end(); ++bufItr) { - mUniformBuffers[i].set(NULL); + bufItr->set(NULL); } - mGenericTransformFeedbackBuffer.set(NULL); - for (int i = 0; i < IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS; i++) + for (BufferVector::iterator bufItr = mTransformFeedbackBuffers.begin(); bufItr != mTransformFeedbackBuffers.end(); ++bufItr) { - mTransformFeedbackBuffers[i].set(NULL); + bufItr->set(NULL); } mCopyReadBuffer.set(NULL); mCopyWriteBuffer.set(NULL); mPack.pixelBuffer.set(NULL); mUnpack.pixelBuffer.set(NULL); } @@ -942,59 +943,64 @@ void State::setGenericUniformBufferBindi void State::setIndexedUniformBufferBinding(GLuint index, Buffer *buffer, GLintptr offset, GLsizeiptr size) { mUniformBuffers[index].set(buffer, offset, size); } GLuint State::getIndexedUniformBufferId(GLuint index) const { - ASSERT(index < IMPLEMENTATION_MAX_COMBINED_SHADER_UNIFORM_BUFFERS); + ASSERT(static_cast<size_t>(index) < mUniformBuffers.size()); return mUniformBuffers[index].id(); } Buffer *State::getIndexedUniformBuffer(GLuint index) const { - ASSERT(index < IMPLEMENTATION_MAX_COMBINED_SHADER_UNIFORM_BUFFERS); + ASSERT(static_cast<size_t>(index) < mUniformBuffers.size()); return mUniformBuffers[index].get(); } void State::setGenericTransformFeedbackBufferBinding(Buffer *buffer) { mGenericTransformFeedbackBuffer.set(buffer); } void State::setIndexedTransformFeedbackBufferBinding(GLuint index, Buffer *buffer, GLintptr offset, GLsizeiptr size) { mTransformFeedbackBuffers[index].set(buffer, offset, size); } GLuint State::getIndexedTransformFeedbackBufferId(GLuint index) const { - ASSERT(index < IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS); + ASSERT(static_cast<size_t>(index) < mTransformFeedbackBuffers.size()); return mTransformFeedbackBuffers[index].id(); } Buffer *State::getIndexedTransformFeedbackBuffer(GLuint index) const { - ASSERT(index < IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS); + ASSERT(static_cast<size_t>(index) < mTransformFeedbackBuffers.size()); return mTransformFeedbackBuffers[index].get(); } GLuint State::getIndexedTransformFeedbackBufferOffset(GLuint index) const { - ASSERT(index < IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS); + ASSERT(static_cast<size_t>(index) < mTransformFeedbackBuffers.size()); return mTransformFeedbackBuffers[index].getOffset(); } +size_t State::getTransformFeedbackBufferIndexRange() const +{ + return mTransformFeedbackBuffers.size(); +} + void State::setCopyReadBufferBinding(Buffer *buffer) { mCopyReadBuffer.set(buffer); } void State::setCopyWriteBufferBinding(Buffer *buffer) { mCopyWriteBuffer.set(buffer); @@ -1028,54 +1034,49 @@ Buffer *State::getTargetBuffer(GLenum ta void State::setEnableVertexAttribArray(unsigned int attribNum, bool enabled) { getVertexArray()->enableAttribute(attribNum, enabled); } void State::setVertexAttribf(GLuint index, const GLfloat values[4]) { - ASSERT(index < gl::MAX_VERTEX_ATTRIBS); + ASSERT(static_cast<size_t>(index) < mVertexAttribCurrentValues.size()); mVertexAttribCurrentValues[index].setFloatValues(values); } void State::setVertexAttribu(GLuint index, const GLuint values[4]) { - ASSERT(index < gl::MAX_VERTEX_ATTRIBS); + ASSERT(static_cast<size_t>(index) < mVertexAttribCurrentValues.size()); mVertexAttribCurrentValues[index].setUnsignedIntValues(values); } void State::setVertexAttribi(GLuint index, const GLint values[4]) { - ASSERT(index < gl::MAX_VERTEX_ATTRIBS); + ASSERT(static_cast<size_t>(index) < mVertexAttribCurrentValues.size()); mVertexAttribCurrentValues[index].setIntValues(values); } void State::setVertexAttribState(unsigned int attribNum, Buffer *boundBuffer, GLint size, GLenum type, bool normalized, bool pureInteger, GLsizei stride, const void *pointer) { getVertexArray()->setAttributeState(attribNum, boundBuffer, size, type, normalized, pureInteger, stride, pointer); } const VertexAttribute &State::getVertexAttribState(unsigned int attribNum) const { return getVertexArray()->getVertexAttribute(attribNum); } const VertexAttribCurrentValueData &State::getVertexAttribCurrentValue(unsigned int attribNum) const { - ASSERT(attribNum < MAX_VERTEX_ATTRIBS); + ASSERT(static_cast<size_t>(attribNum) < mVertexAttribCurrentValues.size()); return mVertexAttribCurrentValues[attribNum]; } -const VertexAttribCurrentValueData *State::getVertexAttribCurrentValues() const -{ - return mVertexAttribCurrentValues; -} - const void *State::getVertexAttribPointer(unsigned int attribNum) const { return getVertexArray()->getVertexAttribute(attribNum).pointer; } void State::setPackAlignment(GLint alignment) { mPack.alignment = alignment; @@ -1180,17 +1181,17 @@ void State::getFloatv(GLenum pname, GLfl } } void State::getIntegerv(GLenum pname, GLint *params) { if (pname >= GL_DRAW_BUFFER0_EXT && pname <= GL_DRAW_BUFFER15_EXT) { unsigned int colorAttachment = (pname - GL_DRAW_BUFFER0_EXT); - ASSERT(colorAttachment < mContext->getCaps().maxDrawBuffers); + ASSERT(colorAttachment < mMaxDrawBuffers); Framebuffer *framebuffer = mDrawFramebuffer; *params = framebuffer->getDrawBufferState(colorAttachment); return; } // Please note: DEPTH_CLEAR_VALUE is not included in our internal getIntegerv implementation // because it is stored as a float, despite the fact that the GL ES 2.0 spec names // GetIntegerv as its native query function. As it would require conversion in any @@ -1327,29 +1328,29 @@ void State::getIntegerv(GLenum pname, GL } else { *params = 0; } } break; case GL_TEXTURE_BINDING_2D: - ASSERT(mActiveSampler < mContext->getCaps().maxCombinedTextureImageUnits); + ASSERT(mActiveSampler < mMaxCombinedTextureImageUnits); *params = mSamplerTextures.at(GL_TEXTURE_2D)[mActiveSampler].id(); break; case GL_TEXTURE_BINDING_CUBE_MAP: - ASSERT(mActiveSampler < mContext->getCaps().maxCombinedTextureImageUnits); + ASSERT(mActiveSampler < mMaxCombinedTextureImageUnits); *params = mSamplerTextures.at(GL_TEXTURE_CUBE_MAP)[mActiveSampler].id(); break; case GL_TEXTURE_BINDING_3D: - ASSERT(mActiveSampler <mContext->getCaps().maxCombinedTextureImageUnits); + ASSERT(mActiveSampler < mMaxCombinedTextureImageUnits); *params = mSamplerTextures.at(GL_TEXTURE_3D)[mActiveSampler].id(); break; case GL_TEXTURE_BINDING_2D_ARRAY: - ASSERT(mActiveSampler < mContext->getCaps().maxCombinedTextureImageUnits); + ASSERT(mActiveSampler < mMaxCombinedTextureImageUnits); *params = mSamplerTextures.at(GL_TEXTURE_2D_ARRAY)[mActiveSampler].id(); break; case GL_UNIFORM_BUFFER_BINDING: *params = mGenericUniformBuffer.id(); break; case GL_TRANSFORM_FEEDBACK_BUFFER_BINDING: *params = mGenericTransformFeedbackBuffer.id(); break; @@ -1371,76 +1372,76 @@ void State::getIntegerv(GLenum pname, GL } } bool State::getIndexedIntegerv(GLenum target, GLuint index, GLint *data) { switch (target) { case GL_TRANSFORM_FEEDBACK_BUFFER_BINDING: - if (index < IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS) + if (static_cast<size_t>(index) < mTransformFeedbackBuffers.size()) { *data = mTransformFeedbackBuffers[index].id(); } break; case GL_UNIFORM_BUFFER_BINDING: - if (index < IMPLEMENTATION_MAX_COMBINED_SHADER_UNIFORM_BUFFERS) + if (static_cast<size_t>(index) < mUniformBuffers.size()) { *data = mUniformBuffers[index].id(); } break; default: return false; } return true; } bool State::getIndexedInteger64v(GLenum target, GLuint index, GLint64 *data) { switch (target) { case GL_TRANSFORM_FEEDBACK_BUFFER_START: - if (index < IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS) + if (static_cast<size_t>(index) < mTransformFeedbackBuffers.size()) { *data = mTransformFeedbackBuffers[index].getOffset(); } break; case GL_TRANSFORM_FEEDBACK_BUFFER_SIZE: - if (index < IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS) + if (static_cast<size_t>(index) < mTransformFeedbackBuffers.size()) { *data = mTransformFeedbackBuffers[index].getSize(); } break; case GL_UNIFORM_BUFFER_START: - if (index < IMPLEMENTATION_MAX_COMBINED_SHADER_UNIFORM_BUFFERS) + if (static_cast<size_t>(index) < mUniformBuffers.size()) { *data = mUniformBuffers[index].getOffset(); } break; case GL_UNIFORM_BUFFER_SIZE: - if (index < IMPLEMENTATION_MAX_COMBINED_SHADER_UNIFORM_BUFFERS) + if (static_cast<size_t>(index) < mUniformBuffers.size()) { *data = mUniformBuffers[index].getSize(); } break; default: return false; } return true; } bool State::hasMappedBuffer(GLenum target) const { if (target == GL_ARRAY_BUFFER) { - for (unsigned int attribIndex = 0; attribIndex < gl::MAX_VERTEX_ATTRIBS; attribIndex++) + for (size_t attribIndex = 0; attribIndex < mVertexAttribCurrentValues.size(); attribIndex++) { - const gl::VertexAttribute &vertexAttrib = getVertexAttribState(attribIndex); + const gl::VertexAttribute &vertexAttrib = getVertexAttribState(static_cast<unsigned int>(attribIndex)); gl::Buffer *boundBuffer = vertexAttrib.buffer.get(); if (vertexAttrib.enabled && boundBuffer && boundBuffer->isMapped()) { return true; } } return false;
--- a/gfx/angle/src/libGLESv2/State.h +++ b/gfx/angle/src/libGLESv2/State.h @@ -30,18 +30,16 @@ class State { public: State(); ~State(); void initialize(const Caps& caps, GLuint clientVersion); void reset(); - void setContext(Context *context) { mContext = context; } - // State chunk getters const RasterizerState &getRasterizerState() const; const BlendState &getBlendState() const; const DepthStencilState &getDepthStencilState() const; // Clear behavior setters & state parameter block generation function void setClearColor(float red, float green, float blue, float alpha); void setClearDepth(float depth); @@ -194,16 +192,17 @@ class State Buffer *getIndexedUniformBuffer(GLuint index) const; // GL_TRANSFORM_FEEDBACK_BUFFER - Both indexed and generic targets void setGenericTransformFeedbackBufferBinding(Buffer *buffer); void setIndexedTransformFeedbackBufferBinding(GLuint index, Buffer *buffer, GLintptr offset, GLsizeiptr size); GLuint getIndexedTransformFeedbackBufferId(GLuint index) const; Buffer *getIndexedTransformFeedbackBuffer(GLuint index) const; GLuint getIndexedTransformFeedbackBufferOffset(GLuint index) const; + size_t getTransformFeedbackBufferIndexRange() const; // GL_COPY_[READ/WRITE]_BUFFER void setCopyReadBufferBinding(Buffer *buffer); void setCopyWriteBufferBinding(Buffer *buffer); // GL_PIXEL[PACK/UNPACK]_BUFFER void setPixelPackBufferBinding(Buffer *buffer); void setPixelUnpackBufferBinding(Buffer *buffer); @@ -215,17 +214,16 @@ class State void setEnableVertexAttribArray(unsigned int attribNum, bool enabled); void setVertexAttribf(GLuint index, const GLfloat values[4]); void setVertexAttribu(GLuint index, const GLuint values[4]); void setVertexAttribi(GLuint index, const GLint values[4]); void setVertexAttribState(unsigned int attribNum, Buffer *boundBuffer, GLint size, GLenum type, bool normalized, bool pureInteger, GLsizei stride, const void *pointer); const VertexAttribute &getVertexAttribState(unsigned int attribNum) const; const VertexAttribCurrentValueData &getVertexAttribCurrentValue(unsigned int attribNum) const; - const VertexAttribCurrentValueData *getVertexAttribCurrentValues() const; const void *getVertexAttribPointer(unsigned int attribNum) const; // Pixel pack state manipulation void setPackAlignment(GLint alignment); GLint getPackAlignment() const; void setPackReverseRowOrder(bool reverseRowOrder); bool getPackReverseRowOrder() const; const PixelPackState &getPackState() const; @@ -242,17 +240,19 @@ class State bool getIndexedIntegerv(GLenum target, GLuint index, GLint *data); bool getIndexedInteger64v(GLenum target, GLuint index, GLint64 *data); bool hasMappedBuffer(GLenum target) const; private: DISALLOW_COPY_AND_ASSIGN(State); - Context *mContext; + // Cached values from Context's caps + GLuint mMaxDrawBuffers; + GLuint mMaxCombinedTextureImageUnits; ColorF mColorClearValue; GLclampf mDepthClearValue; int mStencilClearValue; RasterizerState mRasterizer; bool mScissorTest; Rectangle mScissor; @@ -278,38 +278,40 @@ class State BindingPointer<Buffer> mArrayBuffer; Framebuffer *mReadFramebuffer; Framebuffer *mDrawFramebuffer; BindingPointer<Renderbuffer> mRenderbuffer; GLuint mCurrentProgramId; BindingPointer<ProgramBinary> mCurrentProgramBinary; - VertexAttribCurrentValueData mVertexAttribCurrentValues[MAX_VERTEX_ATTRIBS]; // From glVertexAttrib + typedef std::vector<VertexAttribCurrentValueData> VertexAttribVector; + VertexAttribVector mVertexAttribCurrentValues; // From glVertexAttrib VertexArray *mVertexArray; // Texture and sampler bindings size_t mActiveSampler; // Active texture unit selector - GL_TEXTURE0 typedef std::vector< BindingPointer<Texture> > TextureBindingVector; typedef std::map<GLenum, TextureBindingVector> TextureBindingMap; TextureBindingMap mSamplerTextures; typedef std::vector< BindingPointer<Sampler> > SamplerBindingVector; SamplerBindingVector mSamplers; typedef std::map< GLenum, BindingPointer<Query> > ActiveQueryMap; ActiveQueryMap mActiveQueries; BindingPointer<Buffer> mGenericUniformBuffer; - OffsetBindingPointer<Buffer> mUniformBuffers[IMPLEMENTATION_MAX_COMBINED_SHADER_UNIFORM_BUFFERS]; + typedef std::vector< OffsetBindingPointer<Buffer> > BufferVector; + BufferVector mUniformBuffers; BindingPointer<TransformFeedback> mTransformFeedback; BindingPointer<Buffer> mGenericTransformFeedbackBuffer; - OffsetBindingPointer<Buffer> mTransformFeedbackBuffers[IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS]; + BufferVector mTransformFeedbackBuffers; BindingPointer<Buffer> mCopyReadBuffer; BindingPointer<Buffer> mCopyWriteBuffer; PixelUnpackState mUnpack; PixelPackState mPack; };
--- a/gfx/angle/src/libGLESv2/angletypes.cpp +++ b/gfx/angle/src/libGLESv2/angletypes.cpp @@ -4,16 +4,18 @@ // found in the LICENSE file. // // angletypes.h : Defines a variety of structures and enum types that are used throughout libGLESv2 #include "libGLESv2/angletypes.h" #include "libGLESv2/ProgramBinary.h" #include "libGLESv2/VertexAttribute.h" +#include "libGLESv2/State.h" +#include "libGLESv2/VertexArray.h" namespace gl { SamplerState::SamplerState() : minFilter(GL_NEAREST_MIPMAP_LINEAR), magFilter(GL_LINEAR), wrapS(GL_REPEAT), @@ -143,26 +145,26 @@ VertexFormat::VertexFormat(const VertexA if (mType == GL_FLOAT || mType == GL_HALF_FLOAT || mType == GL_FIXED) { mNormalized = GL_FALSE; } } void VertexFormat::GetInputLayout(VertexFormat *inputLayout, ProgramBinary *programBinary, - const VertexAttribute *attributes, - const gl::VertexAttribCurrentValueData *currentValues) + const State &state) { + const VertexAttribute *vertexAttributes = state.getVertexArray()->getVertexAttributes(); for (unsigned int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++) { int semanticIndex = programBinary->getSemanticIndex(attributeIndex); if (semanticIndex != -1) { - inputLayout[semanticIndex] = VertexFormat(attributes[attributeIndex], currentValues[attributeIndex].Type); + inputLayout[semanticIndex] = VertexFormat(vertexAttributes[attributeIndex], state.getVertexAttribCurrentValue(attributeIndex).Type); } } } bool VertexFormat::operator==(const VertexFormat &other) const { return (mType == other.mType && mComponents == other.mComponents &&
--- a/gfx/angle/src/libGLESv2/angletypes.h +++ b/gfx/angle/src/libGLESv2/angletypes.h @@ -10,16 +10,17 @@ #define LIBGLESV2_ANGLETYPES_H_ #include "libGLESv2/Constants.h" #include "common/RefCountObject.h" namespace gl { class Buffer; +class State; class ProgramBinary; struct VertexAttribute; struct VertexAttribCurrentValueData; enum SamplerType { SAMPLER_PIXEL, SAMPLER_VERTEX @@ -224,18 +225,17 @@ struct VertexFormat VertexFormat(); VertexFormat(GLenum type, GLboolean normalized, GLuint components, bool pureInteger); explicit VertexFormat(const VertexAttribute &attribute); VertexFormat(const VertexAttribute &attribute, GLenum currentValueType); static void GetInputLayout(VertexFormat *inputLayout, ProgramBinary *programBinary, - const VertexAttribute *attributes, - const gl::VertexAttribCurrentValueData *currentValues); + const State& currentValues); bool operator==(const VertexFormat &other) const; bool operator!=(const VertexFormat &other) const; bool operator<(const VertexFormat& other) const; }; }
--- a/gfx/angle/src/libGLESv2/libGLESv2.cpp +++ b/gfx/angle/src/libGLESv2/libGLESv2.cpp @@ -3649,17 +3649,22 @@ void __stdcall glLinkProgram(GLuint prog } else { context->recordError(gl::Error(GL_INVALID_VALUE)); return; } } - context->linkProgram(program); + gl::Error error = context->linkProgram(program); + if (error.isError()) + { + context->recordError(error); + return; + } } } void __stdcall glPixelStorei(GLenum pname, GLint param) { EVENT("(GLenum pname = 0x%X, GLint param = %d)", pname, param); gl::Context *context = gl::getNonLostContext(); @@ -8397,19 +8402,20 @@ void __stdcall glGetProgramBinaryOES(GLu gl::ProgramBinary *programBinary = programObject->getProgramBinary(); if (!programBinary) { context->recordError(gl::Error(GL_INVALID_OPERATION)); return; } - if (!programBinary->save(binaryFormat, binary, bufSize, length)) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); + gl::Error error = programBinary->save(binaryFormat, binary, bufSize, length); + if (error.isError()) + { + context->recordError(error); return; } } } void __stdcall glProgramBinaryOES(GLuint program, GLenum binaryFormat, const void *binary, GLint length) { @@ -8428,17 +8434,22 @@ void __stdcall glProgramBinaryOES(GLuint gl::Program *programObject = context->getProgram(program); if (!programObject) { context->recordError(gl::Error(GL_INVALID_OPERATION)); return; } - context->setProgramBinary(program, binaryFormat, binary, length); + gl::Error error = context->setProgramBinary(program, binaryFormat, binary, length); + if (error.isError()) + { + context->recordError(error); + return; + } } } void __stdcall glDrawBuffersEXT(GLsizei n, const GLenum *bufs) { EVENT("(GLenum n = %d, bufs = 0x%0.8p)", n, bufs); gl::Context *context = gl::getNonLostContext();
--- a/gfx/angle/src/libGLESv2/renderer/Image.cpp +++ b/gfx/angle/src/libGLESv2/renderer/Image.cpp @@ -4,25 +4,41 @@ // found in the LICENSE file. // // Image.h: Implements the rx::Image class, an abstract base class for the // renderer-specific classes which will define the interface to the underlying // surfaces or resources. #include "libGLESv2/renderer/Image.h" +#include "libGLESv2/Framebuffer.h" +#include "libGLESv2/main.h" namespace rx { Image::Image() { mWidth = 0; mHeight = 0; mDepth = 0; mInternalFormat = GL_NONE; mActualFormat = GL_NONE; mTarget = GL_NONE; mRenderable = false; mDirty = false; } +void Image::copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectangle &area, gl::Framebuffer *source) +{ + gl::FramebufferAttachment *colorbuffer = source->getReadColorbuffer(); + + if (!colorbuffer) + { + return gl::error(GL_OUT_OF_MEMORY); + } + + RenderTarget *renderTarget = GetAttachmentRenderTarget(colorbuffer); + ASSERT(renderTarget); + copy(xoffset, yoffset, zoffset, area, renderTarget); } + +}
--- a/gfx/angle/src/libGLESv2/renderer/Image.h +++ b/gfx/angle/src/libGLESv2/renderer/Image.h @@ -14,22 +14,25 @@ #include "common/debug.h" #include "libGLESv2/Error.h" #include <GLES2/gl2.h> namespace gl { class Framebuffer; +struct Rectangle; +struct ImageIndex; } namespace rx { - class Renderer; +class RenderTarget; +class TextureStorage; class Image { public: Image(); virtual ~Image() {}; GLsizei getWidth() const { return mWidth; } @@ -46,17 +49,20 @@ class Image virtual bool redefine(Renderer *renderer, GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, bool forceRelease) = 0; virtual gl::Error loadData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLint unpackAlignment, GLenum type, const void *input) = 0; virtual gl::Error loadCompressedData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, const void *input) = 0; - virtual void copy(GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source) = 0; + void copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectangle &sourceArea, gl::Framebuffer *source); + virtual void copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectangle &sourceArea, RenderTarget *source) = 0; + virtual void copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectangle &sourceArea, + const gl::ImageIndex &sourceIndex, TextureStorage *source) = 0; protected: GLsizei mWidth; GLsizei mHeight; GLsizei mDepth; GLenum mInternalFormat; GLenum mActualFormat; bool mRenderable;
--- a/gfx/angle/src/libGLESv2/renderer/ProgramImpl.h +++ b/gfx/angle/src/libGLESv2/renderer/ProgramImpl.h @@ -27,26 +27,26 @@ public: virtual bool usesPointSize() const = 0; virtual int getShaderVersion() const = 0; virtual GLenum getTransformFeedbackBufferMode() const = 0; virtual std::vector<gl::LinkedVarying> &getTransformFeedbackLinkedVaryings() = 0; virtual sh::Attribute *getShaderAttributes() = 0; virtual GLenum getBinaryFormat() = 0; - virtual bool load(gl::InfoLog &infoLog, gl::BinaryInputStream *stream) = 0; - virtual bool save(gl::BinaryOutputStream *stream) = 0; + virtual gl::LinkResult load(gl::InfoLog &infoLog, gl::BinaryInputStream *stream) = 0; + virtual gl::Error save(gl::BinaryOutputStream *stream) = 0; - virtual bool compileProgramExecutables(gl::InfoLog &infoLog, gl::Shader *fragmentShader, gl::Shader *vertexShader, - int registers) = 0; + virtual gl::LinkResult compileProgramExecutables(gl::InfoLog &infoLog, gl::Shader *fragmentShader, gl::Shader *vertexShader, + int registers) = 0; - virtual bool link(gl::InfoLog &infoLog, gl::Shader *fragmentShader, gl::Shader *vertexShader, - const std::vector<std::string> &transformFeedbackVaryings, GLenum transformFeedbackBufferMode, - int *registers, std::vector<gl::LinkedVarying> *linkedVaryings, - std::map<int, gl::VariableLocation> *outputVariables, const gl::Caps &caps) = 0; + virtual gl::LinkResult link(gl::InfoLog &infoLog, gl::Shader *fragmentShader, gl::Shader *vertexShader, + const std::vector<std::string> &transformFeedbackVaryings, GLenum transformFeedbackBufferMode, + int *registers, std::vector<gl::LinkedVarying> *linkedVaryings, + std::map<int, gl::VariableLocation> *outputVariables, const gl::Caps &caps) = 0; virtual void initializeUniformStorage(const std::vector<gl::LinkedUniform*> &uniforms) = 0; virtual gl::Error applyUniforms(const std::vector<gl::LinkedUniform*> &uniforms) = 0; virtual gl::Error applyUniformBuffers(const std::vector<gl::UniformBlock*> uniformBlocks, const std::vector<gl::Buffer*> boundBuffers, const gl::Caps &caps) = 0; virtual bool assignUniformBlockRegister(gl::InfoLog &infoLog, gl::UniformBlock *uniformBlock, GLenum shader, unsigned int registerIndex, const gl::Caps &caps) = 0;
--- a/gfx/angle/src/libGLESv2/renderer/Renderer.h +++ b/gfx/angle/src/libGLESv2/renderer/Renderer.h @@ -127,20 +127,19 @@ class Renderer virtual void setViewport(const gl::Rectangle &viewport, float zNear, float zFar, GLenum drawMode, GLenum frontFace, bool ignoreViewport) = 0; virtual gl::Error applyRenderTarget(gl::Framebuffer *frameBuffer) = 0; virtual gl::Error applyShaders(gl::ProgramBinary *programBinary, const gl::VertexFormat inputLayout[], const gl::Framebuffer *framebuffer, bool rasterizerDiscard, bool transformFeedbackActive) = 0; virtual gl::Error applyUniforms(const ProgramImpl &program, const std::vector<gl::LinkedUniform*> &uniformArray) = 0; virtual bool applyPrimitiveType(GLenum primitiveType, GLsizei elementCount) = 0; - virtual gl::Error applyVertexBuffer(gl::ProgramBinary *programBinary, const gl::VertexAttribute vertexAttributes[], const gl::VertexAttribCurrentValueData currentValues[], - GLint first, GLsizei count, GLsizei instances) = 0; + virtual gl::Error applyVertexBuffer(const gl::State &state, GLint first, GLsizei count, GLsizei instances) = 0; virtual gl::Error applyIndexBuffer(const GLvoid *indices, gl::Buffer *elementArrayBuffer, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo) = 0; - virtual void applyTransformFeedbackBuffers(gl::Buffer *transformFeedbackBuffers[], GLintptr offsets[]) = 0; + virtual void applyTransformFeedbackBuffers(const gl::State& state) = 0; virtual gl::Error drawArrays(GLenum mode, GLsizei count, GLsizei instances, bool transformFeedbackActive) = 0; virtual gl::Error drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, gl::Buffer *elementArrayBuffer, const TranslatedIndexData &indexInfo, GLsizei instances) = 0; virtual gl::Error clear(const gl::ClearParameters &clearParams, gl::Framebuffer *frameBuffer) = 0; virtual void markAllStateDirty() = 0; @@ -192,22 +191,23 @@ class Renderer virtual RenderTarget *createRenderTarget(int width, int height, GLenum format, GLsizei samples) = 0; // Shader creation virtual ShaderImpl *createShader(GLenum type) = 0; virtual ProgramImpl *createProgram() = 0; // Shader operations virtual void releaseShaderCompiler() = 0; - virtual ShaderExecutable *loadExecutable(const void *function, size_t length, rx::ShaderType type, - const std::vector<gl::LinkedVarying> &transformFeedbackVaryings, - bool separatedOutputBuffers) = 0; - virtual ShaderExecutable *compileToExecutable(gl::InfoLog &infoLog, const std::string &shaderHLSL, rx::ShaderType type, - const std::vector<gl::LinkedVarying> &transformFeedbackVaryings, - bool separatedOutputBuffers, D3DWorkaroundType workaround) = 0; + virtual gl::Error loadExecutable(const void *function, size_t length, rx::ShaderType type, + const std::vector<gl::LinkedVarying> &transformFeedbackVaryings, + bool separatedOutputBuffers, ShaderExecutable **outExecutable) = 0; + virtual gl::Error compileToExecutable(gl::InfoLog &infoLog, const std::string &shaderHLSL, rx::ShaderType type, + const std::vector<gl::LinkedVarying> &transformFeedbackVaryings, + bool separatedOutputBuffers, D3DWorkaroundType workaround, + ShaderExecutable **outExectuable) = 0; virtual UniformStorage *createUniformStorage(size_t storageSize) = 0; // Image operations virtual Image *createImage() = 0; virtual void generateMipmap(Image *dest, Image *source) = 0; virtual TextureStorage *createTextureStorage2D(SwapChain *swapChain) = 0; virtual TextureStorage *createTextureStorage2D(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, int levels) = 0; virtual TextureStorage *createTextureStorageCube(GLenum internalformat, bool renderTarget, int size, int levels) = 0;
--- a/gfx/angle/src/libGLESv2/renderer/Workarounds.h +++ b/gfx/angle/src/libGLESv2/renderer/Workarounds.h @@ -21,17 +21,19 @@ enum D3DWorkaroundType ANGLE_D3D_WORKAROUND_NONE, ANGLE_D3D_WORKAROUND_SKIP_OPTIMIZATION, ANGLE_D3D_WORKAROUND_MAX_OPTIMIZATION }; struct Workarounds { Workarounds() - : mrtPerfWorkaround(false) + : mrtPerfWorkaround(false), + setDataFasterThanImageUpload(false) {} bool mrtPerfWorkaround; + bool setDataFasterThanImageUpload; }; } #endif // LIBGLESV2_RENDERER_WORKAROUNDS_H_
--- a/gfx/angle/src/libGLESv2/renderer/d3d/HLSLCompiler.cpp +++ b/gfx/angle/src/libGLESv2/renderer/d3d/HLSLCompiler.cpp @@ -77,18 +77,18 @@ void HLSLCompiler::release() if (mD3DCompilerModule) { FreeLibrary(mD3DCompilerModule); mD3DCompilerModule = NULL; mD3DCompileFunc = NULL; } } -ID3DBlob *HLSLCompiler::compileToBinary(gl::InfoLog &infoLog, const std::string &hlsl, const std::string &profile, - const std::vector<CompileConfig> &configs) const +gl::Error HLSLCompiler::compileToBinary(gl::InfoLog &infoLog, const std::string &hlsl, const std::string &profile, + const std::vector<CompileConfig> &configs, ID3DBlob **outCompiledBlob) const { ASSERT(mD3DCompilerModule && mD3DCompileFunc); if (gl::perfActive()) { std::string sourcePath = getTempPath(); std::string sourceText = FormatString("#line 2 \"%s\"\n\n%s", sourcePath.c_str(), hlsl.c_str()); writeFile(sourcePath.c_str(), sourceText.c_str(), sourceText.size()); @@ -110,30 +110,34 @@ ID3DBlob *HLSLCompiler::compileToBinary( TRACE("\n%s", hlsl); TRACE("\n%s", message); SafeRelease(errorMessage); } if (SUCCEEDED(result)) { - return binary; + *outCompiledBlob = binary; + return gl::Error(GL_NO_ERROR); } else { if (result == E_OUTOFMEMORY) { - return gl::error<ID3DBlob*>(GL_OUT_OF_MEMORY, NULL); + *outCompiledBlob = NULL; + return gl::Error(GL_OUT_OF_MEMORY, "HLSL compiler had an unexpected failure, result: 0x%X.", result); } infoLog.append("Warning: D3D shader compilation failed with %s flags.", configs[i].name.c_str()); if (i + 1 < configs.size()) { infoLog.append(" Retrying with %s.\n", configs[i + 1].name.c_str()); } } } - return NULL; + // None of the configurations succeeded in compiling this shader but the compiler is still intact + *outCompiledBlob = NULL; + return gl::Error(GL_NO_ERROR); } }
--- a/gfx/angle/src/libGLESv2/renderer/d3d/HLSLCompiler.h +++ b/gfx/angle/src/libGLESv2/renderer/d3d/HLSLCompiler.h @@ -1,11 +1,13 @@ #ifndef LIBGLESV2_RENDERER_HLSL_D3DCOMPILER_H_ #define LIBGLESV2_RENDERER_HLSL_D3DCOMPILER_H_ +#include "libGLESv2/Error.h" + #include "common/angleutils.h" #include "common/platform.h" #include <vector> #include <string> namespace gl { @@ -28,18 +30,20 @@ class HLSLCompiler { public: HLSLCompiler(); ~HLSLCompiler(); bool initialize(); void release(); - ID3DBlob *compileToBinary(gl::InfoLog &infoLog, const std::string &hlsl, const std::string &profile, - const std::vector<CompileConfig> &configs) const; + // Attempt to compile a HLSL shader using the supplied configurations, may output a NULL compiled blob + // even if no GL errors are returned. + gl::Error compileToBinary(gl::InfoLog &infoLog, const std::string &hlsl, const std::string &profile, + const std::vector<CompileConfig> &configs, ID3DBlob **outCompiledBlob) const; private: DISALLOW_COPY_AND_ASSIGN(HLSLCompiler); HMODULE mD3DCompilerModule; pD3DCompile mD3DCompileFunc; };
--- a/gfx/angle/src/libGLESv2/renderer/d3d/ImageD3D.h +++ b/gfx/angle/src/libGLESv2/renderer/d3d/ImageD3D.h @@ -12,16 +12,18 @@ #define LIBGLESV2_RENDERER_IMAGED3D_H_ #include "common/debug.h" #include "libGLESv2/renderer/Image.h" namespace gl { class Framebuffer; +struct ImageIndex; +struct Box; } namespace rx { class TextureStorage; class ImageD3D : public Image { @@ -32,20 +34,20 @@ class ImageD3D : public Image static ImageD3D *makeImageD3D(Image *img); virtual bool isDirty() const = 0; virtual void setManagedSurface2D(TextureStorage *storage, int level) {}; virtual void setManagedSurfaceCube(TextureStorage *storage, int face, int level) {}; virtual void setManagedSurface3D(TextureStorage *storage, int level) {}; virtual void setManagedSurface2DArray(TextureStorage *storage, int layer, int level) {}; - virtual gl::Error copyToStorage2D(TextureStorage *storage, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height) = 0; - virtual gl::Error copyToStorageCube(TextureStorage *storage, int face, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height) = 0; - virtual gl::Error copyToStorage3D(TextureStorage *storage, int level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth) = 0; - virtual gl::Error copyToStorage2DArray(TextureStorage *storage, int level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height) = 0; + virtual gl::Error copyToStorage2D(TextureStorage *storage, const gl::ImageIndex &index, const gl::Box ®ion) = 0; + virtual gl::Error copyToStorageCube(TextureStorage *storage, const gl::ImageIndex &index, const gl::Box ®ion) = 0; + virtual gl::Error copyToStorage3D(TextureStorage *storage, const gl::ImageIndex &index, const gl::Box ®ion) = 0; + virtual gl::Error copyToStorage2DArray(TextureStorage *storage, const gl::ImageIndex &index, const gl::Box ®ion) = 0; private: DISALLOW_COPY_AND_ASSIGN(ImageD3D); }; } #endif // LIBGLESV2_RENDERER_IMAGED3D_H_
--- a/gfx/angle/src/libGLESv2/renderer/d3d/ProgramD3D.cpp +++ b/gfx/angle/src/libGLESv2/renderer/d3d/ProgramD3D.cpp @@ -142,17 +142,17 @@ bool ProgramD3D::usesPointSpriteEmulatio return mUsesPointSize && mRenderer->getMajorShaderModel() >= 4; } bool ProgramD3D::usesGeometryShader() const { return usesPointSpriteEmulation(); } -bool ProgramD3D::load(gl::InfoLog &infoLog, gl::BinaryInputStream *stream) +gl::LinkResult ProgramD3D::load(gl::InfoLog &infoLog, gl::BinaryInputStream *stream) { stream->readInt(&mShaderVersion); stream->readInt(&mTransformFeedbackBufferMode); const unsigned int transformFeedbackVaryingCount = stream->readInt<unsigned int>(); mTransformFeedbackLinkedVaryings.resize(transformFeedbackVaryingCount); for (unsigned int varyingIndex = 0; varyingIndex < transformFeedbackVaryingCount; varyingIndex++) { @@ -196,24 +196,32 @@ bool ProgramD3D::load(gl::InfoLog &infoL stream->readInt(&vertexInput->mType); stream->readInt(&vertexInput->mNormalized); stream->readInt(&vertexInput->mComponents); stream->readBool(&vertexInput->mPureInteger); } unsigned int vertexShaderSize = stream->readInt<unsigned int>(); const unsigned char *vertexShaderFunction = binary + stream->offset(); - ShaderExecutable *shaderExecutable = mRenderer->loadExecutable(vertexShaderFunction, vertexShaderSize, - SHADER_VERTEX, - mTransformFeedbackLinkedVaryings, - (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS)); + + ShaderExecutable *shaderExecutable = NULL; + gl::Error error = mRenderer->loadExecutable(vertexShaderFunction, vertexShaderSize, + SHADER_VERTEX, + mTransformFeedbackLinkedVaryings, + (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS), + &shaderExecutable); + if (error.isError()) + { + return gl::LinkResult(false, error); + } + if (!shaderExecutable) { infoLog.append("Could not create vertex shader."); - return false; + return gl::LinkResult(false, gl::Error(GL_NO_ERROR)); } // generated converted input layout GLenum signature[gl::MAX_VERTEX_ATTRIBS]; getInputLayoutSignature(inputLayout, signature); // add new binary mVertexExecutables.push_back(new VertexExecutable(inputLayout, signature, shaderExecutable)); @@ -228,65 +236,74 @@ bool ProgramD3D::load(gl::InfoLog &infoL std::vector<GLenum> outputs(outputCount); for (size_t outputIndex = 0; outputIndex < outputCount; outputIndex++) { stream->readInt(&outputs[outputIndex]); } const size_t pixelShaderSize = stream->readInt<unsigned int>(); const unsigned char *pixelShaderFunction = binary + stream->offset(); - ShaderExecutable *shaderExecutable = mRenderer->loadExecutable(pixelShaderFunction, pixelShaderSize, - SHADER_PIXEL, - mTransformFeedbackLinkedVaryings, - (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS)); + ShaderExecutable *shaderExecutable = NULL; + gl::Error error = mRenderer->loadExecutable(pixelShaderFunction, pixelShaderSize, SHADER_PIXEL, + mTransformFeedbackLinkedVaryings, + (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS), + &shaderExecutable); + if (error.isError()) + { + return gl::LinkResult(false, error); + } if (!shaderExecutable) { infoLog.append("Could not create pixel shader."); - return false; + return gl::LinkResult(false, gl::Error(GL_NO_ERROR)); } // add new binary mPixelExecutables.push_back(new PixelExecutable(outputs, shaderExecutable)); stream->skip(pixelShaderSize); } unsigned int geometryShaderSize = stream->readInt<unsigned int>(); if (geometryShaderSize > 0) { const unsigned char *geometryShaderFunction = binary + stream->offset(); - mGeometryExecutable = mRenderer->loadExecutable(geometryShaderFunction, geometryShaderSize, - SHADER_GEOMETRY, - mTransformFeedbackLinkedVaryings, - (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS)); + gl::Error error = mRenderer->loadExecutable(geometryShaderFunction, geometryShaderSize, SHADER_GEOMETRY, + mTransformFeedbackLinkedVaryings, + (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS), + &mGeometryExecutable); + if (error.isError()) + { + return gl::LinkResult(false, error); + } if (!mGeometryExecutable) { infoLog.append("Could not create geometry shader."); - return false; + return gl::LinkResult(false, gl::Error(GL_NO_ERROR)); } stream->skip(geometryShaderSize); } GUID binaryIdentifier = {0}; stream->readBytes(reinterpret_cast<unsigned char*>(&binaryIdentifier), sizeof(GUID)); GUID identifier = mRenderer->getAdapterIdentifier(); if (memcmp(&identifier, &binaryIdentifier, sizeof(GUID)) != 0) { infoLog.append("Invalid program binary."); - return false; + return gl::LinkResult(false, gl::Error(GL_NO_ERROR)); } - return true; + return gl::LinkResult(true, gl::Error(GL_NO_ERROR)); } -bool ProgramD3D::save(gl::BinaryOutputStream *stream) +gl::Error ProgramD3D::save(gl::BinaryOutputStream *stream) { stream->writeInt(mShaderVersion); stream->writeInt(mTransformFeedbackBufferMode); stream->writeInt(mTransformFeedbackLinkedVaryings.size()); for (size_t i = 0; i < mTransformFeedbackLinkedVaryings.size(); i++) { const gl::LinkedVarying &varying = mTransformFeedbackLinkedVaryings[i]; @@ -362,22 +379,22 @@ bool ProgramD3D::save(gl::BinaryOutputSt if (mGeometryExecutable != NULL && geometryShaderSize > 0) { const uint8_t *geometryBlob = mGeometryExecutable->getFunction(); stream->writeBytes(geometryBlob, geometryShaderSize); } GUID binaryIdentifier = mRenderer->getAdapterIdentifier(); - stream->writeBytes(reinterpret_cast<unsigned char*>(&binaryIdentifier), sizeof(GUID)); + stream->writeBytes(reinterpret_cast<unsigned char*>(&binaryIdentifier), sizeof(GUID)); - return true; + return gl::Error(GL_NO_ERROR); } -ShaderExecutable *ProgramD3D::getPixelExecutableForFramebuffer(const gl::Framebuffer *fbo) +gl::Error ProgramD3D::getPixelExecutableForFramebuffer(const gl::Framebuffer *fbo, ShaderExecutable **outExecutable) { std::vector<GLenum> outputs; const gl::ColorbufferInfo &colorbuffers = fbo->getColorbuffersForRender(); for (size_t colorAttachment = 0; colorAttachment < colorbuffers.size(); ++colorAttachment) { const gl::FramebufferAttachment *colorbuffer = colorbuffers[colorAttachment]; @@ -387,120 +404,149 @@ ShaderExecutable *ProgramD3D::getPixelEx outputs.push_back(colorbuffer->getBinding() == GL_BACK ? GL_COLOR_ATTACHMENT0 : colorbuffer->getBinding()); } else { outputs.push_back(GL_NONE); } } - return getPixelExecutableForOutputLayout(outputs); + return getPixelExecutableForOutputLayout(outputs, outExecutable); } -ShaderExecutable *ProgramD3D::getPixelExecutableForOutputLayout(const std::vector<GLenum> &outputSignature) +gl::Error ProgramD3D::getPixelExecutableForOutputLayout(const std::vector<GLenum> &outputSignature, ShaderExecutable **outExectuable) { for (size_t executableIndex = 0; executableIndex < mPixelExecutables.size(); executableIndex++) { if (mPixelExecutables[executableIndex]->matchesSignature(outputSignature)) { - return mPixelExecutables[executableIndex]->shaderExecutable(); + *outExectuable = mPixelExecutables[executableIndex]->shaderExecutable(); + return gl::Error(GL_NO_ERROR); } } std::string finalPixelHLSL = mDynamicHLSL->generatePixelShaderForOutputSignature(mPixelHLSL, mPixelShaderKey, mUsesFragDepth, outputSignature); // Generate new pixel executable gl::InfoLog tempInfoLog; - ShaderExecutable *pixelExecutable = mRenderer->compileToExecutable(tempInfoLog, finalPixelHLSL, SHADER_PIXEL, - mTransformFeedbackLinkedVaryings, - (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS), - mPixelWorkarounds); + ShaderExecutable *pixelExecutable = NULL; + gl::Error error = mRenderer->compileToExecutable(tempInfoLog, finalPixelHLSL, SHADER_PIXEL, + mTransformFeedbackLinkedVaryings, + (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS), + mPixelWorkarounds, &pixelExecutable); + if (error.isError()) + { + return error; + } if (!pixelExecutable) { std::vector<char> tempCharBuffer(tempInfoLog.getLength() + 3); tempInfoLog.getLog(tempInfoLog.getLength(), NULL, &tempCharBuffer[0]); ERR("Error compiling dynamic pixel executable:\n%s\n", &tempCharBuffer[0]); } else { mPixelExecutables.push_back(new PixelExecutable(outputSignature, pixelExecutable)); } - return pixelExecutable; + *outExectuable = pixelExecutable; + return gl::Error(GL_NO_ERROR); } -ShaderExecutable *ProgramD3D::getVertexExecutableForInputLayout(const gl::VertexFormat inputLayout[gl::MAX_VERTEX_ATTRIBS]) +gl::Error ProgramD3D::getVertexExecutableForInputLayout(const gl::VertexFormat inputLayout[gl::MAX_VERTEX_ATTRIBS], ShaderExecutable **outExectuable) { GLenum signature[gl::MAX_VERTEX_ATTRIBS]; getInputLayoutSignature(inputLayout, signature); for (size_t executableIndex = 0; executableIndex < mVertexExecutables.size(); executableIndex++) { if (mVertexExecutables[executableIndex]->matchesSignature(signature)) { - return mVertexExecutables[executableIndex]->shaderExecutable(); + *outExectuable = mVertexExecutables[executableIndex]->shaderExecutable(); + return gl::Error(GL_NO_ERROR); } } // Generate new dynamic layout with attribute conversions std::string finalVertexHLSL = mDynamicHLSL->generateVertexShaderForInputLayout(mVertexHLSL, inputLayout, mShaderAttributes); // Generate new vertex executable gl::InfoLog tempInfoLog; - ShaderExecutable *vertexExecutable = mRenderer->compileToExecutable(tempInfoLog, finalVertexHLSL, - SHADER_VERTEX, - mTransformFeedbackLinkedVaryings, - (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS), - mVertexWorkarounds); + ShaderExecutable *vertexExecutable = NULL; + gl::Error error = mRenderer->compileToExecutable(tempInfoLog, finalVertexHLSL, SHADER_VERTEX, + mTransformFeedbackLinkedVaryings, + (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS), + mVertexWorkarounds, &vertexExecutable); + if (error.isError()) + { + return error; + } + if (!vertexExecutable) { std::vector<char> tempCharBuffer(tempInfoLog.getLength()+3); tempInfoLog.getLog(tempInfoLog.getLength(), NULL, &tempCharBuffer[0]); ERR("Error compiling dynamic vertex executable:\n%s\n", &tempCharBuffer[0]); } else { mVertexExecutables.push_back(new VertexExecutable(inputLayout, signature, vertexExecutable)); } - return vertexExecutable; + *outExectuable = vertexExecutable; + return gl::Error(GL_NO_ERROR); } -bool ProgramD3D::compileProgramExecutables(gl::InfoLog &infoLog, gl::Shader *fragmentShader, gl::Shader *vertexShader, - int registers) +gl::LinkResult ProgramD3D::compileProgramExecutables(gl::InfoLog &infoLog, gl::Shader *fragmentShader, gl::Shader *vertexShader, + int registers) { ShaderD3D *vertexShaderD3D = ShaderD3D::makeShaderD3D(vertexShader->getImplementation()); ShaderD3D *fragmentShaderD3D = ShaderD3D::makeShaderD3D(fragmentShader->getImplementation()); gl::VertexFormat defaultInputLayout[gl::MAX_VERTEX_ATTRIBS]; GetDefaultInputLayoutFromShader(vertexShader->getActiveAttributes(), defaultInputLayout); - ShaderExecutable *defaultVertexExecutable = getVertexExecutableForInputLayout(defaultInputLayout); + ShaderExecutable *defaultVertexExecutable = NULL; + gl::Error error = getVertexExecutableForInputLayout(defaultInputLayout, &defaultVertexExecutable); + if (error.isError()) + { + return gl::LinkResult(false, error); + } std::vector<GLenum> defaultPixelOutput = GetDefaultOutputLayoutFromShader(getPixelShaderKey()); - ShaderExecutable *defaultPixelExecutable = getPixelExecutableForOutputLayout(defaultPixelOutput); + ShaderExecutable *defaultPixelExecutable = NULL; + error = getPixelExecutableForOutputLayout(defaultPixelOutput, &defaultPixelExecutable); + if (error.isError()) + { + return gl::LinkResult(false, error); + } if (usesGeometryShader()) { std::string geometryHLSL = mDynamicHLSL->generateGeometryShaderHLSL(registers, fragmentShaderD3D, vertexShaderD3D); - mGeometryExecutable = mRenderer->compileToExecutable(infoLog, geometryHLSL, - SHADER_GEOMETRY, mTransformFeedbackLinkedVaryings, - (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS), - ANGLE_D3D_WORKAROUND_NONE); + + error = mRenderer->compileToExecutable(infoLog, geometryHLSL, SHADER_GEOMETRY, mTransformFeedbackLinkedVaryings, + (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS), + ANGLE_D3D_WORKAROUND_NONE, &mGeometryExecutable); + if (error.isError()) + { + return gl::LinkResult(false, error); + } } - return (defaultVertexExecutable && defaultPixelExecutable && (!usesGeometryShader() || mGeometryExecutable)); + bool linkSuccess = (defaultVertexExecutable && defaultPixelExecutable && (!usesGeometryShader() || mGeometryExecutable)); + return gl::LinkResult(linkSuccess, gl::Error(GL_NO_ERROR)); } -bool ProgramD3D::link(gl::InfoLog &infoLog, gl::Shader *fragmentShader, gl::Shader *vertexShader, - const std::vector<std::string> &transformFeedbackVaryings, GLenum transformFeedbackBufferMode, - int *registers, std::vector<gl::LinkedVarying> *linkedVaryings, - std::map<int, gl::VariableLocation> *outputVariables, const gl::Caps &caps) +gl::LinkResult ProgramD3D::link(gl::InfoLog &infoLog, gl::Shader *fragmentShader, gl::Shader *vertexShader, + const std::vector<std::string> &transformFeedbackVaryings, GLenum transformFeedbackBufferMode, + int *registers, std::vector<gl::LinkedVarying> *linkedVaryings, + std::map<int, gl::VariableLocation> *outputVariables, const gl::Caps &caps) { ShaderD3D *vertexShaderD3D = ShaderD3D::makeShaderD3D(vertexShader->getImplementation()); ShaderD3D *fragmentShaderD3D = ShaderD3D::makeShaderD3D(fragmentShader->getImplementation()); mTransformFeedbackBufferMode = transformFeedbackBufferMode; mPixelHLSL = fragmentShaderD3D->getTranslatedSource(); mPixelWorkarounds = fragmentShaderD3D->getD3DWorkarounds(); @@ -510,34 +556,34 @@ bool ProgramD3D::link(gl::InfoLog &infoL mShaderVersion = vertexShaderD3D->getShaderVersion(); // Map the varyings to the register file VaryingPacking packing = { NULL }; *registers = mDynamicHLSL->packVaryings(infoLog, packing, fragmentShaderD3D, vertexShaderD3D, transformFeedbackVaryings); if (*registers < 0) { - return false; + return gl::LinkResult(false, gl::Error(GL_NO_ERROR)); } if (!gl::ProgramBinary::linkVaryings(infoLog, fragmentShader, vertexShader)) { - return false; + return gl::LinkResult(false, gl::Error(GL_NO_ERROR)); } if (!mDynamicHLSL->generateShaderLinkHLSL(infoLog, *registers, packing, mPixelHLSL, mVertexHLSL, fragmentShaderD3D, vertexShaderD3D, transformFeedbackVaryings, linkedVaryings, outputVariables, &mPixelShaderKey, &mUsesFragDepth)) { - return false; + return gl::LinkResult(false, gl::Error(GL_NO_ERROR)); } mUsesPointSize = vertexShaderD3D->usesPointSize(); - return true; + return gl::LinkResult(true, gl::Error(GL_NO_ERROR)); } void ProgramD3D::getInputLayoutSignature(const gl::VertexFormat inputLayout[], GLenum signature[]) const { mDynamicHLSL->getInputLayoutSignature(inputLayout, signature); } void ProgramD3D::initializeUniformStorage(const std::vector<gl::LinkedUniform*> &uniforms)
--- a/gfx/angle/src/libGLESv2/renderer/d3d/ProgramD3D.h +++ b/gfx/angle/src/libGLESv2/renderer/d3d/ProgramD3D.h @@ -42,31 +42,31 @@ class ProgramD3D : public ProgramImpl std::vector<gl::LinkedVarying> &getTransformFeedbackLinkedVaryings() { return mTransformFeedbackLinkedVaryings; } sh::Attribute *getShaderAttributes() { return mShaderAttributes; } bool usesPointSize() const { return mUsesPointSize; } bool usesPointSpriteEmulation() const; bool usesGeometryShader() const; GLenum getBinaryFormat() { return GL_PROGRAM_BINARY_ANGLE; } - bool load(gl::InfoLog &infoLog, gl::BinaryInputStream *stream); - bool save(gl::BinaryOutputStream *stream); + gl::LinkResult load(gl::InfoLog &infoLog, gl::BinaryInputStream *stream); + gl::Error save(gl::BinaryOutputStream *stream); - ShaderExecutable *getPixelExecutableForFramebuffer(const gl::Framebuffer *fbo); - ShaderExecutable *getPixelExecutableForOutputLayout(const std::vector<GLenum> &outputLayout); - ShaderExecutable *getVertexExecutableForInputLayout(const gl::VertexFormat inputLayout[gl::MAX_VERTEX_ATTRIBS]); + gl::Error getPixelExecutableForFramebuffer(const gl::Framebuffer *fbo, ShaderExecutable **outExectuable); + gl::Error getPixelExecutableForOutputLayout(const std::vector<GLenum> &outputLayout, ShaderExecutable **outExectuable); + gl::Error getVertexExecutableForInputLayout(const gl::VertexFormat inputLayout[gl::MAX_VERTEX_ATTRIBS], ShaderExecutable **outExectuable); ShaderExecutable *getGeometryExecutable() const { return mGeometryExecutable; } - bool compileProgramExecutables(gl::InfoLog &infoLog, gl::Shader *fragmentShader, gl::Shader *vertexShader, - int registers); + gl::LinkResult compileProgramExecutables(gl::InfoLog &infoLog, gl::Shader *fragmentShader, gl::Shader *vertexShader, + int registers); - bool link(gl::InfoLog &infoLog, gl::Shader *fragmentShader, gl::Shader *vertexShader, - const std::vector<std::string> &transformFeedbackVaryings, GLenum transformFeedbackBufferMode, - int *registers, std::vector<gl::LinkedVarying> *linkedVaryings, - std::map<int, gl::VariableLocation> *outputVariables, const gl::Caps &caps); + gl::LinkResult link(gl::InfoLog &infoLog, gl::Shader *fragmentShader, gl::Shader *vertexShader, + const std::vector<std::string> &transformFeedbackVaryings, GLenum transformFeedbackBufferMode, + int *registers, std::vector<gl::LinkedVarying> *linkedVaryings, + std::map<int, gl::VariableLocation> *outputVariables, const gl::Caps &caps); void getInputLayoutSignature(const gl::VertexFormat inputLayout[], GLenum signature[]) const; void initializeUniformStorage(const std::vector<gl::LinkedUniform*> &uniforms); gl::Error applyUniforms(const std::vector<gl::LinkedUniform*> &uniforms); gl::Error applyUniformBuffers(const std::vector<gl::UniformBlock*> uniformBlocks, const std::vector<gl::Buffer*> boundBuffers, const gl::Caps &caps); bool assignUniformBlockRegister(gl::InfoLog &infoLog, gl::UniformBlock *uniformBlock, GLenum shader,
--- a/gfx/angle/src/libGLESv2/renderer/d3d/TextureD3D.cpp +++ b/gfx/angle/src/libGLESv2/renderer/d3d/TextureD3D.cpp @@ -85,81 +85,117 @@ GLint TextureD3D::getBaseLevelDepth() co // where in the base of 2D array textures and cube maps there are several. Don't use // the base level image for anything except querying texture format and size. GLenum TextureD3D::getBaseLevelInternalFormat() const { const Image *baseImage = getBaseLevelImage(); return (baseImage ? baseImage->getInternalFormat() : GL_NONE); } -gl::Error TextureD3D::setImage(const gl::PixelUnpackState &unpack, GLenum type, const void *pixels, Image *image) +gl::Error TextureD3D::setImage(const gl::PixelUnpackState &unpack, GLenum type, const void *pixels, const gl::ImageIndex &index) { + Image *image = getImage(index); + // No-op if (image->getWidth() == 0 || image->getHeight() == 0 || image->getDepth() == 0) { return gl::Error(GL_NO_ERROR); } // We no longer need the "GLenum format" parameter to TexImage to determine what data format "pixels" contains. // From our image internal format we know how many channels to expect, and "type" gives the format of pixel's components. - const void *pixelData = pixels; + const uint8_t *pixelData = NULL; if (unpack.pixelBuffer.id() != 0) { // Do a CPU readback here, if we have an unpack buffer bound and the fast GPU path is not supported gl::Buffer *pixelBuffer = unpack.pixelBuffer.get(); ptrdiff_t offset = reinterpret_cast<ptrdiff_t>(pixels); // TODO: setImage/subImage is the only place outside of renderer that asks for a buffers raw data. // This functionality should be moved into renderer and the getData method of BufferImpl removed. const void *bufferData = pixelBuffer->getImplementation()->getData(); - pixelData = static_cast<const unsigned char *>(bufferData) + offset; + pixelData = static_cast<const uint8_t *>(bufferData) + offset; + } + else + { + pixelData = static_cast<const uint8_t *>(pixels); } if (pixelData != NULL) { - gl::Error error = image->loadData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), unpack.alignment, type, pixelData); + gl::Error error(GL_NO_ERROR); + + gl::InternalFormat internalFormat = gl::GetInternalFormatInfo(image->getInternalFormat()); + + // TODO(jmadill): Handle compressed internal formats + if (mTexStorage && mRenderer->getWorkarounds().setDataFasterThanImageUpload && !internalFormat.compressed) + { + gl::Box sourceBox(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth()); + error = mTexStorage->setData(index, sourceBox, image->getInternalFormat(), type, unpack, pixelData); + } + else + { + error = image->loadData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), unpack.alignment, type, pixelData); + } + if (error.isError()) { return error; } mDirtyImages = true; } return gl::Error(GL_NO_ERROR); } gl::Error TextureD3D::subImage(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels, const gl::ImageIndex &index) { - const void *pixelData = pixels; + const uint8_t *pixelData = static_cast<const uint8_t *>(pixels); // CPU readback & copy where direct GPU copy is not supported if (unpack.pixelBuffer.id() != 0) { gl::Buffer *pixelBuffer = unpack.pixelBuffer.get(); uintptr_t offset = reinterpret_cast<uintptr_t>(pixels); // TODO: setImage/subImage is the only place outside of renderer that asks for a buffers raw data. // This functionality should be moved into renderer and the getData method of BufferImpl removed. const void *bufferData = pixelBuffer->getImplementation()->getData(); - pixelData = static_cast<const unsigned char *>(bufferData) + offset; + pixelData = static_cast<const uint8_t *>(bufferData)+offset; } if (pixelData != NULL) { Image *image = getImage(index); ASSERT(image); + gl::InternalFormat internalFormat = gl::GetInternalFormatInfo(image->getInternalFormat()); + gl::Box region(xoffset, yoffset, zoffset, width, height, depth); + + // TODO(jmadill): Handle compressed internal formats + if (mTexStorage && mRenderer->getWorkarounds().setDataFasterThanImageUpload && !internalFormat.compressed) + { + return mTexStorage->setData(index, region, image->getInternalFormat(), + type, unpack, pixelData); + } + gl::Error error = image->loadData(xoffset, yoffset, zoffset, width, height, depth, unpack.alignment, type, pixelData); if (error.isError()) { return error; } + error = commitRegion(index, region); + if (error.isError()) + { + return error; + } + mDirtyImages = true; } return gl::Error(GL_NO_ERROR); } gl::Error TextureD3D::setCompressedImage(GLsizei imageSize, const void *pixels, Image *image) { @@ -249,41 +285,67 @@ TextureStorage *TextureD3D::getStorage() Image *TextureD3D::getBaseLevelImage() const { return getImage(getImageIndex(0, 0)); } void TextureD3D::generateMipmaps() { - // Set up proper image sizes. + GLint mipCount = mipLevels(); + + if (mipCount == 1) + { + return; // no-op + } + + // Set up proper mipmap chain in our Image array. initMipmapsImages(); // We know that all layers have the same dimension, for the texture to be complete GLint layerCount = static_cast<GLint>(getLayerCount(0)); - GLint mipCount = mipLevels(); - - // The following will create and initialize the storage, or update it if it exists - TextureStorage *storage = getNativeTexture(); - - bool renderableStorage = (storage && storage->isRenderTarget()); + + // When making mipmaps with the setData workaround enabled, the texture storage has + // the image data already. For non-render-target storage, we have to pull it out into + // an image layer. + if (mRenderer->getWorkarounds().setDataFasterThanImageUpload && mTexStorage) + { + if (!mTexStorage->isRenderTarget()) + { + // Copy from the storage mip 0 to Image mip 0 + for (GLint layer = 0; layer < layerCount; ++layer) + { + gl::ImageIndex srcIndex = getImageIndex(0, layer); + + Image *image = getImage(srcIndex); + gl::Rectangle area(0, 0, image->getWidth(), image->getHeight()); + image->copy(0, 0, 0, area, srcIndex, mTexStorage); + } + } + else + { + updateStorage(); + } + } + + bool renderableStorage = (mTexStorage && mTexStorage->isRenderTarget()); for (GLint layer = 0; layer < layerCount; ++layer) { for (GLint mip = 1; mip < mipCount; ++mip) { ASSERT(getLayerCount(mip) == layerCount); gl::ImageIndex sourceIndex = getImageIndex(mip - 1, layer); gl::ImageIndex destIndex = getImageIndex(mip, layer); if (renderableStorage) { // GPU-side mipmapping - storage->generateMipmap(sourceIndex, destIndex); + mTexStorage->generateMipmap(sourceIndex, destIndex); } else { // CPU-side mipmapping mRenderer->generateMipmap(getImage(destIndex), getImage(sourceIndex)); } } } @@ -427,21 +489,21 @@ gl::Error TextureD3D_2D::setImage(GLenum ASSERT(target == GL_TEXTURE_2D && depth == 1); GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type); bool fastUnpacked = false; redefineImage(level, sizedInternalFormat, width, height); + gl::ImageIndex index = gl::ImageIndex::Make2D(level); + // Attempt a fast gpu copy of the pixel data to the surface if (isFastUnpackable(unpack, sizedInternalFormat) && isLevelComplete(level)) { - gl::ImageIndex index = gl::ImageIndex::Make2D(level); - // Will try to create RT storage if it does not exist RenderTarget *destRenderTarget = getRenderTarget(index); gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), 1); if (destRenderTarget) { gl::Error error = fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget); if (error.isError()) @@ -453,17 +515,17 @@ gl::Error TextureD3D_2D::setImage(GLenum mImageArray[level]->markClean(); fastUnpacked = true; } } if (!fastUnpacked) { - gl::Error error = TextureD3D::setImage(unpack, type, pixels, mImageArray[level]); + gl::Error error = TextureD3D::setImage(unpack, type, pixels, index); if (error.isError()) { return error; } } return gl::Error(GL_NO_ERROR); } @@ -484,20 +546,20 @@ gl::Error TextureD3D_2D::subImage(GLenum GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels) { ASSERT(target == GL_TEXTURE_2D && depth == 1 && zoffset == 0); bool fastUnpacked = false; gl::ImageIndex index = gl::ImageIndex::Make2D(level); + gl::Box destArea(xoffset, yoffset, 0, width, height, 1); if (isFastUnpackable(unpack, getInternalFormat(level)) && isLevelComplete(level)) { RenderTarget *renderTarget = getRenderTarget(index); - gl::Box destArea(xoffset, yoffset, 0, width, height, 1); if (renderTarget) { gl::Error error = fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, renderTarget); if (error.isError()) { return error; } @@ -506,29 +568,18 @@ gl::Error TextureD3D_2D::subImage(GLenum mImageArray[level]->markClean(); fastUnpacked = true; } } if (!fastUnpacked) { - gl::ImageIndex index = gl::ImageIndex::Make2D(level); - gl::Error error = TextureD3D::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, - pixels, index); - if (error.isError()) - { - return error; - } - - error = commitRect(level, xoffset, yoffset, width, height); - if (error.isError()) - { - return error; - } + return TextureD3D::subImage(xoffset, yoffset, 0, width, height, 1, format, type, + unpack, pixels, index); } return gl::Error(GL_NO_ERROR); } gl::Error TextureD3D_2D::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels) @@ -536,82 +587,70 @@ gl::Error TextureD3D_2D::subImageCompres ASSERT(target == GL_TEXTURE_2D && depth == 1 && zoffset == 0); gl::Error error = TextureD3D::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[level]); if (error.isError()) { return error; } - error = commitRect(level, xoffset, yoffset, width, height); - if (error.isError()) - { - return error; - } - - return gl::Error(GL_NO_ERROR); + gl::ImageIndex index = gl::ImageIndex::Make2D(level); + gl::Box region(xoffset, yoffset, 0, width, height, 1); + return commitRegion(index, region); } void TextureD3D_2D::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source) { ASSERT(target == GL_TEXTURE_2D); GLenum sizedInternalFormat = gl::GetSizedInternalFormat(format, GL_UNSIGNED_BYTE); redefineImage(level, sizedInternalFormat, width, height); + gl::Rectangle sourceRect(x, y, width, height); + if (!mImageArray[level]->isRenderableFormat()) { - mImageArray[level]->copy(0, 0, 0, x, y, width, height, source); + mImageArray[level]->copy(0, 0, 0, sourceRect, source); mDirtyImages = true; } else { ensureRenderTarget(); mImageArray[level]->markClean(); if (width != 0 && height != 0 && isValidLevel(level)) { - gl::Rectangle sourceRect; - sourceRect.x = x; - sourceRect.width = width; - sourceRect.y = y; - sourceRect.height = height; - mRenderer->copyImage2D(source, sourceRect, format, 0, 0, mTexStorage, level); } } } void TextureD3D_2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source) { ASSERT(target == GL_TEXTURE_2D && zoffset == 0); // can only make our texture storage to a render target if level 0 is defined (with a width & height) and // the current level we're copying to is defined (with appropriate format, width & height) bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0); + gl::Rectangle sourceRect(x, y, width, height); + if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget)) { - mImageArray[level]->copy(xoffset, yoffset, 0, x, y, width, height, source); + mImageArray[level]->copy(xoffset, yoffset, 0, sourceRect, source); mDirtyImages = true; } else { ensureRenderTarget(); if (isValidLevel(level)) { updateStorageLevel(level); - gl::Rectangle sourceRect; - sourceRect.x = x; - sourceRect.width = width; - sourceRect.y = y; - sourceRect.height = height; - mRenderer->copyImage2D(source, sourceRect, gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format, xoffset, yoffset, mTexStorage, level); } } } void TextureD3D_2D::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) @@ -816,17 +855,19 @@ void TextureD3D_2D::updateStorage() void TextureD3D_2D::updateStorageLevel(int level) { ASSERT(level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL); ASSERT(isLevelComplete(level)); if (mImageArray[level]->isDirty()) { - commitRect(level, 0, 0, getWidth(level), getHeight(level)); + gl::ImageIndex index = gl::ImageIndex::Make2D(level); + gl::Box region(0, 0, 0, getWidth(level), getHeight(level), 1); + commitRegion(index, region); } } void TextureD3D_2D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height) { // If there currently is a corresponding storage texture image, it has these parameters const int storageWidth = std::max(1, getBaseLevelWidth() >> level); const int storageHeight = std::max(1, getBaseLevelHeight() >> level); @@ -849,22 +890,25 @@ void TextureD3D_2D::redefineImage(GLint } SafeDelete(mTexStorage); mDirtyImages = true; } } } -gl::Error TextureD3D_2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height) +gl::Error TextureD3D_2D::commitRegion(const gl::ImageIndex &index, const gl::Box ®ion) { + ASSERT(!index.hasLayer()); + GLint level = index.mipIndex; + if (isValidLevel(level)) { ImageD3D *image = mImageArray[level]; - gl::Error error = image->copyToStorage2D(mTexStorage, level, xoffset, yoffset, width, height); + gl::Error error = image->copyToStorage2D(mTexStorage, index, region); if (error.isError()) { return error; } image->markClean(); } @@ -944,22 +988,22 @@ bool TextureD3D_Cube::isDepth(GLint leve } gl::Error TextureD3D_Cube::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels) { ASSERT(depth == 1); - int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target); GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type); - - redefineImage(faceIndex, level, sizedInternalFormat, width, height); - - return TextureD3D::setImage(unpack, type, pixels, mImageArray[faceIndex][level]); + gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level); + + redefineImage(index.layerIndex, level, sizedInternalFormat, width, height); + + return TextureD3D::setImage(unpack, type, pixels, index); } gl::Error TextureD3D_Cube::setCompressedImage(GLenum target, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels) { ASSERT(depth == 1); @@ -971,119 +1015,90 @@ gl::Error TextureD3D_Cube::setCompressed return TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[faceIndex][level]); } gl::Error TextureD3D_Cube::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels) { ASSERT(depth == 1 && zoffset == 0); - - int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target); - gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level); - gl::Error error = TextureD3D::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels, - index); - if (error.isError()) - { - return error; - } - - error = commitRect(faceIndex, level, xoffset, yoffset, width, height); - if (error.isError()) - { - return error; - } - - return gl::Error(GL_NO_ERROR); + return TextureD3D::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels, index); } gl::Error TextureD3D_Cube::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels) { ASSERT(depth == 1 && zoffset == 0); - int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target); - - gl::Error error = TextureD3D::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[faceIndex][level]); + gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level); + + gl::Error error = TextureD3D::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[index.layerIndex][level]); if (error.isError()) { return error; } - error = commitRect(faceIndex, level, xoffset, yoffset, width, height); - if (error.isError()) - { - return error; - } - - return gl::Error(GL_NO_ERROR); + gl::Box region(xoffset, yoffset, 0, width, height, 1); + return commitRegion(index, region); } void TextureD3D_Cube::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source) { int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target); GLenum sizedInternalFormat = gl::GetSizedInternalFormat(format, GL_UNSIGNED_BYTE); redefineImage(faceIndex, level, sizedInternalFormat, width, height); + gl::Rectangle sourceRect(x, y, width, height); + if (!mImageArray[faceIndex][level]->isRenderableFormat()) { - mImageArray[faceIndex][level]->copy(0, 0, 0, x, y, width, height, source); + mImageArray[faceIndex][level]->copy(0, 0, 0, sourceRect, source); mDirtyImages = true; } else { ensureRenderTarget(); mImageArray[faceIndex][level]->markClean(); ASSERT(width == height); if (width > 0 && isValidFaceLevel(faceIndex, level)) { - gl::Rectangle sourceRect; - sourceRect.x = x; - sourceRect.width = width; - sourceRect.y = y; - sourceRect.height = height; - mRenderer->copyImageCube(source, sourceRect, format, 0, 0, mTexStorage, target, level); } } } void TextureD3D_Cube::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source) { int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target); // We can only make our texture storage to a render target if the level we're copying *to* is complete // and the base level is cube-complete. The base level must be cube complete (common case) because we cannot // rely on the "getBaseLevel*" methods reliably otherwise. bool canCreateRenderTarget = isFaceLevelComplete(faceIndex, level) && isCubeComplete(); + gl::Rectangle sourceRect(x, y, width, height); + if (!mImageArray[faceIndex][level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget)) { - mImageArray[faceIndex][level]->copy(0, 0, 0, x, y, width, height, source); + mImageArray[faceIndex][level]->copy(0, 0, 0, sourceRect, source); mDirtyImages = true; } else { ensureRenderTarget(); if (isValidFaceLevel(faceIndex, level)) { updateStorageFaceLevel(faceIndex, level); - gl::Rectangle sourceRect; - sourceRect.x = x; - sourceRect.width = width; - sourceRect.y = y; - sourceRect.height = height; - mRenderer->copyImageCube(source, sourceRect, gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format, xoffset, yoffset, mTexStorage, target, level); } } } void TextureD3D_Cube::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) { @@ -1302,17 +1317,20 @@ bool TextureD3D_Cube::isFaceLevelComplet void TextureD3D_Cube::updateStorageFaceLevel(int faceIndex, int level) { ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL); ImageD3D *image = mImageArray[faceIndex][level]; if (image->isDirty()) { - commitRect(faceIndex, level, 0, 0, image->getWidth(), image->getHeight()); + GLenum faceTarget = gl::TextureCubeMap::layerIndexToTarget(faceIndex); + gl::ImageIndex index = gl::ImageIndex::MakeCube(faceTarget, level); + gl::Box region(0, 0, 0, image->getWidth(), image->getHeight(), 1); + commitRegion(index, region); } } void TextureD3D_Cube::redefineImage(int faceIndex, GLint level, GLenum internalformat, GLsizei width, GLsizei height) { // If there currently is a corresponding storage texture image, it has these parameters const int storageWidth = std::max(1, getBaseLevelWidth() >> level); const int storageHeight = std::max(1, getBaseLevelHeight() >> level); @@ -1339,22 +1357,27 @@ void TextureD3D_Cube::redefineImage(int SafeDelete(mTexStorage); mDirtyImages = true; } } } -gl::Error TextureD3D_Cube::commitRect(int faceIndex, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height) +gl::Error TextureD3D_Cube::commitRegion(const gl::ImageIndex &index, const gl::Box ®ion) { + ASSERT(index.hasLayer()); + + GLint level = index.mipIndex; + int faceIndex = static_cast<int>(index.layerIndex); + if (isValidFaceLevel(faceIndex, level)) { ImageD3D *image = mImageArray[faceIndex][level]; - gl::Error error = image->copyToStorageCube(mTexStorage, faceIndex, level, xoffset, yoffset, width, height); + gl::Error error = image->copyToStorageCube(mTexStorage, index, region); if (error.isError()) { return error; } image->markClean(); } @@ -1458,21 +1481,22 @@ gl::Error TextureD3D_3D::setImage(GLenum { ASSERT(target == GL_TEXTURE_3D); GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type); redefineImage(level, sizedInternalFormat, width, height, depth); bool fastUnpacked = false; + gl::ImageIndex index = gl::ImageIndex::Make3D(level); + // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer if (isFastUnpackable(unpack, sizedInternalFormat)) { // Will try to create RT storage if it does not exist - gl::ImageIndex index = gl::ImageIndex::Make3D(level); RenderTarget *destRenderTarget = getRenderTarget(index); gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), getDepth(level)); if (destRenderTarget) { gl::Error error = fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget); if (error.isError()) { @@ -1483,17 +1507,17 @@ gl::Error TextureD3D_3D::setImage(GLenum mImageArray[level]->markClean(); fastUnpacked = true; } } if (!fastUnpacked) { - gl::Error error = TextureD3D::setImage(unpack, type, pixels, mImageArray[level]); + gl::Error error = TextureD3D::setImage(unpack, type, pixels, index); if (error.isError()) { return error; } } return gl::Error(GL_NO_ERROR); } @@ -1519,48 +1543,37 @@ gl::Error TextureD3D_3D::subImage(GLenum bool fastUnpacked = false; gl::ImageIndex index = gl::ImageIndex::Make3D(level); // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer if (isFastUnpackable(unpack, getInternalFormat(level))) { RenderTarget *destRenderTarget = getRenderTarget(index); - gl::Box destArea(xoffset, yoffset, zoffset, width, height, depth); if (destRenderTarget) { + gl::Box destArea(xoffset, yoffset, zoffset, width, height, depth); gl::Error error = fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, destRenderTarget); if (error.isError()) { return error; } // Ensure we don't overwrite our newly initialized data mImageArray[level]->markClean(); fastUnpacked = true; } } if (!fastUnpacked) { - gl::ImageIndex index = gl::ImageIndex::Make3D(level); - gl::Error error = TextureD3D::subImage(xoffset, yoffset, zoffset, width, height, depth, format, type, unpack, - pixels, index); - if (error.isError()) - { - return error; - } - - error = commitRect(level, xoffset, yoffset, zoffset, width, height, depth); - if (error.isError()) - { - return error; - } + return TextureD3D::subImage(xoffset, yoffset, zoffset, width, height, depth, format, type, + unpack, pixels, index); } return gl::Error(GL_NO_ERROR); } gl::Error TextureD3D_3D::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels) @@ -1569,57 +1582,49 @@ gl::Error TextureD3D_3D::subImageCompres gl::Error error = TextureD3D::subImageCompressed(xoffset, yoffset, zoffset, width, height, depth, format, imageSize, pixels, mImageArray[level]); if (error.isError()) { return error; } - error = commitRect(level, xoffset, yoffset, zoffset, width, height, depth); - if (error.isError()) - { - return error; - } - - return gl::Error(GL_NO_ERROR); + gl::ImageIndex index = gl::ImageIndex::Make3D(level); + gl::Box region(xoffset, yoffset, zoffset, width, height, depth); + return commitRegion(index, region); } void TextureD3D_3D::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source) { UNIMPLEMENTED(); } void TextureD3D_3D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source) { ASSERT(target == GL_TEXTURE_3D); // can only make our texture storage to a render target if level 0 is defined (with a width & height) and // the current level we're copying to is defined (with appropriate format, width & height) bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0); + gl::Rectangle sourceRect(x, y, width, height); + if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget)) { - mImageArray[level]->copy(xoffset, yoffset, zoffset, x, y, width, height, source); + mImageArray[level]->copy(xoffset, yoffset, zoffset, sourceRect, source); mDirtyImages = true; } else { ensureRenderTarget(); if (isValidLevel(level)) { updateStorageLevel(level); - gl::Rectangle sourceRect; - sourceRect.x = x; - sourceRect.width = width; - sourceRect.y = y; - sourceRect.height = height; - mRenderer->copyImage3D(source, sourceRect, gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format, xoffset, yoffset, zoffset, mTexStorage, level); } } } void TextureD3D_3D::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) @@ -1811,17 +1816,19 @@ bool TextureD3D_3D::isLevelComplete(int void TextureD3D_3D::updateStorageLevel(int level) { ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL); ASSERT(isLevelComplete(level)); if (mImageArray[level]->isDirty()) { - commitRect(level, 0, 0, 0, getWidth(level), getHeight(level), getDepth(level)); + gl::ImageIndex index = gl::ImageIndex::Make3D(level); + gl::Box region(0, 0, 0, getWidth(level), getHeight(level), getDepth(level)); + commitRegion(index, region); } } void TextureD3D_3D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) { // If there currently is a corresponding storage texture image, it has these parameters const int storageWidth = std::max(1, getBaseLevelWidth() >> level); const int storageHeight = std::max(1, getBaseLevelHeight() >> level); @@ -1846,22 +1853,25 @@ void TextureD3D_3D::redefineImage(GLint } SafeDelete(mTexStorage); mDirtyImages = true; } } } -gl::Error TextureD3D_3D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth) +gl::Error TextureD3D_3D::commitRegion(const gl::ImageIndex &index, const gl::Box ®ion) { + ASSERT(!index.hasLayer()); + GLint level = index.mipIndex; + if (isValidLevel(level)) { ImageD3D *image = mImageArray[level]; - gl::Error error = image->copyToStorage3D(mTexStorage, level, xoffset, yoffset, zoffset, width, height, depth); + gl::Error error = image->copyToStorage3D(mTexStorage, index, region); if (error.isError()) { return error; } image->markClean(); } @@ -1951,17 +1961,18 @@ gl::Error TextureD3D_2DArray::setImage(G redefineImage(level, sizedInternalFormat, width, height, depth); const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(sizedInternalFormat); GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, width, height, unpack.alignment); for (int i = 0; i < depth; i++) { const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL; - gl::Error error = TextureD3D::setImage(unpack, type, layerPixels, mImageArray[level][i]); + gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, i); + gl::Error error = TextureD3D::setImage(unpack, type, layerPixels, index); if (error.isError()) { return error; } } return gl::Error(GL_NO_ERROR); } @@ -2001,24 +2012,18 @@ gl::Error TextureD3D_2DArray::subImage(G GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, width, height, unpack.alignment); for (int i = 0; i < depth; i++) { int layer = zoffset + i; const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL; gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer); - gl::Error error = TextureD3D::subImage(xoffset, yoffset, zoffset, width, height, 1, format, type, unpack, - layerPixels, index); - if (error.isError()) - { - return error; - } - - error = commitRect(level, xoffset, yoffset, layer, width, height); + gl::Error error = TextureD3D::subImage(xoffset, yoffset, zoffset, width, height, 1, format, type, + unpack, layerPixels, index); if (error.isError()) { return error; } } return gl::Error(GL_NO_ERROR); } @@ -2038,17 +2043,19 @@ gl::Error TextureD3D_2DArray::subImageCo const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL; gl::Error error = TextureD3D::subImageCompressed(xoffset, yoffset, zoffset, width, height, 1, format, imageSize, layerPixels, mImageArray[level][layer]); if (error.isError()) { return error; } - error = commitRect(level, xoffset, yoffset, layer, width, height); + gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer); + gl::Box region(xoffset, yoffset, 0, width, height, 1); + error = commitRegion(index, region); if (error.isError()) { return error; } } return gl::Error(GL_NO_ERROR); } @@ -2061,35 +2068,31 @@ void TextureD3D_2DArray::copyImage(GLenu void TextureD3D_2DArray::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source) { ASSERT(target == GL_TEXTURE_2D_ARRAY); // can only make our texture storage to a render target if level 0 is defined (with a width & height) and // the current level we're copying to is defined (with appropriate format, width & height) bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0); + gl::Rectangle sourceRect(x, y, width, height); + if (!mImageArray[level][0]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget)) { - mImageArray[level][zoffset]->copy(xoffset, yoffset, 0, x, y, width, height, source); + mImageArray[level][zoffset]->copy(xoffset, yoffset, 0, sourceRect, source); mDirtyImages = true; } else { ensureRenderTarget(); if (isValidLevel(level)) { updateStorageLevel(level); - gl::Rectangle sourceRect; - sourceRect.x = x; - sourceRect.width = width; - sourceRect.y = y; - sourceRect.height = height; - mRenderer->copyImage2DArray(source, sourceRect, gl::GetInternalFormatInfo(getInternalFormat(0)).format, xoffset, yoffset, zoffset, mTexStorage, level); } } } void TextureD3D_2DArray::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) { @@ -2285,17 +2288,19 @@ void TextureD3D_2DArray::updateStorageLe ASSERT(level >= 0 && level < (int)ArraySize(mLayerCounts)); ASSERT(isLevelComplete(level)); for (int layer = 0; layer < mLayerCounts[level]; layer++) { ASSERT(mImageArray[level] != NULL && mImageArray[level][layer] != NULL); if (mImageArray[level][layer]->isDirty()) { - commitRect(level, 0, 0, layer, getWidth(level), getHeight(level)); + gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer); + gl::Box region(0, 0, 0, getWidth(level), getHeight(level), 1); + commitRegion(index, region); } } } void TextureD3D_2DArray::deleteImages() { for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level) { @@ -2356,22 +2361,26 @@ void TextureD3D_2DArray::redefineImage(G delete mTexStorage; mTexStorage = NULL; mDirtyImages = true; } } } -gl::Error TextureD3D_2DArray::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint layerTarget, GLsizei width, GLsizei height) +gl::Error TextureD3D_2DArray::commitRegion(const gl::ImageIndex &index, const gl::Box ®ion) { + ASSERT(index.hasLayer()); + GLint level = index.mipIndex; + GLint layerTarget = index.layerIndex; + if (isValidLevel(level) && layerTarget < getLayerCount(level)) { ImageD3D *image = mImageArray[level][layerTarget]; - gl::Error error = image->copyToStorage2DArray(mTexStorage, level, xoffset, yoffset, layerTarget, width, height); + gl::Error error = image->copyToStorage2DArray(mTexStorage, index, region); if (error.isError()) { return error; } image->markClean(); }
--- a/gfx/angle/src/libGLESv2/renderer/d3d/TextureD3D.h +++ b/gfx/angle/src/libGLESv2/renderer/d3d/TextureD3D.h @@ -58,17 +58,17 @@ class TextureD3D : public TextureImpl // slices of their depth texures, so 3D textures ignore the layer parameter. virtual gl::ImageIndex getImageIndex(GLint mip, GLint layer) const = 0; virtual void generateMipmaps(); TextureStorage *getStorage(); Image *getBaseLevelImage() const; protected: - gl::Error setImage(const gl::PixelUnpackState &unpack, GLenum type, const void *pixels, Image *image); + gl::Error setImage(const gl::PixelUnpackState &unpack, GLenum type, const void *pixels, const gl::ImageIndex &index); gl::Error subImage(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels, const gl::ImageIndex &index); gl::Error setCompressedImage(GLsizei imageSize, const void *pixels, Image *image); gl::Error subImageCompressed(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels, Image *image); bool isFastUnpackable(const gl::PixelUnpackState &unpack, GLenum sizedInternalFormat); gl::Error fastUnpackPixels(const gl::PixelUnpackState &unpack, const void *pixels, const gl::Box &destArea, GLenum sizedInternalFormat, GLenum type, RenderTarget *destRenderTarget); @@ -77,16 +77,17 @@ class TextureD3D : public TextureImpl int mipLevels() const; virtual void initMipmapsImages() = 0; bool isBaseImageZeroSize() const; virtual bool ensureRenderTarget(); virtual TextureStorage *createCompleteStorage(bool renderTarget) const = 0; virtual void setCompleteTexStorage(TextureStorage *newCompleteTexStorage) = 0; + virtual gl::Error commitRegion(const gl::ImageIndex &index, const gl::Box ®ion) = 0; Renderer *mRenderer; GLenum mUsage; bool mDirtyImages; bool mImmutable; @@ -134,27 +135,27 @@ class TextureD3D_2D : public TextureD3D virtual gl::ImageIndex getImageIndex(GLint mip, GLint layer) const; private: DISALLOW_COPY_AND_ASSIGN(TextureD3D_2D); virtual void initializeStorage(bool renderTarget); virtual TextureStorage *createCompleteStorage(bool renderTarget) const; virtual void setCompleteTexStorage(TextureStorage *newCompleteTexStorage); + gl::Error commitRegion(const gl::ImageIndex &index, const gl::Box ®ion); virtual void updateStorage(); virtual void initMipmapsImages(); bool isValidLevel(int level) const; bool isLevelComplete(int level) const; void updateStorageLevel(int level); void redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height); - gl::Error commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height); ImageD3D *mImageArray[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; }; class TextureD3D_Cube : public TextureD3D { public: TextureD3D_Cube(Renderer *renderer); @@ -189,27 +190,27 @@ class TextureD3D_Cube : public TextureD3 virtual gl::ImageIndex getImageIndex(GLint mip, GLint layer) const; private: DISALLOW_COPY_AND_ASSIGN(TextureD3D_Cube); virtual void initializeStorage(bool renderTarget); virtual TextureStorage *createCompleteStorage(bool renderTarget) const; virtual void setCompleteTexStorage(TextureStorage *newCompleteTexStorage); + virtual gl::Error commitRegion(const gl::ImageIndex &index, const gl::Box ®ion); virtual void updateStorage(); virtual void initMipmapsImages(); bool isValidFaceLevel(int faceIndex, int level) const; bool isFaceLevelComplete(int faceIndex, int level) const; bool isCubeComplete() const; void updateStorageFaceLevel(int faceIndex, int level); void redefineImage(int faceIndex, GLint level, GLenum internalformat, GLsizei width, GLsizei height); - gl::Error commitRect(int faceIndex, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height); ImageD3D *mImageArray[6][gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; }; class TextureD3D_3D : public TextureD3D { public: TextureD3D_3D(Renderer *renderer); @@ -243,26 +244,26 @@ class TextureD3D_3D : public TextureD3D virtual gl::ImageIndex getImageIndex(GLint mip, GLint layer) const; private: DISALLOW_COPY_AND_ASSIGN(TextureD3D_3D); virtual void initializeStorage(bool renderTarget); virtual TextureStorage *createCompleteStorage(bool renderTarget) const; virtual void setCompleteTexStorage(TextureStorage *newCompleteTexStorage); + virtual gl::Error commitRegion(const gl::ImageIndex &index, const gl::Box ®ion); virtual void updateStorage(); virtual void initMipmapsImages(); bool isValidLevel(int level) const; bool isLevelComplete(int level) const; void updateStorageLevel(int level); void redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); - gl::Error commitRect(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth); ImageD3D *mImageArray[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; }; class TextureD3D_2DArray : public TextureD3D { public: TextureD3D_2DArray(Renderer *renderer); @@ -295,27 +296,27 @@ class TextureD3D_2DArray : public Textur virtual gl::ImageIndex getImageIndex(GLint mip, GLint layer) const; private: DISALLOW_COPY_AND_ASSIGN(TextureD3D_2DArray); virtual void initializeStorage(bool renderTarget); virtual TextureStorage *createCompleteStorage(bool renderTarget) const; virtual void setCompleteTexStorage(TextureStorage *newCompleteTexStorage); + virtual gl::Error commitRegion(const gl::ImageIndex &index, const gl::Box ®ion); virtual void updateStorage(); virtual void initMipmapsImages(); bool isValidLevel(int level) const; bool isLevelComplete(int level) const; void updateStorageLevel(int level); void deleteImages(); void redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); - gl::Error commitRect(GLint level, GLint xoffset, GLint yoffset, GLint layerTarget, GLsizei width, GLsizei height); // Storing images as an array of single depth textures since D3D11 treats each array level of a // Texture2D object as a separate subresource. Each layer would have to be looped over // to update all the texture layers since they cannot all be updated at once and it makes the most // sense for the Image class to not have to worry about layer subresource as well as mip subresources. GLsizei mLayerCounts[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; ImageD3D **mImageArray[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; };
--- a/gfx/angle/src/libGLESv2/renderer/d3d/TextureStorage.h +++ b/gfx/angle/src/libGLESv2/renderer/d3d/TextureStorage.h @@ -8,20 +8,23 @@ #ifndef LIBGLESV2_RENDERER_TEXTURESTORAGE_H_ #define LIBGLESV2_RENDERER_TEXTURESTORAGE_H_ #include "common/debug.h" #include "libGLESv2/Error.h" #include <GLES2/gl2.h> +#include <cstdint> namespace gl { struct ImageIndex; +struct Box; +struct PixelUnpackState; } namespace rx { class Renderer; class SwapChain; class RenderTarget; @@ -35,16 +38,18 @@ class TextureStorage virtual bool isRenderTarget() const = 0; virtual bool isManaged() const = 0; virtual int getLevelCount() const = 0; virtual RenderTarget *getRenderTarget(const gl::ImageIndex &index) = 0; virtual void generateMipmap(const gl::ImageIndex &sourceIndex, const gl::ImageIndex &destIndex) = 0; virtual gl::Error copyToStorage(TextureStorage *destStorage) = 0; + virtual gl::Error setData(const gl::ImageIndex &index, const gl::Box &sourceBox, GLenum internalFormat, GLenum type, + const gl::PixelUnpackState &unpack, const uint8_t *pixelData) = 0; unsigned int getRenderTargetSerial(const gl::ImageIndex &index) const; unsigned int getTextureSerial() const; protected: void initializeSerials(unsigned int rtSerialsToReserve, unsigned int rtSerialsLayerStride); private:
--- a/gfx/angle/src/libGLESv2/renderer/d3d/VertexDataManager.cpp +++ b/gfx/angle/src/libGLESv2/renderer/d3d/VertexDataManager.cpp @@ -9,16 +9,17 @@ #include "libGLESv2/renderer/d3d/VertexDataManager.h" #include "libGLESv2/renderer/d3d/BufferD3D.h" #include "libGLESv2/renderer/d3d/VertexBuffer.h" #include "libGLESv2/renderer/Renderer.h" #include "libGLESv2/Buffer.h" #include "libGLESv2/ProgramBinary.h" #include "libGLESv2/VertexAttribute.h" +#include "libGLESv2/State.h" namespace { enum { INITIAL_STREAM_BUFFER_SIZE = 1024*1024 }; // This has to be at least 4k or else it fails on ATI cards. enum { CONSTANT_VERTEX_BUFFER_SIZE = 4096 }; } @@ -77,90 +78,95 @@ VertexDataManager::~VertexDataManager() delete mStreamingBuffer; for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) { delete mCurrentValueBuffer[i]; } } -gl::Error VertexDataManager::prepareVertexData(const gl::VertexAttribute attribs[], const gl::VertexAttribCurrentValueData currentValues[], - gl::ProgramBinary *programBinary, GLint start, GLsizei count, TranslatedAttribute *translated, GLsizei instances) +gl::Error VertexDataManager::prepareVertexData(const gl::State &state, GLint start, GLsizei count, + TranslatedAttribute *translated, GLsizei instances) { if (!mStreamingBuffer) { return gl::Error(GL_OUT_OF_MEMORY, "Internal streaming vertex buffer is unexpectedly NULL."); } // Invalidate static buffers that don't contain matching attributes for (int attributeIndex = 0; attributeIndex < gl::MAX_VERTEX_ATTRIBS; attributeIndex++) { - translated[attributeIndex].active = (programBinary->getSemanticIndex(attributeIndex) != -1); + translated[attributeIndex].active = (state.getCurrentProgramBinary()->getSemanticIndex(attributeIndex) != -1); + const gl::VertexAttribute &curAttrib = state.getVertexAttribState(attributeIndex); - if (translated[attributeIndex].active && attribs[attributeIndex].enabled) + if (translated[attributeIndex].active && curAttrib.enabled) { - invalidateMatchingStaticData(attribs[attributeIndex], currentValues[attributeIndex]); + invalidateMatchingStaticData(curAttrib, state.getVertexAttribCurrentValue(attributeIndex)); } } // Reserve the required space in the buffers for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) { - if (translated[i].active && attribs[i].enabled) + const gl::VertexAttribute &curAttrib = state.getVertexAttribState(i); + if (translated[i].active && curAttrib.enabled) { - gl::Error error = reserveSpaceForAttrib(attribs[i], currentValues[i], count, instances); + gl::Error error = reserveSpaceForAttrib(curAttrib, state.getVertexAttribCurrentValue(i), count, instances); if (error.isError()) { return error; } } } // Perform the vertex data translations for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) { + const gl::VertexAttribute &curAttrib = state.getVertexAttribState(i); if (translated[i].active) { - if (attribs[i].enabled) + if (curAttrib.enabled) { - gl::Error error = storeAttribute(attribs[i], currentValues[i], &translated[i], - start, count, instances); + gl::Error error = storeAttribute(curAttrib, state.getVertexAttribCurrentValue(i), + &translated[i], start, count, instances); + if (error.isError()) { return error; } } else { if (!mCurrentValueBuffer[i]) { mCurrentValueBuffer[i] = new StreamingVertexBufferInterface(mRenderer, CONSTANT_VERTEX_BUFFER_SIZE); } - gl::Error error = storeCurrentValue(attribs[i], currentValues[i], &translated[i], + gl::Error error = storeCurrentValue(curAttrib, state.getVertexAttribCurrentValue(i), &translated[i], &mCurrentValue[i], &mCurrentValueOffsets[i], mCurrentValueBuffer[i]); if (error.isError()) { return error; } } } } for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) { - if (translated[i].active && attribs[i].enabled) + const gl::VertexAttribute &curAttrib = state.getVertexAttribState(i); + if (translated[i].active && curAttrib.enabled) { - gl::Buffer *buffer = attribs[i].buffer.get(); + gl::Buffer *buffer = curAttrib.buffer.get(); if (buffer) { BufferD3D *bufferImpl = BufferD3D::makeBufferD3D(buffer->getImplementation()); - bufferImpl->promoteStaticUsage(count * ComputeVertexAttributeTypeSize(attribs[i])); + bufferImpl->promoteStaticUsage(count * ComputeVertexAttributeTypeSize(curAttrib)); } } } return gl::Error(GL_NO_ERROR); } void VertexDataManager::invalidateMatchingStaticData(const gl::VertexAttribute &attrib,
--- a/gfx/angle/src/libGLESv2/renderer/d3d/VertexDataManager.h +++ b/gfx/angle/src/libGLESv2/renderer/d3d/VertexDataManager.h @@ -11,18 +11,19 @@ #define LIBGLESV2_RENDERER_VERTEXDATAMANAGER_H_ #include "libGLESv2/Constants.h" #include "libGLESv2/VertexAttribute.h" #include "common/angleutils.h" namespace gl { +class ProgramBinary; +class State; struct VertexAttribute; -class ProgramBinary; struct VertexAttribCurrentValueData; } namespace rx { class BufferD3D; class StreamingVertexBufferInterface; class VertexBuffer; @@ -47,18 +48,18 @@ struct TranslatedAttribute }; class VertexDataManager { public: VertexDataManager(rx::Renderer *renderer); virtual ~VertexDataManager(); - gl::Error prepareVertexData(const gl::VertexAttribute attribs[], const gl::VertexAttribCurrentValueData currentValues[], - gl::ProgramBinary *programBinary, GLint start, GLsizei count, TranslatedAttribute *outAttribs, GLsizei instances); + gl::Error prepareVertexData(const gl::State &state, GLint start, GLsizei count, + TranslatedAttribute *outAttribs, GLsizei instances); private: DISALLOW_COPY_AND_ASSIGN(VertexDataManager); gl::Error reserveSpaceForAttrib(const gl::VertexAttribute &attrib, const gl::VertexAttribCurrentValueData ¤tValue, GLsizei count, GLsizei instances) const;
--- a/gfx/angle/src/libGLESv2/renderer/d3d/d3d11/Image11.cpp +++ b/gfx/angle/src/libGLESv2/renderer/d3d/d3d11/Image11.cpp @@ -4,38 +4,40 @@ // found in the LICENSE file. // // Image11.h: Implements the rx::Image11 class, which acts as the interface to // the actual underlying resources of a Texture #include "libGLESv2/renderer/d3d/d3d11/Renderer11.h" #include "libGLESv2/renderer/d3d/d3d11/Image11.h" +#include "libGLESv2/renderer/d3d/d3d11/RenderTarget11.h" #include "libGLESv2/renderer/d3d/d3d11/TextureStorage11.h" #include "libGLESv2/renderer/d3d/d3d11/formatutils11.h" #include "libGLESv2/renderer/d3d/d3d11/renderer11_utils.h" #include "libGLESv2/Framebuffer.h" #include "libGLESv2/FramebufferAttachment.h" #include "libGLESv2/main.h" #include "common/utilities.h" namespace rx { Image11::Image11() + : mRenderer(NULL), + mDXGIFormat(DXGI_FORMAT_UNKNOWN), + mStagingTexture(NULL), + mStagingSubresource(0), + mRecoverFromStorage(false), + mAssociatedStorage(NULL), + mAssociatedImageIndex(gl::ImageIndex::MakeInvalid()), + mRecoveredFromStorageCount(0) + { - mStagingTexture = NULL; - mRenderer = NULL; - mDXGIFormat = DXGI_FORMAT_UNKNOWN; - mRecoverFromStorage = false; - mAssociatedStorage = NULL; - mAssociatedStorageLevel = 0; - mAssociatedStorageLayerTarget = 0; - mRecoveredFromStorageCount = 0; } Image11::~Image11() { disassociateStorage(); releaseStagingTexture(); } @@ -94,96 +96,96 @@ bool Image11::isDirty() const if (mDirty && !mStagingTexture && !mRecoverFromStorage && !(d3d11::GetTextureFormatInfo(mInternalFormat).dataInitializerFunction != NULL)) { return false; } return mDirty; } -gl::Error Image11::copyToStorage2D(TextureStorage *storage, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height) +gl::Error Image11::copyToStorage2D(TextureStorage *storage, const gl::ImageIndex &index, const gl::Box ®ion) { - TextureStorage11_2D *storage11 = TextureStorage11_2D::makeTextureStorage11_2D(storage); - return copyToStorageImpl(storage11, level, 0, xoffset, yoffset, width, height); + TextureStorage11 *storage11 = TextureStorage11::makeTextureStorage11(storage); + return copyToStorageImpl(storage11, index, region); } -gl::Error Image11::copyToStorageCube(TextureStorage *storage, int face, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height) +gl::Error Image11::copyToStorageCube(TextureStorage *storage, const gl::ImageIndex &index, const gl::Box ®ion) { - TextureStorage11_Cube *storage11 = TextureStorage11_Cube::makeTextureStorage11_Cube(storage); - return copyToStorageImpl(storage11, level, face, xoffset, yoffset, width, height); + TextureStorage11 *storage11 = TextureStorage11::makeTextureStorage11(storage); + return copyToStorageImpl(storage11, index, region); } -gl::Error Image11::copyToStorage3D(TextureStorage *storage, int level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth) +gl::Error Image11::copyToStorage3D(TextureStorage *storage, const gl::ImageIndex &index, const gl::Box ®ion) { - TextureStorage11_3D *storage11 = TextureStorage11_3D::makeTextureStorage11_3D(storage); - return copyToStorageImpl(storage11, level, 0, xoffset, yoffset, width, height); + TextureStorage11 *storage11 = TextureStorage11::makeTextureStorage11(storage); + return copyToStorageImpl(storage11, index, region); } -gl::Error Image11::copyToStorage2DArray(TextureStorage *storage, int level, GLint xoffset, GLint yoffset, GLint arrayLayer, GLsizei width, GLsizei height) +gl::Error Image11::copyToStorage2DArray(TextureStorage *storage, const gl::ImageIndex &index, const gl::Box ®ion) { - TextureStorage11_2DArray *storage11 = TextureStorage11_2DArray::makeTextureStorage11_2DArray(storage); - return copyToStorageImpl(storage11, level, arrayLayer, xoffset, yoffset, width, height); + TextureStorage11 *storage11 = TextureStorage11::makeTextureStorage11(storage); + return copyToStorageImpl(storage11, index, region); } -gl::Error Image11::copyToStorageImpl(TextureStorage11 *storage11, int level, int layerTarget, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height) +gl::Error Image11::copyToStorageImpl(TextureStorage11 *storage11, const gl::ImageIndex &index, const gl::Box ®ion) { // If an app's behavior results in an Image11 copying its data to/from to a TextureStorage multiple times, // then we should just keep the staging texture around to prevent the copying from impacting perf. // We allow the Image11 to copy its data to/from TextureStorage once. // This accounts for an app making a late call to glGenerateMipmap. bool attemptToReleaseStagingTexture = (mRecoveredFromStorageCount < 2); if (attemptToReleaseStagingTexture) { // If another image is relying on this Storage for its data, then we must let it recover its data before we overwrite it. - storage11->releaseAssociatedImage(level, layerTarget, this); + storage11->releaseAssociatedImage(index, this); } - gl::Error error = storage11->updateSubresourceLevel(getStagingTexture(), getStagingSubresource(), level, layerTarget, - xoffset, yoffset, 0, width, height, 1); + gl::Error error = storage11->updateSubresourceLevel(getStagingTexture(), getStagingSubresource(), + index, region); if (error.isError()) { return error; } // Once the image data has been copied into the Storage, we can release it locally. if (attemptToReleaseStagingTexture) { - storage11->associateImage(this, level, layerTarget); + storage11->associateImage(this, index); releaseStagingTexture(); mRecoverFromStorage = true; mAssociatedStorage = storage11; - mAssociatedStorageLevel = level; - mAssociatedStorageLayerTarget = layerTarget; + mAssociatedImageIndex = index; } return gl::Error(GL_NO_ERROR); } bool Image11::isAssociatedStorageValid(TextureStorage11* textureStorage) const { return (mAssociatedStorage == textureStorage); } bool Image11::recoverFromAssociatedStorage() { if (mRecoverFromStorage) { createStagingTexture(); - bool textureStorageCorrect = mAssociatedStorage->isAssociatedImageValid(mAssociatedStorageLevel, mAssociatedStorageLayerTarget, this); + bool textureStorageCorrect = mAssociatedStorage->isAssociatedImageValid(mAssociatedImageIndex, this); // This means that the cached TextureStorage has been modified after this Image11 released its copy of its data. // This should not have happened. The TextureStorage should have told this Image11 to recover its data before it was overwritten. ASSERT(textureStorageCorrect); if (textureStorageCorrect) { // CopySubResource from the Storage to the Staging texture - mAssociatedStorage->copySubresourceLevel(mStagingTexture, mStagingSubresource, mAssociatedStorageLevel, mAssociatedStorageLayerTarget, 0, 0, 0, mWidth, mHeight, mDepth); + gl::Box region(0, 0, 0, mWidth, mHeight, mDepth); + mAssociatedStorage->copySubresourceLevel(mStagingTexture, mStagingSubresource, mAssociatedImageIndex, region); mRecoveredFromStorageCount += 1; } // Reset all the recovery parameters, even if the texture storage association is broken. disassociateStorage(); return textureStorageCorrect; } @@ -191,22 +193,21 @@ bool Image11::recoverFromAssociatedStora return false; } void Image11::disassociateStorage() { if (mRecoverFromStorage) { // Make the texturestorage release the Image11 too - mAssociatedStorage->disassociateImage(mAssociatedStorageLevel, mAssociatedStorageLayerTarget, this); + mAssociatedStorage->disassociateImage(mAssociatedImageIndex, this); mRecoverFromStorage = false; mAssociatedStorage = NULL; - mAssociatedStorageLevel = 0; - mAssociatedStorageLayerTarget = 0; + mAssociatedImageIndex = gl::ImageIndex::MakeInvalid(); } } bool Image11::redefine(Renderer *renderer, GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, bool forceRelease) { if (mWidth != width || mHeight != height || mInternalFormat != internalformat || @@ -315,78 +316,110 @@ gl::Error Image11::loadCompressedData(GL reinterpret_cast<const uint8_t*>(input), inputRowPitch, inputDepthPitch, offsetMappedData, mappedImage.RowPitch, mappedImage.DepthPitch); unmap(); return gl::Error(GL_NO_ERROR); } -void Image11::copy(GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source) +void Image11::copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectangle &sourceArea, RenderTarget *source) +{ + RenderTarget11 *sourceRenderTarget = RenderTarget11::makeRenderTarget11(source); + ASSERT(sourceRenderTarget->getTexture()); + + UINT subresourceIndex = sourceRenderTarget->getSubresourceIndex(); + ID3D11Texture2D *sourceTexture2D = d3d11::DynamicCastComObject<ID3D11Texture2D>(sourceRenderTarget->getTexture()); + + if (!sourceTexture2D) + { + // Error already generated + return; + } + + copy(xoffset, yoffset, zoffset, sourceArea, sourceTexture2D, subresourceIndex); + + SafeRelease(sourceTexture2D); +} + +void Image11::copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectangle &sourceArea, const gl::ImageIndex &sourceIndex, TextureStorage *source) { - gl::FramebufferAttachment *colorbuffer = source->getReadColorbuffer(); + TextureStorage11 *sourceStorage11 = TextureStorage11::makeTextureStorage11(source); + + UINT subresourceIndex = sourceStorage11->getSubresourceIndex(sourceIndex); + ID3D11Texture2D *sourceTexture2D = d3d11::DynamicCastComObject<ID3D11Texture2D>(sourceStorage11->getResource()); + + if (!sourceTexture2D) + { + // Error already generated + return; + } - if (colorbuffer && colorbuffer->getActualFormat() == mActualFormat) + copy(xoffset, yoffset, zoffset, sourceArea, sourceTexture2D, subresourceIndex); + + SafeRelease(sourceTexture2D); +} + +void Image11::copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectangle &sourceArea, ID3D11Texture2D *source, UINT sourceSubResource) +{ + D3D11_TEXTURE2D_DESC textureDesc; + source->GetDesc(&textureDesc); + + if (textureDesc.Format == mDXGIFormat) { // No conversion needed-- use copyback fastpath - ID3D11Texture2D *colorBufferTexture = NULL; - unsigned int subresourceIndex = 0; + ID3D11Device *device = mRenderer->getDevice(); + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); - if (mRenderer->getRenderTargetResource(colorbuffer, &subresourceIndex, &colorBufferTexture)) + UINT subresourceAfterResolve = sourceSubResource; + + ID3D11Texture2D* srcTex = NULL; + if (textureDesc.SampleDesc.Count > 1) { - D3D11_TEXTURE2D_DESC textureDesc; - colorBufferTexture->GetDesc(&textureDesc); + D3D11_TEXTURE2D_DESC resolveDesc; + resolveDesc.Width = textureDesc.Width; + resolveDesc.Height = textureDesc.Height; + resolveDesc.MipLevels = 1; + resolveDesc.ArraySize = 1; + resolveDesc.Format = textureDesc.Format; + resolveDesc.SampleDesc.Count = 1; + resolveDesc.SampleDesc.Quality = 0; + resolveDesc.Usage = D3D11_USAGE_DEFAULT; + resolveDesc.BindFlags = 0; + resolveDesc.CPUAccessFlags = 0; + resolveDesc.MiscFlags = 0; - ID3D11Device *device = mRenderer->getDevice(); - ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); - - ID3D11Texture2D* srcTex = NULL; - if (textureDesc.SampleDesc.Count > 1) + HRESULT result = device->CreateTexture2D(&resolveDesc, NULL, &srcTex); + if (FAILED(result)) { - D3D11_TEXTURE2D_DESC resolveDesc; - resolveDesc.Width = textureDesc.Width; - resolveDesc.Height = textureDesc.Height; - resolveDesc.MipLevels = 1; - resolveDesc.ArraySize = 1; - resolveDesc.Format = textureDesc.Format; - resolveDesc.SampleDesc.Count = 1; - resolveDesc.SampleDesc.Quality = 0; - resolveDesc.Usage = D3D11_USAGE_DEFAULT; - resolveDesc.BindFlags = 0; - resolveDesc.CPUAccessFlags = 0; - resolveDesc.MiscFlags = 0; - - HRESULT result = device->CreateTexture2D(&resolveDesc, NULL, &srcTex); - if (FAILED(result)) - { - ERR("Failed to create resolve texture for Image11::copy, HRESULT: 0x%X.", result); - return; - } - - deviceContext->ResolveSubresource(srcTex, 0, colorBufferTexture, subresourceIndex, textureDesc.Format); - subresourceIndex = 0; - } - else - { - srcTex = colorBufferTexture; - srcTex->AddRef(); + ERR("Failed to create resolve texture for Image11::copy, HRESULT: 0x%X.", result); + return; } - D3D11_BOX srcBox; - srcBox.left = x; - srcBox.right = x + width; - srcBox.top = y; - srcBox.bottom = y + height; - srcBox.front = 0; - srcBox.back = 1; + deviceContext->ResolveSubresource(srcTex, 0, source, sourceSubResource, textureDesc.Format); + subresourceAfterResolve = 0; + } + else + { + srcTex = source; + } - deviceContext->CopySubresourceRegion(mStagingTexture, 0, xoffset, yoffset, zoffset, srcTex, subresourceIndex, &srcBox); + D3D11_BOX srcBox; + srcBox.left = sourceArea.x; + srcBox.right = sourceArea.x + sourceArea.width; + srcBox.top = sourceArea.y; + srcBox.bottom = sourceArea.y + sourceArea.height; + srcBox.front = 0; + srcBox.back = 1; + deviceContext->CopySubresourceRegion(getStagingTexture(), 0, xoffset, yoffset, zoffset, srcTex, subresourceAfterResolve, &srcBox); + + if (textureDesc.SampleDesc.Count > 1) + { SafeRelease(srcTex); - SafeRelease(colorBufferTexture); } } else { // This format requires conversion, so we must copy the texture to staging and manually convert via readPixels D3D11_MAPPED_SUBRESOURCE mappedImage; HRESULT result = map(D3D11_MAP_WRITE, &mappedImage); if (FAILED(result)) @@ -396,20 +429,22 @@ void Image11::copy(GLint xoffset, GLint } // determine the offset coordinate into the destination buffer GLsizei rowOffset = gl::GetInternalFormatInfo(mActualFormat).pixelBytes * xoffset; uint8_t *dataOffset = static_cast<uint8_t*>(mappedImage.pData) + mappedImage.RowPitch * yoffset + rowOffset + zoffset * mappedImage.DepthPitch; const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(mInternalFormat); - mRenderer->readPixels(source, x, y, width, height, formatInfo.format, formatInfo.type, mappedImage.RowPitch, gl::PixelPackState(), dataOffset); + mRenderer->readTextureData(source, sourceSubResource, sourceArea, formatInfo.format, formatInfo.type, mappedImage.RowPitch, gl::PixelPackState(), dataOffset); unmap(); } + + mDirty = true; } ID3D11Resource *Image11::getStagingTexture() { createStagingTexture(); return mStagingTexture; }
--- a/gfx/angle/src/libGLESv2/renderer/d3d/d3d11/Image11.h +++ b/gfx/angle/src/libGLESv2/renderer/d3d/d3d11/Image11.h @@ -6,16 +6,17 @@ // Image11.h: Defines the rx::Image11 class, which acts as the interface to // the actual underlying resources of a Texture #ifndef LIBGLESV2_RENDERER_IMAGE11_H_ #define LIBGLESV2_RENDERER_IMAGE11_H_ #include "libGLESv2/renderer/d3d/ImageD3D.h" +#include "libGLESv2/ImageIndex.h" #include "common/debug.h" namespace gl { class Framebuffer; } @@ -32,58 +33,60 @@ class Image11 : public ImageD3D virtual ~Image11(); static Image11 *makeImage11(Image *img); static void generateMipmap(Image11 *dest, Image11 *src); virtual bool isDirty() const; - virtual gl::Error copyToStorage2D(TextureStorage *storage, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height); - virtual gl::Error copyToStorageCube(TextureStorage *storage, int face, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height); - virtual gl::Error copyToStorage3D(TextureStorage *storage, int level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth); - virtual gl::Error copyToStorage2DArray(TextureStorage *storage, int level, GLint xoffset, GLint yoffset, GLint arrayLayer, GLsizei width, GLsizei height); + virtual gl::Error copyToStorage2D(TextureStorage *storage, const gl::ImageIndex &index, const gl::Box ®ion); + virtual gl::Error copyToStorageCube(TextureStorage *storage, const gl::ImageIndex &index, const gl::Box ®ion); + virtual gl::Error copyToStorage3D(TextureStorage *storage, const gl::ImageIndex &index, const gl::Box ®ion); + virtual gl::Error copyToStorage2DArray(TextureStorage *storage, const gl::ImageIndex &index, const gl::Box ®ion); virtual bool redefine(Renderer *renderer, GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, bool forceRelease); DXGI_FORMAT getDXGIFormat() const; virtual gl::Error loadData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLint unpackAlignment, GLenum type, const void *input); virtual gl::Error loadCompressedData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, const void *input); - virtual void copy(GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source); + virtual void copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectangle &sourceArea, RenderTarget *source); + virtual void copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectangle &sourceArea, + const gl::ImageIndex &sourceIndex, TextureStorage *source); bool recoverFromAssociatedStorage(); bool isAssociatedStorageValid(TextureStorage11* textureStorage) const; void disassociateStorage(); protected: HRESULT map(D3D11_MAP mapType, D3D11_MAPPED_SUBRESOURCE *map); void unmap(); private: DISALLOW_COPY_AND_ASSIGN(Image11); - gl::Error copyToStorageImpl(TextureStorage11 *storage11, int level, int layerTarget, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height); + gl::Error copyToStorageImpl(TextureStorage11 *storage11, const gl::ImageIndex &index, const gl::Box ®ion); + void copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectangle &sourceArea, ID3D11Texture2D *source, UINT sourceSubResource); ID3D11Resource *getStagingTexture(); unsigned int getStagingSubresource(); void createStagingTexture(); void releaseStagingTexture(); Renderer11 *mRenderer; DXGI_FORMAT mDXGIFormat; ID3D11Resource *mStagingTexture; unsigned int mStagingSubresource; bool mRecoverFromStorage; TextureStorage11 *mAssociatedStorage; - int mAssociatedStorageLevel; - int mAssociatedStorageLayerTarget; + gl::ImageIndex mAssociatedImageIndex; unsigned int mRecoveredFromStorageCount; }; } #endif // LIBGLESV2_RENDERER_IMAGE11_H_
--- a/gfx/angle/src/libGLESv2/renderer/d3d/d3d11/InputLayoutCache.cpp +++ b/gfx/angle/src/libGLESv2/renderer/d3d/d3d11/InputLayoutCache.cpp @@ -134,25 +134,33 @@ gl::Error InputLayoutCache::applyVertexB inputLayout = keyIter->second.inputLayout; keyIter->second.lastUsedTime = mCounter++; } else { gl::VertexFormat shaderInputLayout[gl::MAX_VERTEX_ATTRIBS]; GetInputLayout(attributes, shaderInputLayout); ProgramD3D *programD3D = ProgramD3D::makeProgramD3D(programBinary->getImplementation()); - ShaderExecutable11 *shader = ShaderExecutable11::makeShaderExecutable11(programD3D->getVertexExecutableForInputLayout(shaderInputLayout)); + + ShaderExecutable *shader = NULL; + gl::Error error = programD3D->getVertexExecutableForInputLayout(shaderInputLayout, &shader); + if (error.isError()) + { + return error; + } + + ShaderExecutable *shader11 = ShaderExecutable11::makeShaderExecutable11(shader); D3D11_INPUT_ELEMENT_DESC descs[gl::MAX_VERTEX_ATTRIBS]; for (unsigned int j = 0; j < ilKey.elementCount; ++j) { descs[j] = ilKey.elements[j].desc; } - HRESULT result = mDevice->CreateInputLayout(descs, ilKey.elementCount, shader->getFunction(), shader->getLength(), &inputLayout); + HRESULT result = mDevice->CreateInputLayout(descs, ilKey.elementCount, shader11->getFunction(), shader11->getLength(), &inputLayout); if (FAILED(result)) { return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal input layout, HRESULT: 0x%08x", result); } if (mInputLayoutMap.size() >= kMaxInputLayouts) { TRACE("Overflowed the limit of %u input layouts, removing the least recently used "
--- a/gfx/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.cpp +++ b/gfx/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.cpp @@ -6,16 +6,17 @@ // Renderer11.cpp: Implements a back-end specific class for the D3D11 renderer. #include "libGLESv2/main.h" #include "libGLESv2/Buffer.h" #include "libGLESv2/FramebufferAttachment.h" #include "libGLESv2/ProgramBinary.h" #include "libGLESv2/Framebuffer.h" +#include "libGLESv2/State.h" #include "libGLESv2/renderer/d3d/ProgramD3D.h" #include "libGLESv2/renderer/d3d/ShaderD3D.h" #include "libGLESv2/renderer/d3d/TextureD3D.h" #include "libGLESv2/renderer/d3d/TransformFeedbackD3D.h" #include "libGLESv2/renderer/d3d/d3d11/Renderer11.h" #include "libGLESv2/renderer/d3d/d3d11/RenderTarget11.h" #include "libGLESv2/renderer/d3d/d3d11/renderer11_utils.h" #include "libGLESv2/renderer/d3d/d3d11/formatutils11.h" @@ -934,27 +935,26 @@ gl::Error Renderer11::applyRenderTarget( mDepthStencilInitialized = true; } invalidateFramebufferSwizzles(framebuffer); return gl::Error(GL_NO_ERROR); } -gl::Error Renderer11::applyVertexBuffer(gl::ProgramBinary *programBinary, const gl::VertexAttribute vertexAttributes[], const gl::VertexAttribCurrentValueData currentValues[], - GLint first, GLsizei count, GLsizei instances) +gl::Error Renderer11::applyVertexBuffer(const gl::State &state, GLint first, GLsizei count, GLsizei instances) { TranslatedAttribute attributes[gl::MAX_VERTEX_ATTRIBS]; - gl::Error error = mVertexDataManager->prepareVertexData(vertexAttributes, currentValues, programBinary, first, count, attributes, instances); + gl::Error error = mVertexDataManager->prepareVertexData(state, first, count, attributes, instances); if (error.isError()) { return error; } - return mInputLayoutCache.applyVertexBuffers(attributes, programBinary); + return mInputLayoutCache.applyVertexBuffers(attributes, state.getCurrentProgramBinary()); } gl::Error Renderer11::applyIndexBuffer(const GLvoid *indices, gl::Buffer *elementArrayBuffer, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo) { gl::Error error = mIndexDataManager->prepareIndexData(type, count, elementArrayBuffer, indices, indexInfo); if (error.isError()) { return error; @@ -981,51 +981,65 @@ gl::Error Renderer11::applyIndexBuffer(c mAppliedIB = buffer; mAppliedIBFormat = bufferFormat; mAppliedIBOffset = indexInfo->startOffset; } return gl::Error(GL_NO_ERROR); } -void Renderer11::applyTransformFeedbackBuffers(gl::Buffer *transformFeedbackBuffers[], GLintptr offsets[]) +void Renderer11::applyTransformFeedbackBuffers(const gl::State& state) { - ID3D11Buffer* d3dBuffers[gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS]; - UINT d3dOffsets[gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS]; + size_t numXFBBindings = state.getTransformFeedbackBufferIndexRange(); + ASSERT(numXFBBindings <= gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS); + bool requiresUpdate = false; - for (size_t i = 0; i < gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS; i++) + for (size_t i = 0; i < numXFBBindings; i++) { - if (transformFeedbackBuffers[i]) + gl::Buffer *curXFBBuffer = state.getIndexedTransformFeedbackBuffer(i); + GLintptr curXFBOffset = state.getIndexedTransformFeedbackBufferOffset(i); + ID3D11Buffer *d3dBuffer = NULL; + if (curXFBBuffer) { - Buffer11 *storage = Buffer11::makeBuffer11(transformFeedbackBuffers[i]->getImplementation()); - ID3D11Buffer *buffer = storage->getBuffer(BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK); - - d3dBuffers[i] = buffer; - d3dOffsets[i] = (mAppliedTFBuffers[i] != buffer) ? static_cast<UINT>(offsets[i]) : -1; + Buffer11 *storage = Buffer11::makeBuffer11(curXFBBuffer->getImplementation()); + d3dBuffer = storage->getBuffer(BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK); } - else - { - d3dBuffers[i] = NULL; - d3dOffsets[i] = 0; - } - - if (d3dBuffers[i] != mAppliedTFBuffers[i] || offsets[i] != mAppliedTFOffsets[i]) + + // TODO: mAppliedTFBuffers and friends should also be kept in a vector. + if (d3dBuffer != mAppliedTFBuffers[i] || curXFBOffset != mAppliedTFOffsets[i]) { requiresUpdate = true; } } if (requiresUpdate) { - mDeviceContext->SOSetTargets(ArraySize(d3dBuffers), d3dBuffers, d3dOffsets); - for (size_t i = 0; i < gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS; i++) + for (size_t i = 0; i < numXFBBindings; ++i) { - mAppliedTFBuffers[i] = d3dBuffers[i]; - mAppliedTFOffsets[i] = offsets[i]; + gl::Buffer *curXFBBuffer = state.getIndexedTransformFeedbackBuffer(i); + GLintptr curXFBOffset = state.getIndexedTransformFeedbackBufferOffset(i); + + if (curXFBBuffer) + { + Buffer11 *storage = Buffer11::makeBuffer11(curXFBBuffer->getImplementation()); + ID3D11Buffer *d3dBuffer = storage->getBuffer(BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK); + + mCurrentD3DOffsets[i] = (mAppliedTFBuffers[i] != d3dBuffer && mAppliedTFOffsets[i] != curXFBOffset) ? + static_cast<UINT>(curXFBOffset) : -1; + mAppliedTFBuffers[i] = d3dBuffer; + } + else + { + mAppliedTFBuffers[i] = NULL; + mCurrentD3DOffsets[i] = 0; + } + mAppliedTFOffsets[i] = curXFBOffset; } + + mDeviceContext->SOSetTargets(numXFBBindings, mAppliedTFBuffers, mCurrentD3DOffsets); } } gl::Error Renderer11::drawArrays(GLenum mode, GLsizei count, GLsizei instances, bool transformFeedbackActive) { if (mode == GL_POINTS && transformFeedbackActive) { // Since point sprites are generated with a geometry shader, too many vertices will @@ -1325,18 +1339,31 @@ gl::Error Renderer11::drawTriangleFan(GL return gl::Error(GL_NO_ERROR); } gl::Error Renderer11::applyShaders(gl::ProgramBinary *programBinary, const gl::VertexFormat inputLayout[], const gl::Framebuffer *framebuffer, bool rasterizerDiscard, bool transformFeedbackActive) { ProgramD3D *programD3D = ProgramD3D::makeProgramD3D(programBinary->getImplementation()); - ShaderExecutable *vertexExe = programD3D->getVertexExecutableForInputLayout(inputLayout); - ShaderExecutable *pixelExe = programD3D->getPixelExecutableForFramebuffer(framebuffer); + + ShaderExecutable *vertexExe = NULL; + gl::Error error = programD3D->getVertexExecutableForInputLayout(inputLayout, &vertexExe); + if (error.isError()) + { + return error; + } + + ShaderExecutable *pixelExe = NULL; + error = programD3D->getPixelExecutableForFramebuffer(framebuffer, &pixelExe); + if (error.isError()) + { + return error; + } + ShaderExecutable *geometryExe = programD3D->getGeometryExecutable(); ID3D11VertexShader *vertexShader = (vertexExe ? ShaderExecutable11::makeShaderExecutable11(vertexExe)->getVertexShader() : NULL); ID3D11PixelShader *pixelShader = NULL; // Skip pixel shader if we're doing rasterizer discard. if (!rasterizerDiscard) { @@ -2182,32 +2209,33 @@ ProgramImpl *Renderer11::createProgram() return new ProgramD3D(this); } void Renderer11::releaseShaderCompiler() { ShaderD3D::releaseCompiler(); } -ShaderExecutable *Renderer11::loadExecutable(const void *function, size_t length, rx::ShaderType type, - const std::vector<gl::LinkedVarying> &transformFeedbackVaryings, - bool separatedOutputBuffers) +gl::Error Renderer11::loadExecutable(const void *function, size_t length, rx::ShaderType type, + const std::vector<gl::LinkedVarying> &transformFeedbackVaryings, + bool separatedOutputBuffers, ShaderExecutable **outExecutable) { - ShaderExecutable11 *executable = NULL; - HRESULT result; - switch (type) { case rx::SHADER_VERTEX: { ID3D11VertexShader *vertexShader = NULL; ID3D11GeometryShader *streamOutShader = NULL; - result = mDevice->CreateVertexShader(function, length, NULL, &vertexShader); + HRESULT result = mDevice->CreateVertexShader(function, length, NULL, &vertexShader); ASSERT(SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create vertex shader, result: 0x%X.", result); + } if (transformFeedbackVaryings.size() > 0) { std::vector<D3D11_SO_DECLARATION_ENTRY> soDeclaration; for (size_t i = 0; i < transformFeedbackVaryings.size(); i++) { const gl::LinkedVarying &varying = transformFeedbackVaryings[i]; GLenum transposedType = gl::TransposeMatrixType(varying.type); @@ -2223,77 +2251,81 @@ ShaderExecutable *Renderer11::loadExecut entry.OutputSlot = (separatedOutputBuffers ? i : 0); soDeclaration.push_back(entry); } } result = mDevice->CreateGeometryShaderWithStreamOutput(function, length, soDeclaration.data(), soDeclaration.size(), NULL, 0, 0, NULL, &streamOutShader); ASSERT(SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create steam output shader, result: 0x%X.", result); + } } - if (vertexShader) - { - executable = new ShaderExecutable11(function, length, vertexShader, streamOutShader); - } + *outExecutable = new ShaderExecutable11(function, length, vertexShader, streamOutShader); } break; case rx::SHADER_PIXEL: { ID3D11PixelShader *pixelShader = NULL; - result = mDevice->CreatePixelShader(function, length, NULL, &pixelShader); + HRESULT result = mDevice->CreatePixelShader(function, length, NULL, &pixelShader); ASSERT(SUCCEEDED(result)); - - if (pixelShader) + if (FAILED(result)) { - executable = new ShaderExecutable11(function, length, pixelShader); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create pixel shader, result: 0x%X.", result); } + + *outExecutable = new ShaderExecutable11(function, length, pixelShader); } break; case rx::SHADER_GEOMETRY: { ID3D11GeometryShader *geometryShader = NULL; - result = mDevice->CreateGeometryShader(function, length, NULL, &geometryShader); + HRESULT result = mDevice->CreateGeometryShader(function, length, NULL, &geometryShader); ASSERT(SUCCEEDED(result)); - - if (geometryShader) + if (FAILED(result)) { - executable = new ShaderExecutable11(function, length, geometryShader); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create geometry shader, result: 0x%X.", result); } + + *outExecutable = new ShaderExecutable11(function, length, geometryShader); } break; default: UNREACHABLE(); - break; + return gl::Error(GL_INVALID_OPERATION); } - return executable; + return gl::Error(GL_NO_ERROR); } -ShaderExecutable *Renderer11::compileToExecutable(gl::InfoLog &infoLog, const std::string &shaderHLSL, rx::ShaderType type, - const std::vector<gl::LinkedVarying> &transformFeedbackVaryings, - bool separatedOutputBuffers, D3DWorkaroundType workaround) +gl::Error Renderer11::compileToExecutable(gl::InfoLog &infoLog, const std::string &shaderHLSL, rx::ShaderType type, + const std::vector<gl::LinkedVarying> &transformFeedbackVaryings, + bool separatedOutputBuffers, D3DWorkaroundType workaround, + ShaderExecutable **outExectuable) { const char *profileType = NULL; switch (type) { case rx::SHADER_VERTEX: profileType = "vs"; break; case rx::SHADER_PIXEL: profileType = "ps"; break; case rx::SHADER_GEOMETRY: profileType = "gs"; break; default: UNREACHABLE(); - return NULL; + return gl::Error(GL_INVALID_OPERATION); } unsigned int profileMajorVersion = 0; unsigned int profileMinorVersion = 0; switch (mFeatureLevel) { case D3D_FEATURE_LEVEL_11_0: profileMajorVersion = 5; @@ -2304,17 +2336,17 @@ ShaderExecutable *Renderer11::compileToE profileMinorVersion = 1; break; case D3D_FEATURE_LEVEL_10_0: profileMajorVersion = 4; profileMinorVersion = 0; break; default: UNREACHABLE(); - return NULL; + return gl::Error(GL_INVALID_OPERATION); } std::string profile = FormatString("%s_%u_%u", profileType, profileMajorVersion, profileMinorVersion); UINT flags = D3DCOMPILE_OPTIMIZATION_LEVEL0; if (gl::perfActive()) { @@ -2327,27 +2359,40 @@ ShaderExecutable *Renderer11::compileToE // Sometimes D3DCompile will fail with the default compilation flags for complicated shaders when it would otherwise pass with alternative options. // Try the default flags first and if compilation fails, try some alternatives. std::vector<CompileConfig> configs; configs.push_back(CompileConfig(flags, "default" )); configs.push_back(CompileConfig(flags | D3DCOMPILE_SKIP_VALIDATION, "skip validation" )); configs.push_back(CompileConfig(flags | D3DCOMPILE_SKIP_OPTIMIZATION, "skip optimization")); - ID3DBlob *binary = mCompiler.compileToBinary(infoLog, shaderHLSL, profile, configs); + ID3DBlob *binary = NULL; + gl::Error error = mCompiler.compileToBinary(infoLog, shaderHLSL, profile, configs, &binary); + if (error.isError()) + { + return error; + } + + // It's possible that binary is NULL if the compiler failed in all configurations. Set the executable to NULL + // and return GL_NO_ERROR to signify that there was a link error but the internal state is still OK. if (!binary) { - return NULL; + *outExectuable = NULL; + return gl::Error(GL_NO_ERROR); } - ShaderExecutable *executable = loadExecutable(binary->GetBufferPointer(), binary->GetBufferSize(), type, - transformFeedbackVaryings, separatedOutputBuffers); + error = loadExecutable(binary->GetBufferPointer(), binary->GetBufferSize(), type, + transformFeedbackVaryings, separatedOutputBuffers, outExectuable); SafeRelease(binary); - - return executable; + if (error.isError()) + { + return error; + } + + return gl::Error(GL_NO_ERROR); } rx::UniformStorage *Renderer11::createUniformStorage(size_t storageSize) { return new UniformStorage11(this, storageSize); } VertexBuffer *Renderer11::createVertexBuffer() @@ -2422,50 +2467,32 @@ bool Renderer11::supportsFastCopyBufferT gl::Error Renderer11::fastCopyBufferToTexture(const gl::PixelUnpackState &unpack, unsigned int offset, RenderTarget *destRenderTarget, GLenum destinationFormat, GLenum sourcePixelsType, const gl::Box &destArea) { ASSERT(supportsFastCopyBufferToTexture(destinationFormat)); return mPixelTransfer->copyBufferToTexture(unpack, offset, destRenderTarget, destinationFormat, sourcePixelsType, destArea); } -bool Renderer11::getRenderTargetResource(gl::FramebufferAttachment *colorbuffer, unsigned int *subresourceIndex, ID3D11Texture2D **resource) +bool Renderer11::getRenderTargetResource(gl::FramebufferAttachment *colorbuffer, unsigned int *subresourceIndexOut, ID3D11Texture2D **texture2DOut) { ASSERT(colorbuffer != NULL); RenderTarget11 *renderTarget = d3d11::GetAttachmentRenderTarget(colorbuffer); - if (renderTarget) + if (!renderTarget) { - *subresourceIndex = renderTarget->getSubresourceIndex(); - - ID3D11RenderTargetView *colorBufferRTV = renderTarget->getRenderTargetView(); - if (colorBufferRTV) - { - ID3D11Resource *textureResource = NULL; - colorBufferRTV->GetResource(&textureResource); - - if (textureResource) - { - HRESULT result = textureResource->QueryInterface(__uuidof(ID3D11Texture2D), (void**)resource); - SafeRelease(textureResource); - - if (SUCCEEDED(result)) - { - return true; - } - else - { - ERR("Failed to extract the ID3D11Texture2D from the render target resource, " - "HRESULT: 0x%X.", result); - } - } - } + return false; } - return false; + ID3D11Resource *renderTargetResource = renderTarget->getTexture(); + + *subresourceIndexOut = renderTarget->getSubresourceIndex(); + *texture2DOut = d3d11::DynamicCastComObject<ID3D11Texture2D>(renderTargetResource); + + return (*texture2DOut != NULL); } gl::Error Renderer11::blitRect(gl::Framebuffer *readTarget, const gl::Rectangle &readRect, gl::Framebuffer *drawTarget, const gl::Rectangle &drawRect, const gl::Rectangle *scissor, bool blitRenderTarget, bool blitDepth, bool blitStencil, GLenum filter) { if (blitRenderTarget) { gl::FramebufferAttachment *readBuffer = readTarget->getReadColorbuffer();
--- a/gfx/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.h +++ b/gfx/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.h @@ -28,16 +28,17 @@ namespace rx { class VertexDataManager; class IndexDataManager; class StreamingIndexBufferInterface; class Blit11; class Clear11; class PixelTransfer11; +class RenderTarget11; struct PackPixelsParams; enum { MAX_VERTEX_UNIFORM_VECTORS_D3D11 = 1024, MAX_FRAGMENT_UNIFORM_VECTORS_D3D11 = 1024 }; @@ -74,21 +75,21 @@ class Renderer11 : public Renderer virtual void setScissorRectangle(const gl::Rectangle &scissor, bool enabled); virtual void setViewport(const gl::Rectangle &viewport, float zNear, float zFar, GLenum drawMode, GLenum frontFace, bool ignoreViewport); virtual bool applyPrimitiveType(GLenum mode, GLsizei count); virtual gl::Error applyRenderTarget(gl::Framebuffer *frameBuffer); virtual gl::Error applyShaders(gl::ProgramBinary *programBinary, const gl::VertexFormat inputLayout[], const gl::Framebuffer *framebuffer, bool rasterizerDiscard, bool transformFeedbackActive); + virtual gl::Error applyUniforms(const ProgramImpl &program, const std::vector<gl::LinkedUniform*> &uniformArray); - virtual gl::Error applyVertexBuffer(gl::ProgramBinary *programBinary, const gl::VertexAttribute vertexAttributes[], const gl::VertexAttribCurrentValueData currentValues[], - GLint first, GLsizei count, GLsizei instances); + virtual gl::Error applyVertexBuffer(const gl::State &state, GLint first, GLsizei count, GLsizei instances); virtual gl::Error applyIndexBuffer(const GLvoid *indices, gl::Buffer *elementArrayBuffer, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo); - virtual void applyTransformFeedbackBuffers(gl::Buffer *transformFeedbackBuffers[], GLintptr offsets[]); + virtual void applyTransformFeedbackBuffers(const gl::State &state); virtual gl::Error drawArrays(GLenum mode, GLsizei count, GLsizei instances, bool transformFeedbackActive); virtual gl::Error drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, gl::Buffer *elementArrayBuffer, const TranslatedIndexData &indexInfo, GLsizei instances); virtual gl::Error clear(const gl::ClearParameters &clearParams, gl::Framebuffer *frameBuffer); virtual void markAllStateDirty(); @@ -135,22 +136,23 @@ class Renderer11 : public Renderer virtual RenderTarget *createRenderTarget(int width, int height, GLenum format, GLsizei samples); // Shader creation virtual ShaderImpl *createShader(GLenum type); virtual ProgramImpl *createProgram(); // Shader operations virtual void releaseShaderCompiler(); - virtual ShaderExecutable *loadExecutable(const void *function, size_t length, rx::ShaderType type, - const std::vector<gl::LinkedVarying> &transformFeedbackVaryings, - bool separatedOutputBuffers); - virtual ShaderExecutable *compileToExecutable(gl::InfoLog &infoLog, const std::string &shaderHLSL, rx::ShaderType type, - const std::vector<gl::LinkedVarying> &transformFeedbackVaryings, - bool separatedOutputBuffers, D3DWorkaroundType workaround); + virtual gl::Error loadExecutable(const void *function, size_t length, rx::ShaderType type, + const std::vector<gl::LinkedVarying> &transformFeedbackVaryings, + bool separatedOutputBuffers, ShaderExecutable **outExecutable); + virtual gl::Error compileToExecutable(gl::InfoLog &infoLog, const std::string &shaderHLSL, rx::ShaderType type, + const std::vector<gl::LinkedVarying> &transformFeedbackVaryings, + bool separatedOutputBuffers, D3DWorkaroundType workaround, + ShaderExecutable **outExectuable); virtual UniformStorage *createUniformStorage(size_t storageSize); // Image operations virtual Image *createImage(); virtual void generateMipmap(Image *dest, Image *source); virtual TextureStorage *createTextureStorage2D(SwapChain *swapChain); virtual TextureStorage *createTextureStorage2D(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, int levels); virtual TextureStorage *createTextureStorageCube(GLenum internalformat, bool renderTarget, int size, int levels); @@ -182,37 +184,37 @@ class Renderer11 : public Renderer Blit11 *getBlitter() { return mBlit; } // Buffer-to-texture and Texture-to-buffer copies virtual bool supportsFastCopyBufferToTexture(GLenum internalFormat) const; virtual gl::Error fastCopyBufferToTexture(const gl::PixelUnpackState &unpack, unsigned int offset, RenderTarget *destRenderTarget, GLenum destinationFormat, GLenum sourcePixelsType, const gl::Box &destArea); - bool getRenderTargetResource(gl::FramebufferAttachment *colorbuffer, unsigned int *subresourceIndex, ID3D11Texture2D **resource); + bool getRenderTargetResource(gl::FramebufferAttachment *colorbuffer, unsigned int *subresourceIndexOut, ID3D11Texture2D **texture2DOut); void unapplyRenderTargets(); void setOneTimeRenderTarget(ID3D11RenderTargetView *renderTargetView); void packPixels(ID3D11Texture2D *readTexture, const PackPixelsParams ¶ms, uint8_t *pixelsOut); virtual bool getLUID(LUID *adapterLuid) const; virtual rx::VertexConversionType getVertexConversionType(const gl::VertexFormat &vertexFormat) const; virtual GLenum getVertexComponentType(const gl::VertexFormat &vertexFormat) const; + gl::Error readTextureData(ID3D11Texture2D *texture, unsigned int subResource, const gl::Rectangle &area, GLenum format, + GLenum type, GLuint outputPitch, const gl::PixelPackState &pack, uint8_t *pixels); + private: DISALLOW_COPY_AND_ASSIGN(Renderer11); virtual void generateCaps(gl::Caps *outCaps, gl::TextureCapsMap *outTextureCaps, gl::Extensions *outExtensions) const; virtual Workarounds generateWorkarounds() const; gl::Error drawLineLoop(GLsizei count, GLenum type, const GLvoid *indices, int minIndex, gl::Buffer *elementArrayBuffer); gl::Error drawTriangleFan(GLsizei count, GLenum type, const GLvoid *indices, int minIndex, gl::Buffer *elementArrayBuffer, int instances); - gl::Error readTextureData(ID3D11Texture2D *texture, unsigned int subResource, const gl::Rectangle &area, GLenum format, - GLenum type, GLuint outputPitch, const gl::PixelPackState &pack, uint8_t *pixels); - gl::Error blitRenderbufferRect(const gl::Rectangle &readRect, const gl::Rectangle &drawRect, RenderTarget *readRenderTarget, RenderTarget *drawRenderTarget, GLenum filter, const gl::Rectangle *scissor, bool colorBlit, bool depthBlit, bool stencilBlit); ID3D11Texture2D *resolveMultisampledTexture(ID3D11Texture2D *source, unsigned int subresource); static void invalidateFBOAttachmentSwizzles(gl::FramebufferAttachment *attachment, int mipLevel); static void invalidateFramebufferSwizzles(gl::Framebuffer *framebuffer); @@ -282,18 +284,24 @@ class Renderer11 : public Renderer D3D11_PRIMITIVE_TOPOLOGY mCurrentPrimitiveTopology; // Currently applied index buffer ID3D11Buffer *mAppliedIB; DXGI_FORMAT mAppliedIBFormat; unsigned int mAppliedIBOffset; // Currently applied transform feedback buffers - ID3D11Buffer *mAppliedTFBuffers[gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS]; - GLintptr mAppliedTFOffsets[gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS]; + ID3D11Buffer *mAppliedTFBuffers[gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS]; // Tracks the current D3D buffers + // in use for streamout + GLintptr mAppliedTFOffsets[gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS]; // Tracks the current GL-specified + // buffer offsets to transform feedback + // buffers + UINT mCurrentD3DOffsets[gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS]; // Tracks the D3D buffer offsets, + // which may differ from GLs, due + // to different append behavior // Currently applied shaders ID3D11VertexShader *mAppliedVertexShader; ID3D11GeometryShader *mAppliedGeometryShader; ID3D11GeometryShader *mCurPointGeometryShader; ID3D11PixelShader *mAppliedPixelShader; dx_VertexConstants mVertexConstants;
--- a/gfx/angle/src/libGLESv2/renderer/d3d/d3d11/TextureStorage11.cpp +++ b/gfx/angle/src/libGLESv2/renderer/d3d/d3d11/TextureStorage11.cpp @@ -10,16 +10,17 @@ #include "libGLESv2/renderer/d3d/d3d11/TextureStorage11.h" #include "libGLESv2/renderer/d3d/d3d11/Renderer11.h" #include "libGLESv2/renderer/d3d/d3d11/RenderTarget11.h" #include "libGLESv2/renderer/d3d/d3d11/SwapChain11.h" #include "libGLESv2/renderer/d3d/d3d11/renderer11_utils.h" #include "libGLESv2/renderer/d3d/d3d11/Blit11.h" #include "libGLESv2/renderer/d3d/d3d11/formatutils11.h" #include "libGLESv2/renderer/d3d/d3d11/Image11.h" +#include "libGLESv2/renderer/d3d/MemoryBuffer.h" #include "libGLESv2/renderer/d3d/TextureD3D.h" #include "libGLESv2/main.h" #include "libGLESv2/ImageIndex.h" #include "common/utilities.h" namespace rx { @@ -178,24 +179,27 @@ int TextureStorage11::getLevelHeight(int return std::max(static_cast<int>(mTextureHeight) >> mipLevel, 1); } int TextureStorage11::getLevelDepth(int mipLevel) const { return std::max(static_cast<int>(mTextureDepth) >> mipLevel, 1); } -UINT TextureStorage11::getSubresourceIndex(int mipLevel, int layerTarget) const +UINT TextureStorage11::getSubresourceIndex(const gl::ImageIndex &index) const { - UINT index = 0; + UINT subresource = 0; if (getResource()) { - index = D3D11CalcSubresource(mipLevel, layerTarget, mMipLevels); + UINT mipSlice = static_cast<UINT>(index.mipIndex + mTopLevel); + UINT arraySlice = static_cast<UINT>(index.hasLayer() ? index.layerIndex : 0); + subresource = D3D11CalcSubresource(mipSlice, arraySlice, mMipLevels); + ASSERT(subresource != std::numeric_limits<UINT>::max()); } - return index; + return subresource; } ID3D11ShaderResourceView *TextureStorage11::getSRV(const gl::SamplerState &samplerState) { bool swizzleRequired = samplerState.swizzleRequired(); bool mipmapping = gl::IsMipmapFiltered(samplerState); unsigned int mipLevels = mipmapping ? (samplerState.maxLevel - samplerState.baseLevel) : 1; @@ -283,35 +287,35 @@ void TextureStorage11::invalidateSwizzle { for (unsigned int mipLevel = 0; mipLevel < ArraySize(mSwizzleCache); mipLevel++) { invalidateSwizzleCacheLevel(mipLevel); } } gl::Error TextureStorage11::updateSubresourceLevel(ID3D11Resource *srcTexture, unsigned int sourceSubresource, - int level, int layerTarget, GLint xoffset, GLint yoffset, GLint zoffset, - GLsizei width, GLsizei height, GLsizei depth) + const gl::ImageIndex &index, const gl::Box ©Area) { ASSERT(srcTexture); + GLint level = index.mipIndex; + invalidateSwizzleCacheLevel(level); gl::Extents texSize(getLevelWidth(level), getLevelHeight(level), getLevelDepth(level)); - gl::Box copyArea(xoffset, yoffset, zoffset, width, height, depth); bool fullCopy = copyArea.x == 0 && copyArea.y == 0 && copyArea.z == 0 && copyArea.width == texSize.width && copyArea.height == texSize.height && copyArea.depth == texSize.depth; ID3D11Resource *dstTexture = getResource(); - unsigned int dstSubresource = getSubresourceIndex(level + mTopLevel, layerTarget); + unsigned int dstSubresource = getSubresourceIndex(index); ASSERT(dstTexture); const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(mTextureFormat); if (!fullCopy && (dxgiFormatInfo.depthBits > 0 || dxgiFormatInfo.stencilBits > 0)) { // CopySubresourceRegion cannot copy partial depth stencils, use the blitter instead Blit11 *blitter = mRenderer->getBlitter(); @@ -322,43 +326,42 @@ gl::Error TextureStorage11::updateSubres } else { const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(mTextureFormat); D3D11_BOX srcBox; srcBox.left = copyArea.x; srcBox.top = copyArea.y; - srcBox.right = copyArea.x + roundUp((unsigned int)width, dxgiFormatInfo.blockWidth); - srcBox.bottom = copyArea.y + roundUp((unsigned int)height, dxgiFormatInfo.blockHeight); + srcBox.right = copyArea.x + roundUp(static_cast<UINT>(copyArea.width), dxgiFormatInfo.blockWidth); + srcBox.bottom = copyArea.y + roundUp(static_cast<UINT>(copyArea.height), dxgiFormatInfo.blockHeight); srcBox.front = copyArea.z; srcBox.back = copyArea.z + copyArea.depth; ID3D11DeviceContext *context = mRenderer->getDeviceContext(); context->CopySubresourceRegion(dstTexture, dstSubresource, copyArea.x, copyArea.y, copyArea.z, srcTexture, sourceSubresource, fullCopy ? NULL : &srcBox); return gl::Error(GL_NO_ERROR); } } bool TextureStorage11::copySubresourceLevel(ID3D11Resource* dstTexture, unsigned int dstSubresource, - int level, int layerTarget, GLint xoffset, GLint yoffset, GLint zoffset, - GLsizei width, GLsizei height, GLsizei depth) + const gl::ImageIndex &index, const gl::Box ®ion) { if (dstTexture) { ID3D11Resource *srcTexture = getResource(); - unsigned int srcSubresource = getSubresourceIndex(level + mTopLevel, layerTarget); + unsigned int srcSubresource = getSubresourceIndex(index); ASSERT(srcTexture); ID3D11DeviceContext *context = mRenderer->getDeviceContext(); - context->CopySubresourceRegion(dstTexture, dstSubresource, xoffset, yoffset, zoffset, + context->CopySubresourceRegion(dstTexture, dstSubresource, region.x, region.y, region.z, srcTexture, srcSubresource, NULL); return true; } return false; } void TextureStorage11::generateMipmap(const gl::ImageIndex &sourceIndex, const gl::ImageIndex &destIndex) @@ -409,16 +412,71 @@ gl::Error TextureStorage11::copyToStorag ID3D11DeviceContext *immediateContext = mRenderer->getDeviceContext(); immediateContext->CopyResource(dest11->getResource(), getResource()); dest11->invalidateSwizzleCache(); return gl::Error(GL_NO_ERROR); } +gl::Error TextureStorage11::setData(const gl::ImageIndex &index, const gl::Box &destBox, GLenum internalFormat, GLenum type, + const gl::PixelUnpackState &unpack, const uint8_t *pixelData) +{ + ID3D11Resource *resource = getResource(); + ASSERT(resource); + + UINT destSubresource = getSubresourceIndex(index); + + const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(internalFormat); + + // TODO(jmadill): Handle compressed formats + // Compressed formats have different load syntax, so we'll have to handle them with slightly + // different logic. Will implemnent this in a follow-up patch, and ensure we do not use SetData + // with compressed formats in the calling logic. + ASSERT(!internalFormatInfo.compressed); + + UINT srcRowPitch = internalFormatInfo.computeRowPitch(type, destBox.width, unpack.alignment); + UINT srcDepthPitch = internalFormatInfo.computeDepthPitch(type, destBox.width, destBox.height, unpack.alignment); + + D3D11_BOX destD3DBox; + destD3DBox.left = destBox.x; + destD3DBox.right = destBox.x + destBox.width; + destD3DBox.top = destBox.y; + destD3DBox.bottom = destBox.y + destBox.height; + destD3DBox.front = 0; + destD3DBox.back = 1; + + const d3d11::TextureFormat &d3d11Format = d3d11::GetTextureFormatInfo(internalFormat); + const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(d3d11Format.texFormat); + + size_t outputPixelSize = dxgiFormatInfo.pixelBytes; + + UINT bufferRowPitch = outputPixelSize * destBox.width; + UINT bufferDepthPitch = bufferRowPitch * destBox.height; + + MemoryBuffer conversionBuffer; + if (!conversionBuffer.resize(bufferDepthPitch * destBox.depth)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to allocate internal buffer."); + } + + // TODO: fast path + LoadImageFunction loadFunction = d3d11Format.loadFunctions.at(type); + loadFunction(destBox.width, destBox.height, destBox.depth, + pixelData, srcRowPitch, srcDepthPitch, + conversionBuffer.data(), bufferRowPitch, bufferDepthPitch); + + ID3D11DeviceContext *immediateContext = mRenderer->getDeviceContext(); + immediateContext->UpdateSubresource(resource, destSubresource, + &destD3DBox, conversionBuffer.data(), + bufferRowPitch, bufferDepthPitch); + + return gl::Error(GL_NO_ERROR); +} + TextureStorage11_2D::TextureStorage11_2D(Renderer *renderer, SwapChain11 *swapchain) : TextureStorage11(renderer, D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE), mTexture(swapchain->getOffscreenTexture()), mSwizzleTexture(NULL) { mTexture->AddRef(); for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) @@ -555,58 +613,66 @@ TextureStorage11_2D::~TextureStorage11_2 } TextureStorage11_2D *TextureStorage11_2D::makeTextureStorage11_2D(TextureStorage *storage) { ASSERT(HAS_DYNAMIC_TYPE(TextureStorage11_2D*, storage)); return static_cast<TextureStorage11_2D*>(storage); } -void TextureStorage11_2D::associateImage(Image11* image, int level, int layerTarget) +void TextureStorage11_2D::associateImage(Image11* image, const gl::ImageIndex &index) { + GLint level = index.mipIndex; + ASSERT(0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); if (0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) { mAssociatedImages[level] = image; } } -bool TextureStorage11_2D::isAssociatedImageValid(int level, int layerTarget, Image11* expectedImage) +bool TextureStorage11_2D::isAssociatedImageValid(const gl::ImageIndex &index, Image11* expectedImage) { + GLint level = index.mipIndex; + if (0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) { // This validation check should never return false. It means the Image/TextureStorage association is broken. bool retValue = (mAssociatedImages[level] == expectedImage); ASSERT(retValue); return retValue; } return false; } // disassociateImage allows an Image to end its association with a Storage. -void TextureStorage11_2D::disassociateImage(int level, int layerTarget, Image11* expectedImage) +void TextureStorage11_2D::disassociateImage(const gl::ImageIndex &index, Image11* expectedImage) { + GLint level = index.mipIndex; + ASSERT(0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); if (0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) { ASSERT(mAssociatedImages[level] == expectedImage); if (mAssociatedImages[level] == expectedImage) { mAssociatedImages[level] = NULL; } } } // releaseAssociatedImage prepares the Storage for a new Image association. It lets the old Image recover its data before ending the association. -void TextureStorage11_2D::releaseAssociatedImage(int level, int layerTarget, Image11* incomingImage) +void TextureStorage11_2D::releaseAssociatedImage(const gl::ImageIndex &index, Image11* incomingImage) { + GLint level = index.mipIndex; + ASSERT(0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); if (0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) { // No need to let the old Image recover its data, if it is also the incoming Image. if (mAssociatedImages[level] != NULL && mAssociatedImages[level] != incomingImage) { // Ensure that the Image is still associated with this TextureStorage. This should be true. @@ -898,49 +964,58 @@ TextureStorage11_Cube::~TextureStorage11 } TextureStorage11_Cube *TextureStorage11_Cube::makeTextureStorage11_Cube(TextureStorage *storage) { ASSERT(HAS_DYNAMIC_TYPE(TextureStorage11_Cube*, storage)); return static_cast<TextureStorage11_Cube*>(storage); } -void TextureStorage11_Cube::associateImage(Image11* image, int level, int layerTarget) +void TextureStorage11_Cube::associateImage(Image11* image, const gl::ImageIndex &index) { + GLint level = index.mipIndex; + GLint layerTarget = index.layerIndex; + ASSERT(0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); ASSERT(0 <= layerTarget && layerTarget < 6); if (0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) { if (0 <= layerTarget && layerTarget < 6) { mAssociatedImages[layerTarget][level] = image; } } } -bool TextureStorage11_Cube::isAssociatedImageValid(int level, int layerTarget, Image11* expectedImage) +bool TextureStorage11_Cube::isAssociatedImageValid(const gl::ImageIndex &index, Image11* expectedImage) { + GLint level = index.mipIndex; + GLint layerTarget = index.layerIndex; + if (0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) { if (0 <= layerTarget && layerTarget < 6) { // This validation check should never return false. It means the Image/TextureStorage association is broken. bool retValue = (mAssociatedImages[layerTarget][level] == expectedImage); ASSERT(retValue); return retValue; } } return false; } // disassociateImage allows an Image to end its association with a Storage. -void TextureStorage11_Cube::disassociateImage(int level, int layerTarget, Image11* expectedImage) +void TextureStorage11_Cube::disassociateImage(const gl::ImageIndex &index, Image11* expectedImage) { + GLint level = index.mipIndex; + GLint layerTarget = index.layerIndex; + ASSERT(0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); ASSERT(0 <= layerTarget && layerTarget < 6); if (0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) { if (0 <= layerTarget && layerTarget < 6) { ASSERT(mAssociatedImages[layerTarget][level] == expectedImage); @@ -949,18 +1024,21 @@ void TextureStorage11_Cube::disassociate { mAssociatedImages[layerTarget][level] = NULL; } } } } // releaseAssociatedImage prepares the Storage for a new Image association. It lets the old Image recover its data before ending the association. -void TextureStorage11_Cube::releaseAssociatedImage(int level, int layerTarget, Image11* incomingImage) +void TextureStorage11_Cube::releaseAssociatedImage(const gl::ImageIndex &index, Image11* incomingImage) { + GLint level = index.mipIndex; + GLint layerTarget = index.layerIndex; + ASSERT(0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); ASSERT(0 <= layerTarget && layerTarget < 6); if ((0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)) { if (0 <= layerTarget && layerTarget < 6) { // No need to let the old Image recover its data, if it is also the incoming Image. @@ -1289,58 +1367,66 @@ TextureStorage11_3D::~TextureStorage11_3 } TextureStorage11_3D *TextureStorage11_3D::makeTextureStorage11_3D(TextureStorage *storage) { ASSERT(HAS_DYNAMIC_TYPE(TextureStorage11_3D*, storage)); return static_cast<TextureStorage11_3D*>(storage); } -void TextureStorage11_3D::associateImage(Image11* image, int level, int layerTarget) +void TextureStorage11_3D::associateImage(Image11* image, const gl::ImageIndex &index) { + GLint level = index.mipIndex; + ASSERT(0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); if (0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) { mAssociatedImages[level] = image; } } -bool TextureStorage11_3D::isAssociatedImageValid(int level, int layerTarget, Image11* expectedImage) +bool TextureStorage11_3D::isAssociatedImageValid(const gl::ImageIndex &index, Image11* expectedImage) { + GLint level = index.mipIndex; + if (0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) { // This validation check should never return false. It means the Image/TextureStorage association is broken. bool retValue = (mAssociatedImages[level] == expectedImage); ASSERT(retValue); return retValue; } return false; } // disassociateImage allows an Image to end its association with a Storage. -void TextureStorage11_3D::disassociateImage(int level, int layerTarget, Image11* expectedImage) +void TextureStorage11_3D::disassociateImage(const gl::ImageIndex &index, Image11* expectedImage) { + GLint level = index.mipIndex; + ASSERT(0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); if (0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) { ASSERT(mAssociatedImages[level] == expectedImage); if (mAssociatedImages[level] == expectedImage) { mAssociatedImages[level] = NULL; } } } // releaseAssociatedImage prepares the Storage for a new Image association. It lets the old Image recover its data before ending the association. -void TextureStorage11_3D::releaseAssociatedImage(int level, int layerTarget, Image11* incomingImage) +void TextureStorage11_3D::releaseAssociatedImage(const gl::ImageIndex &index, Image11* incomingImage) { + GLint level = index.mipIndex; + ASSERT((0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)); if (0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) { // No need to let the old Image recover its data, if it is also the incoming Image. if (mAssociatedImages[level] != NULL && mAssociatedImages[level] != incomingImage) { // Ensure that the Image is still associated with this TextureStorage. This should be true. @@ -1641,54 +1727,66 @@ TextureStorage11_2DArray::~TextureStorag } TextureStorage11_2DArray *TextureStorage11_2DArray::makeTextureStorage11_2DArray(TextureStorage *storage) { ASSERT(HAS_DYNAMIC_TYPE(TextureStorage11_2DArray*, storage)); return static_cast<TextureStorage11_2DArray*>(storage); } -void TextureStorage11_2DArray::associateImage(Image11* image, int level, int layerTarget) +void TextureStorage11_2DArray::associateImage(Image11* image, const gl::ImageIndex &index) { + GLint level = index.mipIndex; + GLint layerTarget = index.layerIndex; + ASSERT(0 <= level && level < getLevelCount()); if (0 <= level && level < getLevelCount()) { LevelLayerKey key(level, layerTarget); mAssociatedImages[key] = image; } } -bool TextureStorage11_2DArray::isAssociatedImageValid(int level, int layerTarget, Image11* expectedImage) +bool TextureStorage11_2DArray::isAssociatedImageValid(const gl::ImageIndex &index, Image11* expectedImage) { + GLint level = index.mipIndex; + GLint layerTarget = index.layerIndex; + LevelLayerKey key(level, layerTarget); // This validation check should never return false. It means the Image/TextureStorage association is broken. bool retValue = (mAssociatedImages.find(key) != mAssociatedImages.end() && (mAssociatedImages[key] == expectedImage)); ASSERT(retValue); return retValue; } // disassociateImage allows an Image to end its association with a Storage. -void TextureStorage11_2DArray::disassociateImage(int level, int layerTarget, Image11* expectedImage) +void TextureStorage11_2DArray::disassociateImage(const gl::ImageIndex &index, Image11* expectedImage) { + GLint level = index.mipIndex; + GLint layerTarget = index.layerIndex; + LevelLayerKey key(level, layerTarget); bool imageAssociationCorrect = (mAssociatedImages.find(key) != mAssociatedImages.end() && (mAssociatedImages[key] == expectedImage)); ASSERT(imageAssociationCorrect); if (imageAssociationCorrect) { mAssociatedImages[key] = NULL; } } // releaseAssociatedImage prepares the Storage for a new Image association. It lets the old Image recover its data before ending the association. -void TextureStorage11_2DArray::releaseAssociatedImage(int level, int layerTarget, Image11* incomingImage) +void TextureStorage11_2DArray::releaseAssociatedImage(const gl::ImageIndex &index, Image11* incomingImage) { + GLint level = index.mipIndex; + GLint layerTarget = index.layerIndex; + LevelLayerKey key(level, layerTarget); ASSERT(mAssociatedImages.find(key) != mAssociatedImages.end()); if (mAssociatedImages.find(key) != mAssociatedImages.end()) { if (mAssociatedImages[key] != NULL && mAssociatedImages[key] != incomingImage) {
--- a/gfx/angle/src/libGLESv2/renderer/d3d/d3d11/TextureStorage11.h +++ b/gfx/angle/src/libGLESv2/renderer/d3d/d3d11/TextureStorage11.h @@ -46,36 +46,36 @@ class TextureStorage11 : public TextureS virtual RenderTarget *getRenderTarget(const gl::ImageIndex &index) = 0; virtual void generateMipmap(const gl::ImageIndex &sourceIndex, const gl::ImageIndex &destIndex); virtual int getTopLevel() const; virtual bool isRenderTarget() const; virtual bool isManaged() const; virtual int getLevelCount() const; - UINT getSubresourceIndex(int mipLevel, int layerTarget) const; + UINT getSubresourceIndex(const gl::ImageIndex &index) const; gl::Error generateSwizzles(GLenum swizzleRed, GLenum swizzleGreen, GLenum swizzleBlue, GLenum swizzleAlpha); void invalidateSwizzleCacheLevel(int mipLevel); void invalidateSwizzleCache(); - gl::Error updateSubresourceLevel(ID3D11Resource *texture, unsigned int sourceSubresource, int level, - int layerTarget, GLint xoffset, GLint yoffset, GLint zoffset, - GLsizei width, GLsizei height, GLsizei depth); + gl::Error updateSubresourceLevel(ID3D11Resource *texture, unsigned int sourceSubresource, + const gl::ImageIndex &index, const gl::Box ©Area); - bool copySubresourceLevel(ID3D11Resource* dstTexture, unsigned int dstSubresource, int level, - int layerTarget, GLint xoffset, GLint yoffset, GLint zoffset, - GLsizei width, GLsizei height, GLsizei depth); + bool copySubresourceLevel(ID3D11Resource* dstTexture, unsigned int dstSubresource, + const gl::ImageIndex &index, const gl::Box ®ion); - virtual void associateImage(Image11* image, int level, int layerTarget) = 0; - virtual void disassociateImage(int level, int layerTarget, Image11* expectedImage) = 0; - virtual bool isAssociatedImageValid(int level, int layerTarget, Image11* expectedImage) = 0; - virtual void releaseAssociatedImage(int level, int layerTarget, Image11* incomingImage) = 0; + virtual void associateImage(Image11* image, const gl::ImageIndex &index) = 0; + virtual void disassociateImage(const gl::ImageIndex &index, Image11* expectedImage) = 0; + virtual bool isAssociatedImageValid(const gl::ImageIndex &index, Image11* expectedImage) = 0; + virtual void releaseAssociatedImage(const gl::ImageIndex &index, Image11* incomingImage) = 0; virtual gl::Error copyToStorage(TextureStorage *destStorage); + virtual gl::Error setData(const gl::ImageIndex &index, const gl::Box &sourceBox, GLenum internalFormat, GLenum type, + const gl::PixelUnpackState &unpack, const uint8_t *pixelData); protected: TextureStorage11(Renderer *renderer, UINT bindFlags); int getLevelWidth(int mipLevel) const; int getLevelHeight(int mipLevel) const; int getLevelDepth(int mipLevel) const; virtual ID3D11Resource *getSwizzleTexture() = 0; @@ -159,20 +159,20 @@ class TextureStorage11_2D : public Textu TextureStorage11_2D(Renderer *renderer, GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, int levels); virtual ~TextureStorage11_2D(); static TextureStorage11_2D *makeTextureStorage11_2D(TextureStorage *storage); virtual ID3D11Resource *getResource() const; virtual RenderTarget *getRenderTarget(const gl::ImageIndex &index); - virtual void associateImage(Image11* image, int level, int layerTarget); - virtual void disassociateImage(int level, int layerTarget, Image11* expectedImage); - virtual bool isAssociatedImageValid(int level, int layerTarget, Image11* expectedImage); - virtual void releaseAssociatedImage(int level, int layerTarget, Image11* incomingImage); + virtual void associateImage(Image11* image, const gl::ImageIndex &index); + virtual void disassociateImage(const gl::ImageIndex &index, Image11* expectedImage); + virtual bool isAssociatedImageValid(const gl::ImageIndex &index, Image11* expectedImage); + virtual void releaseAssociatedImage(const gl::ImageIndex &index, Image11* incomingImage); protected: virtual ID3D11Resource *getSwizzleTexture(); virtual ID3D11RenderTargetView *getSwizzleRenderTarget(int mipLevel); private: DISALLOW_COPY_AND_ASSIGN(TextureStorage11_2D); @@ -193,20 +193,20 @@ class TextureStorage11_Cube : public Tex TextureStorage11_Cube(Renderer *renderer, GLenum internalformat, bool renderTarget, int size, int levels); virtual ~TextureStorage11_Cube(); static TextureStorage11_Cube *makeTextureStorage11_Cube(TextureStorage *storage); virtual ID3D11Resource *getResource() const; virtual RenderTarget *getRenderTarget(const gl::ImageIndex &index); - virtual void associateImage(Image11* image, int level, int layerTarget); - virtual void disassociateImage(int level, int layerTarget, Image11* expectedImage); - virtual bool isAssociatedImageValid(int level, int layerTarget, Image11* expectedImage); - virtual void releaseAssociatedImage(int level, int layerTarget, Image11* incomingImage); + virtual void associateImage(Image11* image, const gl::ImageIndex &index); + virtual void disassociateImage(const gl::ImageIndex &index, Image11* expectedImage); + virtual bool isAssociatedImageValid(const gl::ImageIndex &index, Image11* expectedImage); + virtual void releaseAssociatedImage(const gl::ImageIndex &index, Image11* incomingImage); protected: virtual ID3D11Resource *getSwizzleTexture(); virtual ID3D11RenderTargetView *getSwizzleRenderTarget(int mipLevel); private: DISALLOW_COPY_AND_ASSIGN(TextureStorage11_Cube); @@ -230,20 +230,20 @@ class TextureStorage11_3D : public Textu static TextureStorage11_3D *makeTextureStorage11_3D(TextureStorage *storage); virtual ID3D11Resource *getResource() const; // Handles both layer and non-layer RTs virtual RenderTarget *getRenderTarget(const gl::ImageIndex &index); - virtual void associateImage(Image11* image, int level, int layerTarget); - virtual void disassociateImage(int level, int layerTarget, Image11* expectedImage); - virtual bool isAssociatedImageValid(int level, int layerTarget, Image11* expectedImage); - virtual void releaseAssociatedImage(int level, int layerTarget, Image11* incomingImage); + virtual void associateImage(Image11* image, const gl::ImageIndex &index); + virtual void disassociateImage(const gl::ImageIndex &index, Image11* expectedImage); + virtual bool isAssociatedImageValid(const gl::ImageIndex &index, Image11* expectedImage); + virtual void releaseAssociatedImage(const gl::ImageIndex &index, Image11* incomingImage); protected: virtual ID3D11Resource *getSwizzleTexture(); virtual ID3D11RenderTargetView *getSwizzleRenderTarget(int mipLevel); private: DISALLOW_COPY_AND_ASSIGN(TextureStorage11_3D); @@ -269,20 +269,20 @@ class TextureStorage11_2DArray : public GLsizei width, GLsizei height, GLsizei depth, int levels); virtual ~TextureStorage11_2DArray(); static TextureStorage11_2DArray *makeTextureStorage11_2DArray(TextureStorage *storage); virtual ID3D11Resource *getResource() const; virtual RenderTarget *getRenderTarget(const gl::ImageIndex &index); - virtual void associateImage(Image11* image, int level, int layerTarget); - virtual void disassociateImage(int level, int layerTarget, Image11* expectedImage); - virtual bool isAssociatedImageValid(int level, int layerTarget, Image11* expectedImage); - virtual void releaseAssociatedImage(int level, int layerTarget, Image11* incomingImage); + virtual void associateImage(Image11* image, const gl::ImageIndex &index); + virtual void disassociateImage(const gl::ImageIndex &index, Image11* expectedImage); + virtual bool isAssociatedImageValid(const gl::ImageIndex &index, Image11* expectedImage); + virtual void releaseAssociatedImage(const gl::ImageIndex &index, Image11* incomingImage); protected: virtual ID3D11Resource *getSwizzleTexture(); virtual ID3D11RenderTargetView *getSwizzleRenderTarget(int mipLevel); private: DISALLOW_COPY_AND_ASSIGN(TextureStorage11_2DArray);
--- a/gfx/angle/src/libGLESv2/renderer/d3d/d3d11/renderer11_utils.cpp +++ b/gfx/angle/src/libGLESv2/renderer/d3d/d3d11/renderer11_utils.cpp @@ -811,17 +811,17 @@ static size_t GetMaximumStreamOutputBuff case D3D_FEATURE_LEVEL_9_3: case D3D_FEATURE_LEVEL_9_2: case D3D_FEATURE_LEVEL_9_1: return 0; default: UNREACHABLE(); return 0; } } -static size_t GetMaximumStreamOutputInterleavedComponenets(D3D_FEATURE_LEVEL featureLevel) +static size_t GetMaximumStreamOutputInterleavedComponents(D3D_FEATURE_LEVEL featureLevel) { switch (featureLevel) { case D3D_FEATURE_LEVEL_11_1: case D3D_FEATURE_LEVEL_11_0: case D3D_FEATURE_LEVEL_10_1: case D3D_FEATURE_LEVEL_10_0: return GetMaximumVertexOutputVectors(featureLevel) * 4; @@ -829,22 +829,22 @@ static size_t GetMaximumStreamOutputInte case D3D_FEATURE_LEVEL_9_3: case D3D_FEATURE_LEVEL_9_2: case D3D_FEATURE_LEVEL_9_1: return 0; default: UNREACHABLE(); return 0; } } -static size_t GetMaximumStreamOutputSeparateCompeonents(D3D_FEATURE_LEVEL featureLevel) +static size_t GetMaximumStreamOutputSeparateComponents(D3D_FEATURE_LEVEL featureLevel) { switch (featureLevel) { case D3D_FEATURE_LEVEL_11_1: - case D3D_FEATURE_LEVEL_11_0: return GetMaximumStreamOutputInterleavedComponenets(featureLevel) / + case D3D_FEATURE_LEVEL_11_0: return GetMaximumStreamOutputInterleavedComponents(featureLevel) / GetMaximumStreamOutputBuffers(featureLevel); // D3D 10 and 10.1 only allow one output per output slot if an output slot other than zero is used. case D3D_FEATURE_LEVEL_10_1: case D3D_FEATURE_LEVEL_10_0: return 4; case D3D_FEATURE_LEVEL_9_3: @@ -943,19 +943,19 @@ void GenerateCaps(ID3D11Device *device, static_cast<GLint64>(caps->maxVertexUniformComponents); caps->maxCombinedFragmentUniformComponents = (static_cast<GLint64>(caps->maxFragmentUniformBlocks) * static_cast<GLint64>(caps->maxUniformBlockSize / 4)) + static_cast<GLint64>(caps->maxFragmentUniformComponents); caps->maxVaryingComponents = GetMaximumVertexOutputVectors(featureLevel) * 4; caps->maxVaryingVectors = GetMaximumVertexOutputVectors(featureLevel); caps->maxCombinedTextureImageUnits = caps->maxVertexTextureImageUnits + caps->maxTextureImageUnits; // Transform feedback limits - caps->maxTransformFeedbackInterleavedComponents = GetMaximumStreamOutputInterleavedComponenets(featureLevel); + caps->maxTransformFeedbackInterleavedComponents = GetMaximumStreamOutputInterleavedComponents(featureLevel); caps->maxTransformFeedbackSeparateAttributes = GetMaximumStreamOutputBuffers(featureLevel); - caps->maxTransformFeedbackSeparateComponents = GetMaximumStreamOutputSeparateCompeonents(featureLevel); + caps->maxTransformFeedbackSeparateComponents = GetMaximumStreamOutputSeparateComponents(featureLevel); // GL extension support extensions->setTextureExtensionSupport(*textureCapsMap); extensions->elementIndexUint = true; extensions->packedDepthStencil = true; extensions->getProgramBinary = true; extensions->rgb8rgba8 = true; extensions->readFormatBGRA = true; @@ -1071,14 +1071,15 @@ RenderTarget11 *GetAttachmentRenderTarge RenderTarget *renderTarget = rx::GetAttachmentRenderTarget(attachment); return RenderTarget11::makeRenderTarget11(renderTarget); } Workarounds GenerateWorkarounds() { Workarounds workarounds; workarounds.mrtPerfWorkaround = true; + workarounds.setDataFasterThanImageUpload = true; return workarounds; } } }
--- a/gfx/angle/src/libGLESv2/renderer/d3d/d3d9/Blit9.cpp +++ b/gfx/angle/src/libGLESv2/renderer/d3d/d3d9/Blit9.cpp @@ -109,36 +109,36 @@ void Blit9::initGeometry() { ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); return gl::error(GL_OUT_OF_MEMORY); } } template <class D3DShaderType> gl::Error Blit9::setShader(ShaderId source, const char *profile, - D3DShaderType *(rx::Renderer9::*createShader)(const DWORD *, size_t length), + gl::Error (Renderer9::*createShader)(const DWORD *, size_t length, D3DShaderType **outShader), HRESULT (WINAPI IDirect3DDevice9::*setShader)(D3DShaderType*)) { IDirect3DDevice9 *device = mRenderer->getDevice(); D3DShaderType *shader; if (mCompiledShaders[source] != NULL) { shader = static_cast<D3DShaderType*>(mCompiledShaders[source]); } else { const BYTE* shaderCode = g_shaderCode[source]; size_t shaderSize = g_shaderSize[source]; - shader = (mRenderer->*createShader)(reinterpret_cast<const DWORD*>(shaderCode), shaderSize); - if (!shader) + gl::Error error = (mRenderer->*createShader)(reinterpret_cast<const DWORD*>(shaderCode), shaderSize, &shader); + if (error.isError()) { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal shader for blit operation"); + return error; } mCompiledShaders[source] = shader; } HRESULT hr = (device->*setShader)(shader); if (FAILED(hr)) {
--- a/gfx/angle/src/libGLESv2/renderer/d3d/d3d9/Blit9.h +++ b/gfx/angle/src/libGLESv2/renderer/d3d/d3d9/Blit9.h @@ -71,17 +71,17 @@ class Blit9 SHADER_COUNT }; // This actually contains IDirect3DVertexShader9 or IDirect3DPixelShader9 casted to IUnknown. IUnknown *mCompiledShaders[SHADER_COUNT]; template <class D3DShaderType> gl::Error setShader(ShaderId source, const char *profile, - D3DShaderType *(Renderer9::*createShader)(const DWORD *, size_t length), + gl::Error (Renderer9::*createShader)(const DWORD *, size_t length, D3DShaderType **outShader), HRESULT (WINAPI IDirect3DDevice9::*setShader)(D3DShaderType*)); gl::Error setVertexShader(ShaderId shader); gl::Error setPixelShader(ShaderId shader); void render(); void saveState(); void restoreState();
--- a/gfx/angle/src/libGLESv2/renderer/d3d/d3d9/Image9.cpp +++ b/gfx/angle/src/libGLESv2/renderer/d3d/d3d9/Image9.cpp @@ -296,46 +296,46 @@ void Image9::setManagedSurface(IDirect3D SafeRelease(mSurface); } mSurface = surface; mD3DPool = desc.Pool; } } -gl::Error Image9::copyToStorage2D(TextureStorage *storage, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height) +gl::Error Image9::copyToStorage2D(TextureStorage *storage, const gl::ImageIndex &index, const gl::Box ®ion) { ASSERT(getSurface() != NULL); TextureStorage9_2D *storage9 = TextureStorage9_2D::makeTextureStorage9_2D(storage); - IDirect3DSurface9 *destSurface = storage9->getSurfaceLevel(level, true); + IDirect3DSurface9 *destSurface = storage9->getSurfaceLevel(index.mipIndex, true); - gl::Error error = copyToSurface(destSurface, xoffset, yoffset, width, height); + gl::Error error = copyToSurface(destSurface, region.x, region.y, region.width, region.height); SafeRelease(destSurface); return error; } -gl::Error Image9::copyToStorageCube(TextureStorage *storage, int face, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height) +gl::Error Image9::copyToStorageCube(TextureStorage *storage, const gl::ImageIndex &index, const gl::Box ®ion) { ASSERT(getSurface() != NULL); TextureStorage9_Cube *storage9 = TextureStorage9_Cube::makeTextureStorage9_Cube(storage); - IDirect3DSurface9 *destSurface = storage9->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level, true); + IDirect3DSurface9 *destSurface = storage9->getCubeMapSurface(index.type, index.mipIndex, true); - gl::Error error = copyToSurface(destSurface, xoffset, yoffset, width, height); + gl::Error error = copyToSurface(destSurface, region.x, region.y, region.width, region.height); SafeRelease(destSurface); return error; } -gl::Error Image9::copyToStorage3D(TextureStorage *storage, int level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth) +gl::Error Image9::copyToStorage3D(TextureStorage *storage, const gl::ImageIndex &index, const gl::Box ®ion) { // 3D textures are not supported by the D3D9 backend. UNREACHABLE(); return gl::Error(GL_INVALID_OPERATION); } -gl::Error Image9::copyToStorage2DArray(TextureStorage *storage, int level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height) +gl::Error Image9::copyToStorage2DArray(TextureStorage *storage, const gl::ImageIndex &index, const gl::Box ®ion) { // 2D array textures are not supported by the D3D9 backend. UNREACHABLE(); return gl::Error(GL_INVALID_OPERATION); } gl::Error Image9::copyToSurface(IDirect3DSurface9 *destSurface, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height) { @@ -461,29 +461,25 @@ gl::Error Image9::loadCompressedData(GLi reinterpret_cast<uint8_t*>(locked.pBits), locked.Pitch, 0); unlock(); return gl::Error(GL_NO_ERROR); } // This implements glCopyTex[Sub]Image2D for non-renderable internal texture formats and incomplete textures -void Image9::copy(GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source) +void Image9::copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectangle &sourceArea, RenderTarget *source) { + ASSERT(source); + // ES3.0 only behaviour to copy into a 3d texture ASSERT(zoffset == 0); - RenderTarget9 *renderTarget = NULL; + RenderTarget9 *renderTarget = RenderTarget9::makeRenderTarget9(source); IDirect3DSurface9 *surface = NULL; - gl::FramebufferAttachment *colorbuffer = source->getColorbuffer(0); - - if (colorbuffer) - { - renderTarget = d3d9::GetAttachmentRenderTarget(colorbuffer); - } if (renderTarget) { surface = renderTarget->getSurface(); } if (!surface) { @@ -511,18 +507,21 @@ void Image9::copy(GLint xoffset, GLint y if (FAILED(result)) { ERR("GetRenderTargetData unexpectedly failed."); SafeRelease(renderTargetData); SafeRelease(surface); return gl::error(GL_OUT_OF_MEMORY); } - RECT sourceRect = {x, y, x + width, y + height}; - RECT destRect = {xoffset, yoffset, xoffset + width, yoffset + height}; + int width = sourceArea.width; + int height = sourceArea.height; + + RECT sourceRect = { sourceArea.x, sourceArea.y, sourceArea.x + width, sourceArea.y + height }; + RECT destRect = { xoffset, yoffset, xoffset + width, yoffset + height }; D3DLOCKED_RECT sourceLock = {0}; result = renderTargetData->LockRect(&sourceLock, &sourceRect, 0); if (FAILED(result)) { ERR("Failed to lock the source surface (rectangle might be invalid)."); SafeRelease(renderTargetData); @@ -550,40 +549,40 @@ void Image9::copy(GLint xoffset, GLint y switch (description.Format) { case D3DFMT_X8R8G8B8: case D3DFMT_A8R8G8B8: switch(getD3DFormat()) { case D3DFMT_X8R8G8B8: case D3DFMT_A8R8G8B8: - for(int y = 0; y < height; y++) + for (int y = 0; y < height; y++) { memcpy(dest, source, 4 * width); source += sourceLock.Pitch; dest += destLock.Pitch; } break; case D3DFMT_L8: - for(int y = 0; y < height; y++) + for (int y = 0; y < height; y++) { - for(int x = 0; x < width; x++) + for (int x = 0; x < width; x++) { dest[x] = source[x * 4 + 2]; } source += sourceLock.Pitch; dest += destLock.Pitch; } break; case D3DFMT_A8L8: - for(int y = 0; y < height; y++) + for (int y = 0; y < height; y++) { - for(int x = 0; x < width; x++) + for (int x = 0; x < width; x++) { dest[x * 2 + 0] = source[x * 4 + 2]; dest[x * 2 + 1] = source[x * 4 + 3]; } source += sourceLock.Pitch; dest += destLock.Pitch; } @@ -591,77 +590,77 @@ void Image9::copy(GLint xoffset, GLint y default: UNREACHABLE(); } break; case D3DFMT_R5G6B5: switch(getD3DFormat()) { case D3DFMT_X8R8G8B8: - for(int y = 0; y < height; y++) + for (int y = 0; y < height; y++) { - for(int x = 0; x < width; x++) + for (int x = 0; x < width; x++) { unsigned short rgb = ((unsigned short*)source)[x]; unsigned char red = (rgb & 0xF800) >> 8; unsigned char green = (rgb & 0x07E0) >> 3; unsigned char blue = (rgb & 0x001F) << 3; dest[x + 0] = blue | (blue >> 5); dest[x + 1] = green | (green >> 6); dest[x + 2] = red | (red >> 5); dest[x + 3] = 0xFF; } source += sourceLock.Pitch; dest += destLock.Pitch; } break; case D3DFMT_L8: - for(int y = 0; y < height; y++) + for (int y = 0; y < height; y++) { - for(int x = 0; x < width; x++) + for (int x = 0; x < width; x++) { unsigned char red = source[x * 2 + 1] & 0xF8; dest[x] = red | (red >> 5); } source += sourceLock.Pitch; dest += destLock.Pitch; } break; default: UNREACHABLE(); } break; case D3DFMT_A1R5G5B5: - switch(getD3DFormat()) + switch (getD3DFormat()) { case D3DFMT_X8R8G8B8: - for(int y = 0; y < height; y++) + for (int y = 0; y < height; y++) { - for(int x = 0; x < width; x++) + for (int x = 0; x < width; x++) { unsigned short argb = ((unsigned short*)source)[x]; unsigned char red = (argb & 0x7C00) >> 7; unsigned char green = (argb & 0x03E0) >> 2; unsigned char blue = (argb & 0x001F) << 3; dest[x + 0] = blue | (blue >> 5); dest[x + 1] = green | (green >> 5); dest[x + 2] = red | (red >> 5); dest[x + 3] = 0xFF; } source += sourceLock.Pitch; dest += destLock.Pitch; } break; case D3DFMT_A8R8G8B8: - for(int y = 0; y < height; y++) + for (int y = 0; y < height; y++) { - for(int x = 0; x < width; x++) + for (int x = 0; x < width; x++) { unsigned short argb = ((unsigned short*)source)[x]; unsigned char red = (argb & 0x7C00) >> 7; unsigned char green = (argb & 0x03E0) >> 2; unsigned char blue = (argb & 0x001F) << 3; unsigned char alpha = (signed short)argb >> 15; dest[x + 0] = blue | (blue >> 5); dest[x + 1] = green | (green >> 5); @@ -669,32 +668,32 @@ void Image9::copy(GLint xoffset, GLint y dest[x + 3] = alpha; } source += sourceLock.Pitch; dest += destLock.Pitch; } break; case D3DFMT_L8: - for(int y = 0; y < height; y++) + for (int y = 0; y < height; y++) { - for(int x = 0; x < width; x++) + for (int x = 0; x < width; x++) { unsigned char red = source[x * 2 + 1] & 0x7C; dest[x] = (red << 1) | (red >> 4); } source += sourceLock.Pitch; dest += destLock.Pitch; } break; case D3DFMT_A8L8: - for(int y = 0; y < height; y++) + for (int y = 0; y < height; y++) { - for(int x = 0; x < width; x++) + for (int x = 0; x < width; x++) { unsigned char red = source[x * 2 + 1] & 0x7C; dest[x * 2 + 0] = (red << 1) | (red >> 4); dest[x * 2 + 1] = (signed char)source[x * 2 + 1] >> 7; } source += sourceLock.Pitch; dest += destLock.Pitch; @@ -713,9 +712,15 @@ void Image9::copy(GLint xoffset, GLint y renderTargetData->UnlockRect(); SafeRelease(renderTargetData); SafeRelease(surface); mDirty = true; } +void Image9::copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectangle &area, const gl::ImageIndex &srcIndex, TextureStorage *srcStorage) +{ + // Currently unreachable, due to only being used in a D3D11-only workaround + UNIMPLEMENTED(); } + +}
--- a/gfx/angle/src/libGLESv2/renderer/d3d/d3d9/Image9.h +++ b/gfx/angle/src/libGLESv2/renderer/d3d/d3d9/Image9.h @@ -39,27 +39,29 @@ class Image9 : public ImageD3D D3DFORMAT getD3DFormat() const; virtual bool isDirty() const; IDirect3DSurface9 *getSurface(); virtual void setManagedSurface2D(TextureStorage *storage, int level); virtual void setManagedSurfaceCube(TextureStorage *storage, int face, int level); - virtual gl::Error copyToStorage2D(TextureStorage *storage, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height); - virtual gl::Error copyToStorageCube(TextureStorage *storage, int face, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height); - virtual gl::Error copyToStorage3D(TextureStorage *storage, int level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth); - virtual gl::Error copyToStorage2DArray(TextureStorage *storage, int level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height); + virtual gl::Error copyToStorage2D(TextureStorage *storage, const gl::ImageIndex &index, const gl::Box ®ion); + virtual gl::Error copyToStorageCube(TextureStorage *storage, const gl::ImageIndex &index, const gl::Box ®ion); + virtual gl::Error copyToStorage3D(TextureStorage *storage, const gl::ImageIndex &index, const gl::Box ®ion); + virtual gl::Error copyToStorage2DArray(TextureStorage *storage, const gl::ImageIndex &index, const gl::Box ®ion); virtual gl::Error loadData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLint unpackAlignment, GLenum type, const void *input); virtual gl::Error loadCompressedData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, const void *input); - virtual void copy(GLint xoffset, GLint yoffset, GLint zoffset,GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source); + virtual void copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectangle &sourceArea, RenderTarget *source); + virtual void copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectangle &sourceArea, + const gl::ImageIndex &sourceIndex, TextureStorage *source); private: DISALLOW_COPY_AND_ASSIGN(Image9); void createSurface(); void setManagedSurface(IDirect3DSurface9 *surface); gl::Error copyToSurface(IDirect3DSurface9 *dest, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height);
--- a/gfx/angle/src/libGLESv2/renderer/d3d/d3d9/Renderer9.cpp +++ b/gfx/angle/src/libGLESv2/renderer/d3d/d3d9/Renderer9.cpp @@ -28,16 +28,17 @@ #include "libGLESv2/renderer/d3d/TransformFeedbackD3D.h" #include "libGLESv2/main.h" #include "libGLESv2/Buffer.h" #include "libGLESv2/Texture.h" #include "libGLESv2/Framebuffer.h" #include "libGLESv2/FramebufferAttachment.h" #include "libGLESv2/Renderbuffer.h" #include "libGLESv2/ProgramBinary.h" +#include "libGLESv2/State.h" #include "libGLESv2/angletypes.h" #include "libEGL/Display.h" #include "common/utilities.h" #include "third_party/trace_event/trace_event.h" @@ -560,24 +561,24 @@ void Renderer9::freeEventQuery(IDirect3D SafeRelease(query); } else { mEventQueryPool.push_back(query); } } -IDirect3DVertexShader9 *Renderer9::createVertexShader(const DWORD *function, size_t length) +gl::Error Renderer9::createVertexShader(const DWORD *function, size_t length, IDirect3DVertexShader9 **outShader) { - return mVertexShaderCache.create(function, length); + return mVertexShaderCache.create(function, length, outShader); } -IDirect3DPixelShader9 *Renderer9::createPixelShader(const DWORD *function, size_t length) +gl::Error Renderer9::createPixelShader(const DWORD *function, size_t length, IDirect3DPixelShader9 **outShader) { - return mPixelShaderCache.create(function, length); + return mPixelShaderCache.create(function, length, outShader); } HRESULT Renderer9::createVertexBuffer(UINT Length, DWORD Usage, IDirect3DVertexBuffer9 **ppVertexBuffer) { D3DPOOL Pool = getBufferPool(Usage); return mDevice->CreateVertexBuffer(Length, Usage, 0, Pool, ppVertexBuffer, NULL); } @@ -1263,27 +1264,26 @@ gl::Error Renderer9::applyRenderTarget(g mRenderTargetDesc.height = attachment->getHeight(); mRenderTargetDesc.format = attachment->getActualFormat(); mRenderTargetDescInitialized = true; } return gl::Error(GL_NO_ERROR); } -gl::Error Renderer9::applyVertexBuffer(gl::ProgramBinary *programBinary, const gl::VertexAttribute vertexAttributes[], const gl::VertexAttribCurrentValueData currentValues[], - GLint first, GLsizei count, GLsizei instances) +gl::Error Renderer9::applyVertexBuffer(const gl::State &state, GLint first, GLsizei count, GLsizei instances) { TranslatedAttribute attributes[gl::MAX_VERTEX_ATTRIBS]; - gl::Error error = mVertexDataManager->prepareVertexData(vertexAttributes, currentValues, programBinary, first, count, attributes, instances); + gl::Error error = mVertexDataManager->prepareVertexData(state, first, count, attributes, instances); if (error.isError()) { return error; } - return mVertexDeclarationCache.applyDeclaration(mDevice, attributes, programBinary, instances, &mRepeatDraw); + return mVertexDeclarationCache.applyDeclaration(mDevice, attributes, state.getCurrentProgramBinary(), instances, &mRepeatDraw); } // Applies the indices and element array bindings to the Direct3D 9 device gl::Error Renderer9::applyIndexBuffer(const GLvoid *indices, gl::Buffer *elementArrayBuffer, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo) { gl::Error error = mIndexDataManager->prepareIndexData(type, count, elementArrayBuffer, indices, indexInfo); if (error.isError()) { @@ -1299,17 +1299,17 @@ gl::Error Renderer9::applyIndexBuffer(co mDevice->SetIndices(indexBuffer->getBuffer()); mAppliedIBSerial = indexInfo->serial; } return gl::Error(GL_NO_ERROR); } -void Renderer9::applyTransformFeedbackBuffers(gl::Buffer *transformFeedbackBuffers[], GLintptr offsets[]) +void Renderer9::applyTransformFeedbackBuffers(const gl::State& state) { UNREACHABLE(); } gl::Error Renderer9::drawArrays(GLenum mode, GLsizei count, GLsizei instances, bool transformFeedbackActive) { ASSERT(!transformFeedbackActive); @@ -1666,18 +1666,30 @@ gl::Error Renderer9::getCountingIB(size_ gl::Error Renderer9::applyShaders(gl::ProgramBinary *programBinary, const gl::VertexFormat inputLayout[], const gl::Framebuffer *framebuffer, bool rasterizerDiscard, bool transformFeedbackActive) { ASSERT(!transformFeedbackActive); ASSERT(!rasterizerDiscard); ProgramD3D *programD3D = ProgramD3D::makeProgramD3D(programBinary->getImplementation()); - ShaderExecutable *vertexExe = programD3D->getVertexExecutableForInputLayout(inputLayout); - ShaderExecutable *pixelExe = programD3D->getPixelExecutableForFramebuffer(framebuffer); + + ShaderExecutable *vertexExe = NULL; + gl::Error error = programD3D->getVertexExecutableForInputLayout(inputLayout, &vertexExe); + if (error.isError()) + { + return error; + } + + ShaderExecutable *pixelExe = NULL; + error = programD3D->getPixelExecutableForFramebuffer(framebuffer, &pixelExe); + if (error.isError()) + { + return error; + } IDirect3DVertexShader9 *vertexShader = (vertexExe ? ShaderExecutable9::makeShaderExecutable9(vertexExe)->getVertexShader() : NULL); IDirect3DPixelShader9 *pixelShader = (pixelExe ? ShaderExecutable9::makeShaderExecutable9(pixelExe)->getPixelShader() : NULL); if (vertexShader != mAppliedVertexShader) { mDevice->SetVertexShader(vertexShader); mAppliedVertexShader = vertexShader; @@ -2786,72 +2798,75 @@ ProgramImpl *Renderer9::createProgram() return new ProgramD3D(this); } void Renderer9::releaseShaderCompiler() { ShaderD3D::releaseCompiler(); } -ShaderExecutable *Renderer9::loadExecutable(const void *function, size_t length, rx::ShaderType type, - const std::vector<gl::LinkedVarying> &transformFeedbackVaryings, - bool separatedOutputBuffers) +gl::Error Renderer9::loadExecutable(const void *function, size_t length, rx::ShaderType type, + const std::vector<gl::LinkedVarying> &transformFeedbackVaryings, + bool separatedOutputBuffers, ShaderExecutable **outExecutable) { // Transform feedback is not supported in ES2 or D3D9 ASSERT(transformFeedbackVaryings.size() == 0); - ShaderExecutable9 *executable = NULL; - switch (type) { case rx::SHADER_VERTEX: { - IDirect3DVertexShader9 *vshader = createVertexShader((DWORD*)function, length); - if (vshader) + IDirect3DVertexShader9 *vshader = NULL; + gl::Error error = createVertexShader((DWORD*)function, length, &vshader); + if (error.isError()) { - executable = new ShaderExecutable9(function, length, vshader); + return error; } + *outExecutable = new ShaderExecutable9(function, length, vshader); } break; case rx::SHADER_PIXEL: { - IDirect3DPixelShader9 *pshader = createPixelShader((DWORD*)function, length); - if (pshader) + IDirect3DPixelShader9 *pshader = NULL; + gl::Error error = createPixelShader((DWORD*)function, length, &pshader); + if (error.isError()) { - executable = new ShaderExecutable9(function, length, pshader); + return error; } + *outExecutable = new ShaderExecutable9(function, length, pshader); } break; default: UNREACHABLE(); - break; + return gl::Error(GL_INVALID_OPERATION); } - return executable; + return gl::Error(GL_NO_ERROR); } -ShaderExecutable *Renderer9::compileToExecutable(gl::InfoLog &infoLog, const std::string &shaderHLSL, rx::ShaderType type, - const std::vector<gl::LinkedVarying> &transformFeedbackVaryings, - bool separatedOutputBuffers, D3DWorkaroundType workaround) +gl::Error Renderer9::compileToExecutable(gl::InfoLog &infoLog, const std::string &shaderHLSL, rx::ShaderType type, + const std::vector<gl::LinkedVarying> &transformFeedbackVaryings, + bool separatedOutputBuffers, D3DWorkaroundType workaround, + ShaderExecutable **outExectuable) { // Transform feedback is not supported in ES2 or D3D9 ASSERT(transformFeedbackVaryings.size() == 0); const char *profileType = NULL; switch (type) { case rx::SHADER_VERTEX: profileType = "vs"; break; case rx::SHADER_PIXEL: profileType = "ps"; break; default: UNREACHABLE(); - return NULL; + return gl::Error(GL_INVALID_OPERATION); } unsigned int profileMajorVersion = (getMajorShaderModel() >= 3) ? 3 : 2; unsigned int profileMinorVersion = 0; std::string profile = FormatString("%s_%u_%u", profileType, profileMajorVersion, profileMinorVersion); UINT flags = ANGLE_COMPILE_OPTIMIZATION_LEVEL; if (workaround == ANGLE_D3D_WORKAROUND_SKIP_OPTIMIZATION) @@ -2875,27 +2890,40 @@ ShaderExecutable *Renderer9::compileToEx // Sometimes D3DCompile will fail with the default compilation flags for complicated shaders when it would otherwise pass with alternative options. // Try the default flags first and if compilation fails, try some alternatives. std::vector<CompileConfig> configs; configs.push_back(CompileConfig(flags, "default" )); configs.push_back(CompileConfig(flags | D3DCOMPILE_AVOID_FLOW_CONTROL, "avoid flow control" )); configs.push_back(CompileConfig(flags | D3DCOMPILE_PREFER_FLOW_CONTROL, "prefer flow control")); - ID3DBlob *binary = mCompiler.compileToBinary(infoLog, shaderHLSL, profile, configs); + ID3DBlob *binary = NULL; + gl::Error error = mCompiler.compileToBinary(infoLog, shaderHLSL, profile, configs, &binary); + if (error.isError()) + { + return error; + } + + // It's possible that binary is NULL if the compiler failed in all configurations. Set the executable to NULL + // and return GL_NO_ERROR to signify that there was a link error but the internal state is still OK. if (!binary) { - return NULL; + *outExectuable = NULL; + return gl::Error(GL_NO_ERROR); } - ShaderExecutable *executable = loadExecutable(binary->GetBufferPointer(), binary->GetBufferSize(), type, - transformFeedbackVaryings, separatedOutputBuffers); + error = loadExecutable(binary->GetBufferPointer(), binary->GetBufferSize(), type, + transformFeedbackVaryings, separatedOutputBuffers, outExectuable); SafeRelease(binary); - - return executable; + if (error.isError()) + { + return error; + } + + return gl::Error(GL_NO_ERROR); } rx::UniformStorage *Renderer9::createUniformStorage(size_t storageSize) { return new UniformStorage(storageSize); } gl::Error Renderer9::boxFilter(IDirect3DSurface9 *source, IDirect3DSurface9 *dest)
--- a/gfx/angle/src/libGLESv2/renderer/d3d/d3d9/Renderer9.h +++ b/gfx/angle/src/libGLESv2/renderer/d3d/d3d9/Renderer9.h @@ -51,18 +51,18 @@ class Renderer9 : public Renderer virtual void sync(bool block); virtual SwapChain *createSwapChain(rx::NativeWindow nativeWindow, HANDLE shareHandle, GLenum backBufferFormat, GLenum depthBufferFormat); IDirect3DQuery9* allocateEventQuery(); void freeEventQuery(IDirect3DQuery9* query); // resource creation - IDirect3DVertexShader9 *createVertexShader(const DWORD *function, size_t length); - IDirect3DPixelShader9 *createPixelShader(const DWORD *function, size_t length); + gl::Error createVertexShader(const DWORD *function, size_t length, IDirect3DVertexShader9 **outShader); + gl::Error createPixelShader(const DWORD *function, size_t length, IDirect3DPixelShader9 **outShader); HRESULT createVertexBuffer(UINT Length, DWORD Usage, IDirect3DVertexBuffer9 **ppVertexBuffer); HRESULT createIndexBuffer(UINT Length, DWORD Usage, D3DFORMAT Format, IDirect3DIndexBuffer9 **ppIndexBuffer); virtual gl::Error generateSwizzle(gl::Texture *texture); virtual gl::Error setSamplerState(gl::SamplerType type, int index, const gl::SamplerState &sampler); virtual gl::Error setTexture(gl::SamplerType type, int index, gl::Texture *texture); virtual gl::Error setUniformBuffers(const gl::Buffer *vertexUniformBuffers[], const gl::Buffer *fragmentUniformBuffers[]); @@ -76,21 +76,20 @@ class Renderer9 : public Renderer virtual void setViewport(const gl::Rectangle &viewport, float zNear, float zFar, GLenum drawMode, GLenum frontFace, bool ignoreViewport); virtual gl::Error applyRenderTarget(gl::Framebuffer *frameBuffer); virtual gl::Error applyShaders(gl::ProgramBinary *programBinary, const gl::VertexFormat inputLayout[], const gl::Framebuffer *framebuffer, bool rasterizerDiscard, bool transformFeedbackActive); virtual gl::Error applyUniforms(const ProgramImpl &program, const std::vector<gl::LinkedUniform*> &uniformArray); virtual bool applyPrimitiveType(GLenum primitiveType, GLsizei elementCount); - virtual gl::Error applyVertexBuffer(gl::ProgramBinary *programBinary, const gl::VertexAttribute vertexAttributes[], const gl::VertexAttribCurrentValueData currentValues[], - GLint first, GLsizei count, GLsizei instances); + virtual gl::Error applyVertexBuffer(const gl::State &state, GLint first, GLsizei count, GLsizei instances); virtual gl::Error applyIndexBuffer(const GLvoid *indices, gl::Buffer *elementArrayBuffer, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo); - virtual void applyTransformFeedbackBuffers(gl::Buffer *transformFeedbackBuffers[], GLintptr offsets[]); + virtual void applyTransformFeedbackBuffers(const gl::State& state); virtual gl::Error drawArrays(GLenum mode, GLsizei count, GLsizei instances, bool transformFeedbackActive); virtual gl::Error drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, gl::Buffer *elementArrayBuffer, const TranslatedIndexData &indexInfo, GLsizei instances); virtual gl::Error clear(const gl::ClearParameters &clearParams, gl::Framebuffer *frameBuffer); virtual void markAllStateDirty(); @@ -139,22 +138,23 @@ class Renderer9 : public Renderer virtual RenderTarget *createRenderTarget(int width, int height, GLenum format, GLsizei samples); // Shader creation virtual ShaderImpl *createShader(GLenum type); virtual ProgramImpl *createProgram(); // Shader operations virtual void releaseShaderCompiler(); - virtual ShaderExecutable *loadExecutable(const void *function, size_t length, rx::ShaderType type, - const std::vector<gl::LinkedVarying> &transformFeedbackVaryings, - bool separatedOutputBuffers); - virtual ShaderExecutable *compileToExecutable(gl::InfoLog &infoLog, const std::string &shaderHLSL, rx::ShaderType type, - const std::vector<gl::LinkedVarying> &transformFeedbackVaryings, - bool separatedOutputBuffers, D3DWorkaroundType workaround); + virtual gl::Error loadExecutable(const void *function, size_t length, rx::ShaderType type, + const std::vector<gl::LinkedVarying> &transformFeedbackVaryings, + bool separatedOutputBuffers, ShaderExecutable **outExecutable); + virtual gl::Error compileToExecutable(gl::InfoLog &infoLog, const std::string &shaderHLSL, rx::ShaderType type, + const std::vector<gl::LinkedVarying> &transformFeedbackVaryings, + bool separatedOutputBuffers, D3DWorkaroundType workaround, + ShaderExecutable **outExectuable); virtual UniformStorage *createUniformStorage(size_t storageSize); // Image operations virtual Image *createImage(); virtual void generateMipmap(Image *dest, Image *source); virtual TextureStorage *createTextureStorage2D(SwapChain *swapChain); virtual TextureStorage *createTextureStorage2D(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, int levels); virtual TextureStorage *createTextureStorageCube(GLenum internalformat, bool renderTarget, int size, int levels);
--- a/gfx/angle/src/libGLESv2/renderer/d3d/d3d9/ShaderCache.h +++ b/gfx/angle/src/libGLESv2/renderer/d3d/d3d9/ShaderCache.h @@ -5,16 +5,18 @@ // // ShaderCache: Defines rx::ShaderCache, a cache of Direct3D shader objects // keyed by their byte code. #ifndef LIBGLESV2_RENDERER_SHADER_CACHE_H_ #define LIBGLESV2_RENDERER_SHADER_CACHE_H_ +#include "libGLESv2/Error.h" + #include "common/debug.h" #include <cstddef> #include <unordered_map> #include <string> namespace rx { @@ -32,44 +34,46 @@ class ShaderCache ASSERT(mMap.empty()); } void initialize(IDirect3DDevice9* device) { mDevice = device; } - ShaderObject *create(const DWORD *function, size_t length) + gl::Error create(const DWORD *function, size_t length, ShaderObject **outShaderObject) { std::string key(reinterpret_cast<const char*>(function), length); typename Map::iterator it = mMap.find(key); if (it != mMap.end()) { it->second->AddRef(); - return it->second; + *outShaderObject = it->second; + return gl::Error(GL_NO_ERROR); } ShaderObject *shader; HRESULT result = createShader(function, &shader); if (FAILED(result)) { - return NULL; + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create shader, result: 0x%X.", result); } // Random eviction policy. if (mMap.size() >= kMaxMapSize) { SafeRelease(mMap.begin()->second); mMap.erase(mMap.begin()); } shader->AddRef(); mMap[key] = shader; - return shader; + *outShaderObject = shader; + return gl::Error(GL_NO_ERROR); } void clear() { for (typename Map::iterator it = mMap.begin(); it != mMap.end(); ++it) { SafeRelease(it->second); }
--- a/gfx/angle/src/libGLESv2/renderer/d3d/d3d9/TextureStorage9.cpp +++ b/gfx/angle/src/libGLESv2/renderer/d3d/d3d9/TextureStorage9.cpp @@ -82,16 +82,23 @@ int TextureStorage9::getTopLevel() const return mTopLevel; } int TextureStorage9::getLevelCount() const { return getBaseTexture() ? (getBaseTexture()->GetLevelCount() - getTopLevel()) : 0; } +gl::Error TextureStorage9::setData(const gl::ImageIndex &index, const gl::Box &sourceBox, GLenum internalFormat, GLenum type, + const gl::PixelUnpackState &unpack, const uint8_t *pixelData) +{ + UNREACHABLE(); + return gl::Error(GL_INVALID_OPERATION); +} + TextureStorage9_2D::TextureStorage9_2D(Renderer *renderer, SwapChain9 *swapchain) : TextureStorage9(renderer, D3DUSAGE_RENDERTARGET) { IDirect3DTexture9 *surfaceTexture = swapchain->getOffscreenTexture(); mTexture = surfaceTexture; mRenderTarget = NULL; initializeRenderTarget();
--- a/gfx/angle/src/libGLESv2/renderer/d3d/d3d9/TextureStorage9.h +++ b/gfx/angle/src/libGLESv2/renderer/d3d/d3d9/TextureStorage9.h @@ -37,16 +37,19 @@ class TextureStorage9 : public TextureSt virtual RenderTarget *getRenderTarget(const gl::ImageIndex &index) = 0; virtual void generateMipmap(const gl::ImageIndex &sourceIndex, const gl::ImageIndex &destIndex) = 0; virtual int getTopLevel() const; virtual bool isRenderTarget() const;