diff --git a/docs/gallium/screen.rst b/docs/gallium/screen.rst index 328b3e3e2f2..4714c0417f5 100644 --- a/docs/gallium/screen.rst +++ b/docs/gallium/screen.rst @@ -615,6 +615,7 @@ The integer capabilities: * ``PIPE_CAP_TEXRECT``: Driver supports rectangle textures. Required for OpenGL on `!prefers_nir` drivers. If this cap is not present, st/mesa will lower the NIR to use normal 2D texture sampling by using either `txs` or `nir_intrinsic_load_texture_scaling` to normalize the texture coordinates. * ``PIPE_CAP_SAMPLER_REDUCTION_MINMAX``: Driver supports EXT min/max sampler reduction. * ``PIPE_CAP_SAMPLER_REDUCTION_MINMAX_ARB``: Driver supports ARB min/max sampler reduction with format queries. +* ``PIPE_CAP_EMULATE_NONFIXED_PRIMITIVE_RESTART``: Driver requests all draws using a non-fixed restart index to be rewritten to use a fixed restart index. .. _pipe_capf: diff --git a/src/gallium/auxiliary/util/u_screen.c b/src/gallium/auxiliary/util/u_screen.c index 32a35c1a8e9..f185282a961 100644 --- a/src/gallium/auxiliary/util/u_screen.c +++ b/src/gallium/auxiliary/util/u_screen.c @@ -466,6 +466,9 @@ u_pipe_screen_get_param_defaults(struct pipe_screen *pscreen, case PIPE_CAP_ALLOW_DYNAMIC_VAO_FASTPATH: return 1; + case PIPE_CAP_EMULATE_NONFIXED_PRIMITIVE_RESTART: + return 0; + default: unreachable("bad PIPE_CAP_*"); } diff --git a/src/gallium/auxiliary/util/u_vbuf.c b/src/gallium/auxiliary/util/u_vbuf.c index 9e5f2e2366e..2d00c16c5e9 100644 --- a/src/gallium/auxiliary/util/u_vbuf.c +++ b/src/gallium/auxiliary/util/u_vbuf.c @@ -91,6 +91,8 @@ #include "util/format/u_format.h" #include "util/u_inlines.h" #include "util/u_memory.h" +#include "indices/u_primconvert.h" +#include "util/u_prim_restart.h" #include "util/u_screen.h" #include "util/u_upload_mgr.h" #include "translate/translate.h" @@ -152,6 +154,7 @@ struct u_vbuf { struct translate_cache *translate_cache; struct cso_cache cso_cache; + struct primconvert_context *pc; bool flatshade_first; /* This is what was set in set_vertex_buffers. @@ -302,6 +305,12 @@ void u_vbuf_get_caps(struct pipe_screen *screen, struct u_vbuf_caps *caps, caps->max_vertex_buffers = screen->get_param(screen, PIPE_CAP_MAX_VERTEX_BUFFERS); + if (screen->get_param(screen, PIPE_CAP_PRIMITIVE_RESTART) || + screen->get_param(screen, PIPE_CAP_PRIMITIVE_RESTART_FIXED_INDEX)) { + caps->rewrite_restart_index = screen->get_param(screen, PIPE_CAP_EMULATE_NONFIXED_PRIMITIVE_RESTART); + caps->fallback_always |= caps->rewrite_restart_index; + } + /* OpenGL 2.0 requires a minimum of 16 vertex buffers */ if (caps->max_vertex_buffers < 16) caps->fallback_always = true; @@ -322,6 +331,13 @@ u_vbuf_create(struct pipe_context *pipe, struct u_vbuf_caps *caps) mgr->caps = *caps; mgr->pipe = pipe; + if (caps->rewrite_restart_index) { + struct primconvert_config cfg; + cfg.fixed_prim_restart = caps->rewrite_restart_index; + cfg.primtypes_mask = 0xff; + cfg.restart_primtypes_mask = 0xff; + mgr->pc = util_primconvert_create_config(pipe, &cfg); + } mgr->translate_cache = translate_cache_create(); memset(mgr->fallback_vbs, ~0, sizeof(mgr->fallback_vbs)); mgr->allowed_vb_mask = u_bit_consecutive(0, mgr->caps.max_vertex_buffers); @@ -405,6 +421,9 @@ void u_vbuf_destroy(struct u_vbuf *mgr) for (i = 0; i < PIPE_MAX_ATTRIBS; i++) pipe_vertex_buffer_unreference(&mgr->real_vertex_buffer[i]); + if (mgr->pc) + util_primconvert_destroy(mgr->pc); + translate_cache_destroy(mgr->translate_cache); cso_cache_delete(&mgr->cso_cache); FREE(mgr); @@ -1356,11 +1375,15 @@ void u_vbuf_draw_vbo(struct u_vbuf *mgr, const struct pipe_draw_info *info, mgr->incompatible_vb_mask & used_vb_mask; struct pipe_draw_info new_info; struct pipe_draw_start_count_bias new_draw; + unsigned fixed_restart_index = info->index_size ? util_prim_restart_index_from_size(info->index_size) : 0; /* Normal draw. No fallback and no user buffers. */ if (!incompatible_vb_mask && !mgr->ve->incompatible_elem_mask && - !user_vb_mask) { + !user_vb_mask && + (!info->primitive_restart || + info->restart_index == fixed_restart_index || + !mgr->caps.rewrite_restart_index)) { /* Set vertex buffers if needed. */ if (mgr->dirty_real_vb_mask & used_vb_mask) { @@ -1639,7 +1662,12 @@ void u_vbuf_draw_vbo(struct u_vbuf *mgr, const struct pipe_draw_info *info, if (mgr->dirty_real_vb_mask) u_vbuf_set_driver_vertex_buffers(mgr); - pipe->draw_vbo(pipe, &new_info, drawid_offset, indirect, &new_draw, 1); + if (new_info.primitive_restart && + (new_info.restart_index != fixed_restart_index && mgr->caps.rewrite_restart_index)) { + util_primconvert_save_flatshade_first(mgr->pc, mgr->flatshade_first); + util_primconvert_draw_vbo(mgr->pc, &new_info, drawid_offset, indirect, &new_draw, 1); + } else + pipe->draw_vbo(pipe, &new_info, drawid_offset, indirect, &new_draw, 1); if (mgr->using_translate) { u_vbuf_translate_end(mgr); diff --git a/src/gallium/auxiliary/util/u_vbuf.h b/src/gallium/auxiliary/util/u_vbuf.h index 3ec93e662a7..a7360be3fc9 100644 --- a/src/gallium/auxiliary/util/u_vbuf.h +++ b/src/gallium/auxiliary/util/u_vbuf.h @@ -59,6 +59,7 @@ struct u_vbuf_caps { bool fallback_always; bool fallback_only_for_user_vbuffers; + bool rewrite_restart_index; }; diff --git a/src/gallium/drivers/nouveau/nv30/nv30_screen.c b/src/gallium/drivers/nouveau/nv30/nv30_screen.c index cc2859384f7..45a75ebdd0e 100644 --- a/src/gallium/drivers/nouveau/nv30/nv30_screen.c +++ b/src/gallium/drivers/nouveau/nv30/nv30_screen.c @@ -115,6 +115,7 @@ nv30_screen_get_param(struct pipe_screen *pscreen, enum pipe_cap param) case PIPE_CAP_PRIMITIVE_RESTART_FIXED_INDEX: return (eng3d->oclass >= NV40_3D_CLASS) ? 1 : 0; /* unsupported */ + case PIPE_CAP_EMULATE_NONFIXED_PRIMITIVE_RESTART: case PIPE_CAP_DEPTH_CLIP_DISABLE_SEPARATE: case PIPE_CAP_MAX_DUAL_SOURCE_RENDER_TARGETS: case PIPE_CAP_FRAGMENT_SHADER_TEXTURE_LOD: diff --git a/src/gallium/drivers/nouveau/nv50/nv50_screen.c b/src/gallium/drivers/nouveau/nv50/nv50_screen.c index cd9946baed6..c88942765f6 100644 --- a/src/gallium/drivers/nouveau/nv50/nv50_screen.c +++ b/src/gallium/drivers/nouveau/nv50/nv50_screen.c @@ -275,6 +275,7 @@ nv50_screen_get_param(struct pipe_screen *pscreen, enum pipe_cap param) return class_3d >= NVA3_3D_CLASS; /* unsupported caps */ + case PIPE_CAP_EMULATE_NONFIXED_PRIMITIVE_RESTART: case PIPE_CAP_DEPTH_CLIP_DISABLE_SEPARATE: case PIPE_CAP_SEAMLESS_CUBE_MAP_PER_TEXTURE: case PIPE_CAP_TGSI_FS_COORD_ORIGIN_LOWER_LEFT: diff --git a/src/gallium/drivers/nouveau/nvc0/nvc0_screen.c b/src/gallium/drivers/nouveau/nvc0/nvc0_screen.c index d1e901c4820..84cae860ba6 100644 --- a/src/gallium/drivers/nouveau/nvc0/nvc0_screen.c +++ b/src/gallium/drivers/nouveau/nvc0/nvc0_screen.c @@ -350,6 +350,7 @@ nvc0_screen_get_param(struct pipe_screen *pscreen, enum pipe_cap param) return 0; /* unsupported caps */ + case PIPE_CAP_EMULATE_NONFIXED_PRIMITIVE_RESTART: case PIPE_CAP_DEPTH_CLIP_DISABLE_SEPARATE: case PIPE_CAP_TGSI_FS_COORD_ORIGIN_LOWER_LEFT: case PIPE_CAP_TGSI_FS_COORD_PIXEL_CENTER_INTEGER: diff --git a/src/gallium/include/pipe/p_defines.h b/src/gallium/include/pipe/p_defines.h index 4523c405555..4747ef7953a 100644 --- a/src/gallium/include/pipe/p_defines.h +++ b/src/gallium/include/pipe/p_defines.h @@ -989,6 +989,7 @@ enum pipe_cap PIPE_CAP_SAMPLER_REDUCTION_MINMAX, PIPE_CAP_SAMPLER_REDUCTION_MINMAX_ARB, PIPE_CAP_ALLOW_DYNAMIC_VAO_FASTPATH, + PIPE_CAP_EMULATE_NONFIXED_PRIMITIVE_RESTART, PIPE_CAP_LAST, /* XXX do not add caps after PIPE_CAP_LAST! */