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

Implement sub-image updates. #1003

Merged
merged 1 commit into from
Mar 23, 2017
Merged

Implement sub-image updates. #1003

merged 1 commit into from
Mar 23, 2017

Conversation

nical
Copy link
Contributor

@nical nical commented Mar 22, 2017

Add an optional dirty rect to the update_image command (None means invalidate all), and only upload the required part of the image if the image was already in the texture cache. This will become more important when used with blob images since the blob image renderer will use this information to avoid repainting the entire image when possible.


This change is Reviewable

@nical
Copy link
Contributor Author

nical commented Mar 22, 2017

r? @glennw

Copy link
Member

@glennw glennw left a comment

Choose a reason for hiding this comment

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

One nit and a question about the purpose of the union() and how that works.

@@ -317,6 +320,11 @@ impl ResourceCache {
data: ImageData::new(bytes),
epoch: next_epoch,
tiling: None,
dirty_rect: match (dirty_rect, prev_dirty_rect) {
Copy link
Member

Choose a reason for hiding this comment

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

I don't really understand this part. I'm assuming the union() here is for the case where you update different parts of the same image multiple times in one frame? But then, the second update loses the bytes from the original update doesn't it?

Copy link
Contributor Author

@nical nical Mar 23, 2017

Choose a reason for hiding this comment

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

The case I'm trying to support is updating an image several times (either several times in the same frame or across several frames if the image isn't requested (not in the viewport?)). In this situation the idea is to keep a dirty rectangle containing all dirty rectangles since the last time the texture_cache was updated.

I'm not sure what you mean by losing the bytes of the original update.

Edit: Ah! After talking with @kvark on irc I realize you probably meant by losing the bytes. The image data sent in update image still contains the whole image, the optional dirty rect only gives a hint that only a portion of the new image is different from the previous version.
So at any time the ImageData that we have can fully describe the whole image (only sending the damaged part would make things more complicated because the image might not be in the texture cache, in which case the dirty rect isn't useful since we need to upload the whole thing).

Same thing for blob images, the new blob is the whole "blob display list" for that image.

data: bytes,
stride: descriptor.stride,
offset: descriptor.offset,
if let Some(dirty) = dirty_rect {
Copy link
Member

Choose a reason for hiding this comment

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

This if let is better as a match since there is an else clause anyway.

@@ -147,8 +147,8 @@ impl RenderBackend {
}
self.resource_cache.add_image_template(id, descriptor, data, tiling);
}
ApiMsg::UpdateImage(id, descriptor, bytes) => {
self.resource_cache.update_image_template(id, descriptor, bytes);
ApiMsg::UpdateImage(id, descriptor, bytes, dirty_rect) => {
Copy link
Member

Choose a reason for hiding this comment

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

naming nit: this is not a "dirty" rectangle, just the one to update. "dirty" brings on more semantics than the interface really provides.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I can rename that updated_rect if you prefer.

stride: descriptor.stride,
offset: descriptor.offset,
if let Some(dirty) = dirty_rect {
let stride = descriptor.compute_stride();
Copy link
Member

Choose a reason for hiding this comment

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

that's a bit confusing that we have both descriptor.stride and descriptor.compute_stride()

Copy link
Contributor Author

Choose a reason for hiding this comment

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

What you mean is that ImageDescriptor::stride being an option is confusing, and that's true (but it's convenient because in a lot of cases we don't have a stride larger than width * bpp).
You can fix that by making the stride not optional, and computing it in a construction function if you want.

Copy link
Member

Choose a reason for hiding this comment

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

right. It's not related to this PR though

@@ -317,6 +320,11 @@ impl ResourceCache {
data: ImageData::new(bytes),
Copy link
Member

Choose a reason for hiding this comment

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

where does the old image data go? Looks like it gets lost

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The old image data is replaced by the new one, yes. The underlying buffer is reference counted, not sure what you mean by lost.

offset: descriptor.offset,
if let Some(dirty) = dirty_rect {
let stride = descriptor.compute_stride();
let offset = descriptor.offset + dirty.origin.y * stride + dirty.origin.x;
Copy link
Member

Choose a reason for hiding this comment

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

gotta double-check this line, but it depends on the answers to previous questions

Copy link
Member

@kvark kvark left a comment

Choose a reason for hiding this comment

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

After talking to @nical on IRC, the questions and details were clarified. My only concern would be the need to re-allocate the whole image on each sub-image update, which seems a bit wasteful.

@nical
Copy link
Contributor Author

nical commented Mar 23, 2017

Yes, I considered only passing the updated rect's worth of pixel data in the update message, but that makes the implementation a lot more complicated, and isn't necessarily more efficient because we currently save copies thanks to the image data being immutable and atomically ref counted.

I'm not against doing it this way but I would prefer to have a compelling use case to motivate the extra complexity.

@glennw
Copy link
Member

glennw commented Mar 23, 2017

@nical OK, that makes sense. Let's get this merged - but it would be good to change that if let to a map as a follow up, which is a bit tidier.

@glennw
Copy link
Member

glennw commented Mar 23, 2017

@bors-servo r+

@bors-servo
Copy link
Contributor

📌 Commit 4a6703d has been approved by glennw

@bors-servo
Copy link
Contributor

⌛ Testing commit 4a6703d with merge a24673b...

bors-servo pushed a commit that referenced this pull request Mar 23, 2017
Implement sub-image updates.

Add an optional dirty rect to the update_image command (None means invalidate all), and only upload the required part of the image if the image was already in the texture cache. This will become more important when used with blob images since the blob image renderer will use this information to avoid repainting the entire image when possible.

<!-- 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/1003)
<!-- Reviewable:end -->
@bors-servo
Copy link
Contributor

☀️ Test successful - status-travis
Approved by: glennw
Pushing a24673b to master...

@bors-servo bors-servo merged commit 4a6703d into servo:master Mar 23, 2017
@nical nical mentioned this pull request Mar 24, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants