v3d_setup_shared_precompile_key(so, &key.base);
v3d_get_compiled_shader(v3d, &key.base, sizeof(key));
} else {
+ /* FIXME: add geometry shaders */
+
struct v3d_vs_key key = {
.base.shader_state = so,
+ /* Emit fixed function outputs */
+ .base.is_last_geometry_stage = true,
};
v3d_setup_shared_precompile_key(so, &key.base);
}
nir_variable_mode lower_mode = nir_var_all & ~nir_var_uniform;
- if (s->info.stage == MESA_SHADER_VERTEX)
+ if (s->info.stage == MESA_SHADER_VERTEX ||
+ s->info.stage == MESA_SHADER_GEOMETRY) {
lower_mode &= ~(nir_var_shader_in | nir_var_shader_out);
+ }
NIR_PASS_V(s, nir_lower_io, lower_mode,
type_size,
(nir_lower_io_options)0);
}
static void
-v3d_update_compiled_vs(struct v3d_context *v3d, uint8_t prim_mode)
+v3d_update_compiled_gs(struct v3d_context *v3d, uint8_t prim_mode)
{
- struct v3d_vs_key local_key;
- struct v3d_vs_key *key = &local_key;
+ struct v3d_gs_key local_key;
+ struct v3d_gs_key *key = &local_key;
- if (!(v3d->dirty & (VC5_DIRTY_PRIM_MODE |
+ if (!(v3d->dirty & (VC5_DIRTY_GEOMTEX |
VC5_DIRTY_RASTERIZER |
- VC5_DIRTY_VERTTEX |
- VC5_DIRTY_VTXSTATE |
- VC5_DIRTY_UNCOMPILED_VS |
+ VC5_DIRTY_UNCOMPILED_GS |
+ VC5_DIRTY_PRIM_MODE |
VC5_DIRTY_FS_INPUTS))) {
return;
}
+ if (!v3d->prog.bind_gs) {
+ v3d->prog.gs = NULL;
+ v3d->prog.gs_bin = NULL;
+ return;
+ }
+
memset(key, 0, sizeof(*key));
- v3d_setup_shared_key(v3d, &key->base, &v3d->tex[PIPE_SHADER_VERTEX]);
- key->base.shader_state = v3d->prog.bind_vs;
+ v3d_setup_shared_key(v3d, &key->base, &v3d->tex[PIPE_SHADER_GEOMETRY]);
+ key->base.shader_state = v3d->prog.bind_gs;
key->base.ucp_enables = v3d->rasterizer->base.clip_plane_enable;
+ key->base.is_last_geometry_stage = true;
key->num_used_outputs = v3d->prog.fs->prog_data.fs->num_inputs;
STATIC_ASSERT(sizeof(key->used_outputs) ==
sizeof(v3d->prog.fs->prog_data.fs->input_slots));
memcpy(key->used_outputs, v3d->prog.fs->prog_data.fs->input_slots,
sizeof(key->used_outputs));
- key->clamp_color = v3d->rasterizer->base.clamp_vertex_color;
key->per_vertex_point_size =
(prim_mode == PIPE_PRIM_POINTS &&
v3d->rasterizer->base.point_size_per_vertex);
- struct v3d_compiled_shader *vs =
+ struct v3d_compiled_shader *gs =
v3d_get_compiled_shader(v3d, &key->base, sizeof(*key));
- if (vs != v3d->prog.vs) {
- v3d->prog.vs = vs;
- v3d->dirty |= VC5_DIRTY_COMPILED_VS;
+ if (gs != v3d->prog.gs) {
+ v3d->prog.gs = gs;
+ v3d->dirty |= VC5_DIRTY_COMPILED_GS;
}
key->is_coord = true;
- /* Coord shaders only output varyings used by transform feedback. */
+
+ /* The last bin-mode shader in the geometry pipeline only outputs
+ * varyings used by transform feedback.
+ */
struct v3d_uncompiled_shader *shader_state = key->base.shader_state;
memcpy(key->used_outputs, shader_state->tf_outputs,
sizeof(*key->used_outputs) * shader_state->num_tf_outputs);
if (shader_state->num_tf_outputs < key->num_used_outputs) {
+ uint32_t size = sizeof(*key->used_outputs) *
+ (key->num_used_outputs -
+ shader_state->num_tf_outputs);
memset(&key->used_outputs[shader_state->num_tf_outputs],
- 0,
- sizeof(*key->used_outputs) * (key->num_used_outputs -
- shader_state->num_tf_outputs));
+ 0, size);
}
key->num_used_outputs = shader_state->num_tf_outputs;
+ struct v3d_compiled_shader *old_gs = v3d->prog.gs;
+ struct v3d_compiled_shader *gs_bin =
+ v3d_get_compiled_shader(v3d, &key->base, sizeof(*key));
+ if (gs_bin != old_gs) {
+ v3d->prog.gs_bin = gs_bin;
+ v3d->dirty |= VC5_DIRTY_COMPILED_GS_BIN;
+ }
+
+ if (old_gs && memcmp(v3d->prog.gs->prog_data.gs->input_slots,
+ old_gs->prog_data.gs->input_slots,
+ sizeof(v3d->prog.gs->prog_data.gs->input_slots))) {
+ v3d->dirty |= VC5_DIRTY_GS_INPUTS;
+ }
+}
+
+static void
+v3d_update_compiled_vs(struct v3d_context *v3d, uint8_t prim_mode)
+{
+ struct v3d_vs_key local_key;
+ struct v3d_vs_key *key = &local_key;
+
+ if (!(v3d->dirty & (VC5_DIRTY_VERTTEX |
+ VC5_DIRTY_VTXSTATE |
+ VC5_DIRTY_UNCOMPILED_VS |
+ (v3d->prog.bind_gs ? 0 : VC5_DIRTY_RASTERIZER) |
+ (v3d->prog.bind_gs ? 0 : VC5_DIRTY_PRIM_MODE) |
+ (v3d->prog.bind_gs ? VC5_DIRTY_GS_INPUTS :
+ VC5_DIRTY_FS_INPUTS)))) {
+ return;
+ }
+
+ memset(key, 0, sizeof(*key));
+ v3d_setup_shared_key(v3d, &key->base, &v3d->tex[PIPE_SHADER_VERTEX]);
+ key->base.shader_state = v3d->prog.bind_vs;
+ key->base.ucp_enables = v3d->rasterizer->base.clip_plane_enable;
+ key->base.is_last_geometry_stage = !v3d->prog.bind_gs;
+
+ if (!v3d->prog.bind_gs) {
+ key->num_used_outputs = v3d->prog.fs->prog_data.fs->num_inputs;
+ STATIC_ASSERT(sizeof(key->used_outputs) ==
+ sizeof(v3d->prog.fs->prog_data.fs->input_slots));
+ memcpy(key->used_outputs, v3d->prog.fs->prog_data.fs->input_slots,
+ sizeof(key->used_outputs));
+ } else {
+ key->num_used_outputs = v3d->prog.gs->prog_data.gs->num_inputs;
+ STATIC_ASSERT(sizeof(key->used_outputs) ==
+ sizeof(v3d->prog.gs->prog_data.gs->input_slots));
+ memcpy(key->used_outputs, v3d->prog.gs->prog_data.gs->input_slots,
+ sizeof(key->used_outputs));
+ }
+
+ key->clamp_color = v3d->rasterizer->base.clamp_vertex_color;
+
+ key->per_vertex_point_size =
+ (prim_mode == PIPE_PRIM_POINTS &&
+ v3d->rasterizer->base.point_size_per_vertex);
+
+ struct v3d_compiled_shader *vs =
+ v3d_get_compiled_shader(v3d, &key->base, sizeof(*key));
+ if (vs != v3d->prog.vs) {
+ v3d->prog.vs = vs;
+ v3d->dirty |= VC5_DIRTY_COMPILED_VS;
+ }
+
+ key->is_coord = true;
+
+ /* Coord shaders only output varyings used by transform feedback,
+ * unless they are linked to other shaders in the geometry side
+ * of the pipeline, since in that case any of the output varyings
+ * could be required in later geometry stages to compute
+ * gl_Position or TF outputs.
+ */
+ if (!v3d->prog.bind_gs) {
+ struct v3d_uncompiled_shader *shader_state =
+ key->base.shader_state;
+ memcpy(key->used_outputs, shader_state->tf_outputs,
+ sizeof(*key->used_outputs) *
+ shader_state->num_tf_outputs);
+ if (shader_state->num_tf_outputs < key->num_used_outputs) {
+ uint32_t tail_bytes =
+ sizeof(*key->used_outputs) *
+ (key->num_used_outputs -
+ shader_state->num_tf_outputs);
+ memset(&key->used_outputs[shader_state->num_tf_outputs],
+ 0, tail_bytes);
+ }
+ key->num_used_outputs = shader_state->num_tf_outputs;
+ }
+
struct v3d_compiled_shader *cs =
v3d_get_compiled_shader(v3d, &key->base, sizeof(*key));
if (cs != v3d->prog.cs) {
v3d_update_compiled_shaders(struct v3d_context *v3d, uint8_t prim_mode)
{
v3d_update_compiled_fs(v3d, prim_mode);
+ v3d_update_compiled_gs(v3d, prim_mode);
v3d_update_compiled_vs(v3d, prim_mode);
}
return _mesa_hash_data(key, sizeof(struct v3d_fs_key));
}
+static uint32_t
+gs_cache_hash(const void *key)
+{
+ return _mesa_hash_data(key, sizeof(struct v3d_gs_key));
+}
+
static uint32_t
vs_cache_hash(const void *key)
{
return memcmp(key1, key2, sizeof(struct v3d_fs_key)) == 0;
}
+static bool
+gs_cache_compare(const void *key1, const void *key2)
+{
+ return memcmp(key1, key2, sizeof(struct v3d_gs_key)) == 0;
+}
+
static bool
vs_cache_compare(const void *key1, const void *key2)
{
v3d->dirty |= VC5_DIRTY_UNCOMPILED_FS;
}
+static void
+v3d_gp_state_bind(struct pipe_context *pctx, void *hwcso)
+{
+ struct v3d_context *v3d = v3d_context(pctx);
+ v3d->prog.bind_gs = hwcso;
+ v3d->dirty |= VC5_DIRTY_UNCOMPILED_GS;
+}
+
static void
v3d_vp_state_bind(struct pipe_context *pctx, void *hwcso)
{
pctx->create_vs_state = v3d_shader_state_create;
pctx->delete_vs_state = v3d_shader_state_delete;
+ pctx->create_gs_state = v3d_shader_state_create;
+ pctx->delete_gs_state = v3d_shader_state_delete;
+
pctx->create_fs_state = v3d_shader_state_create;
pctx->delete_fs_state = v3d_shader_state_delete;
pctx->bind_fs_state = v3d_fp_state_bind;
+ pctx->bind_gs_state = v3d_gp_state_bind;
pctx->bind_vs_state = v3d_vp_state_bind;
if (v3d->screen->has_csd) {
v3d->prog.cache[MESA_SHADER_VERTEX] =
_mesa_hash_table_create(pctx, vs_cache_hash, vs_cache_compare);
+ v3d->prog.cache[MESA_SHADER_GEOMETRY] =
+ _mesa_hash_table_create(pctx, gs_cache_hash, gs_cache_compare);
v3d->prog.cache[MESA_SHADER_FRAGMENT] =
_mesa_hash_table_create(pctx, fs_cache_hash, fs_cache_compare);
v3d->prog.cache[MESA_SHADER_COMPUTE] =