summaryrefslogtreecommitdiffstats
path: root/src/mesa/state_tracker
diff options
context:
space:
mode:
authorRob Clark <[email protected]>2016-08-31 17:44:01 -0400
committerRob Clark <[email protected]>2016-09-26 15:29:17 -0400
commitecd6fce2611e88ff8468a354cff8eda39f260a31 (patch)
treef4c281475a9dfb836cf9c9ff1853de0edc850bc6 /src/mesa/state_tracker
parente0ec1c31345aa8f47b5dea16d26be4420bd908ad (diff)
mesa/st: support lowering multi-planar YUV
Support multi-planar YUV for external EGLImage's (currently just in the dma-buf import path) by lowering to multiple texture fetch's for each plane and CSC in shader. There was some discussion of alternative approaches for tracking the additional UV or U/V planes: https://lists.freedesktop.org/archives/mesa-dev/2016-September/127832.html They all seemed worse than pipe_resource::next Signed-off-by: Rob Clark <[email protected]>
Diffstat (limited to 'src/mesa/state_tracker')
-rw-r--r--src/mesa/state_tracker/st_atom_sampler.c41
-rw-r--r--src/mesa/state_tracker/st_atom_shader.c3
-rw-r--r--src/mesa/state_tracker/st_atom_texture.c58
-rw-r--r--src/mesa/state_tracker/st_cb_eglimage.c18
-rw-r--r--src/mesa/state_tracker/st_context.c7
-rw-r--r--src/mesa/state_tracker/st_glsl_to_nir.cpp1
-rw-r--r--src/mesa/state_tracker/st_glsl_to_tgsi.cpp4
-rw-r--r--src/mesa/state_tracker/st_manager.c1
-rw-r--r--src/mesa/state_tracker/st_program.c35
-rw-r--r--src/mesa/state_tracker/st_program.h37
-rw-r--r--src/mesa/state_tracker/st_texture.h21
11 files changed, 222 insertions, 4 deletions
diff --git a/src/mesa/state_tracker/st_atom_sampler.c b/src/mesa/state_tracker/st_atom_sampler.c
index 6b36ac74aad..065df6dd006 100644
--- a/src/mesa/state_tracker/st_atom_sampler.c
+++ b/src/mesa/state_tracker/st_atom_sampler.c
@@ -243,13 +243,13 @@ update_shader_samplers(struct st_context *st,
struct pipe_sampler_state *samplers,
unsigned *num_samplers)
{
+ GLbitfield samplers_used = prog->SamplersUsed;
+ GLbitfield free_slots = ~prog->SamplersUsed;
+ GLbitfield external_samplers_used = prog->ExternalSamplersUsed;
GLuint unit;
- GLbitfield samplers_used;
const GLuint old_max = *num_samplers;
const struct pipe_sampler_state *states[PIPE_MAX_SAMPLERS];
- samplers_used = prog->SamplersUsed;
-
if (*num_samplers == 0 && samplers_used == 0x0)
return;
@@ -275,6 +275,41 @@ update_shader_samplers(struct st_context *st,
}
}
+ /* For any external samplers with multiplaner YUV, stuff the additional
+ * sampler states we need at the end.
+ *
+ * Just re-use the existing sampler-state from the primary slot.
+ */
+ while (unlikely(external_samplers_used)) {
+ GLuint unit = u_bit_scan(&external_samplers_used);
+ GLuint extra = 0;
+ struct st_texture_object *stObj =
+ st_get_texture_object(st->ctx, prog, unit);
+ struct pipe_sampler_state *sampler = samplers + unit;
+
+ if (!stObj)
+ continue;
+
+ switch (st_get_view_format(stObj)) {
+ case PIPE_FORMAT_NV12:
+ /* we need one additional sampler: */
+ extra = u_bit_scan(&free_slots);
+ states[extra] = sampler;
+ break;
+ case PIPE_FORMAT_IYUV:
+ /* we need two additional samplers: */
+ extra = u_bit_scan(&free_slots);
+ states[extra] = sampler;
+ extra = u_bit_scan(&free_slots);
+ states[extra] = sampler;
+ break;
+ default:
+ break;
+ }
+
+ *num_samplers = MAX2(*num_samplers, extra + 1);
+ }
+
cso_set_samplers(st->cso_context, shader_stage, *num_samplers, states);
}
diff --git a/src/mesa/state_tracker/st_atom_shader.c b/src/mesa/state_tracker/st_atom_shader.c
index 7a23469cede..2f700a2fc55 100644
--- a/src/mesa/state_tracker/st_atom_shader.c
+++ b/src/mesa/state_tracker/st_atom_shader.c
@@ -51,6 +51,7 @@
#include "st_context.h"
#include "st_atom.h"
#include "st_program.h"
+#include "st_texture.h"
/** Compress the fog function enums into a 2-bit value */
@@ -142,6 +143,8 @@ update_fp( struct st_context *st )
}
}
+ key.external = st_get_external_sampler_key(st, &stfp->Base.Base);
+
st->fp_variant = st_get_fp_variant(st, stfp, &key);
st_reference_fragprog(st, &st->fp, stfp);
diff --git a/src/mesa/state_tracker/st_atom_texture.c b/src/mesa/state_tracker/st_atom_texture.c
index 19df6622ef1..efc8c90ffae 100644
--- a/src/mesa/state_tracker/st_atom_texture.c
+++ b/src/mesa/state_tracker/st_atom_texture.c
@@ -408,6 +408,15 @@ update_single_texture(struct st_context *st,
}
}
+ switch (view_format) {
+ case PIPE_FORMAT_NV12:
+ case PIPE_FORMAT_IYUV:
+ view_format = PIPE_FORMAT_R8_UNORM;
+ break;
+ default:
+ break;
+ }
+
*sampler_view =
st_get_texture_sampler_view_from_stobj(st, stObj, view_format,
glsl_version);
@@ -426,6 +435,8 @@ update_textures(struct st_context *st,
{
const GLuint old_max = *num_textures;
GLbitfield samplers_used = prog->SamplersUsed;
+ GLbitfield free_slots = ~prog->SamplersUsed;
+ GLbitfield external_samplers_used = prog->ExternalSamplersUsed;
GLuint unit;
struct gl_shader_program *shader =
st->ctx->_Shader->CurrentProgram[mesa_shader];
@@ -460,6 +471,53 @@ update_textures(struct st_context *st,
pipe_sampler_view_reference(&(sampler_views[unit]), sampler_view);
}
+ /* For any external samplers with multiplaner YUV, stuff the additional
+ * sampler views we need at the end.
+ *
+ * Trying to cache the sampler view in the stObj looks painful, so just
+ * re-create the sampler view for the extra planes each time. Main use
+ * case is video playback (ie. fps games wouldn't be using this) so I
+ * guess no point to try to optimize this feature.
+ */
+ while (unlikely(external_samplers_used)) {
+ GLuint unit = u_bit_scan(&external_samplers_used);
+ GLuint extra = 0;
+ struct st_texture_object *stObj =
+ st_get_texture_object(st->ctx, prog, unit);
+ struct pipe_sampler_view tmpl;
+
+ if (!stObj)
+ continue;
+
+ /* use original view as template: */
+ tmpl = *sampler_views[unit];
+
+ switch (st_get_view_format(stObj)) {
+ case PIPE_FORMAT_NV12:
+ /* we need one additional R8G8 view: */
+ tmpl.format = PIPE_FORMAT_RG88_UNORM;
+ tmpl.swizzle_g = PIPE_SWIZZLE_Y; /* tmpl from Y plane is R8 */
+ extra = u_bit_scan(&free_slots);
+ sampler_views[extra] =
+ st->pipe->create_sampler_view(st->pipe, stObj->pt->next, &tmpl);
+ break;
+ case PIPE_FORMAT_IYUV:
+ /* we need two additional R8 views: */
+ tmpl.format = PIPE_FORMAT_R8_UNORM;
+ extra = u_bit_scan(&free_slots);
+ sampler_views[extra] =
+ st->pipe->create_sampler_view(st->pipe, stObj->pt->next, &tmpl);
+ extra = u_bit_scan(&free_slots);
+ sampler_views[extra] =
+ st->pipe->create_sampler_view(st->pipe, stObj->pt->next->next, &tmpl);
+ break;
+ default:
+ break;
+ }
+
+ *num_textures = MAX2(*num_textures, extra + 1);
+ }
+
cso_set_sampler_views(st->cso_context,
shader_stage,
*num_textures,
diff --git a/src/mesa/state_tracker/st_cb_eglimage.c b/src/mesa/state_tracker/st_cb_eglimage.c
index 1782d154dd6..7bea5653e46 100644
--- a/src/mesa/state_tracker/st_cb_eglimage.c
+++ b/src/mesa/state_tracker/st_cb_eglimage.c
@@ -119,6 +119,24 @@ st_bind_surface(struct gl_context *ctx, GLenum target,
texFormat = st_pipe_format_to_mesa_format(ps->format);
+ /* TODO RequiredTextureImageUnits should probably be reset back
+ * to 1 somewhere if different texture is bound??
+ */
+ if (texFormat == MESA_FORMAT_NONE) {
+ switch (ps->format) {
+ case PIPE_FORMAT_NV12:
+ texFormat = MESA_FORMAT_R_UNORM8;
+ texObj->RequiredTextureImageUnits = 2;
+ break;
+ case PIPE_FORMAT_IYUV:
+ texFormat = MESA_FORMAT_R_UNORM8;
+ texObj->RequiredTextureImageUnits = 3;
+ break;
+ default:
+ unreachable("bad YUV format!");
+ }
+ }
+
_mesa_init_teximage_fields(ctx, texImage,
ps->width, ps->height, 1, 0, internalFormat,
texFormat);
diff --git a/src/mesa/state_tracker/st_context.c b/src/mesa/state_tracker/st_context.c
index 81b3387626c..b9dc0c67da3 100644
--- a/src/mesa/state_tracker/st_context.c
+++ b/src/mesa/state_tracker/st_context.c
@@ -255,11 +255,16 @@ void st_invalidate_state(struct gl_context * ctx, GLbitfield new_state)
st->active_states = st_get_active_states(ctx);
}
- if (new_state & _NEW_TEXTURE)
+ if (new_state & _NEW_TEXTURE) {
st->dirty |= st->active_states &
(ST_NEW_SAMPLER_VIEWS |
ST_NEW_SAMPLERS |
ST_NEW_IMAGE_UNITS);
+ if (ctx->FragmentProgram._Current &&
+ ctx->FragmentProgram._Current->Base.ExternalSamplersUsed) {
+ st->dirty |= ST_NEW_FS_STATE;
+ }
+ }
if (new_state & _NEW_PROGRAM_CONSTANTS)
st->dirty |= st->active_states & ST_NEW_CONSTANTS;
diff --git a/src/mesa/state_tracker/st_glsl_to_nir.cpp b/src/mesa/state_tracker/st_glsl_to_nir.cpp
index 5b5fad44f18..f43460ba67a 100644
--- a/src/mesa/state_tracker/st_glsl_to_nir.cpp
+++ b/src/mesa/state_tracker/st_glsl_to_nir.cpp
@@ -423,6 +423,7 @@ st_nir_get_mesa_program(struct gl_context *ctx,
prog->SamplersUsed = shader->active_samplers;
prog->ShadowSamplers = shader->shadow_samplers;
+ prog->ExternalSamplersUsed = gl_external_samplers(shader);
_mesa_update_shader_textures_used(shader_program, prog);
_mesa_reference_program(ctx, &shader->Program, prog);
diff --git a/src/mesa/state_tracker/st_glsl_to_tgsi.cpp b/src/mesa/state_tracker/st_glsl_to_tgsi.cpp
index 507a7826e38..81ea233a8ec 100644
--- a/src/mesa/state_tracker/st_glsl_to_tgsi.cpp
+++ b/src/mesa/state_tracker/st_glsl_to_tgsi.cpp
@@ -4347,6 +4347,10 @@ count_resources(glsl_to_tgsi_visitor *v, gl_program *prog)
}
}
}
+
+ if (inst->tex_target == TEXTURE_EXTERNAL_INDEX)
+ prog->ExternalSamplersUsed |= 1 << inst->sampler.index;
+
if (inst->buffer.file != PROGRAM_UNDEFINED && (
is_resource_instruction(inst->op) ||
inst->op == TGSI_OPCODE_STORE)) {
diff --git a/src/mesa/state_tracker/st_manager.c b/src/mesa/state_tracker/st_manager.c
index e2da054d2a5..fece5d5dffd 100644
--- a/src/mesa/state_tracker/st_manager.c
+++ b/src/mesa/state_tracker/st_manager.c
@@ -845,6 +845,7 @@ st_manager_get_egl_image_surface(struct st_context *st, void *eglimg)
return NULL;
u_surface_default_template(&surf_tmpl, stimg.texture);
+ surf_tmpl.format = stimg.format;
surf_tmpl.u.tex.level = stimg.level;
surf_tmpl.u.tex.first_layer = stimg.layer;
surf_tmpl.u.tex.last_layer = stimg.layer;
diff --git a/src/mesa/state_tracker/st_program.c b/src/mesa/state_tracker/st_program.c
index 2a4edfa7b7a..91887dc27db 100644
--- a/src/mesa/state_tracker/st_program.c
+++ b/src/mesa/state_tracker/st_program.c
@@ -53,6 +53,7 @@
#include "st_cb_bitmap.h"
#include "st_cb_drawpixels.h"
#include "st_context.h"
+#include "st_tgsi_lower_yuv.h"
#include "st_program.h"
#include "st_mesa_to_tgsi.h"
#include "st_atifs_to_tgsi.h"
@@ -1024,8 +1025,23 @@ st_create_fp_variant(struct st_context *st,
NIR_PASS_V(tgsi.ir.nir, nir_lower_drawpixels, &options);
}
+ if (unlikely(key->external.lower_nv12 || key->external.lower_iyuv)) {
+ nir_lower_tex_options options = {0};
+ options.lower_y_uv_external = key->external.lower_nv12;
+ options.lower_y_u_v_external = key->external.lower_iyuv;
+ NIR_PASS_V(tgsi.ir.nir, nir_lower_tex, &options);
+ }
+
st_finalize_nir(st, &stfp->Base.Base, tgsi.ir.nir);
+ if (unlikely(key->external.lower_nv12 || key->external.lower_iyuv)) {
+ /* This pass needs to happen *after* nir_lower_sampler */
+ NIR_PASS_V(tgsi.ir.nir, st_nir_lower_tex_src_plane,
+ ~stfp->Base.Base.SamplersUsed,
+ key->external.lower_nv12,
+ key->external.lower_iyuv);
+ }
+
variant->driver_shader = pipe->create_fs_state(pipe, &tgsi);
variant->key = *key;
@@ -1122,6 +1138,25 @@ st_create_fp_variant(struct st_context *st,
fprintf(stderr, "mesa: cannot create a shader for glDrawPixels\n");
}
+ if (unlikely(key->external.lower_nv12 || key->external.lower_iyuv)) {
+ const struct tgsi_token *tokens;
+
+ /* samplers inserted would conflict, but this should be unpossible: */
+ assert(!(key->bitmap || key->drawpixels));
+
+ tokens = st_tgsi_lower_yuv(tgsi.tokens,
+ ~stfp->Base.Base.SamplersUsed,
+ key->external.lower_nv12,
+ key->external.lower_iyuv);
+ if (tokens) {
+ if (tgsi.tokens != stfp->tgsi.tokens)
+ tgsi_free_tokens(tgsi.tokens);
+ tgsi.tokens = tokens;
+ } else {
+ fprintf(stderr, "mesa: cannot create a shader for samplerExternalOES\n");
+ }
+ }
+
if (ST_DEBUG & DEBUG_TGSI) {
tgsi_dump(tgsi.tokens, 0);
debug_printf("\n");
diff --git a/src/mesa/state_tracker/st_program.h b/src/mesa/state_tracker/st_program.h
index 8e11bf02fa9..ea55d476ff0 100644
--- a/src/mesa/state_tracker/st_program.h
+++ b/src/mesa/state_tracker/st_program.h
@@ -39,6 +39,7 @@
#include "program/program.h"
#include "pipe/p_state.h"
#include "st_context.h"
+#include "st_texture.h"
#include "st_glsl_to_tgsi.h"
@@ -48,6 +49,40 @@ extern "C" {
#define ST_DOUBLE_ATTRIB_PLACEHOLDER 0xffffffff
+struct st_external_sampler_key
+{
+ GLuint lower_nv12; /**< bitmask of 2 plane YUV samplers */
+ GLuint lower_iyuv; /**< bitmask of 3 plane YUV samplers */
+};
+
+static inline struct st_external_sampler_key
+st_get_external_sampler_key(struct st_context *st, struct gl_program *prog)
+{
+ unsigned mask = prog->ExternalSamplersUsed;
+ struct st_external_sampler_key key;
+
+ memset(&key, 0, sizeof(key));
+
+ while (unlikely(mask)) {
+ unsigned unit = u_bit_scan(&mask);
+ struct st_texture_object *stObj =
+ st_get_texture_object(st->ctx, prog, unit);
+
+ switch (st_get_view_format(stObj)) {
+ case PIPE_FORMAT_NV12:
+ key.lower_nv12 |= (1 << unit);
+ break;
+ case PIPE_FORMAT_IYUV:
+ key.lower_iyuv |= (1 << unit);
+ break;
+ default:
+ break;
+ }
+ }
+
+ return key;
+}
+
/** Fragment program variant key */
struct st_fp_variant_key
{
@@ -72,6 +107,8 @@ struct st_fp_variant_key
/** needed for ATI_fragment_shader */
char texture_targets[MAX_NUM_FRAGMENT_REGISTERS_ATI];
+
+ struct st_external_sampler_key external;
};
diff --git a/src/mesa/state_tracker/st_texture.h b/src/mesa/state_tracker/st_texture.h
index b2ddc14ddfc..d2c4f3f880c 100644
--- a/src/mesa/state_tracker/st_texture.h
+++ b/src/mesa/state_tracker/st_texture.h
@@ -170,6 +170,27 @@ st_create_texture_sampler_view(struct pipe_context *pipe,
texture->format);
}
+static inline struct st_texture_object *
+st_get_texture_object(struct gl_context *ctx,
+ const struct gl_program *prog,
+ unsigned unit)
+{
+ const GLuint texUnit = prog->SamplerUnits[unit];
+ struct gl_texture_object *texObj = ctx->Texture.Unit[texUnit]._Current;
+
+ if (!texObj)
+ return NULL;
+
+ return st_texture_object(texObj);
+}
+
+static inline enum pipe_format
+st_get_view_format(struct st_texture_object *stObj)
+{
+ if (!stObj)
+ return PIPE_FORMAT_NONE;
+ return stObj->surface_based ? stObj->surface_format : stObj->pt->format;
+}
extern struct pipe_resource *