X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fmesa%2Fstate_tracker%2Fst_atom_texture.c;h=5a0f91ccb1403ee50a90cc3c88775034e9abe17b;hb=5f1a16d06d8b2cf6942b1e4b250842ec0be2c8a4;hp=f27a320a5bcfdce29cd404272c475b2b4af1820b;hpb=b549fd138eab508c5e942ec1807a9bac7e6af56f;p=mesa.git diff --git a/src/mesa/state_tracker/st_atom_texture.c b/src/mesa/state_tracker/st_atom_texture.c index f27a320a5bc..5a0f91ccb14 100644 --- a/src/mesa/state_tracker/st_atom_texture.c +++ b/src/mesa/state_tracker/st_atom_texture.c @@ -1,6 +1,6 @@ /************************************************************************** * - * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * Copyright 2007 VMware, Inc. * All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a @@ -18,7 +18,7 @@ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. - * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -27,374 +27,309 @@ /* * Authors: - * Keith Whitwell + * Keith Whitwell * Brian Paul */ +#include "main/context.h" #include "main/macros.h" #include "main/mtypes.h" #include "main/samplerobj.h" +#include "main/teximage.h" #include "main/texobj.h" #include "program/prog_instruction.h" #include "st_context.h" #include "st_atom.h" +#include "st_sampler_view.h" #include "st_texture.h" #include "st_format.h" #include "st_cb_texture.h" #include "pipe/p_context.h" -#include "util/u_format.h" +#include "util/format/u_format.h" #include "util/u_inlines.h" #include "cso_cache/cso_context.h" /** - * Combine depth texture mode with "swizzle" so that depth mode swizzling - * takes place before texture swizzling, and return the resulting swizzle. - * If the format is not a depth format, return "swizzle" unchanged. - * - * \param format PIPE_FORMAT_*. - * \param swizzle Texture swizzle, a bitmask computed using MAKE_SWIZZLE4. - * \param depthmode One of GL_LUMINANCE, GL_INTENSITY, GL_ALPHA, GL_RED. + * Get a pipe_sampler_view object from a texture unit. */ -static GLuint -apply_depthmode(enum pipe_format format, GLuint swizzle, GLenum depthmode) +void +st_update_single_texture(struct st_context *st, + struct pipe_sampler_view **sampler_view, + GLuint texUnit, bool glsl130_or_later, + bool ignore_srgb_decode) { - const struct util_format_description *desc = - util_format_description(format); - unsigned char swiz[4]; - unsigned i; - - if (desc->colorspace != UTIL_FORMAT_COLORSPACE_ZS || - desc->swizzle[0] == UTIL_FORMAT_SWIZZLE_NONE) { - /* Not a depth format. */ - return swizzle; - } - - for (i = 0; i < 4; i++) - swiz[i] = GET_SWZ(swizzle, i); - - switch (depthmode) { - case GL_LUMINANCE: - /* Rewrite reads from W to ONE, and reads from XYZ to XXX. */ - for (i = 0; i < 4; i++) - if (swiz[i] == SWIZZLE_W) - swiz[i] = SWIZZLE_ONE; - else if (swiz[i] < SWIZZLE_W) - swiz[i] = SWIZZLE_X; - break; - - case GL_INTENSITY: - /* Rewrite reads from XYZW to XXXX. */ - for (i = 0; i < 4; i++) - if (swiz[i] <= SWIZZLE_W) - swiz[i] = SWIZZLE_X; - break; - - case GL_ALPHA: - /* Rewrite reads from W to X, and reads from XYZ to 000. */ - for (i = 0; i < 4; i++) - if (swiz[i] == SWIZZLE_W) - swiz[i] = SWIZZLE_X; - else if (swiz[i] < SWIZZLE_W) - swiz[i] = SWIZZLE_ZERO; - break; - case GL_RED: - /* Rewrite reads W to 1, XYZ to X00 */ - for (i = 0; i < 4; i++) - if (swiz[i] == SWIZZLE_W) - swiz[i] = SWIZZLE_ONE; - else if (swiz[i] == SWIZZLE_Y || swiz[i] == SWIZZLE_Z) - swiz[i] = SWIZZLE_ZERO; - break; - } - - return MAKE_SWIZZLE4(swiz[0], swiz[1], swiz[2], swiz[3]); -} - - -/** - * Return TRUE if the swizzling described by "swizzle" and - * "depthmode" (for depth textures only) is different from the swizzling - * set in the given sampler view. - * - * \param sv A sampler view. - * \param swizzle Texture swizzle, a bitmask computed using MAKE_SWIZZLE4. - * \param depthmode One of GL_LUMINANCE, GL_INTENSITY, GL_ALPHA. - */ -static boolean -check_sampler_swizzle(struct pipe_sampler_view *sv, - GLuint swizzle, GLenum depthmode) -{ - swizzle = apply_depthmode(sv->texture->format, swizzle, depthmode); - - if ((sv->swizzle_r != GET_SWZ(swizzle, 0)) || - (sv->swizzle_g != GET_SWZ(swizzle, 1)) || - (sv->swizzle_b != GET_SWZ(swizzle, 2)) || - (sv->swizzle_a != GET_SWZ(swizzle, 3))) - return TRUE; - return FALSE; -} - - -static struct pipe_sampler_view * -st_create_texture_sampler_view_from_stobj(struct pipe_context *pipe, - struct st_texture_object *stObj, - const struct gl_sampler_object *samp, - enum pipe_format format) -{ - struct pipe_sampler_view templ; - GLuint swizzle = apply_depthmode(stObj->pt->format, - stObj->base._Swizzle, - samp->DepthMode); - - u_sampler_view_default_template(&templ, - stObj->pt, - format); - templ.u.tex.first_level = stObj->base.BaseLevel; - - if (swizzle != SWIZZLE_NOOP) { - templ.swizzle_r = GET_SWZ(swizzle, 0); - templ.swizzle_g = GET_SWZ(swizzle, 1); - templ.swizzle_b = GET_SWZ(swizzle, 2); - templ.swizzle_a = GET_SWZ(swizzle, 3); - } - - return pipe->create_sampler_view(pipe, stObj->pt, &templ); -} - - -static struct pipe_sampler_view * -st_get_texture_sampler_view_from_stobj(struct st_texture_object *stObj, - struct pipe_context *pipe, - const struct gl_sampler_object *samp, - enum pipe_format format) -{ - if (!stObj || !stObj->pt) { - return NULL; - } - - if (!stObj->sampler_view) { - stObj->sampler_view = - st_create_texture_sampler_view_from_stobj(pipe, stObj, samp, format); - } - - return stObj->sampler_view; -} - - -static GLboolean -update_single_texture(struct st_context *st, - struct pipe_sampler_view **sampler_view, - GLuint texUnit) -{ - struct pipe_context *pipe = st->pipe; struct gl_context *ctx = st->ctx; const struct gl_sampler_object *samp; struct gl_texture_object *texObj; struct st_texture_object *stObj; - enum pipe_format st_view_format; - GLboolean retval; samp = _mesa_get_samplerobj(ctx, texUnit); texObj = ctx->Texture.Unit[texUnit]._Current; + assert(texObj); - if (!texObj) { - texObj = _mesa_get_fallback_texture(ctx, TEXTURE_2D_INDEX); - samp = &texObj->Sampler; - } stObj = st_texture_object(texObj); - retval = st_finalize_texture(ctx, st->pipe, texObj); - if (!retval) { - /* out of mem */ - return GL_FALSE; + if (unlikely(texObj->Target == GL_TEXTURE_BUFFER)) { + *sampler_view = st_get_buffer_sampler_view_from_stobj(st, stObj); + return; } - /* Determine the format of the texture sampler view */ - st_view_format = stObj->pt->format; - { - const struct st_texture_image *firstImage = - st_texture_image(stObj->base.Image[0][stObj->base.BaseLevel]); - const gl_format texFormat = firstImage->base.TexFormat; - enum pipe_format firstImageFormat = - st_mesa_format_to_pipe_format(texFormat); - - if ((samp->sRGBDecode == GL_SKIP_DECODE_EXT) && - (_mesa_get_format_color_encoding(texFormat) == GL_SRGB)) { - /* Don't do sRGB->RGB conversion. Interpret the texture data as - * linear values. - */ - const gl_format linearFormat = - _mesa_get_srgb_format_linear(texFormat); - firstImageFormat = st_mesa_format_to_pipe_format(linearFormat); - } - - if (firstImageFormat != stObj->pt->format) - st_view_format = firstImageFormat; + if (!st_finalize_texture(ctx, st->pipe, texObj, 0) || + !stObj->pt) { + /* out of mem */ + *sampler_view = NULL; + return; } - /* if sampler view has changed dereference it */ - if (stObj->sampler_view) { - if (check_sampler_swizzle(stObj->sampler_view, - stObj->base._Swizzle, - samp->DepthMode) || - (st_view_format != stObj->sampler_view->format) || - stObj->base.BaseLevel != stObj->sampler_view->u.tex.first_level) { - pipe_sampler_view_reference(&stObj->sampler_view, NULL); - } - } + if (texObj->TargetIndex == TEXTURE_EXTERNAL_INDEX && + stObj->pt->screen->resource_changed) + stObj->pt->screen->resource_changed(stObj->pt->screen, stObj->pt); - *sampler_view = st_get_texture_sampler_view_from_stobj(stObj, pipe, - samp, - st_view_format); - return GL_TRUE; + *sampler_view = + st_get_texture_sampler_view_from_stobj(st, stObj, samp, + glsl130_or_later, + ignore_srgb_decode); } + static void -update_vertex_textures(struct st_context *st) +update_textures(struct st_context *st, + enum pipe_shader_type shader_stage, + const struct gl_program *prog, + struct pipe_sampler_view **sampler_views) { - const struct gl_context *ctx = st->ctx; - struct gl_vertex_program *vprog = ctx->VertexProgram._Current; - GLuint su; - - if (!vprog->Base.SamplersUsed && st->state.num_vertex_textures == 0) + const GLuint old_max = st->state.num_sampler_views[shader_stage]; + GLbitfield samplers_used = prog->SamplersUsed; + GLbitfield texel_fetch_samplers = prog->info.textures_used_by_txf; + GLbitfield free_slots = ~prog->SamplersUsed; + GLbitfield external_samplers_used = prog->ExternalSamplersUsed; + GLuint unit; + + if (samplers_used == 0x0 && old_max == 0) return; - st->state.num_vertex_textures = 0; + unsigned num_textures = 0; + + /* prog->sh.data is NULL if it's ARB_fragment_program */ + bool glsl130 = (prog->sh.data ? prog->sh.data->Version : 0) >= 130; /* loop over sampler units (aka tex image units) */ - for (su = 0; su < ctx->Const.MaxTextureImageUnits; su++) { + for (unit = 0; samplers_used || unit < old_max; + unit++, samplers_used >>= 1, texel_fetch_samplers >>= 1) { struct pipe_sampler_view *sampler_view = NULL; - if (vprog->Base.SamplersUsed & (1 << su)) { - GLboolean retval; - GLuint texUnit; - texUnit = vprog->Base.SamplerUnits[su]; + if (samplers_used & 1) { + const GLuint texUnit = prog->SamplerUnits[unit]; + + /* The EXT_texture_sRGB_decode extension says: + * + * "The conversion of sRGB color space components to linear color + * space is always performed if the texel lookup function is one + * of the texelFetch builtin functions. + * + * Otherwise, if the texel lookup function is one of the texture + * builtin functions or one of the texture gather functions, the + * conversion of sRGB color space components to linear color space + * is controlled by the TEXTURE_SRGB_DECODE_EXT parameter. + * + * If the TEXTURE_SRGB_DECODE_EXT parameter is DECODE_EXT, the + * conversion of sRGB color space components to linear color space + * is performed. + * + * If the TEXTURE_SRGB_DECODE_EXT parameter is SKIP_DECODE_EXT, + * the value is returned without decoding. However, if the texture + * is also [statically] accessed with a texelFetch function, then + * the result of texture builtin functions and/or texture gather + * functions may be returned with decoding or without decoding." + * + * Note: the "statically" will be added to the language per + * https://cvs.khronos.org/bugzilla/show_bug.cgi?id=14934 + * + * So we simply ignore the setting entirely for samplers that are + * (statically) accessed with a texelFetch function. + */ + st_update_single_texture(st, &sampler_view, texUnit, glsl130, + texel_fetch_samplers & 1); + num_textures = unit + 1; + } - retval = update_single_texture(st, &sampler_view, texUnit); - if (retval == GL_FALSE) - continue; + pipe_sampler_view_reference(&(sampler_views[unit]), sampler_view); + } - st->state.num_vertex_textures = su + 1; + /* 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]; + + /* if resource format matches then YUV wasn't lowered */ + if (st_get_view_format(stObj) == stObj->pt->format) + continue; + + 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_P010: + case PIPE_FORMAT_P016: + /* we need one additional R16G16 view: */ + tmpl.format = PIPE_FORMAT_RG1616_UNORM; + tmpl.swizzle_g = PIPE_SWIZZLE_Y; /* tmpl from Y plane is R16 */ + 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; + case PIPE_FORMAT_YUYV: + /* we need one additional BGRA8888 view: */ + tmpl.format = PIPE_FORMAT_BGRA8888_UNORM; + tmpl.swizzle_b = PIPE_SWIZZLE_Z; + tmpl.swizzle_a = PIPE_SWIZZLE_W; + extra = u_bit_scan(&free_slots); + sampler_views[extra] = + st->pipe->create_sampler_view(st->pipe, stObj->pt->next, &tmpl); + break; + case PIPE_FORMAT_UYVY: + /* we need one additional RGBA8888 view: */ + tmpl.format = PIPE_FORMAT_RGBA8888_UNORM; + tmpl.swizzle_b = PIPE_SWIZZLE_Z; + tmpl.swizzle_a = PIPE_SWIZZLE_W; + extra = u_bit_scan(&free_slots); + sampler_views[extra] = + st->pipe->create_sampler_view(st->pipe, stObj->pt->next, &tmpl); + break; + default: + break; } - pipe_sampler_view_reference(&st->state.sampler_vertex_views[su], - sampler_view); - } - if (ctx->Const.MaxVertexTextureImageUnits > 0) { - GLuint numUnits = MIN2(st->state.num_vertex_textures, - ctx->Const.MaxVertexTextureImageUnits); - cso_set_vertex_sampler_views(st->cso_context, - numUnits, - st->state.sampler_vertex_views); + num_textures = MAX2(num_textures, extra + 1); } -} + cso_set_sampler_views(st->cso_context, + shader_stage, + num_textures, + sampler_views); + st->state.num_sampler_views[shader_stage] = num_textures; +} +/* Same as update_textures, but don't store the views in st_context. */ static void -update_fragment_textures(struct st_context *st) +update_textures_local(struct st_context *st, + enum pipe_shader_type shader_stage, + const struct gl_program *prog) { - const struct gl_context *ctx = st->ctx; - struct gl_fragment_program *fprog = ctx->FragmentProgram._Current; - GLuint su; - int old_max = st->state.num_textures; - GLbitfield samplers_used = fprog->Base.SamplersUsed; - - st->state.num_textures = 0; + struct pipe_sampler_view *local_views[PIPE_MAX_SAMPLERS] = {0}; - /* loop over sampler units (aka tex image units) */ - for (su = 0; su < ctx->Const.MaxTextureImageUnits; su++, samplers_used >>= 1) { - struct pipe_sampler_view *sampler_view = NULL; + update_textures(st, shader_stage, prog, local_views); - if (samplers_used & 1) { - GLboolean retval; - GLuint texUnit; + unsigned num = st->state.num_sampler_views[shader_stage]; + for (unsigned i = 0; i < num; i++) + pipe_sampler_view_reference(&local_views[i], NULL); +} - texUnit = fprog->Base.SamplerUnits[su]; +void +st_update_vertex_textures(struct st_context *st) +{ + const struct gl_context *ctx = st->ctx; - retval = update_single_texture(st, &sampler_view, texUnit); - if (retval == GL_FALSE) - continue; + if (ctx->Const.Program[MESA_SHADER_VERTEX].MaxTextureImageUnits > 0) { + update_textures(st, + PIPE_SHADER_VERTEX, + ctx->VertexProgram._Current, + st->state.vert_sampler_views); + } +} - st->state.num_textures = su + 1; - } else if (samplers_used == 0 && su >= old_max) { - /* if we've reset all the old views and we have no more new ones */ - break; - } - pipe_sampler_view_reference(&st->state.sampler_views[su], sampler_view); - } +void +st_update_fragment_textures(struct st_context *st) +{ + const struct gl_context *ctx = st->ctx; - cso_set_fragment_sampler_views(st->cso_context, - st->state.num_textures, - st->state.sampler_views); + update_textures(st, + PIPE_SHADER_FRAGMENT, + ctx->FragmentProgram._Current, + st->state.frag_sampler_views); } -const struct st_tracked_state st_update_texture = { - "st_update_texture", /* name */ - { /* dirty */ - _NEW_TEXTURE, /* mesa */ - ST_NEW_FRAGMENT_PROGRAM, /* st */ - }, - update_fragment_textures /* update */ -}; +void +st_update_geometry_textures(struct st_context *st) +{ + const struct gl_context *ctx = st->ctx; + + if (ctx->GeometryProgram._Current) { + update_textures_local(st, PIPE_SHADER_GEOMETRY, + ctx->GeometryProgram._Current); + } +} -const struct st_tracked_state st_update_vertex_texture = { - "st_update_vertex_texture", /* name */ - { /* dirty */ - _NEW_TEXTURE, /* mesa */ - ST_NEW_VERTEX_PROGRAM, /* st */ - }, - update_vertex_textures /* update */ -}; +void +st_update_tessctrl_textures(struct st_context *st) +{ + const struct gl_context *ctx = st->ctx; + if (ctx->TessCtrlProgram._Current) { + update_textures_local(st, PIPE_SHADER_TESS_CTRL, + ctx->TessCtrlProgram._Current); + } +} -static void -finalize_textures(struct st_context *st) +void +st_update_tesseval_textures(struct st_context *st) { - struct gl_context *ctx = st->ctx; - struct gl_fragment_program *fprog = ctx->FragmentProgram._Current; - const GLboolean prev_missing_textures = st->missing_textures; - GLuint su; - - st->missing_textures = GL_FALSE; - - for (su = 0; su < ctx->Const.MaxTextureCoordUnits; su++) { - if (fprog->Base.SamplersUsed & (1 << su)) { - const GLuint texUnit = fprog->Base.SamplerUnits[su]; - struct gl_texture_object *texObj - = ctx->Texture.Unit[texUnit]._Current; - - if (texObj) { - GLboolean retval; - - retval = st_finalize_texture(ctx, st->pipe, texObj); - if (!retval) { - /* out of mem */ - st->missing_textures = GL_TRUE; - continue; - } - } - } - } + const struct gl_context *ctx = st->ctx; - if (prev_missing_textures != st->missing_textures) - st->dirty.st |= ST_NEW_FRAGMENT_PROGRAM; + if (ctx->TessEvalProgram._Current) { + update_textures_local(st, PIPE_SHADER_TESS_EVAL, + ctx->TessEvalProgram._Current); + } } -const struct st_tracked_state st_finalize_textures = { - "st_finalize_textures", /* name */ - { /* dirty */ - _NEW_TEXTURE, /* mesa */ - 0, /* st */ - }, - finalize_textures /* update */ -}; +void +st_update_compute_textures(struct st_context *st) +{ + const struct gl_context *ctx = st->ctx; + + if (ctx->ComputeProgram._Current) { + update_textures_local(st, PIPE_SHADER_COMPUTE, + ctx->ComputeProgram._Current); + } +}