mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2026-05-03 03:28:09 +02:00
glthread: add display list support to fix state tracking with display lists
The existing display list code is reused to call display lists from the app thread. The util_queue_fence_wait call waits for the last call that modifies display lists (such as glEndList and glDeleteLists), which ensures that accessing display lists from a non-mesa thread is thread safe because the wait guarantees that display lists are immutable during the asynchronous display list execution. Display lists are executed just like normal display lists except that they call glthread functions instead of the default GL dispatch. Many calls in display lists are skipped because glthread only tracks a few states. Acked-by: Pierre-Eric Pelloux-Prayer <pierre-eric.pelloux-prayer@amd.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/8297>
This commit is contained in:
parent
14b47614b4
commit
33ad9e77c5
5 changed files with 321 additions and 9 deletions
|
|
@ -1111,23 +1111,25 @@
|
|||
<type name="DEBUGPROC" size="4" pointer="true"/>
|
||||
|
||||
<function name="NewList" deprecated="3.1"
|
||||
marshal_call_after="ctx->GLThread.ListMode = mode;">
|
||||
marshal_call_after="_mesa_glthread_NewList(ctx, list, mode);">
|
||||
<param name="list" type="GLuint"/>
|
||||
<param name="mode" type="GLenum"/>
|
||||
<glx sop="101"/>
|
||||
</function>
|
||||
|
||||
<function name="EndList" deprecated="3.1"
|
||||
marshal_call_after="ctx->GLThread.ListMode = 0;">
|
||||
marshal_call_after="_mesa_glthread_EndList(ctx);">
|
||||
<glx sop="102"/>
|
||||
</function>
|
||||
|
||||
<function name="CallList" deprecated="3.1">
|
||||
<function name="CallList" deprecated="3.1"
|
||||
marshal_call_after="_mesa_glthread_CallList(ctx, list);">
|
||||
<param name="list" type="GLuint"/>
|
||||
<glx rop="1"/>
|
||||
</function>
|
||||
|
||||
<function name="CallLists" deprecated="3.1">
|
||||
<function name="CallLists" deprecated="3.1"
|
||||
marshal_call_after="_mesa_glthread_CallLists(ctx, n, type, lists);">
|
||||
<param name="n" type="GLsizei" counter="true"/>
|
||||
<param name="type" type="GLenum"/>
|
||||
<param name="lists" type="const GLvoid *" variable_param="type" count="n"
|
||||
|
|
@ -1135,7 +1137,8 @@
|
|||
<glx rop="2" large="true"/>
|
||||
</function>
|
||||
|
||||
<function name="DeleteLists" deprecated="3.1">
|
||||
<function name="DeleteLists" deprecated="3.1"
|
||||
marshal_call_after="_mesa_glthread_DeleteLists(ctx, range);">
|
||||
<param name="list" type="GLuint"/>
|
||||
<param name="range" type="GLsizei"/>
|
||||
<glx sop="103"/>
|
||||
|
|
@ -1147,7 +1150,8 @@
|
|||
<glx sop="104"/>
|
||||
</function>
|
||||
|
||||
<function name="ListBase" deprecated="3.1">
|
||||
<function name="ListBase" deprecated="3.1"
|
||||
marshal_call_after="_mesa_glthread_ListBase(ctx, base);">
|
||||
<param name="base" type="GLuint"/>
|
||||
<glx rop="3"/>
|
||||
</function>
|
||||
|
|
@ -2376,13 +2380,13 @@
|
|||
</function>
|
||||
|
||||
<function name="Disable" es1="1.0" es2="2.0"
|
||||
marshal_call_after="if (cap == GL_PRIMITIVE_RESTART || cap == GL_PRIMITIVE_RESTART_FIXED_INDEX) _mesa_glthread_set_prim_restart(ctx, cap, false);">
|
||||
marshal_call_after="_mesa_glthread_Disable(ctx, cap);">
|
||||
<param name="cap" type="GLenum"/>
|
||||
<glx rop="138" handcode="client"/>
|
||||
</function>
|
||||
|
||||
<function name="Enable" es1="1.0" es2="2.0"
|
||||
marshal_call_after='if (cap == GL_PRIMITIVE_RESTART || cap == GL_PRIMITIVE_RESTART_FIXED_INDEX) { _mesa_glthread_set_prim_restart(ctx, cap, true); } else if (cap == GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB) { _mesa_glthread_disable(ctx, "Enable(DEBUG_OUTPUT_SYNCHRONOUS)"); }'>
|
||||
marshal_call_after='_mesa_glthread_Enable(ctx, cap);'>
|
||||
<param name="cap" type="GLenum"/>
|
||||
<glx rop="139" handcode="client"/>
|
||||
</function>
|
||||
|
|
|
|||
|
|
@ -63,6 +63,7 @@
|
|||
#include "varray.h"
|
||||
#include "arbprogram.h"
|
||||
#include "transformfeedback.h"
|
||||
#include "glthread_marshal.h"
|
||||
|
||||
#include "math/m_matrix.h"
|
||||
|
||||
|
|
@ -14990,6 +14991,87 @@ print_list(struct gl_context *ctx, GLuint list, const char *fname)
|
|||
}
|
||||
|
||||
|
||||
void
|
||||
_mesa_glthread_execute_list(struct gl_context *ctx, GLuint list)
|
||||
{
|
||||
struct gl_display_list *dlist;
|
||||
|
||||
if (list == 0 ||
|
||||
ctx->GLThread.ListCallDepth == MAX_LIST_NESTING ||
|
||||
!_mesa_get_list(ctx, list, &dlist))
|
||||
return;
|
||||
|
||||
ctx->GLThread.ListCallDepth++;
|
||||
|
||||
Node *n = dlist->Head;
|
||||
|
||||
while (1) {
|
||||
const OpCode opcode = n[0].opcode;
|
||||
|
||||
if (is_ext_opcode(opcode)) {
|
||||
n += ctx->ListExt->Opcode[n[0].opcode - OPCODE_EXT_0].Size;
|
||||
} else {
|
||||
switch (opcode) {
|
||||
case OPCODE_CALL_LIST:
|
||||
/* Generated by glCallList(), don't add ListBase */
|
||||
if (ctx->GLThread.ListCallDepth < MAX_LIST_NESTING)
|
||||
_mesa_glthread_execute_list(ctx, n[1].ui);
|
||||
break;
|
||||
case OPCODE_CALL_LISTS:
|
||||
if (ctx->GLThread.ListCallDepth < MAX_LIST_NESTING)
|
||||
_mesa_glthread_CallLists(ctx, n[1].i, n[2].e, get_pointer(&n[3]));
|
||||
break;
|
||||
case OPCODE_DISABLE:
|
||||
_mesa_glthread_Disable(ctx, n[1].e);
|
||||
break;
|
||||
case OPCODE_ENABLE:
|
||||
_mesa_glthread_Enable(ctx, n[1].e);
|
||||
break;
|
||||
case OPCODE_LIST_BASE:
|
||||
_mesa_glthread_ListBase(ctx, n[1].ui);
|
||||
break;
|
||||
case OPCODE_MATRIX_MODE:
|
||||
_mesa_glthread_MatrixMode(ctx, n[1].e);
|
||||
break;
|
||||
case OPCODE_POP_ATTRIB:
|
||||
_mesa_glthread_PopAttrib(ctx);
|
||||
break;
|
||||
case OPCODE_POP_MATRIX:
|
||||
_mesa_glthread_PopMatrix(ctx);
|
||||
break;
|
||||
case OPCODE_PUSH_ATTRIB:
|
||||
_mesa_glthread_PushAttrib(ctx, n[1].bf);
|
||||
break;
|
||||
case OPCODE_PUSH_MATRIX:
|
||||
_mesa_glthread_PushMatrix(ctx);
|
||||
break;
|
||||
case OPCODE_ACTIVE_TEXTURE: /* GL_ARB_multitexture */
|
||||
_mesa_glthread_ActiveTexture(ctx, n[1].e);
|
||||
break;
|
||||
case OPCODE_MATRIX_PUSH:
|
||||
_mesa_glthread_MatrixPushEXT(ctx, n[1].e);
|
||||
break;
|
||||
case OPCODE_MATRIX_POP:
|
||||
_mesa_glthread_MatrixPopEXT(ctx, n[1].e);
|
||||
break;
|
||||
case OPCODE_CONTINUE:
|
||||
n = (Node *)get_pointer(&n[1]);
|
||||
continue;
|
||||
case OPCODE_END_OF_LIST:
|
||||
ctx->GLThread.ListCallDepth--;
|
||||
return;
|
||||
default:
|
||||
/* ignore */
|
||||
break;
|
||||
}
|
||||
|
||||
/* increment n to point to next compiled command */
|
||||
assert(InstSize[opcode] > 0);
|
||||
n += InstSize[opcode];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Clients may call this function to help debug display list problems.
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ glthread_unmarshal_batch(void *job, int thread_index)
|
|||
unsigned batch_index = batch - ctx->GLThread.batches;
|
||||
/* Atomically set this to -1 if it's equal to batch_index. */
|
||||
p_atomic_cmpxchg(&ctx->GLThread.LastProgramChangeBatch, batch_index, -1);
|
||||
|
||||
p_atomic_cmpxchg(&ctx->GLThread.LastDListChangeBatchIndex, batch_index, -1);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -139,6 +139,8 @@ _mesa_glthread_init(struct gl_context *ctx)
|
|||
|
||||
ctx->CurrentClientDispatch = ctx->MarshalExec;
|
||||
|
||||
glthread->LastDListChangeBatchIndex = -1;
|
||||
|
||||
/* Execute the thread initialization function in the thread. */
|
||||
struct util_queue_fence fence;
|
||||
util_queue_fence_init(&fence);
|
||||
|
|
|
|||
|
|
@ -155,6 +155,8 @@ struct glthread_state
|
|||
|
||||
/** Display lists. */
|
||||
GLenum ListMode; /**< Zero if not inside display list, else list mode. */
|
||||
unsigned ListBase;
|
||||
unsigned ListCallDepth;
|
||||
|
||||
/** For L3 cache pinning. */
|
||||
unsigned pin_thread_counter;
|
||||
|
|
@ -210,6 +212,12 @@ struct glthread_state
|
|||
*/
|
||||
int LastProgramChangeBatch;
|
||||
|
||||
/**
|
||||
* The batch index of the last occurence of glEndList or
|
||||
* glDeleteLists or -1 if there is no such enqueued call.
|
||||
*/
|
||||
int LastDListChangeBatchIndex;
|
||||
|
||||
/** Basic matrix state tracking. */
|
||||
int ActiveTexture;
|
||||
GLenum MatrixMode;
|
||||
|
|
@ -234,6 +242,7 @@ void _mesa_glthread_upload(struct gl_context *ctx, const void *data,
|
|||
void _mesa_glthread_reset_vao(struct glthread_vao *vao);
|
||||
void _mesa_error_glthread_safe(struct gl_context *ctx, GLenum error,
|
||||
bool glthread, const char *format, ...);
|
||||
void _mesa_glthread_execute_list(struct gl_context *ctx, GLuint list);
|
||||
|
||||
void _mesa_glthread_BindBuffer(struct gl_context *ctx, GLenum target,
|
||||
GLuint buffer);
|
||||
|
|
|
|||
|
|
@ -423,9 +423,36 @@ _mesa_get_matrix_index(struct gl_context *ctx, GLenum mode)
|
|||
return M_DUMMY;
|
||||
}
|
||||
|
||||
static inline void
|
||||
_mesa_glthread_Enable(struct gl_context *ctx, GLenum cap)
|
||||
{
|
||||
if (ctx->GLThread.ListMode == GL_COMPILE)
|
||||
return;
|
||||
|
||||
if (cap == GL_PRIMITIVE_RESTART ||
|
||||
cap == GL_PRIMITIVE_RESTART_FIXED_INDEX)
|
||||
_mesa_glthread_set_prim_restart(ctx, cap, true);
|
||||
else if (cap == GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB)
|
||||
_mesa_glthread_disable(ctx, "Enable(DEBUG_OUTPUT_SYNCHRONOUS)");
|
||||
}
|
||||
|
||||
static inline void
|
||||
_mesa_glthread_Disable(struct gl_context *ctx, GLenum cap)
|
||||
{
|
||||
if (ctx->GLThread.ListMode == GL_COMPILE)
|
||||
return;
|
||||
|
||||
if (cap == GL_PRIMITIVE_RESTART ||
|
||||
cap == GL_PRIMITIVE_RESTART_FIXED_INDEX)
|
||||
_mesa_glthread_set_prim_restart(ctx, cap, false);
|
||||
}
|
||||
|
||||
static inline void
|
||||
_mesa_glthread_PushAttrib(struct gl_context *ctx, GLbitfield mask)
|
||||
{
|
||||
if (ctx->GLThread.ListMode == GL_COMPILE)
|
||||
return;
|
||||
|
||||
struct glthread_attrib_node *attr =
|
||||
&ctx->GLThread.AttribStack[ctx->GLThread.AttribStackDepth++];
|
||||
|
||||
|
|
@ -441,6 +468,9 @@ _mesa_glthread_PushAttrib(struct gl_context *ctx, GLbitfield mask)
|
|||
static inline void
|
||||
_mesa_glthread_PopAttrib(struct gl_context *ctx)
|
||||
{
|
||||
if (ctx->GLThread.ListMode == GL_COMPILE)
|
||||
return;
|
||||
|
||||
struct glthread_attrib_node *attr =
|
||||
&ctx->GLThread.AttribStack[--ctx->GLThread.AttribStackDepth];
|
||||
unsigned mask = attr->Mask;
|
||||
|
|
@ -457,18 +487,27 @@ _mesa_glthread_PopAttrib(struct gl_context *ctx)
|
|||
static inline void
|
||||
_mesa_glthread_MatrixPushEXT(struct gl_context *ctx, GLenum matrixMode)
|
||||
{
|
||||
if (ctx->GLThread.ListMode == GL_COMPILE)
|
||||
return;
|
||||
|
||||
ctx->GLThread.MatrixStackDepth[_mesa_get_matrix_index(ctx, matrixMode)]++;
|
||||
}
|
||||
|
||||
static inline void
|
||||
_mesa_glthread_MatrixPopEXT(struct gl_context *ctx, GLenum matrixMode)
|
||||
{
|
||||
if (ctx->GLThread.ListMode == GL_COMPILE)
|
||||
return;
|
||||
|
||||
ctx->GLThread.MatrixStackDepth[_mesa_get_matrix_index(ctx, matrixMode)]--;
|
||||
}
|
||||
|
||||
static inline void
|
||||
_mesa_glthread_ActiveTexture(struct gl_context *ctx, GLenum texture)
|
||||
{
|
||||
if (ctx->GLThread.ListMode == GL_COMPILE)
|
||||
return;
|
||||
|
||||
ctx->GLThread.ActiveTexture = texture - GL_TEXTURE0;
|
||||
if (ctx->GLThread.MatrixMode == GL_TEXTURE)
|
||||
ctx->GLThread.MatrixIndex = _mesa_get_matrix_index(ctx, texture);
|
||||
|
|
@ -477,20 +516,196 @@ _mesa_glthread_ActiveTexture(struct gl_context *ctx, GLenum texture)
|
|||
static inline void
|
||||
_mesa_glthread_PushMatrix(struct gl_context *ctx)
|
||||
{
|
||||
if (ctx->GLThread.ListMode == GL_COMPILE)
|
||||
return;
|
||||
|
||||
ctx->GLThread.MatrixStackDepth[ctx->GLThread.MatrixIndex]++;
|
||||
}
|
||||
|
||||
static inline void
|
||||
_mesa_glthread_PopMatrix(struct gl_context *ctx)
|
||||
{
|
||||
if (ctx->GLThread.ListMode == GL_COMPILE)
|
||||
return;
|
||||
|
||||
ctx->GLThread.MatrixStackDepth[ctx->GLThread.MatrixIndex]--;
|
||||
}
|
||||
|
||||
static inline void
|
||||
_mesa_glthread_MatrixMode(struct gl_context *ctx, GLenum mode)
|
||||
{
|
||||
if (ctx->GLThread.ListMode == GL_COMPILE)
|
||||
return;
|
||||
|
||||
ctx->GLThread.MatrixIndex = _mesa_get_matrix_index(ctx, mode);
|
||||
ctx->GLThread.MatrixMode = mode;
|
||||
}
|
||||
|
||||
static inline void
|
||||
_mesa_glthread_ListBase(struct gl_context *ctx, GLuint base)
|
||||
{
|
||||
if (ctx->GLThread.ListMode == GL_COMPILE)
|
||||
return;
|
||||
|
||||
ctx->GLThread.ListBase = base;
|
||||
}
|
||||
|
||||
static inline void
|
||||
_mesa_glthread_CallList(struct gl_context *ctx, GLuint list)
|
||||
{
|
||||
if (ctx->GLThread.ListMode == GL_COMPILE)
|
||||
return;
|
||||
|
||||
/* Wait for all glEndList and glDeleteLists calls to finish to ensure that
|
||||
* all display lists are up to date and the driver thread is not
|
||||
* modifiying them. We will be executing them in the application thread.
|
||||
*/
|
||||
int batch = p_atomic_read(&ctx->GLThread.LastDListChangeBatchIndex);
|
||||
if (batch != -1) {
|
||||
util_queue_fence_wait(&ctx->GLThread.batches[batch].fence);
|
||||
p_atomic_set(&ctx->GLThread.LastDListChangeBatchIndex, -1);
|
||||
}
|
||||
|
||||
/* Clear GL_COMPILE_AND_EXECUTE if needed. We only execute here. */
|
||||
unsigned saved_mode = ctx->GLThread.ListMode;
|
||||
ctx->GLThread.ListMode = 0;
|
||||
|
||||
_mesa_glthread_execute_list(ctx, list);
|
||||
|
||||
ctx->GLThread.ListMode = saved_mode;
|
||||
}
|
||||
|
||||
static inline void
|
||||
_mesa_glthread_CallLists(struct gl_context *ctx, GLsizei n, GLenum type,
|
||||
const GLvoid *lists)
|
||||
{
|
||||
if (ctx->GLThread.ListMode == GL_COMPILE)
|
||||
return;
|
||||
|
||||
if (n <= 0 || !lists)
|
||||
return;
|
||||
|
||||
/* Wait for all glEndList and glDeleteLists calls to finish to ensure that
|
||||
* all display lists are up to date and the driver thread is not
|
||||
* modifiying them. We will be executing them in the application thread.
|
||||
*/
|
||||
int batch = p_atomic_read(&ctx->GLThread.LastDListChangeBatchIndex);
|
||||
if (batch != -1) {
|
||||
util_queue_fence_wait(&ctx->GLThread.batches[batch].fence);
|
||||
p_atomic_set(&ctx->GLThread.LastDListChangeBatchIndex, -1);
|
||||
}
|
||||
|
||||
/* Clear GL_COMPILE_AND_EXECUTE if needed. We only execute here. */
|
||||
unsigned saved_mode = ctx->GLThread.ListMode;
|
||||
ctx->GLThread.ListMode = 0;
|
||||
|
||||
unsigned base = ctx->GLThread.ListBase;
|
||||
|
||||
GLbyte *bptr;
|
||||
GLubyte *ubptr;
|
||||
GLshort *sptr;
|
||||
GLushort *usptr;
|
||||
GLint *iptr;
|
||||
GLuint *uiptr;
|
||||
GLfloat *fptr;
|
||||
|
||||
switch (type) {
|
||||
case GL_BYTE:
|
||||
bptr = (GLbyte *) lists;
|
||||
for (unsigned i = 0; i < n; i++)
|
||||
_mesa_glthread_CallList(ctx, base + bptr[i]);
|
||||
break;
|
||||
case GL_UNSIGNED_BYTE:
|
||||
ubptr = (GLubyte *) lists;
|
||||
for (unsigned i = 0; i < n; i++)
|
||||
_mesa_glthread_CallList(ctx, base + ubptr[i]);
|
||||
break;
|
||||
case GL_SHORT:
|
||||
sptr = (GLshort *) lists;
|
||||
for (unsigned i = 0; i < n; i++)
|
||||
_mesa_glthread_CallList(ctx, base + sptr[i]);
|
||||
break;
|
||||
case GL_UNSIGNED_SHORT:
|
||||
usptr = (GLushort *) lists;
|
||||
for (unsigned i = 0; i < n; i++)
|
||||
_mesa_glthread_CallList(ctx, base + usptr[i]);
|
||||
break;
|
||||
case GL_INT:
|
||||
iptr = (GLint *) lists;
|
||||
for (unsigned i = 0; i < n; i++)
|
||||
_mesa_glthread_CallList(ctx, base + iptr[i]);
|
||||
break;
|
||||
case GL_UNSIGNED_INT:
|
||||
uiptr = (GLuint *) lists;
|
||||
for (unsigned i = 0; i < n; i++)
|
||||
_mesa_glthread_CallList(ctx, base + uiptr[i]);
|
||||
break;
|
||||
case GL_FLOAT:
|
||||
fptr = (GLfloat *) lists;
|
||||
for (unsigned i = 0; i < n; i++)
|
||||
_mesa_glthread_CallList(ctx, base + fptr[i]);
|
||||
break;
|
||||
case GL_2_BYTES:
|
||||
ubptr = (GLubyte *) lists;
|
||||
for (unsigned i = 0; i < n; i++) {
|
||||
_mesa_glthread_CallList(ctx, base +
|
||||
(GLint)ubptr[2 * i] * 256 +
|
||||
(GLint)ubptr[2 * i + 1]);
|
||||
}
|
||||
break;
|
||||
case GL_3_BYTES:
|
||||
ubptr = (GLubyte *) lists;
|
||||
for (unsigned i = 0; i < n; i++) {
|
||||
_mesa_glthread_CallList(ctx, base +
|
||||
(GLint)ubptr[3 * i] * 65536 +
|
||||
(GLint)ubptr[3 * i + 1] * 256 +
|
||||
(GLint)ubptr[3 * i + 2]);
|
||||
}
|
||||
break;
|
||||
case GL_4_BYTES:
|
||||
ubptr = (GLubyte *) lists;
|
||||
for (unsigned i = 0; i < n; i++) {
|
||||
_mesa_glthread_CallList(ctx, base +
|
||||
(GLint)ubptr[4 * i] * 16777216 +
|
||||
(GLint)ubptr[4 * i + 1] * 65536 +
|
||||
(GLint)ubptr[4 * i + 2] * 256 +
|
||||
(GLint)ubptr[4 * i + 3]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
ctx->GLThread.ListMode = saved_mode;
|
||||
}
|
||||
|
||||
static inline void
|
||||
_mesa_glthread_NewList(struct gl_context *ctx, GLuint list, GLuint mode)
|
||||
{
|
||||
if (!ctx->GLThread.ListMode)
|
||||
ctx->GLThread.ListMode = mode;
|
||||
}
|
||||
|
||||
static inline void
|
||||
_mesa_glthread_EndList(struct gl_context *ctx)
|
||||
{
|
||||
if (!ctx->GLThread.ListMode)
|
||||
return;
|
||||
|
||||
ctx->GLThread.ListMode = 0;
|
||||
|
||||
/* Track the last display list change. */
|
||||
p_atomic_set(&ctx->GLThread.LastDListChangeBatchIndex, ctx->GLThread.next);
|
||||
_mesa_glthread_flush_batch(ctx);
|
||||
}
|
||||
|
||||
static inline void
|
||||
_mesa_glthread_DeleteLists(struct gl_context *ctx, GLsizei range)
|
||||
{
|
||||
if (range < 0)
|
||||
return;
|
||||
|
||||
/* Track the last display list change. */
|
||||
p_atomic_set(&ctx->GLThread.LastDListChangeBatchIndex, ctx->GLThread.next);
|
||||
_mesa_glthread_flush_batch(ctx);
|
||||
}
|
||||
|
||||
#endif /* MARSHAL_H */
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue