Xv: Remove illegal usage of private exa symbols.
[nouveau] / src / nv40_video_texture.c
1 /*
2  * Copyright 2007 Maarten Maathuis
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 (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21  * DEALINGS IN THE SOFTWARE.
22  */
23
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif
27
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
38 #include "nv_shaders.h"
39
40 extern Atom xvSyncToVBlank, xvSetDefaults;
41
42 static nv_shader_t nv40_video = {
43         .card_priv.NV30VP.vp_in_reg  = 0x00000309,
44         .card_priv.NV30VP.vp_out_reg = 0x0000c001,
45         .size = (3*4),
46         .data = {
47                 /* MOV result.position, vertex.position */
48                 0x40041c6c, 0x0040000d, 0x8106c083, 0x6041ff80,
49                 /* MOV result.texcoord[0], vertex.texcoord[0] */
50                 0x401f9c6c, 0x0040080d, 0x8106c083, 0x6041ff9c,
51                 /* MOV result.texcoord[1], vertex.texcoord[1] */
52                 0x401f9c6c, 0x0040090d, 0x8106c083, 0x6041ffa1,
53         }
54 };
55
56 static nv_shader_t nv40_yv12 = {
57         .card_priv.NV30FP.num_regs = 2,
58         .size = (8*4),
59         .data = {
60                 /* INST 0: TEXR R0.x (TR0.xyzw), attrib.texcoord[0], abs(texture[0]) */
61                 0x17008200, 0x1c9dc801, 0x0001c800, 0x3fe1c800,
62                 /* INST 1: MADR R1.xyz (TR0.xyzw), R0.xxxx, { 1.16, -0.87, 0.53, -1.08 }.xxxx, { 1.16, -0.87, 0.53, -1.08 }.yzww */
63                 0x04000e02, 0x1c9c0000, 0x00000002, 0x0001f202,
64                 0x3f9507c8, 0xbf5ee393, 0x3f078fef, 0xbf8a6762,
65                 /* INST 2: TEXR R0.yz (TR0.xyzw), attrib.texcoord[1], abs(texture[1]) */
66                 0x1702ac80, 0x1c9dc801, 0x0001c800, 0x3fe1c800,
67                 /* INST 3: MADR R1.xyz (TR0.xyzw), R0.yyyy, { 0.00, -0.39, 2.02, 0.00 }, R1 */
68                 0x04000e02, 0x1c9cab00, 0x0001c802, 0x0001c804,
69                 0x00000000, 0xbec890d6, 0x40011687, 0x00000000,
70                 /* INST 4: MADR R0.xyz (TR0.xyzw), R0.zzzz, { 1.60, -0.81, 0.00, 0.00 }, R1 + END */
71                 0x04000e81, 0x1c9d5500, 0x0001c802, 0x0001c804,
72                 0x3fcc432d, 0xbf501a37, 0x00000000, 0x00000000,
73         }
74 };
75
76 #define SWIZZLE(ts0x,ts0y,ts0z,ts0w,ts1x,ts1y,ts1z,ts1w)                                                        \
77         (                                                                                                                                       \
78         NV40TCL_TEX_SWIZZLE_S0_X_##ts0x | NV40TCL_TEX_SWIZZLE_S0_Y_##ts0y               |       \
79         NV40TCL_TEX_SWIZZLE_S0_Z_##ts0z | NV40TCL_TEX_SWIZZLE_S0_W_##ts0w       |       \
80         NV40TCL_TEX_SWIZZLE_S1_X_##ts1x | NV40TCL_TEX_SWIZZLE_S1_Y_##ts1y       |       \
81         NV40TCL_TEX_SWIZZLE_S1_Z_##ts1z | NV40TCL_TEX_SWIZZLE_S1_W_##ts1w               \
82         )
83
84 static Bool
85 NV40VideoTexture(ScrnInfoPtr pScrn, int offset, uint16_t width, uint16_t height, uint16_t src_pitch, int unit)
86 {
87         NVPtr pNv = NVPTR(pScrn);
88
89         uint32_t card_fmt = 0;
90         uint32_t card_swz = 0;
91
92         if (unit == 0) {
93                 /* Pretend we've got a normal 8 bits format. */
94                 card_fmt = NV40TCL_TEX_FORMAT_FORMAT_L8;
95                 card_swz = SWIZZLE(S1, S1, S1, S1, X, X, X, X);
96         } else {
97                 /* Pretend we've got a normal 2x8 bits format. */
98                 card_fmt = NV40TCL_TEX_FORMAT_FORMAT_A8L8;
99                 card_swz = SWIZZLE(S1, S1, S1, S1, W, Z, Y, X); /* x = V, y = U */
100         }
101
102         BEGIN_RING(Nv3D, NV40TCL_TEX_OFFSET(unit), 8);
103         /* We get an obsolute offset, which needs to be corrected. */
104         OUT_RELOCl(pNv->FB, (uint32_t)(offset - pNv->FB->offset), NOUVEAU_BO_VRAM | NOUVEAU_BO_RD);
105         OUT_RELOCd(pNv->FB, card_fmt | NV40TCL_TEX_FORMAT_LINEAR |
106                         NV40TCL_TEX_FORMAT_DIMS_2D | NV40TCL_TEX_FORMAT_NO_BORDER |
107                         (0x8000) | (1 << NV40TCL_TEX_FORMAT_MIPMAP_COUNT_SHIFT),
108                         NOUVEAU_BO_VRAM | NOUVEAU_BO_RD,
109                         NV40TCL_TEX_FORMAT_DMA0, 0);
110
111         OUT_RING(NV40TCL_TEX_WRAP_S_CLAMP_TO_EDGE |
112                         NV40TCL_TEX_WRAP_T_CLAMP_TO_EDGE |
113                         NV40TCL_TEX_WRAP_R_CLAMP_TO_EDGE);
114         OUT_RING(NV40TCL_TEX_ENABLE_ENABLE);
115         OUT_RING(card_swz);
116         OUT_RING(NV40TCL_TEX_FILTER_MIN_LINEAR |
117                         NV40TCL_TEX_FILTER_MAG_LINEAR |
118                         0x3fd6);
119         OUT_RING((width << 16) | height);
120         OUT_RING(0); /* border ARGB */
121         BEGIN_RING(Nv3D, NV40TCL_TEX_SIZE1(unit), 1);
122         OUT_RING((1 << NV40TCL_TEX_SIZE1_DEPTH_SHIFT) |
123                         (uint16_t) src_pitch);
124
125         return TRUE;
126 }
127
128 Bool
129 NV40GetSurfaceFormat(PixmapPtr pPix, int *fmt_ret)
130 {
131         switch (pPix->drawable.bitsPerPixel) {
132                 case 32:
133                         *fmt_ret = NV40TCL_RT_FORMAT_COLOR_A8R8G8B8;
134                         break;
135                 case 24:
136                         *fmt_ret = NV40TCL_RT_FORMAT_COLOR_X8R8G8B8;
137                         break;
138                 case 16:
139                         *fmt_ret = NV40TCL_RT_FORMAT_COLOR_R5G6B5;
140                         break;
141                 case 8:
142                         *fmt_ret = NV40TCL_RT_FORMAT_COLOR_B8;
143                         break;
144                 default:
145                         return FALSE;
146         }
147
148         return TRUE;
149 }
150
151 void
152 NV40StopTexturedVideo(ScrnInfoPtr pScrn, pointer data, Bool Exit)
153 {
154 }
155
156 /* To support EXA 2.0, 2.1 has this in the header */
157 #ifndef exaMoveInPixmap
158 extern void exaMoveInPixmap(PixmapPtr pPixmap);
159 #endif
160
161 #define SF(bf) (NV40TCL_BLEND_FUNC_SRC_RGB_##bf |                              \
162                 NV40TCL_BLEND_FUNC_SRC_ALPHA_##bf)
163 #define DF(bf) (NV40TCL_BLEND_FUNC_DST_RGB_##bf |                              \
164                 NV40TCL_BLEND_FUNC_DST_ALPHA_##bf)
165
166 #define VERTEX_OUT(sx,sy,dx,dy) do {                                        \
167         BEGIN_RING(Nv3D, NV40TCL_VTX_ATTR_2F_X(8), 4);                         \
168         OUT_RINGf ((sx)); OUT_RINGf ((sy));                                    \
169         OUT_RINGf ((sx)); OUT_RINGf ((sy));                                    \
170         BEGIN_RING(Nv3D, NV40TCL_VTX_ATTR_2I(0), 1);                           \
171         OUT_RING  (((dy)<<16)|(dx));                                           \
172 } while(0)
173
174 #define GET_TEXTURED_PRIVATE(pNv) \
175         (NVPortPrivPtr)((pNv)->blitAdaptor->pPortPrivates[0].ptr)
176
177 int NV40PutTextureImage(ScrnInfoPtr pScrn, int src_offset,
178                 int src_offset2, int id,
179                 int src_pitch, BoxPtr dstBox,
180                 int x1, int y1, int x2, int y2,
181                 uint16_t width, uint16_t height,
182                 uint16_t src_w, uint16_t src_h,
183                 uint16_t drw_w, uint16_t drw_h,
184                 RegionPtr clipBoxes,
185                 DrawablePtr pDraw)
186 {
187         NVPtr pNv   = NVPTR(pScrn);
188         NVPortPrivPtr pPriv = GET_TEXTURED_PRIVATE(pNv);
189         Bool redirected = FALSE;
190
191         /* Remove some warnings. */
192         /* This has to be done better at some point. */
193         (void)nv40_vp_exa_render;
194         (void)nv30_fp_pass_col0;
195         (void)nv30_fp_pass_tex0;
196         (void)nv30_fp_composite_mask;
197         (void)nv30_fp_composite_mask_sa_ca;
198         (void)nv30_fp_composite_mask_ca;
199
200         if (drw_w > 4096 || drw_h > 4096) {
201                 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
202                         "XV: Draw size too large.\n");
203                 return BadAlloc;
204         }
205
206         float X1, X2, Y1, Y2;
207         float scaleX1, scaleX2, scaleY1, scaleY2;
208         float scaleX, scaleY;
209         PixmapPtr pPix = NVGetDrawablePixmap(pDraw);
210         BoxPtr pbox;
211         int nbox;
212         int dst_format = 0;
213         if (!NV40GetSurfaceFormat(pPix, &dst_format)) {
214                 ErrorF("No surface format, bad.\n");
215         }
216
217         /* This has to be called always, since it does more than just migration. */
218         exaMoveInPixmap(pPix);
219         ExaOffscreenMarkUsed(pPix);
220
221 #ifdef COMPOSITE
222         /* Adjust coordinates if drawing to an offscreen pixmap */
223         if (pPix->screen_x || pPix->screen_y) {
224                 REGION_TRANSLATE(pScrn->pScreen, clipBoxes,
225                                                         -pPix->screen_x,
226                                                         -pPix->screen_y);
227                 dstBox->x1 -= pPix->screen_x;
228                 dstBox->x2 -= pPix->screen_x;
229                 dstBox->y1 -= pPix->screen_y;
230                 dstBox->y2 -= pPix->screen_y;
231         }
232
233         /* I suspect that pDraw itself is not offscreen, hence not suited for damage tracking. */
234         DamageDamageRegion(&pPix->drawable, clipBoxes);
235
236         /* This is test is unneeded for !COMPOSITE. */
237         if (!NVExaPixmapIsOnscreen(pPix))
238                 redirected = TRUE;
239 #endif
240
241         pbox = REGION_RECTS(clipBoxes);
242         nbox = REGION_NUM_RECTS(clipBoxes);
243
244         /* Disable blending */
245         BEGIN_RING(Nv3D, NV40TCL_BLEND_ENABLE, 1);
246         OUT_RING(0);
247
248         /* Setup surface */
249         BEGIN_RING(Nv3D, NV40TCL_RT_FORMAT, 3);
250         OUT_RING  (NV40TCL_RT_FORMAT_TYPE_LINEAR |
251                         NV40TCL_RT_FORMAT_ZETA_Z24S8 |
252                         dst_format);
253         OUT_RING  (exaGetPixmapPitch(pPix));
254         OUT_PIXMAPl(pPix, 0, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
255
256         NV40VideoTexture(pScrn, src_offset, src_w, src_h, src_pitch, 0);
257         /* We've got NV12 format, which means half width and half height texture of chroma channels. */
258         NV40VideoTexture(pScrn, src_offset2, src_w/2, src_h/2, src_pitch, 1);
259
260         NV40_LoadVtxProg(pScrn, &nv40_video);
261         NV40_LoadFragProg(pScrn, &nv40_yv12);
262
263         /* Appears to be some kind of cache flush, needed here at least
264          * sometimes.. funky text rendering otherwise :)
265          */
266         BEGIN_RING(Nv3D, NV40TCL_TEX_CACHE_CTL, 1);
267         OUT_RING  (2);
268         BEGIN_RING(Nv3D, NV40TCL_TEX_CACHE_CTL, 1);
269         OUT_RING  (1);
270
271         /* These are fixed point values in the 16.16 format. */
272         x1 >>= 16;
273         x2 >>= 16;
274         y1 >>= 16;
275         y2 >>= 16;
276
277         X1 = (float)x1/(float)src_w;
278         Y1 = (float)y1/(float)src_h;
279         X2 = (float)x2/(float)src_w;
280         Y2 = (float)y2/(float)src_h;
281
282         /* The corrections here are emperical, i tried to explain them as best as possible. */
283
284         /* This correction is need for when the image clips the screen at the right or bottom. */
285         /* In this case x2 and/or y2 is adjusted for the clipping, otherwise not. */
286         /* Otherwise the lower right coordinate stretches in the clipping direction. */
287         scaleX = (float)src_w/(float)(x2 - x1);
288         scaleY = (float)src_h/(float)(y2 - y1);
289
290         /* Just before rendering we wait for vblank in the non-composited case. */
291         if (pPriv->SyncToVBlank && !redirected) {
292                 uint8_t crtcs = nv_window_belongs_to_crtc(pScrn, dstBox->x1, dstBox->y1,
293                         dstBox->x2 - dstBox->x1, dstBox->y2 - dstBox->y1);
294
295                 FIRE_RING();
296                 if (crtcs & 0x1)
297                         NVWaitVSync(pScrn, 0);
298                 else if (crtcs & 0x2)
299                         NVWaitVSync(pScrn, 1);
300         }
301
302         BEGIN_RING(Nv3D, NV40TCL_BEGIN_END, 1);
303         OUT_RING  (NV40TCL_BEGIN_END_QUADS);
304
305         while(nbox--) {
306
307                 /* The src coordinates needs to be scaled to the draw size. */
308                 scaleX1 = (float)(pbox->x1 - dstBox->x1)/(float)drw_w;
309                 scaleX2 = (float)(pbox->x2 - dstBox->x1)/(float)drw_w;
310                 scaleY1 = (float)(pbox->y1 - dstBox->y1)/(float)drw_h;
311                 scaleY2 = (float)(pbox->y2 - dstBox->y1)/(float)drw_h;
312
313                 /* Submit the appropriate vertices. */
314                 /* This submits the same vertices for the Y and the UV texture. */
315                 VERTEX_OUT(X1 + (X2 - X1) * scaleX1 * scaleX, Y1 + (Y2 - Y1) * scaleY1 * scaleY, pbox->x1, pbox->y1);
316                 VERTEX_OUT(X1 + (X2 - X1) * scaleX2 * scaleX, Y1 + (Y2 - Y1) * scaleY1 * scaleY, pbox->x2, pbox->y1);
317                 VERTEX_OUT(X1 + (X2 - X1) * scaleX2 * scaleX, Y1 + (Y2 - Y1) * scaleY2 * scaleY, pbox->x2, pbox->y2);
318                 VERTEX_OUT(X1 + (X2 - X1) * scaleX1 * scaleX, Y1 + (Y2 - Y1) * scaleY2 * scaleY, pbox->x1, pbox->y2);
319
320                 pbox++;
321         }
322
323         BEGIN_RING(Nv3D, NV40TCL_BEGIN_END, 1);
324         OUT_RING  (NV40TCL_BEGIN_END_STOP);
325
326         FIRE_RING();
327
328         return Success;
329 }
330
331 /**
332  * NVSetTexturePortAttribute
333  * sets the attribute "attribute" of port "data" to value "value"
334  * supported attributes:
335  * Sync to vblank.
336  * 
337  * @param pScrenInfo
338  * @param attribute attribute to set
339  * @param value value to which attribute is to be set
340  * @param data port from which the attribute is to be set
341  * 
342  * @return Success, if setting is successful
343  * BadValue/BadMatch, if value/attribute are invalid
344  */
345 int
346 NVSetTexturePortAttribute(ScrnInfoPtr pScrn, Atom attribute,
347                        INT32 value, pointer data)
348 {
349         NVPortPrivPtr pPriv = (NVPortPrivPtr)data;
350         NVPtr           pNv = NVPTR(pScrn);
351
352         if ((attribute == xvSyncToVBlank) && pNv->WaitVSyncPossible) {
353                 if ((value < 0) || (value > 1))
354                         return BadValue;
355                 pPriv->SyncToVBlank = value;
356         } else
357         if (attribute == xvSetDefaults) {
358                 pPriv->SyncToVBlank = pNv->WaitVSyncPossible;
359         } else
360                 return BadMatch;
361
362         return Success;
363 }
364
365 /**
366  * NVGetTexturePortAttribute
367  * reads the value of attribute "attribute" from port "data" into INT32 "*value"
368  * Sync to vblank.
369  * 
370  * @param pScrn unused
371  * @param attribute attribute to be read
372  * @param value value of attribute will be stored here
373  * @param data port from which attribute will be read
374  * @return Success, if queried attribute exists
375  */
376 int
377 NVGetTexturePortAttribute(ScrnInfoPtr pScrn, Atom attribute,
378                        INT32 *value, pointer data)
379 {
380         NVPortPrivPtr pPriv = (NVPortPrivPtr)data;
381
382         if(attribute == xvSyncToVBlank)
383                 *value = (pPriv->SyncToVBlank) ? 1 : 0;
384         else
385                 return BadMatch;
386
387         return Success;
388 }
389