Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle big size image #1564

Merged
merged 3 commits into from Oct 16, 2017
Merged

Handle big size image #1564

merged 3 commits into from Oct 16, 2017

Conversation

@JerryShih
Copy link
Contributor

JerryShih commented Aug 9, 2017

@nical @glennw @kvark @sotaroikeda
r?

This patch try to handle the #1405.
If we hit the maximum texture size, turn to use a 1x1 rgba(255,255,255,255) dummy texture.


This change is Reviewable

@glennw
Copy link
Member

glennw commented Aug 9, 2017

I'm working on a large refactoring of the texture cache at the moment - if possible, I'd like to hold off on merging this until that's done. Is that going to be OK? (I would expect it to be done early next week). Handling this case should be much simpler with the changes I'm working on, too.

@bors-servo
Copy link
Contributor

bors-servo commented Aug 10, 2017

The latest upstream changes (presumably #1563) made this pull request unmergeable. Please resolve the merge conflicts.

@JerryShih
Copy link
Contributor Author

JerryShih commented Aug 11, 2017

@glennw
That's fine. If the refactor is done, please show the note in this thread.

@glennw
Copy link
Member

glennw commented Aug 17, 2017

@JerryShih The texture cache refactor has landed now. Instead of trying to use a dummy texture for this case, could we just not add the item to any batches when we find an invalid texture?

@JerryShih
Copy link
Contributor Author

JerryShih commented Aug 17, 2017

@JerryShih The texture cache refactor has landed now. Instead of trying to use a dummy texture for this case, could we just not add the item to any batches when we find an invalid texture?

@glennw
That could be another approach. I think I will still use a special id for the big size allocation(or failed allocation). Then, we could skip the item with that id in batch list or draw with a special color texture for debugging(with a 1x1 black dummy texture).

@glennw
Copy link
Member

glennw commented Aug 17, 2017

I think the simplest approach will be to early exit from request_image in resource cache, before even getting to texture cache. Then, get_cached_image could just return SourceTexture::Invalid. But let's see how this looks after rebasing to the new texture cache and decide from there :)

@JerryShih JerryShih force-pushed the JerryShih:handle-big-size-image branch 2 times, most recently from 56d88b5 to d58c2ff Aug 17, 2017
@JerryShih
Copy link
Contributor Author

JerryShih commented Aug 17, 2017

@glennw r?

And I need the help for the wrench reftest. I got the different result from the standalone yaml replay and the reftest result.

standalone:
I could see a black Rect. That's what I want.
cargo run show reftests/image/very-big-tile-size.yaml

reftest:
I got a gray Rect.
./headless.py reftest reftests/image/very-big-tile-size.yaml

I don't know the difference between them.

@bors-servo
Copy link
Contributor

bors-servo commented Aug 17, 2017

The latest upstream changes (presumably #1585) made this pull request unmergeable. Please resolve the merge conflicts.

@JerryShih JerryShih force-pushed the JerryShih:handle-big-size-image branch 3 times, most recently from 45c30a8 to 09a5c21 Aug 18, 2017
@JerryShih
Copy link
Contributor Author

JerryShih commented Aug 18, 2017

@glennw r? again.
rebase.
I still hit the reftest problem with wrench. Maybe you have some hints for this problem.

@glennw
Copy link
Member

glennw commented Aug 18, 2017

@JerryShih I'm not really sure why it would be different between standalone and reftest. Perhaps the wrong texture is getting bound or something like that?

I wrote up a prototype of what I was discussing above here glennw@9ca1214

I think if we use a solution like this, where it doesn't involve the texture cache at all, the code is quite a bit simpler. And when we want to display the bad texture, we could do that as a follow up in the renderer (handle the case where a texture resolves to SourceTexture::Invalid during batching). What do you think?

@JerryShih
Copy link
Contributor Author

JerryShih commented Aug 18, 2017

@JerryShih I'm not really sure why it would be different between standalone and reftest. Perhaps the wrong texture is getting bound or something like that?

I wrote up a prototype of what I was discussing above here glennw/webrender@9ca1214

I think if we use a solution like this, where it doesn't involve the texture cache at all, the code is quite a bit simpler. And when we want to display the bad texture, we could do that as a follow up in the renderer (handle the case where a texture resolves to SourceTexture::Invalid during batching). What do you think?

Your prototype is much simpler than me. So, yours is a better solution. I add a comment in glennw/webrender@9ca1214. I will create another follow up if we need to show the skipped image.

@glennw
Copy link
Member

glennw commented Aug 18, 2017

@JerryShih Sounds good, thanks! Do you want me to follow up your comments and open a PR, or should I leave that for you?

@JerryShih
Copy link
Contributor Author

JerryShih commented Aug 18, 2017

@glennw
I would like to do that!

@JerryShih
Copy link
Contributor Author

JerryShih commented Aug 18, 2017

@glennw has a better solution. Close this pr.

@JerryShih JerryShih closed this Aug 18, 2017
@JerryShih JerryShih reopened this Sep 5, 2017
@JerryShih JerryShih force-pushed the JerryShih:handle-big-size-image branch from 09a5c21 to 152401b Sep 5, 2017
@JerryShih
Copy link
Contributor Author

JerryShih commented Sep 5, 2017

@glennw @kvark r? again.
This version just skip the image request and return a invalid CacheItem for the big size image request.

// just early out and drop the image.
if tile_size as u32 > self.texture_cache.max_texture_size() {
warn!("Dropping image, tile size:{} is too big for hardware!", tile_size);
return;

This comment has been minimized.

@kvark

kvark Sep 6, 2017

Member

I'm a bit uncomfortable with these return statements as they are different from other return code paths from this method in that they are failures, while others are successes.
How about we return true/false (at least), and then also modify prepare_prim_for_render to return Option<Metadata> so that a primitive that failed to prepare can be discarded in time?

This comment has been minimized.

@JerryShih

JerryShih Sep 7, 2017

Author Contributor

@kvark
I'm not familiar with the frame_builder::build process. The prepare_prim_for_render() is called by frame_builder::handle_primitive_run()[1]. And the handle_primitive_run() looks like to handle the mask and clip related thing. Are you thinking about skipping the render-task creation in handle_primitive_run() for the case of None Option return value?

[1]
https://dxr.mozilla.org/mozilla-central/rev/c959327c6b75cd4930a6ea087583c38b805e7524/gfx/webrender/src/frame_builder.rs#1996

This comment has been minimized.

@kvark

kvark Sep 7, 2017

Member

Yes

This comment has been minimized.

@JerryShih

JerryShih Oct 11, 2017

Author Contributor

The prepare_prim_for_render() is changed. The "Metadata" can't be remove now.

From the first comment:

I'm a bit uncomfortable with these return statements as they are different from other return code paths from this method in that they are failures, while others are successes.

We still have a case with a failure at [1] in request_image(). So, the new return statements are not just the new failed case. If they are still not looked good, I need to check the prepare_prim_for_render() for the "Metadata" removing.

[1]

debug_assert!(texture_id == None ||
texture_id == Some(cache_item.texture_id));
texture_id = Some(cache_item.texture_id);
if let Some(glyph) = glyph_key_cache.get(key) {

This comment has been minimized.

@kvark

kvark Sep 6, 2017

Member

We need to handle the case of failure here. Does it make sense to return as usual if some of the glyphs failed to be obtained?

//
// TODO(Jerry): add a debug option to fill the corresponding area for
// that invalid CacheItem.
image_info.map_or(CacheItem::invalid(), |image_info| {

This comment has been minimized.

@kvark

kvark Sep 6, 2017

Member

we call get_glyphs when populating batches. Wouldn't it be simpler to just return an error here, so that a corresponding instance can be discarded?

This comment has been minimized.

@JerryShih

JerryShih Oct 11, 2017

Author Contributor

We call get_glyphs at [1]. If there is any error inside get_glyphs()[2], the lambda expression at [3] will not be called(which will push the instance to draw list).

[1]

ctx.resource_cache.fetch_glyphs(

[2]
https://github.com/servo/webrender/pull/1564/files#diff-77cbdf7ba9ebae81feb38a64c21b8454R630
[3]
|texture_id, glyphs| {

@bors-servo
Copy link
Contributor

bors-servo commented Sep 12, 2017

The latest upstream changes (presumably #1689) made this pull request unmergeable. Please resolve the merge conflicts.

@glennw
Copy link
Member

glennw commented Oct 2, 2017

@JerryShih @kvark What's the status of this?

@JerryShih
Copy link
Contributor Author

JerryShih commented Oct 3, 2017

@glennw I'm check an animation artifact problem with WR. I will go back to finish this soon.

@JerryShih JerryShih force-pushed the JerryShih:handle-big-size-image branch from 152401b to 58a136f Oct 11, 2017
@@ -813,6 +817,11 @@ impl ClipBatcher {
ClipSource::Image(ref mask) => {
let cache_item =
resource_cache.get_cached_image(mask.image, ImageRendering::Auto, None);
// Skip the invalid image mask.
if cache_item.texture_id == SourceTexture::Invalid {

This comment has been minimized.

@JerryShih

JerryShih Oct 11, 2017

Author Contributor

This image mask will be rendered at [1]. So, I think we should skip this image if the texture id is not valid.

[1]

for (mask_texture_id, items) in target.clip_batcher.images.iter() {

@JerryShih
Copy link
Contributor Author

JerryShih commented Oct 11, 2017

Copy link
Member

kvark left a comment

Thanks for updating the PR!
I think my only concern is that we still need the key to be present in the resources map, while turning value into Result.

self.resources
.get(key)
.expect("Didn't find a cached resource with that ID!")
/// In some cases, we can't handle the resource request(e.g. the user

This comment has been minimized.

@kvark

kvark Oct 11, 2017

Member

I think we should still differentiate between keys that didn't end up in the map for some other logical reasons, and keys that were just failing to be added. Perhaps, the resources map should contain Result<V> instead of V, so that we can handle those failures in a more explicit way?

@JerryShih JerryShih force-pushed the JerryShih:handle-big-size-image branch from 58a136f to 867da17 Oct 12, 2017
@@ -1057,7 +1057,6 @@ impl PrimitiveStore {
}
}

/// Returns true if the bounding box needs to be updated.

This comment has been minimized.

@JerryShih

JerryShih Oct 12, 2017

Author Contributor

This comment is not correct now.

pub struct ResourceClassCache<K, V> {
resources: FastHashMap<K, V>,
resources: FastHashMap<K, ResourceCacheCacheResult<V>>,

This comment has been minimized.

@JerryShih

JerryShih Oct 12, 2017

Author Contributor

Use Result instead of V.

// just early out and drop the image.
if tile_size as u32 > self.texture_cache.max_texture_size() {
warn!("Dropping image, tile size:{} is too big for hardware!", tile_size);
self.cached_images.insert(request, Err(ResourceClassCacheError::OverLimitSize));

This comment has been minimized.

@JerryShih

JerryShih Oct 12, 2017

Author Contributor

If we hit the size limitation, just insert an Err() entry.

@JerryShih
Copy link
Contributor Author

JerryShih commented Oct 12, 2017

@kvark r?
Try to use Result in ResourceClassCache.

@JerryShih
Copy link
Contributor Author

JerryShih commented Oct 12, 2017

I haven't handled the Err() case for each get/get_mut() call, but I will just add some logs for these paths if we need to have these logs.

Copy link
Member

kvark left a comment

Thanks @JerryShih ! A few more things to fix before we proceed.

OverLimitSize,
}

pub type ResourceCacheCacheResult<V> = Result<V, ResourceClassCacheError>;

This comment has been minimized.

@kvark

kvark Oct 12, 2017

Member

perhaps you meant ResourceClassCacheResult?

@@ -159,7 +174,7 @@ where
.cloned()
.collect::<Vec<_>>();
for key in resources_to_destroy {
self.resources.remove(&key).unwrap();

This comment has been minimized.

@kvark

kvark Oct 12, 2017

Member

why is this removed? I assume we get a warning about unused Result or Option

}
} else {
// The image is too big for hardware texture size.
if template.descriptor.width > self.texture_cache.max_texture_size() ||

This comment has been minimized.

@kvark

kvark Oct 12, 2017

Member

should probably merge this block with the one above, using let side_size = image.tiling.unwrap_or(cmp::max(template.descriptor.width, template.descriptor.height));

// If this image exists in the texture cache, *and* the epoch
// in the cache matches that of the template, then it is
// valid to use as-is.
let (entry, needs_update) = match self.cached_images.entry(request) {
Occupied(entry) => {
let needs_update = entry.get().epoch != template.epoch;
let needs_update = entry.get().as_ref().ok().unwrap().epoch != template.epoch;

This comment has been minimized.

@kvark

kvark Oct 12, 2017

Member

no need for ok() here

true,
),
};

let needs_upload = self.texture_cache
.request(&mut entry.texture_cache_handle, gpu_cache);
.request(&mut entry.as_mut().ok().unwrap().texture_cache_handle, gpu_cache);

This comment has been minimized.

@kvark

kvark Oct 12, 2017

Member

same here - no need for ok()

@@ -656,7 +692,15 @@ impl ResourceCache {
tile,
};
let image_info = &self.cached_images.get(&key);

This comment has been minimized.

@kvark

kvark Oct 12, 2017

Member

would probably be cleaner with a simple match statement

@@ -816,7 +860,7 @@ impl ResourceCache {
image_template.descriptor.clone()
};

let entry = self.cached_images.get_mut(&request).unwrap();
let entry = self.cached_images.get_mut(&request).as_mut().ok().unwrap();

This comment has been minimized.

@kvark

kvark Oct 12, 2017

Member

no need for ok()

@@ -516,6 +517,8 @@ impl AlphaRenderItem {
glyph_fetch_buffer,
gpu_cache,
|texture_id, glyphs| {
debug_assert!(texture_id != SourceTexture::Invalid);

This comment has been minimized.

@kvark

kvark Oct 12, 2017

Member

nit: debug_assert_ne!()

//
// TODO(Jerry): add a debug option to fill the corresponding area for
// that invalid CacheItem.
image_info.as_ref().ok().map_or(CacheItem::invalid(), |image_info| {

This comment has been minimized.

@kvark

kvark Oct 12, 2017

Member

let's just return Result<CacheItem, _> from this function and match it on the other side, there is no need for nullable CacheItem semantic (that invalid() does here)

@JerryShih JerryShih force-pushed the JerryShih:handle-big-size-image branch from 867da17 to d68cf51 Oct 13, 2017
@@ -174,7 +167,7 @@ where
.cloned()
.collect::<Vec<_>>();
for key in resources_to_destroy {
self.resources.remove(&key);
self.resources.remove(&key).unwrap();

This comment has been minimized.

@JerryShih

JerryShih Oct 13, 2017

Author Contributor

I revert the change, but the CI test is failed.

error: unused std::result::Result which must be used
--> src/resource_cache.rs:170:13
|
170 | self.resources.remove(&key).unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: -D unused-must-use implied by -D warnings

@JerryShih
Copy link
Contributor Author

JerryShih commented Oct 13, 2017

@kvark r? for d68cf51

@kvark
kvark approved these changes Oct 13, 2017
@kvark
Copy link
Member

kvark commented Oct 13, 2017

Thank you for addressing my comments!

self.resources.remove(&key).unwrap();

Let's do let _ = self.resources.remove(&key).unwrap();

Please squash the commits together, and we can merge once CI is happy.

@JerryShih JerryShih force-pushed the JerryShih:handle-big-size-image branch from d68cf51 to f903161 Oct 16, 2017
…it image request.

WR can't handle the image request if it's bigger than the hardware limit. Please check texture_cache::max_texture_size().

Skip the image request for a big size image in resource_cache::request_image().
Return an Err() for a big size image in resource_cache::get_cached_image().
@JerryShih
Copy link
Contributor Author

JerryShih commented Oct 16, 2017

@kvark
Update for CI "self.resources.remove(&key).unwrap();" failed, and squash the patch set.

@kvark
Copy link
Member

kvark commented Oct 16, 2017

@JerryShih awesome, :shipit: ! 👍
@bors-servo r+

@bors-servo
Copy link
Contributor

bors-servo commented Oct 16, 2017

📌 Commit f903161 has been approved by kvark

@bors-servo
Copy link
Contributor

bors-servo commented Oct 16, 2017

Testing commit f903161 with merge e4cca26...

bors-servo added a commit that referenced this pull request Oct 16, 2017
Handle big size image

@nical @glennw @kvark @sotaroikeda
r?

This patch try to handle the #1405.
If we hit the maximum texture size, turn to use a 1x1 rgba(255,255,255,255) dummy texture.

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/webrender/1564)
<!-- Reviewable:end -->
@bors-servo
Copy link
Contributor

bors-servo commented Oct 16, 2017

☀️ Test successful - status-appveyor, status-travis
Approved by: kvark
Pushing e4cca26 to master...

@bors-servo bors-servo merged commit f903161 into servo:master Oct 16, 2017
4 checks passed
4 checks passed
Taskcluster (pull_request) TaskGroup: success
Details
continuous-integration/appveyor/pr AppVeyor build succeeded
Details
continuous-integration/travis-ci/pr The Travis CI build passed
Details
homu Test successful
Details
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked issues

Successfully merging this pull request may close these issues.

None yet

4 participants
You can’t perform that action at this time.