DecodedSurfaceProvider.cpp 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  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 "DecodedSurfaceProvider.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. DecodedSurfaceProvider::DecodedSurfaceProvider(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. , mMutex("mozilla::image::DecodedSurfaceProvider")
  19. , mDecoder(aDecoder.get())
  20. {
  21. MOZ_ASSERT(!mDecoder->IsMetadataDecode(),
  22. "Use MetadataDecodingTask for metadata decodes");
  23. MOZ_ASSERT(mDecoder->IsFirstFrameDecode(),
  24. "Use AnimationSurfaceProvider for animation decodes");
  25. }
  26. DecodedSurfaceProvider::~DecodedSurfaceProvider()
  27. {
  28. DropImageReference();
  29. }
  30. void
  31. DecodedSurfaceProvider::DropImageReference()
  32. {
  33. if (!mImage) {
  34. return; // Nothing to do.
  35. }
  36. // RasterImage objects need to be destroyed on the main thread. We also need
  37. // to destroy them asynchronously, because if our surface cache entry is
  38. // destroyed and we were the only thing keeping |mImage| alive, RasterImage's
  39. // destructor may call into the surface cache while whatever code caused us to
  40. // get evicted is holding the surface cache lock, causing deadlock.
  41. RefPtr<RasterImage> image = mImage;
  42. mImage = nullptr;
  43. NS_ReleaseOnMainThread(image.forget(), /* aAlwaysProxy = */ true);
  44. }
  45. DrawableFrameRef
  46. DecodedSurfaceProvider::DrawableRef(size_t aFrame)
  47. {
  48. MOZ_ASSERT(aFrame == 0,
  49. "Requesting an animation frame from a DecodedSurfaceProvider?");
  50. // We depend on SurfaceCache::SurfaceAvailable() to provide synchronization
  51. // for methods that touch |mSurface|; after SurfaceAvailable() is called,
  52. // |mSurface| should be non-null and shouldn't be mutated further until we get
  53. // destroyed. That means that the assertions below are very important; we'll
  54. // end up with data races if these assumptions are violated.
  55. if (Availability().IsPlaceholder()) {
  56. MOZ_ASSERT_UNREACHABLE("Calling DrawableRef() on a placeholder");
  57. return DrawableFrameRef();
  58. }
  59. if (!mSurface) {
  60. MOZ_ASSERT_UNREACHABLE("Calling DrawableRef() when we have no surface");
  61. return DrawableFrameRef();
  62. }
  63. return mSurface->DrawableRef();
  64. }
  65. bool
  66. DecodedSurfaceProvider::IsFinished() const
  67. {
  68. // See DrawableRef() for commentary on these assertions.
  69. if (Availability().IsPlaceholder()) {
  70. MOZ_ASSERT_UNREACHABLE("Calling IsFinished() on a placeholder");
  71. return false;
  72. }
  73. if (!mSurface) {
  74. MOZ_ASSERT_UNREACHABLE("Calling IsFinished() when we have no surface");
  75. return false;
  76. }
  77. return mSurface->IsFinished();
  78. }
  79. void
  80. DecodedSurfaceProvider::SetLocked(bool aLocked)
  81. {
  82. // See DrawableRef() for commentary on these assertions.
  83. if (Availability().IsPlaceholder()) {
  84. MOZ_ASSERT_UNREACHABLE("Calling SetLocked() on a placeholder");
  85. return;
  86. }
  87. if (!mSurface) {
  88. MOZ_ASSERT_UNREACHABLE("Calling SetLocked() when we have no surface");
  89. return;
  90. }
  91. if (aLocked == IsLocked()) {
  92. return; // Nothing to do.
  93. }
  94. // If we're locked, hold a DrawableFrameRef to |mSurface|, which will keep any
  95. // volatile buffer it owns in memory.
  96. mLockRef = aLocked ? mSurface->DrawableRef()
  97. : DrawableFrameRef();
  98. }
  99. size_t
  100. DecodedSurfaceProvider::LogicalSizeInBytes() const
  101. {
  102. // Single frame images are always 32bpp.
  103. IntSize size = GetSurfaceKey().Size();
  104. return size.width * size.height * sizeof(uint32_t);
  105. }
  106. void
  107. DecodedSurfaceProvider::Run()
  108. {
  109. MutexAutoLock lock(mMutex);
  110. if (!mDecoder || !mImage) {
  111. MOZ_ASSERT_UNREACHABLE("Running after decoding finished?");
  112. return;
  113. }
  114. // Run the decoder.
  115. LexerResult result = mDecoder->Decode(WrapNotNull(this));
  116. // If there's a new surface available, announce it to the surface cache.
  117. CheckForNewSurface();
  118. if (result.is<TerminalState>()) {
  119. FinishDecoding();
  120. return; // We're done.
  121. }
  122. // Notify for the progress we've made so far.
  123. if (mDecoder->HasProgress()) {
  124. NotifyProgress(WrapNotNull(mImage), WrapNotNull(mDecoder));
  125. }
  126. MOZ_ASSERT(result.is<Yield>());
  127. if (result == LexerResult(Yield::NEED_MORE_DATA)) {
  128. // We can't make any more progress right now. The decoder itself will ensure
  129. // that we get reenqueued when more data is available; just return for now.
  130. return;
  131. }
  132. // Single-frame images shouldn't yield for any reason except NEED_MORE_DATA.
  133. MOZ_ASSERT_UNREACHABLE("Unexpected yield for single-frame image");
  134. mDecoder->TerminateFailure();
  135. FinishDecoding();
  136. }
  137. void
  138. DecodedSurfaceProvider::CheckForNewSurface()
  139. {
  140. mMutex.AssertCurrentThreadOwns();
  141. MOZ_ASSERT(mDecoder);
  142. if (mSurface) {
  143. // Single-frame images should produce no more than one surface, so if we
  144. // have one, it should be the same one the decoder is working on.
  145. MOZ_ASSERT(mSurface.get() == mDecoder->GetCurrentFrameRef().get(),
  146. "DecodedSurfaceProvider and Decoder have different surfaces?");
  147. return;
  148. }
  149. // We don't have a surface yet; try to get one from the decoder.
  150. mSurface = mDecoder->GetCurrentFrameRef().get();
  151. if (!mSurface) {
  152. return; // No surface yet.
  153. }
  154. // We just got a surface for the first time; let the surface cache know.
  155. MOZ_ASSERT(mImage);
  156. SurfaceCache::SurfaceAvailable(WrapNotNull(this));
  157. }
  158. void
  159. DecodedSurfaceProvider::FinishDecoding()
  160. {
  161. mMutex.AssertCurrentThreadOwns();
  162. MOZ_ASSERT(mImage);
  163. MOZ_ASSERT(mDecoder);
  164. // Send notifications.
  165. NotifyDecodeComplete(WrapNotNull(mImage), WrapNotNull(mDecoder));
  166. // Destroy our decoder; we don't need it anymore. (And if we don't destroy it,
  167. // our surface can never be optimized, because the decoder has a
  168. // RawAccessFrameRef to it.)
  169. mDecoder = nullptr;
  170. // We don't need a reference to our image anymore, either, and we don't want
  171. // one. We may be stored in the surface cache for a long time after decoding
  172. // finishes. If we don't drop our reference to the image, we'll end up
  173. // keeping it alive as long as we remain in the surface cache, which could
  174. // greatly extend the image's lifetime - in fact, if the image isn't
  175. // discardable, it'd result in a leak!
  176. DropImageReference();
  177. }
  178. bool
  179. DecodedSurfaceProvider::ShouldPreferSyncRun() const
  180. {
  181. return mDecoder->ShouldSyncDecode(gfxPrefs::ImageMemDecodeBytesAtATime());
  182. }
  183. } // namespace image
  184. } // namespace mozilla