mesa/st: add PIPE_CAP_GL_CLAMP

when this is not set, this triggers shader and sampler state updates any time a sampler
starts or stops using GL_CLAMP, applying bitmasks needed to run nir_lower_tex
and setting CLAMP_TO_BORDER/CLAMP_TO_EDGE as necessary to mimic the behavior

Reviewed-by: Eric Anholt <eric@anholt.net>
Reviewed-by: Marek Olšák <marek.olsak@amd.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/8756>
This commit is contained in:
Mike Blumenkrantz 2021-01-25 17:37:29 -05:00 committed by Marge Bot
parent 10e71d5c9a
commit e8f71f6ac4
13 changed files with 128 additions and 1 deletions

View File

@ -610,6 +610,7 @@ The integer capabilities:
* ``PIPE_CAP_MAX_TEXTURE_MB``: Maximum texture size in MB (default is 1024)
* ``PIPE_CAP_DEVICE_PROTECTED_CONTENT``: Whether the device support protected / encrypted content.
* ``PIPE_CAP_PREFER_REAL_BUFFER_IN_CONSTBUF0``: The state tracker is encouraged to upload constants into a real buffer and bind it into constant buffer 0 instead of binding a user pointer. This may enable a faster codepath in a gallium frontend for drivers that really prefer a real buffer.
* ``PIPE_CAP_GL_CLAMP``: Driver natively supports GL_CLAMP. Required for non-NIR drivers with the GL frontend. NIR drivers with the cap unavailable will have GL_CLAMP lowered to txd/txl with a saturate on the coordinates.
.. _pipe_capf:

View File

@ -46,6 +46,7 @@ u_pipe_screen_get_param_defaults(struct pipe_screen *pscreen,
return 0;
case PIPE_CAP_GRAPHICS:
case PIPE_CAP_GL_CLAMP:
case PIPE_CAP_MAX_RENDER_TARGETS:
return 1;

View File

@ -300,6 +300,7 @@ nvc0_screen_get_param(struct pipe_screen *pscreen, enum pipe_cap param)
case PIPE_CAP_TEXTURE_SHADOW_LOD:
case PIPE_CAP_PACKED_STREAM_OUTPUT:
case PIPE_CAP_CLEAR_SCISSORED:
case PIPE_CAP_GL_CLAMP:
return 1;
case PIPE_CAP_PREFER_BLIT_BASED_TEXTURE_TRANSFER:
return nouveau_screen(pscreen)->vram_domain & NOUVEAU_BO_VRAM ? 1 : 0;

View File

@ -977,7 +977,7 @@ enum pipe_cap
PIPE_CAP_SHADER_ATOMIC_INT64,
PIPE_CAP_DEVICE_PROTECTED_CONTENT,
PIPE_CAP_PREFER_REAL_BUFFER_IN_CONSTBUF0,
PIPE_CAP_GL_CLAMP,
PIPE_CAP_LAST,
/* XXX do not add caps after PIPE_CAP_LAST! */
};

View File

@ -4879,6 +4879,9 @@ struct gl_driver_flags
/** Programmable sample location state for gl_context::DrawBuffer */
uint64_t NewSampleLocations;
/** For GL_CLAMP emulation */
uint64_t NewSamplersWithClamp;
};
struct gl_buffer_binding

View File

@ -536,6 +536,12 @@ _mesa_set_sampler_wrap(struct gl_context *ctx, struct gl_sampler_object *samp,
#define INVALID_PNAME 0x101
#define INVALID_VALUE 0x102
static inline GLboolean
is_wrap_gl_clamp(GLint param)
{
return param == GL_CLAMP || param == GL_MIRROR_CLAMP_EXT;
}
static GLuint
set_sampler_wrap_s(struct gl_context *ctx, struct gl_sampler_object *samp,
GLint param)
@ -544,6 +550,8 @@ set_sampler_wrap_s(struct gl_context *ctx, struct gl_sampler_object *samp,
return GL_FALSE;
if (validate_texture_wrap_mode(ctx, param)) {
flush(ctx);
if (is_wrap_gl_clamp(samp->Attrib.WrapS) != is_wrap_gl_clamp(param))
ctx->NewDriverState |= ctx->DriverFlags.NewSamplersWithClamp;
samp->Attrib.WrapS = param;
return GL_TRUE;
}
@ -559,6 +567,8 @@ set_sampler_wrap_t(struct gl_context *ctx, struct gl_sampler_object *samp,
return GL_FALSE;
if (validate_texture_wrap_mode(ctx, param)) {
flush(ctx);
if (is_wrap_gl_clamp(samp->Attrib.WrapT) != is_wrap_gl_clamp(param))
ctx->NewDriverState |= ctx->DriverFlags.NewSamplersWithClamp;
samp->Attrib.WrapT = param;
return GL_TRUE;
}
@ -574,6 +584,8 @@ set_sampler_wrap_r(struct gl_context *ctx, struct gl_sampler_object *samp,
return GL_FALSE;
if (validate_texture_wrap_mode(ctx, param)) {
flush(ctx);
if (is_wrap_gl_clamp(samp->Attrib.WrapR) != is_wrap_gl_clamp(param))
ctx->NewDriverState |= ctx->DriverFlags.NewSamplersWithClamp;
samp->Attrib.WrapR = param;
return GL_TRUE;
}

View File

@ -239,6 +239,12 @@ _mesa_target_allows_setting_sampler_parameters(GLenum target)
}
static inline GLboolean
is_wrap_gl_clamp(GLint param)
{
return param == GL_CLAMP || param == GL_MIRROR_CLAMP_EXT;
}
/**
* Set an integer-valued texture parameter
* \return GL_TRUE if legal AND the value changed, GL_FALSE otherwise
@ -317,6 +323,8 @@ set_tex_parameteri(struct gl_context *ctx,
return GL_FALSE;
if (validate_texture_wrap_mode(ctx, texObj->Target, params[0])) {
flush(ctx);
if (is_wrap_gl_clamp(texObj->Sampler.Attrib.WrapS) != is_wrap_gl_clamp(params[0]))
ctx->NewDriverState |= ctx->DriverFlags.NewSamplersWithClamp;
texObj->Sampler.Attrib.WrapS = params[0];
return GL_TRUE;
}
@ -330,6 +338,8 @@ set_tex_parameteri(struct gl_context *ctx,
return GL_FALSE;
if (validate_texture_wrap_mode(ctx, texObj->Target, params[0])) {
flush(ctx);
if (is_wrap_gl_clamp(texObj->Sampler.Attrib.WrapT) != is_wrap_gl_clamp(params[0]))
ctx->NewDriverState |= ctx->DriverFlags.NewSamplersWithClamp;
texObj->Sampler.Attrib.WrapT = params[0];
return GL_TRUE;
}
@ -343,6 +353,8 @@ set_tex_parameteri(struct gl_context *ctx,
return GL_FALSE;
if (validate_texture_wrap_mode(ctx, texObj->Target, params[0])) {
flush(ctx);
if (is_wrap_gl_clamp(texObj->Sampler.Attrib.WrapR) != is_wrap_gl_clamp(params[0]))
ctx->NewDriverState |= ctx->DriverFlags.NewSamplersWithClamp;
texObj->Sampler.Attrib.WrapR = params[0];
return GL_TRUE;
}

View File

@ -98,6 +98,17 @@ gl_filter_to_img_filter(GLenum filter)
return PIPE_TEX_FILTER_NEAREST;
}
static inline unsigned
get_border_clamp(unsigned wrap, bool clamp_to_border)
{
if (wrap == PIPE_TEX_WRAP_CLAMP)
wrap = clamp_to_border ? PIPE_TEX_WRAP_CLAMP_TO_BORDER :
PIPE_TEX_WRAP_CLAMP_TO_EDGE;
else if (wrap == PIPE_TEX_WRAP_MIRROR_CLAMP)
wrap = clamp_to_border ? PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER :
PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE;
return wrap;
}
/**
* Convert a gl_sampler_object to a pipe_sampler_state object.
@ -123,6 +134,14 @@ st_convert_sampler(const struct st_context *st,
}
sampler->min_mip_filter = gl_filter_to_mip_filter(msamp->Attrib.MinFilter);
if (st->emulate_gl_clamp) {
bool clamp_to_border = sampler->min_img_filter != PIPE_TEX_FILTER_NEAREST &&
sampler->mag_img_filter != PIPE_TEX_FILTER_NEAREST;
sampler->wrap_s = get_border_clamp(sampler->wrap_s, clamp_to_border);
sampler->wrap_t = get_border_clamp(sampler->wrap_t, clamp_to_border);
sampler->wrap_r = get_border_clamp(sampler->wrap_r, clamp_to_border);
}
if (texobj->Target != GL_TEXTURE_RECTANGLE_ARB)
sampler->normalized_coords = 1;

View File

@ -73,6 +73,45 @@ get_texture_index(struct gl_context *ctx, const unsigned unit)
}
static inline GLboolean
is_wrap_gl_clamp(GLint param)
{
return param == GL_CLAMP || param == GL_MIRROR_CLAMP_EXT;
}
static void
update_gl_clamp(struct st_context *st, struct gl_program *prog, uint32_t *gl_clamp)
{
if (!st->emulate_gl_clamp)
return;
gl_clamp[0] = gl_clamp[1] = gl_clamp[2] = 0;
GLbitfield samplers_used = prog->SamplersUsed;
unsigned unit;
/* same as st_atom_sampler.c */
for (unit = 0; samplers_used; unit++, samplers_used >>= 1) {
unsigned tex_unit = prog->SamplerUnits[unit];
if (samplers_used & 1 &&
(st->ctx->Texture.Unit[tex_unit]._Current->Target != GL_TEXTURE_BUFFER ||
st->texture_buffer_sampler)) {
const struct gl_texture_object *texobj;
struct gl_context *ctx = st->ctx;
const struct gl_sampler_object *msamp;
texobj = ctx->Texture.Unit[tex_unit]._Current;
assert(texobj);
msamp = _mesa_get_samplerobj(ctx, tex_unit);
if (is_wrap_gl_clamp(msamp->Attrib.WrapS))
gl_clamp[0] |= BITFIELD64_BIT(unit);
if (is_wrap_gl_clamp(msamp->Attrib.WrapT))
gl_clamp[1] |= BITFIELD64_BIT(unit);
if (is_wrap_gl_clamp(msamp->Attrib.WrapR))
gl_clamp[2] |= BITFIELD64_BIT(unit);
}
}
}
/**
* Update fragment program state/atom. This involves translating the
* Mesa fragment program into a gallium fragment program and binding it.
@ -143,6 +182,7 @@ st_update_fp( struct st_context *st )
}
key.external = st_get_external_sampler_key(st, &stfp->Base);
update_gl_clamp(st, st->ctx->FragmentProgram._Current, key.gl_clamp);
simple_mtx_lock(&st->ctx->Shared->Mutex);
shader = st_get_fp_variant(st, stfp, &key)->base.driver_shader;
@ -218,6 +258,8 @@ st_update_vp( struct st_context *st )
key.lower_ucp = st->ctx->Transform.ClipPlanesEnabled;
}
update_gl_clamp(st, st->ctx->VertexProgram._Current, key.gl_clamp);
simple_mtx_lock(&st->ctx->Shared->Mutex);
st->vp_variant = st_get_vp_variant(st, stvp, &key);
simple_mtx_unlock(&st->ctx->Shared->Mutex);
@ -283,6 +325,8 @@ st_update_common_program(struct st_context *st, struct gl_program *prog,
}
update_gl_clamp(st, prog, key.gl_clamp);
simple_mtx_lock(&st->ctx->Shared->Mutex);
void *result = st_get_common_variant(st, stp, &key)->driver_shader;
simple_mtx_unlock(&st->ctx->Shared->Mutex);

View File

@ -574,6 +574,12 @@ st_init_driver_flags(struct st_context *st)
f->NewNvConservativeRasterization = ST_NEW_RASTERIZER;
f->NewNvConservativeRasterizationParams = ST_NEW_RASTERIZER;
f->NewIntelConservativeRasterization = ST_NEW_RASTERIZER;
if (st->emulate_gl_clamp)
f->NewSamplersWithClamp = ST_NEW_SAMPLERS |
ST_NEW_VS_STATE | ST_NEW_TCS_STATE |
ST_NEW_TES_STATE | ST_NEW_GS_STATE |
ST_NEW_FS_STATE | ST_NEW_CS_STATE;
}
@ -690,6 +696,8 @@ st_create_context_priv(struct gl_context *ctx, struct pipe_context *pipe,
!!(screen->get_param(screen, PIPE_CAP_TEXTURE_BORDER_COLOR_QUIRK) &
(PIPE_QUIRK_TEXTURE_BORDER_COLOR_SWIZZLE_NV50 |
PIPE_QUIRK_TEXTURE_BORDER_COLOR_SWIZZLE_R600));
st->emulate_gl_clamp =
!screen->get_param(screen, PIPE_CAP_GL_CLAMP);
st->texture_buffer_sampler =
screen->get_param(screen, PIPE_CAP_TEXTURE_BUFFER_SAMPLER);
st->has_time_elapsed =

View File

@ -182,6 +182,7 @@ struct st_context
boolean needs_texcoord_semantic;
boolean apply_texture_swizzle_to_border_color;
boolean emulate_gl_clamp;
boolean texture_buffer_sampler;
/* On old libGL's for linux we need to invalidate the drawables

View File

@ -783,6 +783,15 @@ st_create_vp_variant(struct st_context *st,
finalize = true;
}
if (st->emulate_gl_clamp &&
(key->gl_clamp[0] || key->gl_clamp[1] || key->gl_clamp[2])) {
nir_lower_tex_options tex_opts = {0};
tex_opts.saturate_s = key->gl_clamp[0];
tex_opts.saturate_t = key->gl_clamp[1];
tex_opts.saturate_r = key->gl_clamp[2];
NIR_PASS_V(state.ir.nir, nir_lower_tex, &tex_opts);
}
if (finalize || !st->allow_st_finalize_nir_twice) {
st_finalize_nir(st, &stvp->Base, stvp->shader_program, state.ir.nir,
true, false);
@ -1310,6 +1319,16 @@ st_create_fp_variant(struct st_context *st,
finalize = true;
}
if (st->emulate_gl_clamp &&
(key->gl_clamp[0] || key->gl_clamp[1] || key->gl_clamp[2])) {
nir_lower_tex_options tex_opts = {0};
tex_opts.saturate_s = key->gl_clamp[0];
tex_opts.saturate_t = key->gl_clamp[1];
tex_opts.saturate_r = key->gl_clamp[2];
NIR_PASS_V(state.ir.nir, nir_lower_tex, &tex_opts);
finalize = true;
}
assert(!(key->bitmap && key->drawpixels));
/* glBitmap */

View File

@ -151,6 +151,9 @@ struct st_fp_variant_key
uint8_t texture_index[MAX_NUM_FRAGMENT_REGISTERS_ATI];
struct st_external_sampler_key external;
/* bitmask of sampler units; PIPE_CAP_GL_CLAMP */
uint32_t gl_clamp[3];
};
/**
@ -209,6 +212,9 @@ struct st_common_variant_key
* not for the driver.
*/
bool is_draw_shader;
/* bitmask of sampler units; PIPE_CAP_GL_CLAMP */
uint32_t gl_clamp[3];
};