randr12: fix dpms, detect, destroy, save and restore for multiple encoders per connector
[nouveau] / src / nv50_xv.c
1 /*
2  * Copyright 2008 Ben Skeggs
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 "xf86xv.h"
28 #include <X11/extensions/Xv.h>
29 #include "exa.h"
30 #include "damage.h"
31 #include "dixstruct.h"
32 #include "fourcc.h"
33
34 #include "nv_include.h"
35 #include "nv_dma.h"
36 #include "nv50_accel.h"
37 #include "nv50_texture.h"
38
39 static Bool
40 nv50_xv_check_image_put(PixmapPtr ppix)
41 {
42         ScrnInfoPtr pScrn = xf86Screens[ppix->drawable.pScreen->myNum];
43         NVPtr pNv = NVPTR(pScrn);
44
45         switch (ppix->drawable.depth) {
46         case 32:
47         case 24:
48         case 16:
49                 break;
50         default:
51                 return FALSE;
52         }
53
54         if (exaGetPixmapOffset(ppix) < pNv->EXADriverPtr->offScreenBase)
55                 return FALSE;
56
57         return TRUE;
58 }
59
60 int
61 nv50_xv_image_put(ScrnInfoPtr pScrn,
62                   struct nouveau_bo *src, int src_offset, int src_offset2,
63                   int id, int src_pitch, BoxPtr dstBox,
64                   int x1, int y1, int x2, int y2,
65                   uint16_t width, uint16_t height,
66                   uint16_t src_w, uint16_t src_h,
67                   uint16_t drw_w, uint16_t drw_h,
68                   RegionPtr clipBoxes, PixmapPtr ppix,
69                   NVPortPrivPtr pPriv)
70 {
71         NVPtr pNv = NVPTR(pScrn);
72         struct nouveau_channel *chan = pNv->chan;
73         struct nouveau_grobj *tesla = pNv->Nv3D;
74         float X1, X2, Y1, Y2;
75         BoxPtr pbox;
76         int nbox;
77
78         if (!nv50_xv_check_image_put(ppix))
79                 return BadMatch;
80
81         BEGIN_RING(chan, tesla, NV50TCL_RT_ADDRESS_HIGH(0), 5);
82         OUT_PIXMAPh(chan, ppix, 0, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
83         OUT_PIXMAPl(chan, ppix, 0, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
84         switch (ppix->drawable.depth) {
85         case 32: OUT_RING  (chan, NV50TCL_RT_FORMAT_32BPP); break;
86         case 24: OUT_RING  (chan, NV50TCL_RT_FORMAT_24BPP); break;
87         case 16: OUT_RING  (chan, NV50TCL_RT_FORMAT_16BPP); break;
88         }
89         OUT_RING  (chan, 0);
90         OUT_RING  (chan, 0);
91         BEGIN_RING(chan, tesla, NV50TCL_RT_HORIZ(0), 2);
92         OUT_RING  (chan, ppix->drawable.width);
93         OUT_RING  (chan, ppix->drawable.height);
94         BEGIN_RING(chan, tesla, 0x1224, 1);
95         OUT_RING  (chan, 1);
96
97         BEGIN_RING(chan, tesla, NV50TCL_BLEND_ENABLE(0), 1);
98         OUT_RING  (chan, 0);
99
100         BEGIN_RING(chan, tesla, NV50TCL_CB_ADDR, 1);
101         OUT_RING  (chan, CB_TIC);
102         BEGIN_RING(chan, tesla, NV50TCL_CB_DATA(0) | 0x40000000, 16);
103         if (id == FOURCC_YV12 || id == FOURCC_I420) {
104         OUT_RING  (chan, NV50TIC_0_0_MAPA_C0 | NV50TIC_0_0_TYPEA_UNORM |
105                          NV50TIC_0_0_MAPR_ZERO | NV50TIC_0_0_TYPER_UNORM |
106                          NV50TIC_0_0_MAPG_ZERO | NV50TIC_0_0_TYPEG_UNORM |
107                          NV50TIC_0_0_MAPB_ZERO | NV50TIC_0_0_TYPEB_UNORM |
108                          NV50TIC_0_0_FMT_8);
109         OUT_RELOCl(chan, src,
110                          src_offset, NOUVEAU_BO_VRAM | NOUVEAU_BO_RD);
111         OUT_RING  (chan, 0xd0005000);
112         OUT_RING  (chan, 0x00300000);
113         OUT_RING  (chan, src_w);
114         OUT_RING  (chan, (1 << NV50TIC_0_5_DEPTH_SHIFT) | src_h);
115         OUT_RING  (chan, 0x03000000);
116         OUT_RELOCh(chan, src,
117                          src_offset, NOUVEAU_BO_VRAM | NOUVEAU_BO_RD);
118         OUT_RING  (chan, NV50TIC_0_0_MAPA_C1 | NV50TIC_0_0_TYPEA_UNORM |
119                          NV50TIC_0_0_MAPR_C0 | NV50TIC_0_0_TYPER_UNORM |
120                          NV50TIC_0_0_MAPG_ZERO | NV50TIC_0_0_TYPEG_UNORM |
121                          NV50TIC_0_0_MAPB_ZERO | NV50TIC_0_0_TYPEB_UNORM |
122                          NV50TIC_0_0_FMT_8_8);
123         OUT_RELOCl(chan, src,
124                          src_offset2, NOUVEAU_BO_VRAM | NOUVEAU_BO_RD);
125         OUT_RING  (chan, 0xd0005000);
126         OUT_RING  (chan, 0x00300000);
127         OUT_RING  (chan, src_w >> 1);
128         OUT_RING  (chan, (1 << NV50TIC_0_5_DEPTH_SHIFT) | (src_h >> 1));
129         OUT_RING  (chan, 0x03000000);
130         OUT_RELOCh(chan, src,
131                          src_offset2, NOUVEAU_BO_VRAM | NOUVEAU_BO_RD);
132         } else {
133         OUT_RING  (chan, NV50TIC_0_0_MAPA_C0 | NV50TIC_0_0_TYPEA_UNORM |
134                          NV50TIC_0_0_MAPR_ZERO | NV50TIC_0_0_TYPER_UNORM |
135                          NV50TIC_0_0_MAPG_ZERO | NV50TIC_0_0_TYPEG_UNORM |
136                          NV50TIC_0_0_MAPB_ZERO | NV50TIC_0_0_TYPEB_UNORM |
137                          NV50TIC_0_0_FMT_8_8);
138         OUT_RELOCl(chan, src,
139                          src_offset, NOUVEAU_BO_VRAM | NOUVEAU_BO_RD);
140         OUT_RING  (chan, 0xd0005000);
141         OUT_RING  (chan, 0x00300000);
142         OUT_RING  (chan, src_w);
143         OUT_RING  (chan, (1 << NV50TIC_0_5_DEPTH_SHIFT) | src_h);
144         OUT_RING  (chan, 0x03000000);
145         OUT_RELOCh(chan, src,
146                          src_offset, NOUVEAU_BO_VRAM | NOUVEAU_BO_RD);
147         OUT_RING  (chan, NV50TIC_0_0_MAPA_C3 | NV50TIC_0_0_TYPEA_UNORM |
148                          NV50TIC_0_0_MAPR_C1 | NV50TIC_0_0_TYPER_UNORM |
149                          NV50TIC_0_0_MAPG_ZERO | NV50TIC_0_0_TYPEG_UNORM |
150                          NV50TIC_0_0_MAPB_ZERO | NV50TIC_0_0_TYPEB_UNORM |
151                          NV50TIC_0_0_FMT_8_8_8_8);
152         OUT_RELOCl(chan, src,
153                          src_offset, NOUVEAU_BO_VRAM | NOUVEAU_BO_RD);
154         OUT_RING  (chan, 0xd0005000);
155         OUT_RING  (chan, 0x00300000);
156         OUT_RING  (chan, (src_w >> 1));
157         OUT_RING  (chan, (1 << NV50TIC_0_5_DEPTH_SHIFT) | src_h);
158         OUT_RING  (chan, 0x03000000);
159         OUT_RELOCh(chan, src,
160                          src_offset, NOUVEAU_BO_VRAM | NOUVEAU_BO_RD);
161         }
162
163         BEGIN_RING(chan, tesla, NV50TCL_CB_ADDR, 1);
164         OUT_RING  (chan, CB_TSC);
165         BEGIN_RING(chan, tesla, NV50TCL_CB_DATA(0) | 0x40000000, 16);
166         OUT_RING  (chan, NV50TSC_1_0_WRAPS_CLAMP_TO_EDGE |
167                          NV50TSC_1_0_WRAPT_CLAMP_TO_EDGE |
168                          NV50TSC_1_0_WRAPR_CLAMP_TO_EDGE);
169         OUT_RING  (chan, NV50TSC_1_1_MAGF_LINEAR |
170                          NV50TSC_1_1_MINF_LINEAR |
171                          NV50TSC_1_1_MIPF_NONE);
172         OUT_RING  (chan, 0x00000000);
173         OUT_RING  (chan, 0x00000000);
174         OUT_RING  (chan, 0x00000000);
175         OUT_RING  (chan, 0x00000000);
176         OUT_RING  (chan, 0x00000000);
177         OUT_RING  (chan, 0x00000000);
178         OUT_RING  (chan, NV50TSC_1_0_WRAPS_CLAMP_TO_EDGE |
179                          NV50TSC_1_0_WRAPT_CLAMP_TO_EDGE |
180                          NV50TSC_1_0_WRAPR_CLAMP_TO_EDGE);
181         OUT_RING  (chan, NV50TSC_1_1_MAGF_LINEAR |
182                          NV50TSC_1_1_MINF_LINEAR |
183                          NV50TSC_1_1_MIPF_NONE);
184         OUT_RING  (chan, 0x00000000);
185         OUT_RING  (chan, 0x00000000);
186         OUT_RING  (chan, 0x00000000);
187         OUT_RING  (chan, 0x00000000);
188         OUT_RING  (chan, 0x00000000);
189         OUT_RING  (chan, 0x00000000);
190
191         BEGIN_RING(chan, tesla, NV50TCL_FP_START_ID, 1);
192         OUT_RING  (chan, PFP_NV12);
193
194         BEGIN_RING(chan, tesla, 0x1334, 1);
195         OUT_RING  (chan, 0);
196
197         BEGIN_RING(chan, tesla, 0x1458, 1);
198         OUT_RING  (chan, 1);
199         BEGIN_RING(chan, tesla, 0x1458, 1);
200         OUT_RING  (chan, 0x203);
201
202         /* These are fixed point values in the 16.16 format. */
203         X1 = (float)(x1>>16)+(float)(x1&0xFFFF)/(float)0x10000;
204         Y1 = (float)(y1>>16)+(float)(y1&0xFFFF)/(float)0x10000;
205         X2 = (float)(x2>>16)+(float)(x2&0xFFFF)/(float)0x10000;
206         Y2 = (float)(y2>>16)+(float)(y2&0xFFFF)/(float)0x10000;
207
208         BEGIN_RING(chan, tesla, NV50TCL_VERTEX_BEGIN, 1);
209         OUT_RING  (chan, NV50TCL_VERTEX_BEGIN_QUADS);
210
211         pbox = REGION_RECTS(clipBoxes);
212         nbox = REGION_NUM_RECTS(clipBoxes);
213         while(nbox--) {
214                 float tx1=X1+(float)(pbox->x1 - dstBox->x1)*(X2-X1)/(float)(drw_w);
215                 float tx2=X1+(float)(pbox->x2 - dstBox->x1)*(src_w)/(float)(drw_w);
216                 float ty1=Y1+(float)(pbox->y1 - dstBox->y1)*(Y2-Y1)/(float)(drw_h);
217                 float ty2=Y1+(float)(pbox->y2 - dstBox->y1)*(src_h)/(float)(drw_h);
218                 int sx1=pbox->x1;
219                 int sx2=pbox->x2;
220                 int sy1=pbox->y1;
221                 int sy2=pbox->y2;
222
223                 tx1 = tx1 / src_w;
224                 tx2 = tx2 / src_w;
225                 ty1 = ty1 / src_h;
226                 ty2 = ty2 / src_h;
227
228                 VTX2s(pNv, tx1, ty1, tx1, ty1, sx1, sy1);
229                 VTX2s(pNv, tx2, ty1, tx2, ty1, sx2, sy1);
230                 VTX2s(pNv, tx2, ty2, tx2, ty2, sx2, sy2);
231                 VTX2s(pNv, tx1, ty2, tx1, ty2, sx1, sy2);
232
233                 pbox++;
234         }
235
236         BEGIN_RING(chan, tesla, NV50TCL_VERTEX_END, 1);
237         OUT_RING  (chan, 0);
238
239         FIRE_RING (chan);
240
241         return Success;
242 }
243
244 void
245 nv50_xv_video_stop(ScrnInfoPtr pScrn, pointer data, Bool exit)
246 {
247 }
248
249 int
250 nv50_xv_port_attribute_set(ScrnInfoPtr pScrn, Atom attribute,
251                            INT32 value, pointer data)
252 {
253         return BadMatch;
254 }
255
256 int
257 nv50_xv_port_attribute_get(ScrnInfoPtr pScrn, Atom attribute,
258                            INT32 *value, pointer data)
259 {
260         return BadMatch;
261 }
262