mesa: add primitive restart state to Driver.Draw parameters

so that display lists don't have to disable it and drivers are simpler.
This will also enable unification with Gallium.

Reviewed-by: Pierre-Eric Pelloux-Prayer <pierre-eric.pelloux-prayer@amd.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/7441>
This commit is contained in:
Marek Olšák 2020-11-01 13:43:43 -05:00 committed by Marge Bot
parent e8c0c80ecd
commit 51c7c64f0a
19 changed files with 119 additions and 64 deletions

View File

@ -1202,6 +1202,7 @@ struct brw_context
struct {
bool in_progress;
bool enable_cut_index;
unsigned restart_index;
} prim_restart;
/** Computed depth/stencil/hiz state from the current attached

View File

@ -1137,6 +1137,8 @@ brw_draw_prims(struct gl_context *ctx,
unsigned nr_prims,
const struct _mesa_index_buffer *ib,
bool index_bounds_valid,
bool primitive_restart,
unsigned restart_index,
unsigned min_index,
unsigned max_index,
unsigned num_instances,
@ -1151,7 +1153,8 @@ brw_draw_prims(struct gl_context *ctx,
/* Handle primitive restart if needed */
if (brw_handle_primitive_restart(ctx, prims, nr_prims, ib, num_instances,
base_instance)) {
base_instance, primitive_restart,
restart_index)) {
/* The draw was handled, so we can exit now */
return;
}
@ -1164,7 +1167,8 @@ brw_draw_prims(struct gl_context *ctx,
_mesa_enum_to_string(ctx->RenderMode));
_swsetup_Wakeup(ctx);
_tnl_wakeup(ctx);
_tnl_draw(ctx, prims, nr_prims, ib, index_bounds_valid, min_index,
_tnl_draw(ctx, prims, nr_prims, ib, index_bounds_valid,
primitive_restart, restart_index, min_index,
max_index, num_instances, base_instance);
return;
}
@ -1176,7 +1180,8 @@ brw_draw_prims(struct gl_context *ctx,
if (!index_bounds_valid && _mesa_draw_user_array_bits(ctx) != 0) {
perf_debug("Scanning index buffer to compute index buffer bounds. "
"Use glDrawRangeElements() to avoid this.\n");
vbo_get_minmax_indices(ctx, prims, ib, &min_index, &max_index, nr_prims);
vbo_get_minmax_indices(ctx, prims, ib, &min_index, &max_index, nr_prims,
primitive_restart, restart_index);
index_bounds_valid = true;
}
@ -1275,7 +1280,9 @@ brw_draw_indirect_prims(struct gl_context *ctx,
unsigned stride,
struct gl_buffer_object *indirect_params,
GLsizeiptr indirect_params_offset,
const struct _mesa_index_buffer *ib)
const struct _mesa_index_buffer *ib,
bool primitive_restart,
unsigned restart_index)
{
struct brw_context *brw = brw_context(ctx);
struct _mesa_prim *prim;
@ -1309,7 +1316,8 @@ brw_draw_indirect_prims(struct gl_context *ctx,
brw->draw.draw_indirect_data = indirect_data;
brw_draw_prims(ctx, prim, draw_count, ib, false, 0, ~0, 0, 0);
brw_draw_prims(ctx, prim, draw_count, ib, false, primitive_restart,
restart_index, 0, ~0, 0, 0);
brw->draw.draw_indirect_data = NULL;
free(prim);

View File

@ -49,7 +49,9 @@ void brw_draw_prims(struct gl_context *ctx,
unsigned nr_prims,
const struct _mesa_index_buffer *ib,
bool index_bounds_valid,
unsigned min_index,
bool primitive_restart,
unsigned restart_index,
unsigned min_index,
unsigned max_index,
unsigned num_instances,
unsigned base_instance);
@ -66,7 +68,9 @@ brw_handle_primitive_restart(struct gl_context *ctx,
const struct _mesa_prim *prims,
GLuint nr_prims,
const struct _mesa_index_buffer *ib,
GLuint num_instances, GLuint base_instance);
GLuint num_instances, GLuint base_instance,
bool primitive_restart,
unsigned restart_index);
void
brw_draw_indirect_prims(struct gl_context *ctx,
@ -77,5 +81,7 @@ brw_draw_indirect_prims(struct gl_context *ctx,
unsigned stride,
struct gl_buffer_object *indirect_params,
GLsizeiptr indirect_params_offset,
const struct _mesa_index_buffer *ib);
const struct _mesa_index_buffer *ib,
bool primitive_restart,
unsigned restart_index);
#endif

View File

@ -41,7 +41,8 @@
*/
static bool
can_cut_index_handle_restart_index(struct gl_context *ctx,
const struct _mesa_index_buffer *ib)
const struct _mesa_index_buffer *ib,
unsigned restart_index)
{
/* The FixedIndex variant means 0xFF, 0xFFFF, or 0xFFFFFFFF based on
* the index buffer type, which corresponds exactly to the hardware.
@ -53,13 +54,13 @@ can_cut_index_handle_restart_index(struct gl_context *ctx,
switch (ib->index_size_shift) {
case 0:
cut_index_will_work = ctx->Array.RestartIndex == 0xff;
cut_index_will_work = restart_index == 0xff;
break;
case 1:
cut_index_will_work = ctx->Array.RestartIndex == 0xffff;
cut_index_will_work = restart_index == 0xffff;
break;
case 2:
cut_index_will_work = ctx->Array.RestartIndex == 0xffffffff;
cut_index_will_work = restart_index == 0xffffffff;
break;
default:
unreachable("not reached");
@ -76,7 +77,8 @@ static bool
can_cut_index_handle_prims(struct gl_context *ctx,
const struct _mesa_prim *prim,
GLuint nr_prims,
const struct _mesa_index_buffer *ib)
const struct _mesa_index_buffer *ib,
unsigned restart_index)
{
struct brw_context *brw = brw_context(ctx);
const struct gen_device_info *devinfo = &brw->screen->devinfo;
@ -85,7 +87,7 @@ can_cut_index_handle_prims(struct gl_context *ctx,
if (devinfo->gen >= 8 || devinfo->is_haswell)
return true;
if (!can_cut_index_handle_restart_index(ctx, ib)) {
if (!can_cut_index_handle_restart_index(ctx, ib, restart_index)) {
/* The primitive restart index can't be handled, so take
* the software path
*/
@ -130,7 +132,9 @@ brw_handle_primitive_restart(struct gl_context *ctx,
const struct _mesa_prim *prims,
GLuint nr_prims,
const struct _mesa_index_buffer *ib,
GLuint num_instances, GLuint base_instance)
GLuint num_instances, GLuint base_instance,
bool primitive_restart,
unsigned restart_index)
{
struct brw_context *brw = brw_context(ctx);
@ -149,7 +153,7 @@ brw_handle_primitive_restart(struct gl_context *ctx,
/* If PrimitiveRestart is not enabled, then we aren't concerned about
* handling this draw.
*/
if (!ctx->Array._PrimitiveRestart[ib->index_size_shift]) {
if (!primitive_restart) {
return GL_FALSE;
}
@ -158,11 +162,13 @@ brw_handle_primitive_restart(struct gl_context *ctx,
*/
brw->prim_restart.in_progress = true;
if (can_cut_index_handle_prims(ctx, prims, nr_prims, ib)) {
if (can_cut_index_handle_prims(ctx, prims, nr_prims, ib, restart_index)) {
/* Cut index should work for primitive restart, so use it
*/
brw->prim_restart.enable_cut_index = true;
brw_draw_prims(ctx, prims, nr_prims, ib, GL_FALSE, -1, -1,
brw->prim_restart.restart_index = restart_index;
brw_draw_prims(ctx, prims, nr_prims, ib, false, primitive_restart,
restart_index, -1, -1,
num_instances, base_instance);
brw->prim_restart.enable_cut_index = false;
} else {
@ -176,7 +182,8 @@ brw_handle_primitive_restart(struct gl_context *ctx,
vbo_sw_primitive_restart(ctx, prims, nr_prims, ib, num_instances,
base_instance, indirect_data,
brw->draw.draw_indirect_offset);
brw->draw.draw_indirect_offset,
primitive_restart, restart_index);
}
brw->prim_restart.in_progress = false;

View File

@ -900,12 +900,10 @@ static const struct brw_tracked_state genX(index_buffer) = {
static void
genX(upload_cut_index)(struct brw_context *brw)
{
const struct gl_context *ctx = &brw->ctx;
brw_batch_emit(brw, GENX(3DSTATE_VF), vf) {
if (ctx->Array._PrimitiveRestart[brw->ib.ib->index_size_shift] && brw->ib.ib) {
if (brw->prim_restart.enable_cut_index && brw->ib.ib) {
vf.IndexedDrawCutIndexEnable = true;
vf.CutIndex = ctx->Array._RestartIndex[brw->ib.ib->index_size_shift];
vf.CutIndex = brw->prim_restart.restart_index;
}
}
}

View File

@ -493,7 +493,7 @@ TAG(vbo_render_prims)(struct gl_context *ctx,
if (!index_bounds_valid)
vbo_get_minmax_indices(ctx, prims, ib, &min_index, &max_index,
nr_prims);
nr_prims, 0, false);
vbo_choose_render_mode(ctx, arrays);
vbo_choose_attrs(ctx, arrays);
@ -545,7 +545,9 @@ TAG(vbo_draw)(struct gl_context *ctx,
const struct _mesa_prim *prims, unsigned nr_prims,
const struct _mesa_index_buffer *ib,
bool index_bounds_valid,
unsigned min_index, unsigned max_index,
bool primitive_restart,
unsigned restart_index,
unsigned min_index, unsigned max_index,
unsigned num_instances, unsigned base_instance)
{
/* Borrow and update the inputs list from the tnl context */

View File

@ -549,6 +549,8 @@ struct dd_function_table {
const struct _mesa_prim *prims, unsigned nr_prims,
const struct _mesa_index_buffer *ib,
bool index_bounds_valid,
bool primitive_restart,
unsigned restart_index,
unsigned min_index, unsigned max_index,
unsigned num_instances, unsigned base_instance);
@ -576,7 +578,9 @@ struct dd_function_table {
unsigned stride,
struct gl_buffer_object *indirect_draw_count_buffer,
GLsizeiptr indirect_draw_count_offset,
const struct _mesa_index_buffer *ib);
const struct _mesa_index_buffer *ib,
bool primitive_restart,
unsigned restart_index);
/**
* Driver implementation of glDrawTransformFeedback.

View File

@ -364,7 +364,7 @@ _mesa_draw_arrays(struct gl_context *ctx, GLenum mode, GLint start,
};
ctx->Driver.Draw(ctx, &prim, 1, NULL,
true, start, start + count - 1,
true, false, 0, start, start + count - 1,
numInstances, baseInstance);
if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH) {
@ -728,7 +728,7 @@ _mesa_exec_MultiDrawArrays(GLenum mode, const GLint *first,
prim[i].basevertex = 0;
}
ctx->Driver.Draw(ctx, prim, primcount, NULL, false, 0, 0, 1, 0);
ctx->Driver.Draw(ctx, prim, primcount, NULL, false, false, 0, 0, 0, 1, 0);
if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH)
_mesa_flush(ctx);
@ -887,7 +887,10 @@ _mesa_validated_drawrangeelements(struct gl_context *ctx, GLenum mode,
*/
ctx->Driver.Draw(ctx, &prim, 1, &ib,
index_bounds_valid, start, end,
index_bounds_valid,
ctx->Array._PrimitiveRestart[ib.index_size_shift],
ctx->Array._RestartIndex[ib.index_size_shift],
start, end,
numInstances, baseInstance);
if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH) {
@ -1309,8 +1312,10 @@ _mesa_validated_multidrawelements(struct gl_context *ctx, GLenum mode,
prim[i].basevertex = 0;
}
ctx->Driver.Draw(ctx, prim, primcount, &ib,
false, 0, ~0, 1, 0);
ctx->Driver.Draw(ctx, prim, primcount, &ib, false,
ctx->Array._PrimitiveRestart[ib.index_size_shift],
ctx->Array._RestartIndex[ib.index_size_shift],
0, ~0, 1, 0);
FREE_PRIMS(prim, primcount);
}
else {
@ -1335,7 +1340,10 @@ _mesa_validated_multidrawelements(struct gl_context *ctx, GLenum mode,
else
prim.basevertex = 0;
ctx->Driver.Draw(ctx, &prim, 1, &ib, false, 0, ~0, 1, 0);
ctx->Driver.Draw(ctx, &prim, 1, &ib, false,
ctx->Array._PrimitiveRestart[ib.index_size_shift],
ctx->Array._RestartIndex[ib.index_size_shift],
0, ~0, 1, 0);
}
}
@ -1533,7 +1541,7 @@ _mesa_validated_multidrawarraysindirect(struct gl_context *ctx, GLenum mode,
ctx->Driver.DrawIndirect(ctx, mode, ctx->DrawIndirectBuffer, indirect,
drawcount, stride, drawcount_buffer,
drawcount_offset, NULL);
drawcount_offset, NULL, false, 0);
if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH)
_mesa_flush(ctx);
@ -1561,7 +1569,9 @@ _mesa_validated_multidrawelementsindirect(struct gl_context *ctx,
ctx->Driver.DrawIndirect(ctx, mode, ctx->DrawIndirectBuffer, indirect,
drawcount, stride, drawcount_buffer,
drawcount_offset, &ib);
drawcount_offset, &ib,
ctx->Array._PrimitiveRestart[ib.index_size_shift],
ctx->Array._RestartIndex[ib.index_size_shift]);
if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH)
_mesa_flush(ctx);

View File

@ -260,7 +260,7 @@ st_RasterPos(struct gl_context *ctx, const GLfloat v[4])
_mesa_set_draw_vao(ctx, rs->VAO, VERT_BIT_POS);
/* Draw the point. */
st_feedback_draw_vbo(ctx, &rs->prim, 1, NULL, GL_TRUE, 0, 1, 1, 0);
st_feedback_draw_vbo(ctx, &rs->prim, 1, NULL, true, false, 0, 0, 1, 1, 0);
/* restore draw's rasterization stage depending on rendermode */
if (ctx->RenderMode == GL_FEEDBACK) {

View File

@ -139,6 +139,8 @@ st_draw_vbo(struct gl_context *ctx,
unsigned nr_prims,
const struct _mesa_index_buffer *ib,
bool index_bounds_valid,
bool primitive_restart,
unsigned restart_index,
unsigned min_index,
unsigned max_index,
unsigned num_instances,
@ -165,7 +167,7 @@ st_draw_vbo(struct gl_context *ctx,
/* Get index bounds for user buffers. */
if (!index_bounds_valid && st->draw_needs_minmax_index) {
vbo_get_minmax_indices(ctx, prims, ib, &min_index, &max_index,
nr_prims);
nr_prims, primitive_restart, restart_index);
index_bounds_valid = true;
}
@ -192,8 +194,8 @@ st_draw_vbo(struct gl_context *ctx,
info.index.user = ib->ptr;
}
info.restart_index = ctx->Array._RestartIndex[ib->index_size_shift];
info.primitive_restart = ctx->Array._PrimitiveRestart[ib->index_size_shift];
info.restart_index = restart_index;
info.primitive_restart = primitive_restart;
}
else {
info.index_size = 0;
@ -242,7 +244,9 @@ st_indirect_draw_vbo(struct gl_context *ctx,
unsigned stride,
struct gl_buffer_object *indirect_draw_count,
GLsizeiptr indirect_draw_count_offset,
const struct _mesa_index_buffer *ib)
const struct _mesa_index_buffer *ib,
bool primitive_restart,
unsigned restart_index)
{
struct st_context *st = st_context(ctx);
struct pipe_draw_info info;
@ -266,8 +270,8 @@ st_indirect_draw_vbo(struct gl_context *ctx,
info.index.resource = st_buffer_object(bufobj)->buffer;
draw.start = pointer_to_offset(ib->ptr) >> ib->index_size_shift;
info.restart_index = ctx->Array._RestartIndex[ib->index_size_shift];
info.primitive_restart = ctx->Array._PrimitiveRestart[ib->index_size_shift];
info.restart_index = restart_index;
info.primitive_restart = primitive_restart;
}
info.mode = translate_prim(ctx, mode);

View File

@ -53,6 +53,8 @@ st_feedback_draw_vbo(struct gl_context *ctx,
unsigned nr_prims,
const struct _mesa_index_buffer *ib,
bool index_bounds_valid,
bool primitive_restart,
unsigned restart_index,
unsigned min_index,
unsigned max_index,
unsigned num_instances,

View File

@ -98,6 +98,8 @@ st_feedback_draw_vbo(struct gl_context *ctx,
unsigned nr_prims,
const struct _mesa_index_buffer *ib,
bool index_bounds_valid,
bool primitive_restart,
unsigned restart_index,
unsigned min_index,
unsigned max_index,
unsigned num_instances,
@ -131,7 +133,8 @@ st_feedback_draw_vbo(struct gl_context *ctx,
st_validate_state(st, ST_PIPELINE_RENDER);
if (ib && !index_bounds_valid) {
vbo_get_minmax_indices(ctx, prims, ib, &min_index, &max_index, nr_prims);
vbo_get_minmax_indices(ctx, prims, ib, &min_index, &max_index, nr_prims,
primitive_restart, restart_index);
index_bounds_valid = true;
}
@ -213,8 +216,8 @@ st_feedback_draw_vbo(struct gl_context *ctx,
(ubyte *) mapped_indices,
index_size, ~0);
info.primitive_restart = ctx->Array._PrimitiveRestart[ib->index_size_shift];
info.restart_index = ctx->Array._RestartIndex[ib->index_size_shift];
info.primitive_restart = primitive_restart;
info.restart_index = restart_index;
} else {
info.index_size = 0;
info.has_user_indices = false;

View File

@ -438,7 +438,8 @@ void _tnl_draw_prims(struct gl_context *ctx,
GLuint i;
if (!index_bounds_valid)
vbo_get_minmax_indices(ctx, prim, ib, &min_index, &max_index, nr_prims);
vbo_get_minmax_indices(ctx, prim, ib, &min_index, &max_index, nr_prims,
false, 0);
/* Mesa core state should have been validated already */
assert(ctx->NewState == 0x0);
@ -630,7 +631,8 @@ void
_tnl_draw(struct gl_context *ctx,
const struct _mesa_prim *prim, unsigned nr_prims,
const struct _mesa_index_buffer *ib,
bool index_bounds_valid, unsigned min_index, unsigned max_index,
bool index_bounds_valid, bool primitive_restart,
unsigned restart_index, unsigned min_index, unsigned max_index,
unsigned num_instances, unsigned base_instance)
{
/* Update TNLcontext::draw_arrays and return that pointer.

View File

@ -114,7 +114,8 @@ void
_tnl_draw(struct gl_context *ctx,
const struct _mesa_prim *prim, unsigned nr_prims,
const struct _mesa_index_buffer *ib,
bool index_bounds_valid, unsigned min_index, unsigned max_index,
bool index_bounds_valid, bool primitive_restart,
unsigned restart_index, unsigned min_index, unsigned max_index,
unsigned num_instances, unsigned base_instance);
extern void

View File

@ -228,7 +228,9 @@ vbo_get_minmax_index_mapped(unsigned count, unsigned index_size,
void
vbo_get_minmax_indices(struct gl_context *ctx, const struct _mesa_prim *prim,
const struct _mesa_index_buffer *ib,
GLuint *min_index, GLuint *max_index, GLuint nr_prims);
GLuint *min_index, GLuint *max_index, GLuint nr_prims,
bool primitive_restart,
unsigned restart_index);
void
vbo_sw_primitive_restart(struct gl_context *ctx,
@ -237,7 +239,9 @@ vbo_sw_primitive_restart(struct gl_context *ctx,
const struct _mesa_index_buffer *ib,
GLuint num_instances, GLuint base_instance,
struct gl_buffer_object *indirect,
GLsizeiptr indirect_offset);
GLsizeiptr indirect_offset,
bool primitive_restart,
unsigned restart_index);
const struct gl_array_attributes*

View File

@ -324,8 +324,8 @@ vbo_exec_vtx_flush(struct vbo_exec_context *exec)
printf("%s %d %d\n", __func__, exec->vtx.prim_count,
exec->vtx.vert_count);
ctx->Driver.Draw(ctx, exec->vtx.prim, exec->vtx.prim_count,
NULL, true, 0, exec->vtx.vert_count - 1, 1, 0);
ctx->Driver.Draw(ctx, exec->vtx.prim, exec->vtx.prim_count, NULL,
true, false, 0, 0, exec->vtx.vert_count - 1, 1, 0);
/* Get new storage -- unless asked not to. */
if (!persistent_mapping)

View File

@ -324,11 +324,10 @@ vbo_get_minmax_index(struct gl_context *ctx,
const struct _mesa_prim *prim,
const struct _mesa_index_buffer *ib,
GLuint *min_index, GLuint *max_index,
const GLuint count)
const GLuint count,
bool primitive_restart,
unsigned restart_index)
{
const GLboolean restart = ctx->Array._PrimitiveRestart[ib->index_size_shift];
const GLuint restartIndex =
ctx->Array._RestartIndex[ib->index_size_shift];
const char *indices;
GLintptr offset = 0;
@ -346,8 +345,8 @@ vbo_get_minmax_index(struct gl_context *ctx,
MAP_INTERNAL);
}
vbo_get_minmax_index_mapped(count, 1 << ib->index_size_shift, restartIndex,
restart, indices, min_index, max_index);
vbo_get_minmax_index_mapped(count, 1 << ib->index_size_shift, restart_index,
primitive_restart, indices, min_index, max_index);
if (ib->obj) {
vbo_minmax_cache_store(ctx, ib->obj, 1 << ib->index_size_shift, offset,
@ -365,7 +364,9 @@ vbo_get_minmax_indices(struct gl_context *ctx,
const struct _mesa_index_buffer *ib,
GLuint *min_index,
GLuint *max_index,
GLuint nr_prims)
GLuint nr_prims,
bool primitive_restart,
unsigned restart_index)
{
GLuint tmp_min, tmp_max;
GLuint i;
@ -385,7 +386,8 @@ vbo_get_minmax_indices(struct gl_context *ctx,
count += prims[i+1].count;
i++;
}
vbo_get_minmax_index(ctx, start_prim, ib, &tmp_min, &tmp_max, count);
vbo_get_minmax_index(ctx, start_prim, ib, &tmp_min, &tmp_max, count,
primitive_restart, restart_index);
*min_index = MIN2(*min_index, tmp_min);
*max_index = MAX2(*max_index, tmp_max);
}

View File

@ -166,7 +166,9 @@ vbo_sw_primitive_restart(struct gl_context *ctx,
const struct _mesa_index_buffer *ib,
GLuint num_instances, GLuint base_instance,
struct gl_buffer_object *indirect,
GLsizeiptr indirect_offset)
GLsizeiptr indirect_offset,
bool primitive_restart,
unsigned restart_index)
{
GLuint prim_num;
struct _mesa_prim new_prim;
@ -177,7 +179,6 @@ vbo_sw_primitive_restart(struct gl_context *ctx,
GLuint sub_prim_num;
GLuint end_index;
GLuint sub_end_index;
GLuint restart_index = ctx->Array._RestartIndex[ib->index_size_shift];
struct _mesa_prim temp_prim;
GLboolean map_ib = ib->obj && !ib->obj->Mappings[MAP_INTERNAL].Pointer;
const void *ptr;
@ -252,12 +253,12 @@ vbo_sw_primitive_restart(struct gl_context *ctx,
temp_prim.count = MIN2(sub_end_index, end_index) - temp_prim.start;
if ((temp_prim.start == sub_prim->start) &&
(temp_prim.count == sub_prim->count)) {
ctx->Driver.Draw(ctx, &temp_prim, 1, ib, true,
ctx->Driver.Draw(ctx, &temp_prim, 1, ib, true, false, 0,
sub_prim->min_index, sub_prim->max_index,
num_instances, base_instance);
} else {
ctx->Driver.Draw(ctx, &temp_prim, 1, ib,
false, -1, -1,
false, false, 0, -1, -1,
num_instances, base_instance);
}
}

View File

@ -213,7 +213,7 @@ vbo_save_playback_vertex_list(struct gl_context *ctx, void *data)
GLuint min_index = _vbo_save_get_min_index(node);
GLuint max_index = _vbo_save_get_max_index(node);
ctx->Driver.Draw(ctx, node->prims, node->prim_count, NULL, true,
min_index, max_index, 1, 0);
false, 0, min_index, max_index, 1, 0);
}
}