Skip to content

Keep all vertice data in a singular buffer #2

Description

@EvoPot

This issue talks about how every vertice data should be kept in a singular buffer should be uploaded when an application written using Jessie is started.

Summary

This is how buffer data is created in Rust using OpenGL ES 2.0 :

fn main() {
    unsafe {
        let vertices: &[u8] = &[/* assume vertex data here */];
        let mut vbo = 0u32;
        gl::GenBuffers(1, &mut vbo);
        gl::BindBuffer(gl::ARRAY_BUFFER, vbo);
        gl::BufferData(
            gl::ARRAY_BUFFER,
            core::mem::size_of_val(vertices) as isize,
            vertices.as_ptr().cast(),
            gl::STATIC_DRAW,
        );
    }
}

This function requires data to be sent from a computers memory connected to the CPU to be sent through the memory of a GPU. This function generally is an expensive operation and it is best if it is done as little as possible.

We want to be able to have our vertice data in such a way that some parts of the data representing a state that doesn't change, for example a label that isn't tied into a text input that is guaranteed to NOT change, for example GitHub's edit menu:

Image

this is an image btw i hope you don't learn it the hard way



The "Write" and "Preview" labels are guaranteed to not change, unless a disruptive action is made (In GitHub's case this can look like changing our language, or simply inspecting the website's source code). This is an illustrative example, lets go with an example where we have a simple label and lets assume that this label can not be disrupted in any other way (It can not be hovered over, its layout doesn't change, etc.)

Image

Because this label is guaranteed to never say anything else, we can store its vertice data in our buffer:

let vertices : &[u8] = &[/* assume vertice data for "Button" here */];

Now lets assume that we have another configuration where the label Button is in another language, for example in Turkish:

Image

... Or Japanese:

Image

Now our vertice structure becomes:

let vertices : &[u8] = &[/* assume vertice data for "Button" here */, /*assume vertice data for "Düğme" here */, /* assume vertice data for "ボタン" here */];

The full code once again:

fn main() {
    unsafe {
        let vertices : &[u8] = &[/* assume vertice data for "Button" here */, /*assume vertice data for "Düğme" here */, /* assume vertice data for "ボタン" here */];
        let mut vbo = 0u32;
        gl::GenBuffers(1, &mut vbo);
        gl::BindBuffer(gl::ARRAY_BUFFER, vbo);
        gl::BufferData(
            gl::ARRAY_BUFFER,
            core::mem::size_of_val(vertices) as isize,
            vertices.as_ptr().cast(),
            gl::STATIC_DRAW,
        );
    }
}

Knowing where each vertice is at compile time can also make us ensure that calls to glDrawArrays have known first and count parameters, which may reduce CPU cost significantly when the CPU is doing draw calls. Example:

fn draw_button() {
    unsafe {
        const BUTTON_START: i32;
        const BUTTON_COUNT: i32;
        gl::DrawArrays(gl::TRIANGLES, BUTTON_START,BUTTON_COUNT);
    }
}

If in any case we do need to calculate vertice data at compile time, we can reserve some extra space for this at our static vertice buffer. It is probably best we zero initialize this area ourselves, as if we provide a size parameter to glBufferData that is bigger than the size of vertices, then this is undefined behavior, which probably can get caught at runtime and cause crashes as well.

and that is basically all i had in my mind i think

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions