From 6e8b9e143d4b1cf843b75a1aae59573cd4c5f189 Mon Sep 17 00:00:00 2001 From: Mike Blumenkrantz Date: Mon, 30 Jun 2025 15:53:08 -0400 Subject: [PATCH] mesa: support NV_timeline_semaphore MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit this is for use with vulkan interop and carries the same mechanics Acked-by: Marek Olšák Part-of: --- src/gallium/include/pipe/p_defines.h | 2 + src/mapi/glapi/gen/NV_timeline_semaphore.xml | 40 +++++++ src/mapi/glapi/gen/gl_API.xml | 1 + src/mapi/glapi/gen/static_data.py | 3 + src/mesa/main/consts_exts.h | 4 + src/mesa/main/extensions_table.h | 1 + src/mesa/main/externalobjects.c | 108 +++++++++++++++++-- src/mesa/main/get.c | 1 + src/mesa/main/get_hash_params.py | 3 + src/mesa/main/glthread_marshal.h | 2 + src/mesa/state_tracker/st_extensions.c | 6 ++ 11 files changed, 160 insertions(+), 11 deletions(-) create mode 100644 src/mapi/glapi/gen/NV_timeline_semaphore.xml diff --git a/src/gallium/include/pipe/p_defines.h b/src/gallium/include/pipe/p_defines.h index 5b13ad36a27..6f036991932 100644 --- a/src/gallium/include/pipe/p_defines.h +++ b/src/gallium/include/pipe/p_defines.h @@ -1088,6 +1088,7 @@ struct pipe_caps { unsigned shader_subgroup_supported_stages; unsigned shader_subgroup_supported_features; unsigned multiview; + uint64_t max_timeline_semaphore_difference; /** for CL SVM */ uint64_t min_vma; @@ -1314,6 +1315,7 @@ enum pipe_fd_type PIPE_FD_TYPE_NATIVE_SYNC, PIPE_FD_TYPE_SYNCOBJ, PIPE_FD_TYPE_TIMELINE_SEMAPHORE_D3D12, + PIPE_FD_TYPE_TIMELINE_SEMAPHORE_VK, }; /** diff --git a/src/mapi/glapi/gen/NV_timeline_semaphore.xml b/src/mapi/glapi/gen/NV_timeline_semaphore.xml new file mode 100644 index 00000000000..95a5e643ac3 --- /dev/null +++ b/src/mapi/glapi/gen/NV_timeline_semaphore.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/mapi/glapi/gen/gl_API.xml b/src/mapi/glapi/gen/gl_API.xml index d75d6399215..48531f74e47 100644 --- a/src/mapi/glapi/gen/gl_API.xml +++ b/src/mapi/glapi/gen/gl_API.xml @@ -11122,4 +11122,5 @@ + diff --git a/src/mapi/glapi/gen/static_data.py b/src/mapi/glapi/gen/static_data.py index 61ec114ce0a..ab06bddd509 100644 --- a/src/mapi/glapi/gen/static_data.py +++ b/src/mapi/glapi/gen/static_data.py @@ -1629,6 +1629,9 @@ all_functions = [ "FramebufferTextureMultiviewOVR", "NamedFramebufferTextureMultiviewOVR", "FramebufferTextureMultisampleMultiviewOVR", + "CreateSemaphoresNV", + "GetSemaphoreParameterivNV", + "SemaphoreParameterivNV", # Keep these last. They are never used by any app. "ColorTable", diff --git a/src/mesa/main/consts_exts.h b/src/mesa/main/consts_exts.h index 63ca724f6e4..06af0af02b1 100644 --- a/src/mesa/main/consts_exts.h +++ b/src/mesa/main/consts_exts.h @@ -287,6 +287,7 @@ struct gl_extensions GLboolean NV_conservative_raster_pre_snap; GLboolean NV_viewport_array2; GLboolean NV_viewport_swizzle; + GLboolean NV_timeline_semaphore; GLboolean NVX_gpu_memory_info; GLboolean TDFX_texture_compression_FXT1; GLboolean OES_EGL_image; @@ -1001,6 +1002,9 @@ struct gl_constants /** Whether pipe_context::draw_vertex_state is supported. */ bool HasDrawVertexState; + /* NV_timeline_semaphore */ + GLuint64 MaxTimelineSemaphoreValueDifference; + /** GL_KHR_shader_subgroup */ GLuint ShaderSubgroupSize; GLuint ShaderSubgroupSupportedStages; diff --git a/src/mesa/main/extensions_table.h b/src/mesa/main/extensions_table.h index 6a812aaf97d..74a2cb09b80 100644 --- a/src/mesa/main/extensions_table.h +++ b/src/mesa/main/extensions_table.h @@ -440,6 +440,7 @@ EXT(NV_texgen_reflection , dummy_true EXT(NV_texture_barrier , NV_texture_barrier , GLL, GLC, x , ES2, 2009) EXT(NV_texture_env_combine4 , NV_texture_env_combine4 , GLL, x , x , x , 1999) EXT(NV_texture_rectangle , NV_texture_rectangle , GLL, x , x , x , 2000) +EXT(NV_timeline_semaphore , NV_timeline_semaphore , GLL, GLC, x , 32, 2020) EXT(NV_vdpau_interop , NV_vdpau_interop , GLL, GLC, x , x , 2010) EXT(NV_viewport_array2 , NV_viewport_array2 , GLL, GLC, x , 31, 2015) EXT(NV_viewport_swizzle , NV_viewport_swizzle , GLL, GLC, x , 31, 2015) diff --git a/src/mesa/main/externalobjects.c b/src/mesa/main/externalobjects.c index 74cce2e85a5..ceeb4f71d35 100644 --- a/src/mesa/main/externalobjects.c +++ b/src/mesa/main/externalobjects.c @@ -778,17 +778,17 @@ _mesa_delete_semaphore_object(struct gl_context *ctx, } } -void GLAPIENTRY -_mesa_GenSemaphoresEXT(GLsizei n, GLuint *semaphores) +static void +create_semaphores(GLsizei n, GLuint *semaphores, bool NV) { GET_CURRENT_CONTEXT(ctx); - const char *func = "glGenSemaphoresEXT"; + const char *func = NV ? "glCreateSemaphoresNV" : "glGenSemaphoresEXT"; if (MESA_VERBOSE & (VERBOSE_API)) _mesa_debug(ctx, "%s(%d, %p)\n", func, n, semaphores); - if (!_mesa_has_EXT_semaphore(ctx)) { + if (NV ? !_mesa_has_NV_timeline_semaphore(ctx) : !_mesa_has_EXT_semaphore(ctx)) { _mesa_error(ctx, GL_INVALID_OPERATION, "%s(unsupported)", func); return; } @@ -812,6 +812,18 @@ _mesa_GenSemaphoresEXT(GLsizei n, GLuint *semaphores) _mesa_HashUnlockMutex(&ctx->Shared->SemaphoreObjects); } +void GLAPIENTRY +_mesa_GenSemaphoresEXT(GLsizei n, GLuint *semaphores) +{ + create_semaphores(n, semaphores, false); +} + +void GLAPIENTRY +_mesa_CreateSemaphoresNV(GLsizei n, GLuint *semaphores) +{ + create_semaphores(n, semaphores, true); +} + void GLAPIENTRY _mesa_DeleteSemaphoresEXT(GLsizei n, const GLuint *semaphores) { @@ -890,7 +902,12 @@ _mesa_SemaphoreParameterui64vEXT(GLuint semaphore, return; } - if (pname != GL_D3D12_FENCE_VALUE_EXT) { + if (!_mesa_has_NV_timeline_semaphore(ctx) && pname == GL_TIMELINE_SEMAPHORE_VALUE_NV) { + _mesa_error(ctx, GL_INVALID_OPERATION, "%s(NV_timeline_semaphore unsupported)", func); + return; + } + + if (pname != GL_D3D12_FENCE_VALUE_EXT && pname != GL_TIMELINE_SEMAPHORE_VALUE_NV) { _mesa_error(ctx, GL_INVALID_ENUM, "%s(pname=0x%x)", func, pname); return; } @@ -900,8 +917,13 @@ _mesa_SemaphoreParameterui64vEXT(GLuint semaphore, if (!semObj) return; - if (semObj->type != PIPE_FD_TYPE_TIMELINE_SEMAPHORE_D3D12) { - _mesa_error(ctx, GL_INVALID_OPERATION, "%s(Not a D3D12 fence)", func); + if (semObj->type < PIPE_FD_TYPE_TIMELINE_SEMAPHORE_D3D12) { + _mesa_error(ctx, GL_INVALID_OPERATION, "%s(Not a %s)", func, pname == GL_TIMELINE_SEMAPHORE_VALUE_NV ? "timeline semaphore" : "D3D12 fence"); + return; + } + if ((semObj->type == PIPE_FD_TYPE_TIMELINE_SEMAPHORE_D3D12 && pname != GL_D3D12_FENCE_VALUE_EXT) || + (semObj->type == PIPE_FD_TYPE_TIMELINE_SEMAPHORE_VK && pname != GL_TIMELINE_SEMAPHORE_VALUE_NV)) { + _mesa_error(ctx, GL_INVALID_OPERATION, "%s(Not a %s)", func, pname == GL_TIMELINE_SEMAPHORE_VALUE_NV ? "timeline semaphore" : "D3D12 fence"); return; } @@ -922,7 +944,42 @@ _mesa_GetSemaphoreParameterui64vEXT(GLuint semaphore, return; } - if (pname != GL_D3D12_FENCE_VALUE_EXT) { + if (!_mesa_has_NV_timeline_semaphore(ctx) && pname == GL_TIMELINE_SEMAPHORE_VALUE_NV) { + _mesa_error(ctx, GL_INVALID_OPERATION, "%s(NV_timeline_semaphore unsupported)", func); + return; + } + + if (pname != GL_D3D12_FENCE_VALUE_EXT && pname != GL_TIMELINE_SEMAPHORE_VALUE_NV) { + _mesa_error(ctx, GL_INVALID_ENUM, "%s(pname=0x%x)", func, pname); + return; + } + struct gl_semaphore_object *semObj = _mesa_lookup_semaphore_object(ctx, + semaphore); + if (!semObj) + return; + + if (semObj->type < PIPE_FD_TYPE_TIMELINE_SEMAPHORE_D3D12) { + _mesa_error(ctx, GL_INVALID_OPERATION, "%s(Not a %s)", func, pname == GL_TIMELINE_SEMAPHORE_VALUE_NV ? "timeline semaphore" : "D3D12 fence"); + return; + } + + params[0] = semObj->timeline_value; +} + +void GLAPIENTRY +_mesa_GetSemaphoreParameterivNV(GLuint semaphore, + GLenum pname, + GLint *params) +{ + GET_CURRENT_CONTEXT(ctx); + const char *func = "glGetSemaphoreParameterivNV"; + + if (!_mesa_has_NV_timeline_semaphore(ctx)) { + _mesa_error(ctx, GL_INVALID_OPERATION, "%s(unsupported)", func); + return; + } + + if (pname != GL_SEMAPHORE_TYPE_NV) { _mesa_error(ctx, GL_INVALID_ENUM, "%s(pname=0x%x)", func, pname); return; } @@ -932,12 +989,41 @@ _mesa_GetSemaphoreParameterui64vEXT(GLuint semaphore, if (!semObj) return; - if (semObj->type != PIPE_FD_TYPE_TIMELINE_SEMAPHORE_D3D12) { - _mesa_error(ctx, GL_INVALID_OPERATION, "%s(Not a D3D12 fence)", func); + params[0] = semObj->type == PIPE_FD_TYPE_TIMELINE_SEMAPHORE_VK ? + GL_TIMELINE_SEMAPHORE_VALUE_NV : + GL_SEMAPHORE_TYPE_BINARY_NV; +} + +void GLAPIENTRY +_mesa_SemaphoreParameterivNV(GLuint semaphore, + GLenum pname, + const GLint *params) +{ + GET_CURRENT_CONTEXT(ctx); + const char *func = "glSemaphoreParameterivNV"; + + if (!_mesa_has_NV_timeline_semaphore(ctx)) { + _mesa_error(ctx, GL_INVALID_OPERATION, "%s(unsupported)", func); return; } - params[0] = semObj->timeline_value; + if (pname != GL_SEMAPHORE_TYPE_NV) { + _mesa_error(ctx, GL_INVALID_ENUM, "%s(pname=0x%x)", func, pname); + return; + } + + if (params[0] != GL_SEMAPHORE_TYPE_BINARY_NV && params[0] != GL_SEMAPHORE_TYPE_TIMELINE_NV) { + _mesa_error(ctx, GL_INVALID_ENUM, "%s(pname=0x%x)", func, pname); + return; + } + + struct gl_semaphore_object *semObj = _mesa_lookup_semaphore_object(ctx, + semaphore); + if (!semObj) + return; + + enum pipe_fd_type type = params[0] == GL_SEMAPHORE_TYPE_TIMELINE_NV ? PIPE_FD_TYPE_TIMELINE_SEMAPHORE_VK : PIPE_FD_TYPE_SYNCOBJ; + create_real_semaphore(ctx, semaphore, semObj, type, func); } void GLAPIENTRY diff --git a/src/mesa/main/get.c b/src/mesa/main/get.c index 1c7a6301bcd..5b5ae884929 100644 --- a/src/mesa/main/get.c +++ b/src/mesa/main/get.c @@ -593,6 +593,7 @@ EXTRA_EXT(NV_viewport_swizzle); EXTRA_EXT(ARB_sparse_texture); EXTRA_EXT(KHR_shader_subgroup); EXTRA_EXT(OVR_multiview); +EXTRA_EXT(NV_timeline_semaphore); static const int extra_ARB_gl_spirv_or_es2_compat[] = { EXT(ARB_gl_spirv), diff --git a/src/mesa/main/get_hash_params.py b/src/mesa/main/get_hash_params.py index 43a46f79a4f..cb1cfd74746 100644 --- a/src/mesa/main/get_hash_params.py +++ b/src/mesa/main/get_hash_params.py @@ -501,6 +501,9 @@ descriptor=[ # OVR_multiview [ "MAX_VIEWS_OVR", "CONST(MAX_VIEWS_OVR), extra_OVR_multiview" ], + +# NV_timeline_semaphore + [ "MAX_TIMELINE_SEMAPHORE_VALUE_DIFFERENCE_NV", "CONTEXT_INT64(Const.MaxTimelineSemaphoreValueDifference), extra_NV_timeline_semaphore" ], ]}, { "apis": ["GLES", "GLES2"], "params": [ diff --git a/src/mesa/main/glthread_marshal.h b/src/mesa/main/glthread_marshal.h index e5e53717187..d18466c1e1d 100644 --- a/src/mesa/main/glthread_marshal.h +++ b/src/mesa/main/glthread_marshal.h @@ -398,6 +398,8 @@ static inline unsigned _mesa_semaphore_enum_to_count(GLenum pname) { switch (pname) { + case GL_TIMELINE_SEMAPHORE_VALUE_NV: + return 1; /* EXT_semaphore and EXT_semaphore_fd define no parameters */ default: return 0; diff --git a/src/mesa/state_tracker/st_extensions.c b/src/mesa/state_tracker/st_extensions.c index c11e54cf9c5..3711f9ce33a 100644 --- a/src/mesa/state_tracker/st_extensions.c +++ b/src/mesa/state_tracker/st_extensions.c @@ -1313,6 +1313,12 @@ void st_init_extensions(struct pipe_screen *screen, consts->GLSLZeroInit = screen->caps.glsl_zero_init; } + if (extensions->EXT_semaphore) { + consts->MaxTimelineSemaphoreValueDifference = screen->caps.max_timeline_semaphore_difference; + extensions->NV_timeline_semaphore = consts->MaxTimelineSemaphoreValueDifference > 0; + assert(!extensions->NV_timeline_semaphore || screen->set_fence_timeline_value); + } + consts->ForceIntegerTexNearest = options->force_integer_tex_nearest; consts->VendorOverride = options->force_gl_vendor;