diff options
author | Thomas Hellstrom <thellstrom@vmware.com> | 2011-12-19 20:25:43 +0100 |
---|---|---|
committer | Thomas Hellstrom <thellstrom@vmware.com> | 2011-12-19 20:25:43 +0100 |
commit | b5546fb1de3f3859151a91e98ab0bd24b6789e2e (patch) | |
tree | 8e5283d6610e87d796e0d64b0a06c42469422b0d /vmwgfx/vmwgfx_tex_video.c | |
parent | abf9cb75630cb27bb4741d194cb23014fe3d09b1 (diff) | |
parent | 5748c33535bc7d3009b9758653885e6ae0e73002 (diff) |
Merge branch 'vmwgfx_branch'
Diffstat (limited to 'vmwgfx/vmwgfx_tex_video.c')
-rw-r--r-- | vmwgfx/vmwgfx_tex_video.c | 855 |
1 files changed, 855 insertions, 0 deletions
diff --git a/vmwgfx/vmwgfx_tex_video.c b/vmwgfx/vmwgfx_tex_video.c new file mode 100644 index 0000000..cc94c20 --- /dev/null +++ b/vmwgfx/vmwgfx_tex_video.c | |||
@@ -0,0 +1,855 @@ | |||
1 | /* | ||
2 | * Copyright 2009-2011 VMWare, Inc. | ||
3 | * All Rights Reserved. | ||
4 | * | ||
5 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
6 | * copy of this software and associated documentation files (the | ||
7 | * "Software"), to deal in the Software without restriction, including | ||
8 | * without limitation the rights to use, copy, modify, merge, publish, | ||
9 | * distribute, sub license, and/or sell copies of the Software, and to | ||
10 | * permit persons to whom the Software is furnished to do so, subject to | ||
11 | * the following conditions: | ||
12 | * | ||
13 | * The above copyright notice and this permission notice (including the | ||
14 | * next paragraph) shall be included in all copies or substantial portions | ||
15 | * of the Software. | ||
16 | * | ||
17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | ||
18 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
19 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. | ||
20 | * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR | ||
21 | * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, | ||
22 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE | ||
23 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
24 | * | ||
25 | * Author: Thomas Hellstrom <thellstrom@vmware.com> | ||
26 | * Author: Zack Rusin <zackr@vmware.com> | ||
27 | */ | ||
28 | |||
29 | #include "vmwgfx_driver.h" | ||
30 | #include "vmwgfx_drmi.h" | ||
31 | #include "vmwgfx_saa.h" | ||
32 | |||
33 | #include <xf86xv.h> | ||
34 | #include <X11/extensions/Xv.h> | ||
35 | #include <fourcc.h> | ||
36 | #include <xa_tracker.h> | ||
37 | #include <xa_context.h> | ||
38 | #include <math.h> | ||
39 | |||
40 | /*XXX get these from pipe's texture limits */ | ||
41 | #define IMAGE_MAX_WIDTH 2048 | ||
42 | #define IMAGE_MAX_HEIGHT 2048 | ||
43 | |||
44 | #define RES_720P_X 1280 | ||
45 | #define RES_720P_Y 720 | ||
46 | |||
47 | |||
48 | #define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE) | ||
49 | |||
50 | /* | ||
51 | * ITU-R BT.601, BT.709 transfer matrices. | ||
52 | * [R', G', B'] values are in the range [0, 1], Y' is in the range [0,1] | ||
53 | * and [Pb, Pr] components are in the range [-0.5, 0.5]. | ||
54 | * | ||
55 | * The matrices are transposed to fit the xa conversion matrix format. | ||
56 | */ | ||
57 | |||
58 | static const float bt_601[] = { | ||
59 | 1.f, 1.f, 1.f, 0.f, | ||
60 | 0.f, -0.344136f, 1.772f, 0.f, | ||
61 | 1.402f, -0.714136f, 0.f, 0.f | ||
62 | }; | ||
63 | |||
64 | static const float bt_709[] = { | ||
65 | 1.f, 1.f, 1.f, 0.f, | ||
66 | 0.f, -0.187324f, 1.8556f, 0.f, | ||
67 | 1.5748f, -0.468124f, 0.f, 0.f | ||
68 | }; | ||
69 | |||
70 | static Atom xvBrightness, xvContrast, xvSaturation, xvHue; | ||
71 | |||
72 | #define NUM_TEXTURED_ATTRIBUTES 4 | ||
73 | static XF86AttributeRec TexturedAttributes[NUM_TEXTURED_ATTRIBUTES] = { | ||
74 | {XvSettable | XvGettable, -1000, 1000, "XV_BRIGHTNESS"}, | ||
75 | {XvSettable | XvGettable, -1000, 1000, "XV_CONTRAST"}, | ||
76 | {XvSettable | XvGettable, -1000, 1000, "XV_SATURATION"}, | ||
77 | {XvSettable | XvGettable, -1000, 1000, "XV_HUE"} | ||
78 | }; | ||
79 | |||
80 | #define NUM_FORMATS 3 | ||
81 | static XF86VideoFormatRec Formats[NUM_FORMATS] = { | ||
82 | {15, TrueColor}, {16, TrueColor}, {24, TrueColor} | ||
83 | }; | ||
84 | |||
85 | static XF86VideoEncodingRec DummyEncoding[1] = { | ||
86 | { | ||
87 | 0, | ||
88 | "XV_IMAGE", | ||
89 | IMAGE_MAX_WIDTH, IMAGE_MAX_HEIGHT, | ||
90 | {1, 1} | ||
91 | } | ||
92 | }; | ||
93 | |||
94 | #define NUM_IMAGES 3 | ||
95 | static XF86ImageRec Images[NUM_IMAGES] = { | ||
96 | XVIMAGE_UYVY, | ||
97 | XVIMAGE_YUY2, | ||
98 | XVIMAGE_YV12, | ||
99 | }; | ||
100 | |||
101 | struct xorg_xv_port_priv { | ||
102 | struct xa_tracker *xat; | ||
103 | struct xa_context *r; | ||
104 | struct xa_fence *fence; | ||
105 | |||
106 | RegionRec clip; | ||
107 | |||
108 | int brightness; | ||
109 | int contrast; | ||
110 | int saturation; | ||
111 | int hue; | ||
112 | |||
113 | int current_set; | ||
114 | struct vmwgfx_dmabuf *bounce[2][3]; | ||
115 | struct xa_surface *yuv[3]; | ||
116 | |||
117 | int drm_fd; | ||
118 | |||
119 | Bool hdtv; | ||
120 | float uv_offset; | ||
121 | float uv_scale; | ||
122 | float y_offset; | ||
123 | float y_scale; | ||
124 | float rgb_offset; | ||
125 | float rgb_scale; | ||
126 | float sinhue; | ||
127 | float coshue; | ||
128 | float cm[16]; | ||
129 | }; | ||
130 | |||
131 | /* | ||
132 | * vmwgfx_update_conversion_matrix - Compute the effective color conversion | ||
133 | * matrix. | ||
134 | * | ||
135 | * Applies yuv- and resulting rgb scales and offsets to compute the correct | ||
136 | * color conversion matrix. These scales and offsets are properties of the | ||
137 | * video stream and can be adjusted using XV properties as well. | ||
138 | */ | ||
139 | static void | ||
140 | vmwgfx_update_conversion_matrix(struct xorg_xv_port_priv *priv) | ||
141 | { | ||
142 | int i; | ||
143 | float *cm = priv->cm; | ||
144 | static const float *bt; | ||
145 | |||
146 | bt = (priv->hdtv) ? bt_709 : bt_601; | ||
147 | |||
148 | memcpy(cm, bt, sizeof(bt_601)); | ||
149 | |||
150 | /* | ||
151 | * Apply hue rotation | ||
152 | */ | ||
153 | cm[4] = priv->coshue * bt[4] - priv->sinhue * bt[8]; | ||
154 | cm[8] = priv->sinhue * bt[4] + priv->coshue * bt[8]; | ||
155 | cm[5] = priv->coshue * bt[5] - priv->sinhue * bt[9]; | ||
156 | cm[9] = priv->sinhue * bt[5] + priv->coshue * bt[9]; | ||
157 | cm[6] = priv->coshue * bt[6] - priv->sinhue * bt[10]; | ||
158 | cm[10] = priv->sinhue * bt[6] + priv->coshue * bt[10]; | ||
159 | |||
160 | /* | ||
161 | * Adjust for yuv scales in input and rgb scale in the converted output. | ||
162 | */ | ||
163 | for(i = 0; i < 3; ++i) { | ||
164 | cm[i] *= (priv->y_scale*priv->rgb_scale); | ||
165 | cm[i+4] *= (priv->uv_scale*priv->rgb_scale); | ||
166 | cm[i+8] *= (priv->uv_scale*priv->rgb_scale); | ||
167 | } | ||
168 | |||
169 | /* | ||
170 | * Adjust for yuv offsets in input and rgb offset in the converted output. | ||
171 | */ | ||
172 | for (i = 0; i < 3; ++i) | ||
173 | cm[i+12] = -cm[i]*priv->y_offset - (cm[i+4] + cm[i+8])*priv->uv_offset | ||
174 | - priv->rgb_offset*priv->rgb_scale; | ||
175 | |||
176 | /* | ||
177 | * Alpha is 1, unconditionally. | ||
178 | */ | ||
179 | cm[15] = 1.f; | ||
180 | } | ||
181 | |||
182 | |||
183 | static void | ||
184 | stop_video(ScrnInfoPtr pScrn, pointer data, Bool shutdown) | ||
185 | { | ||
186 | struct xorg_xv_port_priv *priv = (struct xorg_xv_port_priv *)data; | ||
187 | int i, j; | ||
188 | |||
189 | REGION_EMPTY(pScrn->pScreen, &priv->clip); | ||
190 | if (shutdown) { | ||
191 | |||
192 | /* | ||
193 | * No need to destroy the xa context or xa tracker since | ||
194 | * they are copied from the screen resources. | ||
195 | */ | ||
196 | |||
197 | xa_fence_destroy(priv->fence); | ||
198 | priv->fence = NULL; | ||
199 | |||
200 | for (i=0; i<3; ++i) { | ||
201 | if (priv->yuv[i]) { | ||
202 | xa_surface_destroy(priv->yuv[i]); | ||
203 | priv->yuv[i] = NULL; | ||
204 | } | ||
205 | for (j=0; j<2; ++j) { | ||
206 | if (priv->bounce[j][i]) { | ||
207 | vmwgfx_dmabuf_destroy(priv->bounce[j][i]); | ||
208 | priv->bounce[0][i] = NULL; | ||
209 | } | ||
210 | } | ||
211 | } | ||
212 | } | ||
213 | } | ||
214 | |||
215 | static int | ||
216 | set_port_attribute(ScrnInfoPtr pScrn, | ||
217 | Atom attribute, INT32 value, pointer data) | ||
218 | { | ||
219 | struct xorg_xv_port_priv *priv = (struct xorg_xv_port_priv *)data; | ||
220 | |||
221 | if (attribute == xvBrightness) { | ||
222 | if ((value < -1000) || (value > 1000)) | ||
223 | return BadValue; | ||
224 | |||
225 | priv->brightness = value; | ||
226 | priv->y_offset = -((float) value)/1000.f; | ||
227 | |||
228 | } else if (attribute == xvContrast) { | ||
229 | if ((value < -1000) || (value > 1000)) | ||
230 | return BadValue; | ||
231 | |||
232 | priv->contrast = value; | ||
233 | priv->rgb_scale = ((float) value + 1000.f)/1000.f; | ||
234 | |||
235 | } else if (attribute == xvSaturation) { | ||
236 | if ((value < -1000) || (value > 1000)) | ||
237 | return BadValue; | ||
238 | |||
239 | priv->saturation = value; | ||
240 | priv->uv_scale = ((float) value + 1000.f)/1000.f; | ||
241 | |||
242 | } else if (attribute == xvHue) { | ||
243 | double hue_angle; | ||
244 | |||
245 | if ((value < -1000) || (value > 1000)) | ||
246 | return BadValue; | ||
247 | |||
248 | priv->hue = value; | ||
249 | hue_angle = (double) value * M_PI / 1000.; | ||
250 | priv->sinhue = sin(hue_angle); | ||
251 | priv->coshue = cos(hue_angle); | ||
252 | |||
253 | } else | ||
254 | return BadMatch; | ||
255 | |||
256 | vmwgfx_update_conversion_matrix(priv); | ||
257 | return Success; | ||
258 | } | ||
259 | |||
260 | static int | ||
261 | get_port_attribute(ScrnInfoPtr pScrn, | ||
262 | Atom attribute, INT32 * value, pointer data) | ||
263 | { | ||
264 | struct xorg_xv_port_priv *priv = (struct xorg_xv_port_priv *)data; | ||
265 | |||
266 | if (attribute == xvBrightness) | ||
267 | *value = priv->brightness; | ||
268 | else if (attribute == xvContrast) | ||
269 | *value = priv->contrast; | ||
270 | else if (attribute == xvSaturation) | ||
271 | *value = priv->saturation; | ||
272 | else if (attribute == xvHue) | ||
273 | *value = priv->hue; | ||
274 | else | ||
275 | return BadMatch; | ||
276 | |||
277 | return Success; | ||
278 | } | ||
279 | |||
280 | static void | ||
281 | query_best_size(ScrnInfoPtr pScrn, | ||
282 | Bool motion, | ||
283 | short vid_w, short vid_h, | ||
284 | short drw_w, short drw_h, | ||
285 | unsigned int *p_w, unsigned int *p_h, pointer data) | ||
286 | { | ||
287 | if (vid_w > (drw_w << 1)) | ||
288 | drw_w = vid_w >> 1; | ||
289 | if (vid_h > (drw_h << 1)) | ||
290 | drw_h = vid_h >> 1; | ||
291 | |||
292 | *p_w = drw_w; | ||
293 | *p_h = drw_h; | ||
294 | } | ||
295 | |||
296 | static int | ||
297 | check_yuv_surfaces(struct xorg_xv_port_priv *priv, int id, | ||
298 | int width, int height) | ||
299 | { | ||
300 | struct xa_surface **yuv = priv->yuv; | ||
301 | struct vmwgfx_dmabuf **bounce = priv->bounce[priv->current_set]; | ||
302 | int ret = 0; | ||
303 | int i; | ||
304 | size_t size; | ||
305 | |||
306 | for (i=0; i<3; ++i) { | ||
307 | |||
308 | /* | ||
309 | * Adjust u,v texture size and DMA buffer to what's required by | ||
310 | * the format. | ||
311 | */ | ||
312 | if (i == 1) { | ||
313 | switch(id) { | ||
314 | case FOURCC_YV12: | ||
315 | height /= 2; | ||
316 | /* Fall through */ | ||
317 | case FOURCC_YUY2: | ||
318 | case FOURCC_UYVY: | ||
319 | width /= 2; | ||
320 | break; | ||
321 | default: | ||
322 | break; | ||
323 | } | ||
324 | } | ||
325 | |||
326 | if (!yuv[i]) | ||
327 | yuv[i] = xa_surface_create(priv->xat, width, height, 8, | ||
328 | xa_type_yuv_component, | ||
329 | xa_format_unknown, 0); | ||
330 | else | ||
331 | ret = xa_surface_redefine(yuv[i], width, height, 8, | ||
332 | xa_type_yuv_component, | ||
333 | xa_format_unknown, 0, 0); | ||
334 | if (ret || !yuv[i]) | ||
335 | return BadAlloc; | ||
336 | |||
337 | size = width * height; | ||
338 | |||
339 | if (bounce[i] && (bounce[i]->size < size || | ||
340 | bounce[i]->size > 2*size)) { | ||
341 | vmwgfx_dmabuf_destroy(bounce[i]); | ||
342 | bounce[i] = NULL; | ||
343 | } | ||
344 | |||
345 | if (!bounce[i]) { | ||
346 | bounce[i] = vmwgfx_dmabuf_alloc(priv->drm_fd, size); | ||
347 | if (!bounce[i]) | ||
348 | return BadAlloc; | ||
349 | } | ||
350 | } | ||
351 | return Success; | ||
352 | } | ||
353 | |||
354 | static int | ||
355 | query_image_attributes(ScrnInfoPtr pScrn, | ||
356 | int id, | ||
357 | unsigned short *w, unsigned short *h, | ||
358 | int *pitches, int *offsets) | ||
359 | { | ||
360 | int size, tmp; | ||
361 | |||
362 | if (*w > IMAGE_MAX_WIDTH) | ||
363 | *w = IMAGE_MAX_WIDTH; | ||
364 | if (*h > IMAGE_MAX_HEIGHT) | ||
365 | *h = IMAGE_MAX_HEIGHT; | ||
366 | |||
367 | *w = (*w + 1) & ~1; | ||
368 | if (offsets) | ||
369 | offsets[0] = 0; | ||
370 | |||
371 | switch (id) { | ||
372 | case FOURCC_YV12: | ||
373 | *h = (*h + 1) & ~1; | ||
374 | size = (*w + 3) & ~3; | ||
375 | if (pitches) { | ||
376 | pitches[0] = size; | ||
377 | } | ||
378 | size *= *h; | ||
379 | if (offsets) { | ||
380 | offsets[1] = size; | ||
381 | } | ||
382 | tmp = ((*w >> 1) + 3) & ~3; | ||
383 | if (pitches) { | ||
384 | pitches[1] = pitches[2] = tmp; | ||
385 | } | ||
386 | tmp *= (*h >> 1); | ||
387 | size += tmp; | ||
388 | if (offsets) { | ||
389 | offsets[2] = size; | ||
390 | } | ||
391 | size += tmp; | ||
392 | break; | ||
393 | case FOURCC_UYVY: | ||
394 | case FOURCC_YUY2: | ||
395 | default: | ||
396 | size = *w << 1; | ||
397 | if (pitches) | ||
398 | pitches[0] = size; | ||
399 | size *= *h; | ||
400 | break; | ||
401 | } | ||
402 | |||
403 | return size; | ||
404 | } | ||
405 | |||
406 | static int | ||
407 | copy_packed_data(ScrnInfoPtr pScrn, | ||
408 | struct xorg_xv_port_priv *port, | ||
409 | int id, | ||
410 | unsigned char *buf, | ||
411 | int left, | ||
412 | int top, | ||
413 | unsigned short w, unsigned short h) | ||
414 | { | ||
415 | int i; | ||
416 | struct vmwgfx_dmabuf **bounce = port->bounce[port->current_set]; | ||
417 | char *ymap, *vmap, *umap; | ||
418 | unsigned char y1, y2, u, v; | ||
419 | int yidx, uidx, vidx; | ||
420 | int y_array_size = w * h; | ||
421 | int ret = BadAlloc; | ||
422 | |||
423 | /* | ||
424 | * Here, we could use xa_surface_[map|unmap], but given the size of | ||
425 | * the yuv textures, that could stress the xa tracker dma buffer pool, | ||
426 | * particularaly with multiple videos rendering simultaneously. | ||
427 | * | ||
428 | * Instead, cheat and allocate vmwgfx dma buffers directly. | ||
429 | */ | ||
430 | |||
431 | ymap = (char *)vmwgfx_dmabuf_map(bounce[0]); | ||
432 | if (!ymap) | ||
433 | return BadAlloc; | ||
434 | umap = (char *)vmwgfx_dmabuf_map(bounce[1]); | ||
435 | if (!umap) | ||
436 | goto out_no_umap; | ||
437 | vmap = (char *)vmwgfx_dmabuf_map(bounce[2]); | ||
438 | if (!vmap) | ||
439 | goto out_no_vmap; | ||
440 | |||
441 | |||
442 | yidx = uidx = vidx = 0; | ||
443 | |||
444 | switch (id) { | ||
445 | case FOURCC_YV12: { | ||
446 | int pitches[3], offsets[3]; | ||
447 | unsigned char *y, *u, *v; | ||
448 | query_image_attributes(pScrn, FOURCC_YV12, | ||
449 | &w, &h, pitches, offsets); | ||
450 | |||
451 | y = buf + offsets[0]; | ||
452 | v = buf + offsets[1]; | ||
453 | u = buf + offsets[2]; | ||
454 | memcpy(ymap, y, w*h); | ||
455 | memcpy(vmap, v, w*h/4); | ||
456 | memcpy(umap, u, w*h/4); | ||
457 | break; | ||
458 | } | ||
459 | case FOURCC_UYVY: | ||
460 | for (i = 0; i < y_array_size; i +=2 ) { | ||
461 | /* extracting two pixels */ | ||
462 | u = buf[0]; | ||
463 | y1 = buf[1]; | ||
464 | v = buf[2]; | ||
465 | y2 = buf[3]; | ||
466 | buf += 4; | ||
467 | |||
468 | ymap[yidx++] = y1; | ||
469 | ymap[yidx++] = y2; | ||
470 | umap[uidx++] = u; | ||
471 | vmap[vidx++] = v; | ||
472 | } | ||
473 | break; | ||
474 | case FOURCC_YUY2: | ||
475 | for (i = 0; i < y_array_size; i +=2 ) { | ||
476 | /* extracting two pixels */ | ||
477 | y1 = buf[0]; | ||
478 | u = buf[1]; | ||
479 | y2 = buf[2]; | ||
480 | v = buf[3]; | ||
481 | |||
482 | buf += 4; | ||
483 | |||
484 | ymap[yidx++] = y1; | ||
485 | ymap[yidx++] = y2; | ||
486 | umap[uidx++] = u; | ||
487 | vmap[vidx++] = v; | ||
488 | } | ||
489 | break; | ||
490 | default: | ||
491 | ret = BadAlloc; | ||
492 | break; | ||
493 | } | ||
494 | |||
495 | ret = Success; | ||
496 | vmwgfx_dmabuf_unmap(bounce[2]); | ||
497 | out_no_vmap: | ||
498 | vmwgfx_dmabuf_unmap(bounce[1]); | ||
499 | out_no_umap: | ||
500 | vmwgfx_dmabuf_unmap(bounce[0]); | ||
501 | |||
502 | if (ret == Success) { | ||
503 | struct xa_surface *srf; | ||
504 | struct vmwgfx_dmabuf *buf; | ||
505 | uint32_t handle; | ||
506 | unsigned int stride; | ||
507 | BoxRec box; | ||
508 | RegionRec reg; | ||
509 | |||
510 | box.x1 = 0; | ||
511 | box.x2 = w; | ||
512 | box.y1 = 0; | ||
513 | box.y2 = h; | ||
514 | |||
515 | REGION_INIT(pScrn->pScreen, ®, &box, 1); | ||
516 | |||
517 | for (i=0; i<3; ++i) { | ||
518 | srf = port->yuv[i]; | ||
519 | buf = bounce[i]; | ||
520 | |||
521 | if (i == 1) { | ||
522 | switch(id) { | ||
523 | case FOURCC_YV12: | ||
524 | h /= 2; | ||
525 | /* Fall through */ | ||
526 | case FOURCC_YUY2: | ||
527 | case FOURCC_UYVY: | ||
528 | w /= 2; | ||
529 | break; | ||
530 | default: | ||
531 | break; | ||
532 | } | ||
533 | |||
534 | box.x1 = 0; | ||
535 | box.x2 = w; | ||
536 | box.y1 = 0; | ||
537 | box.y2 = h; | ||
538 | |||
539 | REGION_RESET(pScrn->pScreen, ®, &box); | ||
540 | } | ||
541 | |||
542 | if (xa_surface_handle(srf, &handle, &stride) != 0) { | ||
543 | ret = BadAlloc; | ||
544 | break; | ||
545 | } | ||
546 | |||
547 | if (vmwgfx_dma(0, 0, ®, buf, w, handle, 1) != 0) { | ||
548 | ret = BadAlloc; | ||
549 | break; | ||
550 | } | ||
551 | } | ||
552 | REGION_UNINIT(pScrn->pScreen, ®); | ||
553 | } | ||
554 | |||
555 | return ret; | ||
556 | } | ||
557 | |||
558 | |||
559 | static int | ||
560 | display_video(ScreenPtr pScreen, struct xorg_xv_port_priv *pPriv, int id, | ||
561 | RegionPtr dstRegion, | ||
562 | int src_x, int src_y, int src_w, int src_h, | ||
563 | int dst_x, int dst_y, int dst_w, int dst_h, | ||
564 | PixmapPtr pPixmap) | ||
565 | { | ||
566 | struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pPixmap); | ||
567 | Bool hdtv; | ||
568 | RegionRec reg; | ||
569 | int ret = BadAlloc; | ||
570 | int blit_ret; | ||
571 | |||
572 | REGION_NULL(pScreen, ®); | ||
573 | |||
574 | if (!vmwgfx_hw_accel_validate(pPixmap, 0, XA_FLAG_RENDER_TARGET, 0, ®)) | ||
575 | goto out_no_dst; | ||
576 | |||
577 | hdtv = ((src_w >= RES_720P_X) && (src_h >= RES_720P_Y)); | ||
578 | if (hdtv != pPriv->hdtv) { | ||
579 | pPriv->hdtv = hdtv; | ||
580 | vmwgfx_update_conversion_matrix(pPriv); | ||
581 | } | ||
582 | |||
583 | #ifdef COMPOSITE | ||
584 | |||
585 | /* | ||
586 | * For redirected windows, we need to fix up the destination coordinates. | ||
587 | */ | ||
588 | |||
589 | REGION_TRANSLATE(pScreen, dstRegion, -pPixmap->screen_x, | ||
590 | -pPixmap->screen_y); | ||
591 | dst_x -= pPixmap->screen_x; | ||
592 | dst_y -= pPixmap->screen_y; | ||
593 | #endif | ||
594 | |||
595 | /* | ||
596 | * Throttle on previous blit. | ||
597 | */ | ||
598 | |||
599 | if (pPriv->fence) { | ||
600 | (void) xa_fence_wait(pPriv->fence, 1000000000ULL); | ||
601 | xa_fence_destroy(pPriv->fence); | ||
602 | pPriv->fence = NULL; | ||
603 | } | ||
604 | |||
605 | DamageRegionAppend(&pPixmap->drawable, dstRegion); | ||
606 | |||
607 | blit_ret = xa_yuv_planar_blit(pPriv->r, src_x, src_y, src_w, src_h, | ||
608 | dst_x, dst_y, dst_w, dst_h, | ||
609 | (struct xa_box *)REGION_RECTS(dstRegion), | ||
610 | REGION_NUM_RECTS(dstRegion), | ||
611 | pPriv->cm, | ||
612 | vpix->hw, pPriv->yuv); | ||
613 | |||
614 | saa_pixmap_dirty(pPixmap, TRUE, dstRegion); | ||
615 | DamageRegionProcessPending(&pPixmap->drawable); | ||
616 | ret = Success; | ||
617 | |||
618 | if (!blit_ret) { | ||
619 | ret = Success; | ||
620 | pPriv->fence = xa_fence_get(pPriv->r); | ||
621 | } else | ||
622 | ret = BadAlloc; | ||
623 | |||
624 | out_no_dst: | ||
625 | REGION_UNINIT(pScreen, ®); | ||
626 | return ret; | ||
627 | } | ||
628 | |||
629 | static int | ||
630 | put_image(ScrnInfoPtr pScrn, | ||
631 | short src_x, short src_y, | ||
632 | short drw_x, short drw_y, | ||
633 | short src_w, short src_h, | ||
634 | short drw_w, short drw_h, | ||
635 | int id, unsigned char *buf, | ||
636 | short width, short height, | ||
637 | Bool sync, RegionPtr clipBoxes, pointer data, | ||
638 | DrawablePtr pDraw) | ||
639 | { | ||
640 | struct xorg_xv_port_priv *pPriv = (struct xorg_xv_port_priv *) data; | ||
641 | ScreenPtr pScreen = screenInfo.screens[pScrn->scrnIndex]; | ||
642 | PixmapPtr pPixmap; | ||
643 | INT32 x1, x2, y1, y2; | ||
644 | BoxRec dstBox; | ||
645 | int ret; | ||
646 | |||
647 | /* Clip */ | ||
648 | x1 = src_x; | ||
649 | x2 = src_x + src_w; | ||
650 | y1 = src_y; | ||
651 | y2 = src_y + src_h; | ||
652 | |||
653 | dstBox.x1 = drw_x; | ||
654 | dstBox.x2 = drw_x + drw_w; | ||
655 | dstBox.y1 = drw_y; | ||
656 | dstBox.y2 = drw_y + drw_h; | ||
657 | |||
658 | if (!xf86XVClipVideoHelper(&dstBox, &x1, &x2, &y1, &y2, clipBoxes, | ||
659 | width, height)) | ||
660 | return Success; | ||
661 | |||
662 | ret = check_yuv_surfaces(pPriv, id, width, height); | ||
663 | if (ret) | ||
664 | return ret; | ||
665 | |||
666 | ret = copy_packed_data(pScrn, pPriv, id, buf, | ||
667 | src_x, src_y, width, height); | ||
668 | if (ret) | ||
669 | return ret; | ||
670 | |||
671 | if (pDraw->type == DRAWABLE_WINDOW) { | ||
672 | pPixmap = (*pScreen->GetWindowPixmap)((WindowPtr)pDraw); | ||
673 | } else { | ||
674 | pPixmap = (PixmapPtr)pDraw; | ||
675 | } | ||
676 | |||
677 | display_video(pScrn->pScreen, pPriv, id, clipBoxes, | ||
678 | src_x, src_y, src_w, src_h, | ||
679 | drw_x, drw_y, | ||
680 | drw_w, drw_h, pPixmap); | ||
681 | |||
682 | pPriv->current_set = (pPriv->current_set + 1) & 1; | ||
683 | return Success; | ||
684 | } | ||
685 | |||
686 | static struct xorg_xv_port_priv * | ||
687 | port_priv_create(struct xa_tracker *xat, struct xa_context *r, | ||
688 | int drm_fd) | ||
689 | { | ||
690 | struct xorg_xv_port_priv *priv = NULL; | ||
691 | |||
692 | priv = calloc(1, sizeof(struct xorg_xv_port_priv)); | ||
693 | |||
694 | if (!priv) | ||
695 | return NULL; | ||
696 | |||
697 | priv->r = r; | ||
698 | priv->xat = xat; | ||
699 | priv->drm_fd = drm_fd; | ||
700 | REGION_NULL(pScreen, &priv->clip); | ||
701 | priv->hdtv = FALSE; | ||
702 | priv->uv_offset = 0.5f; | ||
703 | priv->uv_scale = 1.f; | ||
704 | priv->y_offset = 0.f; | ||
705 | priv->y_scale = 1.f; | ||
706 | priv->rgb_offset = 0.f; | ||
707 | priv->rgb_scale = 1.f; | ||
708 | priv->sinhue = 0.f; | ||
709 | priv->coshue = 1.f; | ||
710 | |||
711 | vmwgfx_update_conversion_matrix(priv); | ||
712 | |||
713 | return priv; | ||
714 | } | ||
715 | |||
716 | static void | ||
717 | vmwgfx_free_textured_adaptor(XF86VideoAdaptorPtr adaptor, Bool free_ports) | ||
718 | { | ||
719 | if (free_ports) { | ||
720 | int i; | ||
721 | |||
722 | for(i=0; i<adaptor->nPorts; ++i) { | ||
723 | free(adaptor->pPortPrivates[i].ptr); | ||
724 | } | ||
725 | } | ||
726 | |||
727 | free(adaptor->pAttributes); | ||
728 | free(adaptor->pPortPrivates); | ||
729 | xf86XVFreeVideoAdaptorRec(adaptor); | ||
730 | } | ||
731 | |||
732 | static XF86VideoAdaptorPtr | ||
733 | xorg_setup_textured_adapter(ScreenPtr pScreen) | ||
734 | { | ||
735 | ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; | ||
736 | modesettingPtr ms = modesettingPTR(pScrn); | ||
737 | XF86VideoAdaptorPtr adapt; | ||
738 | XF86AttributePtr attrs; | ||
739 | DevUnion *dev_unions; | ||
740 | int nports = 16, i; | ||
741 | int nattributes; | ||
742 | struct xa_context *xar; | ||
743 | |||
744 | /* | ||
745 | * Use the XA default context since we don't expect the X server | ||
746 | * to render from multiple threads. | ||
747 | */ | ||
748 | |||
749 | xar = xa_context_default(ms->xat); | ||
750 | nattributes = NUM_TEXTURED_ATTRIBUTES; | ||
751 | |||
752 | adapt = calloc(1, sizeof(XF86VideoAdaptorRec)); | ||
753 | dev_unions = calloc(nports, sizeof(DevUnion)); | ||
754 | attrs = calloc(nattributes, sizeof(XF86AttributeRec)); | ||
755 | if (adapt == NULL || dev_unions == NULL || attrs == NULL) { | ||
756 | free(adapt); | ||
757 | free(dev_unions); | ||
758 | free(attrs); | ||
759 | return NULL; | ||
760 | } | ||
761 | |||
762 | adapt->type = XvWindowMask | XvInputMask | XvImageMask; | ||
763 | adapt->flags = 0; | ||
764 | adapt->name = "XA G3D Textured Video"; | ||
765 | adapt->nEncodings = 1; | ||
766 | adapt->pEncodings = DummyEncoding; | ||
767 | adapt->nFormats = NUM_FORMATS; | ||
768 | adapt->pFormats = Formats; | ||
769 | adapt->nPorts = 0; | ||
770 | adapt->pPortPrivates = dev_unions; | ||
771 | adapt->nAttributes = nattributes; | ||
772 | adapt->pAttributes = attrs; | ||
773 | memcpy(attrs, TexturedAttributes, nattributes * sizeof(XF86AttributeRec)); | ||
774 | adapt->nImages = NUM_IMAGES; | ||
775 | adapt->pImages = Images; | ||
776 | adapt->PutVideo = NULL; | ||
777 | adapt->PutStill = NULL; | ||
778 | adapt->GetVideo = NULL; | ||
779 | adapt->GetStill = NULL; | ||
780 | adapt->StopVideo = stop_video; | ||
781 | adapt->SetPortAttribute = set_port_attribute; | ||
782 | adapt->GetPortAttribute = get_port_attribute; | ||
783 | adapt->QueryBestSize = query_best_size; | ||
784 | adapt->PutImage = put_image; | ||
785 | adapt->QueryImageAttributes = query_image_attributes; | ||
786 | |||
787 | |||
788 | for (i = 0; i < nports; i++) { | ||
789 | struct xorg_xv_port_priv *priv = | ||
790 | port_priv_create(ms->xat, xar, ms->fd); | ||
791 | |||
792 | adapt->pPortPrivates[i].ptr = (pointer) (priv); | ||
793 | adapt->nPorts++; | ||
794 | } | ||
795 | |||
796 | return adapt; | ||
797 | } | ||
798 | |||
799 | void | ||
800 | xorg_xv_init(ScreenPtr pScreen) | ||
801 | { | ||
802 | ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; | ||
803 | modesettingPtr ms = modesettingPTR(pScrn); | ||
804 | XF86VideoAdaptorPtr *adaptors, *new_adaptors = NULL; | ||
805 | XF86VideoAdaptorPtr textured_adapter = NULL, overlay_adaptor = NULL; | ||
806 | int num_adaptors; | ||
807 | |||
808 | num_adaptors = xf86XVListGenericAdaptors(pScrn, &adaptors); | ||
809 | new_adaptors = malloc((num_adaptors + 2) * sizeof(XF86VideoAdaptorPtr *)); | ||
810 | if (new_adaptors == NULL) | ||
811 | return; | ||
812 | |||
813 | memcpy(new_adaptors, adaptors, num_adaptors * sizeof(XF86VideoAdaptorPtr)); | ||
814 | adaptors = new_adaptors; | ||
815 | |||
816 | /* Add the adaptors supported by our hardware. First, set up the atoms | ||
817 | * that will be used by both output adaptors. | ||
818 | */ | ||
819 | xvBrightness = MAKE_ATOM("XV_BRIGHTNESS"); | ||
820 | xvContrast = MAKE_ATOM("XV_CONTRAST"); | ||
821 | xvSaturation = MAKE_ATOM("XV_SATURATION"); | ||
822 | xvHue = MAKE_ATOM("XV_HUE"); | ||
823 | |||
824 | if (ms->xat) { | ||
825 | textured_adapter = xorg_setup_textured_adapter(pScreen); | ||
826 | if (textured_adapter) | ||
827 | adaptors[num_adaptors++] = textured_adapter; | ||
828 | } else { | ||
829 | xf86DrvMsg(pScrn->scrnIndex, X_INFO, | ||
830 | "No 3D acceleration. Not setting up textured video.\n"); | ||
831 | } | ||
832 | |||
833 | overlay_adaptor = vmw_video_init_adaptor(pScrn); | ||
834 | if (overlay_adaptor) | ||
835 | adaptors[num_adaptors++] = overlay_adaptor; | ||
836 | |||
837 | if (num_adaptors) { | ||
838 | Bool ret; | ||
839 | ret = xf86XVScreenInit(pScreen, adaptors, num_adaptors); | ||
840 | if (textured_adapter) | ||
841 | vmwgfx_free_textured_adaptor(textured_adapter, !ret); | ||
842 | if (overlay_adaptor) | ||
843 | vmw_video_free_adaptor(overlay_adaptor, !ret); | ||
844 | if (!ret) | ||
845 | xf86DrvMsg(pScrn->scrnIndex, X_ERROR, | ||
846 | "Failed to initialize Xv.\n"); | ||
847 | } else { | ||
848 | xf86DrvMsg(pScrn->scrnIndex, X_WARNING, | ||
849 | "Disabling Xv because no adaptors could be initialized.\n"); | ||
850 | } | ||
851 | |||
852 | |||
853 | out_err_mem: | ||
854 | free(adaptors); | ||
855 | } | ||