From 97fdace6d70b6499d0490cd6ca2a4253284b386d Mon Sep 17 00:00:00 2001 From: Brian Paul Date: Fri, 31 Jan 2014 17:23:11 -0700 Subject: [PATCH] svga: check shader size against max command buffer size If the shader is too large, plug in a dummy shader. This patch also reworks the existing dummy shader code. Reviewed-by: Jose Fonseca --- src/gallium/drivers/svga/include/svga_reg.h | 1 + src/gallium/drivers/svga/svga_state_fs.c | 60 ++++++++++++++++----- 2 files changed, 49 insertions(+), 12 deletions(-) diff --git a/src/gallium/drivers/svga/include/svga_reg.h b/src/gallium/drivers/svga/include/svga_reg.h index 1b96c2ec07d..dee719d2418 100644 --- a/src/gallium/drivers/svga/include/svga_reg.h +++ b/src/gallium/drivers/svga/include/svga_reg.h @@ -889,6 +889,7 @@ typedef enum { } SVGAFifoCmdId; #define SVGA_CMD_MAX_ARGS 64 +#define SVGA_CB_MAX_COMMAND_SIZE (32 * 1024) // 32 KB /* diff --git a/src/gallium/drivers/svga/svga_state_fs.c b/src/gallium/drivers/svga/svga_state_fs.c index 860a0c8e0cf..7119a19f0a8 100644 --- a/src/gallium/drivers/svga/svga_state_fs.c +++ b/src/gallium/drivers/svga/svga_state_fs.c @@ -76,12 +76,18 @@ search_fs_key(const struct svga_fragment_shader *fs, /** * If we fail to compile a fragment shader (because it uses too many * registers, for example) we'll use a dummy/fallback shader that - * simply emits a constant color. + * simply emits a constant color (red for debug, black for release). + * We hit this with the Unigine/Heaven demo when Shaders = High. + * With black, the demo still looks good. */ static const struct tgsi_token * get_dummy_fragment_shader(void) { - static const float red[4] = { 1.0, 0.0, 0.0, 0.0 }; +#ifdef DEBUG + static const float color[4] = { 1.0, 0.0, 0.0, 0.0 }; /* red */ +#else + static const float color[4] = { 0.0, 0.0, 0.0, 0.0 }; /* black */ +#endif struct ureg_program *ureg; const struct tgsi_token *tokens; struct ureg_src src; @@ -93,7 +99,7 @@ get_dummy_fragment_shader(void) return NULL; dst = ureg_DECL_output(ureg, TGSI_SEMANTIC_COLOR, 0); - src = ureg_DECL_immediate(ureg, red, 4); + src = ureg_DECL_immediate(ureg, color, 4); ureg_MOV(ureg, dst, src); ureg_END(ureg); @@ -105,6 +111,29 @@ get_dummy_fragment_shader(void) } +/** + * Replace the given shader's instruction with a simple constant-color + * shader. We use this when normal shader translation fails. + */ +static struct svga_shader_variant * +get_compiled_dummy_shader(struct svga_fragment_shader *fs, + const struct svga_fs_compile_key *key) +{ + const struct tgsi_token *dummy = get_dummy_fragment_shader(); + struct svga_shader_variant *variant; + + if (!dummy) { + return NULL; + } + + FREE((void *) fs->base.tokens); + fs->base.tokens = dummy; + + variant = svga_translate_fragment_program(fs, key); + return variant; +} + + /** * Translate TGSI shader into an svga shader variant. */ @@ -119,17 +148,24 @@ compile_fs(struct svga_context *svga, variant = svga_translate_fragment_program( fs, key ); if (variant == NULL) { - /* some problem during translation, try the dummy shader */ - const struct tgsi_token *dummy = get_dummy_fragment_shader(); - if (!dummy) { - ret = PIPE_ERROR_OUT_OF_MEMORY; + debug_printf("Failed to compile fragment shader," + " using dummy shader instead.\n"); + variant = get_compiled_dummy_shader(fs, key); + if (!variant) { + ret = PIPE_ERROR; goto fail; } - debug_printf("Failed to compile fragment shader, using dummy shader instead.\n"); - FREE((void *) fs->base.tokens); - fs->base.tokens = dummy; - variant = svga_translate_fragment_program(fs, key); - if (variant == NULL) { + } + + if (variant->nr_tokens * sizeof(variant->tokens[0]) + + sizeof(SVGA3dCmdDefineShader) + sizeof(SVGA3dCmdHeader) + >= SVGA_CB_MAX_COMMAND_SIZE) { + /* too big, use dummy shader */ + debug_printf("Shader too large (%lu bytes)," + " using dummy shader instead.\n", + (unsigned long ) variant->nr_tokens * sizeof(variant->tokens[0])); + variant = get_compiled_dummy_shader(fs, key); + if (!variant) { ret = PIPE_ERROR; goto fail; } -- 2.30.2