AnimationSurfaceProvider.cpp 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /* This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this
  4. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. #include "AnimationSurfaceProvider.h"
  6. #include "gfxPrefs.h"
  7. #include "nsProxyRelease.h"
  8. #include "Decoder.h"
  9. using namespace mozilla::gfx;
  10. namespace mozilla {
  11. namespace image {
  12. AnimationSurfaceProvider::AnimationSurfaceProvider(NotNull<RasterImage*> aImage,
  13. const SurfaceKey& aSurfaceKey,
  14. NotNull<Decoder*> aDecoder)
  15. : ISurfaceProvider(ImageKey(aImage.get()), aSurfaceKey,
  16. AvailabilityState::StartAsPlaceholder())
  17. , mImage(aImage.get())
  18. , mDecodingMutex("AnimationSurfaceProvider::mDecoder")
  19. , mDecoder(aDecoder.get())
  20. , mFramesMutex("AnimationSurfaceProvider::mFrames")
  21. {
  22. MOZ_ASSERT(!mDecoder->IsMetadataDecode(),
  23. "Use MetadataDecodingTask for metadata decodes");
  24. MOZ_ASSERT(!mDecoder->IsFirstFrameDecode(),
  25. "Use DecodedSurfaceProvider for single-frame image decodes");
  26. }
  27. AnimationSurfaceProvider::~AnimationSurfaceProvider()
  28. {
  29. DropImageReference();
  30. }
  31. void
  32. AnimationSurfaceProvider::DropImageReference()
  33. {
  34. if (!mImage) {
  35. return; // Nothing to do.
  36. }
  37. // RasterImage objects need to be destroyed on the main thread. We also need
  38. // to destroy them asynchronously, because if our surface cache entry is
  39. // destroyed and we were the only thing keeping |mImage| alive, RasterImage's
  40. // destructor may call into the surface cache while whatever code caused us to
  41. // get evicted is holding the surface cache lock, causing deadlock.
  42. RefPtr<RasterImage> image = mImage;
  43. mImage = nullptr;
  44. NS_ReleaseOnMainThread(image.forget(), /* aAlwaysProxy = */ true);
  45. }
  46. DrawableFrameRef
  47. AnimationSurfaceProvider::DrawableRef(size_t aFrame)
  48. {
  49. MutexAutoLock lock(mFramesMutex);
  50. if (Availability().IsPlaceholder()) {
  51. MOZ_ASSERT_UNREACHABLE("Calling DrawableRef() on a placeholder");
  52. return DrawableFrameRef();
  53. }
  54. if (mFrames.IsEmpty()) {
  55. MOZ_ASSERT_UNREACHABLE("Calling DrawableRef() when we have no frames");
  56. return DrawableFrameRef();
  57. }
  58. // If we don't have that frame, return an empty frame ref.
  59. if (aFrame >= mFrames.Length()) {
  60. return DrawableFrameRef();
  61. }
  62. // We've got the requested frame. Return it.
  63. MOZ_ASSERT(mFrames[aFrame]);
  64. return mFrames[aFrame]->DrawableRef();
  65. }
  66. bool
  67. AnimationSurfaceProvider::IsFinished() const
  68. {
  69. MutexAutoLock lock(mFramesMutex);
  70. if (Availability().IsPlaceholder()) {
  71. MOZ_ASSERT_UNREACHABLE("Calling IsFinished() on a placeholder");
  72. return false;
  73. }
  74. if (mFrames.IsEmpty()) {
  75. MOZ_ASSERT_UNREACHABLE("Calling IsFinished() when we have no frames");
  76. return false;
  77. }
  78. // As long as we have at least one finished frame, we're finished.
  79. return mFrames[0]->IsFinished();
  80. }
  81. size_t
  82. AnimationSurfaceProvider::LogicalSizeInBytes() const
  83. {
  84. // When decoding animated images, we need at most three live surfaces: the
  85. // composited surface, the previous composited surface for
  86. // DisposalMethod::RESTORE_PREVIOUS, and the surface we're currently decoding
  87. // into. The composited surfaces are always BGRA. Although the surface we're
  88. // decoding into may be paletted, and may be smaller than the real size of the
  89. // image, we assume the worst case here.
  90. // XXX(seth): Note that this is actually not accurate yet; we're storing the
  91. // full sequence of frames, not just the three live surfaces mentioned above.
  92. // Unfortunately there's no way to know in advance how many frames an
  93. // animation has, so we really can't do better here. This will become correct
  94. // once bug 1289954 is complete.
  95. IntSize size = GetSurfaceKey().Size();
  96. return 3 * size.width * size.height * sizeof(uint32_t);
  97. }
  98. void
  99. AnimationSurfaceProvider::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
  100. size_t& aHeapSizeOut,
  101. size_t& aNonHeapSizeOut)
  102. {
  103. // Note that the surface cache lock is already held here, and then we acquire
  104. // mFramesMutex. For this method, this ordering is unavoidable, which means
  105. // that we must be careful to always use the same ordering elsewhere.
  106. MutexAutoLock lock(mFramesMutex);
  107. for (const RawAccessFrameRef& frame : mFrames) {
  108. frame->AddSizeOfExcludingThis(aMallocSizeOf, aHeapSizeOut, aNonHeapSizeOut);
  109. }
  110. }
  111. void
  112. AnimationSurfaceProvider::Run()
  113. {
  114. MutexAutoLock lock(mDecodingMutex);
  115. if (!mDecoder || !mImage) {
  116. MOZ_ASSERT_UNREACHABLE("Running after decoding finished?");
  117. return;
  118. }
  119. while (true) {
  120. // Run the decoder.
  121. LexerResult result = mDecoder->Decode(WrapNotNull(this));
  122. if (result.is<TerminalState>()) {
  123. // We may have a new frame now, but it's not guaranteed - a decoding
  124. // failure or truncated data may mean that no new frame got produced.
  125. // Since we're not sure, rather than call CheckForNewFrameAtYield() here
  126. // we call CheckForNewFrameAtTerminalState(), which handles both of these
  127. // possibilities.
  128. CheckForNewFrameAtTerminalState();
  129. // We're done!
  130. FinishDecoding();
  131. return;
  132. }
  133. // Notify for the progress we've made so far.
  134. if (mDecoder->HasProgress()) {
  135. NotifyProgress(WrapNotNull(mImage), WrapNotNull(mDecoder));
  136. }
  137. if (result == LexerResult(Yield::NEED_MORE_DATA)) {
  138. // We can't make any more progress right now. The decoder itself will ensure
  139. // that we get reenqueued when more data is available; just return for now.
  140. return;
  141. }
  142. // There's new output available - a new frame! Grab it.
  143. MOZ_ASSERT(result == LexerResult(Yield::OUTPUT_AVAILABLE));
  144. CheckForNewFrameAtYield();
  145. }
  146. }
  147. void
  148. AnimationSurfaceProvider::CheckForNewFrameAtYield()
  149. {
  150. mDecodingMutex.AssertCurrentThreadOwns();
  151. MOZ_ASSERT(mDecoder);
  152. bool justGotFirstFrame = false;
  153. {
  154. MutexAutoLock lock(mFramesMutex);
  155. // Try to get the new frame from the decoder.
  156. RawAccessFrameRef frame = mDecoder->GetCurrentFrameRef();
  157. if (!frame) {
  158. MOZ_ASSERT_UNREACHABLE("Decoder yielded but didn't produce a frame?");
  159. return;
  160. }
  161. // We should've gotten a different frame than last time.
  162. MOZ_ASSERT_IF(!mFrames.IsEmpty(),
  163. mFrames.LastElement().get() != frame.get());
  164. // Append the new frame to the list.
  165. mFrames.AppendElement(Move(frame));
  166. if (mFrames.Length() == 1) {
  167. justGotFirstFrame = true;
  168. }
  169. }
  170. if (justGotFirstFrame) {
  171. AnnounceSurfaceAvailable();
  172. }
  173. }
  174. void
  175. AnimationSurfaceProvider::CheckForNewFrameAtTerminalState()
  176. {
  177. mDecodingMutex.AssertCurrentThreadOwns();
  178. MOZ_ASSERT(mDecoder);
  179. bool justGotFirstFrame = false;
  180. {
  181. MutexAutoLock lock(mFramesMutex);
  182. RawAccessFrameRef frame = mDecoder->GetCurrentFrameRef();
  183. if (!frame) {
  184. return;
  185. }
  186. if (!mFrames.IsEmpty() && mFrames.LastElement().get() == frame.get()) {
  187. return; // We already have this one.
  188. }
  189. // Append the new frame to the list.
  190. mFrames.AppendElement(Move(frame));
  191. if (mFrames.Length() == 1) {
  192. justGotFirstFrame = true;
  193. }
  194. }
  195. if (justGotFirstFrame) {
  196. AnnounceSurfaceAvailable();
  197. }
  198. }
  199. void
  200. AnimationSurfaceProvider::AnnounceSurfaceAvailable()
  201. {
  202. mFramesMutex.AssertNotCurrentThreadOwns();
  203. MOZ_ASSERT(mImage);
  204. // We just got the first frame; let the surface cache know. We deliberately do
  205. // this outside of mFramesMutex to avoid a potential deadlock with
  206. // AddSizeOfExcludingThis(), since otherwise we'd be acquiring mFramesMutex
  207. // and then the surface cache lock, while the memory reporting code would
  208. // acquire the surface cache lock and then mFramesMutex.
  209. SurfaceCache::SurfaceAvailable(WrapNotNull(this));
  210. }
  211. void
  212. AnimationSurfaceProvider::FinishDecoding()
  213. {
  214. mDecodingMutex.AssertCurrentThreadOwns();
  215. MOZ_ASSERT(mImage);
  216. MOZ_ASSERT(mDecoder);
  217. // Send notifications.
  218. NotifyDecodeComplete(WrapNotNull(mImage), WrapNotNull(mDecoder));
  219. // Destroy our decoder; we don't need it anymore.
  220. mDecoder = nullptr;
  221. // We don't need a reference to our image anymore, either, and we don't want
  222. // one. We may be stored in the surface cache for a long time after decoding
  223. // finishes. If we don't drop our reference to the image, we'll end up
  224. // keeping it alive as long as we remain in the surface cache, which could
  225. // greatly extend the image's lifetime - in fact, if the image isn't
  226. // discardable, it'd result in a leak!
  227. DropImageReference();
  228. }
  229. bool
  230. AnimationSurfaceProvider::ShouldPreferSyncRun() const
  231. {
  232. MutexAutoLock lock(mDecodingMutex);
  233. MOZ_ASSERT(mDecoder);
  234. return mDecoder->ShouldSyncDecode(gfxPrefs::ImageMemDecodeBytesAtATime());
  235. }
  236. } // namespace image
  237. } // namespace mozilla