}
}
+#if V3D_VERSION >= 41
+static void
+v3d_emit_gs_state_record(struct v3d_job *job,
+ struct v3d_compiled_shader *gs_bin,
+ struct v3d_cl_reloc gs_bin_uniforms,
+ struct v3d_compiled_shader *gs,
+ struct v3d_cl_reloc gs_render_uniforms)
+{
+ cl_emit(&job->indirect, GEOMETRY_SHADER_STATE_RECORD, shader) {
+ shader.geometry_bin_mode_shader_code_address =
+ cl_address(v3d_resource(gs_bin->resource)->bo,
+ gs_bin->offset);
+ shader.geometry_bin_mode_shader_4_way_threadable =
+ gs_bin->prog_data.gs->base.threads == 4;
+ shader.geometry_bin_mode_shader_start_in_final_thread_section =
+ gs_bin->prog_data.gs->base.single_seg;
+ shader.geometry_bin_mode_shader_propagate_nans = true;
+ shader.geometry_bin_mode_shader_uniforms_address =
+ gs_bin_uniforms;
+
+ shader.geometry_render_mode_shader_code_address =
+ cl_address(v3d_resource(gs->resource)->bo, gs->offset);
+ shader.geometry_render_mode_shader_4_way_threadable =
+ gs->prog_data.gs->base.threads == 4;
+ shader.geometry_render_mode_shader_start_in_final_thread_section =
+ gs->prog_data.gs->base.single_seg;
+ shader.geometry_render_mode_shader_propagate_nans = true;
+ shader.geometry_render_mode_shader_uniforms_address =
+ gs_render_uniforms;
+ }
+}
+
+static uint8_t
+v3d_gs_output_primitive(uint32_t prim_type)
+{
+ switch (prim_type) {
+ case GL_POINTS:
+ return GEOMETRY_SHADER_POINTS;
+ case GL_LINE_STRIP:
+ return GEOMETRY_SHADER_LINE_STRIP;
+ case GL_TRIANGLE_STRIP:
+ return GEOMETRY_SHADER_TRI_STRIP;
+ default:
+ unreachable("Unsupported primitive type");
+ }
+}
+
+static void
+v3d_emit_tes_gs_common_params(struct v3d_job *job,
+ uint8_t gs_out_prim_type)
+{
+ /* This, and v3d_emit_tes_gs_shader_params below, fill in default
+ * values for tessellation fields even though we don't support
+ * tessellation yet because our packing functions (and the simulator)
+ * complain if we don't.
+ */
+ cl_emit(&job->indirect, TESSELLATION_GEOMETRY_COMMON_PARAMS, shader) {
+ shader.tessellation_type = TESSELLATION_TYPE_TRIANGLE;
+ shader.tessellation_point_mode = false;
+ shader.tessellation_edge_spacing = TESSELLATION_EDGE_SPACING_EVEN;
+ shader.tessellation_clockwise = true;
+ shader.tessellation_invocations = 1;
+
+ shader.geometry_shader_output_format =
+ v3d_gs_output_primitive(gs_out_prim_type);
+ shader.geometry_shader_instances = 1; /* FIXME */
+ }
+}
+
+static void
+v3d_emit_tes_gs_shader_params(struct v3d_job *job,
+ struct v3d_gs_prog_data *gs)
+{
+ cl_emit(&job->indirect, TESSELLATION_GEOMETRY_SHADER_PARAMS, shader) {
+ shader.tcs_batch_flush_mode = V3D_TCS_FLUSH_MODE_FULLY_PACKED;
+ shader.per_patch_data_column_depth = 1;
+ shader.tcs_output_segment_size_in_sectors = 1;
+ shader.tcs_output_segment_pack_mode = V3D_PACK_MODE_16_WAY;
+ shader.tes_output_segment_size_in_sectors = 1;
+ shader.tes_output_segment_pack_mode = V3D_PACK_MODE_16_WAY;
+ shader.gs_output_segment_size_in_sectors =
+ gs->vpm_output_size;
+ shader.gs_output_segment_pack_mode = V3D_PACK_MODE_16_WAY; /* FIXME*/
+ shader.tbg_max_patches_per_tcs_batch = 1;
+ shader.tbg_max_extra_vertex_segs_for_patches_after_first = 0;
+ shader.tbg_min_tcs_output_segments_required_in_play = 1;
+ shader.tbg_min_per_patch_data_segments_required_in_play = 1;
+ shader.tpg_max_patches_per_tes_batch = 1;
+ shader.tpg_max_vertex_segments_per_tes_batch = 0;
+ shader.tpg_max_tcs_output_segments_per_tes_batch = 1;
+ shader.tpg_min_tes_output_segments_required_in_play = 1;
+ shader.gbg_max_tes_output_vertex_segments_per_gs_batch = 0;
+ shader.gbg_min_gs_output_segments_required_in_play = 1;
+ }
+}
+
+#endif
+
static void
v3d_emit_gl_shader_state(struct v3d_context *v3d,
const struct pipe_draw_info *info)
struct v3d_cl_reloc fs_uniforms =
v3d_write_uniforms(v3d, job, v3d->prog.fs,
PIPE_SHADER_FRAGMENT);
+
+ struct v3d_cl_reloc gs_uniforms = { NULL, 0 };
+ struct v3d_cl_reloc gs_bin_uniforms = { NULL, 0 };
+ if (v3d->prog.gs) {
+ gs_uniforms = v3d_write_uniforms(v3d, job, v3d->prog.gs,
+ PIPE_SHADER_GEOMETRY);
+ }
+ if (v3d->prog.gs_bin) {
+ gs_bin_uniforms = v3d_write_uniforms(v3d, job, v3d->prog.gs_bin,
+ PIPE_SHADER_GEOMETRY);
+ }
+
struct v3d_cl_reloc vs_uniforms =
v3d_write_uniforms(v3d, job, v3d->prog.vs,
PIPE_SHADER_VERTEX);
/* Update the cache dirty flag based on the shader progs data */
job->tmu_dirty_rcl |= v3d->prog.cs->prog_data.vs->base.tmu_dirty_rcl;
job->tmu_dirty_rcl |= v3d->prog.vs->prog_data.vs->base.tmu_dirty_rcl;
+ if (v3d->prog.gs_bin) {
+ job->tmu_dirty_rcl |=
+ v3d->prog.gs_bin->prog_data.gs->base.tmu_dirty_rcl;
+ }
+ if (v3d->prog.gs) {
+ job->tmu_dirty_rcl |=
+ v3d->prog.gs->prog_data.gs->base.tmu_dirty_rcl;
+ }
job->tmu_dirty_rcl |= v3d->prog.fs->prog_data.fs->base.tmu_dirty_rcl;
/* See GFXH-930 workaround below */
uint32_t num_elements_to_emit = MAX2(vtx->num_elements, 1);
+
+ uint32_t shader_state_record_length =
+ cl_packet_length(GL_SHADER_STATE_RECORD);
+#if V3D_VERSION >= 41
+ if (v3d->prog.gs) {
+ shader_state_record_length +=
+ cl_packet_length(GEOMETRY_SHADER_STATE_RECORD) +
+ cl_packet_length(TESSELLATION_GEOMETRY_COMMON_PARAMS) +
+ 2 * cl_packet_length(TESSELLATION_GEOMETRY_SHADER_PARAMS);
+ }
+#endif
+
uint32_t shader_rec_offset =
- v3d_cl_ensure_space(&job->indirect,
- cl_packet_length(GL_SHADER_STATE_RECORD) +
+ v3d_cl_ensure_space(&job->indirect,
+ shader_state_record_length +
num_elements_to_emit *
cl_packet_length(GL_SHADER_STATE_ATTRIBUTE_RECORD),
32);
* compile time, so that we mostly just have to OR the VS and FS
* records together at draw time.
*/
+#if V3D_VERSION >= 41
+ if (v3d->prog.gs) {
+ v3d_emit_gs_state_record(v3d->job,
+ v3d->prog.gs_bin, gs_bin_uniforms,
+ v3d->prog.gs, gs_uniforms);
+
+ struct v3d_gs_prog_data *gs = v3d->prog.gs->prog_data.gs;
+ struct v3d_gs_prog_data *gs_bin = v3d->prog.gs_bin->prog_data.gs;
+
+ v3d_emit_tes_gs_common_params(v3d->job, gs->out_prim_type);
+ v3d_emit_tes_gs_shader_params(v3d->job, gs_bin);
+ v3d_emit_tes_gs_shader_params(v3d->job, gs);
+ }
+#endif
+
cl_emit(&job->indirect, GL_SHADER_STATE_RECORD, shader) {
shader.enable_clipping = true;
/* VC5_DIRTY_PRIM_MODE | VC5_DIRTY_RASTERIZER */
shader.fragment_shader_uses_real_pixel_centre_w_in_addition_to_centroid_w2 =
v3d->prog.fs->prog_data.fs->uses_center_w;
+#if V3D_VERSION >= 41
+ shader.any_shader_reads_hardware_written_primitive_id =
+ v3d->prog.gs ? v3d->prog.gs->prog_data.gs->uses_pid :
+ false;
+#endif
+
#if V3D_VERSION >= 40
shader.do_scoreboard_wait_on_first_thread_switch =
v3d->prog.fs->prog_data.fs->lock_scoreboard_on_first_thrsw;
v3d->prog.vs->prog_data.vs->vcm_cache_size;
}
+#if V3D_VERSION >= 41
+ if (v3d->prog.gs) {
+ cl_emit(&job->bcl, GL_SHADER_STATE_INCLUDING_GS, state) {
+ state.address = cl_address(job->indirect.bo,
+ shader_rec_offset);
+ state.number_of_attribute_arrays = num_elements_to_emit;
+ }
+ } else {
+ cl_emit(&job->bcl, GL_SHADER_STATE, state) {
+ state.address = cl_address(job->indirect.bo,
+ shader_rec_offset);
+ state.number_of_attribute_arrays = num_elements_to_emit;
+ }
+ }
+#else
+ assert(!v3d->prog.gs);
cl_emit(&job->bcl, GL_SHADER_STATE, state) {
state.address = cl_address(job->indirect.bo, shader_rec_offset);
state.number_of_attribute_arrays = num_elements_to_emit;
}
+#endif
v3d_bo_unreference(&cs_uniforms.bo);
v3d_bo_unreference(&vs_uniforms.bo);
+ if (gs_uniforms.bo)
+ v3d_bo_unreference(&gs_uniforms.bo);
+ if (gs_bin_uniforms.bo)
+ v3d_bo_unreference(&gs_bin_uniforms.bo);
v3d_bo_unreference(&fs_uniforms.bo);
}
VC5_DIRTY_RASTERIZER |
VC5_DIRTY_COMPILED_CS |
VC5_DIRTY_COMPILED_VS |
+ VC5_DIRTY_COMPILED_GS_BIN |
+ VC5_DIRTY_COMPILED_GS |
VC5_DIRTY_COMPILED_FS |
v3d->prog.cs->uniform_dirty_bits |
v3d->prog.vs->uniform_dirty_bits |
+ (v3d->prog.gs_bin ?
+ v3d->prog.gs_bin->uniform_dirty_bits : 0) |
+ (v3d->prog.gs ?
+ v3d->prog.gs->uniform_dirty_bits : 0) |
v3d->prog.fs->uniform_dirty_bits)) {
v3d_emit_gl_shader_state(v3d, info);
}