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 <jfonseca@vmware.com>
(cherry picked from commit 97fdace6d7)
This commit is contained in:
Brian Paul 2014-01-31 17:23:11 -07:00
parent 16c03a004d
commit 07d1e7f12f
2 changed files with 49 additions and 12 deletions

View file

@ -889,6 +889,7 @@ typedef enum {
} SVGAFifoCmdId;
#define SVGA_CMD_MAX_ARGS 64
#define SVGA_CB_MAX_COMMAND_SIZE (32 * 1024) // 32 KB
/*

View file

@ -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;
}