diff options
author | Kenneth Graunke <kenneth@whitecape.org> | 2016-06-14 12:34:50 -0700 |
---|---|---|
committer | Jordan Justen <jordan.l.justen@intel.com> | 2016-08-25 01:38:26 -0700 |
commit | 1b074cb7d4d53e289c4b0d77bc2fdfa0ae1f4d88 (patch) | |
tree | 4898afd044ed6f78c61dd446f337f0a38973f1cd | |
parent | 5e763127af804b98ee8888856d4c9dad4419231d (diff) |
nir: Add support for emulating border color.
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
-rw-r--r-- | src/compiler/nir/nir.h | 15 | ||||
-rw-r--r-- | src/compiler/nir/nir_lower_tex.c | 110 | ||||
-rw-r--r-- | src/mesa/program/prog_statevars.c | 96 | ||||
-rw-r--r-- | src/mesa/program/prog_statevars.h | 2 |
4 files changed, 222 insertions, 1 deletions
diff --git a/src/compiler/nir/nir.h b/src/compiler/nir/nir.h index ba6069f858a..aa9f768fbe0 100644 --- a/src/compiler/nir/nir.h +++ b/src/compiler/nir/nir.h @@ -2471,6 +2471,21 @@ typedef struct nir_lower_tex_options { unsigned saturate_t; unsigned saturate_r; + /** + * This can be used to emulate the GL_CLAMP_TO_BORDER wrap mode. + * The bits are according to sampler #, ie. if, for example: + * + * (conf->clamp_border & (1 << n)) + * + * is true, then clamp-to-border will be emulated for sampler n. + * + * Note that clamping must happen *after* projector lowering + * so any projected texture sample instruction with a clamped + * coordinate gets automatically lowered, regardless of the + * 'lower_txp' setting. + */ + unsigned clamp_border; + /* Bitmask of textures that need swizzling. * * If (swizzle_result & (1 << texture_index)), then the swizzle in diff --git a/src/compiler/nir/nir_lower_tex.c b/src/compiler/nir/nir_lower_tex.c index 5d97af39f9c..84a30dc5054 100644 --- a/src/compiler/nir/nir_lower_tex.c +++ b/src/compiler/nir/nir_lower_tex.c @@ -37,10 +37,15 @@ #include "nir.h" #include "nir_builder.h" +#include "program/prog_instruction.h" +#include "program/prog_statevars.h" +#include "main/config.h" struct nir_lower_tex_state { const nir_lower_tex_options *options; nir_builder builder; + nir_variable *clamp_to_border_enable_bitfield; + nir_variable *border_color[MAX_SAMPLERS]; }; static int @@ -381,6 +386,100 @@ saturate_src(nir_builder *b, nir_tex_instr *tex, unsigned sat_mask) } } +static void +make_clamp_to_border_enable_bitfield(struct nir_lower_tex_state *state, + nir_shader *nir) +{ + nir_variable *var = nir_variable_create(nir, nir_var_uniform, + glsl_vec_type(3), + "gl_ClampToBorderEnableBitfield"); + var->num_state_slots = 1; + var->state_slots = ralloc_array(var, nir_state_slot, 1); + var->state_slots[0].swizzle = MAKE_SWIZZLE4(0, 1, 2, 2); + var->state_slots[0].tokens[0] = STATE_INTERNAL; + var->state_slots[0].tokens[1] = STATE_CLAMP_TO_BORDER_ENABLE_BITFIELD; + var->state_slots[0].tokens[2] = nir->stage; + for (int i = 3; i < STATE_LENGTH; i++) + var->state_slots[0].tokens[i] = 0; + + state->clamp_to_border_enable_bitfield = var; +} + +static void +clamp_src_to_border(struct nir_lower_tex_state *state, nir_tex_instr *tex) +{ + if (tex->op == nir_texop_lod || tex->op == nir_texop_samples_identical) + return; + + nir_builder *b = &state->builder; + b->cursor = nir_before_instr(&tex->instr); + + /* Make a border color uniform for this sampler if we haven't already */ + if (!state->border_color[tex->sampler_index]) { + char *name = ralloc_asprintf(NULL, "gl_BorderColorForSampler%u", + tex->sampler_index); + nir_variable *var = nir_variable_create(b->shader, nir_var_uniform, + glsl_vec4_type(), name); + ralloc_free(name); + + var->num_state_slots = 1; + var->state_slots = ralloc_array(var, nir_state_slot, 1); + var->state_slots[0].swizzle = SWIZZLE_XYZW; + var->state_slots[0].tokens[0] = STATE_INTERNAL; + var->state_slots[0].tokens[1] = STATE_BORDER_COLOR; + var->state_slots[0].tokens[2] = b->shader->stage; + var->state_slots[0].tokens[3] = tex->sampler_index; + for (int i = 4; i < STATE_LENGTH; i++) + var->state_slots[0].tokens[i] = 0; + + state->border_color[tex->sampler_index] = var; + } + + nir_ssa_def *coord = NULL; + + /* Find the coordinate */ + for (unsigned i = 0; i < tex->num_srcs; i++) { + if (tex->src[i].src_type == nir_tex_src_coord) { + coord = nir_ssa_for_src(b, tex->src[i].src, tex->coord_components); + break; + } + } + + if (!coord) + return; + + /* Normalize coordinates to [0.0, 1.0] for the bounds-check. */ + if (tex->sampler_dim == GLSL_SAMPLER_DIM_RECT) + coord = nir_fdiv(b, coord, get_texture_size(b, tex)); + + const unsigned coord_mask = + (1 << (tex->coord_components - tex->is_array)) - 1; + + /* Mask out any coordinate components that aren't CLAMP_TO_BORDER. */ + nir_ssa_def *bitfield = + nir_channels(b, nir_load_var(b, state->clamp_to_border_enable_bitfield), + coord_mask); + nir_ssa_def *mask = + nir_ishr(b, nir_ishl(b, bitfield, nir_imm_int(b, tex->sampler_index)), + nir_imm_int(b, 31)); + + coord = nir_iand(b, nir_channels(b, coord, coord_mask), mask); + + /* If the normalized coordinates differ when saturated, then they're + * outside of the image and should result in border color. Note that + * masked components will be 0.0, which is equal when saturated. + */ + nir_ssa_def *outside = nir_bany_fnequal(b, coord, nir_fsat(b, coord)); + + b->cursor = nir_after_instr(&tex->instr); + + nir_ssa_def *border = + nir_load_var(b, state->border_color[tex->sampler_index]); + nir_ssa_def *result = nir_bcsel(b, outside, border, &tex->dest.ssa); + nir_ssa_def_rewrite_uses_after(&tex->dest.ssa, nir_src_for_ssa(result), + result->parent_instr); +} + static nir_ssa_def * get_zero_or_one(nir_builder *b, nir_alu_type type, uint8_t swizzle_val) { @@ -507,7 +606,8 @@ nir_lower_tex_block(nir_block *block, struct nir_lower_tex_state *state) /* If we are clamping any coords, we must lower projector first * as clamping happens *after* projection: */ - if (lower_txp || sat_mask) { + if (lower_txp || sat_mask || + ((1 << tex->texture_index) & options->clamp_border)) { project_src(b, tex); progress = true; } @@ -538,6 +638,10 @@ nir_lower_tex_block(nir_block *block, struct nir_lower_tex_state *state) progress = true; } + if ((1 << tex->texture_index) & options->clamp_border) { + clamp_src_to_border(state, tex); + progress = true; + } if (sat_mask) { saturate_src(b, tex, sat_mask); @@ -586,6 +690,10 @@ nir_lower_tex(nir_shader *shader, const nir_lower_tex_options *options) bool progress = false; + if (options->clamp_border) { + make_clamp_to_border_enable_bitfield(&state, shader); + } + nir_foreach_function(function, shader) { if (function->impl) progress |= nir_lower_tex_impl(function->impl, &state); diff --git a/src/mesa/program/prog_statevars.c b/src/mesa/program/prog_statevars.c index 8dddc0b86a9..5884163dfd0 100644 --- a/src/mesa/program/prog_statevars.c +++ b/src/mesa/program/prog_statevars.c @@ -39,8 +39,10 @@ #include "main/fbobject.h" #include "prog_statevars.h" #include "prog_parameter.h" +#include "prog_instruction.h" #include "main/samplerobj.h" #include "main/framebuffer.h" +#include "main/glformats.h" #define ONE_DIV_SQRT_LN2 (1.201122408786449815) @@ -609,6 +611,90 @@ _mesa_fetch_state(struct gl_context *ctx, const gl_state_index state[], val[0].i = ctx->TessCtrlProgram.patch_vertices; return; + case STATE_CLAMP_TO_BORDER_ENABLE_BITFIELD: { + const gl_shader_stage stage = state[2]; + const struct gl_linked_shader *shader = + ctx->_Shader->CurrentProgram[stage]->_LinkedShaders[stage]; + + for (int i = 0; i < 4; i++) + val[i].i = 0; + + for (int s = 0; s < MAX_SAMPLERS; s++) { + const struct gl_sampler_object *sampler = + _mesa_get_samplerobj(ctx, shader->Program->SamplerUnits[s]); + + if (!sampler) + continue; + + if (sampler->WrapS == GL_CLAMP_TO_BORDER) + val[0].u |= 1u << s; + if (sampler->WrapT == GL_CLAMP_TO_BORDER) + val[1].u |= 1u << s; + if (sampler->WrapR == GL_CLAMP_TO_BORDER) + val[2].u |= 1u << s; + } + return; + } + + case STATE_BORDER_COLOR: { + const gl_shader_stage stage = state[2]; + const struct gl_linked_shader *shader = + ctx->_Shader->CurrentProgram[stage]->_LinkedShaders[stage]; + const GLubyte unit = shader->Program->SamplerUnits[state[3]]; + const struct gl_sampler_object *sampler = + _mesa_get_samplerobj(ctx, unit); + const struct gl_texture_object *t = ctx->Texture.Unit[unit]._Current; + const struct gl_texture_image *img = + t ? t->Image[0][t->BaseLevel] : NULL; + + int swizzles[SWIZZLE_NIL + 1] = { + SWIZZLE_ZERO, + SWIZZLE_ZERO, + SWIZZLE_ZERO, + SWIZZLE_ONE, + SWIZZLE_ZERO, + SWIZZLE_ONE, + SWIZZLE_NIL + }; + + if (img) { + if (img->_BaseFormat == GL_ALPHA) { + swizzles[3] = SWIZZLE_W; + } else if (img->_BaseFormat == GL_LUMINANCE) { + for (int i = 0; i < 3; i++) + swizzles[i] = SWIZZLE_X; + } else if (img->_BaseFormat == GL_LUMINANCE_ALPHA) { + for (int i = 0; i < 3; i++) + swizzles[i] = SWIZZLE_X; + swizzles[3] = SWIZZLE_W; + } else if (img->_BaseFormat == GL_INTENSITY) { + for (int i = 0; i < 4; i++) + swizzles[i] = SWIZZLE_X; + } else { + const int components = + _mesa_base_format_component_count(img->_BaseFormat); + + for (int i = 0; i < components; i++) + swizzles[i] = i; + } + } + + for (int i = 0; i < 4; i++) { + int swz = swizzles[GET_SWZ(t->_Swizzle, i)]; + if (swz == SWIZZLE_ZERO) { + val[i].i = 0; + } else if (swz == SWIZZLE_ONE) { + if (t->_IsIntegerFormat) + val[i].i = 1; + else + val[i].f = 1.0f; + } else { + val[i].i = sampler->BorderColor.i[swz]; + } + } + return; + } + /* XXX: make sure new tokens added here are also handled in the * _mesa_program_state_flags() switch, below. */ @@ -719,6 +805,10 @@ _mesa_program_state_flags(const gl_state_index state[STATE_LENGTH]) case STATE_FB_WPOS_Y_TRANSFORM: return _NEW_BUFFERS; + case STATE_CLAMP_TO_BORDER_ENABLE_BITFIELD: + case STATE_BORDER_COLOR: + return _NEW_TEXTURE; + default: /* unknown state indexes are silently ignored and * no flag set, since it is handled by the driver. @@ -925,6 +1015,12 @@ append_token(char *dst, gl_state_index k) case STATE_FB_WPOS_Y_TRANSFORM: append(dst, "FbWposYTransform"); break; + case STATE_CLAMP_TO_BORDER_ENABLE_BITFIELD: + append(dst, "ClampToBorderEnableBitfield"); + break; + case STATE_BORDER_COLOR: + append(dst, "BorderColor"); + break; default: /* probably STATE_INTERNAL_DRIVER+i (driver private state) */ append(dst, "driverState"); diff --git a/src/mesa/program/prog_statevars.h b/src/mesa/program/prog_statevars.h index e716d9070a2..620323c154f 100644 --- a/src/mesa/program/prog_statevars.h +++ b/src/mesa/program/prog_statevars.h @@ -130,6 +130,8 @@ typedef enum gl_state_index_ { STATE_FB_WPOS_Y_TRANSFORM, /**< (1, 0, -1, height) if a FBO is bound, (-1, height, 1, 0) otherwise */ STATE_TCS_PATCH_VERTICES_IN, /**< gl_PatchVerticesIn for TCS (integer) */ STATE_TES_PATCH_VERTICES_IN, /**< gl_PatchVerticesIn for TES (integer) */ + STATE_CLAMP_TO_BORDER_ENABLE_BITFIELD, + STATE_BORDER_COLOR, /**< Sampler Border Color */ STATE_INTERNAL_DRIVER /* first available state index for drivers (must be last) */ } gl_state_index; |