mesa: support NV_timeline_semaphore

this is for use with vulkan interop and carries the same mechanics

Acked-by: Marek Olšák <marek.olsak@amd.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/35866>
This commit is contained in:
Mike Blumenkrantz 2025-06-30 15:53:08 -04:00 committed by Marge Bot
parent 03e5a63058
commit 6e8b9e143d
11 changed files with 160 additions and 11 deletions

View file

@ -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,
};
/**

View file

@ -0,0 +1,40 @@
<?xml version="1.0"?>
<!DOCTYPE OpenGLAPI SYSTEM "gl_API.dtd">
<OpenGLAPI>
<category name="GL_NV_timeline_semaphore" number="551">
<enum name="MAX_TIMELINE_SEMAPHORE_VALUE_DIFFERENCE_NV" count="1" value="0x95B6">
<size name="GetIntegerv" mode="get"/>
<size name="GetFloatv" mode="get"/>
<size name="GetDoublev" mode="get"/>
<size name="GetInteger64v" mode="get"/>
<size name="GetBooleanv" mode="get"/>
</enum>
<function name="CreateSemaphoresNV" es2="3.2">
<param name="n" type="GLsizei" counter="true"/>
<param name="semaphores" type="GLuint *" count="n" output="true"/>
</function>
<function name="SemaphoreParameterivNV" es2="3.2">
<param name="semaphore" type="GLuint"/>
<param name="pname" type="GLenum"/>
<param name="params" type="const GLint *" output="true"/>
</function>
<function name="GetSemaphoreParameterivNV" es2="3.2">
<param name="semaphore" type="GLuint"/>
<param name="pname" type="GLenum"/>
<param name="params" type="GLint *" output="true"/>
</function>
<enum name="SEMAPHORE_TYPE_NV" value="0x95B3"/>
<enum name="SEMAPHORE_TYPE_BINARY_NV" value="0x95B4"/>
<enum name="SEMAPHORE_TYPE_TIMELINE_NV" value="0x95B5"/>
<enum name="TIMELINE_SEMAPHORE_VALUE_NV" value="0x9595"/>
</category>
</OpenGLAPI>

View file

@ -11122,4 +11122,5 @@
<xi:include href="NV_half_float.xml" xmlns:xi="http://www.w3.org/2001/XInclude"/>
<xi:include href="GL4x.xml" xmlns:xi="http://www.w3.org/2001/XInclude"/>
<xi:include href="NV_timeline_semaphore.xml" xmlns:xi="http://www.w3.org/2001/XInclude"/>
</OpenGLAPI>

View file

@ -1629,6 +1629,9 @@ all_functions = [
"FramebufferTextureMultiviewOVR",
"NamedFramebufferTextureMultiviewOVR",
"FramebufferTextureMultisampleMultiviewOVR",
"CreateSemaphoresNV",
"GetSemaphoreParameterivNV",
"SemaphoreParameterivNV",
# Keep these last. They are never used by any app.
"ColorTable",

View file

@ -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;

View file

@ -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)

View file

@ -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

View file

@ -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),

View file

@ -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": [

View file

@ -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;

View file

@ -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;