Skip to content
Back to top
View this page

# Buffer

`Buffer` is a dedicated area of GPU memory. Can store anything in bytes.

Creating a buffer is essentially allocating an area of memory into which data is later written. Therefore, when creating an empty buffer, it may contain memory fragments of deleted objects. Example of creating an empty buffer:

    buf = ctx.buffer(reserve=1)

The `reserve` parameter specifies how many bytes should be allocated, the minimum number is 1.

The buffer is cleared by writing zeros to the allocated memory area. However, this must be done manually:

    buf.clear()

ModernGL allows you to create 2 types of buffer: dynamic and non-dynamic. To do this, when creating a buffer, use the keyword argument `dynamic=True/False` (by default `False`):

    buf = ctx.buffer(reserve=32, dynamic=True)

Note

Using the `dynamic=True` parameter tells the GPU that actions with this `Buffer` will be performed very often. This parameter is optional, but is recommended if the `Buffer` is used frequently.

Later, using the `Buffer.orphan()` function, you can change the buffer size at any time:

    buf.orphan(size=64)

After changing the buffer size, you will need to write data there. This is done using the `Buffer.write()` function. This function will write data from RAM to GPU memory:

    buf.write(b'any bytes data')

However, if the size of this buffer was changed after it was added to `VertexArray`, then when calling `VertexArray.render()` you will need to specify the new number of vertices in the `vertices` parameter. For example:

    # If from the contents of this buffer every 12 bytes fall on one vertex.
    vao.render(vertices=buf.size // 4 // 3)

The same will need to be done when calling the `VertexArray.transform()` function:

    # If from the contents of this buffer every 12 bytes fall on one vertex.
    # output_buf - the buffer into which the transformation will be performed.
    vao.transform(output_buf, vertices=buf.size // 4 // 3)

After `VertexArray.transform()` writes data to `output_buf` using a vertex shader, you may need to read it — use `Buffer.read()`. This function will read data from GPU memory into RAM:

    bytes_data = buf.read()

Warning

Transferring data between RAM and GPU memory comes at a huge performance cost. It is recommended to use `Buffer.write()` and `Buffer.read()` as little as possible.

If you just need to copy data between buffers, look towards the `Context.copy_buffer()` function:

    ctx.copy_buffer(destination_buf, source_buf)

In our example, we simply create a static buffer and write data immediately when it is created:

    vbo = ctx.buffer(vertices.astype("f4").tobytes())

We called it VBO (Vertex Buffer Object) because we will store vertex data in this buffer.

Entire source

     1import moderngl
     2import numpy as np
     3
     4ctx = moderngl.create_context(standalone=True)
     5
     6prog = ctx.program(
     7    vertex_shader="""
     8        #version 330
     9
    10        in vec2 in_vert;
    11        in vec3 in_color;
    12
    13        out vec3 v_color;
    14
    15        void main() {
    16            v_color = in_color;
    17            gl_Position = vec4(in_vert, 0.0, 1.0);
    18        }
    19    """,
    20    fragment_shader="""
    21        #version 330
    22
    23        in vec3 v_color;
    24
    25        out vec3 f_color;
    26
    27        void main() {
    28            f_color = v_color;
    29        }
    30    """,
    31)
    32
    33x = np.linspace(-1.0, 1.0, 50)
    34y = np.random.rand(50) - 0.5
    35r = np.zeros(50)
    36g = np.ones(50)
    37b = np.zeros(50)
    38
    39vertices = np.dstack([x, y, r, g, b])
    40
    41vbo = ctx.buffer(vertices.astype("f4").tobytes())

Proceed to the next step.