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 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 parameter of GetBooleanv, GetDoublev, GetFloatv, GetIntegerv, GetInteger64v, GetUnsignedBytevEXT, GetMemoryObjectParameterivEXT, and the parameter of GetBooleani_v, GetIntegeri_v,GetFloati_v, GetDoublei_v, GetInteger64i_v and GetUnsignedBytei_vEXT: DETACHED_MEMORY_INCARNATION_NV 0x95A9 Accepted by the parameter of GetMemoryObjectParameterivEXT, GetMemoryObjectDetachedResourcesuivNV and ResetMemoryObjectParameterNV: DETACHED_TEXTURES_NV 0x95AA DETACHED_BUFFERS_NV 0x95AB Accepted by the 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 is DETACHED_BUFFERS_NV) or textures (if is DETACHED_TEXTURES_NV) in for memory object . It will return items beginning with item. The number of available items can be queried by calling GetMemoryObjectParameterivEXT with set to DETACHED_TEXTURES_NV or DETACHED_BUFFERS_NV. An INVALID_VALUE error is generated by GetMemoryObjectDetachedResourcesuivNV if is 0. An INVALID_OPERATION error is generated if names a valid memory object which has no associated memory. An INVALID_VALUE error is generated if is neither DETACHED_BUFFERS_NV nor DETACHED_TEXTURES_NV. An INVALID_VALUE error is generated if + is greater than the number of available items in the list. An INVALID_VALUE error is generated if is NULL. MemoryObjectParameterivEXT must be called with 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 is DETACHED_BUFFERS_NV) or textures (if is DETACHED_TEXTURES_NV) for memory object . An INVALID_VALUE error is generated by ResetMemoryObjectParameterNV if is 0. An INVALID_OPERATION error is generated if names a valid memory object which has no associated memory. An INVALID_VALUE error is generated if 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 , which must be one of the values listed in table 6.1. For NamedBufferAttachMemoryNV, is the name of the buffer object. and define a region of memory that will replace the data store for . 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 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 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 is 0. An INVALID_OPERATION error is generated if 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 , 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, is the name of the texture. and define a region of memory that will replace the data store for . 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 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 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 is 0. An INVALID_OPERATION error is generated if 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 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.