---
src/gallium/auxiliary/gallivm/lp_bld_tgsi_soa.c | 14 ++++++++
src/gallium/auxiliary/tgsi/tgsi_exec.c | 48 ++++++++++++++++++++++---
src/gallium/auxiliary/tgsi/tgsi_info_opcodes.h | 1 +
src/gallium/docs/source/tgsi.rst | 12 +++++++
src/gallium/include/pipe/p_shader_tokens.h | 4 ++-
5 files changed, 74 insertions(+), 5 deletions(-)
diff --git a/src/gallium/auxiliary/gallivm/lp_bld_tgsi_soa.c
b/src/gallium/auxiliary/gallivm/lp_bld_tgsi_soa.c
index 3e47372..fe0068b 100644
--- a/src/gallium/auxiliary/gallivm/lp_bld_tgsi_soa.c
+++ b/src/gallium/auxiliary/gallivm/lp_bld_tgsi_soa.c
@@ -3285,6 +3285,18 @@ sviewinfo_emit(
emit_size_query(bld, emit_data->inst, emit_data->output, TRUE);
}
+static void
+lod_emit(
+ const struct lp_build_tgsi_action * action,
+ struct lp_build_tgsi_context * bld_base,
+ struct lp_build_emit_data * emit_data)
+{
+ struct lp_build_tgsi_soa_context * bld = lp_soa_context(bld_base);
+
+ emit_sample(bld, emit_data->inst, LP_BLD_TEX_MODIFIER_NONE,
+ FALSE, LP_SAMPLER_OP_LODQ, emit_data->output);
+}
+
static LLVMValueRef
mask_vec(struct lp_build_tgsi_context *bld_base)
{
@@ -3899,6 +3911,8 @@ lp_build_tgsi_soa(struct gallivm_state *gallivm,
bld.bld_base.op_actions[TGSI_OPCODE_SAMPLE_L].emit = sample_l_emit;
bld.bld_base.op_actions[TGSI_OPCODE_GATHER4].emit = gather4_emit;
bld.bld_base.op_actions[TGSI_OPCODE_SVIEWINFO].emit = sviewinfo_emit;
+ bld.bld_base.op_actions[TGSI_OPCODE_LOD].emit = lod_emit;
+
if (gs_iface) {
/* There's no specific value for this because it should always
diff --git a/src/gallium/auxiliary/tgsi/tgsi_exec.c
b/src/gallium/auxiliary/tgsi/tgsi_exec.c
index 1264df0..4257a60 100644
--- a/src/gallium/auxiliary/tgsi/tgsi_exec.c
+++ b/src/gallium/auxiliary/tgsi/tgsi_exec.c
@@ -2340,15 +2340,22 @@ static void
exec_lodq(struct tgsi_exec_machine *mach,
const struct tgsi_full_instruction *inst)
{
- uint unit;
+ uint resource_unit, sampler_unit;
int dim;
int i;
union tgsi_exec_channel coords[4];
const union tgsi_exec_channel *args[ARRAY_SIZE(coords)];
union tgsi_exec_channel r[2];
- unit = fetch_sampler_unit(mach, inst, 1);
- dim = tgsi_util_get_texture_coord_dim(inst->Texture.Texture);
+ resource_unit = fetch_sampler_unit(mach, inst, 1);
+ if (inst->Instruction.Opcode == TGSI_OPCODE_LOD) {
+ uint target = mach->SamplerViews[resource_unit].Resource;
+ dim = tgsi_util_get_texture_coord_dim(target);
+ sampler_unit = fetch_sampler_unit(mach, inst, 2);
+ } else {
+ dim = tgsi_util_get_texture_coord_dim(inst->Texture.Texture);
+ sampler_unit = resource_unit;
+ }
assert(dim <= ARRAY_SIZE(coords));
/* fetch coordinates */
for (i = 0; i < dim; i++) {
@@ -2358,7 +2365,7 @@ exec_lodq(struct tgsi_exec_machine *mach,
for (i = dim; i < ARRAY_SIZE(coords); i++) {
args[i] = &ZeroVec;
}
- mach->Sampler->query_lod(mach->Sampler, unit, unit,
+ mach->Sampler->query_lod(mach->Sampler, resource_unit, sampler_unit,
args[0]->f,
args[1]->f,
args[2]->f,
@@ -2375,6 +2382,35 @@ exec_lodq(struct tgsi_exec_machine *mach,
store_dest(mach, &r[1], &inst->Dst[0], inst, TGSI_CHAN_Y,
TGSI_EXEC_DATA_FLOAT);
}
+ if (inst->Instruction.Opcode == TGSI_OPCODE_LOD) {
+ unsigned char swizzles[4];
+ unsigned chan;
+ swizzles[0] = inst->Src[1].Register.SwizzleX;
+ swizzles[1] = inst->Src[1].Register.SwizzleY;
+ swizzles[2] = inst->Src[1].Register.SwizzleZ;
+ swizzles[3] = inst->Src[1].Register.SwizzleW;
+
+ for (chan = 0; chan < TGSI_NUM_CHANNELS; chan++) {
+ if (inst->Dst[0].Register.WriteMask & (1 << chan)) {
+ if (swizzles[chan] >= 2) {
+ store_dest(mach, &ZeroVec,
+ &inst->Dst[0], inst, chan, TGSI_EXEC_DATA_FLOAT);
+ } else {
+ store_dest(mach, &r[swizzles[chan]],
+ &inst->Dst[0], inst, chan, TGSI_EXEC_DATA_FLOAT);
+ }
+ }
+ }
+ } else {
+ if (inst->Dst[0].Register.WriteMask & TGSI_WRITEMASK_X) {
+ store_dest(mach, &r[0], &inst->Dst[0], inst, TGSI_CHAN_X,
+ TGSI_EXEC_DATA_FLOAT);
+ }
+ if (inst->Dst[0].Register.WriteMask & TGSI_WRITEMASK_Y) {
+ store_dest(mach, &r[1], &inst->Dst[0], inst, TGSI_CHAN_Y,
+ TGSI_EXEC_DATA_FLOAT);
+ }
+ }
}
static void
@@ -5705,6 +5741,10 @@ exec_instruction(
assert(0);
break;
+ case TGSI_OPCODE_LOD:
+ exec_lodq(mach, inst);
+ break;
+
case TGSI_OPCODE_UARL:
exec_vector_unary(mach, inst, micro_uarl, TGSI_EXEC_DATA_INT,
TGSI_EXEC_DATA_UINT);
break;
diff --git a/src/gallium/auxiliary/tgsi/tgsi_info_opcodes.h
b/src/gallium/auxiliary/tgsi/tgsi_info_opcodes.h
index a4a9771..95a29fd 100644
--- a/src/gallium/auxiliary/tgsi/tgsi_info_opcodes.h
+++ b/src/gallium/auxiliary/tgsi/tgsi_info_opcodes.h
@@ -249,3 +249,4 @@ OPCODE(1, 2, COMP, U64DIV)
OPCODE(1, 2, COMP, I64MOD)
OPCODE(1, 2, COMP, U64MOD)
OPCODE(1, 2, COMP, DDIV)
+OPCODE(1, 3, OTHR, LOD)
diff --git a/src/gallium/docs/source/tgsi.rst b/src/gallium/docs/source/tgsi.rst
index 0bd9964..3f80785 100644
--- a/src/gallium/docs/source/tgsi.rst
+++ b/src/gallium/docs/source/tgsi.rst
@@ -2469,6 +2469,18 @@ after lookup.
NOTE: no driver has implemented this opcode yet (and no state tracker
emits it). This information is subject to change.
+.. opcode:: LOD - level of detail
+
+ Same syntax as the SAMPLE opcode but instead of performing an actual
+ texture lookup/filter, return the computed LOD information that the
+ texture pipe would use to access the texture. The Y component contains
+ the computed LOD lambda_prime. The X component contains the LOD that will
+ be accessed, based on min/max lod's and mipmap filters.
+ The Z and W components are set to 0.
+
+ Syntax: ``LOD dst, address, sampler_view, sampler``
+
+
.. _resourceopcodes:
Resource Access Opcodes
diff --git a/src/gallium/include/pipe/p_shader_tokens.h
b/src/gallium/include/pipe/p_shader_tokens.h
index fa73054..0bb6739 100644
--- a/src/gallium/include/pipe/p_shader_tokens.h
+++ b/src/gallium/include/pipe/p_shader_tokens.h
@@ -607,7 +607,9 @@ struct tgsi_property_data {
#define TGSI_OPCODE_DDIV 248
-#define TGSI_OPCODE_LAST 249
+#define TGSI_OPCODE_LOD 249
+
+#define TGSI_OPCODE_LAST 250
/**
* Opcode is the operation code to execute. A given operation defines the