Skip to content

Conversation

@shallawa
Copy link
Contributor

@shallawa shallawa commented Jan 26, 2024

d20aed3

Move image decoding WorkQueue to a separate class named ImageFrameWorkQueue
https://bugs.webkit.org/show_bug.cgi?id=268184
rdar://121677190

Reviewed by NOBODY (OOPS!).

ImageSource will ask ImageFrameWorkQueue to decode the image frames. Once the
image frame is decoded, ImageSource will be notifed to cache the decoded frame
and tell the observer to repaint its renderer.

Alos ImageFrameWorkQueue will answer whether a frame is being decoded or not.

* Source/WebCore/Headers.cmake:
* Source/WebCore/Sources.txt:
* Source/WebCore/WebCore.xcodeproj/project.pbxproj:
* Source/WebCore/loader/cache/CachedImage.cpp:
(WebCore::CachedImage::removeAllClientsWaitingForAsyncDecoding):
* Source/WebCore/platform/graphics/BitmapImage.cpp:
(WebCore::BitmapImage::~BitmapImage):
(WebCore::BitmapImage::destroyDecodedData):
(WebCore::BitmapImage::draw):
(WebCore::BitmapImage::canDestroyDecodedData):
(WebCore::BitmapImage::internalStartAnimation):
(WebCore::BitmapImage::advanceAnimation):
(WebCore::BitmapImage::internalAdvanceAnimation):
(WebCore::BitmapImage::stopAnimation):
(WebCore::BitmapImage::decode):
(WebCore::BitmapImage::imageFrameAvailableAtIndex):
* Source/WebCore/platform/graphics/BitmapImage.h:
* Source/WebCore/platform/graphics/ImageFrameWorkQueue.cpp: Added.
(WebCore::ImageFrameWorkQueue::create):
(WebCore::ImageFrameWorkQueue::ImageFrameWorkQueue):
(WebCore::ImageFrameWorkQueue::requestQueue):
(WebCore::ImageFrameWorkQueue::start):
(WebCore::ImageFrameWorkQueue::dispatch):
(WebCore::ImageFrameWorkQueue::stop):
(WebCore::ImageFrameWorkQueue::isPendingDecodingAtIndex const):
(WebCore::ImageFrameWorkQueue::dump const):
* Source/WebCore/platform/graphics/ImageFrameWorkQueue.h: Added.
(WebCore::ImageFrameWorkQueue::isIdle const):
(WebCore::ImageFrameWorkQueue::setMinimumDecodingDurationForTesting):
(WebCore::ImageFrameWorkQueue::decodeQueue):
(WebCore::ImageFrameWorkQueue::minimumDecodingDurationForTesting const):
* Source/WebCore/platform/graphics/ImageSource.cpp:
(WebCore::ImageSource::~ImageSource):
(WebCore::ImageSource::ensureDecoderAvailable):
(WebCore::ImageSource::cacheNativeImageAtIndex):
(WebCore::ImageSource::cacheNativeImageAtIndexAsync):
(WebCore::ImageSource::clearFrameAtIndex):
(WebCore::ImageSource::workQueue):
(WebCore::ImageSource::requestFrameAsyncDecodingAtIndex):
(WebCore::ImageSource::stopWorkQueue):
(WebCore::ImageSource::setMinimumDecodingDurationForTesting):
(WebCore::ImageSource::frameAtIndexCacheIfNeeded):
(WebCore::ImageSource::sourceUTF8 const):
(WebCore::ImageSource::frameIsBeingDecodedAndIsCompatibleWithOptionsAtIndex):
(WebCore::ImageSource::cachePlatformImageAtIndex): Deleted.
(WebCore::ImageSource::cachePlatformImageAtIndexAsync): Deleted.
(WebCore::ImageSource::decodingQueue): Deleted.
(WebCore::ImageSource::frameRequestQueue): Deleted.
(WebCore::ImageSource::startAsyncDecodingQueue): Deleted.
(WebCore::ImageSource::isAsyncDecodingQueueIdle const): Deleted.
(WebCore::ImageSource::stopAsyncDecodingQueue): Deleted.
* Source/WebCore/platform/graphics/ImageSource.h:
* Source/WebCore/testing/Internals.cpp:
(WebCore::Internals::setImageFrameDecodingDuration):

d20aed3

Misc iOS, tvOS & watchOS macOS Linux Windows
✅ 🧪 style ✅ 🛠 ios ✅ 🛠 mac ✅ 🛠 wpe ✅ 🛠 wincairo
✅ 🧪 bindings ✅ 🛠 ios-sim ✅ 🛠 mac-AS-debug ✅ 🧪 wpe-wk2
✅ 🧪 webkitperl ✅ 🧪 ios-wk2 ✅ 🧪 api-mac ✅ 🧪 api-wpe
✅ 🧪 ios-wk2-wpt ✅ 🧪 mac-wk1 ✅ 🛠 gtk
✅ 🧪 api-ios ✅ 🧪 mac-wk2 ✅ 🧪 gtk-wk2
✅ 🛠 tv ✅ 🧪 mac-AS-debug-wk2 ✅ 🧪 api-gtk
✅ 🛠 tv-sim
✅ 🛠 watch
✅ 🛠 watch-sim

@shallawa shallawa requested a review from cdumez as a code owner January 26, 2024 19:06
@shallawa shallawa self-assigned this Jan 26, 2024
@shallawa shallawa added the Images For bugs in image handling. label Jan 26, 2024
@shallawa shallawa requested review from heycam and smfr January 27, 2024 01:03
…kQueue

https://bugs.webkit.org/show_bug.cgi?id=268184
rdar://121677190

Reviewed by NOBODY (OOPS!).

ImageSource will ask ImageFrameWorkQueue to decode the image frames. Once the
image frame is decoded, ImageSource will be notifed to cache the decoded frame
and tell the observer to repaint its renderer.

Alos ImageFrameWorkQueue will answer whether a frame is being decoded or not.

* Source/WebCore/Headers.cmake:
* Source/WebCore/Sources.txt:
* Source/WebCore/WebCore.xcodeproj/project.pbxproj:
* Source/WebCore/loader/cache/CachedImage.cpp:
(WebCore::CachedImage::removeAllClientsWaitingForAsyncDecoding):
* Source/WebCore/platform/graphics/BitmapImage.cpp:
(WebCore::BitmapImage::~BitmapImage):
(WebCore::BitmapImage::destroyDecodedData):
(WebCore::BitmapImage::draw):
(WebCore::BitmapImage::canDestroyDecodedData):
(WebCore::BitmapImage::internalStartAnimation):
(WebCore::BitmapImage::advanceAnimation):
(WebCore::BitmapImage::internalAdvanceAnimation):
(WebCore::BitmapImage::stopAnimation):
(WebCore::BitmapImage::decode):
(WebCore::BitmapImage::imageFrameAvailableAtIndex):
* Source/WebCore/platform/graphics/BitmapImage.h:
* Source/WebCore/platform/graphics/ImageFrameWorkQueue.cpp: Added.
(WebCore::ImageFrameWorkQueue::create):
(WebCore::ImageFrameWorkQueue::ImageFrameWorkQueue):
(WebCore::ImageFrameWorkQueue::requestQueue):
(WebCore::ImageFrameWorkQueue::start):
(WebCore::ImageFrameWorkQueue::dispatch):
(WebCore::ImageFrameWorkQueue::stop):
(WebCore::ImageFrameWorkQueue::isPendingDecodingAtIndex const):
(WebCore::ImageFrameWorkQueue::dump const):
* Source/WebCore/platform/graphics/ImageFrameWorkQueue.h: Added.
(WebCore::ImageFrameWorkQueue::isIdle const):
(WebCore::ImageFrameWorkQueue::setMinimumDecodingDurationForTesting):
(WebCore::ImageFrameWorkQueue::decodeQueue):
(WebCore::ImageFrameWorkQueue::minimumDecodingDurationForTesting const):
* Source/WebCore/platform/graphics/ImageSource.cpp:
(WebCore::ImageSource::~ImageSource):
(WebCore::ImageSource::ensureDecoderAvailable):
(WebCore::ImageSource::cacheNativeImageAtIndex):
(WebCore::ImageSource::cacheNativeImageAtIndexAsync):
(WebCore::ImageSource::clearFrameAtIndex):
(WebCore::ImageSource::workQueue):
(WebCore::ImageSource::requestFrameAsyncDecodingAtIndex):
(WebCore::ImageSource::stopWorkQueue):
(WebCore::ImageSource::setMinimumDecodingDurationForTesting):
(WebCore::ImageSource::frameAtIndexCacheIfNeeded):
(WebCore::ImageSource::sourceUTF8 const):
(WebCore::ImageSource::frameIsBeingDecodedAndIsCompatibleWithOptionsAtIndex):
(WebCore::ImageSource::cachePlatformImageAtIndex): Deleted.
(WebCore::ImageSource::cachePlatformImageAtIndexAsync): Deleted.
(WebCore::ImageSource::decodingQueue): Deleted.
(WebCore::ImageSource::frameRequestQueue): Deleted.
(WebCore::ImageSource::startAsyncDecodingQueue): Deleted.
(WebCore::ImageSource::isAsyncDecodingQueueIdle const): Deleted.
(WebCore::ImageSource::stopAsyncDecodingQueue): Deleted.
* Source/WebCore/platform/graphics/ImageSource.h:
* Source/WebCore/testing/Internals.cpp:
(WebCore::Internals::setImageFrameDecodingDuration):
@shallawa shallawa force-pushed the eng/Move-image-decoding-WorkQueue-to-a-separate-class-named-ImageFrameWorkQueue branch from 44c7b71 to d20aed3 Compare February 6, 2024 10:03
ASSERT((!index && !m_currentFrame) || !canAnimate());
if (m_source->isAsyncDecodingQueueIdle())
m_source->stopAsyncDecodingQueue();
if (m_source->isWorkQueueIdle())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should hold a Ref to the source on the stack:

if (Ref source = m_source; source->isWorkQueueIdle())
    source->stopWorkQueue();

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will be fixed in #20916 but in ImageFrameProvider::stopDecodingWorkQueue().


bool shouldUseAsyncDecodingForTesting() const { return m_source->frameDecodingDurationForTesting() > 0_s; }
void setFrameDecodingDurationForTesting(Seconds duration) { m_source->setFrameDecodingDurationForTesting(duration); }
void setMinimumDecodingDurationForTesting(Seconds duration) { m_source->setMinimumDecodingDurationForTesting(duration); }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ref { m_source }->setMinimumDecodingDurationForTesting(duration) per our new smart pointer guidelines.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can also add a protectedSource() getter which returns a Ref<> if you want to make this look nicer.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will be fixed in #20916.

void setAsyncDecodingEnabledForTesting(bool enabled) { m_asyncDecodingEnabledForTesting = enabled; }
bool isAsyncDecodingEnabledForTesting() const { return m_asyncDecodingEnabledForTesting; }
void stopAsyncDecodingQueue() { m_source->stopAsyncDecodingQueue(); }
void stopWorkQueue() { m_source->stopWorkQueue(); }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will be fixed in #20916.

if (m_workQueue)
return;

ASSERT(isMainThread());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be nice to move this above, before the early return.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will be fixed in #20916.

if (minimumDecodingDuration > 0_s)
startingTime = MonotonicTime::now();

auto platformImage = decoder->createFrameImageAtIndex(request.index, request.subsamplingLevel, request.options);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please do not obfuscate smart pointers with auto, use RefPtr

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will be fixed in #20916.

{
if (hasAsyncDecodingQueue() || !isDecoderAvailable())
return;
if (!m_workQueue)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this always called on the same thread? If not, we have a thread-safety issue here and would need a Lock.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes this is called only on the main thread. In #20916. ImageFrameProvider will owns the ImageFrameWorkQueue.

});
LOG(Images, "ImageSource::%s - %p - url: %s. Decoding work queue will be stopped.", __FUNCTION__, this, sourceUTF8());

m_workQueue->stop();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You need a Ref/RefPtr on the stack before you call stop(), e.g. RefPtr { m_workQueue }->stop() or protectedWorkQueue()->stop()

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will be fixed in #20916 but in ImageFrameProvider since it will own the ImageFrameWorkQueue.


// We have to perform synchronous image decoding in this code.
auto platformImage = m_decoder->createFrameImageAtIndex(index, subsamplingLevelValue, decodingOptions);
auto platformImage = m_decoder->createFrameImageAtIndex(index, currentSubsamplingLevel, decodingOptions);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please don't hide smart pointers with auto.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will be fixed in #20916. All auto platformImage = ... are replaced by `PlatformImagePtr platformImage = ...

// We have to perform synchronous image decoding in this code.
auto platformImage = m_decoder->createFrameImageAtIndex(index, subsamplingLevelValue, decodingOptions);
auto platformImage = m_decoder->createFrameImageAtIndex(index, currentSubsamplingLevel, decodingOptions);
auto nativeImage = NativeImage::create(WTFMove(platformImage));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will be fixed in #20916. All auto nativeImage = ... are replaced by RefPtr nativeImage = ...


m_workQueue->dispatch([protectedThis = Ref { *this }, protectedWorkQueue = Ref { *m_workQueue }, protectedSource = Ref { source() }] () mutable {
Request request;
while (protectedThis->requestQueue().dequeue(request)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I need to look into the implementation of this requestQueue(). I assume it does locking?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see, it's a SynchronizedFixedQueue which does indeed Lock internally. All good.

@shallawa
Copy link
Contributor Author

shallawa commented Feb 7, 2024

The plan is to submit the whole BitmapImage refactor PR #20916 as is without split. All the comments here will be addressed #20916.

@shallawa shallawa closed this Feb 7, 2024
@shallawa shallawa deleted the eng/Move-image-decoding-WorkQueue-to-a-separate-class-named-ImageFrameWorkQueue branch March 21, 2024 17:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Images For bugs in image handling.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants