NV_memory_attachment

Name

NV_memory_attachment

Name Strings

GL_NV_memory_attachment

Contributors

Carsten Rohde, NVIDIA
Christoph Kubisch, NVIDIA
James Jones, NVIDIA

Contact

Carsten Rohde, NVIDIA (crohde 'at' nvidia.com)

Status

Complete

Version

Last Modified Date: Aug 27, 2018
Revision: 2

Number

524
OpenGL ES Extension #305

Dependencies

Requires GL_EXT_memory_object and ARB_texture_storage or a version of
OpenGL or OpenGL ES that incorporates it.

Written against the OpenGL 4.6 and OpenGL ES 3.2 specifications.

Interacts with ARB_direct_state_access (OpenGL) when OpenGL < 4.5 is used.

Interacts with NV_shader_buffer_load.

Interacts with NV_bindless_texture and ARB_bindless_texture.

Overview

This extension extends the memory objects introduced with EXT_memory_object
to allow existing textures and buffers to be migrated to an imported memory
allocation.  The primary use-case of this extension is plug-in development
where resource management (creation, deletion, sizing etc.) is handled by
inaccessible host application code.

New Procedures and Functions

If the GL_NV_memory_attachment string is reported, the following
commands are added:

    void GetMemoryObjectDetachedResourcesuivNV(uint memory,
                                               enum pname,
                                               int first,
                                               sizei count,
                                               uint *params)

    void ResetMemoryObjectParameterNV(uint memory,
                                      enum pname);

    void TexAttachMemoryNV(enum target,
                           uint memory,
                           uint64 offset);

    void BufferAttachMemoryNV(enum target,
                              uint memory,
                              uint64 offset);

    [[ The following are added if direct state access is supported ]]

    void TextureAttachMemoryNV(uint texture,
                               uint memory,
                               uint64 offset);

    void NamedBufferAttachMemoryNV(uint buffer,
                                   uint memory,
                                   uint64 offset);

New Tokens

If the GL_NV_memory_attachment string is reported, the following tokens
are added:

Accepted by the <pname> parameter of TexParameter{ifx}{v},
TexParameterI{i ui}v, TextureParameter{if}{v}, TextureParameterI{i ui}v,
GetTexParameter{if}v, GetTexParameterI{i ui}v, GetTextureParameter{if}v,
GetTextureParameterI{i ui}v, GetBufferParameter{i|i64}v and
GetNamedBufferParameter{i|i64}v:

  ATTACHED_MEMORY_OBJECT_NV           0x95A4
  ATTACHED_MEMORY_OFFSET_NV           0x95A5
  MEMORY_ATTACHABLE_ALIGNMENT_NV      0x95A6
  MEMORY_ATTACHABLE_SIZE_NV           0x95A7
  MEMORY_ATTACHABLE_NV                0x95A8

Accepted by the <pname> parameter of GetBooleanv, GetDoublev, GetFloatv,
GetIntegerv, GetInteger64v, GetUnsignedBytevEXT,
GetMemoryObjectParameterivEXT, and the <target> parameter of GetBooleani_v,
GetIntegeri_v,GetFloati_v, GetDoublei_v, GetInteger64i_v and
GetUnsignedBytei_vEXT:

  DETACHED_MEMORY_INCARNATION_NV      0x95A9

Accepted by the <pname> parameter of GetMemoryObjectParameterivEXT,
GetMemoryObjectDetachedResourcesuivNV and ResetMemoryObjectParameterNV:

  DETACHED_TEXTURES_NV                0x95AA
  DETACHED_BUFFERS_NV                 0x95AB

Accepted by the <pname> parameter of MemoryObjectParameterivEXT,
GetMemoryObjectParameterivEXT:

  MAX_DETACHED_TEXTURES_NV            0x95AC
  MAX_DETACHED_BUFFERS_NV             0x95AD

Additions to Chapter 6 of the EXT_external_objects Specification (Memory Objects)

Add a new sections after 6.2 (Memory object parameters)

    6.3 Attaching memory to existing resources

    MEMORY_ATTACHABLE_NV should be used to query if it is valid to attach
    a memory object to an existing resource (buffer or texture).  The
    memory region size and offset alignment required by a resource can be
    queried using MEMORY_ATTACHABLE_SIZE_NV and
    MEMORY_ATTACHABLE_ALIGNMENT_NV respectively.  The current attached
    memory object and the used offset for a resource can be queried by
    ATTACHED_MEMORY_OBJECT_NV and ATTACHED_MEMORY_OFFSET_NV.

    If a resource which has memory attached is resized, the attached memory
    will be detached and a new data store will be allocated.  If a resource
    which has memory attached is deleted, the attached memory will first be
    detached.  If any such detachment occurs, a global incarnation counter
    will be increased and the current value will be stored in the detached
    memory object.  The incarnation counter can be queried by
    DETACHED_MEMORY_INCARNATION_EXT either globally or for a specific
    memory object.

    The command

        void GetMemoryObjectDetachedResourcesuivNV(uint memory,
                                                   enum pname,
                                                   int first,
                                                   sizei count,
                                                   uint *params)

    will return a list of detached buffers (if <pname> is
    DETACHED_BUFFERS_NV) or textures (if <pname> is DETACHED_TEXTURES_NV)
    in <params> for memory object <memory>.  It will return <count> items
    beginning with <first> item.  The number of available items can be
    queried by calling GetMemoryObjectParameterivEXT with <pname> set to
    DETACHED_TEXTURES_NV or DETACHED_BUFFERS_NV.  An INVALID_VALUE error is
    generated by GetMemoryObjectDetachedResourcesuivNV if <memory> is 0.
    An INVALID_OPERATION error is generated if <memory> names a valid
    memory object which has no associated memory.  An INVALID_VALUE error
    is generated if <pname> is neither DETACHED_BUFFERS_NV nor
    DETACHED_TEXTURES_NV.  An INVALID_VALUE error is generated if
    <first> + <count> is greater than the number of available items in the
    list.  An INVALID_VALUE error is generated if <params> is NULL.
    MemoryObjectParameterivEXT must be called with <pname> set to
    MAX_DETACHED_TEXTURES_NV or MAX_DETACHED_BUFFERS_NV before calling
    GetMemoryObjectDetachedResourcesuivNV to set the maximum number of
    items in the list of detached textures or buffers.  The default values
    are 0 which means that tracking of detached textures and buffers is
    disabled by default.

    The command

    void ResetMemoryObjectParameterNV(uint memory,
                                      enum pname);

    will reset the list of detached buffers (if <pname> is
    DETACHED_BUFFERS_NV) or textures (if <pname> is DETACHED_TEXTURES_NV)
    for memory object <memory>.  An INVALID_VALUE error is generated by
    ResetMemoryObjectParameterNV if <memory> is 0.  An INVALID_OPERATION
    error is generated if <memory> names a valid memory object which has
    no associated memory.  An INVALID_VALUE error is generated if <pname>
    is neither DETACHED_BUFFERS_NV nor DETACHED_TEXTURES_NV.

Additions to Chapter 6 of the OpenGL 4.6 Specification (Buffer Objects)

Add a new section after 6.2.1 (Clearing Buffer Object Data Stores)

    6.2.2 Attaching a memory object to a buffer object

    The commands

        void BufferAttachMemoryNV(enum target,
                                  uint memory,
                                  uint64 offset);

        void NamedBufferAttachMemoryNV(uint buffer,
                                       uint memory,
                                       uint64 offset);

    will attach a region of a memory object to a buffer object.  For
    BufferAttachMemoryNV, the buffer object is that bound to <target>,
    which must be one of the values listed in table 6.1.  For
    NamedBufferAttachMemoryNV, <buffer> is the name of the buffer
    object.  <memory> and <offset> define a region of memory that will
    replace the data store for <buffer>. The content of the original data
    store will be preserved by a server side copy and the original data
    store will be deleted after that copy.  The implementation may restrict
    which values of <offset> are valid for a given memory object and buffer
    parameter combination.  These restrictions are outside the scope of
    this extension and must be determined by querying the API or mechanism
    which created the resource which <memory> refers to.  If an invalid
    offset is specified an INVALID_VALUE error is generated.  An
    INVALID_VALUE error is generated by BufferAttachMemoryNV and
    NamedBufferAttachMemoryNV if <memory> is 0. An INVALID_OPERATION error
    is generated if <memory> names a valid memory object which has no
    associated memory.  An INVALID_OPERATION error is generated if the
    specified buffer was created with MAP_PERSISTENT_BIT flag.  An
    INVALID_OPERATION error is generated if the specified buffer is
    currently mapped by client.

Additions to Chapter 8 of the OpenGL 4.6 Specification (Textures and Samplers)

Add a new section between sections 8.19, "Immutable-Format Texture Images"
and section 8.20, "Invalidating Texture Image Data"

    8.20 Attaching a memory object to a texture image

    The commands

        void TexAttachMemoryNV(enum target,
                               uint memory,
                               uint64 offset);

        void TextureAttachMemoryNV(uint texture,
                                   uint memory,
                                   uint64 offset);

    will attach a region of a memory object to a texture.  For
    TexAttachMemoryNV, the texture is that bound to <target>, which must be
    one of TEXTURE_1D, TEXTURE_2D, TEXTURE_3D, TEXTURE_1D_ARRAY,
    TEXTURE_2D_ARRAY, TEXTURE_RECTANGLE, TEXTURE_CUBE_MAP,
    TEXTURE_CUBE_MAP_ARRAY, TEXTURE_2D_MULTISAMPLE, or
    TEXTURE_2D_MULTISAMPLE_ARRAY.  For TextureAttachMemoryNV, <texture> is
    the name of the texture.  <memory> and <offset> define a region of
    memory that will replace the data store for <texture>. The content of
    the original data store will be preserved by a server side copy and the
    original data store will be deleted after that copy.  The
    implementation may restrict which values of <offset> are valid for a
    given memory object and texture parameter combination.  These
    restrictions are outside the scope of this extension and must be
    determined by querying the API or mechanism which created the resource
    which <memory> refers to.  If an invalid offset is specified an
    INVALID_VALUE error is generated.  An INVALID_VALUE error is generated
    by TexAttachMemoryNV and TextureAttachMemoryNV if <memory> is 0.  An
    INVALID_OPERATION error is generated if <memory> names a valid memory
    object which has no associated memory.

Errors

New State

Sample

// host: code not visible to the plug-in developer
// plug-in: code written by plug-in developer

uint tex0;
uint tex1;

// host
{
    // sets up textures as usual
}

// plug-in
{
    int attachable0;
    int attachable1;
    GetTextureParameteriv(tex0, MEMORY_ATTACHABLE_NV, &attachable0);
    GetTextureParameteriv(tex1, MEMORY_ATTACHABLE_NV, &attachable1);

    if (attachable0 && attachable1){

        // allocate memory within vulkan and import it as specified in
        // EXT_memory_object

        // attach imported vulkan memory
        TextureAttachMemoryNV(tex0, memobj, memoffset0);

        // ... do same for tex1
        TextureAttachMemoryNV(tex1, memobj, memoffset1);
    }
}

///////////////////////////////
// Querying mutations by host

int incarnationExpected;

// plug-in
{
    // global query
    GetIntegerv(DETACHED_MEMORY_INCARNATION_NV, &incarnationExpected);

    // if we have multiple memory objects
    for each memobj {
      GetMemoryObjectParameterivEXT(memobj.id,
                                    DETACHED_MEMORY_INCARNATION_NV,
                                    &memobj.incarnation);
      GLint maxDetachedTextures = 64;
      MemoryObjectParameterivEXT(memobj.id,
                                 MAX_DETACHED_TEXTURES_NV,
                                 &maxDetachedTextures);
    }
}

// host
{
    // deletion triggers a detach
    glDeleteTextures(1, &tex1);
}

// plug-in
{
    // global query if resources of context were affected
    int incarnation;
    GetIntegerv(DETACHED_MEMORY_INCARNATION_NV, &incarnation);

    if (incarnation != incarnationExpected) {
        incarnationExpected = incarnation;

        // narrow down search which memory object was affected
        for each memobj {
            GetMemoryObjectParameterivEXT(memobj.id,
                                          DETACHED_MEMORY_INCARNATION_NV,
                                          &incarnation);

            if (incarnation != memobj.incarnation) {
                memobj.incarnation = incarnation;

                int removedTexCount;
                GetMemoryObjectParameterivEXT(memobj.id,
                                              DETACHED_TEXTURES_NV,
                                              &removedTexCount);

                std::vector<uint> removedTexs(removedTexCount);

                GetMemoryObjectDetachedResourcesuivNV(
                    memobj.id,
                    DETACHED_TEXTURES_NV,
                    0, removedTexCount,
                    removedTexs.data());

                for (int i = 0; i < removedTexCount; i++) {
                    uint tex = removedTexs[i];
                    // look up tex in custom allocator and
                    // mark its memory as available again
                }

                ResetMemoryObjectParameter(memobj.id,
                                           DETACHED_TEXTURES_NV);
            }
        }
    }
}

Issues

1)  Do we need to introduce allocation done within OpenGL
    or is attaching existing resources to imported allocation
    sufficient?

    RESOLVED: No.  No need to duplicate work which has already been done
    in Vulkan.

2)  Should binding memory only work on immutable resources?

    RESOLVED: No.  To improve compatibility with existing GL resources,
    allow mutable resources as well. A global and local incarnation counter
    was introduced to test against changes, as well as detecting the
    detached resources.

3)  Do we support client-mappable resources?

    RESOLVED: Yes.  Client-mappable resources are supported but not
    when they are persistent. When memory is attached resource must be
    unmapped.

4)  What are the affects on TextureViews?

    RESOLVED: TextureViews inherit the memory state.

5)  Do bindless resources change?

    RESOLVED: Yes.  The existing handles and GPU addresses become invalid
    when memory is attached and must be queried afterwards.

6)  Should we support resources that were migrated to host memory by driver?

    RESOLVED: Yes, but the attached memory is independ from this state.

7)  Do we need an "attachable" per-resource state?

    RESOLVED: Yes.

8)  How is bindless residency affected?

    RESOLVED: A memory object becomes resident if at least one attached
    resource is resident.

Revision History

Revision 2, 2018-08-20 (Carsten Rohde, Christoph Kubisch)
    - Added spec body describing new commands.
    - Added non-DSA functions
    - Resolve issues

Revision 1, 2018-05-07 (Carsten Rohde, Christoph Kubisch)
    - Initial draft.