WebKit Bugzilla
New
Browse
Log In
×
Sign in with GitHub
or
Remember my login
Create Account
·
Forgot Password
Forgotten password account recovery
RESOLVED FIXED
108892
Passing alpha to DeferredImageDecoder once decoding completes
https://bugs.webkit.org/show_bug.cgi?id=108892
Summary
Passing alpha to DeferredImageDecoder once decoding completes
Min Qin
Reported
2013-02-04 20:00:19 PST
Passing alpha to DeferredImageDecoder once decoding completes
Attachments
Patch
(13.65 KB, patch)
2013-02-05 12:07 PST
,
Min Qin
no flags
Details
Formatted Diff
Diff
Patch
(8.94 KB, patch)
2013-02-12 10:52 PST
,
Min Qin
no flags
Details
Formatted Diff
Diff
Patch
(9.69 KB, patch)
2013-02-13 13:23 PST
,
Min Qin
no flags
Details
Formatted Diff
Diff
Show Obsolete
(2)
View All
Add attachment
proposed patch, testcase, etc.
Min Qin
Comment 1
2013-02-05 12:07:44 PST
Created
attachment 186672
[details]
Patch
WebKit Review Bot
Comment 2
2013-02-05 12:33:38 PST
Comment on
attachment 186672
[details]
Patch
Attachment 186672
[details]
did not pass cr-linux-debug-ews (chromium-xvfb): Output:
http://queues.webkit.org/results/16373796
Hin-Chung Lam
Comment 3
2013-02-11 15:58:22 PST
Comment on
attachment 186672
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=186672&action=review
You don't need to change LazyDecodingPixel or ScaledImageFragment. Save the alpha state in ImageFrameGenerator instead. You will have to lock it when accessing this field.
> Source/WebCore/platform/graphics/chromium/DeferredImageDecoder.cpp:185 > + LazyDecodingPixelRef* pixelRef = static_cast<LazyDecodingPixelRef*>(m_lazyDecodedFrame.getSkBitmap().pixelRef());
alpha state should be saved in ImageFrameGenerator. ImageFrameGenerator corresponds to one image file. It exists regardless whether or not an image is cached or not. So in the case of ScaledImageFragment being evicted the code can return the correct alpha state regardless of whether it is cached or not.
> Source/WebCore/platform/graphics/chromium/ImageFrameGenerator.cpp:213 > + bool hasAlpha = (*decoder)->frameHasAlphaAtIndex(0);
Do something like: m_hasAlpha = isComplete && !fullSizeBitmap.isOpaque();
Min Qin
Comment 4
2013-02-12 09:50:14 PST
Comment on
attachment 186672
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=186672&action=review
>> Source/WebCore/platform/graphics/chromium/ImageFrameGenerator.cpp:213 >> + bool hasAlpha = (*decoder)->frameHasAlphaAtIndex(0); > > Do something like: > > m_hasAlpha = isComplete && !fullSizeBitmap.isOpaque();
hmm.... if isComplete is false, shouldn't we return true there to force image decoding?
Hin-Chung Lam
Comment 5
2013-02-12 09:55:39 PST
Comment on
attachment 186672
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=186672&action=review
>>> Source/WebCore/platform/graphics/chromium/ImageFrameGenerator.cpp:213 >>> + bool hasAlpha = (*decoder)->frameHasAlphaAtIndex(0); >> >> Do something like: >> >> m_hasAlpha = isComplete && !fullSizeBitmap.isOpaque(); > > hmm.... if isComplete is false, shouldn't we return true there to force image decoding?
I don't know what you mean. Actually now I think about it again you can just do !fullSizeBitmap.isOpaque(). Don't call frameHasAlphaAtIndex(0) it might have side effect.
Min Qin
Comment 6
2013-02-12 10:02:20 PST
Comment on
attachment 186672
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=186672&action=review
>>>> Source/WebCore/platform/graphics/chromium/ImageFrameGenerator.cpp:213 >>>> + bool hasAlpha = (*decoder)->frameHasAlphaAtIndex(0); >>> >>> Do something like: >>> >>> m_hasAlpha = isComplete && !fullSizeBitmap.isOpaque(); >> >> hmm.... if isComplete is false, shouldn't we return true there to force image decoding? > > I don't know what you mean. > > Actually now I think about it again you can just do !fullSizeBitmap.isOpaque(). Don't call frameHasAlphaAtIndex(0) it might have side effect.
Yes, I think !fullSizeBitmap.isOpaque() should be correct. hasAlpha should be defaulted to true. So if isComplete is false, we should use true so that there are no optimization happening elsewhere.
Hin-Chung Lam
Comment 7
2013-02-12 10:04:02 PST
Comment on
attachment 186672
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=186672&action=review
>>>>> Source/WebCore/platform/graphics/chromium/ImageFrameGenerator.cpp:213 >>>>> + bool hasAlpha = (*decoder)->frameHasAlphaAtIndex(0); >>>> >>>> Do something like: >>>> >>>> m_hasAlpha = isComplete && !fullSizeBitmap.isOpaque(); >>> >>> hmm.... if isComplete is false, shouldn't we return true there to force image decoding? >> >> I don't know what you mean. >> >> Actually now I think about it again you can just do !fullSizeBitmap.isOpaque(). Don't call frameHasAlphaAtIndex(0) it might have side effect. > > Yes, I think !fullSizeBitmap.isOpaque() should be correct. > hasAlpha should be defaulted to true. So if isComplete is false, we should use true so that there are no optimization happening elsewhere.
isOpaque() is default to false, it is set to true only if decoder tells it to. So it's more accurate than mixing it with isComplete. For example progressive JPEG, an image can be partially decoded (i.e. isComplete == false) but it is opaque.
Min Qin
Comment 8
2013-02-12 10:52:19 PST
Created
attachment 187898
[details]
Patch
Min Qin
Comment 9
2013-02-12 10:52:47 PST
Comment on
attachment 186672
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=186672&action=review
>> Source/WebCore/platform/graphics/chromium/DeferredImageDecoder.cpp:185 >> + LazyDecodingPixelRef* pixelRef = static_cast<LazyDecodingPixelRef*>(m_lazyDecodedFrame.getSkBitmap().pixelRef()); > > alpha state should be saved in ImageFrameGenerator. > > ImageFrameGenerator corresponds to one image file. It exists regardless whether or not an image is cached or not. So in the case of ScaledImageFragment being evicted the code can return the correct alpha state regardless of whether it is cached or not.
Done.
>>>>>> Source/WebCore/platform/graphics/chromium/ImageFrameGenerator.cpp:213 >>>>>> + bool hasAlpha = (*decoder)->frameHasAlphaAtIndex(0); >>>>> >>>>> Do something like: >>>>> >>>>> m_hasAlpha = isComplete && !fullSizeBitmap.isOpaque(); >>>> >>>> hmm.... if isComplete is false, shouldn't we return true there to force image decoding? >>> >>> I don't know what you mean. >>> >>> Actually now I think about it again you can just do !fullSizeBitmap.isOpaque(). Don't call frameHasAlphaAtIndex(0) it might have side effect. >> >> Yes, I think !fullSizeBitmap.isOpaque() should be correct. >> hasAlpha should be defaulted to true. So if isComplete is false, we should use true so that there are no optimization happening elsewhere. > > isOpaque() is default to false, it is set to true only if decoder tells it to. So it's more accurate than mixing it with isComplete. For example progressive JPEG, an image can be partially decoded (i.e. isComplete == false) but it is opaque.
Done.
Hin-Chung Lam
Comment 10
2013-02-12 21:34:43 PST
Comment on
attachment 187898
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=187898&action=review
> Source/WebCore/platform/graphics/chromium/DeferredImageDecoder.cpp:186 > + return pixelRef->frameGenerator()->hasAlpha();
DeferredImageDecoder already has a pointer to ImageFrameGenerator.
> Source/WebCore/platform/graphics/chromium/ImageFrameGenerator.h:70 > + bool hasAlpha() const { return m_hasAlpha; }
This is not thread-safe and we need a lock for reading and writing to this value. You don't want to acquire the decodeMutex.. so I guess it's fine to have a alphaMutex (reluctantly..)
Min Qin
Comment 11
2013-02-13 13:23:42 PST
Created
attachment 188163
[details]
Patch
Min Qin
Comment 12
2013-02-13 13:26:25 PST
Comment on
attachment 187898
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=187898&action=review
>> Source/WebCore/platform/graphics/chromium/DeferredImageDecoder.cpp:186 >> + return pixelRef->frameGenerator()->hasAlpha(); > > DeferredImageDecoder already has a pointer to ImageFrameGenerator.
Done.
>> Source/WebCore/platform/graphics/chromium/ImageFrameGenerator.h:70 >> + bool hasAlpha() const { return m_hasAlpha; } > > This is not thread-safe and we need a lock for reading and writing to this value. > > You don't want to acquire the decodeMutex.. so I guess it's fine to have a alphaMutex (reluctantly..)
Good catch on thread safety.
Hin-Chung Lam
Comment 13
2013-02-13 13:33:54 PST
Okay. LGTM.
Min Qin
Comment 14
2013-02-13 15:05:55 PST
ping. Stephen, any thoughts on this.
Stephen White
Comment 15
2013-02-13 17:03:00 PST
Comment on
attachment 188163
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=188163&action=review
OK. r=me
> Source/WebCore/platform/graphics/chromium/ImageFrameGenerator.cpp:227 > + MutexLocker lock(m_alphaMutex); > + return m_hasAlpha;
I know I'll regret asking this, since threading has a long history of making me look like an idiot, but why do you need to lock the mutex for a read? It's a bool, so all reads should be atomic anyway, no?
Min Qin
Comment 16
2013-02-13 18:18:48 PST
Comment on
attachment 188163
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=188163&action=review
>> Source/WebCore/platform/graphics/chromium/ImageFrameGenerator.cpp:227 >> + return m_hasAlpha; > > I know I'll regret asking this, since threading has a long history of making me look like an idiot, but why do you need to lock the mutex for a read? It's a bool, so all reads should be atomic anyway, no?
reading a bool should be atomic, but I am not sure whether this is the case with multi-core processor cache. If read/write are on different processors, this probably might not hold.
Min Qin
Comment 17
2013-02-13 20:15:47 PST
(In reply to
comment #16
)
> (From update of
attachment 188163
[details]
) > View in context:
https://bugs.webkit.org/attachment.cgi?id=188163&action=review
> > >> Source/WebCore/platform/graphics/chromium/ImageFrameGenerator.cpp:227 > >> + return m_hasAlpha; > > > > I know I'll regret asking this, since threading has a long history of making me look like an idiot, but why do you need to lock the mutex for a read? It's a bool, so all reads should be atomic anyway, no? > > reading a bool should be atomic, but I am not sure whether this is the case with multi-core processor cache. > If read/write are on different processors, this probably might not hold.
In addition to processor cache, there could be other factors that cause out-of-order execution: pipelining, cache, optimization etc. In such cases, when we set the boolean to false, the code before the set statement might not have been executed yet.
Stephen White
Comment 18
2013-02-14 03:39:20 PST
Comment on
attachment 188163
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=188163&action=review
>>>> Source/WebCore/platform/graphics/chromium/ImageFrameGenerator.cpp:227 >>>> + return m_hasAlpha; >>> >>> I know I'll regret asking this, since threading has a long history of making me look like an idiot, but why do you need to lock the mutex for a read? It's a bool, so all reads should be atomic anyway, no? >> >> reading a bool should be atomic, but I am not sure whether this is the case with multi-core processor cache. >> If read/write are on different processors, this probably might not hold. > > In addition to processor cache, there could be other factors that cause out-of-order execution: pipelining, cache, optimization etc. In such cases, when we set the boolean to false, the code before the set statement might not have been executed yet.
Looks like I was wrong in the general case anyway: although for the vast majority of CPU architectures, a single read or write of machine word or smaller is guaranteed atomic, this is still technically processor-specific, and not guaranteed by C++. However, I don't understand what you mean by "the code before the set statement might not have executed yet". Do you mean, the call to !fullSizeBitmap.isOpaque()? That seems to be the only thing that the mutex protects: that m_hasAlpha is set to the value of !fullSizeBitmap.isOpaque() atomically. The call to hasAlpha() could come in on another thread before or after that change to the value, and it might return true or false depending on thread ordering. The only thing the mutex ensures is that it won't occur during !fullSizeBitmap.isOpaque() or the assignment. If that's the intent, sorry for the tangent.
Min Qin
Comment 19
2013-02-14 08:48:36 PST
In out-of-order execution, if you have some code like: do_sth_to_beta(); alpha=true; when alpha=true is executed, you cannot guarantee that do_sth_to_beta() is finished. And on another thread, if you have if(alpha) { beta=false; } This is problematic. Since do_sth_to_beta() could be still running, so setting beta to false will have an adverse effect on that call. (In reply to
comment #18
)
> > Looks like I was wrong in the general case anyway: although for the vast majority of CPU architectures, a single read or write of machine word or smaller is guaranteed atomic, this is still technically processor-specific, and not guaranteed by C++. > > However, I don't understand what you mean by "the code before the set statement might not have executed yet". Do you mean, the call to !fullSizeBitmap.isOpaque()? That seems to be the only thing that the mutex protects: that m_hasAlpha is set to the value of !fullSizeBitmap.isOpaque() atomically. The call to hasAlpha() could come in on another thread before or after that change to the value, and it might return true or false depending on thread ordering. The only thing the mutex ensures is that it won't occur during !fullSizeBitmap.isOpaque() or the assignment. If that's the intent, sorry for the tangent.
Stephen White
Comment 20
2013-02-14 09:34:01 PST
(In reply to
comment #19
)
> In out-of-order execution, if you have some code like: > > do_sth_to_beta(); > alpha=true; > > when alpha=true is executed, you cannot guarantee that do_sth_to_beta() is finished.
I think you're confusing out-of-order execution with multithreading. Out-of-order execution only means that instructions can be reordered on the processor if they have no effect on apparent program order. I.e., you can hoist a read above an ALU op, as long as there are no data dependencies between them. The instructions are still retired in program order. Cache coherence ensures that this holds across processors as well.
> And on another thread, if you have > > if(alpha) { > beta=false; > } > This is problematic. Since do_sth_to_beta() could be still running, so setting beta to false will have an adverse effect on that call.
Right, that would be problematic, but that's not the case here: you only have the mutex protecting one write to the variable, and one read, not two writes. As I said before, I don't think the mutex protecting the read is doing anything, but that is processor-dependent and harmless I guess. Anyway, this is getting way off topic for the code review, and my r+ still stands.
> > (In reply to
comment #18
) > > > > Looks like I was wrong in the general case anyway: although for the vast majority of CPU architectures, a single read or write of machine word or smaller is guaranteed atomic, this is still technically processor-specific, and not guaranteed by C++. > > > > However, I don't understand what you mean by "the code before the set statement might not have executed yet". Do you mean, the call to !fullSizeBitmap.isOpaque()? That seems to be the only thing that the mutex protects: that m_hasAlpha is set to the value of !fullSizeBitmap.isOpaque() atomically. The call to hasAlpha() could come in on another thread before or after that change to the value, and it might return true or false depending on thread ordering. The only thing the mutex ensures is that it won't occur during !fullSizeBitmap.isOpaque() or the assignment. If that's the intent, sorry for the tangent.
Hin-Chung Lam
Comment 21
2013-02-14 10:47:38 PST
I love the fact that you guys are discussing locking, atomic read/write in this thread. :D
WebKit Review Bot
Comment 22
2013-02-14 10:51:07 PST
Comment on
attachment 188163
[details]
Patch Clearing flags on attachment: 188163 Committed
r142891
: <
http://trac.webkit.org/changeset/142891
>
WebKit Review Bot
Comment 23
2013-02-14 10:51:11 PST
All reviewed patches have been landed. Closing bug.
Tom Hudson
Comment 24
2013-02-14 10:54:15 PST
If there's some chance the mutex isn't necessary, I wish we hadn't landed this.
Min Qin
Comment 25
2013-02-14 11:01:54 PST
(In reply to
comment #24
)
> If there's some chance the mutex isn't necessary, I wish we hadn't landed this.
I am wondering whether there will be a case that: if (decoder->frameHasAlphaAtIndex(0)) { read_pixelref(); } However, on another thread where alpha value just got set, the skbitmap still haven't been fully decoded yet. So we need a memory barrier there and Mutex should do that.
Hin-Chung Lam
Comment 26
2013-02-14 11:03:44 PST
(In reply to
comment #25
)
> (In reply to
comment #24
) > > If there's some chance the mutex isn't necessary, I wish we hadn't landed this. > > > I am wondering whether there will be a case that: > if (decoder->frameHasAlphaAtIndex(0)) { > read_pixelref(); > } > However, on another thread where alpha value just got set, the skbitmap still haven't been fully decoded yet. So we need a memory barrier there and Mutex should do that.
That will not be the case. alpha value is known only after an image is fully decoded.
Min Qin
Comment 27
2013-02-14 11:10:40 PST
(In reply to
comment #26
)
> (In reply to
comment #25
) > > (In reply to
comment #24
) > > > If there's some chance the mutex isn't necessary, I wish we hadn't landed this. > > > > > > I am wondering whether there will be a case that: > > if (decoder->frameHasAlphaAtIndex(0)) { > > read_pixelref(); > > } > > However, on another thread where alpha value just got set, the skbitmap still haven't been fully decoded yet. So we need a memory barrier there and Mutex should do that. > > That will not be the case. alpha value is known only after an image is fully decoded.
Would multi processor cache hurt?
Hin-Chung Lam
Comment 28
2013-02-14 11:27:14 PST
(In reply to
comment #27
)
> (In reply to
comment #26
) > > (In reply to
comment #25
) > > > (In reply to
comment #24
) > > > > If there's some chance the mutex isn't necessary, I wish we hadn't landed this. > > > > > > > > > I am wondering whether there will be a case that: > > > if (decoder->frameHasAlphaAtIndex(0)) { > > > read_pixelref(); > > > } > > > However, on another thread where alpha value just got set, the skbitmap still haven't been fully decoded yet. So we need a memory barrier there and Mutex should do that. > > > > That will not be the case. alpha value is known only after an image is fully decoded. > > Would multi processor cache hurt?
I don't know what this means. But reading Stephen's comments that get me thinking that mutex might not be necessary. The value is either true or false and it doesn't hurt to have alpha == true. So even if we don't protect it and assignment comes while decode() is running the worst case is alpha is true when it should be false, which is benign anyway.
Min Qin
Comment 29
2013-02-14 11:45:16 PST
(In reply to
comment #28
)
> (In reply to
comment #27
) > > (In reply to
comment #26
) > > > (In reply to
comment #25
) > > > > (In reply to
comment #24
) > > > > > If there's some chance the mutex isn't necessary, I wish we hadn't landed this. > > > > > > > > > > > > I am wondering whether there will be a case that: > > > > if (decoder->frameHasAlphaAtIndex(0)) { > > > > read_pixelref(); > > > > } > > > > However, on another thread where alpha value just got set, the skbitmap still haven't been fully decoded yet. So we need a memory barrier there and Mutex should do that. > > > > > > That will not be the case. alpha value is known only after an image is fully decoded. > > > > Would multi processor cache hurt? > > I don't know what this means. > > But reading Stephen's comments that get me thinking that mutex might not be necessary. The value is either true or false and it doesn't hurt to have alpha == true. So even if we don't protect it and assignment comes while decode() is running the worst case is alpha is true when it should be false, which is benign anyway.
Yes, for this case we are probably fine since the starting value is always true, and will only be changed to false later on. However, if there is a case that we can change the value from false to true, then it will be different. Processor A changes the value from false to true. At the same time processor B checks its own cache and sees that it is false, so it decides to do nothing. But since that is not going to happen, i think we are probably safe.
Hin-Chung Lam
Comment 30
2013-02-14 11:47:49 PST
No, it won't change from false to true.
Note
You need to
log in
before you can comment on or make changes to this bug.
Top of Page
Format For Printing
XML
Clone This Bug