+static void fs_fb_fetch(const struct lp_build_fs_iface *iface,
+ struct lp_build_context *bld,
+ unsigned cbuf,
+ LLVMValueRef result[4])
+{
+ struct lp_build_fs_llvm_iface *fs_iface = (struct lp_build_fs_llvm_iface *)iface;
+ struct gallivm_state *gallivm = bld->gallivm;
+ LLVMBuilderRef builder = gallivm->builder;
+ const struct lp_fragment_shader_variant_key *key = fs_iface->key;
+ LLVMValueRef index = lp_build_const_int32(gallivm, cbuf);
+ LLVMValueRef color_ptr = LLVMBuildLoad(builder, LLVMBuildGEP(builder, fs_iface->color_ptr_ptr, &index, 1, ""), "");
+ LLVMValueRef stride = LLVMBuildLoad(builder, LLVMBuildGEP(builder, fs_iface->color_stride_ptr, &index, 1, ""), "");
+
+ LLVMValueRef dst[4 * 4];
+ enum pipe_format cbuf_format = key->cbuf_format[cbuf];
+ const struct util_format_description* out_format_desc = util_format_description(cbuf_format);
+ struct lp_type dst_type;
+ unsigned block_size = bld->type.length;
+ unsigned block_height = key->resource_1d ? 1 : 2;
+ unsigned block_width = block_size / block_height;
+
+ lp_mem_type_from_format_desc(out_format_desc, &dst_type);
+
+ struct lp_type blend_type;
+ memset(&blend_type, 0, sizeof blend_type);
+ blend_type.floating = FALSE; /* values are integers */
+ blend_type.sign = FALSE; /* values are unsigned */
+ blend_type.norm = TRUE; /* values are in [0,1] or [-1,1] */
+ blend_type.width = 8; /* 8-bit ubyte values */
+ blend_type.length = 16; /* 16 elements per vector */
+
+ uint32_t dst_alignment;
+ /*
+ * Compute the alignment of the destination pointer in bytes
+ * We fetch 1-4 pixels, if the format has pot alignment then those fetches
+ * are always aligned by MIN2(16, fetch_width) except for buffers (not
+ * 1d tex but can't distinguish here) so need to stick with per-pixel
+ * alignment in this case.
+ */
+ if (key->resource_1d) {
+ dst_alignment = (out_format_desc->block.bits + 7)/(out_format_desc->block.width * 8);
+ }
+ else {
+ dst_alignment = dst_type.length * dst_type.width / 8;
+ }
+ /* Force power-of-two alignment by extracting only the least-significant-bit */
+ dst_alignment = 1 << (ffs(dst_alignment) - 1);
+ /*
+ * Resource base and stride pointers are aligned to 16 bytes, so that's
+ * the maximum alignment we can guarantee
+ */
+ dst_alignment = MIN2(16, dst_alignment);
+
+ LLVMTypeRef blend_vec_type = lp_build_vec_type(gallivm, blend_type);
+ color_ptr = LLVMBuildBitCast(builder, color_ptr, LLVMPointerType(blend_vec_type, 0), "");
+
+ if (key->multisample) {
+ LLVMValueRef sample_stride = LLVMBuildLoad(builder,
+ LLVMBuildGEP(builder, fs_iface->color_sample_stride_ptr,
+ &index, 1, ""), "");
+ LLVMValueRef sample_offset = LLVMBuildMul(builder, sample_stride, fs_iface->sample_id, "");
+ color_ptr = LLVMBuildGEP(builder, color_ptr, &sample_offset, 1, "");
+ }
+ /* fragment shader executes on 4x4 blocks. depending on vector width it can execute 2 or 4 iterations.
+ * only move to the next row once the top row has completed 8 wide 1 iteration, 4 wide 2 iterations */
+ LLVMValueRef x_offset = NULL, y_offset = NULL;
+ if (!key->resource_1d) {
+ LLVMValueRef counter = fs_iface->loop_state->counter;
+
+ if (block_size == 4) {
+ x_offset = LLVMBuildShl(builder,
+ LLVMBuildAnd(builder, fs_iface->loop_state->counter, lp_build_const_int32(gallivm, 1), ""),
+ lp_build_const_int32(gallivm, 1), "");
+ counter = LLVMBuildLShr(builder, fs_iface->loop_state->counter, lp_build_const_int32(gallivm, 1), "");
+ }
+ y_offset = LLVMBuildMul(builder, counter, lp_build_const_int32(gallivm, 2), "");
+ }
+ load_unswizzled_block(gallivm, color_ptr, stride, block_width, block_height, dst, dst_type, block_size, dst_alignment, x_offset, y_offset, true);
+
+ for (unsigned i = 0; i < block_size; i++) {
+ dst[i] = LLVMBuildBitCast(builder, dst[i], LLVMInt32TypeInContext(gallivm->context), "");
+ }
+ LLVMValueRef packed = lp_build_gather_values(gallivm, dst, block_size);
+
+ struct lp_type texel_type = bld->type;
+ if (out_format_desc->colorspace == UTIL_FORMAT_COLORSPACE_RGB &&
+ out_format_desc->channel[0].pure_integer) {
+ if (out_format_desc->channel[0].type == UTIL_FORMAT_TYPE_SIGNED) {
+ texel_type = lp_type_int_vec(bld->type.width, bld->type.width * bld->type.length);
+ }
+ else if (out_format_desc->channel[0].type == UTIL_FORMAT_TYPE_UNSIGNED) {
+ texel_type = lp_type_uint_vec(bld->type.width, bld->type.width * bld->type.length);
+ }
+ }
+ lp_build_unpack_rgba_soa(gallivm, out_format_desc,
+ texel_type,
+ packed, result);
+}
+