radeon_textured_video.c revision 209ff23f
1/* 2 * Copyright 2008 Alex Deucher 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 FROM, 20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 * SOFTWARE. 22 * 23 * 24 * Based on radeon_exa_render.c and kdrive ati_video.c by Eric Anholt, et al. 25 * 26 */ 27 28#ifdef HAVE_CONFIG_H 29#include "config.h" 30#endif 31 32#include <stdlib.h> 33#include <string.h> 34#include <stdio.h> 35#include <math.h> 36 37#include "radeon.h" 38#include "radeon_reg.h" 39#include "radeon_macros.h" 40#include "radeon_probe.h" 41#include "radeon_video.h" 42 43#include <X11/extensions/Xv.h> 44#include "fourcc.h" 45 46#define IMAGE_MAX_WIDTH 2048 47#define IMAGE_MAX_HEIGHT 2048 48 49#define IMAGE_MAX_WIDTH_R500 4096 50#define IMAGE_MAX_HEIGHT_R500 4096 51 52static Bool 53RADEONTilingEnabled(ScrnInfoPtr pScrn, PixmapPtr pPix) 54{ 55 RADEONInfoPtr info = RADEONPTR(pScrn); 56 57#ifdef USE_EXA 58 if (info->useEXA) { 59 if (info->tilingEnabled && exaGetPixmapOffset(pPix) == 0) 60 return TRUE; 61 else 62 return FALSE; 63 } else 64#endif 65 { 66 if (info->tilingEnabled && ((pPix->devPrivate.ptr - info->FB) == 0)) 67 return TRUE; 68 else 69 return FALSE; 70 } 71} 72 73static __inline__ uint32_t F_TO_DW(float val) 74{ 75 union { 76 float f; 77 uint32_t l; 78 } tmp; 79 tmp.f = val; 80 return tmp.l; 81} 82 83#define ACCEL_MMIO 84#define VIDEO_PREAMBLE() unsigned char *RADEONMMIO = info->MMIO 85#define BEGIN_VIDEO(n) RADEONWaitForFifo(pScrn, (n)) 86#define OUT_VIDEO_REG(reg, val) OUTREG(reg, val) 87#define OUT_VIDEO_REG_F(reg, val) OUTREG(reg, F_TO_DW(val)) 88#define FINISH_VIDEO() 89 90#include "radeon_textured_videofuncs.c" 91 92#undef ACCEL_MMIO 93#undef VIDEO_PREAMBLE 94#undef BEGIN_VIDEO 95#undef OUT_VIDEO_REG 96#undef FINISH_VIDEO 97 98#ifdef XF86DRI 99 100#define ACCEL_CP 101#define VIDEO_PREAMBLE() \ 102 RING_LOCALS; \ 103 RADEONCP_REFRESH(pScrn, info) 104#define BEGIN_VIDEO(n) BEGIN_RING(2*(n)) 105#define OUT_VIDEO_REG(reg, val) OUT_RING_REG(reg, val) 106#define FINISH_VIDEO() ADVANCE_RING() 107#define OUT_VIDEO_RING_F(x) OUT_RING(F_TO_DW(x)) 108 109#include "radeon_textured_videofuncs.c" 110 111#endif /* XF86DRI */ 112 113static int 114RADEONPutImageTextured(ScrnInfoPtr pScrn, 115 short src_x, short src_y, 116 short drw_x, short drw_y, 117 short src_w, short src_h, 118 short drw_w, short drw_h, 119 int id, 120 unsigned char *buf, 121 short width, 122 short height, 123 Bool sync, 124 RegionPtr clipBoxes, 125 pointer data, 126 DrawablePtr pDraw) 127{ 128 ScreenPtr pScreen = pScrn->pScreen; 129 RADEONInfoPtr info = RADEONPTR(pScrn); 130 RADEONPortPrivPtr pPriv = (RADEONPortPrivPtr)data; 131 INT32 x1, x2, y1, y2; 132 int srcPitch, srcPitch2, dstPitch; 133 int s2offset, s3offset, tmp; 134 int top, left, npixels, nlines, size; 135 BoxRec dstBox; 136 int dst_width = width, dst_height = height; 137 138 /* make the compiler happy */ 139 s2offset = s3offset = srcPitch2 = 0; 140 141 /* Clip */ 142 x1 = src_x; 143 x2 = src_x + src_w; 144 y1 = src_y; 145 y2 = src_y + src_h; 146 147 dstBox.x1 = drw_x; 148 dstBox.x2 = drw_x + drw_w; 149 dstBox.y1 = drw_y; 150 dstBox.y2 = drw_y + drw_h; 151 152 if (!xf86XVClipVideoHelper(&dstBox, &x1, &x2, &y1, &y2, clipBoxes, width, height)) 153 return Success; 154 155 src_w = (x2 - x1) >> 16; 156 src_h = (y2 - y1) >> 16; 157 drw_w = dstBox.x2 - dstBox.x1; 158 drw_h = dstBox.y2 - dstBox.y1; 159 160 if ((x1 >= x2) || (y1 >= y2)) 161 return Success; 162 163 switch(id) { 164 case FOURCC_YV12: 165 case FOURCC_I420: 166 dstPitch = ((dst_width << 1) + 15) & ~15; 167 srcPitch = (width + 3) & ~3; 168 srcPitch2 = ((width >> 1) + 3) & ~3; 169 size = dstPitch * dst_height; 170 break; 171 case FOURCC_UYVY: 172 case FOURCC_YUY2: 173 default: 174 dstPitch = ((dst_width << 1) + 15) & ~15; 175 srcPitch = (width << 1); 176 srcPitch2 = 0; 177 size = dstPitch * dst_height; 178 break; 179 } 180 181#ifdef XF86DRI 182 if (info->directRenderingEnabled && info->DMAForXv) 183 /* The upload blit only supports multiples of 64 bytes */ 184 dstPitch = (dstPitch + 63) & ~63; 185 else 186#endif 187 dstPitch = (dstPitch + 15) & ~15; 188 189 if (pPriv->video_memory != NULL && size != pPriv->size) { 190 RADEONFreeMemory(pScrn, pPriv->video_memory); 191 pPriv->video_memory = NULL; 192 } 193 194 if (pPriv->video_memory == NULL) { 195 pPriv->video_offset = RADEONAllocateMemory(pScrn, 196 &pPriv->video_memory, 197 size * 2); 198 if (pPriv->video_offset == 0) 199 return BadAlloc; 200 } 201 202 if (pDraw->type == DRAWABLE_WINDOW) 203 pPriv->pPixmap = (*pScreen->GetWindowPixmap)((WindowPtr)pDraw); 204 else 205 pPriv->pPixmap = (PixmapPtr)pDraw; 206 207#ifdef USE_EXA 208 if (info->useEXA) { 209 /* Force the pixmap into framebuffer so we can draw to it. */ 210 exaMoveInPixmap(pPriv->pPixmap); 211 } 212#endif 213 214 if (!info->useEXA && 215 (((char *)pPriv->pPixmap->devPrivate.ptr < (char *)info->FB) || 216 ((char *)pPriv->pPixmap->devPrivate.ptr >= (char *)info->FB + 217 info->FbMapSize))) { 218 /* If the pixmap wasn't in framebuffer, then we have no way in XAA to 219 * force it there. So, we simply refuse to draw and fail. 220 */ 221 return BadAlloc; 222 } 223 224 /* copy data */ 225 top = y1 >> 16; 226 left = (x1 >> 16) & ~1; 227 npixels = ((((x2 + 0xffff) >> 16) + 1) & ~1) - left; 228 229 pPriv->src_offset = pPriv->video_offset + info->fbLocation + pScrn->fbOffset; 230 pPriv->src_addr = (uint8_t *)(info->FB + pPriv->video_offset + (top * dstPitch)); 231 pPriv->src_pitch = dstPitch; 232 pPriv->size = size; 233 pPriv->pDraw = pDraw; 234 235#if 0 236 ErrorF("src_offset: 0x%x\n", pPriv->src_offset); 237 ErrorF("src_addr: 0x%x\n", pPriv->src_addr); 238 ErrorF("src_pitch: 0x%x\n", pPriv->src_pitch); 239#endif 240 241 switch(id) { 242 case FOURCC_YV12: 243 case FOURCC_I420: 244 top &= ~1; 245 nlines = ((((y2 + 0xffff) >> 16) + 1) & ~1) - top; 246 s2offset = srcPitch * height; 247 s3offset = (srcPitch2 * (height >> 1)) + s2offset; 248 top &= ~1; 249 pPriv->src_addr += left << 1; 250 tmp = ((top >> 1) * srcPitch2) + (left >> 1); 251 s2offset += tmp; 252 s3offset += tmp; 253 if (id == FOURCC_I420) { 254 tmp = s2offset; 255 s2offset = s3offset; 256 s3offset = tmp; 257 } 258 RADEONCopyMungedData(pScrn, buf + (top * srcPitch) + left, 259 buf + s2offset, buf + s3offset, pPriv->src_addr, 260 srcPitch, srcPitch2, dstPitch, nlines, npixels); 261 break; 262 case FOURCC_UYVY: 263 case FOURCC_YUY2: 264 default: 265 nlines = ((y2 + 0xffff) >> 16) - top; 266 RADEONCopyData(pScrn, buf, pPriv->src_addr, srcPitch, dstPitch, nlines, npixels, 2); 267 break; 268 } 269 270 /* update cliplist */ 271 if (!REGION_EQUAL(pScrn->pScreen, &pPriv->clip, clipBoxes)) { 272 REGION_COPY(pScrn->pScreen, &pPriv->clip, clipBoxes); 273 } 274 275 pPriv->id = id; 276 pPriv->src_w = src_w; 277 pPriv->src_h = src_h; 278 pPriv->drw_x = drw_x; 279 pPriv->drw_y = drw_y; 280 pPriv->dst_w = drw_w; 281 pPriv->dst_h = drw_h; 282 pPriv->w = width; 283 pPriv->h = height; 284 285#ifdef XF86DRI 286 if (info->directRenderingEnabled) 287 RADEONDisplayTexturedVideoCP(pScrn, pPriv); 288 else 289#endif 290 RADEONDisplayTexturedVideoMMIO(pScrn, pPriv); 291 292 return Success; 293} 294 295/* client libraries expect an encoding */ 296static XF86VideoEncodingRec DummyEncoding[1] = 297{ 298 { 299 0, 300 "XV_IMAGE", 301 IMAGE_MAX_WIDTH, IMAGE_MAX_HEIGHT, 302 {1, 1} 303 } 304}; 305 306static XF86VideoEncodingRec DummyEncodingR500[1] = 307{ 308 { 309 0, 310 "XV_IMAGE", 311 IMAGE_MAX_WIDTH_R500, IMAGE_MAX_HEIGHT_R500, 312 {1, 1} 313 } 314}; 315 316#define NUM_FORMATS 3 317 318static XF86VideoFormatRec Formats[NUM_FORMATS] = 319{ 320 {15, TrueColor}, {16, TrueColor}, {24, TrueColor} 321}; 322 323#define NUM_ATTRIBUTES 0 324 325static XF86AttributeRec Attributes[NUM_ATTRIBUTES] = 326{ 327}; 328 329#define NUM_IMAGES 4 330 331static XF86ImageRec Images[NUM_IMAGES] = 332{ 333 XVIMAGE_YUY2, 334 XVIMAGE_YV12, 335 XVIMAGE_I420, 336 XVIMAGE_UYVY 337}; 338 339XF86VideoAdaptorPtr 340RADEONSetupImageTexturedVideo(ScreenPtr pScreen) 341{ 342 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; 343 RADEONInfoPtr info = RADEONPTR(pScrn); 344 RADEONPortPrivPtr pPortPriv; 345 XF86VideoAdaptorPtr adapt; 346 int i; 347 int num_texture_ports = 16; 348 349 adapt = xcalloc(1, sizeof(XF86VideoAdaptorRec) + num_texture_ports * 350 (sizeof(RADEONPortPrivRec) + sizeof(DevUnion))); 351 if (adapt == NULL) 352 return NULL; 353 354 adapt->type = XvWindowMask | XvInputMask | XvImageMask; 355 adapt->flags = 0; 356 adapt->name = "Radeon Textured Video"; 357 adapt->nEncodings = 1; 358 if (IS_R500_3D) 359 adapt->pEncodings = DummyEncodingR500; 360 else 361 adapt->pEncodings = DummyEncoding; 362 adapt->nFormats = NUM_FORMATS; 363 adapt->pFormats = Formats; 364 adapt->nPorts = num_texture_ports; 365 adapt->pPortPrivates = (DevUnion*)(&adapt[1]); 366 367 pPortPriv = 368 (RADEONPortPrivPtr)(&adapt->pPortPrivates[num_texture_ports]); 369 370 adapt->nAttributes = NUM_ATTRIBUTES; 371 adapt->pAttributes = Attributes; 372 adapt->pImages = Images; 373 adapt->nImages = NUM_IMAGES; 374 adapt->PutVideo = NULL; 375 adapt->PutStill = NULL; 376 adapt->GetVideo = NULL; 377 adapt->GetStill = NULL; 378 adapt->StopVideo = RADEONStopVideo; 379 adapt->SetPortAttribute = RADEONSetPortAttribute; 380 adapt->GetPortAttribute = RADEONGetPortAttribute; 381 adapt->QueryBestSize = RADEONQueryBestSize; 382 adapt->PutImage = RADEONPutImageTextured; 383 adapt->ReputImage = NULL; 384 adapt->QueryImageAttributes = RADEONQueryImageAttributes; 385 386 for (i = 0; i < num_texture_ports; i++) { 387 RADEONPortPrivPtr pPriv = &pPortPriv[i]; 388 389 pPriv->textured = TRUE; 390 pPriv->videoStatus = 0; 391 pPriv->currentBuffer = 0; 392 pPriv->doubleBuffer = 0; 393 394 /* gotta uninit this someplace, XXX: shouldn't be necessary for textured */ 395 REGION_NULL(pScreen, &pPriv->clip); 396 adapt->pPortPrivates[i].ptr = (pointer) (pPriv); 397 } 398 399 return adapt; 400} 401 402