We would crash when stride was bigger than the size of the buffer. The correct behavior is to just fetch zero's in this case. Unfortunatly gallium allows user_buffers in vertex_buffers and we can't figure out the sizes of those, so we need to null check the buffer to see if we can at all perform the check.
Signed-off-by: Zack Rusin <za...@vmware.com> --- src/gallium/auxiliary/draw/draw_llvm.c | 145 +++++++++++++++++++++++++++++--- src/gallium/auxiliary/draw/draw_llvm.h | 16 ++++ src/gallium/auxiliary/draw/draw_pt.c | 3 +- 3 files changed, 151 insertions(+), 13 deletions(-) diff --git a/src/gallium/auxiliary/draw/draw_llvm.c b/src/gallium/auxiliary/draw/draw_llvm.c index d2821a1..194854d 100644 --- a/src/gallium/auxiliary/draw/draw_llvm.c +++ b/src/gallium/auxiliary/draw/draw_llvm.c @@ -78,6 +78,58 @@ draw_gs_llvm_iface(const struct lp_build_tgsi_gs_iface *iface) } /** + * Create LLVM type for pipe_resource, which is inside the + * pipe_vertex_buffer + */ +static LLVMTypeRef +create_jit_resource_type(struct gallivm_state *gallivm, + const char *struct_name) +{ + LLVMTargetDataRef target = gallivm->target; + LLVMTypeRef resource_type; + LLVMTypeRef elem_types[DRAW_JIT_RESOURCE_NUM_FIELDS]; + LLVMTypeRef int32_type = LLVMInt32TypeInContext(gallivm->context); + + elem_types[DRAW_JIT_RESOURCE_REFERENCE] = int32_type; + elem_types[DRAW_JIT_RESOURCE_SCREEN] = + LLVMPointerType(LLVMInt8TypeInContext(gallivm->context), 0); + + elem_types[DRAW_JIT_RESOURCE_TARGET] = int32_type; + elem_types[DRAW_JIT_RESOURCE_FORMAT] = int32_type; + elem_types[DRAW_JIT_RESOURCE_WIDTH0] = int32_type; + + resource_type = LLVMStructTypeInContext(gallivm->context, elem_types, + Elements(elem_types), 0); + +#if HAVE_LLVM < 0x0300 + LLVMAddTypeName(gallivm->module, struct_name, resource_type); + + /* Make sure the target's struct layout cache doesn't return + * stale/invalid data. + */ + LLVMInvalidateStructLayout(gallivm->target, resource_type); +#endif + + LP_CHECK_MEMBER_OFFSET(struct pipe_resource, reference, + target, resource_type, + DRAW_JIT_RESOURCE_REFERENCE); + LP_CHECK_MEMBER_OFFSET(struct pipe_resource, screen, + target, resource_type, + DRAW_JIT_RESOURCE_SCREEN); + LP_CHECK_MEMBER_OFFSET(struct pipe_resource, target, + target, resource_type, + DRAW_JIT_RESOURCE_TARGET); + LP_CHECK_MEMBER_OFFSET(struct pipe_resource, format, + target, resource_type, + DRAW_JIT_RESOURCE_FORMAT); + LP_CHECK_MEMBER_OFFSET(struct pipe_resource, width0, + target, resource_type, + DRAW_JIT_RESOURCE_WIDTH0); + + return resource_type; +} + +/** * Create LLVM type for struct draw_jit_texture */ static LLVMTypeRef @@ -328,7 +380,9 @@ create_gs_jit_input_type(struct gallivm_state *gallivm) * Create LLVM type for struct pipe_vertex_buffer */ static LLVMTypeRef -create_jit_vertex_buffer_type(struct gallivm_state *gallivm, const char *struct_name) +create_jit_vertex_buffer_type(struct gallivm_state *gallivm, + LLVMTypeRef resource_type, + const char *struct_name) { LLVMTargetDataRef target = gallivm->target; LLVMTypeRef elem_types[4]; @@ -336,8 +390,8 @@ create_jit_vertex_buffer_type(struct gallivm_state *gallivm, const char *struct_ elem_types[0] = elem_types[1] = LLVMInt32TypeInContext(gallivm->context); - elem_types[2] = - elem_types[3] = LLVMPointerType(LLVMInt8TypeInContext(gallivm->context), 0); /* vs_constants */ + elem_types[2] = LLVMPointerType(resource_type, 0); + elem_types[3] = LLVMPointerType(LLVMInt8TypeInContext(gallivm->context), 0); vb_type = LLVMStructTypeInContext(gallivm->context, elem_types, Elements(elem_types), 0); @@ -351,6 +405,8 @@ create_jit_vertex_buffer_type(struct gallivm_state *gallivm, const char *struct_ target, vb_type, 0); LP_CHECK_MEMBER_OFFSET(struct pipe_vertex_buffer, buffer_offset, target, vb_type, 1); + LP_CHECK_MEMBER_OFFSET(struct pipe_vertex_buffer, buffer, + target, vb_type, 2); LP_CHECK_STRUCT_SIZE(struct pipe_vertex_buffer, target, vb_type); @@ -422,7 +478,8 @@ static void create_jit_types(struct draw_llvm_variant *variant) { struct gallivm_state *gallivm = variant->gallivm; - LLVMTypeRef texture_type, sampler_type, context_type, buffer_type, vb_type; + LLVMTypeRef texture_type, sampler_type, context_type, buffer_type, + vb_type, resource_type; texture_type = create_jit_texture_type(gallivm, "texture"); sampler_type = create_jit_sampler_type(gallivm, "sampler"); @@ -434,7 +491,10 @@ create_jit_types(struct draw_llvm_variant *variant) buffer_type = LLVMPointerType(LLVMIntTypeInContext(gallivm->context, 8), 0); variant->buffer_ptr_type = LLVMPointerType(buffer_type, 0); - vb_type = create_jit_vertex_buffer_type(gallivm, "pipe_vertex_buffer"); + resource_type = create_jit_resource_type(gallivm, "pipe_resource"); + + vb_type = create_jit_vertex_buffer_type(gallivm, resource_type, + "pipe_vertex_buffer"); variant->vb_ptr_type = LLVMPointerType(vb_type, 0); } @@ -631,6 +691,19 @@ generate_vs(struct draw_llvm_variant *variant, } } +static LLVMValueRef +is_pointer_valid(struct gallivm_state *gallivm, + LLVMValueRef ptr) +{ + LLVMBuilderRef builder = gallivm->builder; + LLVMTypeRef any_ptr_type = LLVMPointerType( + LLVMInt8TypeInContext(gallivm->context), 0); + LLVMValueRef common_ptr = LLVMBuildBitCast(builder, ptr, + any_ptr_type, ""); + LLVMValueRef null_ptr = LLVMConstNull(any_ptr_type); + + return LLVMBuildICmp(builder, LLVMIntNE, common_ptr, null_ptr, ""); +} static void generate_fetch(struct gallivm_state *gallivm, @@ -651,7 +724,16 @@ generate_fetch(struct gallivm_state *gallivm, &indices, 1, ""); LLVMValueRef vb_stride = draw_jit_vbuffer_stride(gallivm, vbuf); LLVMValueRef vb_buffer_offset = draw_jit_vbuffer_offset(gallivm, vbuf); + LLVMValueRef resource = draw_jit_vbuffer_buffer(gallivm, vbuf); LLVMValueRef stride; + struct lp_build_if_state if_ctx; + LLVMValueRef buffer_overflowed, is_ptr_valid; + LLVMValueRef buffer_overflowed_ptr = + lp_build_alloca(gallivm, + LLVMInt1TypeInContext(gallivm->context), ""); + LLVMValueRef temp_ptr = + lp_build_alloca(gallivm, + lp_build_vec_type(gallivm, lp_float32_vec4_type()), ""); if (velem->instance_divisor) { /* array index = instance_id / instance_divisor */ @@ -671,14 +753,53 @@ generate_fetch(struct gallivm_state *gallivm, lp_build_const_int32(gallivm, velem->src_offset), ""); -/* lp_build_printf(gallivm, "vbuf index = %d, stride is %d\n", indices, stride);*/ - vbuffer_ptr = LLVMBuildGEP(builder, vbuffer_ptr, &stride, 1, ""); + is_ptr_valid = is_pointer_valid(gallivm, resource); + lp_build_if(&if_ctx, gallivm, is_ptr_valid); + { + LLVMValueRef buffer_size = draw_jit_resource_width0(gallivm, resource); + buffer_overflowed = LLVMBuildICmp(builder, LLVMIntSGE, + stride, buffer_size, + "buffer_overflowed"); + LLVMBuildStore(builder, buffer_overflowed, buffer_overflowed_ptr); + } + lp_build_else(&if_ctx); + { + LLVMBuildStore( + builder, + LLVMConstInt(LLVMInt1TypeInContext(gallivm->context), 0, 0), + buffer_overflowed_ptr); + } + lp_build_endif(&if_ctx); + + + buffer_overflowed = LLVMBuildLoad(builder, buffer_overflowed_ptr, + "buffer_overflowed"); + /* + lp_build_printf(gallivm, "vbuf index = %d, stride is %d\n", indices, stride); + lp_build_print_value(gallivm, " buffer size = ", buffer_size); + lp_build_print_value(gallivm, " buffer overflowed = ", buffer_overflowed); + */ + lp_build_if(&if_ctx, gallivm, buffer_overflowed); + { + LLVMValueRef val = + lp_build_const_vec(gallivm, lp_float32_vec4_type(), 0); + LLVMBuildStore(builder, val, temp_ptr); + } + lp_build_else(&if_ctx); + { + LLVMValueRef val; + vbuffer_ptr = LLVMBuildGEP(builder, vbuffer_ptr, &stride, 1, ""); + + val = lp_build_fetch_rgba_aos(gallivm, + format_desc, + lp_float32_vec4_type(), + vbuffer_ptr, + zero, zero, zero); + LLVMBuildStore(builder, val, temp_ptr); + } + lp_build_endif(&if_ctx); - *res = lp_build_fetch_rgba_aos(gallivm, - format_desc, - lp_float32_vec4_type(), - vbuffer_ptr, - zero, zero, zero); + *res = LLVMBuildLoad(builder, temp_ptr, "aos"); } static void diff --git a/src/gallium/auxiliary/draw/draw_llvm.h b/src/gallium/auxiliary/draw/draw_llvm.h index 5909fc1..17c9be74 100644 --- a/src/gallium/auxiliary/draw/draw_llvm.h +++ b/src/gallium/auxiliary/draw/draw_llvm.h @@ -173,6 +173,22 @@ enum { #define draw_jit_vbuffer_offset(_gallivm, _ptr) \ lp_build_struct_get(_gallivm, _ptr, 1, "buffer_offset") +#define draw_jit_vbuffer_buffer(_gallivm, _ptr) \ + lp_build_struct_get(_gallivm, _ptr, 2, "buffer") + + +enum { + DRAW_JIT_RESOURCE_REFERENCE = 0, + DRAW_JIT_RESOURCE_SCREEN, + DRAW_JIT_RESOURCE_TARGET, + DRAW_JIT_RESOURCE_FORMAT, + DRAW_JIT_RESOURCE_WIDTH0, + DRAW_JIT_RESOURCE_NUM_FIELDS /* number of fields above */ +}; + +#define draw_jit_resource_width0(_gallivm, _ptr) \ + lp_build_struct_get(_gallivm, _ptr, DRAW_JIT_RESOURCE_WIDTH0, "width0") + /** * This structure is passed directly to the generated geometry shader. diff --git a/src/gallium/auxiliary/draw/draw_pt.c b/src/gallium/auxiliary/draw/draw_pt.c index 602d076..0c2bcae 100644 --- a/src/gallium/auxiliary/draw/draw_pt.c +++ b/src/gallium/auxiliary/draw/draw_pt.c @@ -524,10 +524,11 @@ draw_vbo(struct draw_context *draw, } debug_printf("Buffers:\n"); for (i = 0; i < draw->pt.nr_vertex_buffers; i++) { - debug_printf(" %u: stride=%u offset=%u ptr=%p\n", + debug_printf(" %u: stride=%u offset=%u size=%d ptr=%p\n", i, draw->pt.vertex_buffer[i].stride, draw->pt.vertex_buffer[i].buffer_offset, + draw->pt.vertex_buffer[i].buffer ? draw->pt.vertex_buffer[i].buffer->width0 : 0, draw->pt.user.vbuffer[i]); } } -- 1.7.10.4 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/mesa-dev