nv30_xv_tex.c revision 22d74663
1/* 2 * Copyright 2007-2008 Maarten Maathuis 3 * Copyright 2008 Stephane Marchesin 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a 6 * copy of this software and associated documentation files (the "Software"), 7 * to deal in the Software without restriction, including without limitation 8 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 * and/or sell copies of the Software, and to permit persons to whom the 10 * Software is furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice (including the next 13 * paragraph) shall be included in all copies or substantial portions of the 14 * Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 22 * DEALINGS IN THE SOFTWARE. 23 */ 24 25#ifdef HAVE_CONFIG_H 26#include "config.h" 27#endif 28 29#include "xorg-config.h" 30#include "xf86xv.h" 31#include <X11/extensions/Xv.h> 32#include "exa.h" 33#include "damage.h" 34#include "dixstruct.h" 35#include "fourcc.h" 36 37#include "nv_include.h" 38#include "nv_dma.h" 39 40#include "hwdefs/nv30-40_3d.xml.h" 41#include "nv04_accel.h" 42 43extern Atom xvSyncToVBlank, xvSetDefaults; 44 45#define SWIZZLE(ts0x,ts0y,ts0z,ts0w,ts1x,ts1y,ts1z,ts1w) \ 46 ( \ 47 NV30_3D_TEX_SWIZZLE_S0_X_##ts0x | NV30_3D_TEX_SWIZZLE_S0_Y_##ts0y | \ 48 NV30_3D_TEX_SWIZZLE_S0_Z_##ts0z | NV30_3D_TEX_SWIZZLE_S0_W_##ts0w | \ 49 NV30_3D_TEX_SWIZZLE_S1_X_##ts1x | NV30_3D_TEX_SWIZZLE_S1_Y_##ts1y | \ 50 NV30_3D_TEX_SWIZZLE_S1_Z_##ts1z | NV30_3D_TEX_SWIZZLE_S1_W_##ts1w \ 51 ) 52 53/* 54 * Texture 0 : filter table 55 * Texture 1 : Y data 56 * Texture 2 : UV data 57 */ 58static Bool 59NV30VideoTexture(ScrnInfoPtr pScrn, struct nouveau_bo *src, int offset, 60 uint16_t width, uint16_t height, uint16_t src_pitch, int unit) 61{ 62 NVPtr pNv = NVPTR(pScrn); 63 unsigned reloc = NOUVEAU_BO_VRAM | NOUVEAU_BO_GART | NOUVEAU_BO_RD; 64 struct nouveau_pushbuf *push = pNv->pushbuf; 65 uint32_t card_fmt = 0; 66 uint32_t card_swz = 0; 67 int h = log2i(height); 68 int w = log2i(width); 69 70 switch (unit) { 71 case 0: 72 card_fmt = NV30_3D_TEX_FORMAT_FORMAT_A8R8G8B8; 73 card_swz = SWIZZLE(S1, S1, S1, S1, X, Y, Z, W); 74 break; 75 case 1: 76 card_fmt = NV30_3D_TEX_FORMAT_FORMAT_I8_RECT; 77 card_swz = SWIZZLE(S1, S1, S1, S1, X, X, X, X); 78 break; 79 case 2: 80 card_fmt = NV30_3D_TEX_FORMAT_FORMAT_A8L8_RECT; 81#if X_BYTE_ORDER == X_BIG_ENDIAN 82 card_swz = SWIZZLE(S1, S1, S1, S1, Z, W, X, Y); 83#else 84 card_swz = SWIZZLE(S1, S1, S1, S1, W, Z, Y, X); 85#endif 86 break; 87 } 88 89 BEGIN_NV04(push, NV30_3D(TEX_OFFSET(unit)), 8); 90 PUSH_MTHDl(push, NV30_3D(TEX_OFFSET(unit)), src, offset, reloc); 91 if (unit == 0) { 92 PUSH_MTHD (push, NV30_3D(TEX_FORMAT(unit)), src, 93 NV30_3D_TEX_FORMAT_DIMS_1D | 94 card_fmt | (1 << 16) | 8 /* no idea */ | 95 (w << NV30_3D_TEX_FORMAT_BASE_SIZE_U__SHIFT) | 96 (h << NV30_3D_TEX_FORMAT_BASE_SIZE_V__SHIFT), 97 reloc | NOUVEAU_BO_OR, 98 NV30_3D_TEX_FORMAT_DMA0, 99 NV30_3D_TEX_FORMAT_DMA1); 100 PUSH_DATA (push, NV30_3D_TEX_WRAP_S_REPEAT | 101 NV30_3D_TEX_WRAP_T_CLAMP_TO_EDGE | 102 NV30_3D_TEX_WRAP_R_CLAMP_TO_EDGE); 103 } else { 104 PUSH_MTHD (push, NV30_3D(TEX_FORMAT(unit)), src, 105 NV30_3D_TEX_FORMAT_DIMS_2D | 106 card_fmt | (1 << 16) | 8 /* no idea */ | 107 (w << NV30_3D_TEX_FORMAT_BASE_SIZE_U__SHIFT) | 108 (h << NV30_3D_TEX_FORMAT_BASE_SIZE_V__SHIFT), 109 reloc | NOUVEAU_BO_OR, 110 NV30_3D_TEX_FORMAT_DMA0, 111 NV30_3D_TEX_FORMAT_DMA1); 112 PUSH_DATA (push, NV30_3D_TEX_WRAP_S_CLAMP_TO_EDGE | 113 NV30_3D_TEX_WRAP_T_CLAMP_TO_EDGE | 114 NV30_3D_TEX_WRAP_R_CLAMP_TO_EDGE); 115 } 116 117 PUSH_DATA (push, NV30_3D_TEX_ENABLE_ENABLE); 118 PUSH_DATA (push, (src_pitch << NV30_3D_TEX_SWIZZLE_RECT_PITCH__SHIFT) | 119 card_swz); 120 if (unit == 0) 121 PUSH_DATA (push, NV30_3D_TEX_FILTER_SIGNED_ALPHA | 122 NV30_3D_TEX_FILTER_SIGNED_RED | 123 NV30_3D_TEX_FILTER_SIGNED_GREEN | 124 NV30_3D_TEX_FILTER_SIGNED_BLUE | 125 NV30_3D_TEX_FILTER_MIN_LINEAR | 126 NV30_3D_TEX_FILTER_MAG_LINEAR | 0x2000); 127 else 128 PUSH_DATA (push, NV30_3D_TEX_FILTER_MIN_LINEAR | 129 NV30_3D_TEX_FILTER_MAG_LINEAR | 0x2000); 130 PUSH_DATA (push, (width << NV30_3D_TEX_NPOT_SIZE_W__SHIFT) | height); 131 PUSH_DATA (push, 0); /* border ARGB */ 132 BEGIN_NV04(push, NV30_3D(TEX_MATRIX_ENABLE(unit)), 1); 133 PUSH_DATA (push, 0); 134 135 return TRUE; 136} 137 138static Bool 139NV30GetSurfaceFormat(PixmapPtr ppix, int *fmt_ret) 140{ 141 switch (ppix->drawable.bitsPerPixel) { 142 case 32: 143 *fmt_ret = NV30_3D_RT_FORMAT_COLOR_A8R8G8B8; 144 break; 145 case 24: 146 *fmt_ret = NV30_3D_RT_FORMAT_COLOR_X8R8G8B8; 147 break; 148 case 16: 149 *fmt_ret = NV30_3D_RT_FORMAT_COLOR_R5G6B5; 150 break; 151 case 8: 152 *fmt_ret = NV30_3D_RT_FORMAT_COLOR_B8; 153 break; 154 default: 155 return FALSE; 156 } 157 158 return TRUE; 159} 160 161void 162NV30StopTexturedVideo(ScrnInfoPtr pScrn, pointer data, Bool Exit) 163{ 164} 165 166#define VERTEX_OUT(sx,sy,dx,dy) do { \ 167 BEGIN_NV04(push, NV30_3D(VTX_ATTR_2F_X(8)), 4); \ 168 PUSH_DATAf(push, (sx)); PUSH_DATAf(push, (sy)); \ 169 PUSH_DATAf(push, (sx)/2.0); PUSH_DATAf(push, (sy)/2.0); \ 170 BEGIN_NV04(push, NV30_3D(VTX_ATTR_2I(0)), 1); \ 171 PUSH_DATA (push, (((dy)&0xffff)<<16)|((dx)&0xffff)); \ 172} while(0) 173 174int 175NV30PutTextureImage(ScrnInfoPtr pScrn, struct nouveau_bo *src, int src_offset, 176 int src_offset2, int id, int src_pitch, BoxPtr dstBox, 177 int x1, int y1, int x2, int y2, 178 uint16_t width, uint16_t height, 179 uint16_t src_w, uint16_t src_h, 180 uint16_t drw_w, uint16_t drw_h, 181 RegionPtr clipBoxes, 182 PixmapPtr ppix, 183 NVPortPrivPtr pPriv) 184{ 185 NVPtr pNv = NVPTR(pScrn); 186 struct nouveau_pushbuf *push = pNv->pushbuf; 187 struct nouveau_bo *bo = nouveau_pixmap_bo(ppix); 188 Bool bicubic = pPriv->bicubic; 189 float X1, X2, Y1, Y2; 190 BoxPtr pbox; 191 int nbox; 192 int dst_format = 0; 193 194 if (drw_w > 4096 || drw_h > 4096) { 195 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 196 "XV: Draw size too large.\n"); 197 return BadAlloc; 198 } 199 200 if (!NV30GetSurfaceFormat(ppix, &dst_format)) { 201 ErrorF("No surface format, bad.\n"); 202 return BadImplementation; 203 } 204 205 pbox = REGION_RECTS(clipBoxes); 206 nbox = REGION_NUM_RECTS(clipBoxes); 207 208 if (!PUSH_SPACE(push, 128)) 209 return FALSE; 210 PUSH_RESET(push); 211 212 BEGIN_NV04(push, NV30_3D(BLEND_FUNC_ENABLE), 1); 213 PUSH_DATA (push, 0); 214 BEGIN_NV04(push, NV30_3D(RT_FORMAT), 3); 215 PUSH_DATA (push, NV30_3D_RT_FORMAT_TYPE_LINEAR | 216 NV30_3D_RT_FORMAT_ZETA_Z24S8 | 217 dst_format); 218 PUSH_DATA (push, (exaGetPixmapPitch(ppix) << 16) | 219 exaGetPixmapPitch(ppix)); 220 PUSH_MTHDl(push, NV30_3D(COLOR0_OFFSET), bo, 0, 221 NOUVEAU_BO_VRAM | NOUVEAU_BO_WR); 222 223 if (pNv->dev->chipset == 0x30) { 224 int x = 0; 225 int y = 0; 226 int w = ppix->drawable.x + ppix->drawable.width; 227 int h = ppix->drawable.y + ppix->drawable.height; 228 229 BEGIN_NV04(push, NV30_3D(VIEWPORT_HORIZ), 2); 230 PUSH_DATA (push, (w<<16)|x); 231 PUSH_DATA (push, (h<<16)|y); 232 BEGIN_NV04(push, NV30_3D(VIEWPORT_CLIP_HORIZ(0)), 2); 233 PUSH_DATA (push, (w-1+x)<<16); 234 PUSH_DATA (push, (h-1+y)<<16); 235 BEGIN_NV04(push, NV30_3D(VIEWPORT_TX_ORIGIN), 1); 236 PUSH_DATA (push, (y<<16)|x); 237 } 238 239 BEGIN_NV04(push, NV30_3D(TEX_UNITS_ENABLE), 1); 240 PUSH_DATA (push, NV30_3D_TEX_UNITS_ENABLE_TX0 | 241 NV30_3D_TEX_UNITS_ENABLE_TX1); 242 243 if (!NV30VideoTexture(pScrn, pNv->scratch, XV_TABLE, XV_TABLE_SIZE, 244 1, 0, 0) || 245 !NV30VideoTexture(pScrn, src, src_offset, src_w, src_h, 246 src_pitch, 1)) 247 return BadImplementation; 248 249 /* We've got NV12 format, which means half width and half height 250 * texture of chroma channels. 251 */ 252 if (!NV30VideoTexture(pScrn, src, src_offset2, src_w/2, src_h/2, 253 src_pitch, 2)) { 254 PUSH_RESET(push); 255 return BadImplementation; 256 } 257 258 BEGIN_NV04(push, NV30_3D(TEX_ENABLE(3)), 1); 259 PUSH_DATA (push, 0x0); 260 261 if (drw_w / 2 < src_w || drw_h / 2 < src_h) 262 bicubic = FALSE; 263 264 BEGIN_NV04(push, NV30_3D(FP_ACTIVE_PROGRAM), 1); 265 PUSH_MTHD (push, NV30_3D(FP_ACTIVE_PROGRAM), pNv->scratch, 266 bicubic ? PFP_NV12_BICUBIC : PFP_NV12_BILINEAR, 267 NOUVEAU_BO_VRAM | NOUVEAU_BO_RD | NOUVEAU_BO_LOW | 268 NOUVEAU_BO_OR, 269 NV30_3D_FP_ACTIVE_PROGRAM_DMA0, 270 NV30_3D_FP_ACTIVE_PROGRAM_DMA1); 271 BEGIN_NV04(push, NV30_3D(FP_REG_CONTROL), 1); 272 PUSH_DATA (push, 0x0001000f); 273 BEGIN_NV04(push, NV30_3D(FP_CONTROL), 1); 274 PUSH_DATA (push, 0x00000001); 275 BEGIN_NV04(push, NV30_3D(RC_ENABLE), 1); 276 PUSH_DATA (push, 0x00000000); 277 278 nouveau_pushbuf_bufctx(push, pNv->bufctx); 279 if (nouveau_pushbuf_validate(push)) { 280 nouveau_pushbuf_bufctx(push, NULL); 281 return BadAlloc; 282 } 283 284 /* Before rendering we wait for vblank in the non-composited case. */ 285 if (pPriv->SyncToVBlank) 286 NV11SyncToVBlank(ppix, dstBox); 287 288 /* These are fixed point values in the 16.16 format. */ 289 X1 = (float)(x1>>16)+(float)(x1&0xFFFF)/(float)0x10000; 290 Y1 = (float)(y1>>16)+(float)(y1&0xFFFF)/(float)0x10000; 291 X2 = (float)(x2>>16)+(float)(x2&0xFFFF)/(float)0x10000; 292 Y2 = (float)(y2>>16)+(float)(y2&0xFFFF)/(float)0x10000; 293 294 BEGIN_NV04(push, NV30_3D(VERTEX_BEGIN_END), 1); 295 PUSH_DATA (push, NV30_3D_VERTEX_BEGIN_END_TRIANGLES); 296 while (nbox--) { 297 float tx1=X1+(float)(pbox->x1 - dstBox->x1)*(X2-X1)/(float)(drw_w); 298 float tx2=X1+(float)(pbox->x2 - dstBox->x1)*(src_w)/(float)(drw_w); 299 float ty1=Y1+(float)(pbox->y1 - dstBox->y1)*(Y2-Y1)/(float)(drw_h); 300 float ty2=Y1+(float)(pbox->y2 - dstBox->y1)*(src_h)/(float)(drw_h); 301 int sx1=pbox->x1; 302 int sx2=pbox->x2; 303 int sy1=pbox->y1; 304 int sy2=pbox->y2; 305 306 if (!PUSH_SPACE(push, 64)) { 307 nouveau_pushbuf_bufctx(push, NULL); 308 return BadImplementation; 309 } 310 311 BEGIN_NV04(push, NV30_3D(SCISSOR_HORIZ), 2); 312 PUSH_DATA (push, (sx2 << 16) | 0); 313 PUSH_DATA (push, (sy2 << 16) | 0); 314 315 VERTEX_OUT(tx1, ty1, sx1, sy1); 316 VERTEX_OUT(tx2+(tx2-tx1), ty1, sx2+(sx2-sx1), sy1); 317 VERTEX_OUT(tx1, ty2+(ty2-ty1), sx1, sy2+(sy2-sy1)); 318 319 pbox++; 320 } 321 BEGIN_NV04(push, NV30_3D(VERTEX_BEGIN_END), 1); 322 PUSH_DATA (push, NV30_3D_VERTEX_BEGIN_END_STOP); 323 324 if (pNv->dev->chipset == 0x30) { 325 BEGIN_NV04(push, NV30_3D(VIEWPORT_HORIZ), 2); 326 PUSH_DATA (push, 4096 << 16); 327 PUSH_DATA (push, 4096 << 16); 328 BEGIN_NV04(push, NV30_3D(VIEWPORT_CLIP_HORIZ(0)), 2); 329 PUSH_DATA (push, 4095 << 16); 330 PUSH_DATA (push, 4095 << 16); 331 BEGIN_NV04(push, NV30_3D(VIEWPORT_TX_ORIGIN), 1); 332 PUSH_DATA (push, 0); 333 } 334 335 nouveau_pushbuf_bufctx(push, NULL); 336 PUSH_KICK(push); 337 return Success; 338} 339 340/** 341 * NV30SetTexturePortAttribute 342 * sets the attribute "attribute" of port "data" to value "value" 343 * supported attributes: 344 * Sync to vblank. 345 * 346 * @param pScrenInfo 347 * @param attribute attribute to set 348 * @param value value to which attribute is to be set 349 * @param data port from which the attribute is to be set 350 * 351 * @return Success, if setting is successful 352 * BadValue/BadMatch, if value/attribute are invalid 353 */ 354int 355NV30SetTexturePortAttribute(ScrnInfoPtr pScrn, Atom attribute, 356 INT32 value, pointer data) 357{ 358 NVPortPrivPtr pPriv = (NVPortPrivPtr)data; 359 360 if (attribute == xvSyncToVBlank) { 361 if ((value < 0) || (value > 1)) 362 return BadValue; 363 pPriv->SyncToVBlank = value; 364 } else 365 if (attribute == xvSetDefaults) { 366 pPriv->SyncToVBlank = TRUE; 367 } else 368 return BadMatch; 369 370 return Success; 371} 372 373/** 374 * NV30GetTexturePortAttribute 375 * reads the value of attribute "attribute" from port "data" into INT32 "*value" 376 * Sync to vblank. 377 * 378 * @param pScrn unused 379 * @param attribute attribute to be read 380 * @param value value of attribute will be stored here 381 * @param data port from which attribute will be read 382 * @return Success, if queried attribute exists 383 */ 384int 385NV30GetTexturePortAttribute(ScrnInfoPtr pScrn, Atom attribute, 386 INT32 *value, pointer data) 387{ 388 NVPortPrivPtr pPriv = (NVPortPrivPtr)data; 389 390 if(attribute == xvSyncToVBlank) 391 *value = (pPriv->SyncToVBlank) ? 1 : 0; 392 else 393 return BadMatch; 394 395 return Success; 396} 397 398