1
/**************************************************************************
3
* Copyright (c) Intel Corp. 2007.
6
* Intel funded Tungsten Graphics (http://www.tungstengraphics.com) to
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:
17
* The above copyright notice and this permission notice (including the
18
* next paragraph) shall be included in all copies or substantial portions
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.
29
**************************************************************************/
38
#include "xf86_OSproc.h"
39
#include "xf86Resources.h"
43
#include <X11/extensions/Xv.h>
45
#include "psb_driver.h"
47
#include "regionstr.h"
48
#include "../libmm/mm_interface.h"
52
#define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE)
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
60
* YUV to RBG conversion.
63
static float yOffset = 16.f;
64
static float yRange = 219.f;
65
static float videoGamma = 2.8f;
68
* The ITU-R BT.601 conversion matrix for SDTV.
71
static float bt_601[] = {
73
1.0, -0.3455, -0.7169,
78
* The ITU-R BT.709 conversion matrix for HDTV.
81
static float bt_709[] = {
87
#ifndef exaMoveInPixmap
88
void exaMoveInPixmap(PixmapPtr pPixmap);
91
static XF86VideoEncodingRec DummyEncoding[1] = {
95
PSB_IMAGE_MAX_WIDTH, PSB_IMAGE_MAX_HEIGHT,
100
#define PSB_NUM_FORMATS 3
101
static XF86VideoFormatRec Formats[PSB_NUM_FORMATS] = {
102
{15, TrueColor}, {16, TrueColor}, {24, TrueColor}
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"},
113
#define PSB_NUM_ATTRIBUTES sizeof(Attributes)/sizeof(XF86AttributeRec)
118
#define FOURCC_NV12 (('2' << 24) + ('1' << 16) + ('V' << 8) + 'N')
120
#define XVIMAGE_NV12 \
126
0x00,0x00,0x00,0x10,0x80,0x00,0x00,0xAA,0x00,0x38,0x9B,0x71}, \
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}, \
139
static XF86ImageRec Images[] = {
147
#define PSB_NUM_IMAGES sizeof(Images)/sizeof(XF86ImageRec)
150
* Currently we have 4 ports on the adaptor.
151
* We might want to make this a configurable option.
154
#define PSB_ADAPT0_NUM_PORTS 4
156
/*define some structure used by the ported code */
158
static Atom xvBrightness;
159
static Atom xvContrast;
160
static Atom xvSaturation;
163
#define HUE_DEFAULT_VALUE 0
167
#define BRIGHTNESS_DEFAULT_VALUE 0
168
#define BRIGHTNESS_MIN -50
169
#define BRIGHTNESS_MAX 50
171
#define CONTRAST_DEFAULT_VALUE 0
172
#define CONTRAST_MIN -100
173
#define CONTRAST_MAX 100
175
#define SATURATION_DEFAULT_VALUE 100
176
#define SATURATION_MIN 0
177
#define SATURATION_MAX 200
179
#define CLAMP_ATTR(a,max,min) (a>max?max:(a<min?min:a))
181
typedef enum _psb_nominalrange
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
193
typedef enum _psb_videotransfermatrix
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;
202
typedef struct _psb_fixed32
208
unsigned short Fraction;
215
#define Degree (2*PI / 360.0)
218
typedef struct _psb_transform_coeffs_
223
} psb_transform_coeffs;
225
typedef struct _psb_coeffs_
236
unsigned char rShift;
237
unsigned char gShift;
238
unsigned char bShift;
242
} psb_coeffs_s, *psb_coeffs_p;
244
typedef struct _PsbPortPrivRec
247
struct _MMManager *man;
248
struct _MMBuffer *videoBuf[2];
251
float conversionData[11];
253
XpsbSurface srf[3][2];
255
unsigned int bufPitch;
257
/* information of display attribute */
258
psb_fixed32 brightness;
259
psb_fixed32 contrast;
260
psb_fixed32 saturation;
263
/* gets set by any changes to Hue, Brightness,saturation, hue or csc matrix. */
265
unsigned long sgx_coeffs[9];
267
unsigned int src_nominalrange;
268
unsigned int dst_nominalrange;
269
unsigned int video_transfermatrix;
270
} PsbPortPrivRec, *PsbPortPrivPtr;
273
psbSetupConversionData(PsbPortPrivPtr pPriv, Bool hdtv)
275
if (pPriv->hdtv != hdtv) {
279
memcpy(pPriv->conversionData, bt_709, sizeof(bt_709));
281
memcpy(pPriv->conversionData, bt_601, sizeof(bt_601));
283
for (i = 0; i < 9; ++i) {
284
pPriv->conversionData[i] /= yRange;
288
* Adjust for brightness, contrast, hue and saturation here.
291
pPriv->conversionData[9] = -yOffset;
295
pPriv->conversionData[10] = videoGamma;
300
static void psb_setup_coeffs(PsbPortPrivPtr);
301
static void psb_pack_coeffs(PsbPortPrivPtr, unsigned long *);
304
psbSetupPlanarConversionData(PsbPortPrivPtr pPriv, Bool hdtv)
306
psb_setup_coeffs(pPriv);
307
psb_pack_coeffs(pPriv, &pPriv->sgx_coeffs[0]);
310
static void psbStopVideo(ScrnInfoPtr pScrn, pointer data, Bool shutdown);
312
static PsbPortPrivPtr
313
psbPortPrivCreate(ScrnInfoPtr pScrn)
315
PsbDevicePtr pDevice = psbDevicePTR(psbPTR(pScrn));
316
PsbPortPrivPtr pPriv;
318
pPriv = xcalloc(1, sizeof(*pPriv));
321
pPriv->man = pDevice->man;
322
REGION_NULL(pScreen, &pPriv->clip);
324
psbSetupConversionData(pPriv, FALSE);
326
/* coeffs defaut value */
327
pPriv->brightness.Value = BRIGHTNESS_DEFAULT_VALUE;
328
pPriv->brightness.Fraction = 0;
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;
337
psbSetupPlanarConversionData(pPriv, FALSE);
343
psbPortPrivDestroy(ScrnInfoPtr pScrn, PsbPortPrivPtr pPriv)
348
psbStopVideo(pScrn, pPriv, TRUE);
350
if (pPriv->videoBuf[0]) {
351
mmBufDestroy(pPriv->videoBuf[0]);
352
mmBufDestroy(pPriv->videoBuf[1]);
358
psbCheckVideoBuffer(PsbPortPrivPtr pPriv, unsigned int size)
360
size = ALIGN_TO(size, 4096);
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;
368
if (!pPriv->videoBuf[0]) {
369
pPriv->videoBuf[0] = pPriv->man->createBuf(pPriv->man,
372
DRM_PSB_FLAG_MEM_MMU |
374
DRM_BO_HINT_DONT_FENCE);
375
if (!pPriv->videoBuf[0])
378
pPriv->videoBuf[1] = pPriv->man->createBuf(pPriv->man,
381
DRM_PSB_FLAG_MEM_MMU |
383
DRM_BO_HINT_DONT_FENCE);
384
if (!pPriv->videoBuf[1]) {
385
mmBufDestroy(pPriv->videoBuf[0]);
386
pPriv->videoBuf[0] = NULL;
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;
400
psbSetPortAttribute(ScrnInfoPtr pScrn,
401
Atom attribute, INT32 value, pointer data)
403
PsbPortPrivPtr pPriv = (PsbPortPrivPtr) data;
404
int update_coeffs = 0;
406
if (attribute == xvBrightness) {
407
pPriv->brightness.Value =
408
CLAMP_ATTR(value, BRIGHTNESS_MAX, BRIGHTNESS_MIN);
410
} else if (attribute == xvContrast) {
411
pPriv->contrast.Value = CLAMP_ATTR(value, CONTRAST_MAX, CONTRAST_MIN);
413
} else if (attribute == xvHue) {
414
pPriv->hue.Value = CLAMP_ATTR(value, HUE_MAX, HUE_MIN);
416
} else if (attribute == xvSaturation) {
417
pPriv->saturation.Value =
418
CLAMP_ATTR(value, SATURATION_MAX, SATURATION_MIN);
424
psb_setup_coeffs(pPriv);
425
psb_pack_coeffs(pPriv, &pPriv->sgx_coeffs[0]);
433
psbGetPortAttribute(ScrnInfoPtr pScrn,
434
Atom attribute, INT32 * value, pointer data)
436
PsbPortPrivPtr pPriv = (PsbPortPrivPtr) data;
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;
453
psbQueryBestSize(ScrnInfoPtr pScrn,
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)
459
if (vid_w > (drw_w << 1))
461
if (vid_h > (drw_h << 1))
469
psbCopyPackedData(ScrnInfoPtr pScrn, PsbPortPrivPtr pPriv,
471
int srcPitch, int dstPitch, int top, int left, int h, int w)
473
unsigned char *src, *dst;
475
struct _MMBuffer *dstBuf = pPriv->videoBuf[pPriv->curBuf];
477
src = buf + (top * srcPitch) + (left << 1);
480
* Note. Map also syncs with previous usage.
483
dstBuf->man->mapBuf(dstBuf, MM_FLAG_WRITE, 0);
484
dst = mmBufVirtual(dstBuf);
486
for (i = 0; i < h; i++) {
491
dstBuf->man->unMapBuf(dstBuf);
495
psbCopyPlanarYUVData(ScrnInfoPtr pScrn, PsbPortPrivPtr pPriv,
497
int srcPitch, int dstPitch, int dstPitch2,
498
int top, int left, int h, int w, int id)
500
unsigned char *src_y, *src_u, *src_v, *dst_y, *dst_u, *dst_v;
502
struct _MMBuffer *dstBuf = pPriv->videoBuf[pPriv->curBuf];
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);
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);
516
* Note. Map also syncs with previous usage.
519
dstBuf->man->mapBuf(dstBuf, MM_FLAG_WRITE, 0);
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);
527
for (i = 0; i < h; i++) {
528
memcpy(dst_y, src_y, w);
538
for (i = 0; i < h; i++) {
539
memcpy(dst_u, src_u, w);
545
for (i = 0; i < h; i++) {
546
memcpy(dst_v, src_v, w);
551
dstBuf->man->unMapBuf(dstBuf);
555
psbCopyPlanarNV12Data(ScrnInfoPtr pScrn, PsbPortPrivPtr pPriv,
557
int srcPitch, int dstPitch,
558
int top, int left, int h, int w)
560
unsigned char *src_y, *src_uv, *dst_y, *dst_uv;
562
struct _MMBuffer *dstBuf = pPriv->videoBuf[pPriv->curBuf];
564
src_y = buf + (top * srcPitch) + left;
565
src_uv = buf + srcPitch * h + top * srcPitch + left;
568
* Note. Map also syncs with previous usage.
571
dstBuf->man->mapBuf(dstBuf, MM_FLAG_WRITE, 0);
573
dst_y = mmBufVirtual(dstBuf);
574
dst_uv = dst_y + dstPitch * h;
577
for (i = 0; i < h; i++) {
578
memcpy(dst_y, src_y, w);
585
for (i = 0; i < h; i++) {
586
memcpy(dst_uv, src_uv, w);
591
dstBuf->man->unMapBuf(dstBuf);
595
psbDisplayVideo(ScrnInfoPtr pScrn, PsbPortPrivPtr pPriv, int id,
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,
602
struct _MMBuffer *dstBuf;
606
unsigned long pre_add;
609
XpsbSurfacePtr src[3];
610
float tc0[6], tc1[6], tc2[6];
612
float *conversion_data = NULL;
614
hdtv = ((src_w >= PSB_HDTV_LIMIT_X) && (src_h >= PSB_HDTV_LIMIT_Y));
616
src[0] = &pPriv->srf[0][pPriv->curBuf];
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;
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
632
src[0]->isYUVPacked = 1;
634
/* pass id, ignore "packed" or "planar" */
635
src[0]->packedYUVId = id;
641
psbSetupConversionData(pPriv, hdtv);
642
conversion_data = &pPriv->conversionData[0];
647
src[1] = &pPriv->srf[1][pPriv->curBuf];
648
memcpy(src[1], src[0], sizeof(XpsbSurface));
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;
656
conversion_data = (float *)(&pPriv->sgx_coeffs[0]);
662
src[1] = &pPriv->srf[1][pPriv->curBuf];
663
memcpy(src[1], src[0], sizeof(XpsbSurface));
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;
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;
677
conversion_data = (float *)(&pPriv->sgx_coeffs[0]);
683
/* Set up the offset for translating from the given region (in screen
684
* coordinates) to the backing pixmap.
687
while (!psbExaGetSuperOffset(pPixmap, &pre_add, &dstBuf))
688
exaMoveInPixmap(pPixmap);
690
dst.buffer = mmKernelBuf(dstBuf);
691
dst.offset = pre_add;
692
dst.stride = pPixmap->devKind;
694
switch (pPixmap->drawable.depth) {
696
dst.pictFormat = PICT_x1r5g5b5;
699
dst.pictFormat = PICT_r5g6b5;
703
dst.pictFormat = PICT_x8r8g8b8;
709
REGION_TRANSLATE(pScrn->pScreen, dstRegion, -pPixmap->screen_x,
712
dxo = dstRegion->extents.x1;
713
dyo = dstRegion->extents.y1;
715
pbox = REGION_RECTS(dstRegion);
716
nbox = REGION_NUM_RECTS(dstRegion);
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 */
725
int box_x1 = pbox->x1;
726
int box_y1 = pbox->y1;
727
int box_x2 = pbox->x2;
728
int box_y2 = pbox->y2;
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 */
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 */
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 */
739
dst.w = box_x2 - box_x1;
740
dst.h = box_y2 - box_y1;
747
PsbPtr pPsb = psbPTR(pScrn);
749
if (pPsb->vsync && !fallback) {
750
psbBlitYUVDetear(pScrn,
760
#endif /* PSB_DETEAR */
774
DamageDamageRegion(&pPixmap->drawable, dstRegion);
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.
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)
802
PsbPortPrivPtr pPriv = (PsbPortPrivPtr) data;
803
ScreenPtr pScreen = screenInfo.screens[pScrn->scrnIndex];
805
INT32 x1, x2, y1, y2;
806
int srcPitch, dstPitch, dstPitch2 = 0, destId;
818
dstBox.x2 = drw_x + drw_w;
820
dstBox.y2 = drw_y + drw_h;
822
if (!xf86XVClipVideoHelper(&dstBox, &x1, &x2, &y1, &y2, clipBoxes,
831
srcPitch = width << 1;
833
* Hardware limitation.
835
dstPitch = ALIGN_TO(width, 32) << 1;
836
size = dstPitch * height;
841
dstPitch = ALIGN_TO(width, 32);
842
dstPitch2 = ALIGN_TO(width >> 1, 32);
843
size = dstPitch * height + /* UV */ 2 * dstPitch2 * (height >> 1);
847
dstPitch = ALIGN_TO(width, 32);
848
dstPitch2 = ALIGN_TO(width >> 1, 32);
849
size = dstPitch * height + /* UV */ 2 * dstPitch2 * (height >> 1);
852
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
853
"Unsupported Fourcc 0x%x\n", id);
857
ret = psbCheckVideoBuffer(pPriv, size);
865
psbCopyPackedData(pScrn, pPriv, buf, srcPitch, dstPitch,
866
src_y, src_x, height, width);
871
psbCopyPlanarYUVData(pScrn, pPriv, buf, srcPitch, dstPitch, dstPitch2,
872
src_y, src_x, height, width, id);
875
psbCopyPlanarNV12Data(pScrn, pPriv, buf, srcPitch, dstPitch,
876
src_y, src_x, height, width);
882
if (pDraw->type == DRAWABLE_WINDOW) {
883
pPixmap = (*pScreen->GetWindowPixmap) ((WindowPtr) pDraw);
885
pPixmap = (PixmapPtr) pDraw;
889
psbDisplayVideo(pScrn, pPriv, destId, clipBoxes, width, height,
890
dstPitch, x1, y1, x2, y2,
891
src_w, src_h, drw_w, drw_h, pPixmap);
893
pPriv->curBuf = (pPriv->curBuf + 1) & 1;
898
psbStopVideo(ScrnInfoPtr pScrn, pointer data, Bool shutdown)
900
PsbPortPrivPtr pPriv = (PsbPortPrivPtr) data;
902
REGION_EMPTY(pScrn->pScreen, &pPriv->clip);
906
psbQueryImageAttributes(ScrnInfoPtr pScrn,
908
unsigned short *w, unsigned short *h,
909
int *pitches, int *offsets)
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;
934
pitches[1] = (*w) >> 1;
935
pitches[2] = (*w) >> 1;
939
offsets[1] = (*w) * (*h);
940
offsets[2] = offsets[1] + ((*w) >> 1) * ((*h) >> 1);
944
(*w) * (*h) + ((*w) >> 1) * ((*h) >> 1) +
945
((*w) >> 1) * ((*h) >> 1);
954
offsets[1] = (*w) * (*h);
957
size = (*w) * (*h) + 2 * ((*w) >> 1) * ((*h) >> 1);
959
default: /* YUY2 UYVY */
971
psbFreeAdaptor(ScrnInfoPtr pScrn, XF86VideoAdaptorPtr adapt)
973
PsbPortPrivPtr pPriv;
980
pDev = (DevUnion *) adapt->pPortPrivates;
982
for (i = 0; i < adapt->nPorts; ++i) {
983
pPriv = (PsbPortPrivPtr) pDev[i].ptr;
984
psbPortPrivDestroy(pScrn, pPriv);
988
if (adapt->pAttributes)
989
xfree(adapt->pAttributes);
993
static XF86VideoAdaptorPtr
994
psbSetupImageVideo(ScreenPtr pScreen)
996
ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
997
XF86VideoAdaptorPtr adapt;
998
PsbPortPrivPtr pPriv;
999
XF86AttributePtr att;
1002
if (!(adapt = xcalloc(1, sizeof(XF86VideoAdaptorRec))))
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;
1013
adapt->nAttributes = PSB_NUM_ATTRIBUTES;
1014
adapt->pAttributes =
1015
xcalloc(adapt->nAttributes, sizeof(XF86AttributeRec));
1016
/* Now copy the attributes */
1017
att = adapt->pAttributes;
1021
memcpy((char *)att, (char *)Attributes,
1022
sizeof(XF86AttributeRec) * PSB_NUM_ATTRIBUTES);
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;
1038
adapt->pPortPrivates = (DevUnion *)
1039
xcalloc(PSB_ADAPT0_NUM_PORTS, sizeof(DevUnion));
1041
if (!adapt->pPortPrivates)
1045
for (i = 0; i < PSB_ADAPT0_NUM_PORTS; ++i) {
1046
pPriv = psbPortPrivCreate(pScrn);
1050
adapt->pPortPrivates[i].ptr = (pointer) pPriv;
1058
if (adapt->nPorts == 0)
1059
psbFreeAdaptor(pScrn, adapt);
1067
psbInitVideo(ScreenPtr pScreen)
1069
ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
1070
XF86VideoAdaptorPtr *adaptors, *newAdaptors = NULL;
1071
XF86VideoAdaptorPtr adaptor = NULL;
1074
xvBrightness = MAKE_ATOM("XV_BRIGHTNESS");
1075
xvContrast = MAKE_ATOM("XV_CONTRAST");
1076
xvSaturation = MAKE_ATOM("XV_SATURATION");
1077
xvHue = MAKE_ATOM("XV_HUE");
1079
num_adaptors = xf86XVListGenericAdaptors(pScrn, &adaptors);
1081
newAdaptors = xalloc((num_adaptors + 1) * sizeof(XF86VideoAdaptorPtr *));
1082
if (newAdaptors == NULL)
1085
memcpy(newAdaptors, adaptors, num_adaptors * sizeof(XF86VideoAdaptorPtr));
1086
adaptors = newAdaptors;
1088
adaptor = psbSetupImageVideo(pScreen);
1089
if (adaptor != NULL) {
1090
adaptors[num_adaptors++] = adaptor;
1091
xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Set up textured video\n");
1093
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1094
"Failed to set up textured video\n");
1098
xf86XVScreenInit(pScreen, adaptors, num_adaptors);
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.
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,
1117
*pYCoeff = yScale * contrast;
1118
*pUCoeff = uScale * contrast;
1119
*pVCoeff = vScale * contrast;
1121
*pConstant = (((yOff + brightness) * yScale)
1122
+ (uOff * uScale) + (vOff * vScale)) * contrast + rgbOff;
1126
* Checks if the specified coefficients are within the ranges required
1127
* and returns true if they are else false.
1130
psb_check_coeffs(double Ycoeff, double Ucoeff, double Vcoeff,
1131
double ConstantTerm, signed char byShift)
1133
if ((Ycoeff > 127) || (Ycoeff < -128)) {
1136
if ((Ucoeff > 127) || (Ucoeff < -128)) {
1139
if ((Vcoeff > 127) || (Vcoeff < -128)) {
1142
if ((ConstantTerm > 32766) || (ConstantTerm < -32767)) {
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
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)
1165
ConstantTerm *= 256;
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.
1176
while (psb_check_coeffs(Ycoeff, Ucoeff, Vcoeff, ConstantTerm, *pShift)) {
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);
1190
* Performs a hue and saturation adjustment on the CSC coefficients supplied.
1193
psb_transform_sathuecoeffs(psb_transform_coeffs * dest,
1194
const psb_transform_coeffs * const source,
1195
double fHue, double fSat)
1197
double fHueSatSin, fHueSatCos;
1199
fHueSatSin = sin(fHue) * fSat;
1200
fHueSatCos = cos(fHue) * fSat;
1202
dest->rY = source->rY;
1203
dest->rCb = source->rCb * fHueSatCos - source->rCr * fHueSatSin;
1204
dest->rCr = source->rCr * fHueSatCos + source->rCb * fHueSatSin;
1206
dest->gY = source->gY;
1207
dest->gCb = source->gCb * fHueSatCos - source->gCr * fHueSatSin;
1208
dest->gCr = source->gCr * fHueSatCos + source->gCb * fHueSatSin;
1210
dest->bY = source->bY;
1211
dest->bCb = source->bCb * fHueSatCos - source->bCr * fHueSatSin;
1212
dest->bCr = source->bCr * fHueSatCos + source->bCb * fHueSatSin;
1216
* Scales the tranfer matrix depending on the input/output
1220
psb_scale_transfermatrix(psb_transform_coeffs * transfer_matrix,
1221
double YColumScale, double CbColumScale,
1222
double CrColumnScale)
1224
/* First column of the transfer matrix */
1225
transfer_matrix->rY *= YColumScale;
1226
transfer_matrix->gY *= YColumScale;
1227
transfer_matrix->bY *= YColumScale;
1229
/* Second column of the transfer matrix */
1230
transfer_matrix->rCb *= CbColumScale;
1231
transfer_matrix->gCb *= CbColumScale;
1232
transfer_matrix->bCb *= CbColumScale;
1234
/* Third column of the transfer matrix */
1235
transfer_matrix->rCr *= CrColumnScale;
1236
transfer_matrix->gCr *= CrColumnScale;
1237
transfer_matrix->bCr *= CrColumnScale;
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].
1246
static psb_transform_coeffs s601 = {
1247
1, -0.000001, 1.402,
1248
1, -0.344136, -0.714136,
1252
static psb_transform_coeffs s709 = {
1254
1, -0.187324, -0.468124,
1258
static psb_transform_coeffs s240M = {
1259
1, -0.000657, 1.575848,
1260
1, -0.226418, -0.476529,
1261
1, 1.825958, 0.000378
1265
These are the corresponding matrices when using NominalRange_16_235
1266
for the input surface and NominalRange_0_255 for the outpur surface:
1268
static const psb_transform_coeffs s601 = {
1270
1.164, -0.391, -0.813,
1274
static const psb_transform_coeffs s709 = {
1276
1.164, -0.213, -0.534,
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
1288
* Select which transfer matrix to use in the YUV->RGB conversion.
1291
psb_select_transfermatrix(PsbPortPrivRec * pPriv,
1292
psb_transform_coeffs * transfer_matrix,
1293
double *Y_offset, double *CbCr_offset,
1296
double RGB_scale, Y_scale, Cb_scale, Cr_scale;
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.
1308
* Example: Conversion of the SMPTE 240M transfer matrix.
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].
1313
* R' 1 -0.000657 1.575848 Y'
1314
* G' = 1 -0.226418 -0.476529 * Pb
1315
* B' 1 1.825958 0.000378 Pr
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.
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
1325
* Conversion from [Y', Cb, Cr] to R'G'B' in the range [0, 255].
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
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] */
1339
} /* workaroud for float point bug? */
1342
Cb_scale = Cr_scale = 255;
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] */
1350
Cb_scale = Cr_scale = 224;
1353
case PSB_NominalRange_48_208:
1354
/* Y has a range of [48, 208] and Cb, Cr have a range of [48, 208] */
1357
Cb_scale = Cr_scale = 160;
1362
/* Y has a range of [0, 1], U and V have a range of [-0.5, 0.5] */
1365
Cb_scale = Cr_scale = 1;
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:
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.
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] */
1389
case PSB_NominalRange_16_235: // for stRGB
1390
/* R, G and B have a range of [16, 235] */
1394
case PSB_NominalRange_48_208: // for Bt.1361 RGB
1395
/* R, G and B have a range of [48, 208] */
1400
/* R, G and B have a range of [0, 1] */
1406
switch (pPriv->video_transfermatrix) {
1407
case PSB_VideoTransferMatrix_BT709:
1408
memcpy(transfer_matrix, &s709, sizeof(psb_transform_coeffs));
1410
case PSB_VideoTransferMatrix_BT601:
1411
memcpy(transfer_matrix, &s601, sizeof(psb_transform_coeffs));
1413
case PSB_VideoTransferMatrix_SMPTE240M:
1414
memcpy(transfer_matrix, &s240M, sizeof(psb_transform_coeffs));
1416
case PSB_VideoTransferMatrix_Unknown:
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.
1422
if (1 /*pPriv->sVideoDesc.SampleWidth < 720 */ ) { /* TODO, width selection */
1423
memcpy(transfer_matrix, &s601, sizeof(psb_transform_coeffs));
1425
memcpy(transfer_matrix, &s709, sizeof(psb_transform_coeffs));
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
1436
psb_scale_transfermatrix(transfer_matrix, 1 / Y_scale, 1 / Cb_scale,
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
1443
psb_scale_transfermatrix(transfer_matrix, RGB_scale, RGB_scale,
1449
* Updates the CSC coefficients if required.
1452
psb_setup_coeffs(PsbPortPrivRec * pPriv)
1454
double yCoeff, uCoeff, vCoeff, Constant;
1456
double Y_offset, CbCr_offset, RGB_offset;
1458
psb_transform_coeffs coeffs, transfer_matrix;
1460
/* Offsets in the input and output ranges are
1461
* included in the constant of the transform equation
1463
psb_select_transfermatrix(pPriv, &transfer_matrix,
1464
&Y_offset, &CbCr_offset, &RGB_offset);
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.
1474
bright_off = pPriv->brightness.Value;
1475
fContrast = (pPriv->contrast.Value + 100) / 100.0;
1477
/* Apply hue and saturation correction to transfer matrix */
1478
psb_transform_sathuecoeffs(&coeffs,
1480
pPriv->hue.Value * Degree,
1481
pPriv->saturation.Value / 100.0);
1483
/* Create coefficients to get component R
1484
* (including brightness and contrast correction)
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,
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);
1497
/* Create coefficients to get component G
1498
* (including brightness and contrast correction)
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,
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);
1512
/* Create coefficients to get component B
1513
* (including brightness and contrast correction)
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,
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);
1529
psb_pack_coeffs(PsbPortPrivRec * pPriv, unsigned long *sgx_coeffs)
1531
/* We use taps 0,3 and 6 which I means an filter offset of either 4,5,6
1536
((pPriv->coeffs.rY & 0xff) << 24) | ((pPriv->coeffs.rU & 0xff) << 0);
1537
sgx_coeffs[1] = (pPriv->coeffs.rV & 0xff) << 8;
1539
((pPriv->coeffs.rConst & 0xffff) << 4) | (pPriv->coeffs.rShift & 0xf);
1542
((pPriv->coeffs.gY & 0xff) << 24) | ((pPriv->coeffs.gU & 0xff) << 0);
1543
sgx_coeffs[4] = (pPriv->coeffs.gV & 0xff) << 8;
1545
((pPriv->coeffs.gConst & 0xffff) << 4) | (pPriv->coeffs.gShift & 0xf);
1548
((pPriv->coeffs.bY & 0xff) << 24) | ((pPriv->coeffs.bU & 0xff) << 0);
1549
sgx_coeffs[7] = (pPriv->coeffs.bV & 0xff) << 8;
1551
((pPriv->coeffs.bConst & 0xffff) << 4) | (pPriv->coeffs.bShift & 0xf);