r600_textured_videofuncs.c revision 921a55d8
1/*
2 * Copyright 2008 Advanced Micro Devices, Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 * SOFTWARE.
22 *
23 * Author: Alex Deucher <alexander.deucher@amd.com>
24 *
25 */
26
27#ifdef HAVE_CONFIG_H
28#include "config.h"
29#endif
30
31#include "xf86.h"
32
33#include "exa.h"
34
35#include "radeon.h"
36#include "radeon_reg.h"
37#include "r600_shader.h"
38#include "r600_reg.h"
39#include "r600_state.h"
40
41#include "radeon_video.h"
42
43#include <X11/extensions/Xv.h>
44#include "fourcc.h"
45
46#include "damage.h"
47
48#include "radeon_exa_shared.h"
49#include "radeon_vbo.h"
50
51/* Parameters for ITU-R BT.601 and ITU-R BT.709 colour spaces
52   note the difference to the parameters used in overlay are due
53   to 10bit vs. float calcs */
54static REF_TRANSFORM trans[2] =
55{
56    {1.1643, 0.0, 1.5960, -0.3918, -0.8129, 2.0172, 0.0}, /* BT.601 */
57    {1.1643, 0.0, 1.7927, -0.2132, -0.5329, 2.1124, 0.0}  /* BT.709 */
58};
59
60void
61R600DisplayTexturedVideo(ScrnInfoPtr pScrn, RADEONPortPrivPtr pPriv)
62{
63    RADEONInfoPtr info = RADEONPTR(pScrn);
64    struct radeon_accel_state *accel_state = info->accel_state;
65    PixmapPtr pPixmap = pPriv->pPixmap;
66    BoxPtr pBox = REGION_RECTS(&pPriv->clip);
67    int nBox = REGION_NUM_RECTS(&pPriv->clip);
68    int dstxoff, dstyoff;
69    struct r600_accel_object src_obj, dst_obj;
70    cb_config_t     cb_conf;
71    tex_resource_t  tex_res;
72    tex_sampler_t   tex_samp;
73    shader_config_t vs_conf, ps_conf;
74    /*
75     * y' = y - .0625
76     * u' = u - .5
77     * v' = v - .5;
78     *
79     * r = 1.1643 * y' + 0.0     * u' + 1.5958  * v'
80     * g = 1.1643 * y' - 0.39173 * u' - 0.81290 * v'
81     * b = 1.1643 * y' + 2.017   * u' + 0.0     * v'
82     *
83     * DP3 might look like the straightforward solution
84     * but we'd need to move the texture yuv values in
85     * the same reg for this to work. Therefore use MADs.
86     * Brightness just adds to the off constant.
87     * Contrast is multiplication of luminance.
88     * Saturation and hue change the u and v coeffs.
89     * Default values (before adjustments - depend on colorspace):
90     * yco = 1.1643
91     * uco = 0, -0.39173, 2.017
92     * vco = 1.5958, -0.8129, 0
93     * off = -0.0625 * yco + -0.5 * uco[r] + -0.5 * vco[r],
94     *       -0.0625 * yco + -0.5 * uco[g] + -0.5 * vco[g],
95     *       -0.0625 * yco + -0.5 * uco[b] + -0.5 * vco[b],
96     *
97     * temp = MAD(yco, yuv.yyyy, off)
98     * temp = MAD(uco, yuv.uuuu, temp)
99     * result = MAD(vco, yuv.vvvv, temp)
100     */
101    /* TODO: calc consts in the shader */
102    const float Loff = -0.0627;
103    const float Coff = -0.502;
104    float uvcosf, uvsinf;
105    float yco;
106    float uco[3], vco[3], off[3];
107    float bright, cont, gamma;
108    int ref = pPriv->transform_index;
109    Bool needgamma = FALSE;
110    float ps_alu_consts[12];
111    float vs_alu_consts[4];
112
113    cont = RTFContrast(pPriv->contrast);
114    bright = RTFBrightness(pPriv->brightness);
115    gamma = (float)pPriv->gamma / 1000.0;
116    uvcosf = RTFSaturation(pPriv->saturation) * cos(RTFHue(pPriv->hue));
117    uvsinf = RTFSaturation(pPriv->saturation) * sin(RTFHue(pPriv->hue));
118    /* overlay video also does pre-gamma contrast/sat adjust, should we? */
119
120    yco = trans[ref].RefLuma * cont;
121    uco[0] = -trans[ref].RefRCr * uvsinf;
122    uco[1] = trans[ref].RefGCb * uvcosf - trans[ref].RefGCr * uvsinf;
123    uco[2] = trans[ref].RefBCb * uvcosf;
124    vco[0] = trans[ref].RefRCr * uvcosf;
125    vco[1] = trans[ref].RefGCb * uvsinf + trans[ref].RefGCr * uvcosf;
126    vco[2] = trans[ref].RefBCb * uvsinf;
127    off[0] = Loff * yco + Coff * (uco[0] + vco[0]) + bright;
128    off[1] = Loff * yco + Coff * (uco[1] + vco[1]) + bright;
129    off[2] = Loff * yco + Coff * (uco[2] + vco[2]) + bright;
130
131    // XXX
132    gamma = 1.0;
133
134    if (gamma != 1.0) {
135	needgamma = TRUE;
136	/* note: gamma correction is out = in ^ gamma;
137	   gpu can only do LG2/EX2 therefore we transform into
138	   in ^ gamma = 2 ^ (log2(in) * gamma).
139	   Lots of scalar ops, unfortunately (better solution?) -
140	   without gamma that's 3 inst, with gamma it's 10...
141	   could use different gamma factors per channel,
142	   if that's of any use. */
143    }
144
145    /* setup the ps consts */
146    ps_alu_consts[0] = off[0];
147    ps_alu_consts[1] = off[1];
148    ps_alu_consts[2] = off[2];
149    ps_alu_consts[3] = yco;
150
151    ps_alu_consts[4] = uco[0];
152    ps_alu_consts[5] = uco[1];
153    ps_alu_consts[6] = uco[2];
154    ps_alu_consts[7] = gamma;
155
156    ps_alu_consts[8] = vco[0];
157    ps_alu_consts[9] = vco[1];
158    ps_alu_consts[10] = vco[2];
159    ps_alu_consts[11] = 0.0;
160
161    CLEAR (cb_conf);
162    CLEAR (tex_res);
163    CLEAR (tex_samp);
164    CLEAR (vs_conf);
165    CLEAR (ps_conf);
166
167#if defined(XF86DRM_MODE)
168    if (info->cs) {
169	dst_obj.offset = 0;
170	src_obj.offset = 0;
171	dst_obj.bo = radeon_get_pixmap_bo(pPixmap);
172    } else
173#endif
174    {
175	dst_obj.offset = exaGetPixmapOffset(pPixmap) + info->fbLocation + pScrn->fbOffset;
176	src_obj.offset = pPriv->src_offset + info->fbLocation + pScrn->fbOffset;
177	dst_obj.bo = src_obj.bo = NULL;
178    }
179    dst_obj.pitch = exaGetPixmapPitch(pPixmap) / (pPixmap->drawable.bitsPerPixel / 8);
180
181    src_obj.pitch = pPriv->src_pitch;
182    src_obj.width = pPriv->w;
183    src_obj.height = pPriv->h;
184    src_obj.bpp = 16;
185    src_obj.domain = RADEON_GEM_DOMAIN_VRAM | RADEON_GEM_DOMAIN_GTT;
186    src_obj.bo = pPriv->src_bo[pPriv->currentBuffer];
187
188    dst_obj.width = pPixmap->drawable.width;
189    dst_obj.height = pPixmap->drawable.height;
190    dst_obj.bpp = pPixmap->drawable.bitsPerPixel;
191    dst_obj.domain = RADEON_GEM_DOMAIN_VRAM;
192
193    if (!R600SetAccelState(pScrn,
194			   &src_obj,
195			   NULL,
196			   &dst_obj,
197			   accel_state->xv_vs_offset, accel_state->xv_ps_offset,
198			   3, 0xffffffff))
199	return;
200
201#ifdef COMPOSITE
202    dstxoff = -pPixmap->screen_x + pPixmap->drawable.x;
203    dstyoff = -pPixmap->screen_y + pPixmap->drawable.y;
204#else
205    dstxoff = 0;
206    dstyoff = 0;
207#endif
208
209    radeon_vbo_check(pScrn, &accel_state->vbo, 16);
210    radeon_cp_start(pScrn);
211
212    r600_set_default_state(pScrn, accel_state->ib);
213
214    r600_set_generic_scissor(pScrn, accel_state->ib, 0, 0, accel_state->dst_obj.width, accel_state->dst_obj.height);
215    r600_set_screen_scissor(pScrn, accel_state->ib, 0, 0, accel_state->dst_obj.width, accel_state->dst_obj.height);
216    r600_set_window_scissor(pScrn, accel_state->ib, 0, 0, accel_state->dst_obj.width, accel_state->dst_obj.height);
217
218    /* PS bool constant */
219    switch(pPriv->id) {
220    case FOURCC_YV12:
221    case FOURCC_I420:
222	r600_set_bool_consts(pScrn, accel_state->ib, SQ_BOOL_CONST_ps, (1 << 0));
223	break;
224    case FOURCC_UYVY:
225    case FOURCC_YUY2:
226    default:
227	r600_set_bool_consts(pScrn, accel_state->ib, SQ_BOOL_CONST_ps, (0 << 0));
228	break;
229    }
230
231    /* Shader */
232    vs_conf.shader_addr         = accel_state->vs_mc_addr;
233    vs_conf.shader_size         = accel_state->vs_size;
234    vs_conf.num_gprs            = 2;
235    vs_conf.stack_size          = 0;
236    vs_conf.bo                  = accel_state->shaders_bo;
237    r600_vs_setup(pScrn, accel_state->ib, &vs_conf, RADEON_GEM_DOMAIN_VRAM);
238
239    ps_conf.shader_addr         = accel_state->ps_mc_addr;
240    ps_conf.shader_size         = accel_state->ps_size;
241    ps_conf.num_gprs            = 3;
242    ps_conf.stack_size          = 1;
243    ps_conf.uncached_first_inst = 1;
244    ps_conf.clamp_consts        = 0;
245    ps_conf.export_mode         = 2;
246    ps_conf.bo                  = accel_state->shaders_bo;
247    r600_ps_setup(pScrn, accel_state->ib, &ps_conf, RADEON_GEM_DOMAIN_VRAM);
248
249    /* PS alu constants */
250    r600_set_alu_consts(pScrn, accel_state->ib, SQ_ALU_CONSTANT_ps,
251			sizeof(ps_alu_consts) / SQ_ALU_CONSTANT_offset, ps_alu_consts);
252
253    /* Texture */
254    switch(pPriv->id) {
255    case FOURCC_YV12:
256    case FOURCC_I420:
257	accel_state->src_size[0] = accel_state->src_obj[0].pitch * pPriv->h;
258
259	/* Y texture */
260	tex_res.id                  = 0;
261	tex_res.w                   = accel_state->src_obj[0].width;
262	tex_res.h                   = accel_state->src_obj[0].height;
263	tex_res.pitch               = accel_state->src_obj[0].pitch;
264	tex_res.depth               = 0;
265	tex_res.dim                 = SQ_TEX_DIM_2D;
266	tex_res.base                = accel_state->src_obj[0].offset;
267	tex_res.mip_base            = accel_state->src_obj[0].offset;
268	tex_res.size                = accel_state->src_size[0];
269	tex_res.bo                  = accel_state->src_obj[0].bo;
270	tex_res.mip_bo              = accel_state->src_obj[0].bo;
271
272	tex_res.format              = FMT_8;
273	tex_res.dst_sel_x           = SQ_SEL_X; /* Y */
274	tex_res.dst_sel_y           = SQ_SEL_1;
275	tex_res.dst_sel_z           = SQ_SEL_1;
276	tex_res.dst_sel_w           = SQ_SEL_1;
277
278	tex_res.request_size        = 1;
279	tex_res.base_level          = 0;
280	tex_res.last_level          = 0;
281	tex_res.perf_modulation     = 0;
282	tex_res.interlaced          = 0;
283	r600_set_tex_resource(pScrn, accel_state->ib, &tex_res, accel_state->src_obj[0].domain);
284
285	/* Y sampler */
286	tex_samp.id                 = 0;
287	tex_samp.clamp_x            = SQ_TEX_CLAMP_LAST_TEXEL;
288	tex_samp.clamp_y            = SQ_TEX_CLAMP_LAST_TEXEL;
289	tex_samp.clamp_z            = SQ_TEX_WRAP;
290
291	/* xxx: switch to bicubic */
292	tex_samp.xy_mag_filter      = SQ_TEX_XY_FILTER_BILINEAR;
293	tex_samp.xy_min_filter      = SQ_TEX_XY_FILTER_BILINEAR;
294
295	tex_samp.z_filter           = SQ_TEX_Z_FILTER_NONE;
296	tex_samp.mip_filter         = 0;			/* no mipmap */
297	r600_set_tex_sampler(pScrn, accel_state->ib, &tex_samp);
298
299	/* U or V texture */
300	tex_res.id                  = 1;
301	tex_res.format              = FMT_8;
302	tex_res.w                   = accel_state->src_obj[0].width >> 1;
303	tex_res.h                   = accel_state->src_obj[0].height >> 1;
304	tex_res.pitch               = RADEON_ALIGN(accel_state->src_obj[0].pitch >> 1, 256);
305	tex_res.dst_sel_x           = SQ_SEL_X; /* V or U */
306	tex_res.dst_sel_y           = SQ_SEL_1;
307	tex_res.dst_sel_z           = SQ_SEL_1;
308	tex_res.dst_sel_w           = SQ_SEL_1;
309	tex_res.interlaced          = 0;
310
311	tex_res.base                = accel_state->src_obj[0].offset + pPriv->planev_offset;
312	tex_res.mip_base            = accel_state->src_obj[0].offset + pPriv->planev_offset;
313	tex_res.size                = tex_res.pitch * (pPriv->h >> 1);
314	r600_set_tex_resource(pScrn, accel_state->ib, &tex_res, accel_state->src_obj[0].domain);
315
316	/* U or V sampler */
317	tex_samp.id                 = 1;
318	r600_set_tex_sampler(pScrn, accel_state->ib, &tex_samp);
319
320	/* U or V texture */
321	tex_res.id                  = 2;
322	tex_res.format              = FMT_8;
323	tex_res.w                   = accel_state->src_obj[0].width >> 1;
324	tex_res.h                   = accel_state->src_obj[0].height >> 1;
325	tex_res.pitch               = RADEON_ALIGN(accel_state->src_obj[0].pitch >> 1, 256);
326	tex_res.dst_sel_x           = SQ_SEL_X; /* V or U */
327	tex_res.dst_sel_y           = SQ_SEL_1;
328	tex_res.dst_sel_z           = SQ_SEL_1;
329	tex_res.dst_sel_w           = SQ_SEL_1;
330	tex_res.interlaced          = 0;
331
332	tex_res.base                = accel_state->src_obj[0].offset + pPriv->planeu_offset;
333	tex_res.mip_base            = accel_state->src_obj[0].offset + pPriv->planeu_offset;
334	tex_res.size                = tex_res.pitch * (pPriv->h >> 1);
335	r600_set_tex_resource(pScrn, accel_state->ib, &tex_res, accel_state->src_obj[0].domain);
336
337	/* UV sampler */
338	tex_samp.id                 = 2;
339	r600_set_tex_sampler(pScrn, accel_state->ib, &tex_samp);
340	break;
341    case FOURCC_UYVY:
342    case FOURCC_YUY2:
343    default:
344	accel_state->src_size[0] = accel_state->src_obj[0].pitch * pPriv->h;
345
346	/* Y texture */
347	tex_res.id                  = 0;
348	tex_res.w                   = accel_state->src_obj[0].width;
349	tex_res.h                   = accel_state->src_obj[0].height;
350	tex_res.pitch               = accel_state->src_obj[0].pitch >> 1;
351	tex_res.depth               = 0;
352	tex_res.dim                 = SQ_TEX_DIM_2D;
353	tex_res.base                = accel_state->src_obj[0].offset;
354	tex_res.mip_base            = accel_state->src_obj[0].offset;
355	tex_res.size                = accel_state->src_size[0];
356	tex_res.bo                  = accel_state->src_obj[0].bo;
357	tex_res.mip_bo              = accel_state->src_obj[0].bo;
358
359	tex_res.format              = FMT_8_8;
360	if (pPriv->id == FOURCC_UYVY)
361	    tex_res.dst_sel_x           = SQ_SEL_Y; /* Y */
362	else
363	    tex_res.dst_sel_x           = SQ_SEL_X; /* Y */
364	tex_res.dst_sel_y           = SQ_SEL_1;
365	tex_res.dst_sel_z           = SQ_SEL_1;
366	tex_res.dst_sel_w           = SQ_SEL_1;
367
368	tex_res.request_size        = 1;
369	tex_res.base_level          = 0;
370	tex_res.last_level          = 0;
371	tex_res.perf_modulation     = 0;
372	tex_res.interlaced          = 0;
373	r600_set_tex_resource(pScrn, accel_state->ib, &tex_res, accel_state->src_obj[0].domain);
374
375	/* Y sampler */
376	tex_samp.id                 = 0;
377	tex_samp.clamp_x            = SQ_TEX_CLAMP_LAST_TEXEL;
378	tex_samp.clamp_y            = SQ_TEX_CLAMP_LAST_TEXEL;
379	tex_samp.clamp_z            = SQ_TEX_WRAP;
380
381	/* xxx: switch to bicubic */
382	tex_samp.xy_mag_filter      = SQ_TEX_XY_FILTER_BILINEAR;
383	tex_samp.xy_min_filter      = SQ_TEX_XY_FILTER_BILINEAR;
384
385	tex_samp.z_filter           = SQ_TEX_Z_FILTER_NONE;
386	tex_samp.mip_filter         = 0;			/* no mipmap */
387	r600_set_tex_sampler(pScrn, accel_state->ib, &tex_samp);
388
389	/* UV texture */
390	tex_res.id                  = 1;
391	tex_res.format              = FMT_8_8_8_8;
392	tex_res.w                   = accel_state->src_obj[0].width >> 1;
393	tex_res.h                   = accel_state->src_obj[0].height;
394	tex_res.pitch               = accel_state->src_obj[0].pitch >> 2;
395	if (pPriv->id == FOURCC_UYVY) {
396	    tex_res.dst_sel_x           = SQ_SEL_X; /* V */
397	    tex_res.dst_sel_y           = SQ_SEL_Z; /* U */
398	} else {
399	    tex_res.dst_sel_x           = SQ_SEL_Y; /* V */
400	    tex_res.dst_sel_y           = SQ_SEL_W; /* U */
401	}
402	tex_res.dst_sel_z           = SQ_SEL_1;
403	tex_res.dst_sel_w           = SQ_SEL_1;
404	tex_res.interlaced          = 0;
405
406	tex_res.base                = accel_state->src_obj[0].offset;
407	tex_res.mip_base            = accel_state->src_obj[0].offset;
408	tex_res.size                = accel_state->src_size[0];
409	r600_set_tex_resource(pScrn, accel_state->ib, &tex_res, accel_state->src_obj[0].domain);
410
411	/* UV sampler */
412	tex_samp.id                 = 1;
413	r600_set_tex_sampler(pScrn, accel_state->ib, &tex_samp);
414	break;
415    }
416
417    cb_conf.id = 0;
418    cb_conf.w = accel_state->dst_obj.pitch;
419    cb_conf.h = accel_state->dst_obj.height;
420    cb_conf.base = accel_state->dst_obj.offset;
421    cb_conf.bo = accel_state->dst_obj.bo;
422
423    switch (accel_state->dst_obj.bpp) {
424    case 16:
425	if (pPixmap->drawable.depth == 15) {
426	    cb_conf.format = COLOR_1_5_5_5;
427	    cb_conf.comp_swap = 1; /* ARGB */
428	} else {
429	    cb_conf.format = COLOR_5_6_5;
430	    cb_conf.comp_swap = 2; /* RGB */
431	}
432	break;
433    case 32:
434	cb_conf.format = COLOR_8_8_8_8;
435	cb_conf.comp_swap = 1; /* ARGB */
436	break;
437    default:
438	return;
439    }
440
441    cb_conf.source_format = 1;
442    cb_conf.blend_clamp = 1;
443    r600_set_render_target(pScrn, accel_state->ib, &cb_conf, accel_state->dst_obj.domain);
444
445    /* Render setup */
446    BEGIN_BATCH(20);
447    EREG(accel_state->ib, CB_TARGET_MASK,                      (0x0f << TARGET0_ENABLE_shift));
448    EREG(accel_state->ib, CB_COLOR_CONTROL,                    (0xcc << ROP3_shift)); /* copy */
449
450    /* Interpolator setup */
451    /* export tex coords from VS */
452    EREG(accel_state->ib, SPI_VS_OUT_CONFIG, ((1 - 1) << VS_EXPORT_COUNT_shift));
453    EREG(accel_state->ib, SPI_VS_OUT_ID_0, (0 << SEMANTIC_0_shift));
454    EREG(accel_state->ib, SPI_PS_INPUT_CNTL_0 + (0 << 2),       ((0    << SEMANTIC_shift)	|
455								(0x03 << DEFAULT_VAL_shift)	|
456								SEL_CENTROID_bit));
457
458    /* Enabling flat shading needs both FLAT_SHADE_bit in SPI_PS_INPUT_CNTL_x
459     * *and* FLAT_SHADE_ENA_bit in SPI_INTERP_CONTROL_0 */
460    PACK0(accel_state->ib, SPI_PS_IN_CONTROL_0, 3);
461    E32(accel_state->ib, ((1 << NUM_INTERP_shift)));
462    E32(accel_state->ib, 0);
463    E32(accel_state->ib, 0);
464    END_BATCH();
465
466    vs_alu_consts[0] = 1.0 / pPriv->w;
467    vs_alu_consts[1] = 1.0 / pPriv->h;
468    vs_alu_consts[2] = 0.0;
469    vs_alu_consts[3] = 0.0;
470
471    /* VS alu constants */
472    r600_set_alu_consts(pScrn, accel_state->ib, SQ_ALU_CONSTANT_vs,
473			sizeof(vs_alu_consts) / SQ_ALU_CONSTANT_offset, vs_alu_consts);
474
475    if (pPriv->vsync) {
476	xf86CrtcPtr crtc;
477	if (pPriv->desired_crtc)
478	    crtc = pPriv->desired_crtc;
479	else
480	    crtc = radeon_pick_best_crtc(pScrn,
481					 pPriv->drw_x,
482					 pPriv->drw_x + pPriv->dst_w,
483					 pPriv->drw_y,
484					 pPriv->drw_y + pPriv->dst_h);
485	if (crtc)
486	    r600_cp_wait_vline_sync(pScrn, accel_state->ib, pPixmap,
487				    crtc,
488				    pPriv->drw_y - crtc->y,
489				    (pPriv->drw_y - crtc->y) + pPriv->dst_h);
490    }
491
492    while (nBox--) {
493	int srcX, srcY, srcw, srch;
494	int dstX, dstY, dstw, dsth;
495	float *vb;
496
497
498	dstX = pBox->x1 + dstxoff;
499	dstY = pBox->y1 + dstyoff;
500	dstw = pBox->x2 - pBox->x1;
501	dsth = pBox->y2 - pBox->y1;
502
503	srcX = pPriv->src_x;
504	srcX += ((pBox->x1 - pPriv->drw_x) *
505		 pPriv->src_w) / pPriv->dst_w;
506	srcY = pPriv->src_y;
507	srcY += ((pBox->y1 - pPriv->drw_y) *
508		 pPriv->src_h) / pPriv->dst_h;
509
510	srcw = (pPriv->src_w * dstw) / pPriv->dst_w;
511	srch = (pPriv->src_h * dsth) / pPriv->dst_h;
512
513	vb = radeon_vbo_space(pScrn, &accel_state->vbo, 16);
514
515	vb[0] = (float)dstX;
516	vb[1] = (float)dstY;
517	vb[2] = (float)srcX;
518	vb[3] = (float)srcY;
519
520	vb[4] = (float)dstX;
521	vb[5] = (float)(dstY + dsth);
522	vb[6] = (float)srcX;
523	vb[7] = (float)(srcY + srch);
524
525	vb[8] = (float)(dstX + dstw);
526	vb[9] = (float)(dstY + dsth);
527	vb[10] = (float)(srcX + srcw);
528	vb[11] = (float)(srcY + srch);
529
530	radeon_vbo_commit(pScrn, &accel_state->vbo);
531
532	pBox++;
533    }
534
535    r600_finish_op(pScrn, 16);
536
537    DamageDamageRegion(pPriv->pDraw, &pPriv->clip);
538}
539