diff options
author | Zack Rusin <[email protected]> | 2013-04-16 20:31:22 -0700 |
---|---|---|
committer | Zack Rusin <[email protected]> | 2013-04-16 23:38:47 -0700 |
commit | f01f754ca13373d62f5f4ba5ff76d83aa4eac62b (patch) | |
tree | af3c40e5cebfeb05e40efd447b6af18a035653fb /src/gallium/auxiliary/gallivm | |
parent | be497ac9d3b5c50a4cd126578081bd54b68f16a9 (diff) |
draw/gs: make sure geometry shaders don't overflow
The specification says that the geometry shader should exit if the
number of emitted vertices is bigger or equal to max_output_vertices and
we can't do that because we're running in the SoA mode, which means that
our storing routines will keep getting called on channels that have
overflown (even though they will be masked out, but we just can't skip
them).
So we need some scratch area where we can keep writing the overflown
vertices without overwriting anything important or crashing.
Signed-off-by: Zack Rusin <[email protected]>
Reviewed-by: Jose Fonseca <[email protected]>
Diffstat (limited to 'src/gallium/auxiliary/gallivm')
-rw-r--r-- | src/gallium/auxiliary/gallivm/lp_bld_tgsi.h | 1 | ||||
-rw-r--r-- | src/gallium/auxiliary/gallivm/lp_bld_tgsi_soa.c | 34 |
2 files changed, 34 insertions, 1 deletions
diff --git a/src/gallium/auxiliary/gallivm/lp_bld_tgsi.h b/src/gallium/auxiliary/gallivm/lp_bld_tgsi.h index f1b1d79eab7..0fbb8aabbb0 100644 --- a/src/gallium/auxiliary/gallivm/lp_bld_tgsi.h +++ b/src/gallium/auxiliary/gallivm/lp_bld_tgsi.h @@ -396,6 +396,7 @@ struct lp_build_tgsi_soa_context LLVMValueRef emitted_prims_vec_ptr; LLVMValueRef total_emitted_vertices_vec_ptr; LLVMValueRef emitted_vertices_vec_ptr; + LLVMValueRef max_output_vertices_vec; LLVMValueRef consts_ptr; const LLVMValueRef *pos; diff --git a/src/gallium/auxiliary/gallivm/lp_bld_tgsi_soa.c b/src/gallium/auxiliary/gallivm/lp_bld_tgsi_soa.c index 9822f72c6a3..28eb57b4b51 100644 --- a/src/gallium/auxiliary/gallivm/lp_bld_tgsi_soa.c +++ b/src/gallium/auxiliary/gallivm/lp_bld_tgsi_soa.c @@ -828,7 +828,6 @@ emit_fetch_gs_input( vertex_index = lp_build_const_int32(gallivm, reg->Dimension.Index); } - res = bld->gs_iface->fetch_input(bld->gs_iface, bld_base, vertex_index, attrib_index, swizzle_index); @@ -2257,6 +2256,20 @@ clear_uint_vec_ptr_from_mask(struct lp_build_tgsi_context * bld_base, LLVMBuildStore(builder, current_vec, ptr); } +static LLVMValueRef +clamp_mask_to_max_output_vertices(struct lp_build_tgsi_soa_context * bld, + LLVMValueRef current_mask_vec, + LLVMValueRef total_emitted_vertices_vec) +{ + LLVMBuilderRef builder = bld->bld_base.base.gallivm->builder; + struct lp_build_context *uint_bld = &bld->bld_base.uint_bld; + LLVMValueRef max_mask = lp_build_cmp(uint_bld, PIPE_FUNC_LESS, + total_emitted_vertices_vec, + bld->max_output_vertices_vec); + + return LLVMBuildAnd(builder, current_mask_vec, max_mask, ""); +} + static void emit_vertex( const struct lp_build_tgsi_action * action, @@ -2270,6 +2283,8 @@ emit_vertex( LLVMValueRef masked_ones = mask_to_one_vec(bld_base); LLVMValueRef total_emitted_vertices_vec = LLVMBuildLoad(builder, bld->total_emitted_vertices_vec_ptr, ""); + masked_ones = clamp_mask_to_max_output_vertices(bld, masked_ones, + total_emitted_vertices_vec); gather_outputs(bld); bld->gs_iface->emit_vertex(bld->gs_iface, &bld->bld_base, bld->outputs, @@ -2812,12 +2827,29 @@ lp_build_tgsi_soa(struct gallivm_state *gallivm, bld.bld_base.op_actions[TGSI_OPCODE_SVIEWINFO].emit = sviewinfo_emit; if (gs_iface) { + /* There's no specific value for this because it should always + * be set, but apps using ext_geometry_shader4 quite often + * were forgetting so we're using MAX_VERTEX_VARYING from + * that spec even though we could debug_assert if it's not + * set, but that's a lot uglier. */ + uint max_output_vertices = 32; + uint i = 0; /* inputs are always indirect with gs */ bld.indirect_files |= (1 << TGSI_FILE_INPUT); bld.gs_iface = gs_iface; bld.bld_base.emit_fetch_funcs[TGSI_FILE_INPUT] = emit_fetch_gs_input; bld.bld_base.op_actions[TGSI_OPCODE_EMIT].emit = emit_vertex; bld.bld_base.op_actions[TGSI_OPCODE_ENDPRIM].emit = end_primitive; + + for (i = 0; i < info->num_properties; ++i) { + if (info->properties[i].name == + TGSI_PROPERTY_GS_MAX_OUTPUT_VERTICES) { + max_output_vertices = info->properties[i].data[0]; + } + } + bld.max_output_vertices_vec = + lp_build_const_int_vec(gallivm, bld.bld_base.uint_bld.type, + max_output_vertices); } lp_exec_mask_init(&bld.exec_mask, &bld.bld_base.base); |