1/*
2 * Copyright 2007 Arthur Huillet
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17 * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
18 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
19 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 * SOFTWARE.
21 */
22
23#ifdef HAVE_CONFIG_H
24#include "config.h"
25#endif
26
27#include "xorg-config.h"
28#include "xf86xv.h"
29#include <X11/extensions/Xv.h>
30#include "exa.h"
31#include "damage.h"
32#include "dixstruct.h"
33#include "fourcc.h"
34
35#include "nv_include.h"
36#include "nv_dma.h"
37
38extern Atom xvBrightness, xvContrast, xvColorKey, xvSaturation;
39extern Atom xvHue, xvAutopaintColorKey, xvSetDefaults, xvDoubleBuffer;
40extern Atom xvITURBT709, xvSyncToVBlank, xvOnCRTCNb;
41
42/**
43 * NV10PutOverlayImage
44 * program hardware to overlay image into front buffer
45 *
46 * @param pScrn screen
47 * @param offset card offset to the pixel data
48 * @param id format of image
49 * @param dstPitch pitch of the pixel data in VRAM
50 * @param dstBox destination box
51 * @param x1 first source point - x
52 * @param y1 first source point - y
53 * @param x2 second source point - x
54 * @param y2 second source point - y
55 * @param width width of the source image = x2 - x1
56 * @param height height
57 * @param src_w width of the image data in VRAM
58 * @param src_h height
59 * @param drw_w width of the image to draw to screen
60 * @param drw_h height
61 * @param clipBoxes ???
62 */
63void
64NV10PutOverlayImage(ScrnInfoPtr pScrn,
65		    struct nouveau_bo *src, int offset, int uvoffset, int id,
66		    int dstPitch, BoxPtr dstBox, int x1, int y1, int x2, int y2,
67		    short width, short height, short src_w, short src_h,
68		    short drw_w, short drw_h, RegionPtr clipBoxes)
69{
70	NVPtr         pNv    = NVPTR(pScrn);
71	NVPortPrivPtr pPriv  = GET_OVERLAY_PRIVATE(pNv);
72#ifdef NVOVL_SUPPORT
73	int           buffer = pPriv->currentBuffer;
74	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
75	xf86CrtcPtr crtc = xf86_config->crtc[pPriv->overlayCRTC];
76
77	if (crtc->mode.Flags & V_DBLSCAN) {
78		dstBox->y1 <<= 1;
79		dstBox->y2 <<= 1;
80		drw_h <<= 1;
81	}
82
83	/* paint the color key */
84        if(pPriv->autopaintColorKey && (pPriv->grabbedByV4L ||
85                !REGION_EQUAL(pScrn->pScreen, &pPriv->clip, clipBoxes))) {
86                /* we always paint V4L's color key */
87                if (!pPriv->grabbedByV4L)
88                        REGION_COPY(pScrn->pScreen, &pPriv->clip, clipBoxes);
89                {
90                xf86XVFillKeyHelper(pScrn->pScreen, pPriv->colorKey, clipBoxes);
91                }
92        }
93
94        //xf86DrvMsg(0, X_INFO, "SIZE_IN h %d w %d, POINT_IN x %d y %d, DS_DX %d DT_DY %d, POINT_OUT x %d y %d SIZE_OUT h %d w %d\n", height, width, x1 >>
95	//16,y1>>16, (src_w << 20) / drw_w, (src_h << 20) / drw_h,  (dstBox->x1),(dstBox->y1), (dstBox->y2 - dstBox->y1), (dstBox->x2 - dstBox->x1));
96
97        nvWriteVIDEO(pNv, NV_PVIDEO_BASE(buffer)     , 0);
98        nvWriteVIDEO(pNv, NV_PVIDEO_OFFSET_BUFF(buffer),
99			  src->offset + offset);
100        nvWriteVIDEO(pNv, NV_PVIDEO_SIZE_IN(buffer)  , (height << 16) | width);
101        nvWriteVIDEO(pNv, NV_PVIDEO_POINT_IN(buffer) ,
102                          ((y1 << 4) & 0xffff0000) | (x1 >> 12));
103        nvWriteVIDEO(pNv, NV_PVIDEO_DS_DX(buffer)    , (src_w << 20) / drw_w);
104        nvWriteVIDEO(pNv, NV_PVIDEO_DT_DY(buffer)    , (src_h << 20) / drw_h);
105        nvWriteVIDEO(pNv, NV_PVIDEO_POINT_OUT(buffer),
106                          (dstBox->y1 << 16) | dstBox->x1);
107        nvWriteVIDEO(pNv, NV_PVIDEO_SIZE_OUT(buffer) ,
108                          ((dstBox->y2 - dstBox->y1) << 16) |
109                           (dstBox->x2 - dstBox->x1));
110
111        dstPitch |= NV_PVIDEO_FORMAT_DISPLAY_COLOR_KEY;   /* use color key */
112        if(id != FOURCC_UYVY)
113                dstPitch |= NV_PVIDEO_FORMAT_COLOR_LE_CR8YB8CB8YA8;
114        if(pPriv->iturbt_709)
115                dstPitch |= NV_PVIDEO_FORMAT_MATRIX_ITURBT709;
116
117        if( id == FOURCC_YV12 || id == FOURCC_I420 )
118                dstPitch |= NV_PVIDEO_FORMAT_PLANAR;
119
120        /* Those are important only for planar formats (NV12) */
121        if (uvoffset) {
122                nvWriteVIDEO(pNv, NV_PVIDEO_UVPLANE_BASE(buffer), 0);
123                nvWriteVIDEO(pNv, NV_PVIDEO_UVPLANE_OFFSET_BUFF(buffer),
124				  src->offset + uvoffset);
125	}
126
127        nvWriteVIDEO(pNv, NV_PVIDEO_FORMAT(buffer), dstPitch);
128        nvWriteVIDEO(pNv, NV_PVIDEO_STOP, 0);
129        nvWriteVIDEO(pNv, NV_PVIDEO_BUFFER, buffer ? 0x10 :  0x1);
130#endif
131
132        pPriv->videoStatus = CLIENT_VIDEO_ON;
133}
134
135/**
136 * NV10SetOverlayPortAttribute
137 * sets the attribute "attribute" of port "data" to value "value"
138 * calls NVResetVideo(pScrn) to apply changes to hardware
139 *
140 * @param pScrenInfo
141 * @param attribute attribute to set
142 * @param value value to which attribute is to be set
143 * @param data port from which the attribute is to be set
144 *
145 * @return Success, if setting is successful
146 * BadValue/BadMatch, if value/attribute are invalid
147 * @see NVResetVideo(ScrnInfoPtr pScrn)
148 */
149int
150NV10SetOverlayPortAttribute(ScrnInfoPtr pScrn, Atom attribute,
151                          INT32 value, pointer data)
152{
153        NVPortPrivPtr pPriv = (NVPortPrivPtr)data;
154
155        if (attribute == xvBrightness) {
156                if ((value < -512) || (value > 512))
157                        return BadValue;
158                pPriv->brightness = value;
159        } else
160        if (attribute == xvDoubleBuffer) {
161                if ((value < 0) || (value > 1))
162                        return BadValue;
163                pPriv->doubleBuffer = value;
164        } else
165        if (attribute == xvContrast) {
166                if ((value < 0) || (value > 8191))
167                        return BadValue;
168                pPriv->contrast = value;
169        } else
170        if (attribute == xvHue) {
171                value %= 360;
172                if (value < 0)
173                        value += 360;
174                pPriv->hue = value;
175        } else
176        if (attribute == xvSaturation) {
177                if ((value < 0) || (value > 8191))
178                        return BadValue;
179                pPriv->saturation = value;
180        } else
181        if (attribute == xvColorKey) {
182                pPriv->colorKey = value;
183                REGION_EMPTY(pScrn->pScreen, &pPriv->clip);
184        } else
185        if (attribute == xvAutopaintColorKey) {
186                if ((value < 0) || (value > 1))
187                        return BadValue;
188                pPriv->autopaintColorKey = value;
189        } else
190        if (attribute == xvITURBT709) {
191                if ((value < 0) || (value > 1))
192                        return BadValue;
193                pPriv->iturbt_709 = value;
194        } else
195        if (attribute == xvSetDefaults) {
196                NVSetPortDefaults(pScrn, pPriv);
197        } else
198#ifdef NVOVL_SUPPORT
199        if ( attribute == xvOnCRTCNb) {
200		NVPtr pNv = NVPTR(pScrn);
201
202                if ((value < 0) || (value > 1))
203                        return BadValue;
204                pPriv->overlayCRTC = value;
205                NVWriteCRTC(pNv, value, NV_PCRTC_ENGINE_CTRL,
206			    NVReadCRTC(pNv, value, NV_PCRTC_ENGINE_CTRL) | NV_CRTC_FSEL_OVERLAY);
207                NVWriteCRTC(pNv, !value, NV_PCRTC_ENGINE_CTRL,
208			    NVReadCRTC(pNv, !value, NV_PCRTC_ENGINE_CTRL) & ~NV_CRTC_FSEL_OVERLAY);
209        } else
210#endif
211                return BadMatch;
212
213        NV10WriteOverlayParameters(pScrn);
214
215        return Success;
216}
217
218/**
219 * NV10GetOverlayPortAttribute
220 *
221 * @param pScrn unused
222 * @param attribute attribute to be read
223 * @param value value of attribute will be stored in this pointer
224 * @param data port from which attribute will be read
225 * @return Success, if queried attribute exists
226 */
227int
228NV10GetOverlayPortAttribute(ScrnInfoPtr pScrn, Atom attribute,
229                          INT32 *value, pointer data)
230{
231        NVPortPrivPtr pPriv = (NVPortPrivPtr)data;
232
233        if (attribute == xvBrightness)
234                *value = pPriv->brightness;
235        else if (attribute == xvDoubleBuffer)
236                *value = (pPriv->doubleBuffer) ? 1 : 0;
237        else if (attribute == xvContrast)
238                *value = pPriv->contrast;
239        else if (attribute == xvSaturation)
240                *value = pPriv->saturation;
241        else if (attribute == xvHue)
242                *value = pPriv->hue;
243        else if (attribute == xvColorKey)
244                *value = pPriv->colorKey;
245        else if (attribute == xvAutopaintColorKey)
246                *value = (pPriv->autopaintColorKey) ? 1 : 0;
247        else if (attribute == xvITURBT709)
248                *value = (pPriv->iturbt_709) ? 1 : 0;
249        else if (attribute == xvOnCRTCNb)
250                *value = (pPriv->overlayCRTC) ? 1 : 0;
251        else
252                return BadMatch;
253
254        return Success;
255}
256
257/**
258 * NV10StopOverlay
259 * Tell the hardware to stop the overlay
260 */
261void
262NV10StopOverlay (ScrnInfoPtr pScrn)
263{
264#ifdef NVOVL_SUPPORT
265    NVPtr pNv = NVPTR(pScrn);
266    nvWriteVIDEO(pNv, NV_PVIDEO_STOP, 1);
267#endif
268}
269
270/**
271 * NV10WriteOverlayParameters
272 * Tell the hardware about parameters that are too expensive to be set
273 * on every frame
274 */
275void
276NV10WriteOverlayParameters (ScrnInfoPtr pScrn)
277{
278    NVPtr          pNv     = NVPTR(pScrn);
279    NVPortPrivPtr  pPriv   = GET_OVERLAY_PRIVATE(pNv);
280    int            satSine, satCosine;
281    double         angle;
282
283    angle = (double)pPriv->hue * 3.1415927 / 180.0;
284
285    satSine = pPriv->saturation * sin(angle);
286    if (satSine < -1024)
287	satSine = -1024;
288    satCosine = pPriv->saturation * cos(angle);
289    if (satCosine < -1024)
290	satCosine = -1024;
291
292#ifdef NVOVL_SUPPORT
293    nvWriteVIDEO(pNv, NV_PVIDEO_LUMINANCE(0), (pPriv->brightness << 16) |
294	    pPriv->contrast);
295    nvWriteVIDEO(pNv, NV_PVIDEO_LUMINANCE(1), (pPriv->brightness << 16) |
296	    pPriv->contrast);
297    nvWriteVIDEO(pNv, NV_PVIDEO_CHROMINANCE(0), (satSine << 16) |
298	    (satCosine & 0xffff));
299    nvWriteVIDEO(pNv, NV_PVIDEO_CHROMINANCE(1), (satSine << 16) |
300	    (satCosine & 0xffff));
301    nvWriteVIDEO(pNv, NV_PVIDEO_COLOR_KEY, pPriv->colorKey);
302#endif
303}
304
305