mesa/st/samplerview: explicitly block releasing in-use samplerviews
Some checks are pending
macOS-CI / macOS-CI (dri) (push) Waiting to run
macOS-CI / macOS-CI (xlib) (push) Waiting to run

st_texture_set_sampler_view() currently allows only one samplerview for
a given texobj per context. in a scenario where the same texobj is
bound multiple times with different samplerviews (e.g., SRGB) for the
same draw like

samplerviews[] = {view0, view1}

then st_texture_set_sampler_view() will release view0 while creating view1
before either view is actually set to the driver, and then the driver will explode

this is gross, but the best solution which avoids infinite memory ballooning
from bufferview offsets is to pass through the array of views during creation
to ensure that the cache doesn't try to prune a view it just created

caught by Left 4 Dead 2

Closes: https://gitlab.freedesktop.org/mesa/mesa/-/issues/15045

Reviewed-by: Timothy Arceri <tarceri@itsqueeze.com>
(cherry picked from commit 3264adf863)

Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/40488>
This commit is contained in:
Mike Blumenkrantz 2026-03-11 13:32:04 -04:00 committed by Eric Engestrom
parent d123fcf112
commit cbc172ecb2
7 changed files with 49 additions and 17 deletions

View file

@ -974,7 +974,7 @@
"description": "mesa/st/samplerview: explicitly block releasing in-use samplerviews",
"nominated": false,
"nomination_type": 0,
"resolution": 4,
"resolution": 1,
"main_sha": null,
"because_sha": null,
"notes": null

View file

@ -237,9 +237,9 @@ new_texture_handle(struct gl_context *ctx, struct gl_texture_object *texObj,
/* TODO: Clarify the interaction of ARB_bindless_texture and EXT_texture_sRGB_decode */
view = st_get_texture_sampler_view_from_stobj(st, texObj, sampObj, 0,
false);
false, 0, NULL);
} else {
view = st_get_buffer_sampler_view_from_stobj(st, texObj);
view = st_get_buffer_sampler_view_from_stobj(st, texObj, 0, NULL);
sampler.unnormalized_coords = 0;
}

View file

@ -58,7 +58,9 @@
struct pipe_sampler_view *
st_update_single_texture(struct st_context *st,
GLuint texUnit, bool glsl130_or_later,
bool ignore_srgb_decode)
bool ignore_srgb_decode,
unsigned num_norelease_views,
const struct pipe_sampler_view **norelease_views)
{
struct gl_context *ctx = st->ctx;
struct gl_texture_object *texObj;
@ -69,7 +71,7 @@ st_update_single_texture(struct st_context *st,
GLenum target = texObj->Target;
if (unlikely(target == GL_TEXTURE_BUFFER))
return st_get_buffer_sampler_view_from_stobj(st, texObj);
return st_get_buffer_sampler_view_from_stobj(st, texObj, num_norelease_views, norelease_views);
if (!st_finalize_texture(ctx, st->pipe, texObj, 0) || !texObj->pt)
return NULL; /* out of mem */
@ -81,7 +83,8 @@ st_update_single_texture(struct st_context *st,
return st_get_texture_sampler_view_from_stobj(st, texObj,
_mesa_get_samplerobj(ctx, texUnit),
glsl130_or_later,
ignore_srgb_decode);
ignore_srgb_decode,
num_norelease_views, norelease_views);
}
@ -147,7 +150,9 @@ st_get_sampler_views(struct st_context *st,
*/
sampler_views[unit] =
st_update_single_texture(st, prog->SamplerUnits[unit], glsl130,
texel_fetch_samplers & bit);
texel_fetch_samplers & bit,
/* prevent any of these views from being released */
unit, (const struct pipe_sampler_view **)sampler_views);
}
/* For any external samplers with multiplaner YUV, stuff the additional

View file

@ -40,6 +40,18 @@
#include "st_format.h"
#include "st_cb_texture.h"
static bool
can_release_samplerview(const struct pipe_sampler_view *view,
unsigned num_norelease_views,
const struct pipe_sampler_view **norelease_views)
{
for (unsigned i = 0; i < num_norelease_views; i++) {
if (norelease_views[i] == view)
return false;
}
return true;
}
/**
* Set the given view as the current context's view for the texture.
*
@ -56,7 +68,9 @@ st_texture_set_sampler_view(struct st_context *st,
struct gl_texture_object *stObj,
struct pipe_sampler_view *view,
bool glsl130_or_later,
bool locked)
bool locked,
unsigned num_norelease_views,
const struct pipe_sampler_view **norelease_views)
{
struct st_sampler_views *views;
struct st_sampler_view *free = NULL;
@ -73,7 +87,8 @@ st_texture_set_sampler_view(struct st_context *st,
/* Is the array entry used ? */
if (sv->view) {
/* check if the context matches */
if (sv->view->context == st->pipe) {
if (sv->view->context == st->pipe &&
can_release_samplerview(sv->view, num_norelease_views, norelease_views)) {
st->pipe->sampler_view_release(st->pipe, sv->view);
sv->view = NULL;
goto found;
@ -527,7 +542,9 @@ st_get_texture_sampler_view_from_stobj(struct st_context *st,
struct gl_texture_object *texObj,
const struct gl_sampler_object *samp,
bool glsl130_or_later,
bool ignore_srgb_decode)
bool ignore_srgb_decode,
unsigned num_norelease_views,
const struct pipe_sampler_view **norelease_views)
{
struct st_sampler_view *sv;
bool srgb_skip_decode = false;
@ -571,7 +588,8 @@ st_get_texture_sampler_view_from_stobj(struct st_context *st,
view = st_texture_set_sampler_view(st, texObj, view,
glsl130_or_later,
true);
true,
num_norelease_views, norelease_views);
simple_mtx_unlock(&texObj->validate_mutex);
return view;
@ -580,7 +598,9 @@ st_get_texture_sampler_view_from_stobj(struct st_context *st,
struct pipe_sampler_view *
st_get_buffer_sampler_view_from_stobj(struct st_context *st,
struct gl_texture_object *texObj)
struct gl_texture_object *texObj,
unsigned num_norelease_views,
const struct pipe_sampler_view **norelease_views)
{
struct st_sampler_view *sv;
struct gl_buffer_object *stBuf =
@ -640,7 +660,8 @@ st_get_buffer_sampler_view_from_stobj(struct st_context *st,
struct pipe_sampler_view *view =
st->pipe->create_sampler_view(st->pipe, buf, &templ);
view = st_texture_set_sampler_view(st, texObj, view, false, false);
view = st_texture_set_sampler_view(st, texObj, view, false, false,
num_norelease_views, norelease_views);
return view;
}

View file

@ -71,11 +71,15 @@ st_get_texture_sampler_view_from_stobj(struct st_context *st,
struct gl_texture_object *stObj,
const struct gl_sampler_object *samp,
bool glsl130_or_later,
bool ignore_srgb_decode);
bool ignore_srgb_decode,
unsigned num_norelease_views,
const struct pipe_sampler_view **norelease_views);
struct pipe_sampler_view *
st_get_buffer_sampler_view_from_stobj(struct st_context *st,
struct gl_texture_object *stObj);
struct gl_texture_object *stObj,
unsigned num_norelease_views,
const struct pipe_sampler_view **norelease_views);
enum pipe_format
st_get_sampler_view_format(const struct st_context *st,

View file

@ -546,7 +546,7 @@ st_create_texture_handle_from_unit(struct st_context *st,
(prog->shader_program ? prog->shader_program->GLSL_Version : 0) >= 130;
/* TODO: Clarify the interaction of ARB_bindless_texture and EXT_texture_sRGB_decode */
view = st_update_single_texture(st, texUnit, glsl130, true);
view = st_update_single_texture(st, texUnit, glsl130, true, 0, NULL);
if (!view)
return 0;

View file

@ -249,7 +249,9 @@ st_convert_sampler_from_unit(const struct st_context *st,
struct pipe_sampler_view *
st_update_single_texture(struct st_context *st,
GLuint texUnit, bool glsl130_or_later,
bool ignore_srgb_decode);
bool ignore_srgb_decode,
unsigned num_norelease_views,
const struct pipe_sampler_view **norelease_views);
unsigned
st_get_sampler_views(struct st_context *st,