Commit deeca217 authored by Emma Anholt's avatar Emma Anholt Committed by Adam Jackson
Browse files

glamor: Require and use GL_ARB_sampler_objects



Sampler objects were introduced to GL in 2010, and are a software-only
API improvement that reduces the overhead of texture state changes,
which glamor's Render acceleration does a lot of. The idea is that
instead of doing a series of TexParameteri calls that have to validate a
bunch of GLenums and their values, you do one BindSampler of the sampler
object you want to use, and the driver gets to cache computed state in
the sampler object and reuse that.

For now, instead of having each core operation doing texturing reset
the sampler object, we have the Render and XV cases reset the sampler
on their way out. This causes more state changes for Render-only
operation, but is less invasive as it matches our previous behavior.

This commit is a prerequisite for doing ARB_texture_view for Render
acceleration of other formats.
Signed-off-by: Emma Anholt's avatarEric Anholt <eric@anholt.net>
parent f6f2f203
Pipeline #356736 passed with stages
in 4 minutes and 32 seconds
......@@ -776,6 +776,15 @@ glamor_init(ScreenPtr screen, unsigned int flags)
epoxy_has_gl_extension("GL_ARB_instanced_arrays"))
glamor_priv->use_gpu_shader4 = epoxy_has_gl_extension("GL_EXT_gpu_shader4");
/* XXX could still support GLES2 if we had GL_MESA_sampler_objects
* https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/2440
*/
if (!epoxy_has_gl_extension("GL_ARB_sampler_objects") &&
!(glamor_priv->is_gles && gl_version >= 30)) {
ErrorF("GL_ARB_sampler_objects required.\n");
goto fail;
}
glamor_priv->has_rw_pbo = FALSE;
if (!glamor_priv->is_gles)
glamor_priv->has_rw_pbo = TRUE;
......@@ -842,6 +851,22 @@ glamor_init(ScreenPtr screen, unsigned int flags)
glamor_set_debug_level(&glamor_debug_level);
/* Set up the default samplers at screen init time.
*
* This makes sure that all glamor core operations, including
* pixmap allocation, have the default texture sampler bound. If
* the texture unit doesn't have a sampler bound, then the
* texture's internal sampler will be used, which starts off in
* mipmap mode, and thus the texture would be considered
* incomplete.
*
* Additionally, at least on Mesa drivers, the relevant sampler
* object will be peeked at to guess at whether textures should
* have mipmap levels allocated at glTexImage2D time.
*/
glamor_reset_sampler(glamor_priv, 0);
glamor_reset_sampler(glamor_priv, 1);
if (!glamor_font_init(screen))
goto fail;
......@@ -1117,3 +1142,58 @@ glamor_finish(ScreenPtr screen)
glamor_make_current(glamor_priv);
glFinish();
}
static GLenum
glamor_sampler_filter(enum glamor_sampler sampler)
{
switch (sampler) {
case GLAMOR_SAMPLER_NEAREST_EDGE:
case GLAMOR_SAMPLER_NEAREST_BORDER:
case GLAMOR_SAMPLER_NEAREST_REPEAT:
case GLAMOR_SAMPLER_NEAREST_MIRRORED_REPEAT:
return GL_NEAREST;
case GLAMOR_SAMPLER_LINEAR_EDGE:
case GLAMOR_SAMPLER_LINEAR_BORDER:
case GLAMOR_SAMPLER_LINEAR_REPEAT:
case GLAMOR_SAMPLER_LINEAR_MIRRORED_REPEAT:
default:
return GL_LINEAR;
}
}
static GLenum
glamor_sampler_wrap(enum glamor_sampler sampler)
{
switch (sampler) {
case GLAMOR_SAMPLER_NEAREST_EDGE:
case GLAMOR_SAMPLER_LINEAR_EDGE:
return GL_CLAMP_TO_EDGE;
case GLAMOR_SAMPLER_NEAREST_BORDER:
case GLAMOR_SAMPLER_LINEAR_BORDER:
return GL_CLAMP_TO_BORDER;
case GLAMOR_SAMPLER_NEAREST_REPEAT:
case GLAMOR_SAMPLER_LINEAR_REPEAT:
return GL_REPEAT;
case GLAMOR_SAMPLER_NEAREST_MIRRORED_REPEAT:
case GLAMOR_SAMPLER_LINEAR_MIRRORED_REPEAT:
default:
return GL_MIRRORED_REPEAT;
}
}
void
glamor_init_sampler(glamor_screen_private *glamor_priv,
enum glamor_sampler state)
{
GLuint sampler;
glGenSamplers(1, &sampler);
glSamplerParameteri(sampler, GL_TEXTURE_MIN_FILTER,
glamor_sampler_filter(state));
glSamplerParameteri(sampler, GL_TEXTURE_MAG_FILTER,
glamor_sampler_filter(state));
glSamplerParameteri(sampler, GL_TEXTURE_WRAP_S, glamor_sampler_wrap(state));
glSamplerParameteri(sampler, GL_TEXTURE_WRAP_T, glamor_sampler_wrap(state));
glamor_priv->samplers[state] = sampler;
}
......@@ -126,9 +126,6 @@ glamor_create_texture_from_image(ScreenPtr screen,
glGenTextures(1, texture);
glBindTexture(GL_TEXTURE_2D, *texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, image);
glBindTexture(GL_TEXTURE_2D, 0);
......
......@@ -128,7 +128,15 @@ _glamor_create_tex(glamor_screen_private *glamor_priv,
glamor_make_current(glamor_priv);
glGenTextures(1, &tex);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, tex);
/* Even though all of glamor rendering uses sampler objects, we
* still set these parameters on the texture object's internal
* sampler state so that when we TexImage it we get a single-level
* texture. When we eventually use TexStorage, we won't need
* this.
*/
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
if (f->format == GL_RED)
......
......@@ -116,6 +116,12 @@ glamor_font_get(ScreenPtr screen, FontPtr font)
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, glamor_font->texture_id);
/* Even though all of glamor rendering uses sampler objects, we
* still set these parameters on the texture object's internal
* sampler state so that when we TexImage it we get a single-level
* texture. When we eventually use TexStorage, we won't need
* this.
*/
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
......
......@@ -152,6 +152,18 @@ enum gradient_shader {
SHADER_GRADIENT_COUNT,
};
enum glamor_sampler {
GLAMOR_SAMPLER_NEAREST_EDGE,
GLAMOR_SAMPLER_NEAREST_BORDER,
GLAMOR_SAMPLER_NEAREST_REPEAT,
GLAMOR_SAMPLER_NEAREST_MIRRORED_REPEAT,
GLAMOR_SAMPLER_LINEAR_EDGE,
GLAMOR_SAMPLER_LINEAR_BORDER,
GLAMOR_SAMPLER_LINEAR_REPEAT,
GLAMOR_SAMPLER_LINEAR_MIRRORED_REPEAT,
GLAMOR_SAMPLER_COUNT,
};
struct glamor_screen_private;
struct glamor_pixmap_private;
......@@ -258,6 +270,8 @@ typedef struct glamor_screen_private {
int glyph_max_dim;
char *glyph_defines;
GLuint samplers[GLAMOR_SAMPLER_COUNT];
/** Vertex buffer for all GPU rendering. */
GLuint vao;
GLuint vbo;
......@@ -586,6 +600,37 @@ glamor_pixmap_fbo *glamor_create_fbo_array(glamor_screen_private *glamor_priv,
void glamor_gldrawarrays_quads_using_indices(glamor_screen_private *glamor_priv,
unsigned count);
void
glamor_init_sampler(glamor_screen_private *glamor_priv,
enum glamor_sampler sampler);
static inline void
glamor_set_sampler(glamor_screen_private *glamor_priv, GLuint unit,
enum glamor_sampler sampler)
{
if (_X_UNLIKELY(!glamor_priv->samplers[sampler]))
glamor_init_sampler(glamor_priv, sampler);
glBindSampler(unit, glamor_priv->samplers[sampler]);
}
/**
* Resets a texture unit's sampler to its default state.
*
* Glamor core rendering doesn't set the sampler, and the sampler
* object is bound to the unit not the texture object, so we reset it
* on the way out of operations doing filtering.
*
* Since the core rendering is all 1:1 it seems like it shouldn't
* matter, but some hardware will have wrong LSBs in 1:1 with linear,
* and on even more hardware than that we're probably spending extra
* power on doing no-op interpolating.
*/
static inline void
glamor_reset_sampler(glamor_screen_private *glamor_priv, GLuint unit)
{
glamor_set_sampler(glamor_priv, unit, GLAMOR_SAMPLER_NEAREST_REPEAT);
}
/* glamor_core.c */
Bool glamor_get_drawable_location(const DrawablePtr drawable);
void glamor_get_drawable_deltas(DrawablePtr drawable, PixmapPtr pixmap,
......
......@@ -519,9 +519,12 @@ glamor_set_composite_texture(glamor_screen_private *glamor_priv, int unit,
glamor_pixmap_fbo *fbo = pixmap_priv->fbo;
float wh[4];
int repeat_type;
enum glamor_sampler sampler;
glamor_make_current(glamor_priv);
repeat_type = picture->repeatType;
/* The red channel swizzling doesn't depend on whether we're using
* 'fbo' as source or mask as we must have the same answer in case
* the same fbo is being used for both. That means the mask
......@@ -531,22 +534,19 @@ glamor_set_composite_texture(glamor_screen_private *glamor_priv, int unit,
glamor_bind_texture(glamor_priv, GL_TEXTURE0 + unit, fbo,
dest_priv->fbo->is_red);
repeat_type = picture->repeatType;
switch (picture->repeatType) {
case RepeatNone:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
sampler = GLAMOR_SAMPLER_NEAREST_BORDER;
break;
case RepeatNormal:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
sampler = GLAMOR_SAMPLER_NEAREST_REPEAT;
break;
case RepeatPad:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
sampler = GLAMOR_SAMPLER_NEAREST_EDGE;
break;
case RepeatReflect:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);
sampler = GLAMOR_SAMPLER_NEAREST_MIRRORED_REPEAT;
break;
}
......@@ -554,17 +554,16 @@ glamor_set_composite_texture(glamor_screen_private *glamor_priv, int unit,
default:
case PictFilterFast:
case PictFilterNearest:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
break;
case PictFilterGood:
case PictFilterBest:
case PictFilterBilinear:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
sampler += GLAMOR_SAMPLER_LINEAR_EDGE - GLAMOR_SAMPLER_NEAREST_EDGE;
break;
}
glamor_set_sampler(glamor_priv, unit, sampler);
/* Handle RepeatNone in the shader when the source is missing the
* alpha channel, as GL will return an alpha for 1 if the texture
* is RGB (no alpha), which we use for 16bpp textures.
......@@ -1305,6 +1304,10 @@ disable_va:
glDisableVertexAttribArray(GLAMOR_VERTEX_SOURCE);
glDisableVertexAttribArray(GLAMOR_VERTEX_MASK);
glDisable(GL_BLEND);
glamor_reset_sampler(glamor_priv, 0);
glamor_reset_sampler(glamor_priv, 1);
DEBUGF("finish rendering.\n");
if (saved_source_format)
source->format = saved_source_format;
......
......@@ -380,27 +380,18 @@ glamor_xv_render(glamor_port_private *port_priv, int id)
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, src_pixmap_priv[0]->fbo->tex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glamor_set_sampler(glamor_priv, 0, GLAMOR_SAMPLER_LINEAR_EDGE);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, src_pixmap_priv[1]->fbo->tex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glamor_set_sampler(glamor_priv, 1, GLAMOR_SAMPLER_LINEAR_EDGE);
switch (id) {
case FOURCC_YV12:
case FOURCC_I420:
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, src_pixmap_priv[2]->fbo->tex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glamor_set_sampler(glamor_priv, 2, GLAMOR_SAMPLER_LINEAR_EDGE);
break;
case FOURCC_NV12:
break;
......@@ -478,6 +469,9 @@ glamor_xv_render(glamor_port_private *port_priv, int id)
glDisableVertexAttribArray(GLAMOR_VERTEX_POS);
glDisableVertexAttribArray(GLAMOR_VERTEX_SOURCE);
glamor_reset_sampler(glamor_priv, 0);
glamor_reset_sampler(glamor_priv, 1);
glamor_reset_sampler(glamor_priv, 2);
DamageDamageRegion(port_priv->pDraw, &port_priv->clip);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment