+
+ /* some advanced gather instructions (txgo) would require 4 offsets */
+ if (inst->Texture.NumOffsets == 1) {
+ unsigned dim;
+ for (dim = 0; dim < num_offsets; dim++) {
+ offsets[dim] = lp_build_emit_fetch_texoffset(&bld->bld_base, inst, 0, dim);
+ }
+ }
+
+ bld->sampler->emit_fetch_texel(bld->sampler,
+ bld->bld_base.base.gallivm,
+ bld->bld_base.base.type,
+ FALSE,
+ unit, unit,
+ coords,
+ offsets,
+ deriv_ptr,
+ lod_bias, explicit_lod, lod_property,
+ texel);
+}
+
+static void
+emit_sample(struct lp_build_tgsi_soa_context *bld,
+ const struct tgsi_full_instruction *inst,
+ enum lp_build_tex_modifier modifier,
+ boolean compare,
+ LLVMValueRef *texel)
+{
+ struct gallivm_state *gallivm = bld->bld_base.base.gallivm;
+ unsigned texture_unit, sampler_unit;
+ LLVMValueRef lod_bias, explicit_lod;
+ LLVMValueRef coords[5];
+ LLVMValueRef offsets[3] = { NULL };
+ struct lp_derivatives derivs;
+ struct lp_derivatives *deriv_ptr = NULL;
+ enum lp_sampler_lod_property lod_property = LP_SAMPLER_LOD_SCALAR;
+
+ unsigned num_offsets, num_derivs, i;
+ unsigned layer_coord = 0;
+
+ if (!bld->sampler) {
+ _debug_printf("warning: found texture instruction but no sampler generator supplied\n");
+ for (i = 0; i < 4; i++) {
+ texel[i] = bld->bld_base.base.undef;
+ }
+ return;
+ }
+
+ /*
+ * unlike old-style tex opcodes the texture/sampler indices
+ * always come from src1 and src2 respectively.
+ */
+ texture_unit = inst->Src[1].Register.Index;
+ sampler_unit = inst->Src[2].Register.Index;
+
+ /*
+ * Note inst->Texture.Texture will contain the number of offsets,
+ * however the target information is NOT there and comes from the
+ * declared sampler views instead.
+ */
+ switch (bld->sv[texture_unit].Resource) {
+ case TGSI_TEXTURE_1D:
+ num_offsets = 1;
+ num_derivs = 1;
+ break;
+ case TGSI_TEXTURE_1D_ARRAY:
+ layer_coord = 1;
+ num_offsets = 1;
+ num_derivs = 1;
+ break;
+ case TGSI_TEXTURE_2D:
+ case TGSI_TEXTURE_RECT:
+ num_offsets = 2;
+ num_derivs = 2;
+ break;
+ case TGSI_TEXTURE_2D_ARRAY:
+ layer_coord = 2;
+ num_offsets = 2;
+ num_derivs = 2;
+ break;
+ case TGSI_TEXTURE_CUBE:
+ num_offsets = 2;
+ num_derivs = 3;
+ break;
+ case TGSI_TEXTURE_3D:
+ num_offsets = 3;
+ num_derivs = 3;
+ break;
+ case TGSI_TEXTURE_CUBE_ARRAY:
+ layer_coord = 3;
+ num_offsets = 2;
+ num_derivs = 3;
+ break;
+ default:
+ assert(0);
+ return;
+ }
+
+ if (modifier == LP_BLD_TEX_MODIFIER_LOD_BIAS ||
+ modifier == LP_BLD_TEX_MODIFIER_EXPLICIT_LOD) {
+ LLVMValueRef lod = lp_build_emit_fetch(&bld->bld_base, inst, 3, 0);
+ if (modifier == LP_BLD_TEX_MODIFIER_LOD_BIAS) {
+ lod_bias = lod;
+ explicit_lod = NULL;
+ }
+ else if (modifier == LP_BLD_TEX_MODIFIER_EXPLICIT_LOD) {
+ lod_bias = NULL;
+ explicit_lod = lod;
+ }
+ lod_property = lp_build_lod_property(&bld->bld_base, inst, 0);
+ }
+ else if (modifier == LP_BLD_TEX_MODIFIER_LOD_ZERO) {
+ lod_bias = NULL;
+ /* XXX might be better to explicitly pass the level zero information */
+ explicit_lod = lp_build_const_vec(gallivm, bld->bld_base.base.type, 0.0F);
+ }
+ else {
+ lod_bias = NULL;
+ explicit_lod = NULL;
+ }
+
+ for (i = 0; i < num_derivs; i++) {
+ coords[i] = lp_build_emit_fetch(&bld->bld_base, inst, 0, i);
+ }
+ for (i = num_derivs; i < 5; i++) {
+ coords[i] = bld->bld_base.base.undef;
+ }
+
+ /* Layer coord always goes into 3rd slot, except for cube map arrays */
+ if (layer_coord) {
+ if (layer_coord == 3)
+ coords[3] = lp_build_emit_fetch(&bld->bld_base, inst, 0, layer_coord);
+ else
+ coords[2] = lp_build_emit_fetch(&bld->bld_base, inst, 0, layer_coord);
+ }
+ /* Shadow coord occupies always 5th slot. */
+ if (compare) {
+ coords[4] = lp_build_emit_fetch(&bld->bld_base, inst, 3, 0);
+ }
+
+ if (modifier == LP_BLD_TEX_MODIFIER_EXPLICIT_DERIV) {
+ unsigned dim;
+ for (dim = 0; dim < num_derivs; ++dim) {
+ derivs.ddx[dim] = lp_build_emit_fetch(&bld->bld_base, inst, 3, dim);
+ derivs.ddy[dim] = lp_build_emit_fetch(&bld->bld_base, inst, 4, dim);
+ }
+ deriv_ptr = &derivs;
+ /*
+ * could also check all src regs if constant but I doubt such
+ * cases exist in practice.
+ */
+ if (bld->bld_base.info->processor == TGSI_PROCESSOR_FRAGMENT) {
+ if (gallivm_debug & GALLIVM_DEBUG_NO_QUAD_LOD) {
+ lod_property = LP_SAMPLER_LOD_PER_ELEMENT;
+ }
+ else {
+ lod_property = LP_SAMPLER_LOD_PER_QUAD;
+ }
+ }
+ else {
+ lod_property = LP_SAMPLER_LOD_PER_ELEMENT;
+ }
+ }
+
+ /* some advanced gather instructions (txgo) would require 4 offsets */
+ if (inst->Texture.NumOffsets == 1) {
+ unsigned dim;
+ for (dim = 0; dim < num_offsets; dim++) {
+ offsets[dim] = lp_build_emit_fetch_texoffset(&bld->bld_base, inst, 0, dim);
+ }
+ }
+
+ bld->sampler->emit_fetch_texel(bld->sampler,
+ bld->bld_base.base.gallivm,
+ bld->bld_base.base.type,
+ FALSE,
+ texture_unit, sampler_unit,
+ coords,
+ offsets,
+ deriv_ptr,
+ lod_bias, explicit_lod, lod_property,
+ texel);
+
+ if (inst->Src[1].Register.SwizzleX != PIPE_SWIZZLE_RED ||
+ inst->Src[1].Register.SwizzleY != PIPE_SWIZZLE_GREEN ||
+ inst->Src[1].Register.SwizzleZ != PIPE_SWIZZLE_BLUE ||
+ inst->Src[1].Register.SwizzleW != PIPE_SWIZZLE_ALPHA) {
+ unsigned char swizzles[4];
+ 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;
+
+ lp_build_swizzle_soa_inplace(&bld->bld_base.base, texel, swizzles);
+ }
+}
+
+static void
+emit_fetch_texels( struct lp_build_tgsi_soa_context *bld,
+ const struct tgsi_full_instruction *inst,
+ LLVMValueRef *texel,
+ boolean is_samplei)
+{
+ unsigned unit, target;
+ LLVMValueRef coord_undef = LLVMGetUndef(bld->bld_base.base.int_vec_type);
+ LLVMValueRef explicit_lod = NULL;
+ LLVMValueRef coords[3];
+ LLVMValueRef offsets[3] = { NULL };
+ enum lp_sampler_lod_property lod_property = LP_SAMPLER_LOD_SCALAR;
+ unsigned dims, i;
+ unsigned layer_coord = 0;
+
+ if (!bld->sampler) {
+ _debug_printf("warning: found texture instruction but no sampler generator supplied\n");
+ for (i = 0; i < 4; i++) {
+ texel[i] = coord_undef;
+ }
+ return;
+ }
+
+ unit = inst->Src[1].Register.Index;
+
+ if (is_samplei) {
+ target = bld->sv[unit].Resource;
+ }
+ else {
+ target = inst->Texture.Texture;
+ }
+
+ switch (target) {
+ case TGSI_TEXTURE_1D:
+ case TGSI_TEXTURE_BUFFER:
+ dims = 1;
+ break;
+ case TGSI_TEXTURE_1D_ARRAY:
+ layer_coord = 1;
+ dims = 1;
+ break;
+ case TGSI_TEXTURE_2D:
+ case TGSI_TEXTURE_RECT:
+ dims = 2;
+ break;
+ case TGSI_TEXTURE_2D_ARRAY:
+ layer_coord = 2;
+ dims = 2;
+ break;
+ case TGSI_TEXTURE_3D:
+ dims = 3;
+ break;
+ default:
+ assert(0);
+ return;
+ }
+
+ /* always have lod except for buffers ? */
+ if (target != TGSI_TEXTURE_BUFFER) {
+ explicit_lod = lp_build_emit_fetch(&bld->bld_base, inst, 0, 3);
+ lod_property = lp_build_lod_property(&bld->bld_base, inst, 0);
+ }
+
+ for (i = 0; i < dims; i++) {
+ coords[i] = lp_build_emit_fetch(&bld->bld_base, inst, 0, i);
+ }
+ for (i = dims; i < 3; i++) {
+ coords[i] = coord_undef;
+ }
+ if (layer_coord)
+ coords[2] = lp_build_emit_fetch(&bld->bld_base, inst, 0, layer_coord);
+
+ if (inst->Texture.NumOffsets == 1) {
+ unsigned dim;
+ for (dim = 0; dim < dims; dim++) {
+ offsets[dim] = lp_build_emit_fetch_texoffset(&bld->bld_base, inst, 0, dim);
+ }