Skip to content

Memory Management

Blender is responsible for memory management in Vulkan. Most of this is implemented using the VMA library. This section describes how the memory on modern GPUs are organized and how this is utilized by Blender.

Memory Areas

In Vulkan there each device can have its own memory areas where each area has different characteristics. Some areas are directly accessible via the host, others are only visible by the GPU. There are areas that can be cached by the GPU and others not.

The layout for an Dedicated AMD VEGA GPUs looks like:

Area GPU Capabilities Host Capabilities Size
#0 Stored / Visible / Cached Fast Read Write Most of VRAM
#1 Visible / Cached Stored / Visible Fast Write
#2 Stored / Visible / Cached Fast Read Write Visible Fast Write 256MB
#3 Visible / Cached Stored / Visible / Cached Fast Read Write

Note

This can be differ for each platform. An Integrated GPU or CPU/GPU with shared memory model or different GPU architectures can have different areas. This area layout was taken from AMD VEGA.

Buffers and Images

Memory Usage Types

Depending on the usage of the buffer we can select the memory area we want to keep the data.

  • GPU_USAGE_STATIC, GPU_USAGE_DYNAMIC and GPU_USAGE_DEVICE_ONLY will be loaded in an area that is fast for the GPU to access. These buffers are expected to be used multiple times.
  • GPU_USAGE_STREAM will be loaded in GPU and host visible memory. It is assumed that the data is only used once. Uploading to the GPU would already access it multiple times.

Todo

Current implementation uploads the data to host visible area, but eventually this should be as described above to improve performance.

Note

More information about this topic can be found at https://www.youtube.com/watch?v=K-2bxdmosH8

Staging buffers

One Fixed Size Staging buffer. Transfers from the GPU to HOST is always slow.

Todo

When would be add staging buffers

Unbinding from contexts

  • Device should be aware of each available context.
  • When memory is freed, it will be removed from each known context.
  • A resource can be bound to multiple contexts. When a resource is freed it should be unbound from all contexts.
classDiagram

    class VKDevice {
        void context_register(VKContext *context)
        void context_unregister(VKContext *context)
    }

    class VKContext {

    }

    class VKStateManager {

        void unbind_image(Texture *texture)
        void unbind_texture(Texture *texture)
        void unbind_storage_buffer(VKBindableResource &resource)
        void unbind_buffer(VKBindableResource &resource)
    }

    class VKBindSpace {
        void bind(int binding, VKBindableResource &resource)
        void apply_bindings()
        void unbind(VKBindableResource&resource)
        void unbind_all()
    }



    VKDevice "1" o--> "N" VKContext: contexts
    VKContext "1" *--> "1" VKStateManager: state_manager
    VKStateManager *--> VKBindSpace: images, textures, uniform_buffers, storage_buffers

Todo

move to shader resource management

classDiagram

    class VKBindableResource {
        void bind(int binding, BindType bind_type)
        void unbind_from_active_context()
        void unbind_from_all_contexts()
    }

     VKBindableResource <|-- VKStorageBuffer
     VKBindableResource <|-- VKTexture
     VKBindableResource <|-- VKUniformBuffer
     VKBindableResource <|-- VKIndexBuffer
     VKBindableResource <|-- VKVertexBuffer
When unbinding a resource, the resource will be unbound from the active context (if any) When destoying the resource, the resource will be unbound from all registered contexts.