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