{
LLVMTargetDataRef target = gallivm->target;
LLVMTypeRef float_type = LLVMFloatTypeInContext(gallivm->context);
+ LLVMTypeRef int_type = LLVMInt32TypeInContext(gallivm->context);
LLVMTypeRef elem_types[DRAW_JIT_CTX_NUM_FIELDS];
LLVMTypeRef context_type;
elem_types[0] = LLVMArrayType(LLVMPointerType(float_type, 0), /* vs_constants */
LP_MAX_TGSI_CONST_BUFFERS);
- elem_types[1] = LLVMPointerType(LLVMArrayType(LLVMArrayType(float_type, 4),
+ elem_types[1] = LLVMArrayType(int_type, /* num_vs_constants */
+ LP_MAX_TGSI_CONST_BUFFERS);
+ elem_types[2] = LLVMPointerType(LLVMArrayType(LLVMArrayType(float_type, 4),
DRAW_TOTAL_CLIP_PLANES), 0);
- elem_types[2] = LLVMPointerType(float_type, 0); /* viewport */
- elem_types[3] = LLVMArrayType(texture_type,
+ elem_types[3] = LLVMPointerType(float_type, 0); /* viewport */
+ elem_types[4] = LLVMArrayType(texture_type,
PIPE_MAX_SHADER_SAMPLER_VIEWS); /* textures */
- elem_types[4] = LLVMArrayType(sampler_type,
+ elem_types[5] = LLVMArrayType(sampler_type,
PIPE_MAX_SAMPLERS); /* samplers */
context_type = LLVMStructTypeInContext(gallivm->context, elem_types,
Elements(elem_types), 0);
LP_CHECK_MEMBER_OFFSET(struct draw_jit_context, vs_constants,
target, context_type, DRAW_JIT_CTX_CONSTANTS);
+ LP_CHECK_MEMBER_OFFSET(struct draw_jit_context, num_vs_constants,
+ target, context_type, DRAW_JIT_CTX_NUM_CONSTANTS);
LP_CHECK_MEMBER_OFFSET(struct draw_jit_context, planes,
target, context_type, DRAW_JIT_CTX_PLANES);
LP_CHECK_MEMBER_OFFSET(struct draw_jit_context, viewport,
elem_types[0] = LLVMArrayType(LLVMPointerType(float_type, 0), /* constants */
LP_MAX_TGSI_CONST_BUFFERS);
- elem_types[1] = LLVMPointerType(LLVMArrayType(LLVMArrayType(float_type, 4),
+ elem_types[1] = LLVMArrayType(int_type, /* num_constants */
+ LP_MAX_TGSI_CONST_BUFFERS);
+ elem_types[2] = LLVMPointerType(LLVMArrayType(LLVMArrayType(float_type, 4),
DRAW_TOTAL_CLIP_PLANES), 0);
- elem_types[2] = LLVMPointerType(float_type, 0); /* viewport */
+ elem_types[3] = LLVMPointerType(float_type, 0); /* viewport */
- elem_types[3] = LLVMArrayType(texture_type,
+ elem_types[4] = LLVMArrayType(texture_type,
PIPE_MAX_SHADER_SAMPLER_VIEWS); /* textures */
- elem_types[4] = LLVMArrayType(sampler_type,
+ elem_types[5] = LLVMArrayType(sampler_type,
PIPE_MAX_SAMPLERS); /* samplers */
- elem_types[5] = LLVMPointerType(LLVMPointerType(int_type, 0), 0);
- elem_types[6] = LLVMPointerType(LLVMVectorType(int_type,
- vector_length), 0);
+ elem_types[6] = LLVMPointerType(LLVMPointerType(int_type, 0), 0);
elem_types[7] = LLVMPointerType(LLVMVectorType(int_type,
vector_length), 0);
+ elem_types[8] = LLVMPointerType(LLVMVectorType(int_type,
+ vector_length), 0);
context_type = LLVMStructTypeInContext(gallivm->context, elem_types,
Elements(elem_types), 0);
LP_CHECK_MEMBER_OFFSET(struct draw_gs_jit_context, constants,
target, context_type, DRAW_GS_JIT_CTX_CONSTANTS);
+ LP_CHECK_MEMBER_OFFSET(struct draw_gs_jit_context, num_constants,
+ target, context_type, DRAW_GS_JIT_CTX_NUM_CONSTANTS);
LP_CHECK_MEMBER_OFFSET(struct draw_gs_jit_context, planes,
target, context_type, DRAW_GS_JIT_CTX_PLANES);
LP_CHECK_MEMBER_OFFSET(struct draw_gs_jit_context, viewport,
{
struct draw_llvm *llvm = variant->llvm;
const struct tgsi_token *tokens = llvm->draw->vs.vertex_shader->state.tokens;
- LLVMValueRef consts_ptr = draw_jit_context_vs_constants(variant->gallivm, context_ptr);
+ LLVMValueRef consts_ptr =
+ draw_jit_context_vs_constants(variant->gallivm, context_ptr);
+ LLVMValueRef num_consts_ptr =
+ draw_jit_context_num_vs_constants(variant->gallivm, context_ptr);
struct lp_build_sampler_soa *sampler = 0;
if (gallivm_debug & (GALLIVM_DEBUG_TGSI | GALLIVM_DEBUG_IR)) {
vs_type,
NULL /*struct lp_build_mask_context *mask*/,
consts_ptr,
+ num_consts_ptr,
system_values,
inputs,
outputs,
unsigned i;
struct draw_gs_llvm_iface gs_iface;
const struct tgsi_token *tokens = variant->shader->base.state.tokens;
- LLVMValueRef consts_ptr;
+ LLVMValueRef consts_ptr, num_consts_ptr;
LLVMValueRef outputs[PIPE_MAX_SHADER_OUTPUTS][TGSI_NUM_CHANNELS];
struct lp_build_mask_context mask;
const struct tgsi_shader_info *gs_info = &variant->shader->base.info;
gs_type.length = vector_length;
consts_ptr = draw_gs_jit_context_constants(variant->gallivm, context_ptr);
+ num_consts_ptr =
+ draw_gs_jit_context_num_constants(variant->gallivm, context_ptr);
/* code generated texture sampling */
sampler = draw_llvm_sampler_soa_create(variant->key.samplers,
gs_type,
&mask,
consts_ptr,
+ num_consts_ptr,
&system_values,
NULL,
outputs,
struct draw_jit_context
{
const float *vs_constants[LP_MAX_TGSI_CONST_BUFFERS];
+ int num_vs_constants[LP_MAX_TGSI_CONST_BUFFERS];
float (*planes) [DRAW_TOTAL_CLIP_PLANES][4];
float *viewport;
};
enum {
- DRAW_JIT_CTX_CONSTANTS = 0,
- DRAW_JIT_CTX_PLANES = 1,
- DRAW_JIT_CTX_VIEWPORT = 2,
- DRAW_JIT_CTX_TEXTURES = 3,
- DRAW_JIT_CTX_SAMPLERS = 4,
+ DRAW_JIT_CTX_CONSTANTS = 0,
+ DRAW_JIT_CTX_NUM_CONSTANTS = 1,
+ DRAW_JIT_CTX_PLANES = 2,
+ DRAW_JIT_CTX_VIEWPORT = 3,
+ DRAW_JIT_CTX_TEXTURES = 4,
+ DRAW_JIT_CTX_SAMPLERS = 5,
DRAW_JIT_CTX_NUM_FIELDS
};
#define draw_jit_context_vs_constants(_gallivm, _ptr) \
lp_build_struct_get_ptr(_gallivm, _ptr, DRAW_JIT_CTX_CONSTANTS, "vs_constants")
+#define draw_jit_context_num_vs_constants(_gallivm, _ptr) \
+ lp_build_struct_get_ptr(_gallivm, _ptr, DRAW_JIT_CTX_NUM_CONSTANTS, "num_vs_constants")
+
#define draw_jit_context_planes(_gallivm, _ptr) \
lp_build_struct_get(_gallivm, _ptr, DRAW_JIT_CTX_PLANES, "planes")
struct draw_gs_jit_context
{
const float *constants[LP_MAX_TGSI_CONST_BUFFERS];
+ int num_constants[LP_MAX_TGSI_CONST_BUFFERS];
float (*planes) [DRAW_TOTAL_CLIP_PLANES][4];
float *viewport;
enum {
DRAW_GS_JIT_CTX_CONSTANTS = 0,
- DRAW_GS_JIT_CTX_PLANES = 1,
- DRAW_GS_JIT_CTX_VIEWPORT = 2,
+ DRAW_GS_JIT_CTX_NUM_CONSTANTS = 1,
+ DRAW_GS_JIT_CTX_PLANES = 2,
+ DRAW_GS_JIT_CTX_VIEWPORT = 3,
/* Textures and samples are reserved for DRAW_JIT_CTX_TEXTURES
* and DRAW_JIT_CTX_SAMPLERS, because they both need
* to be at exactly the same locations as they are in the
* VS ctx structure for sampling to work. */
DRAW_GS_JIT_CTX_TEXTURES = DRAW_JIT_CTX_TEXTURES,
DRAW_GS_JIT_CTX_SAMPLERS = DRAW_JIT_CTX_SAMPLERS,
- DRAW_GS_JIT_CTX_PRIM_LENGTHS = 5,
- DRAW_GS_JIT_CTX_EMITTED_VERTICES = 6,
- DRAW_GS_JIT_CTX_EMITTED_PRIMS = 7,
- DRAW_GS_JIT_CTX_NUM_FIELDS = 8
+ DRAW_GS_JIT_CTX_PRIM_LENGTHS = 6,
+ DRAW_GS_JIT_CTX_EMITTED_VERTICES = 7,
+ DRAW_GS_JIT_CTX_EMITTED_PRIMS = 8,
+ DRAW_GS_JIT_CTX_NUM_FIELDS = 9
};
#define draw_gs_jit_context_constants(_gallivm, _ptr) \
lp_build_struct_get_ptr(_gallivm, _ptr, DRAW_GS_JIT_CTX_CONSTANTS, "constants")
+#define draw_gs_jit_context_num_constants(_gallivm, _ptr) \
+ lp_build_struct_get_ptr(_gallivm, _ptr, DRAW_GS_JIT_CTX_NUM_CONSTANTS, "num_constants")
+
#define draw_gs_jit_context_planes(_gallivm, _ptr) \
lp_build_struct_get(_gallivm, _ptr, DRAW_GS_JIT_CTX_PLANES, "planes")
unsigned i;
for (i = 0; i < Elements(fpme->llvm->jit_context.vs_constants); ++i) {
+ int num_consts =
+ draw->pt.user.vs_constants_size[i] / (sizeof(float) * 4);
fpme->llvm->jit_context.vs_constants[i] = draw->pt.user.vs_constants[i];
+ fpme->llvm->jit_context.num_vs_constants[i] = num_consts;
}
for (i = 0; i < Elements(fpme->llvm->gs_jit_context.constants); ++i) {
+ int num_consts =
+ draw->pt.user.gs_constants_size[i] / (sizeof(float) * 4);
fpme->llvm->gs_jit_context.constants[i] = draw->pt.user.gs_constants[i];
+ fpme->llvm->gs_jit_context.num_constants[i] = num_consts;
}
fpme->llvm->jit_context.planes =
struct lp_type type,
struct lp_build_mask_context *mask,
LLVMValueRef consts_ptr,
+ LLVMValueRef const_sizes_ptr,
const struct lp_bld_tgsi_system_values *system_values,
const LLVMValueRef (*inputs)[4],
LLVMValueRef (*outputs)[4],
LLVMValueRef max_output_vertices_vec;
LLVMValueRef consts_ptr;
+ LLVMValueRef const_sizes_ptr;
const LLVMValueRef (*inputs)[TGSI_NUM_CHANNELS];
LLVMValueRef (*outputs)[TGSI_NUM_CHANNELS];
static LLVMValueRef
build_gather(struct lp_build_context *bld,
LLVMValueRef base_ptr,
- LLVMValueRef indexes)
+ LLVMValueRef indexes,
+ LLVMValueRef *overflow_mask)
{
LLVMBuilderRef builder = bld->gallivm->builder;
LLVMValueRef res = bld->undef;
unsigned i;
+ LLVMValueRef temp_ptr;
+
+ if (overflow_mask) {
+ temp_ptr = lp_build_alloca(
+ bld->gallivm,
+ lp_build_vec_type(bld->gallivm, bld->type), "");
+ }
/*
* Loop over elements of index_vec, load scalar value, insert it into 'res'.
LLVMValueRef ii = lp_build_const_int32(bld->gallivm, i);
LLVMValueRef index = LLVMBuildExtractElement(builder,
indexes, ii, "");
- LLVMValueRef scalar_ptr = LLVMBuildGEP(builder, base_ptr,
- &index, 1, "gather_ptr");
- LLVMValueRef scalar = LLVMBuildLoad(builder, scalar_ptr, "");
+ LLVMValueRef scalar_ptr, scalar;
+ LLVMValueRef overflow;
+ struct lp_build_if_state if_ctx;
+
+ /*
+ * overflow_mask is a boolean vector telling us which channels
+ * in the vector overflowed. We use the overflow behavior for
+ * constant buffers which is defined as:
+ * Out of bounds access to constant buffer returns 0 in all
+ * componenets. Out of bounds behavior is always with respect
+ * to the size of the buffer bound at that slot.
+ */
+ if (overflow_mask) {
+ overflow = LLVMBuildExtractElement(builder, *overflow_mask,
+ ii, "");
+ lp_build_if(&if_ctx, bld->gallivm, overflow);
+ {
+ LLVMValueRef val = LLVMBuildLoad(builder, temp_ptr, "");
+ val = LLVMBuildInsertElement(
+ builder, val,
+ LLVMConstNull(LLVMFloatTypeInContext(bld->gallivm->context)),
+ ii, "");
+ LLVMBuildStore(builder, val, temp_ptr);
+ }
+ lp_build_else(&if_ctx);
+ {
+ LLVMValueRef val = LLVMBuildLoad(builder, temp_ptr, "");
+
+ scalar_ptr = LLVMBuildGEP(builder, base_ptr,
+ &index, 1, "gather_ptr");
+ scalar = LLVMBuildLoad(builder, scalar_ptr, "");
+
+ val = LLVMBuildInsertElement(builder, val, scalar, ii, "");
- res = LLVMBuildInsertElement(builder, res, scalar, ii, "");
+ LLVMBuildStore(builder, val, temp_ptr);
+ }
+ lp_build_endif(&if_ctx);
+ } else {
+ scalar_ptr = LLVMBuildGEP(builder, base_ptr,
+ &index, 1, "gather_ptr");
+ scalar = LLVMBuildLoad(builder, scalar_ptr, "");
+
+ res = LLVMBuildInsertElement(builder, res, scalar, ii, "");
+ }
+ }
+
+ if (overflow_mask) {
+ res = LLVMBuildLoad(builder, temp_ptr, "gather_val");
}
return res;
index = lp_build_add(uint_bld, base, rel);
- max_index = lp_build_const_int_vec(bld->bld_base.base.gallivm,
- uint_bld->type,
- bld->bld_base.info->file_max[reg_file]);
+ /*
+ * emit_fetch_constant handles constant buffer overflow so this code
+ * is pointless for them.
+ * Furthermore the D3D10 spec in section 6.5 says:
+ * If the constant buffer bound to a slot is larger than the size
+ * declared in the shader for that slot, implementations are allowed
+ * to return incorrect data (not necessarily 0) for indices that are
+ * larger than the declared size but smaller than the buffer size.
+ */
+ if (reg_file != TGSI_FILE_CONSTANT) {
+ max_index = lp_build_const_int_vec(bld->bld_base.base.gallivm,
+ uint_bld->type,
+ bld->bld_base.info->file_max[reg_file]);
- assert(!uint_bld->type.sign);
- index = lp_build_min(uint_bld, index, max_index);
+ assert(!uint_bld->type.sign);
+ index = lp_build_min(uint_bld, index, max_index);
+ }
return index;
}
unsigned dimension = 0;
LLVMValueRef dimension_index;
LLVMValueRef consts_ptr;
+ LLVMValueRef num_consts;
LLVMValueRef res;
/* XXX: Handle fetching xyzw components as a vector */
}
dimension_index = lp_build_const_int32(gallivm, dimension);
- consts_ptr = lp_build_array_get(gallivm, bld->consts_ptr, dimension_index);
+ consts_ptr =
+ lp_build_array_get(gallivm, bld->consts_ptr, dimension_index);
+ num_consts =
+ lp_build_array_get(gallivm, bld->const_sizes_ptr, dimension_index);
if (reg->Register.Indirect) {
LLVMValueRef indirect_index;
LLVMValueRef swizzle_vec =
lp_build_const_int_vec(gallivm, uint_bld->type, swizzle);
LLVMValueRef index_vec; /* index into the const buffer */
+ LLVMValueRef overflow_mask;
indirect_index = get_indirect_index(bld,
reg->Register.File,
reg->Register.Index,
®->Indirect);
+ /* All fetches are from the same constant buffer, so
+ * we need to propagate the size to a vector to do a
+ * vector comparison */
+ num_consts = lp_build_broadcast_scalar(uint_bld, num_consts);
+ /* Construct a boolean vector telling us which channels
+ * overflow the bound constant buffer */
+ overflow_mask = LLVMBuildICmp(builder, LLVMIntUGE,
+ indirect_index,
+ num_consts, "");
+
/* index_vec = indirect_index * 4 + swizzle */
index_vec = lp_build_shl_imm(uint_bld, indirect_index, 2);
index_vec = lp_build_add(uint_bld, index_vec, swizzle_vec);
/* Gather values from the constant buffer */
- res = build_gather(&bld_base->base, consts_ptr, index_vec);
+ res = build_gather(&bld_base->base, consts_ptr, index_vec,
+ &overflow_mask);
}
else {
LLVMValueRef index; /* index into the const buffer */
struct lp_build_context *bld_fetch = stype_to_fetch(bld_base, stype);
res = LLVMBuildBitCast(builder, res, bld_fetch->vec_type, "");
}
+
return res;
}
imms_array = LLVMBuildBitCast(builder, bld->imms_array, fptr_type, "");
/* Gather values from the immediate register array */
- res = build_gather(&bld_base->base, imms_array, index_vec);
+ res = build_gather(&bld_base->base, imms_array, index_vec, NULL);
}
else {
res = bld->immediates[reg->Register.Index][swizzle];
inputs_array = LLVMBuildBitCast(builder, bld->inputs_array, fptr_type, "");
/* Gather values from the input register array */
- res = build_gather(&bld_base->base, inputs_array, index_vec);
+ res = build_gather(&bld_base->base, inputs_array, index_vec, NULL);
} else {
if (bld->indirect_files & (1 << TGSI_FILE_INPUT)) {
LLVMValueRef lindex = lp_build_const_int32(gallivm,
temps_array = LLVMBuildBitCast(builder, bld->temps_array, fptr_type, "");
/* Gather values from the temporary register array */
- res = build_gather(&bld_base->base, temps_array, index_vec);
+ res = build_gather(&bld_base->base, temps_array, index_vec, NULL);
}
else {
LLVMValueRef temp_ptr;
struct lp_type type,
struct lp_build_mask_context *mask,
LLVMValueRef consts_ptr,
+ LLVMValueRef const_sizes_ptr,
const struct lp_bld_tgsi_system_values *system_values,
const LLVMValueRef (*inputs)[TGSI_NUM_CHANNELS],
LLVMValueRef (*outputs)[TGSI_NUM_CHANNELS],
bld.inputs = inputs;
bld.outputs = outputs;
bld.consts_ptr = consts_ptr;
+ bld.const_sizes_ptr = const_sizes_ptr;
bld.sampler = sampler;
bld.bld_base.info = info;
bld.indirect_files = info->indirect_files;
LLVMTypeRef context_type;
elem_types[LP_JIT_CTX_CONSTANTS] =
- LLVMArrayType(LLVMPointerType(LLVMFloatTypeInContext(lc), 0), LP_MAX_TGSI_CONST_BUFFERS);
+ LLVMArrayType(LLVMPointerType(LLVMFloatTypeInContext(lc), 0), LP_MAX_TGSI_CONST_BUFFERS);
+ elem_types[LP_JIT_CTX_NUM_CONSTANTS] =
+ LLVMArrayType(LLVMInt32TypeInContext(lc), LP_MAX_TGSI_CONST_BUFFERS);
elem_types[LP_JIT_CTX_ALPHA_REF] = LLVMFloatTypeInContext(lc);
elem_types[LP_JIT_CTX_STENCIL_REF_FRONT] =
elem_types[LP_JIT_CTX_STENCIL_REF_BACK] = LLVMInt32TypeInContext(lc);
LP_CHECK_MEMBER_OFFSET(struct lp_jit_context, constants,
gallivm->target, context_type,
LP_JIT_CTX_CONSTANTS);
+ LP_CHECK_MEMBER_OFFSET(struct lp_jit_context, num_constants,
+ gallivm->target, context_type,
+ LP_JIT_CTX_NUM_CONSTANTS);
LP_CHECK_MEMBER_OFFSET(struct lp_jit_context, alpha_ref_value,
gallivm->target, context_type,
LP_JIT_CTX_ALPHA_REF);
struct lp_jit_context
{
const float *constants[LP_MAX_TGSI_CONST_BUFFERS];
+ int num_constants[LP_MAX_TGSI_CONST_BUFFERS];
float alpha_ref_value;
*/
enum {
LP_JIT_CTX_CONSTANTS = 0,
+ LP_JIT_CTX_NUM_CONSTANTS,
LP_JIT_CTX_ALPHA_REF,
LP_JIT_CTX_STENCIL_REF_FRONT,
LP_JIT_CTX_STENCIL_REF_BACK,
#define lp_jit_context_constants(_gallivm, _ptr) \
lp_build_struct_get_ptr(_gallivm, _ptr, LP_JIT_CTX_CONSTANTS, "constants")
+#define lp_jit_context_num_constants(_gallivm, _ptr) \
+ lp_build_struct_get_ptr(_gallivm, _ptr, LP_JIT_CTX_NUM_CONSTANTS, "num_constants")
+
#define lp_jit_context_alpha_ref_value(_gallivm, _ptr) \
lp_build_struct_get(_gallivm, _ptr, LP_JIT_CTX_ALPHA_REF, "alpha_ref_value")
struct pipe_resource *buffer = setup->constants[i].current.buffer;
const unsigned current_size = setup->constants[i].current.buffer_size;
const ubyte *current_data = NULL;
+ int num_constants;
if (buffer) {
/* resource buffer */
setup->constants[i].stored_data = NULL;
}
- setup->fs.current.jit_context.constants[i] = setup->constants[i].stored_data;
+ setup->fs.current.jit_context.constants[i] =
+ setup->constants[i].stored_data;
+ num_constants =
+ setup->constants[i].stored_size / (sizeof(float) * 4);
+ setup->fs.current.jit_context.num_constants[i] = num_constants;
setup->dirty |= LP_SETUP_NEW_FS;
}
}
const struct tgsi_token *tokens = shader->base.tokens;
LLVMTypeRef vec_type;
LLVMValueRef mask_ptr, mask_val;
- LLVMValueRef consts_ptr;
+ LLVMValueRef consts_ptr, num_consts_ptr;
LLVMValueRef z;
LLVMValueRef z_value, s_value;
LLVMValueRef z_fb, s_fb;
vec_type = lp_build_vec_type(gallivm, type);
consts_ptr = lp_jit_context_constants(gallivm, context_ptr);
+ num_consts_ptr = lp_jit_context_num_constants(gallivm, context_ptr);
lp_build_for_loop_begin(&loop_state, gallivm,
lp_build_const_int32(gallivm, 0),
/* Build the actual shader */
lp_build_tgsi_soa(gallivm, tokens, type, &mask,
- consts_ptr, &system_values,
+ consts_ptr, num_consts_ptr, &system_values,
interp->inputs,
outputs, sampler, &shader->info.base, NULL);