Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

[Impeller] Don't discard GLES buffer for each copy; respect destination offset #33545

Merged
merged 2 commits into from
May 23, 2022

Conversation

bdero
Copy link
Member

@bdero bdero commented May 22, 2022

Ran into this while working on impeller-cmake-example. The ImGui Impeller backend allocates one geometry buffer per frame, performing two contiguous buffer copies using DeviceBuffer::CopyHostBuffer: One for vertices and one for indices.

This fixes two problems:

  • The buffer was getting discarded/recreated with each CopyHostBuffer call.
  • The destination offset was not being respected, so writes to the buffer were always starting at the first byte.

Made lots of progress with impeller-cmake on Windows this weekend! Screenshot of the example so far:

image

@bdero bdero requested review from chinmaygarde and dnfield May 22, 2022 21:35
@flutter-dashboard
Copy link

It looks like this pull request may not have tests. Please make sure to add tests before merging. If you need an exemption to this rule, contact Hixie on the #hackers channel in Chat (don't just cc him here, he won't see it! He's on Discord!).

If you are not sure if you need tests, consider this rule of thumb: the purpose of a test is to make sure someone doesn't accidentally revert the fix. Ask yourself, is there anything in your PR that you feel it is important we not accidentally revert back to how it was before your fix?

Reviewers: Read the Tree Hygiene page and make sure this patch meets those guidelines before LGTMing.

Copy link
Member

@chinmaygarde chinmaygarde left a comment

Choose a reason for hiding this comment

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

Nits, suggestions and yak-shaves. But otherwise looks like a positive bug fix. Thanks for braving into using this super new backend.

@@ -3,7 +3,9 @@
// found in the LICENSE file.

#include "impeller/renderer/backend/gles/allocator_gles.h"
#include <memory>
Copy link
Member

Choose a reason for hiding this comment

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

Nit: Newline between the header types.

Copy link
Member Author

Choose a reason for hiding this comment

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

Done.

return false;
}
data_ = std::move(mapping);

std::memmove(buffer_->GetBuffer() + offset, source + source_range.offset,
Copy link
Member

Choose a reason for hiding this comment

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

Oof. Good catch.

@@ -33,8 +39,9 @@ class DeviceBufferGLES final
ReactorGLES::Ref reactor_;
HandleGLES handle_;
std::string label_;
mutable std::shared_ptr<fml::Mapping> data_;
mutable bool uploaded_ = false;
mutable std::shared_ptr<Allocation> buffer_;
Copy link
Member

Choose a reason for hiding this comment

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

I think a better name for this would be backing_store_.

Copy link
Member Author

Choose a reason for hiding this comment

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

Done.

mutable std::shared_ptr<fml::Mapping> data_;
mutable bool uploaded_ = false;
mutable std::shared_ptr<Allocation> buffer_;
mutable bool dirty_ = false;
Copy link
Member

Choose a reason for hiding this comment

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

IMO, the dirty_ and has_uploaded_ is becoming hard to reason about. The only reason has_uploaded_ exists is because debug object labels cannot be set be on textures and buffers that are generated but not bound (they are so called "create on bind" resources). Unfortunately, glCreateBuffers and friends are not available on OpenGL ES 2. So the has_uploaded_ field was tracking the create (via bind and data upload).

Perhaps you can add a field here that bumps up the generation of data whenever we get a SetContents call and another field that notes the generation that's been uploaded (so, generation_ and uploaded_generation_). We can set debug labels and such when uploaded_generation > 0 and upload data when uploaded_generation_ != generation_.

Copy link
Member Author

Choose a reason for hiding this comment

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

Great idea, done.

TRACE_EVENT0("impeller", "BufferData");
gl.BufferData(target_type, data_->GetSize(), data_->GetMapping(),
gl.BufferData(target_type, buffer_->GetLength(), buffer_->GetBuffer(),
Copy link
Member

Choose a reason for hiding this comment

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

I realize this is a bit yak-shavy, but there is a pessimization here where the entire arena will get uploaded even when only a sub-range has been modified.

In a later patch, we could setup the backing store to use a sparse mmap'ed arena and memmove into it any data the application provides. Then, note the range that must be flushed. During the upload, use glSubTexImage2D to upload the arenas that need to be flushed (after consolidation for overlapping ranges and such).

It is just the tedium of dealing with GLES 2.0 :/

A yak-shave within a yak-shave: impeller/base needs an mmaped allocation for sparse arenas. We just never ended up needing these in the Metal backend (and will probably not need them for anything other than ES). The posix stuff ought to be easy. The windows impl may need someone with a Windows box.

Copy link
Member Author

@bdero bdero May 23, 2022

Choose a reason for hiding this comment

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

Oh yes, for sure. I added a bug here. Did you mean glBufferSubData (as opposed to glSubTexImage2D)? Although having sparse texture uploading would be good too.

Having the backing store be an mmapped arena sounds like a good idea -- just to make sure we're on the same page: The aim would be to make the arena contents have a per-upload lifetime (flush), that way we only ever hang onto enough memory to keep track of what needs uploading, and avoid needlessly mirroring all the device data.

Copy link
Member

Choose a reason for hiding this comment

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

Right. The bug looks good.

@bdero bdero merged commit 7442ecf into flutter:main May 23, 2022
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request May 23, 2022
houhuayong pushed a commit to houhuayong/engine that referenced this pull request Jun 21, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants