We can discard frames from an animated image if the memory footprint
exceeds the threshold. This will cause us to redecode frames on demand
instead. However decoders can fail to produce the same results on
subsequent runs due to differences in memory pressure, etc. If this
happens our state can get inconsistent. In particular, if we keep
failing on the first frame, we end up in an infinite loop on the decoder
thread.
Since we don't have the owning image to signal, as we had to release our
reference to it after the first pass, we can do little but stop decoding.
From the user's perspective, the animation will come to a stop.
If an imgCacheValidator object is destroyed without calling
imgCacheValidator::OnStartRequest, or imgRequest::Init fails in
OnStartRequest, we left the bound proxies hanging on an update. Now we
cancel the new request, and bind the validating proxies to said request
to ensure their listeners fail gracefully.
We can discard frames from an animated image if the memory footprint
exceeds the threshold. This will cause us to redecode frames on demand
instead. However decoders can fail to produce the same results on
subsequent runs due to differences in memory pressure, etc. If this
happens our state can get inconsistent. In particular, if we keep
failing on the first frame, we end up in an infinite loop on the decoder
thread.
Since we don't have the owning image to signal, as we had to release our
reference to it after the first pass, we can do little but stop decoding.
From the user's perspective, the animation will come to a stop.
Many of these could probably be fuzzed but in the interests of getting
the reftest suite turned on sooner I'm doing a blanket fails-if. This
covers all the reftests where there is more fuzz with webrender on
windows than any of existing annotations account for. In some cases the
fuzz is only a few pixels more than the equivalent Linux fuzz already
annotated, but I'll clean that up in a future bug.
MozReview-Commit-ID: IaKarbnL46d
--HG--
extra : rebase_source : 71889340305b0b12fa8eace722e42bb3faf14419
NullPrincipal::Create() (will null OA) may cause an OriginAttributes bypass.
We change Create() so OriginAttributes is no longer optional, and rename
Create() with no arguments to make it more explicit about what the caller is doing.
MozReview-Commit-ID: 7DQGlgh1tgJ
When we shutdown the decode pool threads, it does not do a simple join
with the main thread. It will actually process the main thread event
loop, which can cause a bad series of events. The refresh tick could
still be running and advancing our animated images, causing the animated
decoders to continue running, which in turn prevents the decoder threads
from finishing shutting down, and the main thread from joining them.
Now we check on each frame whether or not the decoder should just stop
decoding more frames because the decode pool has started shutdown. If it
has, it will stop immediately.
We should only attempt to discard animation image frames after passing
the frame threshold on the very first pass on the animation. Redecodes
are already in the correct state, as it will discard frames as it
advances the animation. This patch makes it clear what it should be
doing when, but there should be no functional change.
* Deserialization now only happens via a mutator
* The CID for URI implementations actually returns the nsIURIMutator for each class
* The QueryInterface of mutators implementing nsISerializable will now act as a finalizer if passed the IID of an interface implemented by the URI it holds
MozReview-Commit-ID: H5MUJOEkpia
--HG--
extra : rebase_source : 01c8d16f7d31977eda6ca061e7889cedbf6940c2
* Deserialization now only happens via a mutator
* The CID for URI implementations actually returns the nsIURIMutator for each class
* The QueryInterface of mutators implementing nsISerializable will now act as a finalizer if passed the IID of an interface implemented by the URI it holds
MozReview-Commit-ID: H5MUJOEkpia
--HG--
extra : rebase_source : 8ebb459445cab23288a6c4c86e4e00c6ee611e34
After decoding the first frame we allocate the second frame, but before it finishes we encounter an error, Decoder::PostError is called it aborts the second frame and decrements the frame count. But AnimationSurfaceProvider::CheckForFrameAtTerminalState just asks for the current frame ref from the decoder (which it never cleared) and inserts that.
The condition that we use from the decoder to decide to report a new frame is mFinishedNewFrame (via TakeCompleteFrameCount), however this doesn't directly correspond to mFrameCount. So we create a new bool on the Decoder to track when there is a frame that we can take.
This didn't cause any problems before but now we have tighter coupling between the list of frames the AnimationSurfaceProvider has and what FrameAnimator expects.
Another possible fix would be to clear the current frame ref in PostError, but the only place we clear the current frame is when we allocate the new frame and we have the mImageData pointer still around that decoders could theorhetically use to do final processing on the last partial frame.
These threads should not have deep stacks, and as we can have a number
of them running simultaneously, it's beneficial to set the stack size to
something reasonably low.
When cloning an animated image decoder, we asserted that
Decoder::HasAnimation was true. This is incorrect because if the decoder
has yet to complete the metadata decoding, or it has but only finds out
the image is animated when it discovers the second frame, then we will
try to clone a valid animated image decoder, but fail the assertion.
Instead, this patch verifies the image type supports animations.
With the previous parts, for large animated images, we will now discard
previous frames after we reach the threshold. This mochitest configures
a very low threshold, such that it will trigger on a small animated
image. It then verifies that we are already to loop the animation a
couple of times.
When we need to recreate an animated image decoder because it was
discarded, the animation may have progressed beyond the first frame.
Given that later in the patch series we need FrameAnimator to be driving
the decoding more actively, it simplifies its role by making it assume
the initial state of the decoder matches its initial state. Passing in
the currently displayed frame allows the decoder to advance its frame
buffer (and potentially discard unnecessary frames), such that when the
animation actually wants to advance as it normally would, the decoder
state matches what it would have been if it had never been discarded.
Note that AnimationSurfaceProvider will override these methods to give a
proper implementation in a later patch in this series. For now, they are
mostly stubbed, using the default implementation from ISurfaceProvider.
They focus on the main operations we perform on an animation:
1) Progressing through the animation, e.g. advancing a frame. If we
don't decode the whole animation up front, we need to know at the
decoder level where we are in the display of the animation.
2) Restarting an animation from the beginning. This is a specialized
case of the above, where we want to skip explicitly advancing through
the remaining frames and instead restart at the beginning. The decoder
may have already discarded the earliest frames and must start redecoding
them.
3) Knowing whether or not the decoder is still active, e.g. can we be
missing frames.
Later in the patch series, we use the new APIs to facilitate cloning of
an existing decoder. This is useful when you want to redecode the same
image with the exact same configuration but from the very beginning.
The shared memory handle reporting has been generalized to be an
external handle reporting. This is used for both shared memory, and for
volatile memory (on Android.) This will allow us to have a better sense
of just how many handles are being used by images on Android.
Additionally we were not properly reporting forced heap allocated
memory, if we were putting animated frames on the heap. This is because
we used SourceSurfaceAlignedRawData without implementing
AddSizeOfExcludingThis.
image.mem.volatile.min_threshold_kb is the minimum buffer allocation for
an image frame in KB before it will use volatile memory. If it is less
than it will use the heap. This only is set to > 0 on Android.
image.mem.animated.use_heap forces image frames to use the heap if it is
for an animated image. This is only enabled for Android, and was
previously a compile time option also for Android.
Move the initialization of SharedSurfacesParent from the compositor
thread creation to mirror the other WebRender-specific components, such
as the render thread creation. Now it will only be created if WebRender
is in use. Also prevent shared surfaces from being used by the image
frame allocator, even if image.mem.shared is set -- there is no purpose
in allowing this at present. It was causing startup crashes for users
who requested image.mem.shared and/or WebRender via gfx.webrender.all
but did not actually get WebRender at all. Surfaces would get allocated
in the shared memory, try to register themselves with the WR render
thread, and then crash since that thread was never created.
The image decoding thread pool can grow to be quite large, up to 32
threads, depending on the number of processors on the system. If the
user is not actively browsing, these threads are occupying resources
which could be reused elsewhere. After the timeout period, it will
release up to half of the threads in the pool.
Currently imagelib's DecodePool spawns the maximum number of threads
during startup, based on the number of processors. This patch changes it
to spawn a single thread on startup (which cannot fail), and more up to
the maximum as jobs are added to the queue. A thread will only be
spawned if there is a backlog present when a new job is added. This
typically results in fewer threads allocated in the parent process, as
well as deferred spawning in the content processes.
Originally we attempted to finalize the current frame from the contained
decoder in nsICODecoder::FinishResource. This is wrong because we
haven't acquired the frame from the contained decoder yet. This happens
in nsICODecoder::GetFinalStateFromContainedDecoder, and so
imgFrame::Finalize call should be moved there. This was causing us to
use fallback image sharing with WebRender after a GPU process crash,
instead of shared surfaces, because it can't get a new file handle for
the surface data until we have finished writing all of the image data.
Move the initialization of SharedSurfacesParent from the compositor
thread creation to mirror the other WebRender-specific components, such
as the render thread creation. Now it will only be created if WebRender
is in use. Also prevent shared surfaces from being used by the image
frame allocator, even if image.mem.shared is set -- there is no purpose
in allowing this at present. It was causing startup crashes for users
who requested image.mem.shared and/or WebRender via gfx.webrender.all
but did not actually get WebRender at all. Surfaces would get allocated
in the shared memory, try to register themselves with the WR render
thread, and then crash since that thread was never created.
Originally image decoding tasks were processed in a FILO ordering, due
to that being the most efficient way to use an nsTArray as a queue. This
patch changes the decoding pool to use an std::queue to promise FIFO
ordering (relative to the priority of the tasks). This will allow the
first images to be requested to be the first images displayed.
The image decoding thread pool can grow to be quite large, up to 32
threads, depending on the number of processors on the system. If the
user is not actively browsing, these threads are occupying resources
which could be reused elsewhere. After the timeout period, it will
release up to half of the threads in the pool.
Currently imagelib's DecodePool spawns the maximum number of threads
during startup, based on the number of processors. This patch changes it
to spawn a single thread on startup (which cannot fail), and more up to
the maximum as jobs are added to the queue. A thread will only be
spawned if there is a backlog present when a new job is added. This
typically results in fewer threads allocated in the parent process, as
well as deferred spawning in the content processes.
The change to RootAccessible.cpp fixes an obvious bug introduced in bug 741707.
The visibility changes in gfx/thebes are because NS_DECL_ISUPPORTS has a
trailing "public:" that those classes were relying on to have public
constructors.
MozReview-Commit-ID: IeB8KIJCGhU
In order to reduce the log size, increase the snapshot polling timeout
from 1ms to 20ms. Additionally use SimpleTest.requestCompleteLog() to
ensure we get everything when the test eventually fails.
If there is an active provider which has yet to produce a frame, any
calls to SurfaceCache::Lookup will return MatchType::PENDING. If
RasterImage::Lookup gets the above result while given FLAG_SYNC_DECODE,
it will attempt to start a new decoder. It is entirely possible that
when we try to insert the new provider into the SurfaceCache, it cannot
because the original provider finally did produce something. In that
case we should abandon attempting to redecode and retry our lookup.
These asserts are somewhat faulty given the
image.downscale-during-decode.enabled preference is a live preference
and thus can change at any time. Given the decision to downscale is made
on the main thread, and it is asserted on a decoder thread, this will
always be inherently racy. Most of the time this isn't a problem, but
with our automated tests, we frequently flip this preference, and the
assertion may fail unnecessarily with an unrelated image. The reftests
themselves verify downscaling did or did not occur based upon comparison
to the reference, and don't require the assert for verification.
There are two other means from which a caller can get the current state
which originally ignored validation -- GetImageStatus and
StartDecodingWithResult. These methods are used by layout in some
circumstances to decide whether or not the image is ready to display. As
observed in some web platform tests, in particular
css/css-backgrounds-3/background-size-031.html, we may actually validate
and purge the cache for images under test. The state given by the
aforementioned methods was misleading, because validation changed it.
Now they take into account validation, and do not imply any particular
state while validation is in progress.
IProgressObserver::SetNotificationsDeferred is now used just for
ProgressTracker to track when there is a pending notification for
an observer. It has been renamed to MarkPendingNotify and
ClearPendingNotify to make a clear distinction.
When cache validation is in progress, imgRequestProxy defers its
notifications to its listener until the validation is complete. This is
because the cache may be discarded, and the current state will change.
It attempted to share the same flags with notification deferrals used by
ProgressTracker to indicate that there is a pending notification, but
this has problematic/confusing. Hence this patch creates dedicated flags
for notification deferrals due to cache validation.
This patch was autogenerated by my decomponents.py
It covers almost every file with the extension js, jsm, html, py,
xhtml, or xul.
It removes blank lines after removed lines, when the removed lines are
preceded by either blank lines or the start of a new block. The "start
of a new block" is defined fairly hackily: either the line starts with
//, ends with */, ends with {, <![CDATA[, """ or '''. The first two
cover comments, the third one covers JS, the fourth covers JS embedded
in XUL, and the final two cover JS embedded in Python. This also
applies if the removed line was the first line of the file.
It covers the pattern matching cases like "var {classes: Cc,
interfaces: Ci, utils: Cu, results: Cr} = Components;". It'll remove
the entire thing if they are all either Ci, Cr, Cc or Cu, or it will
remove the appropriate ones and leave the residue behind. If there's
only one behind, then it will turn it into a normal, non-pattern
matching variable definition. (For instance, "const { classes: Cc,
Constructor: CC, interfaces: Ci, utils: Cu } = Components" becomes
"const CC = Components.Constructor".)
MozReview-Commit-ID: DeSHcClQ7cG
--HG--
extra : rebase_source : d9c41878036c1ef7766ef5e91a7005025bc1d72b
This was done using the following script:
37e3803c7a/processors/chromeutils-import.jsm
MozReview-Commit-ID: 1Nc3XDu0wGl
--HG--
extra : source : 12fc4dee861c812fd2bd032c63ef17af61800c70
extra : intermediate-source : 34c999fa006bffe8705cf50c54708aa21a962e62
extra : histedit_source : b2be2c5e5d226e6c347312456a6ae339c1e634b0
This was done using the following script:
37e3803c7a/processors/chromeutils-import.jsm
MozReview-Commit-ID: 1Nc3XDu0wGl
--HG--
extra : source : 12fc4dee861c812fd2bd032c63ef17af61800c70
This was done using the following script:
37e3803c7a/processors/chromeutils-import.jsm
MozReview-Commit-ID: 1Nc3XDu0wGl
--HG--
extra : rebase_source : c004a023389f1f6bf3d2f3efe93c13d423b23ccd