2 * Copyright 2007 Maarten Maathuis
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:
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
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.
29 #include <X11/extensions/Xv.h>
32 #include "dixstruct.h"
35 #include "nv_include.h"
38 #include "nv_shaders.h"
40 extern Atom xvSyncToVBlank, xvSetDefaults;
42 static nv_shader_t nv40_video = {
43 .card_priv.NV30VP.vp_in_reg = 0x00000309,
44 .card_priv.NV30VP.vp_out_reg = 0x0000c001,
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,
56 static nv_shader_t nv40_yv12 = {
57 .card_priv.NV30FP.num_regs = 2,
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,
76 #define SWIZZLE(ts0x,ts0y,ts0z,ts0w,ts1x,ts1y,ts1z,ts1w) \
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 \
85 NV40VideoTexture(ScrnInfoPtr pScrn, int offset, uint16_t width, uint16_t height, uint16_t src_pitch, int unit)
87 NVPtr pNv = NVPTR(pScrn);
89 uint32_t card_fmt = 0;
90 uint32_t card_swz = 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);
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 */
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);
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);
116 OUT_RING(NV40TCL_TEX_FILTER_MIN_LINEAR |
117 NV40TCL_TEX_FILTER_MAG_LINEAR |
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);
129 NV40GetSurfaceFormat(PixmapPtr pPix, int *fmt_ret)
131 switch (pPix->drawable.bitsPerPixel) {
133 *fmt_ret = NV40TCL_RT_FORMAT_COLOR_A8R8G8B8;
136 *fmt_ret = NV40TCL_RT_FORMAT_COLOR_X8R8G8B8;
139 *fmt_ret = NV40TCL_RT_FORMAT_COLOR_R5G6B5;
142 *fmt_ret = NV40TCL_RT_FORMAT_COLOR_B8;
152 NV40StopTexturedVideo(ScrnInfoPtr pScrn, pointer data, Bool Exit)
156 #ifndef ExaOffscreenMarkUsed
157 extern void ExaOffscreenMarkUsed(PixmapPtr);
159 #ifndef exaGetDrawablePixmap
160 extern PixmapPtr exaGetDrawablePixmap(DrawablePtr);
162 #ifndef exaPixmapIsOffscreen
163 extern Bool exaPixmapIsOffscreen(PixmapPtr p);
165 /* To support EXA 2.0, 2.1 has this in the header */
166 #ifndef exaMoveInPixmap
167 extern void exaMoveInPixmap(PixmapPtr pPixmap);
170 #define SF(bf) (NV40TCL_BLEND_FUNC_SRC_RGB_##bf | \
171 NV40TCL_BLEND_FUNC_SRC_ALPHA_##bf)
172 #define DF(bf) (NV40TCL_BLEND_FUNC_DST_RGB_##bf | \
173 NV40TCL_BLEND_FUNC_DST_ALPHA_##bf)
175 #define VERTEX_OUT(sx,sy,dx,dy) do { \
176 BEGIN_RING(Nv3D, NV40TCL_VTX_ATTR_2F_X(8), 4); \
177 OUT_RINGf ((sx)); OUT_RINGf ((sy)); \
178 OUT_RINGf ((sx)); OUT_RINGf ((sy)); \
179 BEGIN_RING(Nv3D, NV40TCL_VTX_ATTR_2I(0), 1); \
180 OUT_RING (((dy)<<16)|(dx)); \
183 #define GET_TEXTURED_PRIVATE(pNv) \
184 (NVPortPrivPtr)((pNv)->blitAdaptor->pPortPrivates[0].ptr)
186 int NV40PutTextureImage(ScrnInfoPtr pScrn, int src_offset,
187 int src_offset2, int id,
188 int src_pitch, BoxPtr dstBox,
189 int x1, int y1, int x2, int y2,
190 uint16_t width, uint16_t height,
191 uint16_t src_w, uint16_t src_h,
192 uint16_t drw_w, uint16_t drw_h,
196 NVPtr pNv = NVPTR(pScrn);
197 NVPortPrivPtr pPriv = GET_TEXTURED_PRIVATE(pNv);
198 Bool redirected = FALSE;
200 /* Remove some warnings. */
201 /* This has to be done better at some point. */
202 (void)nv40_vp_exa_render;
203 (void)nv30_fp_pass_col0;
204 (void)nv30_fp_pass_tex0;
205 (void)nv30_fp_composite_mask;
206 (void)nv30_fp_composite_mask_sa_ca;
207 (void)nv30_fp_composite_mask_ca;
209 if (drw_w > 4096 || drw_h > 4096) {
210 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
211 "XV: Draw size too large.\n");
215 float X1, X2, Y1, Y2;
216 float scaleX1, scaleX2, scaleY1, scaleY2;
217 float scaleX, scaleY;
218 PixmapPtr pPix = exaGetDrawablePixmap(pDraw);
222 if (!NV40GetSurfaceFormat(pPix, &dst_format)) {
223 ErrorF("No surface format, bad.\n");
226 /* Try to get the dest drawable into vram */
227 if (!exaPixmapIsOffscreen(pPix)) {
228 exaMoveInPixmap(pPix);
229 ExaOffscreenMarkUsed(pPix);
232 /* Fail if we can't move the pixmap into memory. */
233 if (!exaPixmapIsOffscreen(pPix)) {
234 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
235 "XV: couldn't move dst surface into vram.\n");
240 /* Adjust coordinates if drawing to an offscreen pixmap */
241 if (pPix->screen_x || pPix->screen_y) {
242 REGION_TRANSLATE(pScrn->pScreen, clipBoxes,
245 dstBox->x1 -= pPix->screen_x;
246 dstBox->x2 -= pPix->screen_x;
247 dstBox->y1 -= pPix->screen_y;
248 dstBox->y2 -= pPix->screen_y;
251 /* I suspect that pDraw itself is not offscreen, hence not suited for damage tracking. */
252 DamageDamageRegion(&pPix->drawable, clipBoxes);
254 /* This is test is unneeded for !COMPOSITE. */
255 if (!NVExaPixmapIsOnscreen(pPix))
259 pbox = REGION_RECTS(clipBoxes);
260 nbox = REGION_NUM_RECTS(clipBoxes);
262 /* Disable blending */
263 BEGIN_RING(Nv3D, NV40TCL_BLEND_ENABLE, 1);
267 BEGIN_RING(Nv3D, NV40TCL_RT_FORMAT, 3);
268 OUT_RING (NV40TCL_RT_FORMAT_TYPE_LINEAR |
269 NV40TCL_RT_FORMAT_ZETA_Z24S8 |
271 OUT_RING (exaGetPixmapPitch(pPix));
272 OUT_PIXMAPl(pPix, 0, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
274 NV40VideoTexture(pScrn, src_offset, src_w, src_h, src_pitch, 0);
275 /* We've got NV12 format, which means half width and half height texture of chroma channels. */
276 NV40VideoTexture(pScrn, src_offset2, src_w/2, src_h/2, src_pitch, 1);
278 NV40_LoadVtxProg(pScrn, &nv40_video);
279 NV40_LoadFragProg(pScrn, &nv40_yv12);
281 /* Appears to be some kind of cache flush, needed here at least
282 * sometimes.. funky text rendering otherwise :)
284 BEGIN_RING(Nv3D, NV40TCL_TEX_CACHE_CTL, 1);
286 BEGIN_RING(Nv3D, NV40TCL_TEX_CACHE_CTL, 1);
289 /* These are fixed point values in the 16.16 format. */
295 X1 = (float)x1/(float)src_w;
296 Y1 = (float)y1/(float)src_h;
297 X2 = (float)x2/(float)src_w;
298 Y2 = (float)y2/(float)src_h;
300 /* The corrections here are emperical, i tried to explain them as best as possible. */
302 /* This correction is need for when the image clips the screen at the right or bottom. */
303 /* In this case x2 and/or y2 is adjusted for the clipping, otherwise not. */
304 /* Otherwise the lower right coordinate stretches in the clipping direction. */
305 scaleX = (float)src_w/(float)(x2 - x1);
306 scaleY = (float)src_h/(float)(y2 - y1);
308 /* Just before rendering we wait for vblank in the non-composited case. */
309 if (pPriv->SyncToVBlank && !redirected) {
310 uint8_t crtcs = nv_window_belongs_to_crtc(pScrn, dstBox->x1, dstBox->y1,
311 dstBox->x2, dstBox->y2);
315 NVWaitVSync(pScrn, 0);
316 else if (crtcs & 0x2)
317 NVWaitVSync(pScrn, 1);
320 BEGIN_RING(Nv3D, NV40TCL_BEGIN_END, 1);
321 OUT_RING (NV40TCL_BEGIN_END_QUADS);
325 /* The src coordinates needs to be scaled to the draw size. */
326 scaleX1 = (float)(pbox->x1 - dstBox->x1)/(float)drw_w;
327 scaleX2 = (float)(pbox->x2 - dstBox->x1)/(float)drw_w;
328 scaleY1 = (float)(pbox->y1 - dstBox->y1)/(float)drw_h;
329 scaleY2 = (float)(pbox->y2 - dstBox->y1)/(float)drw_h;
331 /* Submit the appropriate vertices. */
332 /* This submits the same vertices for the Y and the UV texture. */
333 VERTEX_OUT(X1 + (X2 - X1) * scaleX1 * scaleX, Y1 + (Y2 - Y1) * scaleY1 * scaleY, pbox->x1, pbox->y1);
334 VERTEX_OUT(X1 + (X2 - X1) * scaleX2 * scaleX, Y1 + (Y2 - Y1) * scaleY1 * scaleY, pbox->x2, pbox->y1);
335 VERTEX_OUT(X1 + (X2 - X1) * scaleX2 * scaleX, Y1 + (Y2 - Y1) * scaleY2 * scaleY, pbox->x2, pbox->y2);
336 VERTEX_OUT(X1 + (X2 - X1) * scaleX1 * scaleX, Y1 + (Y2 - Y1) * scaleY2 * scaleY, pbox->x1, pbox->y2);
341 BEGIN_RING(Nv3D, NV40TCL_BEGIN_END, 1);
342 OUT_RING (NV40TCL_BEGIN_END_STOP);
350 * NVSetTexturePortAttribute
351 * sets the attribute "attribute" of port "data" to value "value"
352 * supported attributes:
356 * @param attribute attribute to set
357 * @param value value to which attribute is to be set
358 * @param data port from which the attribute is to be set
360 * @return Success, if setting is successful
361 * BadValue/BadMatch, if value/attribute are invalid
364 NVSetTexturePortAttribute(ScrnInfoPtr pScrn, Atom attribute,
365 INT32 value, pointer data)
367 NVPortPrivPtr pPriv = (NVPortPrivPtr)data;
368 NVPtr pNv = NVPTR(pScrn);
370 if ((attribute == xvSyncToVBlank) && pNv->WaitVSyncPossible) {
371 if ((value < 0) || (value > 1))
373 pPriv->SyncToVBlank = value;
375 if (attribute == xvSetDefaults) {
376 pPriv->SyncToVBlank = pNv->WaitVSyncPossible;
384 * NVGetTexturePortAttribute
385 * reads the value of attribute "attribute" from port "data" into INT32 "*value"
388 * @param pScrn unused
389 * @param attribute attribute to be read
390 * @param value value of attribute will be stored here
391 * @param data port from which attribute will be read
392 * @return Success, if queried attribute exists
395 NVGetTexturePortAttribute(ScrnInfoPtr pScrn, Atom attribute,
396 INT32 *value, pointer data)
398 NVPortPrivPtr pPriv = (NVPortPrivPtr)data;
400 if(attribute == xvSyncToVBlank)
401 *value = (pPriv->SyncToVBlank) ? 1 : 0;