summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKenneth Graunke <kenneth@whitecape.org>2016-06-14 12:34:50 -0700
committerJordan Justen <jordan.l.justen@intel.com>2016-08-25 01:38:26 -0700
commit1b074cb7d4d53e289c4b0d77bc2fdfa0ae1f4d88 (patch)
tree4898afd044ed6f78c61dd446f337f0a38973f1cd
parent5e763127af804b98ee8888856d4c9dad4419231d (diff)
nir: Add support for emulating border color.
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
-rw-r--r--src/compiler/nir/nir.h15
-rw-r--r--src/compiler/nir/nir_lower_tex.c110
-rw-r--r--src/mesa/program/prog_statevars.c96
-rw-r--r--src/mesa/program/prog_statevars.h2
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;