From d6fa71fbb0d365cefdabfea9de62cfece71f7486 Mon Sep 17 00:00:00 2001 From: Brian Paul Date: Wed, 15 Jan 2014 18:09:56 -0800 Subject: llvmpipe: handle NULL color buffer pointers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes regression from 9baa45f78b8ca7d66280e36009b6a685055d7cd6 v2: incorporate a few small changes suggested by Roland. Reviewed-by: José Fonseca Reviewed-by: Roland Scheidegger --- src/gallium/drivers/llvmpipe/lp_rast.c | 62 ++++++++---- src/gallium/drivers/llvmpipe/lp_rast_priv.h | 11 +- src/gallium/drivers/llvmpipe/lp_scene.c | 23 +++-- src/gallium/drivers/llvmpipe/lp_setup.c | 2 +- src/gallium/drivers/llvmpipe/lp_state_fs.c | 152 +++++++++++++++------------- 5 files changed, 156 insertions(+), 94 deletions(-) (limited to 'src/gallium') diff --git a/src/gallium/drivers/llvmpipe/lp_rast.c b/src/gallium/drivers/llvmpipe/lp_rast.c index 6feec947137..6ee849b64ad 100644 --- a/src/gallium/drivers/llvmpipe/lp_rast.c +++ b/src/gallium/drivers/llvmpipe/lp_rast.c @@ -109,6 +109,25 @@ lp_rast_tile_begin(struct lp_rasterizer_task *task, } +/** + * Examine a framebuffer object to determine if any of the colorbuffers + * use a pure integer format. + * XXX this could be a gallium utility function if useful elsewhere. + */ +static boolean +is_fb_pure_integer(const struct pipe_framebuffer_state *fb) +{ + unsigned i; + for (i = 0; i < fb->nr_cbufs; i++) { + if (fb->cbufs[i] && + util_format_is_pure_integer(fb->cbufs[i]->format)) { + return TRUE; + } + } + return FALSE; +} + + /** * Clear the rasterizer's current color tile. * This is a bin command called during bin processing. @@ -124,7 +143,7 @@ lp_rast_clear_color(struct lp_rasterizer_task *task, unsigned i; union util_color uc; - if (util_format_is_pure_integer(scene->fb.cbufs[0]->format)) { + if (is_fb_pure_integer(&scene->fb)) { /* * We expect int/uint clear values here, though some APIs * might disagree (but in any case util_pack_color() @@ -174,20 +193,22 @@ lp_rast_clear_color(struct lp_rasterizer_task *task, clear_color[3]); for (i = 0; i < scene->fb.nr_cbufs; i++) { - util_pack_color(arg.clear_color.f, - scene->fb.cbufs[i]->format, &uc); - - util_fill_box(scene->cbufs[i].map, - scene->fb.cbufs[i]->format, - scene->cbufs[i].stride, - scene->cbufs[i].layer_stride, - task->x, - task->y, - 0, - task->width, - task->height, - scene->fb_max_layer + 1, - &uc); + if (scene->fb.cbufs[i]) { + util_pack_color(arg.clear_color.f, + scene->fb.cbufs[i]->format, &uc); + + util_fill_box(scene->cbufs[i].map, + scene->fb.cbufs[i]->format, + scene->cbufs[i].stride, + scene->cbufs[i].layer_stride, + task->x, + task->y, + 0, + task->width, + task->height, + scene->fb_max_layer + 1, + &uc); + } } } } @@ -444,8 +465,15 @@ lp_rast_shade_quads_mask(struct lp_rasterizer_task *task, /* color buffer */ for (i = 0; i < scene->fb.nr_cbufs; i++) { - stride[i] = scene->cbufs[i].stride; - color[i] = lp_rast_get_unswizzled_color_block_pointer(task, i, x, y, inputs->layer); + if (scene->fb.cbufs[i]) { + stride[i] = scene->cbufs[i].stride; + color[i] = lp_rast_get_unswizzled_color_block_pointer(task, i, x, y, + inputs->layer); + } + else { + stride[i] = 0; + color[i] = NULL; + } } /* depth buffer */ diff --git a/src/gallium/drivers/llvmpipe/lp_rast_priv.h b/src/gallium/drivers/llvmpipe/lp_rast_priv.h index bc361b6f1b9..063a70e9a34 100644 --- a/src/gallium/drivers/llvmpipe/lp_rast_priv.h +++ b/src/gallium/drivers/llvmpipe/lp_rast_priv.h @@ -293,8 +293,15 @@ lp_rast_shade_quads_all( struct lp_rasterizer_task *task, /* color buffer */ for (i = 0; i < scene->fb.nr_cbufs; i++) { - stride[i] = scene->cbufs[i].stride; - color[i] = lp_rast_get_unswizzled_color_block_pointer(task, i, x, y, inputs->layer); + if (scene->fb.cbufs[i]) { + stride[i] = scene->cbufs[i].stride; + color[i] = lp_rast_get_unswizzled_color_block_pointer(task, i, x, y, + inputs->layer); + } + else { + stride[i] = 0; + color[i] = NULL; + } } if (scene->zsbuf.map) { diff --git a/src/gallium/drivers/llvmpipe/lp_scene.c b/src/gallium/drivers/llvmpipe/lp_scene.c index 0296b79edb4..9ba5f1ace2e 100644 --- a/src/gallium/drivers/llvmpipe/lp_scene.c +++ b/src/gallium/drivers/llvmpipe/lp_scene.c @@ -156,6 +156,14 @@ lp_scene_begin_rasterization(struct lp_scene *scene) for (i = 0; i < scene->fb.nr_cbufs; i++) { struct pipe_surface *cbuf = scene->fb.cbufs[i]; + + if (!cbuf) { + scene->cbufs[i].stride = 0; + scene->cbufs[i].layer_stride = 0; + scene->cbufs[i].map = NULL; + continue; + } + if (llvmpipe_resource_is_texture(cbuf->texture)) { scene->cbufs[i].stride = llvmpipe_resource_stride(cbuf->texture, cbuf->u.tex.level); @@ -171,7 +179,7 @@ lp_scene_begin_rasterization(struct lp_scene *scene) struct llvmpipe_resource *lpr = llvmpipe_resource(cbuf->texture); unsigned pixstride = util_format_get_blocksize(cbuf->format); scene->cbufs[i].stride = cbuf->texture->width0; - + scene->cbufs[i].layer_stride = 0; scene->cbufs[i].map = lpr->data; scene->cbufs[i].map += cbuf->u.buf.first_element * pixstride; } @@ -521,11 +529,14 @@ void lp_scene_begin_binning( struct lp_scene *scene, */ for (i = 0; i < scene->fb.nr_cbufs; i++) { struct pipe_surface *cbuf = scene->fb.cbufs[i]; - if (llvmpipe_resource_is_texture(cbuf->texture)) { - max_layer = MIN2(max_layer, cbuf->u.tex.last_layer - cbuf->u.tex.first_layer); - } - else { - max_layer = 0; + if (cbuf) { + if (llvmpipe_resource_is_texture(cbuf->texture)) { + max_layer = MIN2(max_layer, + cbuf->u.tex.last_layer - cbuf->u.tex.first_layer); + } + else { + max_layer = 0; + } } } if (fb->zsbuf) { diff --git a/src/gallium/drivers/llvmpipe/lp_setup.c b/src/gallium/drivers/llvmpipe/lp_setup.c index 58811b0edd3..50acf5157b6 100644 --- a/src/gallium/drivers/llvmpipe/lp_setup.c +++ b/src/gallium/drivers/llvmpipe/lp_setup.c @@ -882,7 +882,7 @@ lp_setup_is_resource_referenced( const struct lp_setup_context *setup, /* check the render targets */ for (i = 0; i < setup->fb.nr_cbufs; i++) { - if (setup->fb.cbufs[i]->texture == texture) + if (setup->fb.cbufs[i] && setup->fb.cbufs[i]->texture == texture) return LP_REFERENCED_FOR_READ | LP_REFERENCED_FOR_WRITE; } if (setup->fb.zsbuf && setup->fb.zsbuf->texture == texture) { diff --git a/src/gallium/drivers/llvmpipe/lp_state_fs.c b/src/gallium/drivers/llvmpipe/lp_state_fs.c index 31ed8478e9b..504a7aa2901 100644 --- a/src/gallium/drivers/llvmpipe/lp_state_fs.c +++ b/src/gallium/drivers/llvmpipe/lp_state_fs.c @@ -2362,28 +2362,33 @@ generate_fragment(struct llvmpipe_context *lp, /* Loop over color outputs / color buffers to do blending. */ for(cbuf = 0; cbuf < key->nr_cbufs; cbuf++) { - LLVMValueRef color_ptr; - LLVMValueRef stride; - LLVMValueRef index = lp_build_const_int32(gallivm, cbuf); + if (key->cbuf_format[cbuf] != PIPE_FORMAT_NONE) { + LLVMValueRef color_ptr; + LLVMValueRef stride; + LLVMValueRef index = lp_build_const_int32(gallivm, cbuf); - boolean do_branch = ((key->depth.enabled - || key->stencil[0].enabled - || key->alpha.enabled) - && !shader->info.base.uses_kill); + boolean do_branch = ((key->depth.enabled + || key->stencil[0].enabled + || key->alpha.enabled) + && !shader->info.base.uses_kill); - color_ptr = LLVMBuildLoad(builder, - LLVMBuildGEP(builder, color_ptr_ptr, &index, 1, ""), - ""); + color_ptr = LLVMBuildLoad(builder, + LLVMBuildGEP(builder, color_ptr_ptr, + &index, 1, ""), + ""); - lp_build_name(color_ptr, "color_ptr%d", cbuf); + lp_build_name(color_ptr, "color_ptr%d", cbuf); - stride = LLVMBuildLoad(builder, - LLVMBuildGEP(builder, stride_ptr, &index, 1, ""), - ""); + stride = LLVMBuildLoad(builder, + LLVMBuildGEP(builder, stride_ptr, &index, 1, ""), + ""); - generate_unswizzled_blend(gallivm, cbuf, variant, key->cbuf_format[cbuf], - num_fs, fs_type, fs_mask, fs_out_color, - context_ptr, color_ptr, stride, partial_mask, do_branch); + generate_unswizzled_blend(gallivm, cbuf, variant, + key->cbuf_format[cbuf], + num_fs, fs_type, fs_mask, fs_out_color, + context_ptr, color_ptr, stride, + partial_mask, do_branch); + } } LLVMBuildRetVoid(builder); @@ -2901,6 +2906,7 @@ make_variant_key(struct llvmpipe_context *lp, /* alpha test only applies if render buffer 0 is non-integer (or does not exist) */ if (!lp->framebuffer.nr_cbufs || + !lp->framebuffer.cbufs[0] || !util_format_is_pure_integer(lp->framebuffer.cbufs[0]->format)) { key->alpha.enabled = lp->depth_stencil->alpha.enabled; } @@ -2928,64 +2934,74 @@ make_variant_key(struct llvmpipe_context *lp, } for (i = 0; i < lp->framebuffer.nr_cbufs; i++) { - enum pipe_format format = lp->framebuffer.cbufs[i]->format; struct pipe_rt_blend_state *blend_rt = &key->blend.rt[i]; - const struct util_format_description *format_desc; - key->cbuf_format[i] = format; + if (lp->framebuffer.cbufs[i]) { + enum pipe_format format = lp->framebuffer.cbufs[i]->format; + const struct util_format_description *format_desc; - /* - * Figure out if this is a 1d resource. Note that OpenGL allows crazy - * mixing of 2d textures with height 1 and 1d textures, so make sure - * we pick 1d if any cbuf or zsbuf is 1d. - */ - if (llvmpipe_resource_is_1d(lp->framebuffer.cbufs[0]->texture)) { - key->resource_1d = TRUE; - } + key->cbuf_format[i] = format; - format_desc = util_format_description(format); - assert(format_desc->colorspace == UTIL_FORMAT_COLORSPACE_RGB || - format_desc->colorspace == UTIL_FORMAT_COLORSPACE_SRGB); + /* + * Figure out if this is a 1d resource. Note that OpenGL allows crazy + * mixing of 2d textures with height 1 and 1d textures, so make sure + * we pick 1d if any cbuf or zsbuf is 1d. + */ + if (llvmpipe_resource_is_1d(lp->framebuffer.cbufs[i]->texture)) { + key->resource_1d = TRUE; + } - /* - * Mask out color channels not present in the color buffer. - */ - blend_rt->colormask &= util_format_colormask(format_desc); + format_desc = util_format_description(format); + assert(format_desc->colorspace == UTIL_FORMAT_COLORSPACE_RGB || + format_desc->colorspace == UTIL_FORMAT_COLORSPACE_SRGB); - /* - * Disable blend for integer formats. - */ - if (util_format_is_pure_integer(format)) { - blend_rt->blend_enable = 0; - } + /* + * Mask out color channels not present in the color buffer. + */ + blend_rt->colormask &= util_format_colormask(format_desc); - /* - * Our swizzled render tiles always have an alpha channel, but the linear - * render target format often does not, so force here the dst alpha to be - * one. - * - * This is not a mere optimization. Wrong results will be produced if the - * dst alpha is used, the dst format does not have alpha, and the previous - * rendering was not flushed from the swizzled to linear buffer. For - * example, NonPowTwo DCT. - * - * TODO: This should be generalized to all channels for better - * performance, but only alpha causes correctness issues. - * - * Also, force rgb/alpha func/factors match, to make AoS blending easier. - */ - if (format_desc->swizzle[3] > UTIL_FORMAT_SWIZZLE_W || - format_desc->swizzle[3] == format_desc->swizzle[0]) { - /* Doesn't cover mixed snorm/unorm but can't render to them anyway */ - boolean clamped_zero = !util_format_is_float(format) && - !util_format_is_snorm(format); - blend_rt->rgb_src_factor = force_dst_alpha_one(blend_rt->rgb_src_factor, - clamped_zero); - blend_rt->rgb_dst_factor = force_dst_alpha_one(blend_rt->rgb_dst_factor, - clamped_zero); - blend_rt->alpha_func = blend_rt->rgb_func; - blend_rt->alpha_src_factor = blend_rt->rgb_src_factor; - blend_rt->alpha_dst_factor = blend_rt->rgb_dst_factor; + /* + * Disable blend for integer formats. + */ + if (util_format_is_pure_integer(format)) { + blend_rt->blend_enable = 0; + } + + /* + * Our swizzled render tiles always have an alpha channel, but the + * linear render target format often does not, so force here the dst + * alpha to be one. + * + * This is not a mere optimization. Wrong results will be produced if + * the dst alpha is used, the dst format does not have alpha, and the + * previous rendering was not flushed from the swizzled to linear + * buffer. For example, NonPowTwo DCT. + * + * TODO: This should be generalized to all channels for better + * performance, but only alpha causes correctness issues. + * + * Also, force rgb/alpha func/factors match, to make AoS blending + * easier. + */ + if (format_desc->swizzle[3] > UTIL_FORMAT_SWIZZLE_W || + format_desc->swizzle[3] == format_desc->swizzle[0]) { + /* Doesn't cover mixed snorm/unorm but can't render to them anyway */ + boolean clamped_zero = !util_format_is_float(format) && + !util_format_is_snorm(format); + blend_rt->rgb_src_factor = + force_dst_alpha_one(blend_rt->rgb_src_factor, clamped_zero); + blend_rt->rgb_dst_factor = + force_dst_alpha_one(blend_rt->rgb_dst_factor, clamped_zero); + blend_rt->alpha_func = blend_rt->rgb_func; + blend_rt->alpha_src_factor = blend_rt->rgb_src_factor; + blend_rt->alpha_dst_factor = blend_rt->rgb_dst_factor; + } + } + else { + /* no color buffer for this fragment output */ + key->cbuf_format[i] = PIPE_FORMAT_NONE; + blend_rt->colormask = 0x0; + blend_rt->blend_enable = 0; } } -- cgit v1.2.3