From 1082735bb69e9f64cb3991a52f0e270902917855 Mon Sep 17 00:00:00 2001 From: Brian Paul Date: Thu, 22 Oct 2015 15:36:25 -0600 Subject: [PATCH] svga: detect constant color writes in fragment shaders MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Examine the fragment shader to try to detect TGSI shaders which use "MOV OUT[0], CONST[i]" to write a constant value for the fragment color. In this case, all fragments will have the same color (unless blending is enabled). This is a common case for OpenGL code such as: glColor(), glBegin(), glVertex(), ..., glEnd() when lighting/fog/etc are disabled. In this case, the Mesa/gallium state tracker actually generates a simple "MOV OUT[0], CONST[i]" fragment shader. This will be used by the next commit to avoid provoking vertex conversion (creating/rewriting an index buffer) when drawing flat-shaded primitives. Reviewed-by: Charmaine Lee Reviewed-by: José Fonseca --- src/gallium/drivers/svga/svga_shader.h | 3 ++ src/gallium/drivers/svga/svga_tgsi.c | 7 ++++ src/gallium/drivers/svga/svga_tgsi_emit.h | 3 ++ src/gallium/drivers/svga/svga_tgsi_insn.c | 27 ++++++++++++++ src/gallium/drivers/svga/svga_tgsi_vgpu10.c | 39 +++++++++++++++++++-- 5 files changed, 77 insertions(+), 2 deletions(-) diff --git a/src/gallium/drivers/svga/svga_shader.h b/src/gallium/drivers/svga/svga_shader.h index efcac408626..f49fdb46d0e 100644 --- a/src/gallium/drivers/svga/svga_shader.h +++ b/src/gallium/drivers/svga/svga_shader.h @@ -155,6 +155,9 @@ struct svga_shader_variant * applied to any of the varyings. */ + /** Is the color output just a constant value? (fragment shader only) */ + boolean constant_color_output; + /** For FS-based polygon stipple */ unsigned pstipple_sampler_unit; diff --git a/src/gallium/drivers/svga/svga_tgsi.c b/src/gallium/drivers/svga/svga_tgsi.c index 202eee276b7..4c16f4313a0 100644 --- a/src/gallium/drivers/svga/svga_tgsi.c +++ b/src/gallium/drivers/svga/svga_tgsi.c @@ -240,6 +240,13 @@ svga_tgsi_vgpu9_translate(struct svga_context *svga, variant->pstipple_sampler_unit = emit.pstipple_sampler_unit; + /* If there was exactly one write to a fragment shader output register + * and it came from a constant buffer, we know all fragments will have + * the same color (except for blending). + */ + variant->constant_color_output = + emit.constant_color_output && emit.num_output_writes == 1; + #if 0 if (!svga_shader_verify(variant->tokens, variant->nr_tokens) || SVGA_DEBUG & DEBUG_TGSI) { diff --git a/src/gallium/drivers/svga/svga_tgsi_emit.h b/src/gallium/drivers/svga/svga_tgsi_emit.h index 0b82483ab2e..83f0c8bd4d0 100644 --- a/src/gallium/drivers/svga/svga_tgsi_emit.h +++ b/src/gallium/drivers/svga/svga_tgsi_emit.h @@ -84,6 +84,9 @@ struct svga_shader_emitter int dynamic_branching_level; + unsigned num_output_writes; + boolean constant_color_output; + boolean in_main_func; boolean created_common_immediate; diff --git a/src/gallium/drivers/svga/svga_tgsi_insn.c b/src/gallium/drivers/svga/svga_tgsi_insn.c index 00c91a4fa61..dbb90f7654e 100644 --- a/src/gallium/drivers/svga/svga_tgsi_insn.c +++ b/src/gallium/drivers/svga/svga_tgsi_insn.c @@ -99,6 +99,7 @@ translate_dst_register( struct svga_shader_emitter *emit, * Need to lookup a table built at decl time: */ dest = emit->output_map[reg->Register.Index]; + emit->num_output_writes++; break; default: @@ -2102,6 +2103,29 @@ emit_simple_instruction(struct svga_shader_emitter *emit, } +/** + * TGSI_OPCODE_MOVE is only special-cased here to detect the + * svga_fragment_shader::constant_color_output case. + */ +static boolean +emit_mov(struct svga_shader_emitter *emit, + const struct tgsi_full_instruction *insn) +{ + const struct tgsi_full_src_register *src = &insn->Src[0]; + const struct tgsi_full_dst_register *dst = &insn->Dst[0]; + + if (emit->unit == PIPE_SHADER_FRAGMENT && + dst->Register.File == TGSI_FILE_OUTPUT && + dst->Register.Index == 0 && + src->Register.File == TGSI_FILE_CONSTANT && + !src->Register.Indirect) { + emit->constant_color_output = TRUE; + } + + return emit_simple_instruction(emit, SVGA3DOP_MOV, insn); +} + + /** * Translate/emit TGSI DDX, DDY instructions. */ @@ -3045,6 +3069,9 @@ svga_emit_instruction(struct svga_shader_emitter *emit, case TGSI_OPCODE_SSG: return emit_ssg( emit, insn ); + case TGSI_OPCODE_MOV: + return emit_mov( emit, insn ); + default: { unsigned opcode = translate_opcode(insn->Instruction.Opcode); diff --git a/src/gallium/drivers/svga/svga_tgsi_vgpu10.c b/src/gallium/drivers/svga/svga_tgsi_vgpu10.c index 332904f88b4..e70ee689c59 100644 --- a/src/gallium/drivers/svga/svga_tgsi_vgpu10.c +++ b/src/gallium/drivers/svga/svga_tgsi_vgpu10.c @@ -202,6 +202,9 @@ struct svga_shader_emitter_v10 /* user clip plane constant slot indexes */ unsigned clip_plane_const[PIPE_MAX_CLIP_PLANES]; + unsigned num_output_writes; + boolean constant_color_output; + boolean uses_flat_interp; /* For all shaders: const reg index for RECT coord scaling */ @@ -913,6 +916,8 @@ emit_dst_register(struct svga_shader_emitter_v10 *emit, */ assert(sem_name == TGSI_SEMANTIC_COLOR); index = emit->info.output_semantic_index[index]; + + emit->num_output_writes++; } } } @@ -5572,6 +5577,29 @@ emit_simple(struct svga_shader_emitter_v10 *emit, } +/** + * We only special case the MOV instruction to try to detect constant + * color writes in the fragment shader. + */ +static boolean +emit_mov(struct svga_shader_emitter_v10 *emit, + const struct tgsi_full_instruction *inst) +{ + const struct tgsi_full_src_register *src = &inst->Src[0]; + const struct tgsi_full_dst_register *dst = &inst->Dst[0]; + + if (emit->unit == PIPE_SHADER_FRAGMENT && + dst->Register.File == TGSI_FILE_OUTPUT && + dst->Register.Index == 0 && + src->Register.File == TGSI_FILE_CONSTANT && + !src->Register.Indirect) { + emit->constant_color_output = TRUE; + } + + return emit_simple(emit, inst); +} + + /** * Emit a simple VGPU10 instruction which writes to multiple dest registers, * where TGSI only uses one dest register. @@ -5652,7 +5680,6 @@ emit_vgpu10_instruction(struct svga_shader_emitter_v10 *emit, case TGSI_OPCODE_MAD: case TGSI_OPCODE_MAX: case TGSI_OPCODE_MIN: - case TGSI_OPCODE_MOV: case TGSI_OPCODE_MUL: case TGSI_OPCODE_NOP: case TGSI_OPCODE_NOT: @@ -5677,7 +5704,8 @@ emit_vgpu10_instruction(struct svga_shader_emitter_v10 *emit, /* simple instructions */ return emit_simple(emit, inst); - + case TGSI_OPCODE_MOV: + return emit_mov(emit, inst); case TGSI_OPCODE_EMIT: return emit_vertex(emit, inst); case TGSI_OPCODE_ENDPRIM: @@ -6762,6 +6790,13 @@ svga_tgsi_vgpu10_translate(struct svga_context *svga, variant->pstipple_sampler_unit = emit->fs.pstipple_sampler_unit; + /* If there was exactly one write to a fragment shader output register + * and it came from a constant buffer, we know all fragments will have + * the same color (except for blending). + */ + variant->constant_color_output = + emit->constant_color_output && emit->num_output_writes == 1; + /** keep track in the variant if flat interpolation is used * for any of the varyings. */ -- 2.30.2