New issue
Advanced search Search tips
Note: Color blocks (like or ) mean that a user may not be available. Tooltip shows the reason.

Issue 597127 link

Starred by 2 users

Issue metadata

Status: Fixed
Owner:
Closed: Mar 2016
Cc:
Components:
EstimatedDays: ----
NextAction: ----
OS: Android , Mac
Pri: 1
Type: Bug-Regression

Blocked on:
issue 598549



Sign in to add a comment

ctx.drawImage not rendering images properly when some render calls are off the canvas

Reported by ken...@yttromobile.com, Mar 23 2016

Issue description

UserAgent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.87 Safari/537.36

Example URL:
http://h5.yttromobile.com

Steps to reproduce the problem:
The above URL is our production site. Please see simplified test case (attached file).

In the test file, I am creating a large canvas and drawing images tiles into the canvas. Only some of the images are rendered.

Each image is 504x504.
There are 5 images in each direction.
The canvas is 2520x2520.

What is the expected behavior?
All the images should be rendered. The screen should be filled with the canvas. This works properly in Safari.

What went wrong?
Only some images are rendered in the canvas.

Does it occur on multiple sites: N/A

Is it a problem with a plugin? N/A 

Did this work before? Yes Not sure which earlier version worked

Does this work in other browsers? Yes 

Chrome version: 49.0.2623.87  Channel: stable
OS Version: OS X 10.10.5
Flash Version: Shockwave Flash 21.0 r0
 
test-drawImage.html
1.1 KB View Download
More browsers:

Broken
Mac: Chrome Version 49.0.2623.87 (64-bit)
Android: Chrome Version 49.0.2623.91

Works
Linux: Chrome Version 49.0.2623.87 (64-bit)
iOS: Chrome Version 49.0.2623.73


Components: Blink>Canvas

Comment 3 by junov@chromium.org, Mar 23 2016

Labels: -Pri-2 -Type-Compat Needs-Bisect Pri-1 Type-Bug-Regression
Owner: xidac...@chromium.org
Status: Assigned (was: Unconfirmed)
Reproducible on linux if GPU-accelerated canvas is enabled by starting Chrome with --ignore-gpu-blacklist

What I am observing on linux is none of the tile are rendered!

Comment 4 by noel@chromium.org, Mar 26 2016

xidachen@ sent me some CL suggesting that YUV JPEG decoding is at fault.  But, YUV JPEG decoding (Ganesh) is not enabled on desktop chrome, and this bug was reported for Stable 49 Chrome Mac desktop.

Anyway, fist we should have a test case that checks these images can be decoded at all.  Test case attached.

kenson@ could you load that image decoding test case and let us know if you see problems.  Also, if you have experimental features enabled in Chrome, please turn them off (on the chrome://flags page, click the "reset all to default" button).
test-draw-image.html
1002 bytes View Download
noel@ thanks for the img node test case! I reset the chrome://flags as instructed and your img node test shows all the images correctly but the canvas based rendering does not.

Comment 6 by noel@chromium.org, Mar 27 2016

The image test case in #4 works for me, with default hrome flags: all images are shown.  However, enabling --force-gpu-rasterization (Ganesh) via chrome://flags causes the bug to manifest, images are missing (picture attached).
test-draw-image-force-gpu-rasterization.png
761 KB View Download

Comment 7 by noel@chromium.org, Mar 27 2016

I downloaded the missing images and inspected them. They are all the same type: they are all _Progressive JPEG_ images, examples attached.
AGA_7_1x_0_0.jpg
87.2 KB View Download
AGA_7_1x_2_0.jpg
85.8 KB View Download
AGA_7_1x_2_1.jpg
98.9 KB View Download
AGA_7_1x_2_4.jpg
92.3 KB View Download
AGA_7_1x_4_0.jpg
96.1 KB View Download

Comment 8 by noel@chromium.org, Mar 27 2016

Cc: scroggo@chromium.org msarett@chromium.org junov@chromium.org

Comment 9 by noel@chromium.org, Mar 27 2016

I instrumented the code and changed the test case in #4 to draw one of the progressive JPEG images given in #7.

Progressive JPEG Image draw, --force-gpu-rasteriztion (Ganesh), DecodingImageGenerator at address 412503C0, which contains an ImageFrameGenerator at address 4139C820.

Image Drawing steps (annotated).

1) A SkImage preroll calls tryLockAsBitmap() and the SkImageCacherator calls getPixels() on the SkImage as a result, which decodes the image

412503C0 DecodingImageGenerator::onGetPixels
4139C820 ImageFrameGenerator::decodeAndScale m_decodeFailed false
4139C820 ImageFrameGenerator::tryToResumeDecode
4139C820 ImageFrameGenerator::decode
  onGetPixels success

2) That RGBA image decode succeeds. Ganesh then requests YUV decoding of the same image ...

412503C0 DecodingImageGenerator::onRefEncodedData
412503C0 DecodingImageGenerator::onQueryYUV8 m_canYUVDecode true
4139C820 ImageFrameGenerator::getYUVComponentSizes
  getYUVComponentSizes: allDataReceived true
  updateYUVComponentSizes
   decoder->canDecodeToYUV success
  onQueryYUV8 result: success

2a) and the image say it can be YUV decoded, so Genesh tries that ...

412503C0 DecodingImageGenerator::onGetYUV8Planes m_canYUVDecode true
4139C820 ImageFrameGenerator::decodeToYUV m_decodeFailed false
  onGetYUV8Planes decodeToYUV failed

3) but the image fails to YUV decode because it is a Progressive JPEG image and the decode is marked failed.

4) Ganesh falls back on this failure to try using the preroll RGBA decoded image from step 1).

Result: the decoded RGBA image is not drawn, due to 3) marking the decode failed, and an empty box appears on screen in the image test case.

Probable fix: do not mark decoding failed at step 3) to allow Ganesh to fall back to use the preroll RGBA image.

Comment 10 by noel@chromium.org, Mar 27 2016

Interesting then to see what happens in the <canvas> case.  Added a test case for that.
test-draw-canvas.html
1.2 KB View Download

Comment 11 by noel@chromium.org, Mar 27 2016

The canvas test in #10 works for me, with default chrome flags: all images are shown.

When I enable --force-gpu-rasterization (Ganesh) via chrome://flags then the bug manifests, some <canvas> images are missing (picture attached).  And once again, the missing images are all _Progressive JPEG_ images.
test-draw-canvas-force-gpu-rasterization.png
764 KB View Download

Comment 12 by noel@chromium.org, Mar 27 2016

Again, I instrumented the code and changed the test case in #10 to draw one of the progressive JPEG images given in #7 to the <canvas>.

Progressive JPEG Image draw, --force-gpu-rasteriztion (Ganesh), DecodingImageGenerator at address 412503C0, which contains an ImageFrameGenerator at address 4139C820.

<canvas> Image Drawing steps (annotated, note the <canvas> image draw flow is not the same as <img> image draw flow).

1) Ganesh requests YUV decoding of the image ...

412503C0 DecodingImageGenerator::onRefEncodedData
412503C0 DecodingImageGenerator::onQueryYUV8 m_canYUVDecode true
4139C820 ImageFrameGenerator::getYUVComponentSizes
  getYUVComponentSizes: allDataReceived true
  updateYUVComponentSizes
   decoder->canDecodeToYUV success
  onQueryYUV8 result: success

1a) and the image says it can be YUV decoded, so Genesh tries that ...

412503C0 DecodingImageGenerator::onGetYUV8Planes m_canYUVDecode true
4139C820 ImageFrameGenerator::decodeToYUV m_decodeFailed false
  onGetYUV8Planes decodeToYUV failed

2) but the image fails to YUV decode because it is a Progressive JPEG image, and the decode is marked failed.

412503C0 DecodingImageGenerator::onGetPixels
4139C820 ImageFrameGenerator::decodeAndScale m_decodeFailed false
4139C820 ImageFrameGenerator::tryToResumeDecode
4139C820 ImageFrameGenerator::decode
  onGetPixels success

3) Ganesh falls back on this failure and tries to RGBA decode the image (with success).

Result: the decoded RGBA image is not drawn, due to 2) marking the decode failed, and an empty box appears on screen in the <canvas> test case.

Probable fix: do not mark decoding failed at step 2) to allow Ganesh to fall back to use the decoded RGBA image.

Comment 13 by noel@chromium.org, Mar 27 2016

Where was the failure detected that caused the empty image to be drawn?  In my debugging, line 86 in DeferredImageDecoder::createFrameAtIndex()

https://code.google.com/p/chromium/codesearch#chromium/src/third_party/WebKit/Source/platform/graphics/DeferredImageDecoder.cpp&sq=package:chromium&type=cs&l=84&q=DeferredImageDecoder.cpp%20createFrameAtIndex

86:   if (m_frameGenerator && m_frameGenerator->decodeFailed())
87:        return nullptr;
noel@: Yes, my debug also showed that it is return nullptr at line 86. At the reason is that m_frameGenerator->decodeFailed() is true.

Question: if we don't mark decoding failed, then the image will show up correctly, does that mean it won't use GPU in this case?

Comment 15 by noel@chromium.org, Mar 27 2016

xidachen@ thanks for the line 86 confirm.  Re your question: yes the image will show correctly if we don't mark it failed.  And yes that means the GPU won't be used, but that is fine in this case (since we can't YUV decode Progressive JPEG on the GPU).

The fix you proposed in https://codereview.chromium.org/1829923004/#ps1 (don't mark the decode failed) works.  I tested it with the test cases in #4 and #10, and --force-gpu-rasterization ... no more missing images.

Another fix would be to add ImageFrameGenerator::m_yuvDecodingFailed, default false, and in ImageFrameGenerator::decodeToYUV(), set it true if YUV decoding fails therein:

250   ASSERT(decoder->failed());
251   m_yuvDecodeFailed = true;	
252   return false;

ImageFrameGenerator::getYUVComponentSizes() could also test m_yuvDecodeFailed to deny future requests for a YUV decode (since we know they won't work).

Let me know how you'd like to proceed.
noel@: Thank you for the detailed guidance. I will add the m_yuvDecodingFailed in the same patch.
Project Member

Comment 17 by bugdroid1@chromium.org, Mar 27 2016

The following revision refers to this bug:
  https://chromium.googlesource.com/chromium/src.git/+/0e4b0bc92e29939d10ff76a3540b4c2b3b5549b6

commit 0e4b0bc92e29939d10ff76a3540b4c2b3b5549b6
Author: xidachen <xidachen@chromium.org>
Date: Sun Mar 27 22:29:23 2016

Do not set m_decodeFailed in ImageFrameGenerator::decodeToYUV

This method sets m_decodeFailed bit to be true at the end on VUY
decode failure, which can result a null SkImage in

  DeferredImageDecoder::createFrameAtIndex()

when Ganesh is enabled and the image is Progressive JPEG. Ganesh
falls back to displaying an RGBA decoded image on decode failure
but the null SkImage was shown instead (see bug examples).

When decodeToYUV() fails, do not set m_decodeFailed. Instead set
m_yuvDecodingFailed to allow Ganesh fallback logic (that decodes
the image to RGBA on the CPU) to render Progressive JPEG. Update
getYUVComponentSizes() to early return if m_yuvDecodingFailed to
deny subsequent Ganesh requests to YUV decode the image.

BUG= 597127 

Review URL: https://codereview.chromium.org/1829923004

Cr-Commit-Position: refs/heads/master@{#383472}

[modify] https://crrev.com/0e4b0bc92e29939d10ff76a3540b4c2b3b5549b6/third_party/WebKit/Source/platform/graphics/ImageFrameGenerator.cpp
[modify] https://crrev.com/0e4b0bc92e29939d10ff76a3540b4c2b3b5549b6/third_party/WebKit/Source/platform/graphics/ImageFrameGenerator.h

Comment 18 by ajha@chromium.org, Mar 28 2016

Labels: -Needs-Bisect
Removing the Needs-Bisect label as the Fix is already landed  in C#17. Will verify the fix once the latest canary is available.

Comment 19 by msar...@google.com, Mar 28 2016

If we expect progressive jpegs to fail to decode to YUV, we should be able to disable these decode in onQueryYUV8() rather than waiting to fail in onGetYUV8Planes().

We successfully do this *some* of the time now.  yuvSubsampling() catches jpegs where (info.comps_in_scan < info.num_components).
https://code.google.com/p/chromium/codesearch#chromium/src/third_party/WebKit/Source/platform/image-decoders/jpeg/JPEGImageDecoder.cpp&q=JPEGImageDecoder&sq=package:chromium&l=222

However, some progressive jpegs (including the ones in this bug) still have 3 components in their first scan.  They just have additional information on at least one of the components in subsequent scans.

We can detect all progressive/mulit-scan jpegs by instead calling jpeg_has_multiple_scans().

FWIW, skia's decoders support YUV decoding of progressive images.  Is this something Chrome would want?  I *think* this can be fixed in Chrome if we use "comp_info" instead of "cur_comp_info" in outputRawData().

Chrome currently decodes all progressive images in buffered image mode.  I'm not sure it makes much sense to decode to YUV in buffered image mode, since we would have to repeatedly draw YUV->RGBA every time the YUV data was updated.  Maybe this is not so bad though?

Another alternative would be to disable buffered image mode on YUV decodes of progressive images (again if that was something we wanted to support).

Comment 20 by noel@chromium.org, Mar 29 2016

jpeg_has_multiple_scans() and the other fixes you suggest all seem possible, and would need testing.  Might be a good subject for another bug?

There are no layout tests for the YUV decoding modes we do currently support, so maybe some tests are due in that area, per :)

https://codereview.chromium.org/1719533002#msg35
https://codereview.chromium.org/1719533002#msg41

and add a layout test for this current bug.

Comment 21 by noel@chromium.org, Mar 29 2016

Blockedon: 598549

Comment 22 by msar...@google.com, Mar 29 2016

Yes I agree that the first step would be adding tests and I agree that this fits in another bug.  I'll go ahead and file one and notify when I can start work on this.
Status: Fixed (was: Assigned)
verified on Mac with latest snapshot, the bug is fixed.

Comment 25 by noel@chromium.org, Mar 29 2016

Verified on Win with latest snapshot, the bug is fixed.

Comment 26 by noel@chromium.org, Mar 30 2016

kenson@ re: the progressive JPEG images in #7.  Do you own those images?  We need permission from their owner to use them a Blink layout test.  Possible?

noel@ Unfortunately I do not own the images. The images are built from app icons from Apple App Store apps.

I'll see if I can create another test case using Creative Commons-licensed images.
I've found some images from http://www.gratisography.com/, under the permissive CC0 license (http://www.gratisography.com/terms.html). I've processed these images in the same manner that I processed the previous test images. The attached test cases are updated to use these new images.

test-drawImage-cc0.html (using canvas) still shows the issue (missing images)
test-draw-image-cc0.html (regular <img>) does not show the issue (all images visible)

Can anyone else reproduce the missing images with test-draw-image-cc0.html on Chrome Stable?

BTW these images are hosted on yttromobile.com so if the images become part of an automated test suite, can they be copied/hosted elsewhere?

test-drawImage-cc0.html
1.1 KB View Download
test-draw-image-cc0.html
993 bytes View Download
Status: Assigned (was: Fixed)
kenson@: re-opening this bug for further investigation based on your comment.
kenson@: Were you trying the new tests on Chrome stable? The change that we made is not pushed to the stable channel. If you are using windows, could you try chrome canary here: https://www.google.com/chrome/browser/canary.html.

If you are using Mac, could you download the latest snapshot here:
https://commondatastorage.googleapis.com/chromium-browser-snapshots/index.html?prefix=Mac/383958/

The newly attached files seem to both display fine when I use the latest snapshot on mac.
xidachen@ Sorry for the confusion. I was re-creating the test cases and ensuring that they are still broken on Chrome Stable. Unfortunately, I was not able to cause test-draw-image-cc0.html (regular <img>) to break again. 

Glad to see they are fixed on Chrome Canary!


Status: Fixed (was: Assigned)

Comment 33 by noel@chromium.org, Mar 30 2016

#31 I was re-creating the test cases and ensuring that they are still broken on Chrome Stable. Unfortunately, I was not able to cause test-draw-image-cc0.html (regular <img>) to break again.

Reload the image test case a few times.  Doing that, I see missing images with in Chrome Stable Win when running with --force-gpu-rasterization.
chrome-stable-win-49.0.2623.108-test-draw-image-c00-result.png
307 KB View Download

Comment 34 by noel@chromium.org, Mar 30 2016

And I see _no missing images_ when running Chrome Canary Win 51.0.2694.1 canary (64-bit) when running with --force-gpu-rasterization.  Looks fixed to me.

Comment 35 by noel@chromium.org, Apr 4 2016

Labels: OS-Android
Tests submitted:  issue 598949   issue 598549  and  issue 600087 .  Updating labels: GPU rasterization ships on Android only, and then only if the web page uses a special <meta> tag (refer to  issue 598949  for details).


Comment 36 by noel@chromium.org, Apr 4 2016

xidachen@, want to do the honors and apply for merge labels now the fix has had sufficient time to bake on canary?
Labels: Merge-Request-50
Happy to do so, thank you for asking.

Comment 38 by tin...@google.com, Apr 4 2016

Labels: -Merge-Request-50 Merge-Approved-50 Hotlist-Merge-Approved
Your change meets the bar and is auto-approved for M50 (branch: 2661)
Project Member

Comment 39 by bugdroid1@chromium.org, Apr 4 2016

Labels: -merge-approved-50 merge-merged-2661
The following revision refers to this bug:
  https://chromium.googlesource.com/chromium/src.git/+/e367e01f30ded9fef9dac6a8574cc372e5b05e0f

commit e367e01f30ded9fef9dac6a8574cc372e5b05e0f
Author: Xida Chen <xidachen@chromium.org>
Date: Mon Apr 04 14:17:53 2016

Do not set m_decodeFailed in ImageFrameGenerator::decodeToYUV

This method sets m_decodeFailed bit to be true at the end on VUY
decode failure, which can result a null SkImage in

  DeferredImageDecoder::createFrameAtIndex()

when Ganesh is enabled and the image is Progressive JPEG. Ganesh
falls back to displaying an RGBA decoded image on decode failure
but the null SkImage was shown instead (see bug examples).

When decodeToYUV() fails, do not set m_decodeFailed. Instead set
m_yuvDecodingFailed to allow Ganesh fallback logic (that decodes
the image to RGBA on the CPU) to render Progressive JPEG. Update
getYUVComponentSizes() to early return if m_yuvDecodingFailed to
deny subsequent Ganesh requests to YUV decode the image.

BUG= 597127 

Review URL: https://codereview.chromium.org/1829923004

Cr-Commit-Position: refs/heads/master@{#383472}
(cherry picked from commit 0e4b0bc92e29939d10ff76a3540b4c2b3b5549b6)

Review URL: https://codereview.chromium.org/1860523002 .

Cr-Commit-Position: refs/branch-heads/2661@{#471}
Cr-Branched-From: ef6f6ae5e4c96622286b563658d5cd62a6cf1197-refs/heads/master@{#378081}

[modify] https://crrev.com/e367e01f30ded9fef9dac6a8574cc372e5b05e0f/third_party/WebKit/Source/platform/graphics/ImageFrameGenerator.cpp
[modify] https://crrev.com/e367e01f30ded9fef9dac6a8574cc372e5b05e0f/third_party/WebKit/Source/platform/graphics/ImageFrameGenerator.h

Sign in to add a comment