[Mesa-dev] [RFC 2/2] mesa/st: support lowering multi-planar YUV
Marek Olšák
maraeo at gmail.com
Mon Sep 5 16:52:09 UTC 2016
On Fri, Sep 2, 2016 at 9:45 PM, Rob Clark <robdclark at gmail.com> wrote:
> 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.
>
> Currently lots of TODO's, only NV12 implemented so far, only wired up in
> frag shader, etc, etc..
> ---
> src/gallium/auxiliary/util/u_inlines.h | 4 +-
> src/gallium/include/pipe/p_state.h | 9 +++
> src/gallium/include/state_tracker/st_api.h | 3 +
> src/gallium/state_trackers/dri/dri2.c | 111 ++++++++++++++++++++++------
> src/gallium/state_trackers/dri/dri_screen.c | 11 +++
> src/mesa/main/mtypes.h | 16 ++++
> src/mesa/program/ir_to_mesa.cpp | 1 +
> src/mesa/state_tracker/st_atom_sampler.c | 52 ++++++++++++-
> src/mesa/state_tracker/st_atom_shader.c | 27 +++++++
> src/mesa/state_tracker/st_atom_texture.c | 71 +++++++++++++++++-
> src/mesa/state_tracker/st_cb_eglimage.c | 18 +++++
> src/mesa/state_tracker/st_context.c | 10 ++-
> src/mesa/state_tracker/st_glsl_to_nir.cpp | 1 +
> src/mesa/state_tracker/st_glsl_to_tgsi.cpp | 4 +
> src/mesa/state_tracker/st_manager.c | 1 +
> src/mesa/state_tracker/st_program.c | 18 +++++
> src/mesa/state_tracker/st_program.h | 3 +
> 17 files changed, 330 insertions(+), 30 deletions(-)
>
> diff --git a/src/gallium/auxiliary/util/u_inlines.h b/src/gallium/auxiliary/util/u_inlines.h
> index c2a0b08..b7b8313 100644
> --- a/src/gallium/auxiliary/util/u_inlines.h
> +++ b/src/gallium/auxiliary/util/u_inlines.h
> @@ -136,8 +136,10 @@ pipe_resource_reference(struct pipe_resource **ptr, struct pipe_resource *tex)
> struct pipe_resource *old_tex = *ptr;
>
> if (pipe_reference_described(&(*ptr)->reference, &tex->reference,
> - (debug_reference_descriptor)debug_describe_resource))
> + (debug_reference_descriptor)debug_describe_resource)) {
> + pipe_resource_reference(&old_tex->next, NULL);
> old_tex->screen->resource_destroy(old_tex->screen, old_tex);
> + }
> *ptr = tex;
> }
>
> diff --git a/src/gallium/include/pipe/p_state.h b/src/gallium/include/pipe/p_state.h
> index ebd0337..4a88da6 100644
> --- a/src/gallium/include/pipe/p_state.h
> +++ b/src/gallium/include/pipe/p_state.h
> @@ -498,6 +498,15 @@ struct pipe_resource
>
> unsigned bind; /**< bitmask of PIPE_BIND_x */
> unsigned flags; /**< bitmask of PIPE_RESOURCE_FLAG_x */
> +
> + /**
> + * For planar images, ie. YUV EGLImage external, etc, pointer to the
> + * next plane.
> + *
> + * TODO might be useful for dealing w/ z32s8 too, since at least a
> + * couple drivers split these out into separate buffers internally.
> + */
> + struct pipe_resource *next;
I'm not a fan of this but I don't have a better idea.
> };
>
>
> diff --git a/src/gallium/include/state_tracker/st_api.h b/src/gallium/include/state_tracker/st_api.h
> index 21d5177..06abfc5 100644
> --- a/src/gallium/include/state_tracker/st_api.h
> +++ b/src/gallium/include/state_tracker/st_api.h
> @@ -200,6 +200,9 @@ struct st_egl_image
> /* this is owned by the caller */
> struct pipe_resource *texture;
>
> + /* format only differs from texture->format for multi-planar (YUV): */
> + enum pipe_format format;
> +
> unsigned level;
> unsigned layer;
> };
> diff --git a/src/gallium/state_trackers/dri/dri2.c b/src/gallium/state_trackers/dri/dri2.c
> index fdab499..91eabc8 100644
> --- a/src/gallium/state_trackers/dri/dri2.c
> +++ b/src/gallium/state_trackers/dri/dri2.c
> @@ -83,6 +83,20 @@ static int convert_fourcc(int format, int *dri_components_p)
> format = __DRI_IMAGE_FORMAT_GR88;
> dri_components = __DRI_IMAGE_COMPONENTS_RG;
> break;
> + /*
> + * For multi-planar YUV formats, we return the format of the first
> + * plane only. Since there is only one caller which supports multi-
> + * planar YUV it gets to figure out the remaining planes on it's
> + * own.
> + */
> + case __DRI_IMAGE_FOURCC_YUV420:
> + format = __DRI_IMAGE_FORMAT_R8;
> + dri_components = __DRI_IMAGE_COMPONENTS_Y_U_V;
> + break;
> + case __DRI_IMAGE_FOURCC_NV12:
> + format = __DRI_IMAGE_FORMAT_R8;
> + dri_components = __DRI_IMAGE_COMPONENTS_Y_UV;
> + break;
> default:
> return -1;
> }
> @@ -90,6 +104,11 @@ static int convert_fourcc(int format, int *dri_components_p)
> return format;
> }
>
> +/* NOTE this probably isn't going to do the right thing for YUV images
> + * (but I think the same can be said for intel_query_image()). I think
> + * only needed for exporting dmabuf's, so I think I won't loose much
> + * sleep over it.
> + */
> static int convert_to_fourcc(int format)
> {
> switch(format) {
> @@ -762,14 +781,16 @@ dri2_lookup_egl_image(struct dri_screen *screen, void *handle)
> static __DRIimage *
> dri2_create_image_from_winsys(__DRIscreen *_screen,
> int width, int height, int format,
> - struct winsys_handle *whandle,
> + int num_handles, struct winsys_handle *whandle,
> void *loaderPrivate)
> {
> struct dri_screen *screen = dri_screen(_screen);
> + struct pipe_screen *pscreen = screen->base.screen;
> __DRIimage *img;
> struct pipe_resource templ;
> unsigned tex_usage;
> enum pipe_format pf;
> + int i;
>
> tex_usage = PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW;
>
> @@ -783,19 +804,47 @@ dri2_create_image_from_winsys(__DRIscreen *_screen,
>
> memset(&templ, 0, sizeof(templ));
> templ.bind = tex_usage;
> - templ.format = pf;
> templ.target = screen->target;
> templ.last_level = 0;
> - templ.width0 = width;
> - templ.height0 = height;
> templ.depth0 = 1;
> templ.array_size = 1;
>
> - img->texture = screen->base.screen->resource_from_handle(screen->base.screen,
> - &templ, whandle, PIPE_HANDLE_USAGE_READ_WRITE);
> - if (!img->texture) {
> - FREE(img);
> - return NULL;
> + for (i = num_handles - 1; i >= 0; i--) {
> + struct pipe_resource *tex;
> +
> + /* TODO: something a lot less ugly */
> + switch (i) {
> + case 0:
> + templ.width0 = width;
> + templ.height0 = height;
> + templ.format = pf;
> + break;
> + case 1:
> + templ.width0 = width / 2;
> + templ.height0 = height / 2;
> + templ.format = (num_handles == 2) ?
> + PIPE_FORMAT_RG88_UNORM : /* NV12, etc */
> + PIPE_FORMAT_R8_UNORM; /* I420, etc */
> + break;
> + case 2:
> + templ.width0 = width / 2;
> + templ.height0 = height / 2;
> + templ.format = PIPE_FORMAT_R8_UNORM;
> + break;
> + default:
> + unreachable("too many planes!");
> + }
> +
> + tex = pscreen->resource_from_handle(pscreen,
> + &templ, &whandle[i], PIPE_HANDLE_USAGE_READ_WRITE);
> + if (!tex) {
> + pipe_resource_reference(&img->texture, NULL);
> + FREE(img);
> + return NULL;
> + }
> +
> + tex->next = img->texture;
> + img->texture = tex;
> }
>
> img->level = 0;
> @@ -826,7 +875,7 @@ dri2_create_image_from_name(__DRIscreen *_screen,
> whandle.stride = pitch * util_format_get_blocksize(pf);
>
> return dri2_create_image_from_winsys(_screen, width, height, format,
> - &whandle, loaderPrivate);
> + 1, &whandle, loaderPrivate);
> }
>
> static __DRIimage *
> @@ -836,12 +885,25 @@ dri2_create_image_from_fd(__DRIscreen *_screen,
> int *offsets, unsigned *error,
> int *dri_components, void *loaderPrivate)
> {
> - struct winsys_handle whandle;
> + struct winsys_handle whandles[3];
> int format;
> __DRIimage *img = NULL;
> unsigned err = __DRI_IMAGE_ERROR_SUCCESS;
> + int expected_num_fds, i;
>
> - if (num_fds != 1) {
> + switch (fourcc) {
> + case __DRI_IMAGE_FOURCC_YUV420:
> + expected_num_fds = 3;
> + break;
> + case __DRI_IMAGE_FOURCC_NV12:
> + expected_num_fds = 2;
> + break;
> + default:
> + expected_num_fds = 1;
> + break;
> + }
> +
> + if (num_fds != expected_num_fds) {
> err = __DRI_IMAGE_ERROR_BAD_MATCH;
> goto exit;
> }
> @@ -852,19 +914,22 @@ dri2_create_image_from_fd(__DRIscreen *_screen,
> goto exit;
> }
>
> - if (fds[0] < 0) {
> - err = __DRI_IMAGE_ERROR_BAD_ALLOC;
> - goto exit;
> - }
> + memset(whandles, 0, sizeof(whandles));
>
> - memset(&whandle, 0, sizeof(whandle));
> - whandle.type = DRM_API_HANDLE_TYPE_FD;
> - whandle.handle = (unsigned)fds[0];
> - whandle.stride = (unsigned)strides[0];
> - whandle.offset = (unsigned)offsets[0];
> + for (i = 0; i < num_fds; i++) {
> + if (fds[i] < 0) {
> + err = __DRI_IMAGE_ERROR_BAD_ALLOC;
> + goto exit;
> + }
> +
> + whandles[i].type = DRM_API_HANDLE_TYPE_FD;
> + whandles[i].handle = (unsigned)fds[i];
> + whandles[i].stride = (unsigned)strides[i];
> + whandles[i].offset = (unsigned)offsets[i];
> + }
>
> img = dri2_create_image_from_winsys(_screen, width, height, format,
> - &whandle, loaderPrivate);
> + num_fds, whandles, loaderPrivate);
> if(img == NULL)
> err = __DRI_IMAGE_ERROR_BAD_ALLOC;
>
> @@ -1067,7 +1132,7 @@ dri2_from_names(__DRIscreen *screen, int width, int height, int format,
> whandle.offset = offsets[0];
>
> img = dri2_create_image_from_winsys(screen, width, height, format,
> - &whandle, loaderPrivate);
> + 1, &whandle, loaderPrivate);
> if (img == NULL)
> return NULL;
>
> diff --git a/src/gallium/state_trackers/dri/dri_screen.c b/src/gallium/state_trackers/dri/dri_screen.c
> index 79bcb5a..aa0ad09 100644
> --- a/src/gallium/state_trackers/dri/dri_screen.c
> +++ b/src/gallium/state_trackers/dri/dri_screen.c
> @@ -334,6 +334,17 @@ dri_get_egl_image(struct st_manager *smapi,
>
> stimg->texture = NULL;
> pipe_resource_reference(&stimg->texture, img->texture);
> + switch (img->dri_components) {
> + case __DRI_IMAGE_COMPONENTS_Y_U_V:
> + stimg->format = PIPE_FORMAT_IYUV;
> + break;
> + case __DRI_IMAGE_COMPONENTS_Y_UV:
> + stimg->format = PIPE_FORMAT_NV12;
> + break;
> + default:
> + stimg->format = img->texture->format;
> + break;
> + }
> stimg->level = img->level;
> stimg->layer = img->layer;
>
> diff --git a/src/mesa/main/mtypes.h b/src/mesa/main/mtypes.h
> index 4013ca7..4500376 100644
> --- a/src/mesa/main/mtypes.h
> +++ b/src/mesa/main/mtypes.h
> @@ -45,6 +45,7 @@
> #include "compiler/shader_enums.h"
> #include "main/formats.h" /* MESA_FORMAT_COUNT */
> #include "compiler/glsl/list.h"
> +#include "util/bitscan.h"
>
>
> #ifdef __cplusplus
> @@ -1926,6 +1927,7 @@ struct gl_program
> GLbitfield TexturesUsed[MAX_COMBINED_TEXTURE_IMAGE_UNITS]; /**< TEXTURE_x_BIT bitmask */
> GLbitfield SamplersUsed; /**< Bitfield of which samplers are used */
> GLbitfield ShadowSamplers; /**< Texture units used for shadow sampling. */
> + GLbitfield ExternalSamplersUsed; /**< Texture units used for samplerExternalOES */
>
> GLboolean UsesGather; /**< Does this program use gather4 at all? */
>
> @@ -2457,6 +2459,20 @@ struct gl_linked_shader
> struct gl_shader_info info;
> };
>
> +static inline GLbitfield gl_external_samplers(struct gl_linked_shader *shader)
> +{
> + GLbitfield external_samplers = 0;
> + GLbitfield mask = shader->active_samplers;
> +
> + while (mask) {
> + int idx = u_bit_scan(&mask);
> + if (shader->SamplerTargets[idx] == TEXTURE_EXTERNAL_INDEX)
> + external_samplers |= (1 << idx);
> + }
> +
> + return external_samplers;
> +}
> +
> /**
> * A GLSL shader object.
> */
> diff --git a/src/mesa/program/ir_to_mesa.cpp b/src/mesa/program/ir_to_mesa.cpp
> index e74d94f..9b6b5e8 100644
> --- a/src/mesa/program/ir_to_mesa.cpp
> +++ b/src/mesa/program/ir_to_mesa.cpp
> @@ -2921,6 +2921,7 @@ 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);
>
> /* Set the gl_FragDepth layout. */
> diff --git a/src/mesa/state_tracker/st_atom_sampler.c b/src/mesa/state_tracker/st_atom_sampler.c
> index 6b36ac7..ffdec08 100644
> --- a/src/mesa/state_tracker/st_atom_sampler.c
> +++ b/src/mesa/state_tracker/st_atom_sampler.c
> @@ -243,13 +243,12 @@ update_shader_samplers(struct st_context *st,
> struct pipe_sampler_state *samplers,
> unsigned *num_samplers)
> {
> - GLuint unit;
> - GLbitfield samplers_used;
> + GLbitfield samplers_used = prog->SamplersUsed;
> + GLbitfield external_samplers_used = prog->ExternalSamplersUsed;
> + GLuint unit, last_used = 0;
> 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;
>
> @@ -264,6 +263,7 @@ update_shader_samplers(struct st_context *st,
>
> convert_sampler(st, sampler, texUnit);
> states[unit] = sampler;
> + last_used = unit;
> *num_samplers = unit + 1;
> }
> else if (samplers_used != 0 || unit < old_max) {
> @@ -275,6 +275,50 @@ 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)) {
> + struct gl_context *ctx = st->ctx;
> + GLuint unit = u_bit_scan(&external_samplers_used);
> + const GLuint texUnit = prog->SamplerUnits[unit];
> + struct gl_texture_object *texObj = ctx->Texture.Unit[texUnit]._Current;
> + struct st_texture_object *stObj = st_texture_object(texObj);
> + struct pipe_sampler_state *sampler = samplers + unit;
> + enum pipe_format view_format;
> +
> + if (!texObj)
> + continue;
> +
> + view_format =
> + stObj->surface_based ? stObj->surface_format : stObj->pt->format;
> +
> + switch (view_format) {
> + case PIPE_FORMAT_NV12:
> + /* we need one additional sampler: */
> + states[++last_used] = sampler;
> + break;
> + case PIPE_FORMAT_IYUV:
> + /* we need two additional samplers: */
> + states[++last_used] = sampler;
> + states[++last_used] = sampler;
> + break;
> + default:
> + break;
> + }
> +
> + /* TODO The OES_EGL_image_external spec allows YUV external images to
> + * consume multiple sampler slots (and even provides a way to query
> + * this).. but we should fail w/ a gl error somewhere sooner if the
> + * user exceeds this..
> + */
> + assert(last_used < PIPE_MAX_SAMPLERS);
> + }
> +
> + *num_samplers = MAX2(*num_samplers, last_used + 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 7a23469..154069d 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,32 @@ update_fp( struct st_context *st )
> }
> }
>
> + if (unlikely(stfp->Base.Base.ExternalSamplersUsed)) {
> + struct gl_context *ctx = st->ctx;
> + unsigned mask = stfp->Base.Base.ExternalSamplersUsed;
> + while (mask) {
> + unsigned unit = u_bit_scan(&mask);
> + unsigned texUnit = stfp->Base.Base.SamplerUnits[unit];
> + struct gl_texture_object *texObj = ctx->Texture.Unit[texUnit]._Current;
> + struct st_texture_object *stObj = st_texture_object(texObj);
> + enum pipe_format view_format;
> +
> + view_format =
> + stObj->surface_based ? stObj->surface_format : stObj->pt->format;
> +
> + switch (view_format) {
> + case PIPE_FORMAT_NV12:
> + key.lower_nv12 |= (1 << unit);
> + break;
> + case PIPE_FORMAT_IYUV:
> + key.lower_iyuv |= (1 << unit);
> + break;
> + default:
> + break;
> + }
> + }
> + }
> +
> 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 b647117..909e724 100644
> --- a/src/mesa/state_tracker/st_atom_texture.c
> +++ b/src/mesa/state_tracker/st_atom_texture.c
> @@ -405,6 +405,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);
> @@ -423,7 +432,8 @@ update_textures(struct st_context *st,
> {
> const GLuint old_max = *num_textures;
> GLbitfield samplers_used = prog->SamplersUsed;
> - GLuint unit;
> + GLbitfield external_samplers_used = prog->ExternalSamplersUsed;
> + GLuint unit, last_used = 0;
> struct gl_shader_program *shader =
> st->ctx->_Shader->CurrentProgram[mesa_shader];
> unsigned glsl_version = shader ? shader->Version : 0;
> @@ -454,9 +464,68 @@ update_textures(struct st_context *st,
> break;
> }
>
> + if (sampler_view)
> + last_used = unit;
> +
> 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)) {
> + struct gl_context *ctx = st->ctx;
> + GLuint unit = u_bit_scan(&external_samplers_used);
> + const GLuint texUnit = prog->SamplerUnits[unit];
> + struct gl_texture_object *texObj = ctx->Texture.Unit[texUnit]._Current;
> + struct st_texture_object *stObj = st_texture_object(texObj);
> + enum pipe_format view_format;
> + struct pipe_sampler_view tmpl;
> +
> + if (!texObj)
> + continue;
> +
> + /* use original view as template: */
> + tmpl = *sampler_views[unit];
> +
> + view_format =
> + stObj->surface_based ? stObj->surface_format : stObj->pt->format;
> +
> + switch (view_format) {
> + 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 */
> + sampler_views[++last_used] =
> + 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;
> + sampler_views[++last_used] =
> + st->pipe->create_sampler_view(st->pipe, stObj->pt->next, &tmpl);
> + sampler_views[++last_used] =
> + st->pipe->create_sampler_view(st->pipe, stObj->pt->next->next, &tmpl);
> + break;
> + default:
> + break;
> + }
> +
> + /* TODO The OES_EGL_image_external spec allows YUV external images to
> + * consume multiple sampler slots (and even provides a way to query
> + * this).. but we should fail w/ a gl error somewhere sooner if the
> + * user exceeds this..
> + */
> + assert(last_used < PIPE_MAX_SAMPLERS);
> + }
> +
> + *num_textures = MAX2(*num_textures, last_used + 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 1782d15..7bea565 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 ddc11a4..0e3b491 100644
> --- a/src/mesa/state_tracker/st_context.c
> +++ b/src/mesa/state_tracker/st_context.c
> @@ -254,11 +254,19 @@ 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);
> + // TODO we need to do this for all shader stages
> + if (st->fp && st->fp->Base.Base.ExternalSamplersUsed) {
> + /* TODO check if external imgs have actually changed # of
> + * samplers used (ie. between RGB / 2-plane YUV / 3-plane YUV)
> + */
> + st->dirty |= ST_NEW_FS_STATE;
> + }
You don't want to use st->fp here, because it comes from the previous
draw call, not the current state. ctx->FragmentProgram._Current is the
correct variable here.
> + }
>
> 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 307bf3e..ac9cc9d 100644
> --- a/src/mesa/state_tracker/st_glsl_to_nir.cpp
> +++ b/src/mesa/state_tracker/st_glsl_to_nir.cpp
> @@ -422,6 +422,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 b7e47db..3f1f8fc 100644
> --- a/src/mesa/state_tracker/st_glsl_to_tgsi.cpp
> +++ b/src/mesa/state_tracker/st_glsl_to_tgsi.cpp
> @@ -4346,6 +4346,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 e2da054..fece5d5 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 03a685c..e6b1017 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"
> @@ -1020,6 +1021,10 @@ st_create_fp_variant(struct st_context *st,
> NIR_PASS_V(tgsi.ir.nir, nir_lower_drawpixels, &options);
> }
>
> + if (unlikely(key->lower_nv12 || key->lower_iyuv)) {
> + assert(0); // TODO
> + }
> +
> st_finalize_nir(st, &stfp->Base.Base, tgsi.ir.nir);
>
> variant->driver_shader = pipe->create_fs_state(pipe, &tgsi);
Did you forget to drop this hunk?
> @@ -1118,6 +1123,19 @@ st_create_fp_variant(struct st_context *st,
> fprintf(stderr, "mesa: cannot create a shader for glDrawPixels\n");
> }
>
> + if (unlikely(key->lower_nv12 || key->lower_iyuv)) {
> + const struct tgsi_token *tokens;
> + unsigned first_extra_sampler = ffs(~stfp->Base.Base.SamplersUsed) - 1;
> +
> + /* samplers inserted would conflict, but this should be unpossible: */
> + assert(!(key->bitmap || key->drawpixels));
> +
> + tokens = st_tgsi_lower_yuv(tgsi.tokens, first_extra_sampler,
> + key->lower_nv12, key->lower_iyuv);
> + tgsi_free_tokens(tgsi.tokens);
> + tgsi.tokens = tokens;
> + }
What if SamplersUsed has holes, e.g. SamplersUsed = 1011011b.
Marek
More information about the mesa-dev
mailing list