X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fmesa%2Fstate_tracker%2Fst_atom_sampler.c;h=b74d47b691fed88ca8f981942bd97bb42fb6aa8d;hb=013d9e40feed336d983b728357e4ce77b871c36d;hp=70ae55fd2eba33b7d0a1b8828fd79079bec3f754;hpb=6c8a13215813841703e7c2efa233e8d4cf517dfd;p=mesa.git diff --git a/src/mesa/state_tracker/st_atom_sampler.c b/src/mesa/state_tracker/st_atom_sampler.c index 70ae55fd2eb..b74d47b691f 100644 --- a/src/mesa/state_tracker/st_atom_sampler.c +++ b/src/mesa/state_tracker/st_atom_sampler.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,26 +27,31 @@ /* * Authors: - * Keith Whitwell + * Keith Whitwell * Brian Paul */ #include "main/macros.h" #include "main/mtypes.h" +#include "main/glformats.h" #include "main/samplerobj.h" +#include "main/teximage.h" #include "main/texobj.h" #include "st_context.h" #include "st_cb_texture.h" #include "st_format.h" #include "st_atom.h" +#include "st_sampler_view.h" #include "st_texture.h" #include "pipe/p_context.h" #include "pipe/p_defines.h" #include "cso_cache/cso_context.h" +#include "util/format/u_format.h" + /** * Convert GLenum texcoord wrap tokens to pipe tokens. @@ -54,90 +59,56 @@ static GLuint gl_wrap_xlate(GLenum wrap) { - switch (wrap) { - case GL_REPEAT: - return PIPE_TEX_WRAP_REPEAT; - case GL_CLAMP: - return PIPE_TEX_WRAP_CLAMP; - case GL_CLAMP_TO_EDGE: - return PIPE_TEX_WRAP_CLAMP_TO_EDGE; - case GL_CLAMP_TO_BORDER: - return PIPE_TEX_WRAP_CLAMP_TO_BORDER; - case GL_MIRRORED_REPEAT: - return PIPE_TEX_WRAP_MIRROR_REPEAT; - case GL_MIRROR_CLAMP_EXT: - return PIPE_TEX_WRAP_MIRROR_CLAMP; - case GL_MIRROR_CLAMP_TO_EDGE_EXT: - return PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE; - case GL_MIRROR_CLAMP_TO_BORDER_EXT: - return PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER; - default: - assert(0); - return 0; - } + /* Take advantage of how the enums are defined. */ + static const unsigned table[32] = { + [GL_REPEAT & 0x1f] = PIPE_TEX_WRAP_REPEAT, + [GL_CLAMP & 0x1f] = PIPE_TEX_WRAP_CLAMP, + [GL_CLAMP_TO_EDGE & 0x1f] = PIPE_TEX_WRAP_CLAMP_TO_EDGE, + [GL_CLAMP_TO_BORDER & 0x1f] = PIPE_TEX_WRAP_CLAMP_TO_BORDER, + [GL_MIRRORED_REPEAT & 0x1f] = PIPE_TEX_WRAP_MIRROR_REPEAT, + [GL_MIRROR_CLAMP_EXT & 0x1f] = PIPE_TEX_WRAP_MIRROR_CLAMP, + [GL_MIRROR_CLAMP_TO_EDGE & 0x1f] = PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE, + [GL_MIRROR_CLAMP_TO_BORDER_EXT & 0x1f] = PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER, + }; + + return table[wrap & 0x1f]; } static GLuint gl_filter_to_mip_filter(GLenum filter) { - switch (filter) { - case GL_NEAREST: - case GL_LINEAR: + /* Take advantage of how the enums are defined. */ + if (filter <= GL_LINEAR) return PIPE_TEX_MIPFILTER_NONE; - - case GL_NEAREST_MIPMAP_NEAREST: - case GL_LINEAR_MIPMAP_NEAREST: + if (filter <= GL_LINEAR_MIPMAP_NEAREST) return PIPE_TEX_MIPFILTER_NEAREST; - case GL_NEAREST_MIPMAP_LINEAR: - case GL_LINEAR_MIPMAP_LINEAR: - return PIPE_TEX_MIPFILTER_LINEAR; - - default: - assert(0); - return PIPE_TEX_MIPFILTER_NONE; - } + return PIPE_TEX_MIPFILTER_LINEAR; } static GLuint gl_filter_to_img_filter(GLenum filter) { - switch (filter) { - case GL_NEAREST: - case GL_NEAREST_MIPMAP_NEAREST: - case GL_NEAREST_MIPMAP_LINEAR: - return PIPE_TEX_FILTER_NEAREST; - - case GL_LINEAR: - case GL_LINEAR_MIPMAP_NEAREST: - case GL_LINEAR_MIPMAP_LINEAR: + /* Take advantage of how the enums are defined. */ + if (filter & 1) return PIPE_TEX_FILTER_LINEAR; - default: - assert(0); - return PIPE_TEX_FILTER_NEAREST; - } + return PIPE_TEX_FILTER_NEAREST; } -static void -convert_sampler(struct st_context *st, - struct pipe_sampler_state *sampler, - GLuint texUnit) +/** + * Convert a gl_sampler_object to a pipe_sampler_state object. + */ +void +st_convert_sampler(const struct st_context *st, + const struct gl_texture_object *texobj, + const struct gl_sampler_object *msamp, + float tex_unit_lod_bias, + struct pipe_sampler_state *sampler) { - struct gl_texture_object *texobj; - struct gl_context *ctx = st->ctx; - struct gl_sampler_object *msamp; - - texobj = ctx->Texture.Unit[texUnit]._Current; - if (!texobj) { - texobj = _mesa_get_fallback_texture(ctx, TEXTURE_2D_INDEX); - } - - msamp = _mesa_get_samplerobj(ctx, texUnit); - memset(sampler, 0, sizeof(*sampler)); sampler->wrap_s = gl_wrap_xlate(msamp->WrapS); sampler->wrap_t = gl_wrap_xlate(msamp->WrapT); @@ -150,13 +121,16 @@ convert_sampler(struct st_context *st, if (texobj->Target != GL_TEXTURE_RECTANGLE_ARB) sampler->normalized_coords = 1; - sampler->lod_bias = ctx->Texture.Unit[texUnit].LodBias + msamp->LodBias; + sampler->lod_bias = msamp->LodBias + tex_unit_lod_bias; + /* Reduce the number of states by allowing only the values that AMD GCN + * can represent. Apps use lod_bias for smooth transitions to bigger mipmap + * levels. + */ + sampler->lod_bias = CLAMP(sampler->lod_bias, -16, 16); + sampler->lod_bias = floorf(sampler->lod_bias * 256) / 256; - sampler->min_lod = CLAMP(msamp->MinLod, - 0.0f, - (GLfloat) texobj->MaxLevel - texobj->BaseLevel); - sampler->max_lod = MIN2((GLfloat) texobj->MaxLevel - texobj->BaseLevel, - msamp->MaxLod); + sampler->min_lod = MAX2(msamp->MinLod, 0.0f); + sampler->max_lod = msamp->MaxLod; if (sampler->max_lod < sampler->min_lod) { /* The GL spec doesn't seem to specify what to do in this case. * Swap the values. @@ -167,31 +141,107 @@ convert_sampler(struct st_context *st, assert(sampler->min_lod <= sampler->max_lod); } - if (msamp->BorderColor.ui[0] || - msamp->BorderColor.ui[1] || - msamp->BorderColor.ui[2] || - msamp->BorderColor.ui[3]) { - struct gl_texture_image *teximg; - - teximg = texobj->Image[0][texobj->BaseLevel]; - - st_translate_color(msamp->BorderColor.f, - teximg ? teximg->_BaseFormat : GL_RGBA, - sampler->border_color.f); + /* Check that only wrap modes using the border color have the first bit + * set. + */ + STATIC_ASSERT(PIPE_TEX_WRAP_CLAMP & 0x1); + STATIC_ASSERT(PIPE_TEX_WRAP_CLAMP_TO_BORDER & 0x1); + STATIC_ASSERT(PIPE_TEX_WRAP_MIRROR_CLAMP & 0x1); + STATIC_ASSERT(PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER & 0x1); + STATIC_ASSERT(((PIPE_TEX_WRAP_REPEAT | + PIPE_TEX_WRAP_CLAMP_TO_EDGE | + PIPE_TEX_WRAP_MIRROR_REPEAT | + PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE) & 0x1) == 0); + + /* For non-black borders... */ + if (/* This is true if wrap modes are using the border color: */ + (sampler->wrap_s | sampler->wrap_t | sampler->wrap_r) & 0x1 && + (msamp->BorderColor.ui[0] || + msamp->BorderColor.ui[1] || + msamp->BorderColor.ui[2] || + msamp->BorderColor.ui[3])) { + const GLboolean is_integer = texobj->_IsIntegerFormat; + GLenum texBaseFormat = _mesa_base_tex_image(texobj)->_BaseFormat; + + if (texobj->StencilSampling) + texBaseFormat = GL_STENCIL_INDEX; + + if (st->apply_texture_swizzle_to_border_color) { + const struct st_texture_object *stobj = st_texture_object_const(texobj); + /* XXX: clean that up to not use the sampler view at all */ + const struct st_sampler_view *sv = st_texture_get_current_sampler_view(st, stobj); + + if (sv) { + struct pipe_sampler_view *view = sv->view; + union pipe_color_union tmp; + const unsigned char swz[4] = + { + view->swizzle_r, + view->swizzle_g, + view->swizzle_b, + view->swizzle_a, + }; + + st_translate_color(&msamp->BorderColor, &tmp, + texBaseFormat, is_integer); + + util_format_apply_color_swizzle(&sampler->border_color, + &tmp, swz, is_integer); + } else { + st_translate_color(&msamp->BorderColor, + &sampler->border_color, + texBaseFormat, is_integer); + } + } else { + st_translate_color(&msamp->BorderColor, + &sampler->border_color, + texBaseFormat, is_integer); + } } sampler->max_anisotropy = (msamp->MaxAnisotropy == 1.0 ? 0 : (GLuint) msamp->MaxAnisotropy); - /* only care about ARB_shadow, not SGI shadow */ + /* If sampling a depth texture and using shadow comparison */ if (msamp->CompareMode == GL_COMPARE_R_TO_TEXTURE) { - sampler->compare_mode = PIPE_TEX_COMPARE_R_TO_TEXTURE; - sampler->compare_func - = st_compare_func_to_pipe(msamp->CompareFunc); + GLenum texBaseFormat = _mesa_base_tex_image(texobj)->_BaseFormat; + + if (texBaseFormat == GL_DEPTH_COMPONENT || + (texBaseFormat == GL_DEPTH_STENCIL && !texobj->StencilSampling)) { + sampler->compare_mode = PIPE_TEX_COMPARE_R_TO_TEXTURE; + sampler->compare_func = st_compare_func_to_pipe(msamp->CompareFunc); + } } - sampler->seamless_cube_map = - ctx->Texture.CubeMapSeamless || msamp->CubeMapSeamless; + /* Only set the seamless cube map texture parameter because the per-context + * enable should be ignored and treated as disabled when using texture + * handles, as specified by ARB_bindless_texture. + */ + sampler->seamless_cube_map = msamp->CubeMapSeamless; +} + +/** + * Get a pipe_sampler_state object from a texture unit. + */ +void +st_convert_sampler_from_unit(const struct st_context *st, + struct pipe_sampler_state *sampler, + GLuint texUnit) +{ + const struct gl_texture_object *texobj; + struct gl_context *ctx = st->ctx; + const struct gl_sampler_object *msamp; + + texobj = ctx->Texture.Unit[texUnit]._Current; + assert(texobj); + assert(texobj->Target != GL_TEXTURE_BUFFER); + + msamp = _mesa_get_samplerobj(ctx, texUnit); + + st_convert_sampler(st, texobj, msamp, ctx->Texture.Unit[texUnit].LodBias, + sampler); + + sampler->seamless_cube_map |= ctx->Texture.CubeMapSeamless; } @@ -201,84 +251,167 @@ convert_sampler(struct st_context *st, */ static void update_shader_samplers(struct st_context *st, - unsigned shader_stage, + enum pipe_shader_type shader_stage, const struct gl_program *prog, - unsigned max_units, struct pipe_sampler_state *samplers, - unsigned *num_samplers) + unsigned *out_num_samplers) { - GLuint unit; - GLbitfield samplers_used; - const GLuint old_max = *num_samplers; - - samplers_used = prog->SamplersUsed; + struct gl_context *ctx = st->ctx; + GLbitfield samplers_used = prog->SamplersUsed; + GLbitfield free_slots = ~prog->SamplersUsed; + GLbitfield external_samplers_used = prog->ExternalSamplersUsed; + unsigned unit, num_samplers; + struct pipe_sampler_state local_samplers[PIPE_MAX_SAMPLERS]; + const struct pipe_sampler_state *states[PIPE_MAX_SAMPLERS]; + + if (samplers_used == 0x0) { + if (out_num_samplers) + *out_num_samplers = 0; + return; + } - if (*num_samplers == 0 && samplers_used == 0x0) - return; + if (!samplers) + samplers = local_samplers; - *num_samplers = 0; + num_samplers = util_last_bit(samplers_used); /* loop over sampler units (aka tex image units) */ - for (unit = 0; unit < max_units; unit++, samplers_used >>= 1) { + for (unit = 0; samplers_used; unit++, samplers_used >>= 1) { struct pipe_sampler_state *sampler = samplers + unit; + unsigned tex_unit = prog->SamplerUnits[unit]; - if (samplers_used & 1) { - const GLuint texUnit = prog->SamplerUnits[unit]; - - convert_sampler(st, sampler, texUnit); + /* Don't update the sampler for TBOs. cso_context will not bind sampler + * states that are NULL. + */ + if (samplers_used & 1 && + ctx->Texture.Unit[tex_unit]._Current->Target != GL_TEXTURE_BUFFER) { + st_convert_sampler_from_unit(st, sampler, tex_unit); + states[unit] = sampler; + } else { + states[unit] = NULL; + } + } - *num_samplers = unit + 1; + /* 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; - cso_single_sampler(st->cso_context, shader_stage, unit, sampler); - } - else if (samplers_used != 0 || unit < old_max) { - cso_single_sampler(st->cso_context, shader_stage, unit, NULL); - } - else { - /* if we've reset all the old samplers and we have no more new ones */ + /* if resource format matches then YUV wasn't lowered */ + if (!stObj || st_get_view_format(stObj) == stObj->pt->format) + continue; + + switch (st_get_view_format(stObj)) { + case PIPE_FORMAT_NV12: + case PIPE_FORMAT_P010: + case PIPE_FORMAT_P016: + case PIPE_FORMAT_YUYV: + case PIPE_FORMAT_UYVY: + /* 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_single_sampler_done(st->cso_context, shader_stage); + cso_set_samplers(st->cso_context, shader_stage, num_samplers, states); + + if (out_num_samplers) + *out_num_samplers = num_samplers; } -static void -update_samplers(struct st_context *st) +void +st_update_vertex_samplers(struct st_context *st) { const struct gl_context *ctx = st->ctx; - update_shader_samplers(st, - PIPE_SHADER_FRAGMENT, - &ctx->FragmentProgram._Current->Base, - ctx->Const.MaxTextureImageUnits, - st->state.samplers[PIPE_SHADER_FRAGMENT], - &st->state.num_samplers[PIPE_SHADER_FRAGMENT]); - update_shader_samplers(st, PIPE_SHADER_VERTEX, - &ctx->VertexProgram._Current->Base, - ctx->Const.MaxVertexTextureImageUnits, - st->state.samplers[PIPE_SHADER_VERTEX], - &st->state.num_samplers[PIPE_SHADER_VERTEX]); + ctx->VertexProgram._Current, + st->state.vert_samplers, + &st->state.num_vert_samplers); +} + + +void +st_update_tessctrl_samplers(struct st_context *st) +{ + const struct gl_context *ctx = st->ctx; + + if (ctx->TessCtrlProgram._Current) { + update_shader_samplers(st, + PIPE_SHADER_TESS_CTRL, + ctx->TessCtrlProgram._Current, NULL, NULL); + } +} + + +void +st_update_tesseval_samplers(struct st_context *st) +{ + const struct gl_context *ctx = st->ctx; + + if (ctx->TessEvalProgram._Current) { + update_shader_samplers(st, + PIPE_SHADER_TESS_EVAL, + ctx->TessEvalProgram._Current, NULL, NULL); + } +} + + +void +st_update_geometry_samplers(struct st_context *st) +{ + const struct gl_context *ctx = st->ctx; + + if (ctx->GeometryProgram._Current) { + update_shader_samplers(st, + PIPE_SHADER_GEOMETRY, + ctx->GeometryProgram._Current, NULL, NULL); + } +} + + +void +st_update_fragment_samplers(struct st_context *st) +{ + const struct gl_context *ctx = st->ctx; -/* update_shader_samplers(st, - PIPE_SHADER_GEOMETRY, - &ctx->GeometryProgram._Current->Base, - ctx->Const.MaxGeometryTextureImageUnits, - st->state.samplers[PIPE_SHADER_GEOMETRY], - &st->state.num_samplers[PIPE_SHADER_GEOMETRY]); -*/ + PIPE_SHADER_FRAGMENT, + ctx->FragmentProgram._Current, + st->state.frag_samplers, + &st->state.num_frag_samplers); } -const struct st_tracked_state st_update_sampler = { - "st_update_sampler", /* name */ - { /* dirty */ - _NEW_TEXTURE, /* mesa */ - 0, /* st */ - }, - update_samplers /* update */ -}; +void +st_update_compute_samplers(struct st_context *st) +{ + const struct gl_context *ctx = st->ctx; + + if (ctx->ComputeProgram._Current) { + update_shader_samplers(st, + PIPE_SHADER_COMPUTE, + ctx->ComputeProgram._Current, NULL, NULL); + } +}