~gma500/emgd/trunk

« back to all changes in this revision

Viewing changes to xserver-xorg-video-psb/xserver-xorg-video-psb-0.32.1/src/psb_video.c

  • Committer: José Bernardo Bandos
  • Date: 2010-08-28 16:04:10 UTC
  • Revision ID: jbs@jbs-laptop-20100828160410-nw5zohdn37oupdv2
First step to add emgd drivers from meego

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/**************************************************************************
2
 
 *
3
 
 * Copyright (c) Intel Corp. 2007.
4
 
 * All Rights Reserved.
5
 
 *
6
 
 * Intel funded Tungsten Graphics (http://www.tungstengraphics.com) to
7
 
 * develop this driver.
8
 
 *
9
 
 * Permission is hereby granted, free of charge, to any person obtaining a
10
 
 * copy of this software and associated documentation files (the
11
 
 * "Software"), to deal in the Software without restriction, including
12
 
 * without limitation the rights to use, copy, modify, merge, publish,
13
 
 * distribute, sub license, and/or sell copies of the Software, and to
14
 
 * permit persons to whom the Software is furnished to do so, subject to
15
 
 * the following conditions:
16
 
 *
17
 
 * The above copyright notice and this permission notice (including the
18
 
 * next paragraph) shall be included in all copies or substantial portions
19
 
 * of the Software.
20
 
 *
21
 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22
 
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23
 
 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
24
 
 * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
25
 
 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
26
 
 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
27
 
 * USE OR OTHER DEALINGS IN THE SOFTWARE.
28
 
 *
29
 
 **************************************************************************/
30
 
/*
31
 
 */
32
 
 
33
 
#ifdef HAVE_CONFIG_H
34
 
#include "config.h"
35
 
#endif
36
 
 
37
 
#include "xf86.h"
38
 
#include "xf86_OSproc.h"
39
 
#include "xf86Resources.h"
40
 
#include "compiler.h"
41
 
 
42
 
#include "xf86xv.h"
43
 
#include <X11/extensions/Xv.h>
44
 
 
45
 
#include "psb_driver.h"
46
 
#include "fourcc.h"
47
 
#include "regionstr.h"
48
 
#include "../libmm/mm_interface.h"
49
 
#include "psb_drm.h"
50
 
#include "Xpsb.h"
51
 
 
52
 
#define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE)
53
 
 
54
 
#define PSB_IMAGE_MAX_WIDTH             2047
55
 
#define PSB_IMAGE_MAX_HEIGHT            2047
56
 
#define PSB_HDTV_LIMIT_X                1280
57
 
#define PSB_HDTV_LIMIT_Y                720
58
 
 
59
 
/*
60
 
 * YUV to RBG conversion.
61
 
 */
62
 
 
63
 
static float yOffset = 16.f;
64
 
static float yRange = 219.f;
65
 
static float videoGamma = 2.8f;
66
 
 
67
 
/*
68
 
 * The ITU-R BT.601 conversion matrix for SDTV.
69
 
 */
70
 
 
71
 
static float bt_601[] = {
72
 
    1.0, 0.0, 1.4075,
73
 
    1.0, -0.3455, -0.7169,
74
 
    1.0, 1.7790, 0.
75
 
};
76
 
 
77
 
/*
78
 
 * The ITU-R BT.709 conversion matrix for HDTV.
79
 
 */
80
 
 
81
 
static float bt_709[] = {
82
 
    1.0, 0.0, 1.581,
83
 
    1.0, -0.1881, -0.47,
84
 
    1.0, 1.8629, 0.
85
 
};
86
 
 
87
 
#ifndef exaMoveInPixmap
88
 
void exaMoveInPixmap(PixmapPtr pPixmap);
89
 
#endif
90
 
 
91
 
static XF86VideoEncodingRec DummyEncoding[1] = {
92
 
    {
93
 
     0,
94
 
     "XV_IMAGE",
95
 
     PSB_IMAGE_MAX_WIDTH, PSB_IMAGE_MAX_HEIGHT,
96
 
     {1, 1}
97
 
     }
98
 
};
99
 
 
100
 
#define PSB_NUM_FORMATS 3
101
 
static XF86VideoFormatRec Formats[PSB_NUM_FORMATS] = {
102
 
    {15, TrueColor}, {16, TrueColor}, {24, TrueColor}
103
 
};
104
 
 
105
 
static XF86AttributeRec Attributes[] = {
106
 
    /* {XvSettable | XvGettable, 0, (1 << 24) - 1, "XV_COLORKEY"}, */
107
 
    {XvSettable | XvGettable, -50, 50, "XV_BRIGHTNESS"},
108
 
    {XvSettable | XvGettable, -30, 30, "XV_HUE"},
109
 
    {XvSettable | XvGettable, 0, 200, "XV_SATURATION"},
110
 
    {XvSettable | XvGettable, -100, 100, "XV_CONTRAST"},
111
 
};
112
 
 
113
 
#define PSB_NUM_ATTRIBUTES sizeof(Attributes)/sizeof(XF86AttributeRec)
114
 
 
115
 
/*
116
 
 * FOURCC definitions
117
 
 */
118
 
#define FOURCC_NV12     (('2' << 24) + ('1' << 16) + ('V' << 8) + 'N')
119
 
 
120
 
#define XVIMAGE_NV12 \
121
 
   { \
122
 
        FOURCC_NV12, \
123
 
        XvYUV, \
124
 
        LSBFirst, \
125
 
        {'N','V','1','2', \
126
 
          0x00,0x00,0x00,0x10,0x80,0x00,0x00,0xAA,0x00,0x38,0x9B,0x71}, \
127
 
        12, \
128
 
        XvPlanar, \
129
 
        2, \
130
 
        0, 0, 0, 0, \
131
 
        8, 8, 8, \
132
 
        1, 2, 2, \
133
 
        1, 2, 2, \
134
 
        {'Y','U','V', \
135
 
          0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, \
136
 
        XvTopToBottom \
137
 
   }
138
 
 
139
 
static XF86ImageRec Images[] = {
140
 
    XVIMAGE_UYVY,
141
 
    XVIMAGE_YUY2,
142
 
    XVIMAGE_YV12,
143
 
    XVIMAGE_I420,
144
 
    XVIMAGE_NV12,
145
 
};
146
 
 
147
 
#define PSB_NUM_IMAGES sizeof(Images)/sizeof(XF86ImageRec)
148
 
 
149
 
/*
150
 
 * Currently we have 4 ports on the adaptor.
151
 
 * We might want to make this a configurable option.
152
 
 */
153
 
 
154
 
#define PSB_ADAPT0_NUM_PORTS 4
155
 
 
156
 
/*define some structure used by the ported code  */
157
 
 
158
 
static Atom xvBrightness;
159
 
static Atom xvContrast;
160
 
static Atom xvSaturation;
161
 
static Atom xvHue;
162
 
 
163
 
#define HUE_DEFAULT_VALUE   0
164
 
#define HUE_MIN            -30
165
 
#define HUE_MAX             30
166
 
 
167
 
#define BRIGHTNESS_DEFAULT_VALUE   0
168
 
#define BRIGHTNESS_MIN            -50
169
 
#define BRIGHTNESS_MAX             50
170
 
 
171
 
#define CONTRAST_DEFAULT_VALUE     0
172
 
#define CONTRAST_MIN              -100
173
 
#define CONTRAST_MAX               100
174
 
 
175
 
#define SATURATION_DEFAULT_VALUE   100
176
 
#define SATURATION_MIN             0
177
 
#define SATURATION_MAX             200
178
 
 
179
 
#define CLAMP_ATTR(a,max,min) (a>max?max:(a<min?min:a))
180
 
 
181
 
typedef enum _psb_nominalrange
182
 
{
183
 
    PSB_NominalRangeMask = 0x07,
184
 
    PSB_NominalRange_Unknown = 0,
185
 
    PSB_NominalRange_Normal = 1,
186
 
    PSB_NominalRange_Wide = 2,
187
 
    /* explicit range forms */
188
 
    PSB_NominalRange_0_255 = 1,
189
 
    PSB_NominalRange_16_235 = 2,
190
 
    PSB_NominalRange_48_208 = 3
191
 
} psb_nominalrange;
192
 
 
193
 
typedef enum _psb_videotransfermatrix
194
 
{
195
 
    PSB_VideoTransferMatrixMask = 0x07,
196
 
    PSB_VideoTransferMatrix_Unknown = 0,
197
 
    PSB_VideoTransferMatrix_BT709 = 1,
198
 
    PSB_VideoTransferMatrix_BT601 = 2,
199
 
    PSB_VideoTransferMatrix_SMPTE240M = 3
200
 
} psb_videotransfermatrix;
201
 
 
202
 
typedef struct _psb_fixed32
203
 
{
204
 
    union
205
 
    {
206
 
        struct
207
 
        {
208
 
            unsigned short Fraction;
209
 
            short Value;
210
 
        };
211
 
        long ll;
212
 
    };
213
 
} psb_fixed32;
214
 
 
215
 
#define Degree (2*PI / 360.0)
216
 
#define PI 3.1415927
217
 
 
218
 
typedef struct _psb_transform_coeffs_
219
 
{
220
 
    double rY, rCb, rCr;
221
 
    double gY, gCb, gCr;
222
 
    double bY, bCb, bCr;
223
 
} psb_transform_coeffs;
224
 
 
225
 
typedef struct _psb_coeffs_
226
 
{
227
 
    signed char rY;
228
 
    signed char rU;
229
 
    signed char rV;
230
 
    signed char gY;
231
 
    signed char gU;
232
 
    signed char gV;
233
 
    signed char bY;
234
 
    signed char bU;
235
 
    signed char bV;
236
 
    unsigned char rShift;
237
 
    unsigned char gShift;
238
 
    unsigned char bShift;
239
 
    signed short rConst;
240
 
    signed short gConst;
241
 
    signed short bConst;
242
 
} psb_coeffs_s, *psb_coeffs_p;
243
 
 
244
 
typedef struct _PsbPortPrivRec
245
 
{
246
 
    RegionRec clip;
247
 
    struct _MMManager *man;
248
 
    struct _MMBuffer *videoBuf[2];
249
 
    int curBuf;
250
 
    int videoBufSize;
251
 
    float conversionData[11];
252
 
    Bool hdtv;
253
 
    XpsbSurface srf[3][2];
254
 
    XpsbSurface dst;
255
 
    unsigned int bufPitch;
256
 
 
257
 
    /* information of display attribute */
258
 
    psb_fixed32 brightness;
259
 
    psb_fixed32 contrast;
260
 
    psb_fixed32 saturation;
261
 
    psb_fixed32 hue;
262
 
 
263
 
    /* gets set by any changes to Hue, Brightness,saturation, hue or csc matrix. */
264
 
    psb_coeffs_s coeffs;
265
 
    unsigned long sgx_coeffs[9];
266
 
 
267
 
    unsigned int src_nominalrange;
268
 
    unsigned int dst_nominalrange;
269
 
    unsigned int video_transfermatrix;
270
 
} PsbPortPrivRec, *PsbPortPrivPtr;
271
 
 
272
 
static void
273
 
psbSetupConversionData(PsbPortPrivPtr pPriv, Bool hdtv)
274
 
{
275
 
    if (pPriv->hdtv != hdtv) {
276
 
        int i;
277
 
 
278
 
        if (hdtv)
279
 
            memcpy(pPriv->conversionData, bt_709, sizeof(bt_709));
280
 
        else
281
 
            memcpy(pPriv->conversionData, bt_601, sizeof(bt_601));
282
 
 
283
 
        for (i = 0; i < 9; ++i) {
284
 
            pPriv->conversionData[i] /= yRange;
285
 
        }
286
 
 
287
 
        /*
288
 
         * Adjust for brightness, contrast, hue and saturation here.
289
 
         */
290
 
 
291
 
        pPriv->conversionData[9] = -yOffset;
292
 
        /*
293
 
         * Not used ATM
294
 
         */
295
 
        pPriv->conversionData[10] = videoGamma;
296
 
        pPriv->hdtv = hdtv;
297
 
    }
298
 
}
299
 
 
300
 
static void psb_setup_coeffs(PsbPortPrivPtr);
301
 
static void psb_pack_coeffs(PsbPortPrivPtr, unsigned long *);
302
 
 
303
 
static void
304
 
psbSetupPlanarConversionData(PsbPortPrivPtr pPriv, Bool hdtv)
305
 
{
306
 
    psb_setup_coeffs(pPriv);
307
 
    psb_pack_coeffs(pPriv, &pPriv->sgx_coeffs[0]);
308
 
}
309
 
 
310
 
static void psbStopVideo(ScrnInfoPtr pScrn, pointer data, Bool shutdown);
311
 
 
312
 
static PsbPortPrivPtr
313
 
psbPortPrivCreate(ScrnInfoPtr pScrn)
314
 
{
315
 
    PsbDevicePtr pDevice = psbDevicePTR(psbPTR(pScrn));
316
 
    PsbPortPrivPtr pPriv;
317
 
 
318
 
    pPriv = xcalloc(1, sizeof(*pPriv));
319
 
    if (!pPriv)
320
 
        return NULL;
321
 
    pPriv->man = pDevice->man;
322
 
    REGION_NULL(pScreen, &pPriv->clip);
323
 
    pPriv->hdtv = TRUE;
324
 
    psbSetupConversionData(pPriv, FALSE);
325
 
 
326
 
    /* coeffs defaut value */
327
 
    pPriv->brightness.Value = BRIGHTNESS_DEFAULT_VALUE;
328
 
    pPriv->brightness.Fraction = 0;
329
 
 
330
 
    pPriv->contrast.Value = CONTRAST_DEFAULT_VALUE;
331
 
    pPriv->contrast.Fraction = 0;
332
 
    pPriv->hue.Value = HUE_DEFAULT_VALUE;
333
 
    pPriv->hue.Fraction = 0;
334
 
    pPriv->saturation.Value = SATURATION_DEFAULT_VALUE;
335
 
    pPriv->saturation.Fraction = 0;
336
 
 
337
 
    psbSetupPlanarConversionData(pPriv, FALSE);
338
 
 
339
 
    return pPriv;
340
 
}
341
 
 
342
 
static void
343
 
psbPortPrivDestroy(ScrnInfoPtr pScrn, PsbPortPrivPtr pPriv)
344
 
{
345
 
    if (!pPriv)
346
 
        return;
347
 
 
348
 
    psbStopVideo(pScrn, pPriv, TRUE);
349
 
 
350
 
    if (pPriv->videoBuf[0]) {
351
 
        mmBufDestroy(pPriv->videoBuf[0]);
352
 
        mmBufDestroy(pPriv->videoBuf[1]);
353
 
    }
354
 
    xfree(pPriv);
355
 
}
356
 
 
357
 
static int
358
 
psbCheckVideoBuffer(PsbPortPrivPtr pPriv, unsigned int size)
359
 
{
360
 
    size = ALIGN_TO(size, 4096);
361
 
 
362
 
    if (pPriv->videoBuf[0] && pPriv->videoBufSize != size) {
363
 
        mmBufDestroy(pPriv->videoBuf[0]);
364
 
        mmBufDestroy(pPriv->videoBuf[1]);
365
 
        pPriv->videoBuf[0] = NULL;
366
 
        pPriv->videoBuf[1] = NULL;
367
 
    }
368
 
    if (!pPriv->videoBuf[0]) {
369
 
        pPriv->videoBuf[0] = pPriv->man->createBuf(pPriv->man,
370
 
                                                   size,
371
 
                                                   0,
372
 
                                                   DRM_PSB_FLAG_MEM_MMU |
373
 
                                                   DRM_BO_FLAG_READ,
374
 
                                                   DRM_BO_HINT_DONT_FENCE);
375
 
        if (!pPriv->videoBuf[0])
376
 
            return BadAlloc;
377
 
 
378
 
        pPriv->videoBuf[1] = pPriv->man->createBuf(pPriv->man,
379
 
                                                   size,
380
 
                                                   0,
381
 
                                                   DRM_PSB_FLAG_MEM_MMU |
382
 
                                                   DRM_BO_FLAG_READ,
383
 
                                                   DRM_BO_HINT_DONT_FENCE);
384
 
        if (!pPriv->videoBuf[1]) {
385
 
            mmBufDestroy(pPriv->videoBuf[0]);
386
 
            pPriv->videoBuf[0] = NULL;
387
 
            return BadAlloc;
388
 
        }
389
 
 
390
 
        pPriv->videoBufSize = size;
391
 
        pPriv->srf[0][0].buffer = mmKernelBuf(pPriv->videoBuf[0]);
392
 
        pPriv->srf[0][0].offset = 0;
393
 
        pPriv->srf[0][1].buffer = mmKernelBuf(pPriv->videoBuf[1]);
394
 
        pPriv->srf[0][1].offset = 0;
395
 
    }
396
 
    return Success;
397
 
}
398
 
 
399
 
static int
400
 
psbSetPortAttribute(ScrnInfoPtr pScrn,
401
 
                    Atom attribute, INT32 value, pointer data)
402
 
{
403
 
    PsbPortPrivPtr pPriv = (PsbPortPrivPtr) data;
404
 
    int update_coeffs = 0;
405
 
 
406
 
    if (attribute == xvBrightness) {
407
 
        pPriv->brightness.Value =
408
 
            CLAMP_ATTR(value, BRIGHTNESS_MAX, BRIGHTNESS_MIN);
409
 
        update_coeffs = 1;
410
 
    } else if (attribute == xvContrast) {
411
 
        pPriv->contrast.Value = CLAMP_ATTR(value, CONTRAST_MAX, CONTRAST_MIN);
412
 
        update_coeffs = 1;
413
 
    } else if (attribute == xvHue) {
414
 
        pPriv->hue.Value = CLAMP_ATTR(value, HUE_MAX, HUE_MIN);
415
 
        update_coeffs = 1;
416
 
    } else if (attribute == xvSaturation) {
417
 
        pPriv->saturation.Value =
418
 
            CLAMP_ATTR(value, SATURATION_MAX, SATURATION_MIN);
419
 
        update_coeffs = 1;
420
 
    } else
421
 
        return BadValue;
422
 
 
423
 
    if (update_coeffs) {
424
 
        psb_setup_coeffs(pPriv);
425
 
        psb_pack_coeffs(pPriv, &pPriv->sgx_coeffs[0]);
426
 
        update_coeffs = 0;
427
 
    }
428
 
 
429
 
    return Success;
430
 
}
431
 
 
432
 
static int
433
 
psbGetPortAttribute(ScrnInfoPtr pScrn,
434
 
                    Atom attribute, INT32 * value, pointer data)
435
 
{
436
 
    PsbPortPrivPtr pPriv = (PsbPortPrivPtr) data;
437
 
 
438
 
    if (attribute == xvBrightness)
439
 
        *value = pPriv->brightness.Value;
440
 
    else if (attribute == xvContrast)
441
 
        *value = pPriv->contrast.Value;
442
 
    else if (attribute == xvHue)
443
 
        *value = pPriv->hue.Value;
444
 
    else if (attribute == xvSaturation)
445
 
        *value = pPriv->saturation.Value;
446
 
    else
447
 
        return BadValue;
448
 
 
449
 
    return Success;
450
 
}
451
 
 
452
 
static void
453
 
psbQueryBestSize(ScrnInfoPtr pScrn,
454
 
                 Bool motion,
455
 
                 short vid_w, short vid_h,
456
 
                 short drw_w, short drw_h,
457
 
                 unsigned int *p_w, unsigned int *p_h, pointer data)
458
 
{
459
 
    if (vid_w > (drw_w << 1))
460
 
        drw_w = vid_w >> 1;
461
 
    if (vid_h > (drw_h << 1))
462
 
        drw_h = vid_h >> 1;
463
 
 
464
 
    *p_w = drw_w;
465
 
    *p_h = drw_h;
466
 
}
467
 
 
468
 
static void
469
 
psbCopyPackedData(ScrnInfoPtr pScrn, PsbPortPrivPtr pPriv,
470
 
                  unsigned char *buf,
471
 
                  int srcPitch, int dstPitch, int top, int left, int h, int w)
472
 
{
473
 
    unsigned char *src, *dst;
474
 
    int i;
475
 
    struct _MMBuffer *dstBuf = pPriv->videoBuf[pPriv->curBuf];
476
 
 
477
 
    src = buf + (top * srcPitch) + (left << 1);
478
 
 
479
 
    /*
480
 
     * Note. Map also syncs with previous usage.
481
 
     */
482
 
 
483
 
    dstBuf->man->mapBuf(dstBuf, MM_FLAG_WRITE, 0);
484
 
    dst = mmBufVirtual(dstBuf);
485
 
    w <<= 1;
486
 
    for (i = 0; i < h; i++) {
487
 
        memcpy(dst, src, w);
488
 
        src += srcPitch;
489
 
        dst += dstPitch;
490
 
    }
491
 
    dstBuf->man->unMapBuf(dstBuf);
492
 
}
493
 
 
494
 
static void
495
 
psbCopyPlanarYUVData(ScrnInfoPtr pScrn, PsbPortPrivPtr pPriv,
496
 
                     unsigned char *buf,
497
 
                     int srcPitch, int dstPitch, int dstPitch2,
498
 
                     int top, int left, int h, int w, int id)
499
 
{
500
 
    unsigned char *src_y, *src_u, *src_v, *dst_y, *dst_u, *dst_v;
501
 
    int i;
502
 
    struct _MMBuffer *dstBuf = pPriv->videoBuf[pPriv->curBuf];
503
 
 
504
 
    src_y = buf + (top * srcPitch) + left;
505
 
    if (id == FOURCC_YV12) {           /* YUV */
506
 
        src_u = buf + srcPitch * h + top * (srcPitch >> 1) + (left >> 1);
507
 
        src_v = buf + srcPitch * h + (srcPitch >> 1) * (h >> 1)
508
 
            + top * (srcPitch >> 1) + (left >> 1);
509
 
    } else {                           /* YVU */
510
 
        src_v = buf + srcPitch * h + top * (srcPitch >> 1) + (left >> 1);
511
 
        src_u = buf + srcPitch * h + (srcPitch >> 1) * (h >> 1)
512
 
            + top * (srcPitch >> 1) + (left >> 1);
513
 
    }
514
 
 
515
 
    /*
516
 
     * Note. Map also syncs with previous usage.
517
 
     */
518
 
 
519
 
    dstBuf->man->mapBuf(dstBuf, MM_FLAG_WRITE, 0);
520
 
 
521
 
    /* dst always YUV, not YVU for I420 */
522
 
    dst_y = mmBufVirtual(dstBuf);
523
 
    dst_u = dst_y + dstPitch * h;
524
 
    dst_v = dst_u + dstPitch2 * (h >> 1);
525
 
 
526
 
    /* copy Y data */
527
 
    for (i = 0; i < h; i++) {
528
 
        memcpy(dst_y, src_y, w);
529
 
        src_y += srcPitch;
530
 
        dst_y += dstPitch;
531
 
    }
532
 
 
533
 
    /* copy UV data */
534
 
    srcPitch >>= 1;
535
 
    w >>= 1;
536
 
    h >>= 1;
537
 
 
538
 
    for (i = 0; i < h; i++) {
539
 
        memcpy(dst_u, src_u, w);
540
 
        src_u += srcPitch;
541
 
        dst_u += dstPitch2;
542
 
    }
543
 
 
544
 
    /* copy V data */
545
 
    for (i = 0; i < h; i++) {
546
 
        memcpy(dst_v, src_v, w);
547
 
        src_v += srcPitch;
548
 
        dst_v += dstPitch2;
549
 
    }
550
 
 
551
 
    dstBuf->man->unMapBuf(dstBuf);
552
 
}
553
 
 
554
 
static void
555
 
psbCopyPlanarNV12Data(ScrnInfoPtr pScrn, PsbPortPrivPtr pPriv,
556
 
                      unsigned char *buf,
557
 
                      int srcPitch, int dstPitch,
558
 
                      int top, int left, int h, int w)
559
 
{
560
 
    unsigned char *src_y, *src_uv, *dst_y, *dst_uv;
561
 
    int i;
562
 
    struct _MMBuffer *dstBuf = pPriv->videoBuf[pPriv->curBuf];
563
 
 
564
 
    src_y = buf + (top * srcPitch) + left;
565
 
    src_uv = buf + srcPitch * h + top * srcPitch + left;
566
 
 
567
 
    /*
568
 
     * Note. Map also syncs with previous usage.
569
 
     */
570
 
 
571
 
    dstBuf->man->mapBuf(dstBuf, MM_FLAG_WRITE, 0);
572
 
 
573
 
    dst_y = mmBufVirtual(dstBuf);
574
 
    dst_uv = dst_y + dstPitch * h;
575
 
 
576
 
    /* copy Y data */
577
 
    for (i = 0; i < h; i++) {
578
 
        memcpy(dst_y, src_y, w);
579
 
        src_y += srcPitch;
580
 
        dst_y += dstPitch;
581
 
    }
582
 
 
583
 
    /* copy UV data */
584
 
    h >>= 1;
585
 
    for (i = 0; i < h; i++) {
586
 
        memcpy(dst_uv, src_uv, w);
587
 
        src_uv += srcPitch;
588
 
        dst_uv += dstPitch;
589
 
    }
590
 
 
591
 
    dstBuf->man->unMapBuf(dstBuf);
592
 
}
593
 
 
594
 
int
595
 
psbDisplayVideo(ScrnInfoPtr pScrn, PsbPortPrivPtr pPriv, int id,
596
 
                RegionPtr dstRegion,
597
 
                short width, short height, int video_pitch,
598
 
                int x1, int y1, int x2, int y2,
599
 
                short src_w, short src_h, short drw_w, short drw_h,
600
 
                PixmapPtr pPixmap)
601
 
{
602
 
    struct _MMBuffer *dstBuf;
603
 
    BoxPtr pbox;
604
 
    int nbox;
605
 
    int dxo, dyo;
606
 
    unsigned long pre_add;
607
 
    Bool hdtv;
608
 
    XpsbSurface dst;
609
 
    XpsbSurfacePtr src[3];
610
 
    float tc0[6], tc1[6], tc2[6];
611
 
    int num_texture = 0;
612
 
    float *conversion_data = NULL;    
613
 
 
614
 
    hdtv = ((src_w >= PSB_HDTV_LIMIT_X) && (src_h >= PSB_HDTV_LIMIT_Y));
615
 
 
616
 
    src[0] = &pPriv->srf[0][pPriv->curBuf];
617
 
    src[0]->w = src_w;
618
 
    src[0]->h = src_h;
619
 
    src[0]->stride = video_pitch;
620
 
    src[0]->minFilter = Xpsb_nearest;
621
 
    src[0]->magFilter = Xpsb_linear;
622
 
    src[0]->uMode = Xpsb_clamp;
623
 
    src[0]->vMode = Xpsb_clamp;
624
 
    src[0]->texCoordIndex = 0;
625
 
 
626
 
    /* Use "isYUVPacked" to indicate:
627
 
     *   0: this surface is not for Xvideo
628
 
     *   1: is YUV data, and it is the first planar
629
 
     *   2: is YUV data, and it is the second planar
630
 
     *   3: is YUV data, and it is the third planar
631
 
     */
632
 
    src[0]->isYUVPacked = 1;
633
 
 
634
 
    /* pass id, ignore "packed" or "planar" */
635
 
    src[0]->packedYUVId = id;
636
 
 
637
 
    switch (id) {
638
 
    case FOURCC_UYVY:
639
 
    case FOURCC_YUY2:
640
 
        num_texture = 1;
641
 
        psbSetupConversionData(pPriv, hdtv);
642
 
        conversion_data = &pPriv->conversionData[0];
643
 
        break;
644
 
    case FOURCC_NV12:
645
 
        num_texture = 2;
646
 
 
647
 
        src[1] = &pPriv->srf[1][pPriv->curBuf];
648
 
        memcpy(src[1], src[0], sizeof(XpsbSurface));
649
 
        src[1]->h /= 2;
650
 
        src[1]->w /= 2;                /* width will be used as stride in Xpsb */
651
 
        src[1]->stride = ALIGN_TO(src[1]->w, 32);
652
 
        src[1]->texCoordIndex = 1;
653
 
        src[1]->offset = src[0]->offset + video_pitch * src_h;
654
 
        src[1]->isYUVPacked = 2;
655
 
 
656
 
        conversion_data = (float *)(&pPriv->sgx_coeffs[0]);
657
 
        break;
658
 
    case FOURCC_YV12:
659
 
    case FOURCC_I420:
660
 
        num_texture = 3;
661
 
 
662
 
        src[1] = &pPriv->srf[1][pPriv->curBuf];
663
 
        memcpy(src[1], src[0], sizeof(XpsbSurface));
664
 
        src[1]->w /= 2;
665
 
        src[1]->h /= 2;
666
 
        src[1]->stride = ALIGN_TO(src[1]->w, 32);
667
 
        src[1]->texCoordIndex = 1;
668
 
        src[1]->offset = src[0]->offset + video_pitch * src_h;
669
 
        src[1]->isYUVPacked = 2;
670
 
 
671
 
        src[2] = &pPriv->srf[2][pPriv->curBuf];
672
 
        memcpy(src[2], src[1], sizeof(XpsbSurface));
673
 
        src[2]->texCoordIndex = 2;
674
 
        src[2]->offset = src[1]->offset + src[1]->stride * (src_h / 2);
675
 
        src[2]->isYUVPacked = 3;
676
 
 
677
 
        conversion_data = (float *)(&pPriv->sgx_coeffs[0]);
678
 
        break;
679
 
    default:
680
 
        break;
681
 
    }
682
 
 
683
 
    /* Set up the offset for translating from the given region (in screen
684
 
     * coordinates) to the backing pixmap.
685
 
     */
686
 
 
687
 
    while (!psbExaGetSuperOffset(pPixmap, &pre_add, &dstBuf))
688
 
        exaMoveInPixmap(pPixmap);
689
 
 
690
 
    dst.buffer = mmKernelBuf(dstBuf);
691
 
    dst.offset = pre_add;
692
 
    dst.stride = pPixmap->devKind;
693
 
 
694
 
    switch (pPixmap->drawable.depth) {
695
 
    case 15:
696
 
        dst.pictFormat = PICT_x1r5g5b5;
697
 
        break;
698
 
    case 16:
699
 
        dst.pictFormat = PICT_r5g6b5;
700
 
        break;
701
 
    case 24:
702
 
    case 32:
703
 
        dst.pictFormat = PICT_x8r8g8b8;
704
 
        break;
705
 
    default:
706
 
        return FALSE;
707
 
    }
708
 
 
709
 
    REGION_TRANSLATE(pScrn->pScreen, dstRegion, -pPixmap->screen_x,
710
 
                     -pPixmap->screen_y);
711
 
 
712
 
    dxo = dstRegion->extents.x1;
713
 
    dyo = dstRegion->extents.y1;
714
 
 
715
 
    pbox = REGION_RECTS(dstRegion);
716
 
    nbox = REGION_NUM_RECTS(dstRegion);
717
 
 
718
 
#ifdef PSB_DETEAR
719
 
    /* we don't support multiple box render detearing with temp buffer
720
 
       very well, have to fall back to original rendering */
721
 
    int fallback = (nbox>1);
722
 
#endif  /* PSB_DETEAR */
723
 
 
724
 
    while (nbox--) {
725
 
        int box_x1 = pbox->x1;
726
 
        int box_y1 = pbox->y1;
727
 
        int box_x2 = pbox->x2;
728
 
        int box_y2 = pbox->y2;
729
 
 
730
 
        tc0[0] = tc0[2] = tc0[4] = (double)(box_x1 - dxo) / (double)drw_w;      /* u0 */
731
 
        tc0[1] = tc0[3] = tc0[5] = (double)(box_y1 - dyo) / (double)drw_h;      /* v0 */
732
 
 
733
 
        tc1[0] = tc1[2] = tc1[4] = (double)(box_x2 - dxo) / (double)drw_w;      /* u1 */
734
 
        tc1[1] = tc1[3] = tc1[5] = tc0[1];      /* v0 */
735
 
 
736
 
        tc2[0] = tc2[2] = tc2[4] = tc0[0];      /* u0 */
737
 
        tc2[1] = tc2[3] = tc2[5] = (double)(box_y2 - dyo) / (double)drw_h;      /* v1 */
738
 
 
739
 
        dst.w = box_x2 - box_x1;
740
 
        dst.h = box_y2 - box_y1;
741
 
        dst.x = box_x1;
742
 
        dst.y = box_y1;
743
 
 
744
 
        pbox++;
745
 
 
746
 
#ifdef PSB_DETEAR
747
 
        PsbPtr pPsb = psbPTR(pScrn);
748
 
 
749
 
        if (pPsb->vsync && !fallback) {
750
 
                psbBlitYUVDetear(pScrn,
751
 
                                 &dst,
752
 
                                 &src[0],
753
 
                                 num_texture,
754
 
                                 TRUE,
755
 
                                 src[0]->packedYUVId,
756
 
                                 tc0, tc1, tc2, 
757
 
                                 num_texture, 
758
 
                                 conversion_data);
759
 
        } else
760
 
#endif  /* PSB_DETEAR */
761
 
                {
762
 
                        psbBlitYUV(pScrn,
763
 
                                   &dst,
764
 
                                   &src[0],
765
 
                                   num_texture,
766
 
                                   TRUE,
767
 
                                   src[0]->packedYUVId,
768
 
                                   tc0, tc1, tc2, 
769
 
                                   num_texture, 
770
 
                                   conversion_data);                    
771
 
                } 
772
 
    }
773
 
 
774
 
    DamageDamageRegion(&pPixmap->drawable, dstRegion);
775
 
    return TRUE;
776
 
}
777
 
 
778
 
/*
779
 
 * The source rectangle of the video is defined by (src_x, src_y, src_w, src_h).
780
 
 * The dest rectangle of the video is defined by (drw_x, drw_y, drw_w, drw_h).
781
 
 * id is a fourcc code for the format of the video.
782
 
 * buf is the pointer to the source data in system memory.
783
 
 * width and height are the w/h of the source data.
784
 
 * If "sync" is TRUE, then we must be finished with *buf at the point of return
785
 
 * (which we always are).
786
 
 * clipBoxes is the clipping region in screen space.
787
 
 * data is a pointer to our port private.
788
 
 * pDraw is a Drawable, which might not be the screen in the case of
789
 
 * compositing.  It's a new argument to the function in the 1.1 server.
790
 
 */
791
 
 
792
 
static int
793
 
psbPutImage(ScrnInfoPtr pScrn,
794
 
            short src_x, short src_y,
795
 
            short drw_x, short drw_y,
796
 
            short src_w, short src_h,
797
 
            short drw_w, short drw_h,
798
 
            int id, unsigned char *buf,
799
 
            short width, short height,
800
 
            Bool sync, RegionPtr clipBoxes, pointer data, DrawablePtr pDraw)
801
 
{
802
 
    PsbPortPrivPtr pPriv = (PsbPortPrivPtr) data;
803
 
    ScreenPtr pScreen = screenInfo.screens[pScrn->scrnIndex];
804
 
    PixmapPtr pPixmap;
805
 
    INT32 x1, x2, y1, y2;
806
 
    int srcPitch, dstPitch, dstPitch2 = 0, destId;
807
 
    int size = 0;
808
 
    BoxRec dstBox;
809
 
    int ret;
810
 
 
811
 
    /* Clip */
812
 
    x1 = src_x;
813
 
    x2 = src_x + src_w;
814
 
    y1 = src_y;
815
 
    y2 = src_y + src_h;
816
 
 
817
 
    dstBox.x1 = drw_x;
818
 
    dstBox.x2 = drw_x + drw_w;
819
 
    dstBox.y1 = drw_y;
820
 
    dstBox.y2 = drw_y + drw_h;
821
 
 
822
 
    if (!xf86XVClipVideoHelper(&dstBox, &x1, &x2, &y1, &y2, clipBoxes,
823
 
                               width, height))
824
 
        return Success;
825
 
 
826
 
    destId = id;
827
 
 
828
 
    switch (id) {
829
 
    case FOURCC_UYVY:
830
 
    case FOURCC_YUY2:
831
 
        srcPitch = width << 1;
832
 
        /*
833
 
         * Hardware limitation.
834
 
         */
835
 
        dstPitch = ALIGN_TO(width, 32) << 1;
836
 
        size = dstPitch * height;
837
 
        break;
838
 
    case FOURCC_YV12:
839
 
    case FOURCC_I420:
840
 
        srcPitch = width;
841
 
        dstPitch = ALIGN_TO(width, 32);
842
 
        dstPitch2 = ALIGN_TO(width >> 1, 32);
843
 
        size = dstPitch * height + /* UV */ 2 * dstPitch2 * (height >> 1);
844
 
        break;
845
 
    case FOURCC_NV12:
846
 
        srcPitch = width;
847
 
        dstPitch = ALIGN_TO(width, 32);
848
 
        dstPitch2 = ALIGN_TO(width >> 1, 32);
849
 
        size = dstPitch * height + /* UV */ 2 * dstPitch2 * (height >> 1);
850
 
        break;
851
 
    default:
852
 
        xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
853
 
                   "Unsupported Fourcc 0x%x\n", id);
854
 
        return BadValue;
855
 
    }
856
 
 
857
 
    ret = psbCheckVideoBuffer(pPriv, size);
858
 
 
859
 
    if (ret)
860
 
        return ret;
861
 
 
862
 
    switch (id) {
863
 
    case FOURCC_UYVY:
864
 
    case FOURCC_YUY2:
865
 
        psbCopyPackedData(pScrn, pPriv, buf, srcPitch, dstPitch,
866
 
                          src_y, src_x, height, width);
867
 
        break;
868
 
 
869
 
    case FOURCC_YV12:
870
 
    case FOURCC_I420:
871
 
        psbCopyPlanarYUVData(pScrn, pPriv, buf, srcPitch, dstPitch, dstPitch2,
872
 
                             src_y, src_x, height, width, id);
873
 
        break;
874
 
    case FOURCC_NV12:
875
 
        psbCopyPlanarNV12Data(pScrn, pPriv, buf, srcPitch, dstPitch,
876
 
                              src_y, src_x, height, width);
877
 
        break;
878
 
    default:
879
 
        break;
880
 
    }
881
 
 
882
 
    if (pDraw->type == DRAWABLE_WINDOW) {
883
 
        pPixmap = (*pScreen->GetWindowPixmap) ((WindowPtr) pDraw);
884
 
    } else {
885
 
        pPixmap = (PixmapPtr) pDraw;
886
 
    }
887
 
 
888
 
 
889
 
    psbDisplayVideo(pScrn, pPriv, destId, clipBoxes, width, height,
890
 
                    dstPitch, x1, y1, x2, y2,
891
 
                    src_w, src_h, drw_w, drw_h, pPixmap);
892
 
 
893
 
    pPriv->curBuf = (pPriv->curBuf + 1) & 1;
894
 
    return Success;
895
 
}
896
 
 
897
 
static void
898
 
psbStopVideo(ScrnInfoPtr pScrn, pointer data, Bool shutdown)
899
 
{
900
 
    PsbPortPrivPtr pPriv = (PsbPortPrivPtr) data;
901
 
 
902
 
    REGION_EMPTY(pScrn->pScreen, &pPriv->clip);
903
 
}
904
 
 
905
 
static int
906
 
psbQueryImageAttributes(ScrnInfoPtr pScrn,
907
 
                        int id,
908
 
                        unsigned short *w, unsigned short *h,
909
 
                        int *pitches, int *offsets)
910
 
{
911
 
    int size;
912
 
 
913
 
    if (*w > PSB_IMAGE_MAX_WIDTH)
914
 
        *w = PSB_IMAGE_MAX_WIDTH;
915
 
    if (*h > PSB_IMAGE_MAX_HEIGHT)
916
 
        *h = PSB_IMAGE_MAX_HEIGHT;
917
 
 
918
 
    *w = (*w + 1) & ~1;
919
 
    if (offsets)
920
 
        offsets[0] = 0;
921
 
 
922
 
    switch (id) {
923
 
    case FOURCC_UYVY:
924
 
    case FOURCC_YUY2:
925
 
        size = *w << 1;
926
 
        if (pitches)
927
 
            pitches[0] = size;
928
 
        size *= *h;
929
 
        break;
930
 
    case FOURCC_YV12:
931
 
    case FOURCC_I420:
932
 
        if (pitches) {
933
 
            pitches[0] = (*w);
934
 
            pitches[1] = (*w) >> 1;
935
 
            pitches[2] = (*w) >> 1;
936
 
        }
937
 
        if (offsets) {
938
 
            offsets[0] = 0;
939
 
            offsets[1] = (*w) * (*h);
940
 
            offsets[2] = offsets[1] + ((*w) >> 1) * ((*h) >> 1);
941
 
        }
942
 
 
943
 
        size =
944
 
            (*w) * (*h) + ((*w) >> 1) * ((*h) >> 1) +
945
 
            ((*w) >> 1) * ((*h) >> 1);
946
 
        break;
947
 
    case FOURCC_NV12:
948
 
        if (pitches) {
949
 
            pitches[0] = (*w);
950
 
            pitches[1] = (*w);
951
 
        }
952
 
        if (offsets) {
953
 
            offsets[0] = 0;
954
 
            offsets[1] = (*w) * (*h);
955
 
        }
956
 
 
957
 
        size = (*w) * (*h) + 2 * ((*w) >> 1) * ((*h) >> 1);
958
 
        break;
959
 
    default:                           /* YUY2 UYVY */
960
 
        size = *w << 1;
961
 
        if (pitches)
962
 
            pitches[0] = size;
963
 
        size *= *h;
964
 
        break;
965
 
    }
966
 
 
967
 
    return size;
968
 
}
969
 
 
970
 
void
971
 
psbFreeAdaptor(ScrnInfoPtr pScrn, XF86VideoAdaptorPtr adapt)
972
 
{
973
 
    PsbPortPrivPtr pPriv;
974
 
    DevUnion *pDev;
975
 
    int i;
976
 
 
977
 
    if (!adapt)
978
 
        return;
979
 
 
980
 
    pDev = (DevUnion *) adapt->pPortPrivates;
981
 
    if (pDev) {
982
 
        for (i = 0; i < adapt->nPorts; ++i) {
983
 
            pPriv = (PsbPortPrivPtr) pDev[i].ptr;
984
 
            psbPortPrivDestroy(pScrn, pPriv);
985
 
        }
986
 
        xfree(pDev);
987
 
    }
988
 
    if (adapt->pAttributes)
989
 
        xfree(adapt->pAttributes);
990
 
    xfree(adapt);
991
 
}
992
 
 
993
 
static XF86VideoAdaptorPtr
994
 
psbSetupImageVideo(ScreenPtr pScreen)
995
 
{
996
 
    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
997
 
    XF86VideoAdaptorPtr adapt;
998
 
    PsbPortPrivPtr pPriv;
999
 
    XF86AttributePtr att;
1000
 
    int i;
1001
 
 
1002
 
    if (!(adapt = xcalloc(1, sizeof(XF86VideoAdaptorRec))))
1003
 
        return NULL;
1004
 
 
1005
 
    adapt->type = XvWindowMask | XvInputMask | XvImageMask;
1006
 
    adapt->flags = VIDEO_OVERLAID_IMAGES /*| VIDEO_CLIP_TO_VIEWPORT */ ;
1007
 
    adapt->name = "Intel(R) Textured Overlay";
1008
 
    adapt->nEncodings = 1;
1009
 
    adapt->pEncodings = DummyEncoding;
1010
 
    adapt->nFormats = PSB_NUM_FORMATS;
1011
 
    adapt->pFormats = Formats;
1012
 
 
1013
 
    adapt->nAttributes = PSB_NUM_ATTRIBUTES;
1014
 
    adapt->pAttributes =
1015
 
        xcalloc(adapt->nAttributes, sizeof(XF86AttributeRec));
1016
 
    /* Now copy the attributes */
1017
 
    att = adapt->pAttributes;
1018
 
    if (!att)
1019
 
        goto out_err;
1020
 
 
1021
 
    memcpy((char *)att, (char *)Attributes,
1022
 
           sizeof(XF86AttributeRec) * PSB_NUM_ATTRIBUTES);
1023
 
 
1024
 
    adapt->nImages = PSB_NUM_IMAGES;
1025
 
    adapt->pImages = Images;
1026
 
    adapt->PutVideo = NULL;
1027
 
    adapt->PutStill = NULL;
1028
 
    adapt->GetVideo = NULL;
1029
 
    adapt->GetStill = NULL;
1030
 
    adapt->StopVideo = psbStopVideo;
1031
 
    adapt->SetPortAttribute = psbSetPortAttribute;
1032
 
    adapt->GetPortAttribute = psbGetPortAttribute;
1033
 
    adapt->QueryBestSize = psbQueryBestSize;
1034
 
    adapt->PutImage = psbPutImage;
1035
 
    adapt->ReputImage = NULL;
1036
 
    adapt->QueryImageAttributes = psbQueryImageAttributes;
1037
 
 
1038
 
    adapt->pPortPrivates = (DevUnion *)
1039
 
        xcalloc(PSB_ADAPT0_NUM_PORTS, sizeof(DevUnion));
1040
 
 
1041
 
    if (!adapt->pPortPrivates)
1042
 
        goto out_err;
1043
 
 
1044
 
    adapt->nPorts = 0;
1045
 
    for (i = 0; i < PSB_ADAPT0_NUM_PORTS; ++i) {
1046
 
        pPriv = psbPortPrivCreate(pScrn);
1047
 
        if (!pPriv)
1048
 
            goto out_err;
1049
 
 
1050
 
        adapt->pPortPrivates[i].ptr = (pointer) pPriv;
1051
 
        adapt->nPorts++;
1052
 
    }
1053
 
 
1054
 
    return adapt;
1055
 
 
1056
 
  out_err:
1057
 
 
1058
 
    if (adapt->nPorts == 0)
1059
 
        psbFreeAdaptor(pScrn, adapt);
1060
 
    else
1061
 
        return adapt;
1062
 
 
1063
 
    return NULL;
1064
 
}
1065
 
 
1066
 
XF86VideoAdaptorPtr
1067
 
psbInitVideo(ScreenPtr pScreen)
1068
 
{
1069
 
    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
1070
 
    XF86VideoAdaptorPtr *adaptors, *newAdaptors = NULL;
1071
 
    XF86VideoAdaptorPtr adaptor = NULL;
1072
 
    int num_adaptors;
1073
 
 
1074
 
    xvBrightness = MAKE_ATOM("XV_BRIGHTNESS");
1075
 
    xvContrast = MAKE_ATOM("XV_CONTRAST");
1076
 
    xvSaturation = MAKE_ATOM("XV_SATURATION");
1077
 
    xvHue = MAKE_ATOM("XV_HUE");
1078
 
 
1079
 
    num_adaptors = xf86XVListGenericAdaptors(pScrn, &adaptors);
1080
 
 
1081
 
    newAdaptors = xalloc((num_adaptors + 1) * sizeof(XF86VideoAdaptorPtr *));
1082
 
    if (newAdaptors == NULL)
1083
 
        return NULL;
1084
 
 
1085
 
    memcpy(newAdaptors, adaptors, num_adaptors * sizeof(XF86VideoAdaptorPtr));
1086
 
    adaptors = newAdaptors;
1087
 
 
1088
 
    adaptor = psbSetupImageVideo(pScreen);
1089
 
    if (adaptor != NULL) {
1090
 
        adaptors[num_adaptors++] = adaptor;
1091
 
        xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Set up textured video\n");
1092
 
    } else {
1093
 
        xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1094
 
                   "Failed to set up textured video\n");
1095
 
    }
1096
 
 
1097
 
    if (num_adaptors)
1098
 
        xf86XVScreenInit(pScreen, adaptors, num_adaptors);
1099
 
 
1100
 
    xfree(adaptors);
1101
 
    return adaptor;
1102
 
}
1103
 
 
1104
 
/*
1105
 
 * Calculates the coefficintes of a YUV->RGB conversion based on
1106
 
 * the provided basis coefficients (already had HUe and Satu applied).
1107
 
 * Performs brightness and contrast adjustment as well as the required
1108
 
 * offsets to put into correct range for hardware conversion.
1109
 
 */
1110
 
static void
1111
 
psb_create_coeffs(double yOff, double uOff, double vOff, double rgbOff,
1112
 
                  double yScale, double uScale, double vScale,
1113
 
                  double brightness, double contrast,
1114
 
                  double *pYCoeff, double *pUCoeff, double *pVCoeff,
1115
 
                  double *pConstant)
1116
 
{
1117
 
    *pYCoeff = yScale * contrast;
1118
 
    *pUCoeff = uScale * contrast;
1119
 
    *pVCoeff = vScale * contrast;
1120
 
 
1121
 
    *pConstant = (((yOff + brightness) * yScale)
1122
 
                  + (uOff * uScale) + (vOff * vScale)) * contrast + rgbOff;
1123
 
}
1124
 
 
1125
 
/**
1126
 
 * Checks if the specified coefficients are within the ranges required
1127
 
 * and returns true if they are else false.
1128
 
 */
1129
 
static int
1130
 
psb_check_coeffs(double Ycoeff, double Ucoeff, double Vcoeff,
1131
 
                 double ConstantTerm, signed char byShift)
1132
 
{
1133
 
    if ((Ycoeff > 127) || (Ycoeff < -128)) {
1134
 
        return 1;
1135
 
    }
1136
 
    if ((Ucoeff > 127) || (Ucoeff < -128)) {
1137
 
        return 1;
1138
 
    }
1139
 
    if ((Vcoeff > 127) || (Vcoeff < -128)) {
1140
 
        return 1;
1141
 
    }
1142
 
    if ((ConstantTerm > 32766) || (ConstantTerm < -32767)) {
1143
 
        return 1;
1144
 
    }
1145
 
    return 0;
1146
 
}
1147
 
 
1148
 
/*
1149
 
 * Converts a floating point function in the form
1150
 
 *    a*yCoeff + b*uCoeff + c * vCoeff + d
1151
 
 *  Into a fixed point function of the forrm
1152
 
 *   (a*pY + b * pU + c * pV + constant)>>pShift
1153
 
 */
1154
 
static void
1155
 
psb_convert_coeffs(double Ycoeff, double Ucoeff, double Vcoeff,
1156
 
                   double ConstantTerm, signed char *pY, signed char *pU,
1157
 
                   signed char *pV, signed short *constant,
1158
 
                   unsigned char *pShift)
1159
 
{
1160
 
    *pShift = 0;
1161
 
 
1162
 
    Ycoeff *= 256;
1163
 
    Ucoeff *= 256;
1164
 
    Vcoeff *= 256;
1165
 
    ConstantTerm *= 256;
1166
 
    *pShift = 8;
1167
 
 
1168
 
    /*
1169
 
     * What we want to do is scale up the coefficients so that they just fit into their
1170
 
     * allowed bits, so we are using signed maths giving us coefficients can be between +-128.
1171
 
     * The constant can be between =- 32767.
1172
 
     * The divide can be between 0 and 256 (on powers of two only).
1173
 
     * A mathematical approach would be nice, but for simplicity do an iterative compare
1174
 
     * and divide. Until something fits.
1175
 
     */
1176
 
    while (psb_check_coeffs(Ycoeff, Ucoeff, Vcoeff, ConstantTerm, *pShift)) {
1177
 
        Ycoeff /= 2;
1178
 
        Ucoeff /= 2;
1179
 
        Vcoeff /= 2;
1180
 
        ConstantTerm /= 2;
1181
 
        (*pShift)--;
1182
 
    }
1183
 
    *pY = (signed char)(Ycoeff + 0.5);
1184
 
    *pU = (signed char)(Ucoeff + 0.5);
1185
 
    *pV = (signed char)(Vcoeff + 0.5);
1186
 
    *constant = (signed short)(ConstantTerm + 0.5);
1187
 
}
1188
 
 
1189
 
/**
1190
 
 * Performs a hue and saturation adjustment on the CSC coefficients supplied.
1191
 
 */
1192
 
static void
1193
 
psb_transform_sathuecoeffs(psb_transform_coeffs * dest,
1194
 
                           const psb_transform_coeffs * const source,
1195
 
                           double fHue, double fSat)
1196
 
{
1197
 
    double fHueSatSin, fHueSatCos;
1198
 
 
1199
 
    fHueSatSin = sin(fHue) * fSat;
1200
 
    fHueSatCos = cos(fHue) * fSat;
1201
 
 
1202
 
    dest->rY = source->rY;
1203
 
    dest->rCb = source->rCb * fHueSatCos - source->rCr * fHueSatSin;
1204
 
    dest->rCr = source->rCr * fHueSatCos + source->rCb * fHueSatSin;
1205
 
 
1206
 
    dest->gY = source->gY;
1207
 
    dest->gCb = source->gCb * fHueSatCos - source->gCr * fHueSatSin;
1208
 
    dest->gCr = source->gCr * fHueSatCos + source->gCb * fHueSatSin;
1209
 
 
1210
 
    dest->bY = source->bY;
1211
 
    dest->bCb = source->bCb * fHueSatCos - source->bCr * fHueSatSin;
1212
 
    dest->bCr = source->bCr * fHueSatCos + source->bCb * fHueSatSin;
1213
 
}
1214
 
 
1215
 
/*
1216
 
 * Scales the tranfer matrix depending on the input/output
1217
 
 * nominal ranges.
1218
 
 */
1219
 
static void
1220
 
psb_scale_transfermatrix(psb_transform_coeffs * transfer_matrix,
1221
 
                         double YColumScale, double CbColumScale,
1222
 
                         double CrColumnScale)
1223
 
{
1224
 
    /* First column of the transfer matrix */
1225
 
    transfer_matrix->rY *= YColumScale;
1226
 
    transfer_matrix->gY *= YColumScale;
1227
 
    transfer_matrix->bY *= YColumScale;
1228
 
 
1229
 
    /* Second column of the transfer matrix */
1230
 
    transfer_matrix->rCb *= CbColumScale;
1231
 
    transfer_matrix->gCb *= CbColumScale;
1232
 
    transfer_matrix->bCb *= CbColumScale;
1233
 
 
1234
 
    /* Third column of the transfer matrix */
1235
 
    transfer_matrix->rCr *= CrColumnScale;
1236
 
    transfer_matrix->gCr *= CrColumnScale;
1237
 
    transfer_matrix->bCr *= CrColumnScale;
1238
 
}
1239
 
 
1240
 
/*
1241
 
 * ITU-R BT.601, BT.709 and SMPTE 240M transfer matrices from DXVA 2.0
1242
 
 * Video Color Field definitions Design Spec(Version 0.03).
1243
 
 * [R', G', B'] values are in the range [0, 1], Y' is in the range [0,1]
1244
 
 * and [Pb, Pr] components are in the range [-0.5, 0.5].
1245
 
 */
1246
 
static psb_transform_coeffs s601 = {
1247
 
    1, -0.000001, 1.402,
1248
 
    1, -0.344136, -0.714136,
1249
 
    1, 1.772, 0
1250
 
};
1251
 
 
1252
 
static psb_transform_coeffs s709 = {
1253
 
    1, 0, 1.5748,
1254
 
    1, -0.187324, -0.468124,
1255
 
    1, 1.8556, 0
1256
 
};
1257
 
 
1258
 
static psb_transform_coeffs s240M = {
1259
 
    1, -0.000657, 1.575848,
1260
 
    1, -0.226418, -0.476529,
1261
 
    1, 1.825958, 0.000378
1262
 
};
1263
 
 
1264
 
/*
1265
 
  These are the corresponding matrices when using NominalRange_16_235
1266
 
  for the input surface and NominalRange_0_255 for the outpur surface:
1267
 
 
1268
 
  static const psb_transform_coeffs s601 = {
1269
 
  1.164,                0,              1.596,
1270
 
  1.164,                -0.391,         -0.813,
1271
 
  1.164,                2.018,          0
1272
 
  };
1273
 
 
1274
 
  static const psb_transform_coeffs s709 = {
1275
 
  1.164,                0,              1.793,
1276
 
  1.164,                -0.213,         -0.534,
1277
 
  1.164,                2.115,          0
1278
 
  };
1279
 
 
1280
 
  static const psb_transform_coeffs s240M = {
1281
 
  1.164,                -0.0007,        1.793,
1282
 
  1.164,                -0.257,         -0.542,
1283
 
  1.164,                2.078,          0.0004
1284
 
  };
1285
 
*/
1286
 
 
1287
 
/**
1288
 
 * Select which transfer matrix to use in the YUV->RGB conversion.
1289
 
 */
1290
 
static void
1291
 
psb_select_transfermatrix(PsbPortPrivRec * pPriv,
1292
 
                          psb_transform_coeffs * transfer_matrix,
1293
 
                          double *Y_offset, double *CbCr_offset,
1294
 
                          double *RGB_offset)
1295
 
{
1296
 
    double RGB_scale, Y_scale, Cb_scale, Cr_scale;
1297
 
 
1298
 
    /*
1299
 
     * Depending on the nominal ranges of the input YUV surface and the output RGB
1300
 
     * surface, it might be needed to perform some scaling on the transfer matrix.
1301
 
     * The excursion in the YUV values implies that the first column of the matrix
1302
 
     * must be divided by the Y excursion, and the second and third columns be
1303
 
     * divided by the U and V excursions respectively. The offset does not affect
1304
 
     * the values of the matrix.
1305
 
     * The excursion in the RGB values implies that all the values in the transfer
1306
 
     * matrix must be multiplied by the value of the excursion.
1307
 
     * 
1308
 
     * Example: Conversion of the SMPTE 240M transfer matrix.
1309
 
     * 
1310
 
     * Conversion from [Y', Pb, Pr] to [R', G', B'] in the range of [0, 1]. Y' is in
1311
 
     * the range of [0, 1]      and Pb and Pr in the range of [-0.5, 0.5].
1312
 
     * 
1313
 
     * R'               1       -0.000657       1.575848                Y'
1314
 
     * G'       =       1       -0.226418       -0.476529       *       Pb
1315
 
     * B'               1       1.825958        0.000378                Pr
1316
 
     * 
1317
 
     * Conversion from [Y', Cb, Cr] to {R', G', B'] in the range of [0, 1]. Y' has an
1318
 
     * excursion of 219 and an offset of +16, and CB and CR have excursions of +/-112
1319
 
     * and offset of +128, for a range of 16 through 240 inclusive.
1320
 
     * 
1321
 
     * R'               1/219   -0.000657/224   1.575848/224            Y'       16
1322
 
     * G'       =       1/219   -0.226418/224   -0.476529/224   *       Cb - 128
1323
 
     * B'               1/219   1.825958/224    0.000378/224            Cr   128
1324
 
     * 
1325
 
     * Conversion from [Y', Cb, Cr] to R'G'B' in the range [0, 255].
1326
 
     * 
1327
 
     * R'                         1/219 -0.000657/224 1.575848/224                      Y'       16
1328
 
     * G'       =       255 * 1/219     -0.226418/224 -0.476529/224             *       Cb - 128
1329
 
     * B'                         1/219 1.825958/224  0.000378/224                      Cr   128
1330
 
     */
1331
 
 
1332
 
    switch (pPriv->src_nominalrange) {
1333
 
    case PSB_NominalRange_0_255:
1334
 
        /* Y has a range of [0, 255], U and V have a range of [0, 255] */
1335
 
        {
1336
 
            double tmp = 0.0;
1337
 
 
1338
 
            (void)tmp;
1339
 
        }                              /* workaroud for float point bug? */
1340
 
        Y_scale = 255.0;
1341
 
        *Y_offset = 0;
1342
 
        Cb_scale = Cr_scale = 255;
1343
 
        *CbCr_offset = 128;
1344
 
        break;
1345
 
    case PSB_NominalRange_16_235:
1346
 
    case PSB_NominalRange_Unknown:
1347
 
        /* Y has a range of [16, 235] and Cb, Cr have a range of [16, 240] */
1348
 
        Y_scale = 219;
1349
 
        *Y_offset = 16;
1350
 
        Cb_scale = Cr_scale = 224;
1351
 
        *CbCr_offset = 128;
1352
 
        break;
1353
 
    case PSB_NominalRange_48_208:
1354
 
        /* Y has a range of [48, 208] and Cb, Cr have a range of [48, 208] */
1355
 
        Y_scale = 160;
1356
 
        *Y_offset = 48;
1357
 
        Cb_scale = Cr_scale = 160;
1358
 
        *CbCr_offset = 128;
1359
 
        break;
1360
 
 
1361
 
    default:
1362
 
        /* Y has a range of [0, 1], U and V have a range of [-0.5, 0.5] */
1363
 
        Y_scale = 1;
1364
 
        *Y_offset = 0;
1365
 
        Cb_scale = Cr_scale = 1;
1366
 
        *CbCr_offset = 0;
1367
 
        break;
1368
 
    }
1369
 
 
1370
 
    /*
1371
 
     * 8-bit computer RGB,      also known as sRGB or "full-scale" RGB, and studio
1372
 
     * video RGB, or "RGB with  head-room and toe-room." These are defined as follows:
1373
 
     * 
1374
 
     * - Computer RGB uses 8 bits for each sample of red, green, and blue. Black
1375
 
     * is represented by R = G = B = 0, and white is represented by R = G = B = 255.
1376
 
     * - Studio video RGB uses some number of bits N for each sample of red, green,
1377
 
     * and blue, where N is 8 or more. Studio video RGB uses a different scaling
1378
 
     * factor than computer RGB, and it has an offset. Black is represented by
1379
 
     * R = G = B = 16*2^(N-8), and white is represented by R = G = B = 235*2^(N-8).
1380
 
     * However, actual values may fall outside this range.
1381
 
     */
1382
 
    switch (pPriv->dst_nominalrange) {
1383
 
    case PSB_NominalRange_0_255:      // for sRGB
1384
 
    case PSB_NominalRange_Unknown:
1385
 
        /* R, G and B have a range of [0, 255] */
1386
 
        RGB_scale = 255;
1387
 
        *RGB_offset = 0;
1388
 
        break;
1389
 
    case PSB_NominalRange_16_235:     // for stRGB
1390
 
        /* R, G and B have a range of [16, 235] */
1391
 
        RGB_scale = 219;
1392
 
        *RGB_offset = 16;
1393
 
        break;
1394
 
    case PSB_NominalRange_48_208:     // for Bt.1361 RGB
1395
 
        /* R, G and B have a range of [48, 208] */
1396
 
        RGB_scale = 160;
1397
 
        *RGB_offset = 48;
1398
 
        break;
1399
 
    default:
1400
 
        /* R, G and B have a range of [0, 1] */
1401
 
        RGB_scale = 1;
1402
 
        *RGB_offset = 0;
1403
 
        break;
1404
 
    }
1405
 
 
1406
 
    switch (pPriv->video_transfermatrix) {
1407
 
    case PSB_VideoTransferMatrix_BT709:
1408
 
        memcpy(transfer_matrix, &s709, sizeof(psb_transform_coeffs));
1409
 
        break;
1410
 
    case PSB_VideoTransferMatrix_BT601:
1411
 
        memcpy(transfer_matrix, &s601, sizeof(psb_transform_coeffs));
1412
 
        break;
1413
 
    case PSB_VideoTransferMatrix_SMPTE240M:
1414
 
        memcpy(transfer_matrix, &s240M, sizeof(psb_transform_coeffs));
1415
 
        break;
1416
 
    case PSB_VideoTransferMatrix_Unknown:
1417
 
        /*
1418
 
         * Specifies that the video transfer matrix is not specified.
1419
 
         * The default value is BT601 for standard definition (SD) video and BT709
1420
 
         * for high definition (HD) video.
1421
 
         */
1422
 
        if (1 /*pPriv->sVideoDesc.SampleWidth < 720 */ ) {      /* TODO, width selection */
1423
 
            memcpy(transfer_matrix, &s601, sizeof(psb_transform_coeffs));
1424
 
        } else {
1425
 
            memcpy(transfer_matrix, &s709, sizeof(psb_transform_coeffs));
1426
 
        }
1427
 
        break;
1428
 
    default:
1429
 
        break;
1430
 
    }
1431
 
 
1432
 
    if (Y_scale != 1 || Cb_scale != 1 || Cr_scale != 1) {
1433
 
        /* Each column of the transfer matrix has to
1434
 
         * be scaled by the excursion of each component
1435
 
         */
1436
 
        psb_scale_transfermatrix(transfer_matrix, 1 / Y_scale, 1 / Cb_scale,
1437
 
                                 1 / Cr_scale);
1438
 
    }
1439
 
    if (RGB_scale != 1) {
1440
 
        /* All the values in the transfer matrix have to be multiplied
1441
 
         * by the excursion of the RGB components
1442
 
         */
1443
 
        psb_scale_transfermatrix(transfer_matrix, RGB_scale, RGB_scale,
1444
 
                                 RGB_scale);
1445
 
    }
1446
 
}
1447
 
 
1448
 
/**
1449
 
 * Updates the CSC coefficients if required.
1450
 
 */
1451
 
static void
1452
 
psb_setup_coeffs(PsbPortPrivRec * pPriv)
1453
 
{
1454
 
    double yCoeff, uCoeff, vCoeff, Constant;
1455
 
    double fContrast;
1456
 
    double Y_offset, CbCr_offset, RGB_offset;
1457
 
    int bright_off = 0;
1458
 
    psb_transform_coeffs coeffs, transfer_matrix;
1459
 
 
1460
 
    /* Offsets in the input and output ranges are
1461
 
     * included in the constant of the transform equation
1462
 
     */
1463
 
    psb_select_transfermatrix(pPriv, &transfer_matrix,
1464
 
                              &Y_offset, &CbCr_offset, &RGB_offset);
1465
 
 
1466
 
    /*
1467
 
     * It is at this point we should adjust the parameters for the procamp:
1468
 
     * - Brightness is handled as an offset of the Y parameter.
1469
 
     * - Contrast is an adjustment of the Y scale.
1470
 
     * - Saturation is a scaling of the U anc V parameters.
1471
 
     * - Hue is a rotation of the U and V parameters.
1472
 
     */
1473
 
 
1474
 
    bright_off = pPriv->brightness.Value;
1475
 
    fContrast = (pPriv->contrast.Value + 100) / 100.0;
1476
 
 
1477
 
    /* Apply hue and saturation correction to transfer matrix */
1478
 
    psb_transform_sathuecoeffs(&coeffs,
1479
 
                               &transfer_matrix,
1480
 
                               pPriv->hue.Value * Degree,
1481
 
                               pPriv->saturation.Value / 100.0);
1482
 
 
1483
 
    /* Create coefficients to get component R
1484
 
     * (including brightness and contrast correction)
1485
 
     */
1486
 
    psb_create_coeffs(-1 * Y_offset, -1 * CbCr_offset, -1 * CbCr_offset,
1487
 
                      RGB_offset, coeffs.rY, coeffs.rCb, coeffs.rCr,
1488
 
                      bright_off, fContrast, &yCoeff, &uCoeff, &vCoeff,
1489
 
                      &Constant);
1490
 
 
1491
 
    /* Convert transform operation from floating point to fixed point */
1492
 
    psb_convert_coeffs(yCoeff, uCoeff, vCoeff, Constant,        /* input coefficients */
1493
 
                       &pPriv->coeffs.rY, &pPriv->coeffs.rU,
1494
 
                       &pPriv->coeffs.rV, &pPriv->coeffs.rConst,
1495
 
                       &pPriv->coeffs.rShift);
1496
 
 
1497
 
    /* Create coefficients to get component G
1498
 
     * (including brightness and contrast correction)
1499
 
     */
1500
 
    psb_create_coeffs(-1 * Y_offset, -1 * CbCr_offset, -1 * CbCr_offset,
1501
 
                      RGB_offset, coeffs.gY, coeffs.gCb, coeffs.gCr,
1502
 
                      bright_off, fContrast, &yCoeff, &uCoeff, &vCoeff,
1503
 
                      &Constant);
1504
 
 
1505
 
    /* Convert transform operation from floating point to fixed point */
1506
 
    psb_convert_coeffs(yCoeff, uCoeff, vCoeff, Constant,
1507
 
                       /* tranfer matrix coefficients for G */
1508
 
                       &pPriv->coeffs.gY, &pPriv->coeffs.gU,
1509
 
                       &pPriv->coeffs.gV, &pPriv->coeffs.gConst,
1510
 
                       &pPriv->coeffs.gShift);
1511
 
 
1512
 
    /* Create coefficients to get component B
1513
 
     * (including brightness and contrast correction)
1514
 
     */
1515
 
    psb_create_coeffs(-1 * Y_offset, -1 * CbCr_offset, -1 * CbCr_offset,
1516
 
                      RGB_offset, coeffs.bY, coeffs.bCb, coeffs.bCr,
1517
 
                      bright_off, fContrast, &yCoeff, &uCoeff, &vCoeff,
1518
 
                      &Constant);
1519
 
 
1520
 
    /* Convert transform operation from floating point to fixed point */
1521
 
    psb_convert_coeffs(yCoeff, uCoeff, vCoeff, Constant,
1522
 
                       /* tranfer matrix coefficients for B */
1523
 
                       &pPriv->coeffs.bY, &pPriv->coeffs.bU,
1524
 
                       &pPriv->coeffs.bV, &pPriv->coeffs.bConst,
1525
 
                       &pPriv->coeffs.bShift);
1526
 
}
1527
 
 
1528
 
static void
1529
 
psb_pack_coeffs(PsbPortPrivRec * pPriv, unsigned long *sgx_coeffs)
1530
 
{
1531
 
    /* We use taps 0,3 and 6 which I means an filter offset of either 4,5,6
1532
 
     * yyyyuvuv
1533
 
     * x00x00x0
1534
 
     */
1535
 
    sgx_coeffs[0] =
1536
 
        ((pPriv->coeffs.rY & 0xff) << 24) | ((pPriv->coeffs.rU & 0xff) << 0);
1537
 
    sgx_coeffs[1] = (pPriv->coeffs.rV & 0xff) << 8;
1538
 
    sgx_coeffs[2] =
1539
 
        ((pPriv->coeffs.rConst & 0xffff) << 4) | (pPriv->coeffs.rShift & 0xf);
1540
 
 
1541
 
    sgx_coeffs[3] =
1542
 
        ((pPriv->coeffs.gY & 0xff) << 24) | ((pPriv->coeffs.gU & 0xff) << 0);
1543
 
    sgx_coeffs[4] = (pPriv->coeffs.gV & 0xff) << 8;
1544
 
    sgx_coeffs[5] =
1545
 
        ((pPriv->coeffs.gConst & 0xffff) << 4) | (pPriv->coeffs.gShift & 0xf);
1546
 
 
1547
 
    sgx_coeffs[6] =
1548
 
        ((pPriv->coeffs.bY & 0xff) << 24) | ((pPriv->coeffs.bU & 0xff) << 0);
1549
 
    sgx_coeffs[7] = (pPriv->coeffs.bV & 0xff) << 8;
1550
 
    sgx_coeffs[8] =
1551
 
        ((pPriv->coeffs.bConst & 0xffff) << 4) | (pPriv->coeffs.bShift & 0xf);
1552
 
}