[Mesa-dev] [PATCH V3 1/2] i965/blorp: Add bilinear filtering of samples for multisample scaled blits
Paul Berry
stereotype441 at gmail.com
Wed Jun 26 20:56:30 PDT 2013
On 26 June 2013 19:41, Anuj Phogat <anuj.phogat at gmail.com> wrote:
> On Tue, Jun 25, 2013 at 10:27 AM, Paul Berry <stereotype441 at gmail.com>
> wrote:
> >
> > On 19 June 2013 19:45, Anuj Phogat <anuj.phogat at gmail.com> wrote:
> >>
> >> Current implementation of ext_framebuffer_multisample_blit_scaled in
> >> i965/blorp uses nearest filtering for multisample scaled blits. Using
> >> nearest filtering produces blocky artifacts and negates the benefits
> >> of MSAA. That is the reason why extension was not enabled on i965.
> >>
> >> This patch implements the bilinear filtering of samples in blorp engine.
> >> Images generated with this patch are free from blocky artifacts and show
> >> big improvement in visual quality.
> >>
> >> Observed no piglit and gles3 regressions.
> >>
> >> V3:
> >> - Algorithm used for filtering assumes a rectangular grid of samples
> >> roughly corresponding to sample locations.
> >> - Test the boundary conditions on the edges of texture.
> >>
> >> Signed-off-by: Anuj Phogat <anuj.phogat at gmail.com>
> >
> >
> > Thanks for all your effort on this, Anuj. I think we have an algorithm
> that's going to get us good quality. I have a number of minor comments
> below, but I think the basic approach is good.
> >
> >>
> >> ---
> >> src/mesa/drivers/dri/i965/brw_blorp.h | 11 ++
> >> src/mesa/drivers/dri/i965/brw_blorp_blit.cpp | 257
> +++++++++++++++++++++++++--
> >> 2 files changed, 258 insertions(+), 10 deletions(-)
> >>
> >> diff --git a/src/mesa/drivers/dri/i965/brw_blorp.h
> b/src/mesa/drivers/dri/i965/brw_blorp.h
> >> index ffc27cc..0a15b89 100644
> >> --- a/src/mesa/drivers/dri/i965/brw_blorp.h
> >> +++ b/src/mesa/drivers/dri/i965/brw_blorp.h
> >> @@ -319,6 +319,17 @@ struct brw_blorp_blit_prog_key
> >> * than one sample per pixel.
> >> */
> >> bool persample_msaa_dispatch;
> >> +
> >> + /* True for scaled blitting. */
> >> + bool blit_scaled;
> >> +
> >> + /* Source rectangle dimensions. Used to test boundary conditions in
> shader
> >> + * program.
> >> + */
> >> + float src_x0;
> >> + float src_y0;
> >> + float src_x1;
> >> + float src_y1;
> >
> >
> > Two comments about this:
> >
> > (1) Rather than clamp to the boundary of the source rectangle, I have a
> minor preference for clamping to the boundary of the source image. This is
> what I've observed in nVidia's blitter, and it's what's implemented in
> Mesa's meta path for scaled blits. Also, it would have the benefit of
> simplifying some of the logic below, since the lower clamp will always be 0.
> >
> > (2) We can't put these numbers in the program key, since they're going
> to change frequently, and changing the program key causes the program to be
> recompiled. They need to go in push constants, like we do for the
> destination rectangle coordinates and the multipliers and offsets.
> >
> >
> >>
> >> };
> >>
> >> class brw_blorp_blit_params : public brw_blorp_params
> >> diff --git a/src/mesa/drivers/dri/i965/brw_blorp_blit.cpp
> b/src/mesa/drivers/dri/i965/brw_blorp_blit.cpp
> >> index 8694128..e99c9df 100644
> >> --- a/src/mesa/drivers/dri/i965/brw_blorp_blit.cpp
> >> +++ b/src/mesa/drivers/dri/i965/brw_blorp_blit.cpp
> >> @@ -622,7 +622,8 @@ private:
> >> void kill_if_outside_dst_rect();
> >> void translate_dst_to_src();
> >> void single_to_blend();
> >> - void manual_blend(unsigned num_samples);
> >> + void manual_blend_average(unsigned num_samples);
> >> + void manual_blend_linear(unsigned num_samples);
> >
> >
> > Minor nit pick: can we call this function manual_blend_bilinear()?
> "linear" is such a generic term that it's hard to guess what it does, but
> "bilinear" makes it obvious.
> >
> >>
> >> void sample(struct brw_reg dst);
> >> void texel_fetch(struct brw_reg dst);
> >> void mcs_fetch();
> >> @@ -676,6 +677,16 @@ private:
> >> */
> >> struct brw_reg y_coords[2];
> >>
> >> + /* X, Y coordinates of the pixel from which we need to fetch the
> specific
> >> + * sample. These are used for multisample scaled blitting.
> >> + */
> >> + struct brw_reg x_sample_coords;
> >> + struct brw_reg y_sample_coords;
> >> +
> >> + /* Store the values to use to interpolate in x and y directions */
> >> + struct brw_reg x_lerp;
> >> + struct brw_reg y_lerp;
> >> +
> >
> >
> > I had trouble guessing what the "lerp" variables are used for. How
> about something like this instead?
> >
> > /* Fractional parts of the x and y coordinates, used as bilinear
> interpolation coefficients */
> > struct brw_reg x_frac;
> > struct brw_reg y_frac;
> >
> >>
> >> /* Which element of x_coords and y_coords is currently in use.
> >> */
> >> int xy_coord_index;
> >> @@ -814,15 +825,17 @@ brw_blorp_blit_program::compile(struct
> brw_context *brw,
> >> * that we want to texture from. Exception: if we are blending,
> then S is
> >> * irrelevant, because we are going to fetch all samples.
> >> */
> >> - if (key->blend) {
> >> + if (key->blend && !key->blit_scaled) {
> >> if (brw->intel.gen == 6) {
> >> /* Gen6 hardware an automatically blend using the SAMPLE
> message */
> >> single_to_blend();
> >> sample(texture_data[0]);
> >> } else {
> >> /* Gen7+ hardware doesn't automaticaly blend. */
> >> - manual_blend(key->src_samples);
> >> + manual_blend_average(key->src_samples);
> >> }
> >> + } else if(key->blend && key->blit_scaled) {
> >> + manual_blend_linear(key->src_samples);
> >> } else {
> >> /* We aren't blending, which means we just want to fetch a
> single sample
> >> * from the source surface. The address that we want to fetch
> from is
> >> @@ -913,6 +926,18 @@ brw_blorp_blit_program::alloc_regs()
> >> = retype(brw_vec8_grf(reg, 0), BRW_REGISTER_TYPE_UD);
> >> reg += 2;
> >> }
> >> +
> >> + if (key->blit_scaled && key->blend) {
> >> + this->x_sample_coords = brw_vec8_grf(reg, 0);
> >> + reg += 2;
> >> + this->y_sample_coords = brw_vec8_grf(reg, 0);
> >> + reg += 2;
> >> + this->x_lerp = brw_vec8_grf(reg, 0);
> >> + reg += 2;
> >> + this->y_lerp = brw_vec8_grf(reg, 0);
> >> + reg += 2;
> >> + }
> >> +
> >> this->xy_coord_index = 0;
> >> this->sample_index
> >> = retype(brw_vec8_grf(reg, 0), BRW_REGISTER_TYPE_UD);
> >> @@ -1368,11 +1393,82 @@ brw_blorp_blit_program::translate_dst_to_src()
> >> brw_MUL(&func, Y_f, Yp_f, y_transform.multiplier);
> >> brw_ADD(&func, X_f, X_f, x_transform.offset);
> >> brw_ADD(&func, Y_f, Y_f, y_transform.offset);
> >> - /* Round the float coordinates down to nearest integer by moving to
> >> - * UD registers.
> >> - */
> >> - brw_MOV(&func, Xp, X_f);
> >> - brw_MOV(&func, Yp, Y_f);
> >> + if (key->blit_scaled && key->blend) {
> >> + float x_scale = 2.0;
> >> + float y_scale = key->src_samples / 2.0;
> >
> >
> > It would be nice to have a comment above x_scale and y_scale explaining
> that they are the scale factor between the pixel grid and the grid of
> samples that we're texturing from.
> >
> > Also, I'd recommend moving them to someplace more global (either the
> class definition or the program key) so that they can be accessed from
> manual_blend_linear().
> >
> >>
> >> + /* Translate coordinates to lay out the samples in a rectangular
> grid
> >> + * roughly corresponding to sample locations.
> >>
> >> + */
> >> + brw_ADD(&func, X_f, X_f, brw_imm_f(-0.25));
> >> + brw_ADD(&func, Y_f, Y_f, brw_imm_f(-1.0 / key->src_samples));
> >> + brw_MUL(&func, X_f, X_f, brw_imm_f(x_scale));
> >> + brw_MUL(&func, Y_f, Y_f, brw_imm_f(y_scale));
> >
> >
> > The additive constants -0.25 and -1.0/key->src_samples are a bit
> difficult to understand. I believe this is equivalent, and would be easier
> to follow:
> >
> > /* Translate coordinates to lay out the samples in a rectangular grid
> > * roughly corresponding to sample locations.
> > */
> > brw_MUL(&func, X_f, X_f, brw_imm_f(x_scale));
> > brw_MUL(&func, Y_f, Y_f, brw_imm_f(y_scale));
> >
> > /* Adjust coordinates so that integers represent pixel centers rather
> > * than pixel edges.
> > */
> > brw_ADD(&func, X_f, X_f, brw_imm_f(-0.5));
> > brw_ADD(&func, Y_f, Y_f, brw_imm_f(-0.5));
> >
> >>
> >> +
> >> + /* Test boundary conditions to properly handle the sampling of
> texels on
> >> + * texture edges.
> >> + */
> >> + brw_CMP(&func, vec16(brw_null_reg()), BRW_CONDITIONAL_L,
> >> + X_f, brw_imm_f(2.0 * key->src_x0));
> >> + brw_IF(&func, BRW_EXECUTE_16);
> >> + {
> >> + /* Left Edge in X */
> >> + brw_MOV(&func, x_lerp, brw_imm_f(1.0));
> >> + }
> >> + brw_ELSE(&func);
> >> + {
> >> + brw_CMP(&func, vec16(brw_null_reg()), BRW_CONDITIONAL_GE,
> >> + X_f, brw_imm_f(2.0 * (key->src_x1 - 0.50)));
> >> + brw_IF(&func, BRW_EXECUTE_16);
> >> + {
> >> + /* Right Edge in X */
> >> + brw_MOV(&func, x_lerp, brw_imm_f(0.0));
> >> + }
> >> + brw_ELSE(&func);
> >> + {
> >> + /* Store the fractional part to be used as color
> interpolator */
> >> + brw_FRC(&func, x_lerp, X_f);
> >> + }
> >> + brw_ENDIF(&func);
> >> + }
> >> + brw_ENDIF(&func);
> >>
> >> +
> >> + brw_CMP(&func, vec16(brw_null_reg()), BRW_CONDITIONAL_L,
> >> + Y_f, brw_imm_f((y_scale) * key->src_y0));
> >> + brw_IF(&func, BRW_EXECUTE_16);
> >> + {
> >> + /* Bottom Edge in Y */
> >> + brw_MOV(&func, y_lerp, brw_imm_f(1.0));
> >> + }
> >> + brw_ELSE(&func);
> >> + {
> >> + brw_CMP(&func, vec16(brw_null_reg()), BRW_CONDITIONAL_GE, Y_f,
> >> + brw_imm_f((y_scale) * (key->src_y1 - 1 / y_scale)));
> >> + brw_IF(&func, BRW_EXECUTE_16);
> >> + {
> >> + /* Top Edge in Y */
> >> + brw_MOV(&func, y_lerp, brw_imm_f(0.0));
> >> + }
> >> + brw_ELSE(&func);
> >> + {
> >> + /* Store the fractional part to be used as color
> interpolator */
> >> + brw_FRC(&func, y_lerp, Y_f);
> >> + }
> >> + brw_ENDIF(&func);
> >> + }
> >> + brw_ENDIF(&func);
> >
> >
> > A few thoughts on the above conditional logic:
> >
> > (1) I think the math would be easier to follow if the following
> expressions were changed to equivalent forms:
> >
> > "2.0 * key->src_x0" => "x_scale * key->src_x0"
> > "2.0 * (key->src_x1 - 0.50)" => "x_scale * key->src_x1 - 1.0"
> > "(y_scale) * (key->src_y1 - 1 / y_scale)" => "y_scale * key->src_y1 -
> 1.0"
> >
> > This will also help in the future when we want to support hardware with
> 16x MSAA, because in that case we'll want x_scale = y_scale = 4.
> >
> > (2) Effectively what this code is doing is clamping the x and y
> coordinates to the boundary of the source rectangle. But since it's
> accomplishing the clamping by adjusting x_lerp to 0.0 or 1.0, can only
> clamp things that aren't too far outside the source rectangle to begin with
> (i.e. no more than 1.0 outside the boundary). I *think* that will work,
> but it seems like an unnecessary risk (and an unnecessary source of
> confusion). Why not just clamp X_f to the range [x_scale * key->src_x0,
> x_scale * key->src_x1 - 1.0] (and similar for Y_f), and then afterward
> compute x_lerp = FRC(X_f)? That way there will be no doubt that the
> coordinate is properly in range.
> >
> > (3) You can probably save a lot of instructions if you use conditional
> moves to do the clamping, e.g.
> >
> > brw_CMP(&func, vec16(brw_null_reg()), BRW_CONDITIONAL_L, X_f,
> brw_imm_f(x_scale * key->src_x0));
> > brw_MOV(&func, X_f, brw_imm_f(x_scale * key->src_x0));
> > brw_set_predicate_control(&func, BRW_PREDICATE_NONE);
> > ...etc.
> >
> >>
> >> +
> >> + /* Round the float coordinates down to nearest integer */
> >> + brw_RNDD(&func, Xp_f, X_f);
> >> + brw_RNDD(&func, Yp_f, Y_f);
> >> + brw_MUL(&func, X_f, Xp_f, brw_imm_f(0.5));
> >> + brw_MUL(&func, Y_f, Yp_f, brw_imm_f(1 / y_scale));
> >> + } else {
> >> + /* Round the float coordinates down to nearest integer by moving
> to
> >> + * UD registers.
> >> + */
> >> + brw_MOV(&func, Xp, X_f);
> >> + brw_MOV(&func, Yp, Y_f);
> >> + }
> >> SWAP_XY_AND_XPYP();
> >> brw_set_compression_control(&func, BRW_COMPRESSION_NONE);
> >> }
> >> @@ -1418,7 +1514,7 @@ inline int count_trailing_one_bits(unsigned value)
> >>
> >>
> >> void
> >> -brw_blorp_blit_program::manual_blend(unsigned num_samples)
> >> +brw_blorp_blit_program::manual_blend_average(unsigned num_samples)
> >> {
> >> if (key->tex_layout == INTEL_MSAA_LAYOUT_CMS)
> >> mcs_fetch();
> >> @@ -1523,6 +1619,135 @@ brw_blorp_blit_program::manual_blend(unsigned
> num_samples)
> >> brw_ENDIF(&func);
> >> }
> >>
> >> +void
> >> +brw_blorp_blit_program::manual_blend_linear(unsigned num_samples)
> >> +{
> >> + if (key->tex_layout == INTEL_MSAA_LAYOUT_CMS)
> >> + mcs_fetch();
> >
> >
> > This won't work. The MCS value we fetch has to match up with the pixel
> that we're sampling from. Since this function samples from different
> pixels in each iteration of the "for" loop below, the call to mcs_fetch()
> needs to go inside the loop, and it needs to happen after storing the
> coordinates in X and Y.
> >
> I think MCS value fetch will not be required anymore as we are anyway
> getting rid of optimization which compares mcs value to zero.
>
MCS fetch is still needed, since the MCS value needs to be passed into the
ld2dms message that is used to read the samples from the surface.
>
> >>
> >> +
> >> + /* We do this computation by performing the following operations:
> >> + *
> >> + * In case of 4x, 8x MSAA:
> >> + * - Compute the pixel coordinates and sample numbers (a, b, c, d)
> >> + * which are later used for interpolation
> >> + * - linearly interpolate samples a and b in X
> >> + * - linearly interpolate samples c and d in X
> >> + * - linearly interpolate the results of last two operations in Y
> >> + *
> >> + * result = lrp(lrp(a + b) + lrp(c + d))
> >> + */
> >> + struct brw_reg Xp_f = retype(Xp, BRW_REGISTER_TYPE_F);
> >> + struct brw_reg Yp_f = retype(Yp, BRW_REGISTER_TYPE_F);
> >> + struct brw_reg t1_f = retype(t1, BRW_REGISTER_TYPE_F);
> >> + struct brw_reg t2_f = retype(t2, BRW_REGISTER_TYPE_F);
> >> +
> >> + for (unsigned i = 0; i < 4; ++i) {
> >> + assert(i < ARRAY_SIZE(texture_data));
> >> + s_is_zero = false;
> >> +
> >> + /* Compute pixel coordinates */
> >> + brw_ADD(&func, vec16(x_sample_coords), Xp_f,
> >> + brw_imm_f((float)(i & 0x1) * 0.5));
> >> + brw_ADD(&func, vec16(y_sample_coords), Yp_f,
> >> + brw_imm_f((float)(i & 0x2) * (1.0 / num_samples)));
> >> + brw_MOV(&func, vec16(X), x_sample_coords);
> >> + brw_MOV(&func, vec16(Y), y_sample_coords);
> >> +
> >> + /* Compute sample index. In case of 4x MSAA, sample index is
> >> + * equal to sample number.
> >> + */
> >
> >
> > This comment should explain what you mean by "sample index" vs "sample
> number".
> >
> >>
> >> + brw_FRC(&func, vec16(t1_f), x_sample_coords);
> >> + brw_FRC(&func, vec16(t2_f), y_sample_coords);
> >> + brw_MUL(&func, vec16(t1_f), t1_f, brw_imm_f(2.0));
> >> + brw_MUL(&func, vec16(t2_f), t2_f, brw_imm_f(num_samples));
> >
> >
> > How about this instead? It's a little more future proof and it
> clarifies that what we're doing is computing our position within the grid
> of samples corresponding to a single pixel:
> >
> > brw_MUL(&func, vec16(t1_f), t1_f, brw_imm_f(x_scale));
> > brw_MUL(&func, vec16(t2_f), t2_f, brw_imm_f(x_scale * y_scale));
> >
> >>
> >> + brw_ADD(&func, vec16(t1_f), t1_f, t2_f);
> >> + brw_MOV(&func, vec16(S), t1_f);
> >> +
> >> + if (num_samples == 8) {
> >> + /* Map the sample index to a sample number */
> >> + brw_CMP(&func, vec16(brw_null_reg()), BRW_CONDITIONAL_L,
> >> + S, brw_imm_d(4));
> >> + brw_IF(&func, BRW_EXECUTE_16);
> >> + {
> >> + brw_MOV(&func, vec16(t2), brw_imm_d(5));
> >> + brw_CMP(&func, vec16(brw_null_reg()), BRW_CONDITIONAL_EQ,
> >> + S, brw_imm_d(1));
> >> + brw_MOV(&func, vec16(t2), brw_imm_d(2));
> >> + brw_set_predicate_control(&func, BRW_PREDICATE_NONE);
> >> + brw_CMP(&func, vec16(brw_null_reg()), BRW_CONDITIONAL_EQ,
> >> + S, brw_imm_d(2));
> >> + brw_MOV(&func, vec16(t2), brw_imm_d(4));
> >> + brw_set_predicate_control(&func, BRW_PREDICATE_NONE);
> >> + brw_CMP(&func, vec16(brw_null_reg()), BRW_CONDITIONAL_EQ,
> >> + S, brw_imm_d(3));
> >> + brw_MOV(&func, vec16(t2), brw_imm_d(6));
> >> + brw_set_predicate_control(&func, BRW_PREDICATE_NONE);
> >> + }
> >> + brw_ELSE(&func);
> >> + {
> >> + brw_MOV(&func, vec16(t2), brw_imm_d(0));
> >> + brw_CMP(&func, vec16(brw_null_reg()), BRW_CONDITIONAL_EQ,
> >> + S, brw_imm_d(5));
> >> + brw_MOV(&func, vec16(t2), brw_imm_d(3));
> >> + brw_set_predicate_control(&func, BRW_PREDICATE_NONE);
> >> + brw_CMP(&func, vec16(brw_null_reg()), BRW_CONDITIONAL_EQ,
> >> + S, brw_imm_d(6));
> >> + brw_MOV(&func, vec16(t2), brw_imm_d(7));
> >> + brw_set_predicate_control(&func, BRW_PREDICATE_NONE);
> >> + brw_CMP(&func, vec16(brw_null_reg()), BRW_CONDITIONAL_EQ,
> >> + S, brw_imm_d(7));
> >> + brw_MOV(&func, vec16(t2), brw_imm_d(1));
> >> + brw_set_predicate_control(&func, BRW_PREDICATE_NONE);
> >> + }
> >> + brw_ENDIF(&func);
> >> + brw_MOV(&func, vec16(S), t2);
> >
> >
> > This seems like a lot of work to accomplish what is effectively a lookup
> table. If this winds up becoming a performance bottleneck, you might want
> to consider passing the table in via a push constant, and using indirect
> addressing to convert sample index to sample number.
> >
> >>
> >> + }
> >> + texel_fetch(texture_data[i]);
> >> +
> >> + if (i == 0 && key->tex_layout == INTEL_MSAA_LAYOUT_CMS) {
> >> + /* The Ivy Bridge PRM, Vol4 Part1 p27 (Multisample Control
> Surface)
> >> + * suggests an optimization:
> >> + *
> >> + * "A simple optimization with probable large return in
> >> + * performance is to compare the MCS value to zero
> (indicating
> >> + * all samples are on sample slice 0), and sample only
> from
> >> + * sample slice 0 using ld2dss if MCS is zero."
> >> + *
> >> + * Note that in the case where the MCS value is zero,
> sampling from
> >> + * sample slice 0 using ld2dss and sampling from sample 0
> using
> >> + * ld2dms are equivalent (since all samples are on sample
> slice 0).
> >> + * Since we have already sampled from sample 0, all we need
> to do is
> >> + * skip the remaining fetches and averaging if MCS is zero.
> >> + */
> >> + brw_CMP(&func, vec16(brw_null_reg()), BRW_CONDITIONAL_NZ,
> >> + mcs_data, brw_imm_ud(0));
> >> + brw_IF(&func, BRW_EXECUTE_16);
> >> + }
> >
> >
> > We can't do this optimization for scaled multisample blits, because it
> relies on the assumption that all the samples we're blending together
> belong to the same pixel. I'd recommend just pulling this code out.
> >
> >>
> >> + }
> >> +
> >> +#define SAMPLE(x, y) offset(texture_data[x], y)
> >> + brw_set_access_mode(&func, BRW_ALIGN_16);
> >> + for (int index = 3; index > 0; ) {
> >> + for (int k = 0; k < 8; ++k)
> >> + brw_LRP(&func,
> >> + vec8(SAMPLE(index - 1, k)),
> >> + offset(x_lerp, k & 1),
> >> + SAMPLE(index, k),
> >> + SAMPLE(index - 1, k));
> >> + index -= 2;
> >> + }
> >> + for (int k = 0; k < 8; ++k)
> >> + brw_LRP(&func,
> >> + vec8(SAMPLE(0, k)),
> >> + offset(y_lerp, k & 1),
> >> + vec8(SAMPLE(2, k)),
> >> + vec8(SAMPLE(0, k)));
> >> + brw_set_access_mode(&func, BRW_ALIGN_1);
> >
> >
> > I'm confused why we need loops from 0 to 7 here. It looks like you're
> trying to interpolate each component of the SIMD8 register separately.
> That shouldn't be necessary.
> >
> >>
> >> +#undef SAMPLE
> >> + if (key->tex_layout == INTEL_MSAA_LAYOUT_CMS)
> >> + brw_ENDIF(&func);
> >> +}
> >> +
> >> /**
> >> * Emit code to look up a value in the texture using the SAMPLE
> message (which
> >> * does blending of MSAA surfaces).
> >> @@ -1535,7 +1760,8 @@ brw_blorp_blit_program::sample(struct brw_reg dst)
> >> SAMPLER_MESSAGE_ARG_V_FLOAT
> >> };
> >>
> >> - texture_lookup(dst, GEN5_SAMPLER_MESSAGE_SAMPLE, args,
> ARRAY_SIZE(args));
> >> + texture_lookup(dst, GEN5_SAMPLER_MESSAGE_SAMPLE, args,
> >> + ARRAY_SIZE(args));
> >> }
> >>
> >> /**
> >> @@ -1872,6 +2098,17 @@
> brw_blorp_blit_params::brw_blorp_blit_params(struct brw_context *brw,
> >> wm_prog_key.persample_msaa_dispatch = true;
> >> }
> >>
> >> + /* Scaled blitting or not. */
> >> + wm_prog_key.blit_scaled =
> >> + ((dst_x1 - dst_x0) == (src_x1 - src_x0) &&
> >> + (dst_y1 - dst_y0) == (src_y1 - src_y0)) ? false : true;
> >> +
> >> + /* Source rectangle dimensions */
> >> + wm_prog_key.src_x0 = src_x0;
> >> + wm_prog_key.src_y0 = src_y0;
> >> + wm_prog_key.src_x1 = src_x1;
> >> + wm_prog_key.src_y1 = src_y1;
> >> +
> >> /* The render path must be configured to use the same number of
> samples as
> >> * the destination buffer.
> >> */
> >> --
> >> 1.8.1.4
> >>
> >
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.freedesktop.org/archives/mesa-dev/attachments/20130626/4adc6a40/attachment-0001.html>
More information about the mesa-dev
mailing list