savage_state.c revision 152909
123353Sdfr/* savage_state.c -- State and drawing support for Savage 223353Sdfr * 323353Sdfr * Copyright 2004 Felix Kuehling 423353Sdfr * All Rights Reserved. 523353Sdfr * 623353Sdfr * Permission is hereby granted, free of charge, to any person obtaining a 723353Sdfr * copy of this software and associated documentation files (the "Software"), 823353Sdfr * to deal in the Software without restriction, including without limitation 923353Sdfr * the rights to use, copy, modify, merge, publish, distribute, sub license, 1023353Sdfr * and/or sell copies of the Software, and to permit persons to whom the 1123353Sdfr * Software is furnished to do so, subject to the following conditions: 1223353Sdfr * 1323353Sdfr * The above copyright notice and this permission notice (including the 1423353Sdfr * next paragraph) shall be included in all copies or substantial portions 1523353Sdfr * of the Software. 1623353Sdfr * 1723353Sdfr * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 1823353Sdfr * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 1923353Sdfr * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 2023353Sdfr * NON-INFRINGEMENT. IN NO EVENT SHALL FELIX KUEHLING BE LIABLE FOR 2123353Sdfr * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 2223353Sdfr * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 2323353Sdfr * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 2423353Sdfr */ 2523353Sdfr 2623353Sdfr#include <sys/cdefs.h> 2723353Sdfr__FBSDID("$FreeBSD: head/sys/dev/drm/savage_state.c 152909 2005-11-28 23:13:57Z anholt $"); 2823353Sdfr#include "dev/drm/drmP.h" 2950476Speter#include "dev/drm/savage_drm.h" 3023353Sdfr#include "dev/drm/savage_drv.h" 3123353Sdfr 32206622Suqsvoid savage_emit_clip_rect_s3d(drm_savage_private_t *dev_priv, 3323353Sdfr const drm_clip_rect_t *pbox) 3423353Sdfr{ 3523353Sdfr uint32_t scstart = dev_priv->state.s3d.new_scstart; 3623353Sdfr uint32_t scend = dev_priv->state.s3d.new_scend; 3723353Sdfr scstart = (scstart & ~SAVAGE_SCISSOR_MASK_S3D) | 3823353Sdfr ((uint32_t)pbox->x1 & 0x000007ff) | 3984306Sru (((uint32_t)pbox->y1 << 16) & 0x07ff0000); 4084306Sru scend = (scend & ~SAVAGE_SCISSOR_MASK_S3D) | 4184306Sru (((uint32_t)pbox->x2-1) & 0x000007ff) | 4223353Sdfr ((((uint32_t)pbox->y2-1) << 16) & 0x07ff0000); 4323353Sdfr if (scstart != dev_priv->state.s3d.scstart || 4423353Sdfr scend != dev_priv->state.s3d.scend) { 4523353Sdfr DMA_LOCALS; 4623353Sdfr BEGIN_DMA(4); 4723353Sdfr DMA_WRITE(BCI_CMD_WAIT|BCI_CMD_WAIT_3D); 4823353Sdfr DMA_SET_REGISTERS(SAVAGE_SCSTART_S3D, 2); 4923353Sdfr DMA_WRITE(scstart); 5023353Sdfr DMA_WRITE(scend); 51115440Shmp dev_priv->state.s3d.scstart = scstart; 52140931Sru dev_priv->state.s3d.scend = scend; 53115440Shmp dev_priv->waiting = 1; 54140931Sru DMA_COMMIT(); 55115440Shmp } 56140931Sru} 57115440Shmp 58140931Sruvoid savage_emit_clip_rect_s4(drm_savage_private_t *dev_priv, 5923353Sdfr const drm_clip_rect_t *pbox) 6023353Sdfr{ 6123353Sdfr uint32_t drawctrl0 = dev_priv->state.s4.new_drawctrl0; 6223353Sdfr uint32_t drawctrl1 = dev_priv->state.s4.new_drawctrl1; 63107788Sru drawctrl0 = (drawctrl0 & ~SAVAGE_SCISSOR_MASK_S4) | 6454533Salfred ((uint32_t)pbox->x1 & 0x000007ff) | 65107788Sru (((uint32_t)pbox->y1 << 12) & 0x00fff000); 66121382Shmp drawctrl1 = (drawctrl1 & ~SAVAGE_SCISSOR_MASK_S4) | 67121382Shmp (((uint32_t)pbox->x2-1) & 0x000007ff) | 6854533Salfred ((((uint32_t)pbox->y2-1) << 12) & 0x00fff000); 69140931Sru if (drawctrl0 != dev_priv->state.s4.drawctrl0 || 7023353Sdfr drawctrl1 != dev_priv->state.s4.drawctrl1) { 71140931Sru DMA_LOCALS; 7223353Sdfr BEGIN_DMA(4); 73140931Sru DMA_WRITE(BCI_CMD_WAIT|BCI_CMD_WAIT_3D); 7423353Sdfr DMA_SET_REGISTERS(SAVAGE_DRAWCTRL0_S4, 2); 75140931Sru DMA_WRITE(drawctrl0); 7623353Sdfr DMA_WRITE(drawctrl1); 77140931Sru dev_priv->state.s4.drawctrl0 = drawctrl0; 7823353Sdfr dev_priv->state.s4.drawctrl1 = drawctrl1; 7923353Sdfr dev_priv->waiting = 1; 80140931Sru DMA_COMMIT(); 8123353Sdfr } 82140931Sru} 8323353Sdfr 8423353Sdfrstatic int savage_verify_texaddr(drm_savage_private_t *dev_priv, int unit, 8523353Sdfr uint32_t addr) 8623353Sdfr{ 8723353Sdfr if ((addr & 6) != 2) { /* reserved bits */ 8823353Sdfr DRM_ERROR("bad texAddr%d %08x (reserved bits)\n", unit, addr); 8923467Smpp return DRM_ERR(EINVAL); 9078278Srwatson } 9178278Srwatson if (!(addr & 1)) { /* local */ 9278278Srwatson addr &= ~7; 9323353Sdfr if (addr < dev_priv->texture_offset || 94107788Sru addr >= dev_priv->texture_offset+dev_priv->texture_size) { 9578278Srwatson DRM_ERROR("bad texAddr%d %08x (local addr out of range)\n", 9678278Srwatson unit, addr); 9778278Srwatson return DRM_ERR(EINVAL); 9823353Sdfr } 9923353Sdfr } else { /* AGP */ 10029966Swosch if (!dev_priv->agp_textures) { 10129966Swosch DRM_ERROR("bad texAddr%d %08x (AGP not available)\n", 10223353Sdfr unit, addr); 103147647Shmp return DRM_ERR(EINVAL); 10434504Scharnier } 105 addr &= ~7; 106 if (addr < dev_priv->agp_textures->offset || 107 addr >= (dev_priv->agp_textures->offset + 108 dev_priv->agp_textures->size)) { 109 DRM_ERROR("bad texAddr%d %08x (AGP addr out of range)\n", 110 unit, addr); 111 return DRM_ERR(EINVAL); 112 } 113 } 114 return 0; 115} 116 117#define SAVE_STATE(reg,where) \ 118 if(start <= reg && start+count > reg) \ 119 dev_priv->state.where = regs[reg - start] 120#define SAVE_STATE_MASK(reg,where,mask) do { \ 121 if(start <= reg && start+count > reg) { \ 122 uint32_t tmp; \ 123 tmp = regs[reg - start]; \ 124 dev_priv->state.where = (tmp & (mask)) | \ 125 (dev_priv->state.where & ~(mask)); \ 126 } \ 127} while (0) 128static int savage_verify_state_s3d(drm_savage_private_t *dev_priv, 129 unsigned int start, unsigned int count, 130 const uint32_t *regs) 131{ 132 if (start < SAVAGE_TEXPALADDR_S3D || 133 start+count-1 > SAVAGE_DESTTEXRWWATERMARK_S3D) { 134 DRM_ERROR("invalid register range (0x%04x-0x%04x)\n", 135 start, start+count-1); 136 return DRM_ERR(EINVAL); 137 } 138 139 SAVE_STATE_MASK(SAVAGE_SCSTART_S3D, s3d.new_scstart, 140 ~SAVAGE_SCISSOR_MASK_S3D); 141 SAVE_STATE_MASK(SAVAGE_SCEND_S3D, s3d.new_scend, 142 ~SAVAGE_SCISSOR_MASK_S3D); 143 144 /* if any texture regs were changed ... */ 145 if (start <= SAVAGE_TEXCTRL_S3D && 146 start+count > SAVAGE_TEXPALADDR_S3D) { 147 /* ... check texture state */ 148 SAVE_STATE(SAVAGE_TEXCTRL_S3D, s3d.texctrl); 149 SAVE_STATE(SAVAGE_TEXADDR_S3D, s3d.texaddr); 150 if (dev_priv->state.s3d.texctrl & SAVAGE_TEXCTRL_TEXEN_MASK) 151 return savage_verify_texaddr( 152 dev_priv, 0, dev_priv->state.s3d.texaddr); 153 } 154 155 return 0; 156} 157 158static int savage_verify_state_s4(drm_savage_private_t *dev_priv, 159 unsigned int start, unsigned int count, 160 const uint32_t *regs) 161{ 162 int ret = 0; 163 164 if (start < SAVAGE_DRAWLOCALCTRL_S4 || 165 start+count-1 > SAVAGE_TEXBLENDCOLOR_S4) { 166 DRM_ERROR("invalid register range (0x%04x-0x%04x)\n", 167 start, start+count-1); 168 return DRM_ERR(EINVAL); 169 } 170 171 SAVE_STATE_MASK(SAVAGE_DRAWCTRL0_S4, s4.new_drawctrl0, 172 ~SAVAGE_SCISSOR_MASK_S4); 173 SAVE_STATE_MASK(SAVAGE_DRAWCTRL1_S4, s4.new_drawctrl1, 174 ~SAVAGE_SCISSOR_MASK_S4); 175 176 /* if any texture regs were changed ... */ 177 if (start <= SAVAGE_TEXDESCR_S4 && 178 start+count > SAVAGE_TEXPALADDR_S4) { 179 /* ... check texture state */ 180 SAVE_STATE(SAVAGE_TEXDESCR_S4, s4.texdescr); 181 SAVE_STATE(SAVAGE_TEXADDR0_S4, s4.texaddr0); 182 SAVE_STATE(SAVAGE_TEXADDR1_S4, s4.texaddr1); 183 if (dev_priv->state.s4.texdescr & SAVAGE_TEXDESCR_TEX0EN_MASK) 184 ret |= savage_verify_texaddr( 185 dev_priv, 0, dev_priv->state.s4.texaddr0); 186 if (dev_priv->state.s4.texdescr & SAVAGE_TEXDESCR_TEX1EN_MASK) 187 ret |= savage_verify_texaddr( 188 dev_priv, 1, dev_priv->state.s4.texaddr1); 189 } 190 191 return ret; 192} 193#undef SAVE_STATE 194#undef SAVE_STATE_MASK 195 196static int savage_dispatch_state(drm_savage_private_t *dev_priv, 197 const drm_savage_cmd_header_t *cmd_header, 198 const uint32_t *regs) 199{ 200 unsigned int count = cmd_header->state.count; 201 unsigned int start = cmd_header->state.start; 202 unsigned int count2 = 0; 203 unsigned int bci_size; 204 int ret; 205 DMA_LOCALS; 206 207 if (!count) 208 return 0; 209 210 if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) { 211 ret = savage_verify_state_s3d(dev_priv, start, count, regs); 212 if (ret != 0) 213 return ret; 214 /* scissor regs are emitted in savage_dispatch_draw */ 215 if (start < SAVAGE_SCSTART_S3D) { 216 if (start+count > SAVAGE_SCEND_S3D+1) 217 count2 = count - (SAVAGE_SCEND_S3D+1 - start); 218 if (start+count > SAVAGE_SCSTART_S3D) 219 count = SAVAGE_SCSTART_S3D - start; 220 } else if (start <= SAVAGE_SCEND_S3D) { 221 if (start+count > SAVAGE_SCEND_S3D+1) { 222 count -= SAVAGE_SCEND_S3D+1 - start; 223 start = SAVAGE_SCEND_S3D+1; 224 } else 225 return 0; 226 } 227 } else { 228 ret = savage_verify_state_s4(dev_priv, start, count, regs); 229 if (ret != 0) 230 return ret; 231 /* scissor regs are emitted in savage_dispatch_draw */ 232 if (start < SAVAGE_DRAWCTRL0_S4) { 233 if (start+count > SAVAGE_DRAWCTRL1_S4+1) 234 count2 = count - (SAVAGE_DRAWCTRL1_S4+1 - start); 235 if (start+count > SAVAGE_DRAWCTRL0_S4) 236 count = SAVAGE_DRAWCTRL0_S4 - start; 237 } else if (start <= SAVAGE_DRAWCTRL1_S4) { 238 if (start+count > SAVAGE_DRAWCTRL1_S4+1) { 239 count -= SAVAGE_DRAWCTRL1_S4+1 - start; 240 start = SAVAGE_DRAWCTRL1_S4+1; 241 } else 242 return 0; 243 } 244 } 245 246 bci_size = count + (count+254)/255 + count2 + (count2+254)/255; 247 248 if (cmd_header->state.global) { 249 BEGIN_DMA(bci_size+1); 250 DMA_WRITE(BCI_CMD_WAIT | BCI_CMD_WAIT_3D); 251 dev_priv->waiting = 1; 252 } else { 253 BEGIN_DMA(bci_size); 254 } 255 256 do { 257 while (count > 0) { 258 unsigned int n = count < 255 ? count : 255; 259 DMA_SET_REGISTERS(start, n); 260 DMA_COPY(regs, n); 261 count -= n; 262 start += n; 263 regs += n; 264 } 265 start += 2; 266 regs += 2; 267 count = count2; 268 count2 = 0; 269 } while (count); 270 271 DMA_COMMIT(); 272 273 return 0; 274} 275 276static int savage_dispatch_dma_prim(drm_savage_private_t *dev_priv, 277 const drm_savage_cmd_header_t *cmd_header, 278 const drm_buf_t *dmabuf) 279{ 280 unsigned char reorder = 0; 281 unsigned int prim = cmd_header->prim.prim; 282 unsigned int skip = cmd_header->prim.skip; 283 unsigned int n = cmd_header->prim.count; 284 unsigned int start = cmd_header->prim.start; 285 unsigned int i; 286 BCI_LOCALS; 287 288 if (!dmabuf) { 289 DRM_ERROR("called without dma buffers!\n"); 290 return DRM_ERR(EINVAL); 291 } 292 293 if (!n) 294 return 0; 295 296 switch (prim) { 297 case SAVAGE_PRIM_TRILIST_201: 298 reorder = 1; 299 prim = SAVAGE_PRIM_TRILIST; 300 case SAVAGE_PRIM_TRILIST: 301 if (n % 3 != 0) { 302 DRM_ERROR("wrong number of vertices %u in TRILIST\n", 303 n); 304 return DRM_ERR(EINVAL); 305 } 306 break; 307 case SAVAGE_PRIM_TRISTRIP: 308 case SAVAGE_PRIM_TRIFAN: 309 if (n < 3) { 310 DRM_ERROR("wrong number of vertices %u in TRIFAN/STRIP\n", 311 n); 312 return DRM_ERR(EINVAL); 313 } 314 break; 315 default: 316 DRM_ERROR("invalid primitive type %u\n", prim); 317 return DRM_ERR(EINVAL); 318 } 319 320 if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) { 321 if (skip != 0) { 322 DRM_ERROR("invalid skip flags 0x%04x for DMA\n", 323 skip); 324 return DRM_ERR(EINVAL); 325 } 326 } else { 327 unsigned int size = 10 - (skip & 1) - (skip >> 1 & 1) - 328 (skip >> 2 & 1) - (skip >> 3 & 1) - (skip >> 4 & 1) - 329 (skip >> 5 & 1) - (skip >> 6 & 1) - (skip >> 7 & 1); 330 if (skip > SAVAGE_SKIP_ALL_S4 || size != 8) { 331 DRM_ERROR("invalid skip flags 0x%04x for DMA\n", 332 skip); 333 return DRM_ERR(EINVAL); 334 } 335 if (reorder) { 336 DRM_ERROR("TRILIST_201 used on Savage4 hardware\n"); 337 return DRM_ERR(EINVAL); 338 } 339 } 340 341 if (start + n > dmabuf->total/32) { 342 DRM_ERROR("vertex indices (%u-%u) out of range (0-%u)\n", 343 start, start + n - 1, dmabuf->total/32); 344 return DRM_ERR(EINVAL); 345 } 346 347 /* Vertex DMA doesn't work with command DMA at the same time, 348 * so we use BCI_... to submit commands here. Flush buffered 349 * faked DMA first. */ 350 DMA_FLUSH(); 351 352 if (dmabuf->bus_address != dev_priv->state.common.vbaddr) { 353 BEGIN_BCI(2); 354 BCI_SET_REGISTERS(SAVAGE_VERTBUFADDR, 1); 355 BCI_WRITE(dmabuf->bus_address | dev_priv->dma_type); 356 dev_priv->state.common.vbaddr = dmabuf->bus_address; 357 } 358 if (S3_SAVAGE3D_SERIES(dev_priv->chipset) && dev_priv->waiting) { 359 /* Workaround for what looks like a hardware bug. If a 360 * WAIT_3D_IDLE was emitted some time before the 361 * indexed drawing command then the engine will lock 362 * up. There are two known workarounds: 363 * WAIT_IDLE_EMPTY or emit at least 63 NOPs. */ 364 BEGIN_BCI(63); 365 for (i = 0; i < 63; ++i) 366 BCI_WRITE(BCI_CMD_WAIT); 367 dev_priv->waiting = 0; 368 } 369 370 prim <<= 25; 371 while (n != 0) { 372 /* Can emit up to 255 indices (85 triangles) at once. */ 373 unsigned int count = n > 255 ? 255 : n; 374 if (reorder) { 375 /* Need to reorder indices for correct flat 376 * shading while preserving the clock sense 377 * for correct culling. Only on Savage3D. */ 378 int reorder[3] = {-1, -1, -1}; 379 reorder[start%3] = 2; 380 381 BEGIN_BCI((count+1+1)/2); 382 BCI_DRAW_INDICES_S3D(count, prim, start+2); 383 384 for (i = start+1; i+1 < start+count; i += 2) 385 BCI_WRITE((i + reorder[i % 3]) | 386 ((i+1 + reorder[(i+1) % 3]) << 16)); 387 if (i < start+count) 388 BCI_WRITE(i + reorder[i%3]); 389 } else if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) { 390 BEGIN_BCI((count+1+1)/2); 391 BCI_DRAW_INDICES_S3D(count, prim, start); 392 393 for (i = start+1; i+1 < start+count; i += 2) 394 BCI_WRITE(i | ((i+1) << 16)); 395 if (i < start+count) 396 BCI_WRITE(i); 397 } else { 398 BEGIN_BCI((count+2+1)/2); 399 BCI_DRAW_INDICES_S4(count, prim, skip); 400 401 for (i = start; i+1 < start+count; i += 2) 402 BCI_WRITE(i | ((i+1) << 16)); 403 if (i < start+count) 404 BCI_WRITE(i); 405 } 406 407 start += count; 408 n -= count; 409 410 prim |= BCI_CMD_DRAW_CONT; 411 } 412 413 return 0; 414} 415 416static int savage_dispatch_vb_prim(drm_savage_private_t *dev_priv, 417 const drm_savage_cmd_header_t *cmd_header, 418 const uint32_t *vtxbuf, unsigned int vb_size, 419 unsigned int vb_stride) 420{ 421 unsigned char reorder = 0; 422 unsigned int prim = cmd_header->prim.prim; 423 unsigned int skip = cmd_header->prim.skip; 424 unsigned int n = cmd_header->prim.count; 425 unsigned int start = cmd_header->prim.start; 426 unsigned int vtx_size; 427 unsigned int i; 428 DMA_LOCALS; 429 430 if (!n) 431 return 0; 432 433 switch (prim) { 434 case SAVAGE_PRIM_TRILIST_201: 435 reorder = 1; 436 prim = SAVAGE_PRIM_TRILIST; 437 case SAVAGE_PRIM_TRILIST: 438 if (n % 3 != 0) { 439 DRM_ERROR("wrong number of vertices %u in TRILIST\n", 440 n); 441 return DRM_ERR(EINVAL); 442 } 443 break; 444 case SAVAGE_PRIM_TRISTRIP: 445 case SAVAGE_PRIM_TRIFAN: 446 if (n < 3) { 447 DRM_ERROR("wrong number of vertices %u in TRIFAN/STRIP\n", 448 n); 449 return DRM_ERR(EINVAL); 450 } 451 break; 452 default: 453 DRM_ERROR("invalid primitive type %u\n", prim); 454 return DRM_ERR(EINVAL); 455 } 456 457 if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) { 458 if (skip > SAVAGE_SKIP_ALL_S3D) { 459 DRM_ERROR("invalid skip flags 0x%04x\n", skip); 460 return DRM_ERR(EINVAL); 461 } 462 vtx_size = 8; /* full vertex */ 463 } else { 464 if (skip > SAVAGE_SKIP_ALL_S4) { 465 DRM_ERROR("invalid skip flags 0x%04x\n", skip); 466 return DRM_ERR(EINVAL); 467 } 468 vtx_size = 10; /* full vertex */ 469 } 470 471 vtx_size -= (skip & 1) + (skip >> 1 & 1) + 472 (skip >> 2 & 1) + (skip >> 3 & 1) + (skip >> 4 & 1) + 473 (skip >> 5 & 1) + (skip >> 6 & 1) + (skip >> 7 & 1); 474 475 if (vtx_size > vb_stride) { 476 DRM_ERROR("vertex size greater than vb stride (%u > %u)\n", 477 vtx_size, vb_stride); 478 return DRM_ERR(EINVAL); 479 } 480 481 if (start + n > vb_size / (vb_stride*4)) { 482 DRM_ERROR("vertex indices (%u-%u) out of range (0-%u)\n", 483 start, start + n - 1, vb_size / (vb_stride*4)); 484 return DRM_ERR(EINVAL); 485 } 486 487 prim <<= 25; 488 while (n != 0) { 489 /* Can emit up to 255 vertices (85 triangles) at once. */ 490 unsigned int count = n > 255 ? 255 : n; 491 if (reorder) { 492 /* Need to reorder vertices for correct flat 493 * shading while preserving the clock sense 494 * for correct culling. Only on Savage3D. */ 495 int reorder[3] = {-1, -1, -1}; 496 reorder[start%3] = 2; 497 498 BEGIN_DMA(count*vtx_size+1); 499 DMA_DRAW_PRIMITIVE(count, prim, skip); 500 501 for (i = start; i < start+count; ++i) { 502 unsigned int j = i + reorder[i % 3]; 503 DMA_COPY(&vtxbuf[vb_stride*j], vtx_size); 504 } 505 506 DMA_COMMIT(); 507 } else { 508 BEGIN_DMA(count*vtx_size+1); 509 DMA_DRAW_PRIMITIVE(count, prim, skip); 510 511 if (vb_stride == vtx_size) { 512 DMA_COPY(&vtxbuf[vb_stride*start], 513 vtx_size*count); 514 } else { 515 for (i = start; i < start+count; ++i) { 516 DMA_COPY(&vtxbuf[vb_stride*i], 517 vtx_size); 518 } 519 } 520 521 DMA_COMMIT(); 522 } 523 524 start += count; 525 n -= count; 526 527 prim |= BCI_CMD_DRAW_CONT; 528 } 529 530 return 0; 531} 532 533static int savage_dispatch_dma_idx(drm_savage_private_t *dev_priv, 534 const drm_savage_cmd_header_t *cmd_header, 535 const uint16_t *idx, 536 const drm_buf_t *dmabuf) 537{ 538 unsigned char reorder = 0; 539 unsigned int prim = cmd_header->idx.prim; 540 unsigned int skip = cmd_header->idx.skip; 541 unsigned int n = cmd_header->idx.count; 542 unsigned int i; 543 BCI_LOCALS; 544 545 if (!dmabuf) { 546 DRM_ERROR("called without dma buffers!\n"); 547 return DRM_ERR(EINVAL); 548 } 549 550 if (!n) 551 return 0; 552 553 switch (prim) { 554 case SAVAGE_PRIM_TRILIST_201: 555 reorder = 1; 556 prim = SAVAGE_PRIM_TRILIST; 557 case SAVAGE_PRIM_TRILIST: 558 if (n % 3 != 0) { 559 DRM_ERROR("wrong number of indices %u in TRILIST\n", 560 n); 561 return DRM_ERR(EINVAL); 562 } 563 break; 564 case SAVAGE_PRIM_TRISTRIP: 565 case SAVAGE_PRIM_TRIFAN: 566 if (n < 3) { 567 DRM_ERROR("wrong number of indices %u in TRIFAN/STRIP\n", 568 n); 569 return DRM_ERR(EINVAL); 570 } 571 break; 572 default: 573 DRM_ERROR("invalid primitive type %u\n", prim); 574 return DRM_ERR(EINVAL); 575 } 576 577 if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) { 578 if (skip != 0) { 579 DRM_ERROR("invalid skip flags 0x%04x for DMA\n", 580 skip); 581 return DRM_ERR(EINVAL); 582 } 583 } else { 584 unsigned int size = 10 - (skip & 1) - (skip >> 1 & 1) - 585 (skip >> 2 & 1) - (skip >> 3 & 1) - (skip >> 4 & 1) - 586 (skip >> 5 & 1) - (skip >> 6 & 1) - (skip >> 7 & 1); 587 if (skip > SAVAGE_SKIP_ALL_S4 || size != 8) { 588 DRM_ERROR("invalid skip flags 0x%04x for DMA\n", 589 skip); 590 return DRM_ERR(EINVAL); 591 } 592 if (reorder) { 593 DRM_ERROR("TRILIST_201 used on Savage4 hardware\n"); 594 return DRM_ERR(EINVAL); 595 } 596 } 597 598 /* Vertex DMA doesn't work with command DMA at the same time, 599 * so we use BCI_... to submit commands here. Flush buffered 600 * faked DMA first. */ 601 DMA_FLUSH(); 602 603 if (dmabuf->bus_address != dev_priv->state.common.vbaddr) { 604 BEGIN_BCI(2); 605 BCI_SET_REGISTERS(SAVAGE_VERTBUFADDR, 1); 606 BCI_WRITE(dmabuf->bus_address | dev_priv->dma_type); 607 dev_priv->state.common.vbaddr = dmabuf->bus_address; 608 } 609 if (S3_SAVAGE3D_SERIES(dev_priv->chipset) && dev_priv->waiting) { 610 /* Workaround for what looks like a hardware bug. If a 611 * WAIT_3D_IDLE was emitted some time before the 612 * indexed drawing command then the engine will lock 613 * up. There are two known workarounds: 614 * WAIT_IDLE_EMPTY or emit at least 63 NOPs. */ 615 BEGIN_BCI(63); 616 for (i = 0; i < 63; ++i) 617 BCI_WRITE(BCI_CMD_WAIT); 618 dev_priv->waiting = 0; 619 } 620 621 prim <<= 25; 622 while (n != 0) { 623 /* Can emit up to 255 indices (85 triangles) at once. */ 624 unsigned int count = n > 255 ? 255 : n; 625 626 /* check indices */ 627 for (i = 0; i < count; ++i) { 628 if (idx[i] > dmabuf->total/32) { 629 DRM_ERROR("idx[%u]=%u out of range (0-%u)\n", 630 i, idx[i], dmabuf->total/32); 631 return DRM_ERR(EINVAL); 632 } 633 } 634 635 if (reorder) { 636 /* Need to reorder indices for correct flat 637 * shading while preserving the clock sense 638 * for correct culling. Only on Savage3D. */ 639 int reorder[3] = {2, -1, -1}; 640 641 BEGIN_BCI((count+1+1)/2); 642 BCI_DRAW_INDICES_S3D(count, prim, idx[2]); 643 644 for (i = 1; i+1 < count; i += 2) 645 BCI_WRITE(idx[i + reorder[i % 3]] | 646 (idx[i+1 + reorder[(i+1) % 3]] << 16)); 647 if (i < count) 648 BCI_WRITE(idx[i + reorder[i%3]]); 649 } else if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) { 650 BEGIN_BCI((count+1+1)/2); 651 BCI_DRAW_INDICES_S3D(count, prim, idx[0]); 652 653 for (i = 1; i+1 < count; i += 2) 654 BCI_WRITE(idx[i] | (idx[i+1] << 16)); 655 if (i < count) 656 BCI_WRITE(idx[i]); 657 } else { 658 BEGIN_BCI((count+2+1)/2); 659 BCI_DRAW_INDICES_S4(count, prim, skip); 660 661 for (i = 0; i+1 < count; i += 2) 662 BCI_WRITE(idx[i] | (idx[i+1] << 16)); 663 if (i < count) 664 BCI_WRITE(idx[i]); 665 } 666 667 idx += count; 668 n -= count; 669 670 prim |= BCI_CMD_DRAW_CONT; 671 } 672 673 return 0; 674} 675 676static int savage_dispatch_vb_idx(drm_savage_private_t *dev_priv, 677 const drm_savage_cmd_header_t *cmd_header, 678 const uint16_t *idx, 679 const uint32_t *vtxbuf, 680 unsigned int vb_size, 681 unsigned int vb_stride) 682{ 683 unsigned char reorder = 0; 684 unsigned int prim = cmd_header->idx.prim; 685 unsigned int skip = cmd_header->idx.skip; 686 unsigned int n = cmd_header->idx.count; 687 unsigned int vtx_size; 688 unsigned int i; 689 DMA_LOCALS; 690 691 if (!n) 692 return 0; 693 694 switch (prim) { 695 case SAVAGE_PRIM_TRILIST_201: 696 reorder = 1; 697 prim = SAVAGE_PRIM_TRILIST; 698 case SAVAGE_PRIM_TRILIST: 699 if (n % 3 != 0) { 700 DRM_ERROR("wrong number of indices %u in TRILIST\n", 701 n); 702 return DRM_ERR(EINVAL); 703 } 704 break; 705 case SAVAGE_PRIM_TRISTRIP: 706 case SAVAGE_PRIM_TRIFAN: 707 if (n < 3) { 708 DRM_ERROR("wrong number of indices %u in TRIFAN/STRIP\n", 709 n); 710 return DRM_ERR(EINVAL); 711 } 712 break; 713 default: 714 DRM_ERROR("invalid primitive type %u\n", prim); 715 return DRM_ERR(EINVAL); 716 } 717 718 if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) { 719 if (skip > SAVAGE_SKIP_ALL_S3D) { 720 DRM_ERROR("invalid skip flags 0x%04x\n", skip); 721 return DRM_ERR(EINVAL); 722 } 723 vtx_size = 8; /* full vertex */ 724 } else { 725 if (skip > SAVAGE_SKIP_ALL_S4) { 726 DRM_ERROR("invalid skip flags 0x%04x\n", skip); 727 return DRM_ERR(EINVAL); 728 } 729 vtx_size = 10; /* full vertex */ 730 } 731 732 vtx_size -= (skip & 1) + (skip >> 1 & 1) + 733 (skip >> 2 & 1) + (skip >> 3 & 1) + (skip >> 4 & 1) + 734 (skip >> 5 & 1) + (skip >> 6 & 1) + (skip >> 7 & 1); 735 736 if (vtx_size > vb_stride) { 737 DRM_ERROR("vertex size greater than vb stride (%u > %u)\n", 738 vtx_size, vb_stride); 739 return DRM_ERR(EINVAL); 740 } 741 742 prim <<= 25; 743 while (n != 0) { 744 /* Can emit up to 255 vertices (85 triangles) at once. */ 745 unsigned int count = n > 255 ? 255 : n; 746 747 /* Check indices */ 748 for (i = 0; i < count; ++i) { 749 if (idx[i] > vb_size / (vb_stride*4)) { 750 DRM_ERROR("idx[%u]=%u out of range (0-%u)\n", 751 i, idx[i], vb_size / (vb_stride*4)); 752 return DRM_ERR(EINVAL); 753 } 754 } 755 756 if (reorder) { 757 /* Need to reorder vertices for correct flat 758 * shading while preserving the clock sense 759 * for correct culling. Only on Savage3D. */ 760 int reorder[3] = {2, -1, -1}; 761 762 BEGIN_DMA(count*vtx_size+1); 763 DMA_DRAW_PRIMITIVE(count, prim, skip); 764 765 for (i = 0; i < count; ++i) { 766 unsigned int j = idx[i + reorder[i % 3]]; 767 DMA_COPY(&vtxbuf[vb_stride*j], vtx_size); 768 } 769 770 DMA_COMMIT(); 771 } else { 772 BEGIN_DMA(count*vtx_size+1); 773 DMA_DRAW_PRIMITIVE(count, prim, skip); 774 775 for (i = 0; i < count; ++i) { 776 unsigned int j = idx[i]; 777 DMA_COPY(&vtxbuf[vb_stride*j], vtx_size); 778 } 779 780 DMA_COMMIT(); 781 } 782 783 idx += count; 784 n -= count; 785 786 prim |= BCI_CMD_DRAW_CONT; 787 } 788 789 return 0; 790} 791 792static int savage_dispatch_clear(drm_savage_private_t *dev_priv, 793 const drm_savage_cmd_header_t *cmd_header, 794 const drm_savage_cmd_header_t *data, 795 unsigned int nbox, 796 const drm_clip_rect_t *boxes) 797{ 798 unsigned int flags = cmd_header->clear0.flags; 799 unsigned int clear_cmd; 800 unsigned int i, nbufs; 801 DMA_LOCALS; 802 803 if (nbox == 0) 804 return 0; 805 806 clear_cmd = BCI_CMD_RECT | BCI_CMD_RECT_XP | BCI_CMD_RECT_YP | 807 BCI_CMD_SEND_COLOR | BCI_CMD_DEST_PBD_NEW; 808 BCI_CMD_SET_ROP(clear_cmd,0xCC); 809 810 nbufs = ((flags & SAVAGE_FRONT) ? 1 : 0) + 811 ((flags & SAVAGE_BACK) ? 1 : 0) + 812 ((flags & SAVAGE_DEPTH) ? 1 : 0); 813 if (nbufs == 0) 814 return 0; 815 816 if (data->clear1.mask != 0xffffffff) { 817 /* set mask */ 818 BEGIN_DMA(2); 819 DMA_SET_REGISTERS(SAVAGE_BITPLANEWTMASK, 1); 820 DMA_WRITE(data->clear1.mask); 821 DMA_COMMIT(); 822 } 823 for (i = 0; i < nbox; ++i) { 824 unsigned int x, y, w, h; 825 unsigned int buf; 826 827 x = boxes[i].x1, y = boxes[i].y1; 828 w = boxes[i].x2 - boxes[i].x1; 829 h = boxes[i].y2 - boxes[i].y1; 830 BEGIN_DMA(nbufs*6); 831 for (buf = SAVAGE_FRONT; buf <= SAVAGE_DEPTH; buf <<= 1) { 832 if (!(flags & buf)) 833 continue; 834 DMA_WRITE(clear_cmd); 835 switch(buf) { 836 case SAVAGE_FRONT: 837 DMA_WRITE(dev_priv->front_offset); 838 DMA_WRITE(dev_priv->front_bd); 839 break; 840 case SAVAGE_BACK: 841 DMA_WRITE(dev_priv->back_offset); 842 DMA_WRITE(dev_priv->back_bd); 843 break; 844 case SAVAGE_DEPTH: 845 DMA_WRITE(dev_priv->depth_offset); 846 DMA_WRITE(dev_priv->depth_bd); 847 break; 848 } 849 DMA_WRITE(data->clear1.value); 850 DMA_WRITE(BCI_X_Y(x, y)); 851 DMA_WRITE(BCI_W_H(w, h)); 852 } 853 DMA_COMMIT(); 854 } 855 if (data->clear1.mask != 0xffffffff) { 856 /* reset mask */ 857 BEGIN_DMA(2); 858 DMA_SET_REGISTERS(SAVAGE_BITPLANEWTMASK, 1); 859 DMA_WRITE(0xffffffff); 860 DMA_COMMIT(); 861 } 862 863 return 0; 864} 865 866static int savage_dispatch_swap(drm_savage_private_t *dev_priv, 867 unsigned int nbox, const drm_clip_rect_t *boxes) 868{ 869 unsigned int swap_cmd; 870 unsigned int i; 871 DMA_LOCALS; 872 873 if (nbox == 0) 874 return 0; 875 876 swap_cmd = BCI_CMD_RECT | BCI_CMD_RECT_XP | BCI_CMD_RECT_YP | 877 BCI_CMD_SRC_PBD_COLOR_NEW | BCI_CMD_DEST_GBD; 878 BCI_CMD_SET_ROP(swap_cmd,0xCC); 879 880 for (i = 0; i < nbox; ++i) { 881 BEGIN_DMA(6); 882 DMA_WRITE(swap_cmd); 883 DMA_WRITE(dev_priv->back_offset); 884 DMA_WRITE(dev_priv->back_bd); 885 DMA_WRITE(BCI_X_Y(boxes[i].x1, boxes[i].y1)); 886 DMA_WRITE(BCI_X_Y(boxes[i].x1, boxes[i].y1)); 887 DMA_WRITE(BCI_W_H(boxes[i].x2-boxes[i].x1, 888 boxes[i].y2-boxes[i].y1)); 889 DMA_COMMIT(); 890 } 891 892 return 0; 893} 894 895static int savage_dispatch_draw(drm_savage_private_t *dev_priv, 896 const drm_savage_cmd_header_t *start, 897 const drm_savage_cmd_header_t *end, 898 const drm_buf_t *dmabuf, 899 const unsigned int *vtxbuf, 900 unsigned int vb_size, unsigned int vb_stride, 901 unsigned int nbox, 902 const drm_clip_rect_t *boxes) 903{ 904 unsigned int i, j; 905 int ret; 906 907 for (i = 0; i < nbox; ++i) { 908 const drm_savage_cmd_header_t *cmdbuf; 909 dev_priv->emit_clip_rect(dev_priv, &boxes[i]); 910 911 cmdbuf = start; 912 while (cmdbuf < end) { 913 drm_savage_cmd_header_t cmd_header; 914 cmd_header = *cmdbuf; 915 cmdbuf++; 916 switch (cmd_header.cmd.cmd) { 917 case SAVAGE_CMD_DMA_PRIM: 918 ret = savage_dispatch_dma_prim( 919 dev_priv, &cmd_header, dmabuf); 920 break; 921 case SAVAGE_CMD_VB_PRIM: 922 ret = savage_dispatch_vb_prim( 923 dev_priv, &cmd_header, 924 vtxbuf, vb_size, vb_stride); 925 break; 926 case SAVAGE_CMD_DMA_IDX: 927 j = (cmd_header.idx.count + 3) / 4; 928 /* j was check in savage_bci_cmdbuf */ 929 ret = savage_dispatch_dma_idx(dev_priv, 930 &cmd_header, (const uint16_t *)cmdbuf, 931 dmabuf); 932 cmdbuf += j; 933 break; 934 case SAVAGE_CMD_VB_IDX: 935 j = (cmd_header.idx.count + 3) / 4; 936 /* j was check in savage_bci_cmdbuf */ 937 ret = savage_dispatch_vb_idx(dev_priv, 938 &cmd_header, (const uint16_t *)cmdbuf, 939 (const uint32_t *)vtxbuf, vb_size, 940 vb_stride); 941 cmdbuf += j; 942 break; 943 default: 944 /* What's the best return code? EFAULT? */ 945 DRM_ERROR("IMPLEMENTATION ERROR: " 946 "non-drawing-command %d\n", 947 cmd_header.cmd.cmd); 948 return DRM_ERR(EINVAL); 949 } 950 951 if (ret != 0) 952 return ret; 953 } 954 } 955 956 return 0; 957} 958 959int savage_bci_cmdbuf(DRM_IOCTL_ARGS) 960{ 961 DRM_DEVICE; 962 drm_savage_private_t *dev_priv = dev->dev_private; 963 drm_device_dma_t *dma = dev->dma; 964 drm_buf_t *dmabuf; 965 drm_savage_cmdbuf_t cmdbuf; 966 drm_savage_cmd_header_t *kcmd_addr = NULL; 967 drm_savage_cmd_header_t *first_draw_cmd; 968 unsigned int *kvb_addr = NULL; 969 drm_clip_rect_t *kbox_addr = NULL; 970 unsigned int i, j; 971 int ret = 0; 972 973 DRM_DEBUG("\n"); 974 975 LOCK_TEST_WITH_RETURN(dev, filp); 976 977 DRM_COPY_FROM_USER_IOCTL(cmdbuf, (drm_savage_cmdbuf_t __user *)data, 978 sizeof(cmdbuf)); 979 980 if (dma && dma->buflist) { 981 if (cmdbuf.dma_idx > dma->buf_count) { 982 DRM_ERROR("vertex buffer index %u out of range (0-%u)\n", 983 cmdbuf.dma_idx, dma->buf_count-1); 984 return DRM_ERR(EINVAL); 985 } 986 dmabuf = dma->buflist[cmdbuf.dma_idx]; 987 } else { 988 dmabuf = NULL; 989 } 990 991 /* Copy the user buffers into kernel temporary areas. This hasn't been 992 * a performance loss compared to VERIFYAREA_READ/ 993 * COPY_FROM_USER_UNCHECKED when done in other drivers, and is correct 994 * for locking on FreeBSD. 995 */ 996 if (cmdbuf.size) { 997 kcmd_addr = drm_alloc(cmdbuf.size * 8, DRM_MEM_DRIVER); 998 if (kcmd_addr == NULL) 999 return ENOMEM; 1000 1001 if (DRM_COPY_FROM_USER(kcmd_addr, cmdbuf.cmd_addr, 1002 cmdbuf.size * 8)) 1003 { 1004 drm_free(kcmd_addr, cmdbuf.size * 8, DRM_MEM_DRIVER); 1005 return DRM_ERR(EFAULT); 1006 } 1007 cmdbuf.cmd_addr = kcmd_addr; 1008 } 1009 if (cmdbuf.vb_size) { 1010 kvb_addr = drm_alloc(cmdbuf.vb_size, DRM_MEM_DRIVER); 1011 if (kvb_addr == NULL) { 1012 ret = DRM_ERR(ENOMEM); 1013 goto done; 1014 } 1015 1016 if (DRM_COPY_FROM_USER(kvb_addr, cmdbuf.vb_addr, 1017 cmdbuf.vb_size)) { 1018 ret = DRM_ERR(EFAULT); 1019 goto done; 1020 } 1021 cmdbuf.vb_addr = kvb_addr; 1022 } 1023 if (cmdbuf.nbox) { 1024 kbox_addr = drm_alloc(cmdbuf.nbox * sizeof(drm_clip_rect_t), 1025 DRM_MEM_DRIVER); 1026 if (kbox_addr == NULL) { 1027 ret = DRM_ERR(ENOMEM); 1028 goto done; 1029 } 1030 1031 if (DRM_COPY_FROM_USER(kbox_addr, cmdbuf.box_addr, 1032 cmdbuf.nbox * sizeof(drm_clip_rect_t))) { 1033 ret = DRM_ERR(EFAULT); 1034 goto done; 1035 } 1036 cmdbuf.box_addr = kbox_addr; 1037 } 1038 1039 /* Make sure writes to DMA buffers are finished before sending 1040 * DMA commands to the graphics hardware. */ 1041 DRM_MEMORYBARRIER(); 1042 1043 /* Coming from user space. Don't know if the Xserver has 1044 * emitted wait commands. Assuming the worst. */ 1045 dev_priv->waiting = 1; 1046 1047 i = 0; 1048 first_draw_cmd = NULL; 1049 while (i < cmdbuf.size) { 1050 drm_savage_cmd_header_t cmd_header; 1051 cmd_header = *(drm_savage_cmd_header_t *)cmdbuf.cmd_addr; 1052 cmdbuf.cmd_addr++; 1053 i++; 1054 1055 /* Group drawing commands with same state to minimize 1056 * iterations over clip rects. */ 1057 j = 0; 1058 switch (cmd_header.cmd.cmd) { 1059 case SAVAGE_CMD_DMA_IDX: 1060 case SAVAGE_CMD_VB_IDX: 1061 j = (cmd_header.idx.count + 3) / 4; 1062 if (i + j > cmdbuf.size) { 1063 DRM_ERROR("indexed drawing command extends " 1064 "beyond end of command buffer\n"); 1065 DMA_FLUSH(); 1066 return DRM_ERR(EINVAL); 1067 } 1068 /* fall through */ 1069 case SAVAGE_CMD_DMA_PRIM: 1070 case SAVAGE_CMD_VB_PRIM: 1071 if (!first_draw_cmd) 1072 first_draw_cmd = cmdbuf.cmd_addr-1; 1073 cmdbuf.cmd_addr += j; 1074 i += j; 1075 break; 1076 default: 1077 if (first_draw_cmd) { 1078 ret = savage_dispatch_draw ( 1079 dev_priv, first_draw_cmd, 1080 cmdbuf.cmd_addr-1, 1081 dmabuf, cmdbuf.vb_addr, cmdbuf.vb_size, 1082 cmdbuf.vb_stride, 1083 cmdbuf.nbox, cmdbuf.box_addr); 1084 if (ret != 0) 1085 return ret; 1086 first_draw_cmd = NULL; 1087 } 1088 } 1089 if (first_draw_cmd) 1090 continue; 1091 1092 switch (cmd_header.cmd.cmd) { 1093 case SAVAGE_CMD_STATE: 1094 j = (cmd_header.state.count + 1) / 2; 1095 if (i + j > cmdbuf.size) { 1096 DRM_ERROR("command SAVAGE_CMD_STATE extends " 1097 "beyond end of command buffer\n"); 1098 DMA_FLUSH(); 1099 ret = DRM_ERR(EINVAL); 1100 goto done; 1101 } 1102 ret = savage_dispatch_state(dev_priv, &cmd_header, 1103 (const uint32_t *)cmdbuf.cmd_addr); 1104 cmdbuf.cmd_addr += j; 1105 i += j; 1106 break; 1107 case SAVAGE_CMD_CLEAR: 1108 if (i + 1 > cmdbuf.size) { 1109 DRM_ERROR("command SAVAGE_CMD_CLEAR extends " 1110 "beyond end of command buffer\n"); 1111 DMA_FLUSH(); 1112 ret = DRM_ERR(EINVAL); 1113 goto done; 1114 } 1115 ret = savage_dispatch_clear(dev_priv, &cmd_header, 1116 cmdbuf.cmd_addr, 1117 cmdbuf.nbox, cmdbuf.box_addr); 1118 cmdbuf.cmd_addr++; 1119 i++; 1120 break; 1121 case SAVAGE_CMD_SWAP: 1122 ret = savage_dispatch_swap(dev_priv, cmdbuf.nbox, 1123 cmdbuf.box_addr); 1124 break; 1125 default: 1126 DRM_ERROR("invalid command 0x%x\n", cmd_header.cmd.cmd); 1127 DMA_FLUSH(); 1128 ret = DRM_ERR(EINVAL); 1129 goto done; 1130 } 1131 1132 if (ret != 0) { 1133 DMA_FLUSH(); 1134 goto done; 1135 } 1136 } 1137 1138 if (first_draw_cmd) { 1139 ret = savage_dispatch_draw ( 1140 dev_priv, first_draw_cmd, cmdbuf.cmd_addr, dmabuf, 1141 cmdbuf.vb_addr, cmdbuf.vb_size, cmdbuf.vb_stride, 1142 cmdbuf.nbox, cmdbuf.box_addr); 1143 if (ret != 0) { 1144 DMA_FLUSH(); 1145 goto done; 1146 } 1147 } 1148 1149 DMA_FLUSH(); 1150 1151 if (dmabuf && cmdbuf.discard) { 1152 drm_savage_buf_priv_t *buf_priv = dmabuf->dev_private; 1153 uint16_t event; 1154 event = savage_bci_emit_event(dev_priv, SAVAGE_WAIT_3D); 1155 SET_AGE(&buf_priv->age, event, dev_priv->event_wrap); 1156 savage_freelist_put(dev, dmabuf); 1157 } 1158 1159done: 1160 /* If we didn't need to allocate them, these'll be NULL */ 1161 drm_free(kcmd_addr, cmdbuf.size * 8, DRM_MEM_DRIVER); 1162 drm_free(kvb_addr, cmdbuf.vb_size, DRM_MEM_DRIVER); 1163 drm_free(kbox_addr, cmdbuf.nbox * sizeof(drm_clip_rect_t), 1164 DRM_MEM_DRIVER); 1165 1166 return ret; 1167} 1168