X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fmesa%2Fstate_tracker%2Fst_atom_sampler.c;h=7ae981b71b4c7c37d69184f29564a006846a9d07;hb=7f0b6a5df8e360e52a97f59948dda927fe9df15e;hp=b67068df373d7a358c701a08b7714efceda81404;hpb=e5aa69f6a6779d1e0fb3d413ad7007b0fb90b176;p=mesa.git diff --git a/src/mesa/state_tracker/st_atom_sampler.c b/src/mesa/state_tracker/st_atom_sampler.c index b67068df373..7ae981b71b4 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,21 +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. @@ -49,222 +59,364 @@ 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 -xlate_border_color(const GLfloat *colorIn, GLenum baseFormat, GLfloat *colorOut) +/** + * 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) { - switch (baseFormat) { - case GL_RED: - colorOut[0] = colorIn[0]; - colorOut[1] = 0.0F; - colorOut[2] = 0.0F; - colorOut[3] = 1.0F; - break; - case GL_RG: - colorOut[0] = colorIn[0]; - colorOut[1] = colorIn[1]; - colorOut[2] = 0.0F; - colorOut[3] = 1.0F; - break; - case GL_RGB: - colorOut[0] = colorIn[0]; - colorOut[1] = colorIn[1]; - colorOut[2] = colorIn[2]; - colorOut[3] = 1.0F; - break; - case GL_ALPHA: - colorOut[0] = colorOut[1] = colorOut[2] = 0.0; - colorOut[3] = colorIn[3]; - break; - case GL_LUMINANCE: - colorOut[0] = colorOut[1] = colorOut[2] = colorIn[0]; - colorOut[3] = 1.0; - break; - case GL_LUMINANCE_ALPHA: - colorOut[0] = colorOut[1] = colorOut[2] = colorIn[0]; - colorOut[3] = colorIn[3]; - break; - case GL_INTENSITY: - colorOut[0] = colorOut[1] = colorOut[2] = colorOut[3] = colorIn[0]; - break; - default: - COPY_4V(colorOut, colorIn); + memset(sampler, 0, sizeof(*sampler)); + sampler->wrap_s = gl_wrap_xlate(msamp->WrapS); + sampler->wrap_t = gl_wrap_xlate(msamp->WrapT); + sampler->wrap_r = gl_wrap_xlate(msamp->WrapR); + + if (texobj->_IsIntegerFormat && st->ctx->Const.ForceIntegerTexNearest) { + sampler->min_img_filter = gl_filter_to_img_filter(GL_NEAREST); + sampler->mag_img_filter = gl_filter_to_img_filter(GL_NEAREST); + } else { + sampler->min_img_filter = gl_filter_to_img_filter(msamp->MinFilter); + sampler->mag_img_filter = gl_filter_to_img_filter(msamp->MagFilter); + } + sampler->min_mip_filter = gl_filter_to_mip_filter(msamp->MinFilter); + + if (texobj->Target != GL_TEXTURE_RECTANGLE_ARB) + sampler->normalized_coords = 1; + + 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 = 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. + */ + float tmp = sampler->max_lod; + sampler->max_lod = sampler->min_lod; + sampler->min_lod = tmp; + assert(sampler->min_lod <= sampler->max_lod); + } + + /* 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); + + /* If sampling a depth texture and using shadow comparison */ + if (msamp->CompareMode == GL_COMPARE_R_TO_TEXTURE) { + 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); + } + } + + /* 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; } -static void -update_samplers(struct st_context *st) +/** + * Update the gallium driver's sampler state for fragment, vertex or + * geometry shader stage. + */ +static void +update_shader_samplers(struct st_context *st, + enum pipe_shader_type shader_stage, + const struct gl_program *prog, + struct pipe_sampler_state *samplers, + unsigned *out_num_samplers) { - struct gl_vertex_program *vprog = st->ctx->VertexProgram._Current; - struct gl_fragment_program *fprog = st->ctx->FragmentProgram._Current; - const GLbitfield samplersUsed = (vprog->Base.SamplersUsed | - fprog->Base.SamplersUsed); - GLuint su; + 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 (!samplers) + samplers = local_samplers; - st->state.num_samplers = 0; + num_samplers = util_last_bit(samplers_used); /* loop over sampler units (aka tex image units) */ - for (su = 0; su < st->ctx->Const.MaxTextureImageUnits; su++) { - struct pipe_sampler_state *sampler = st->state.samplers + su; + for (unit = 0; samplers_used; unit++, samplers_used >>= 1) { + struct pipe_sampler_state *sampler = samplers + unit; + unsigned tex_unit = prog->SamplerUnits[unit]; + + /* 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; + } + } - memset(sampler, 0, sizeof(*sampler)); + /* 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 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; + } - if (samplersUsed & (1 << su)) { - struct gl_texture_object *texobj; - struct gl_texture_image *teximg; - GLuint texUnit; + num_samplers = MAX2(num_samplers, extra + 1); + } - if (fprog->Base.SamplersUsed & (1 << su)) - texUnit = fprog->Base.SamplerUnits[su]; - else - texUnit = vprog->Base.SamplerUnits[su]; + cso_set_samplers(st->cso_context, shader_stage, num_samplers, states); - texobj = st->ctx->Texture.Unit[texUnit]._Current; - if (!texobj) { - texobj = st_get_default_texture(st); - } + if (out_num_samplers) + *out_num_samplers = num_samplers; +} - teximg = texobj->Image[0][texobj->BaseLevel]; - sampler->wrap_s = gl_wrap_xlate(texobj->WrapS); - sampler->wrap_t = gl_wrap_xlate(texobj->WrapT); - sampler->wrap_r = gl_wrap_xlate(texobj->WrapR); +void +st_update_vertex_samplers(struct st_context *st) +{ + const struct gl_context *ctx = st->ctx; - sampler->min_img_filter = gl_filter_to_img_filter(texobj->MinFilter); - sampler->min_mip_filter = gl_filter_to_mip_filter(texobj->MinFilter); - sampler->mag_img_filter = gl_filter_to_img_filter(texobj->MagFilter); + update_shader_samplers(st, + PIPE_SHADER_VERTEX, + ctx->VertexProgram._Current, + st->state.vert_samplers, + &st->state.num_vert_samplers); +} - if (texobj->Target != GL_TEXTURE_RECTANGLE_ARB) - sampler->normalized_coords = 1; - sampler->lod_bias = st->ctx->Texture.Unit[su].LodBias; +void +st_update_tessctrl_samplers(struct st_context *st) +{ + const struct gl_context *ctx = st->ctx; - sampler->min_lod = texobj->BaseLevel + texobj->MinLod; - if (sampler->min_lod < texobj->BaseLevel) - sampler->min_lod = texobj->BaseLevel; + if (ctx->TessCtrlProgram._Current) { + update_shader_samplers(st, + PIPE_SHADER_TESS_CTRL, + ctx->TessCtrlProgram._Current, NULL, NULL); + } +} - sampler->max_lod = MIN2((GLfloat) texobj->MaxLevel, - (texobj->MaxLod + texobj->BaseLevel)); - if (sampler->max_lod < sampler->min_lod) { - /* The GL spec doesn't seem to specify what to do in this case. - * Swap the values. - */ - float tmp = sampler->max_lod; - sampler->max_lod = sampler->min_lod; - sampler->min_lod = tmp; - assert(sampler->min_lod <= sampler->max_lod); - } - xlate_border_color(texobj->BorderColor.f, - teximg ? teximg->_BaseFormat : GL_RGBA, - sampler->border_color); +void +st_update_tesseval_samplers(struct st_context *st) +{ + const struct gl_context *ctx = st->ctx; - sampler->max_anisotropy = (texobj->MaxAnisotropy == 1.0 ? 0 : (GLuint)texobj->MaxAnisotropy); + if (ctx->TessEvalProgram._Current) { + update_shader_samplers(st, + PIPE_SHADER_TESS_EVAL, + ctx->TessEvalProgram._Current, NULL, NULL); + } +} - /* only care about ARB_shadow, not SGI shadow */ - if (texobj->CompareMode == GL_COMPARE_R_TO_TEXTURE) { - sampler->compare_mode = PIPE_TEX_COMPARE_R_TO_TEXTURE; - sampler->compare_func - = st_compare_func_to_pipe(texobj->CompareFunc); - } - st->state.num_samplers = su + 1; +void +st_update_geometry_samplers(struct st_context *st) +{ + const struct gl_context *ctx = st->ctx; - /*printf("%s su=%u non-null\n", __FUNCTION__, su);*/ - cso_single_sampler(st->cso_context, su, sampler); - if (su < st->ctx->Const.MaxVertexTextureImageUnits) { - cso_single_vertex_sampler(st->cso_context, su, sampler); - } - } - else { - /*printf("%s su=%u null\n", __FUNCTION__, su);*/ - cso_single_sampler(st->cso_context, su, NULL); - if (su < st->ctx->Const.MaxVertexTextureImageUnits) { - cso_single_vertex_sampler(st->cso_context, su, NULL); - } - } + if (ctx->GeometryProgram._Current) { + update_shader_samplers(st, + PIPE_SHADER_GEOMETRY, + ctx->GeometryProgram._Current, NULL, NULL); } +} - cso_single_sampler_done(st->cso_context); - if (st->ctx->Const.MaxVertexTextureImageUnits > 0) { - cso_single_vertex_sampler_done(st->cso_context); - } + +void +st_update_fragment_samplers(struct st_context *st) +{ + const struct gl_context *ctx = st->ctx; + + update_shader_samplers(st, + 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); + } +}