Bug 163298 - [CG] Add the option to immediately decode an image frame and control its memory caching
Summary: [CG] Add the option to immediately decode an image frame and control its memo...
Status: RESOLVED FIXED
Alias: None
Product: WebKit
Classification: Unclassified
Component: Images (show other bugs)
Version: WebKit Nightly Build
Hardware: Unspecified Unspecified
: P2 Normal
Assignee: Said Abou-Hallawa
URL:
Keywords:
Depends on:
Blocks: 155322 155546
  Show dependency treegraph
 
Reported: 2016-10-11 14:28 PDT by Said Abou-Hallawa
Modified: 2016-10-12 10:19 PDT (History)
7 users (show)

See Also:


Attachments
Patch (12.18 KB, patch)
2016-10-11 14:29 PDT, Said Abou-Hallawa
no flags Details | Formatted Diff | Diff
Patch (15.77 KB, patch)
2016-10-11 14:49 PDT, Said Abou-Hallawa
no flags Details | Formatted Diff | Diff
Patch (15.61 KB, patch)
2016-10-11 15:44 PDT, Said Abou-Hallawa
no flags Details | Formatted Diff | Diff
image-decode-CGImageSourceCreateThumbnailAtIndex-only.trace (2.08 MB, application/zip)
2016-10-11 17:35 PDT, Said Abou-Hallawa
no flags Details
image-decode-kCGImageSourceCreateThumbnailFromImageAlways-only.trace (4.16 MB, application/zip)
2016-10-11 17:38 PDT, Said Abou-Hallawa
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description Said Abou-Hallawa 2016-10-11 14:28:19 PDT
This work is needed for asynchronous image decoding. By default an image frame is decoded only when it'e needed. Usually the image frame is needed when it is drawn. If the image decoding is done on the main thread, two things might happen. The main thread is blocked such that an activity, like scrolling, is not smooth. Secondly the image decoding is slow such that rendering a layout frame is done in more than 16ms, so we miss drawing a frame.

This bug should fix two things. It should add the option to immediately decode an image frame. This should happen on a different thread earlier than  the drawing time. The BitmapImage should also control when the image frame is deleted from memory. Currently CG can cache an image frame even if WebKit does not have a reference to it. The only way to guarantee an image frame is removed from memory is to delete the reference to the CGImageSourceRef.
Comment 1 Said Abou-Hallawa 2016-10-11 14:29:49 PDT
Created attachment 291298 [details]
Patch
Comment 2 Said Abou-Hallawa 2016-10-11 14:49:35 PDT
Created attachment 291300 [details]
Patch
Comment 3 Tim Horton 2016-10-11 14:59:43 PDT
Comment on attachment 291300 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=291300&action=review

> Source/WebCore/ChangeLog:3
> +        [CG] Add the option to immediacy decode an image frame and control its memory caching

s/immediacy/immediately/

> Source/WebCore/platform/graphics/cg/ImageDecoderCG.cpp:80
> +    void append(const void *key, const void *value)
> +    {
> +        ASSERT(numOptions < basicOptions + extraOptions);
> +        keys[numOptions] = key;
> +        values[numOptions++] = value;
> +    }
> +
> +    static const CFIndex basicOptions = 3;
> +    static const CFIndex extraOptions = 3;
> +
> +    const void* keys[basicOptions + extraOptions];
> +    const void* values[basicOptions + extraOptions];
> +    CFIndex numOptions { 0 };

This is all very sad, maybe we should just use CFMutableDictionary?

> Source/WebCore/platform/graphics/cg/ImageDecoderCG.cpp:367
> +        image = adoptCF(CGImageSourceCreateImageAtIndex(m_nativeDecoder.get(), index, imageSourceOptions(subsamplingLevel, decodingMode).get()));

Maybe factor out creation of imageSourceOptions for cleanliness' sake?
Comment 4 Said Abou-Hallawa 2016-10-11 15:44:33 PDT
Created attachment 291310 [details]
Patch
Comment 5 Simon Fraser (smfr) 2016-10-11 16:09:17 PDT
Comment on attachment 291310 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=291310&action=review

> Source/WebCore/platform/graphics/cg/ImageDecoderCG.cpp:351
> +    if (decodingMode == DecodingMode::OnDemand)
> +        image = adoptCF(CGImageSourceCreateImageAtIndex(m_nativeDecoder.get(), index, options));
> +    else
> +        image = adoptCF(CGImageSourceCreateThumbnailAtIndex(m_nativeDecoder.get(), index, options));

Do we need both the call to CGImageSourceCreateThumbnailAtIndex(), AND the kCGImageSourceCreateThumbnailFromImageAlways = kCFBooleanTrue in the options?
Comment 6 Said Abou-Hallawa 2016-10-11 17:29:37 PDT
Comment on attachment 291310 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=291310&action=review

>> Source/WebCore/platform/graphics/cg/ImageDecoderCG.cpp:351
>> +        image = adoptCF(CGImageSourceCreateThumbnailAtIndex(m_nativeDecoder.get(), index, options));
> 
> Do we need both the call to CGImageSourceCreateThumbnailAtIndex(), AND the kCGImageSourceCreateThumbnailFromImageAlways = kCFBooleanTrue in the options?

YES, we do. Deleting one of them does not force immediate image decoding. The returned CGImageRef does not hold the decoded data. So we end up with synchronous image decoding which happens only at drawing time.
Comment 7 Said Abou-Hallawa 2016-10-11 17:35:11 PDT
Created attachment 291322 [details]
image-decode-CGImageSourceCreateThumbnailAtIndex-only.trace

This is the Instruments trace when calling CGImageSourceCreateThumbnailAtIndex() with passing the flag kCGImageSourceCreateThumbnailFromImageAlways.

GIFReadPlugin::decodeGIFFrame() is called from CG::DrawOp() in the drawing thread.
Comment 8 Said Abou-Hallawa 2016-10-11 17:36:44 PDT
(In reply to comment #7)
> Created attachment 291322 [details]
> image-decode-CGImageSourceCreateThumbnailAtIndex-only.trace
> 
> This is the Instruments trace when calling
> CGImageSourceCreateThumbnailAtIndex() with passing the flag
> kCGImageSourceCreateThumbnailFromImageAlways.

I meant "without passing ...."

> 
> GIFReadPlugin::decodeGIFFrame() is called from CG::DrawOp() in the drawing
> thread.
Comment 9 Said Abou-Hallawa 2016-10-11 17:38:43 PDT
Created attachment 291323 [details]
image-decode-kCGImageSourceCreateThumbnailFromImageAlways-only.trace

This is the Instruments trace when calling CGImageSourceCreateImageAtIndex() with passing the flag kCGImageSourceCreateThumbnailFromImageAlways.

GIFReadPlugin::decodeGIFFrame() is called from CG::DrawOp() in the drawing thread
Comment 10 Simon Fraser (smfr) 2016-10-11 17:42:00 PDT
Comment on attachment 291310 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=291310&action=review

>>> Source/WebCore/platform/graphics/cg/ImageDecoderCG.cpp:351
>>> +        image = adoptCF(CGImageSourceCreateThumbnailAtIndex(m_nativeDecoder.get(), index, options));
>> 
>> Do we need both the call to CGImageSourceCreateThumbnailAtIndex(), AND the kCGImageSourceCreateThumbnailFromImageAlways = kCFBooleanTrue in the options?
> 
> YES, we do. Deleting one of them does not force immediate image decoding. The returned CGImageRef does not hold the decoded data. So we end up with synchronous image decoding which happens only at drawing time.

I see. kCGImageSourceCreateThumbnailFromImageAlways says to always create the thumbnail from the full image (not any thumbnail embedded in the image file).
Comment 11 WebKit Commit Bot 2016-10-11 18:42:50 PDT
Comment on attachment 291310 [details]
Patch

Clearing flags on attachment: 291310

Committed r207182: <http://trac.webkit.org/changeset/207182>
Comment 12 WebKit Commit Bot 2016-10-11 18:42:54 PDT
All reviewed patches have been landed.  Closing bug.
Comment 13 Csaba Osztrogonác 2016-10-12 05:01:39 PDT
(In reply to comment #11)
> Comment on attachment 291310 [details]
> Patch
> 
> Clearing flags on attachment: 291310
> 
> Committed r207182: <http://trac.webkit.org/changeset/207182>

It broke the Apple Windows build, see build.webkit.org for details.
Comment 14 Said Abou-Hallawa 2016-10-12 09:13:36 PDT
(In reply to comment #13)
> (In reply to comment #11)
> > Comment on attachment 291310 [details]
> > Patch
> > 
> > Clearing flags on attachment: 291310
> > 
> > Committed r207182: <http://trac.webkit.org/changeset/207182>
> 
> It broke the Apple Windows build, see build.webkit.org for details.

Yes. This is true. The error is:

C:\cygwin\home\buildbot\slave\win-release\build\Source\WebCore\platform\graphics\cg\ImageDecoderCG.cpp(77): error C2065: 'kCGImageSourceShouldCacheImmediately': undeclared identifier [C:\cygwin\home\buildbot\slave\win-release\build\WebKitBuild\Release\Source\WebCore\WebCore.vcxproj]

Working on a fix.
Comment 15 Said Abou-Hallawa 2016-10-12 10:19:57 PDT
Fix the Windows build: Committed r207216: <http://trac.webkit.org/changeset/207216>