[Mesa-dev] [PATCH] llvmpipe: handle NULL color buffer pointers
Roland Scheidegger
sroland at vmware.com
Thu Jan 16 09:46:11 PST 2014
Am 16.01.2014 17:20, schrieb Brian Paul:
> Fixes regression from 9baa45f78b8ca7d66280e36009b6a685055d7cd6
>
> v2: incorporate a few small changes suggested by Roland.
> ---
> 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(-)
>
> diff --git a/src/gallium/drivers/llvmpipe/lp_rast.c b/src/gallium/drivers/llvmpipe/lp_rast.c
> index 6feec94..6ee849b 100644
> --- a/src/gallium/drivers/llvmpipe/lp_rast.c
> +++ b/src/gallium/drivers/llvmpipe/lp_rast.c
> @@ -110,6 +110,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.
> * Clear commands always clear all bound layers.
> @@ -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 bc361b6..063a70e 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 0296b79..9ba5f1a 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 7f22231..2437318 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 eedafa3..abdb6b3 100644
> --- a/src/gallium/drivers/llvmpipe/lp_state_fs.c
> +++ b/src/gallium/drivers/llvmpipe/lp_state_fs.c
> @@ -2361,28 +2361,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);
> @@ -2900,6 +2905,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;
> }
> @@ -2927,64 +2933,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;
> }
> }
>
>
LGTM.
Roland
More information about the mesa-dev
mailing list