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

Mesh overhaul with custom vertex attributes #592 #599

Merged
merged 35 commits into from
Oct 31, 2020

Conversation

julhe
Copy link
Contributor

@julhe julhe commented Sep 28, 2020

Pull request draft for #592

crates/bevy_render/src/mesh/mesh.rs Outdated Show resolved Hide resolved
crates/bevy_render/src/mesh/mesh.rs Outdated Show resolved Hide resolved
crates/bevy_render/src/mesh/mesh.rs Outdated Show resolved Hide resolved
Comment on lines 641 to 647
for index in 1..4 { //TODO: use actual vertex buffer count
if let Some(RenderResourceId::Buffer(vertex_buffer)) =
render_resource_context.get_asset_resource(*handle, index)
{
println!("setup vertex buffer {}", index);
render_pipelines.bindings.set_vertex_buffer(index as u8, vertex_buffer);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

based on my above comments, this would end up as something like

for pipeline in render_pipelines.pipelines {
    let pipeline_descriptor = pipeline_descriptors.get(pipeline.descriptor).unwrap();
    if let Some(layout) = pipelin_descriptor.layout {
        for (slot, vertex_buffer_descriptor) in layout.vertex_buffer_descriptors.iter().enumerate() {
            let handle = render_resource_context
                .get_asset_resource(*handle, vertex_buffer_descriptor.name)
                .expect("mesh does not provide required vertex attribute {} for pipeline {:?}", vertex_buffer_descriptor.name, pipeline_descriptor);
            println!("setup vertex buffer {}", slot);
            render_pipelines.bindings.set_vertex_buffer(slot as u8, handle);
        }
    }
}

@Moxinilian Moxinilian added C-Feature A new feature, making something new possible A-Rendering Drawing game state to the screen labels Sep 29, 2020
@julhe
Copy link
Contributor Author

julhe commented Sep 29, 2020

Gonna fix the rough edges now and propose this PR. ⌨️

Julian Heinken added 4 commits October 1, 2020 02:28
removed uncessary tests as they don't apply anymore for seperate buffers
removed vertex.rs and as_vertex_buffer_descriptor.rs
simplified ``VertexBufferDescriptor`` to use only one ``VertexAttributeDescriptor``
ran clippy and fmt
@julhe julhe marked this pull request as ready for review October 1, 2020 01:18
@julhe julhe marked this pull request as draft October 1, 2020 09:24
@julhe
Copy link
Contributor Author

julhe commented Oct 1, 2020

#592 (comment)

@julhe julhe changed the title Change default vertex layout to seperate buffers #592 Change default vertex layout to separate buffers #592 Oct 1, 2020
@julhe julhe marked this pull request as ready for review October 1, 2020 23:26
Copy link
Contributor

@fu5ha fu5ha left a comment

Choose a reason for hiding this comment

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

Mostly looking good to me. Has this been tested with sprite/2d pipelines?

@julhe
Copy link
Contributor Author

julhe commented Oct 2, 2020

Has this been tested with sprite/2d pipelines?

Works all for me🙂

@julhe julhe marked this pull request as draft October 3, 2020 01:06
@julhe
Copy link
Contributor Author

julhe commented Oct 5, 2020

Quick summary

  • You can straight forward throw any attribute data at Mesh now and it will be mapped to the named binding slot. No dealing with vertices structs anymore. That also means any code that bridges between separate <-> interleaved vertex data is gone, therefore the reduced code size.
  • That also means that VertexBufferAttributes don't need to be defined upfront. All necessary info (stride, shader_location) is implicit.
  • Shader attribute naming is now mostly irrelevant. Attributes that start with "I_" will be used for instancing.

Uncool things

  • No support for interleaved buffers at all. This is cool for desktop GPUs (and any CPU) but might be a bottleneck on mobile GPUs. Change default vertex layout to seperate buffers #592 (comment)
  • No way of using half for vertex attributes. Would be nice to have, since many attributes (normal, vertex-colors, uv's, ...) can be stored as half just fine. (This wasn't possible before either, but now it would be harder to add).
  • When a vertex buffer is required by a shader but not defined by the mesh, this is only noticed on the very last step. This could be hard to debug in bigger projects.

@julhe julhe marked this pull request as ready for review October 7, 2020 01:19
@julhe
Copy link
Contributor Author

julhe commented Oct 7, 2020

Okay, from my POV there’s nothing to add to this anymore. 🙂

Some post PR things: While this approach will work for now, over long term, we will hit some issues:

  1. As Change default vertex layout to seperate buffers #592 (comment) mention, there will be issues regarding max. bound buffers. from wgpu limitations when animations come into place.
  2. Unbound attribute handling.
  3. Mobile GPUs still preferer interleaved data.
  4. Support for half or other formats

My idea would be to decouple all these things from mesh.rs and instead add something like a VertexDataToGPUAdapter which could:

  • Bundle attributes into interleaved buffers
  • Convert attributes to half or other formats
  • Undefined attribute handling
  • Allow for custom attribute encoding, like converting normals into octahedrons for reduced bandwidth.

This would probably sit somewhere at render_pipeline.rs and would be user configureable. The API would be something like Res<VertexDataToGPUConfig> and could have functions like:

  • fn set_attribute_post_processing(attribute_name: &str, on_attribute_post: Fn) (handles type conversion + attribute post proccessing)
  • fn set_attribute_prefered_interleaved_buffer(attribute_name: &str, buffer_id: usize)
  • fn set_attribute_missing_behaviour(attribute_name: &str, on_attribute_missing: Fn)

@julhe
Copy link
Contributor Author

julhe commented Oct 23, 2020

Summary (Dev version)

  • mesh.rs packs now all attributes into one buffer via attributes_to_vertex_buffer_data().
  • mesh.rs also provides dummy buffer (VERTEX_FALLBACK_BUFFER_ID) for undefined attributes, so the pipeline can be rendered in any case.
  • render_pipeline can now specializes on individual buffer descriptions.
  • reflect_layout returns each attribute as a single buffer. (This shall be subject of change later)
  • Removed any old code like VertexAttribute, Vertex, AsVertexBufferDescriptor
  • RenderResourceContext uses u64 now.
  • mesh.attributes is a HashMap now.

Future stuff

  • Add API to customize attribute data befor passing to buffer to allow:
    • Float -> Half/NormU16/... conversion
    • Attribute Packing (is that even still a thing?)
    • normal compression
    • (custom initialization of undefinied attributes ?)
  • Allow for multiple attribute buffers.
  • Replace buffer names with hashes for tighter structs.
  • Allow for VertexAttributeValues to be unloaded after beeing send to GPU to save CPU memory.
  • Allocated one big fallback buffer instead of speperate ones for each mesh.
  • Provide example.

Copy link
Member

@cart cart left a comment

Choose a reason for hiding this comment

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

In general this looks good to me. Most of my feedback is superficial. Allocating a "fallback buffer" for each Mesh feels like overkill, but its not a big deal and we could always allocate "shared fallback buffers" of varying sizes if/when it becomes a problem. We might need to revisit it when we re-add support for multiple vertex buffers (ex: for instancing).

crates/bevy_render/src/mesh/mesh.rs Outdated Show resolved Hide resolved
crates/bevy_render/src/mesh/mesh.rs Outdated Show resolved Hide resolved
crates/bevy_render/src/mesh/mesh.rs Outdated Show resolved Hide resolved
crates/bevy_render/src/mesh/mesh.rs Outdated Show resolved Hide resolved
crates/bevy_render/src/mesh/mesh.rs Outdated Show resolved Hide resolved
crates/bevy_render/src/mesh/mesh.rs Outdated Show resolved Hide resolved
crates/bevy_render/src/pipeline/pipeline_compiler.rs Outdated Show resolved Hide resolved
crates/bevy_sprite/src/render/sprite_sheet.vert Outdated Show resolved Hide resolved
@cart
Copy link
Member

cart commented Oct 28, 2020

Another followup I'd like is a "custom mesh with custom attributes" example that proves that we support arbitrary layouts with custom shaders.

@julhe
Copy link
Contributor Author

julhe commented Oct 30, 2020

In general this looks good to me. Most of my feedback is superficial. Allocating a "fallback buffer" for each Mesh feels like overkill, but its not a big deal and we could always allocate "shared fallback buffers" of varying sizes if/when it becomes a problem.

Agree. I'm thinking of a generic buffer that expands size by the largest allocated mesh. Will add this to the followup.

@cart
Copy link
Member

cart commented Oct 30, 2020

Looks like sorting attributes breaks the shader_custom_material and shader_defs examples. Maybe something was reliant on that order?

@cart
Copy link
Member

cart commented Oct 31, 2020

Gave the new fixes a try with various permutations of attributes in custom shaders and they all worked. I think this is good to go!

@cart cart merged commit 4645da3 into bevyengine:master Oct 31, 2020
@julhe julhe deleted the render_mesh_seperate_buffers branch October 31, 2020 13:40
@julhe julhe restored the render_mesh_seperate_buffers branch October 31, 2020 13:41
@julhe julhe mentioned this pull request Oct 31, 2020
7 tasks
@J-F-Liu
Copy link
Contributor

J-F-Liu commented Nov 2, 2020

After update to latest bevy code, there is a big performance degradation caused by this PR.

@cart
Copy link
Member

cart commented Nov 2, 2020

@J-F-Liu that's probably related to #764. I have a PR out that should fix it

@J-F-Liu
Copy link
Contributor

J-F-Liu commented Nov 2, 2020

My frame rate dropped from 28 to 7, I check out mesh-allocation-fix and have a try, the frame rate rises to 25.
Btw, Mesh:: attribute(&mut self, should remove mut.

@julhe
Copy link
Contributor Author

julhe commented Nov 2, 2020

@J-F-Liu sounds interesting, can you tell some context? (or even provide some source code?)

@J-F-Liu
Copy link
Contributor

J-F-Liu commented Nov 3, 2020

@julhe There are 5431 mesh objects rendered as PrimitiveTopology::LineList, plus mouse movement screen ray interaction checking.

@cart
Copy link
Member

cart commented Nov 3, 2020

I'm guessing the extra allocations for the VertexBufferDescriptor in each entity's PipelineSpecialization are to blame for the slight drop in performance (and maybe also the act of re-computing it).

If so that would be resolved by the followups called out here: #768 (comment)

@cart
Copy link
Member

cart commented Nov 3, 2020

I think the approach we're using now is the right path forward. We just need to remove some of the hot-spots introduced by some slightly naive choices made for simplicity (and to meet the 0.3 deadline that I have arbitrarily set 😄 ).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-Rendering Drawing game state to the screen C-Feature A new feature, making something new possible
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants