1 /*
2 * Copyright (c) 2008-2024 Broadcom. All Rights Reserved.
3 * The term “Broadcom” refers to Broadcom Inc.
4 * and/or its subsidiaries.
5 * SPDX-License-Identifier: MIT
6 */
7
8 #include "util/u_inlines.h"
9 #include "pipe/p_defines.h"
10 #include "util/u_math.h"
11 #include "util/format/u_format.h"
12
13 #include "svga_context.h"
14 #include "svga_state.h"
15 #include "svga_cmd.h"
16 #include "svga_debug.h"
17 #include "svga_screen.h"
18 #include "svga_surface.h"
19 #include "svga_resource_texture.h"
20
21
22 /*
23 * flush our command buffer after the 8th distinct render target
24 *
25 * This helps improve the surface cache behaviour in the face of the
26 * large number of single-use render targets generated by EXA and the xorg
27 * state tracker. Without this we can reference hundreds of individual
28 * render targets from a command buffer, which leaves little scope for
29 * sharing or reuse of those targets.
30 */
31 #define MAX_RT_PER_BATCH 8
32
33
34
35 static enum pipe_error
emit_fb_vgpu9(struct svga_context * svga)36 emit_fb_vgpu9(struct svga_context *svga)
37 {
38 struct svga_screen *svgascreen = svga_screen(svga->pipe.screen);
39 const struct pipe_framebuffer_state *curr = &svga->curr.framebuffer;
40 struct pipe_framebuffer_state *hw = &svga->state.hw_clear.framebuffer;
41 bool reemit = svga->rebind.flags.rendertargets;
42 unsigned i;
43 enum pipe_error ret;
44
45 assert(!svga_have_vgpu10(svga));
46
47 /*
48 * We need to reemit non-null surface bindings, even when they are not
49 * dirty, to ensure that the resources are paged in.
50 */
51
52 for (i = 0; i < svgascreen->max_color_buffers; i++) {
53 if ((curr->cbufs[i] != hw->cbufs[i]) || (reemit && hw->cbufs[i])) {
54 if (svga->curr.nr_fbs++ > MAX_RT_PER_BATCH)
55 return PIPE_ERROR_OUT_OF_MEMORY;
56
57 /* Check to see if we need to propagate the render target surface */
58 if (hw->cbufs[i] && svga_surface_needs_propagation(hw->cbufs[i]))
59 svga_propagate_surface(svga, hw->cbufs[i], true);
60
61 ret = SVGA3D_SetRenderTarget(svga->swc, SVGA3D_RT_COLOR0 + i,
62 curr->cbufs[i]);
63 if (ret != PIPE_OK)
64 return ret;
65
66 pipe_surface_reference(&hw->cbufs[i], curr->cbufs[i]);
67 }
68
69 /* Set the rendered-to flag */
70 struct pipe_surface *s = curr->cbufs[i];
71 if (s) {
72 svga_set_texture_rendered_to(svga_texture(s->texture));
73 }
74 }
75
76 if ((curr->zsbuf != hw->zsbuf) || (reemit && hw->zsbuf)) {
77 ret = SVGA3D_SetRenderTarget(svga->swc, SVGA3D_RT_DEPTH, curr->zsbuf);
78 if (ret != PIPE_OK)
79 return ret;
80
81 /* Check to see if we need to propagate the depth stencil surface */
82 if (hw->zsbuf && svga_surface_needs_propagation(hw->zsbuf))
83 svga_propagate_surface(svga, hw->zsbuf, true);
84
85 if (curr->zsbuf &&
86 util_format_is_depth_and_stencil(curr->zsbuf->format)) {
87 ret = SVGA3D_SetRenderTarget(svga->swc, SVGA3D_RT_STENCIL,
88 curr->zsbuf);
89 if (ret != PIPE_OK)
90 return ret;
91 }
92 else {
93 ret = SVGA3D_SetRenderTarget(svga->swc, SVGA3D_RT_STENCIL, NULL);
94 if (ret != PIPE_OK)
95 return ret;
96 }
97
98 pipe_surface_reference(&hw->zsbuf, curr->zsbuf);
99
100 /* Set the rendered-to flag */
101 struct pipe_surface *s = curr->zsbuf;
102 if (s) {
103 svga_set_texture_rendered_to(svga_texture(s->texture));
104 }
105 }
106
107 return PIPE_OK;
108 }
109
110
111 /*
112 * Rebind rendertargets.
113 *
114 * Similar to emit_framebuffer, but without any state checking/update.
115 *
116 * Called at the beginning of every new command buffer to ensure that
117 * non-dirty rendertargets are properly paged-in.
118 */
119 static enum pipe_error
svga_reemit_framebuffer_bindings_vgpu9(struct svga_context * svga)120 svga_reemit_framebuffer_bindings_vgpu9(struct svga_context *svga)
121 {
122 struct svga_screen *svgascreen = svga_screen(svga->pipe.screen);
123 struct pipe_framebuffer_state *hw = &svga->state.hw_clear.framebuffer;
124 unsigned i;
125 enum pipe_error ret;
126
127 assert(!svga_have_vgpu10(svga));
128
129 for (i = 0; i < svgascreen->max_color_buffers; i++) {
130 if (hw->cbufs[i]) {
131 ret = SVGA3D_SetRenderTarget(svga->swc, SVGA3D_RT_COLOR0 + i,
132 hw->cbufs[i]);
133 if (ret != PIPE_OK) {
134 return ret;
135 }
136 }
137 }
138
139 if (hw->zsbuf) {
140 ret = SVGA3D_SetRenderTarget(svga->swc, SVGA3D_RT_DEPTH, hw->zsbuf);
141 if (ret != PIPE_OK) {
142 return ret;
143 }
144
145 if (hw->zsbuf &&
146 util_format_is_depth_and_stencil(hw->zsbuf->format)) {
147 ret = SVGA3D_SetRenderTarget(svga->swc, SVGA3D_RT_STENCIL, hw->zsbuf);
148 if (ret != PIPE_OK) {
149 return ret;
150 }
151 }
152 else {
153 ret = SVGA3D_SetRenderTarget(svga->swc, SVGA3D_RT_STENCIL, NULL);
154 if (ret != PIPE_OK) {
155 return ret;
156 }
157 }
158 }
159
160 return PIPE_OK;
161 }
162
163
164
165 static enum pipe_error
emit_fb_vgpu10(struct svga_context * svga)166 emit_fb_vgpu10(struct svga_context *svga)
167 {
168 const struct svga_screen *ss = svga_screen(svga->pipe.screen);
169 struct pipe_surface *rtv[SVGA3D_MAX_RENDER_TARGETS];
170 struct pipe_surface *dsv;
171 struct pipe_framebuffer_state *curr = &svga->curr.framebuffer;
172 struct pipe_framebuffer_state *hw = &svga->state.hw_clear.framebuffer;
173 const unsigned num_color = MAX2(curr->nr_cbufs, hw->nr_cbufs);
174 int last_rtv = -1;
175 unsigned i;
176 enum pipe_error ret = PIPE_OK;
177
178 assert(svga_have_vgpu10(svga));
179
180 /* Reset the has_backed_views flag.
181 * The flag is set in svga_validate_surface_view() if
182 * a backed surface view is used.
183 */
184 svga->state.hw_draw.has_backed_views = false;
185
186 /* Setup render targets array. Note that we loop over the max of the
187 * number of previously bound buffers and the new buffers to unbind
188 * any previously bound buffers when the new number of buffers is less
189 * than the old number of buffers.
190 */
191 for (i = 0; i < num_color; i++) {
192 if (curr->cbufs[i]) {
193 struct pipe_surface *s = curr->cbufs[i];
194
195 if (curr->cbufs[i] != hw->cbufs[i]) {
196 rtv[i] = svga_validate_surface_view(svga, svga_surface(s));
197 if (rtv[i] == NULL) {
198 return PIPE_ERROR_OUT_OF_MEMORY;
199 }
200 } else {
201 rtv[i] = svga->state.hw_clear.rtv[i];
202 }
203
204 assert(svga_surface(rtv[i])->view_id != SVGA3D_INVALID_ID);
205 last_rtv = i;
206
207 /* Set the rendered-to flag */
208 svga_set_texture_rendered_to(svga_texture(s->texture));
209 }
210 else {
211 rtv[i] = NULL;
212 }
213 }
214
215 /* Setup depth stencil view */
216 if (curr->zsbuf) {
217 struct pipe_surface *s = curr->zsbuf;
218
219 if (curr->zsbuf != hw->zsbuf) {
220 dsv = svga_validate_surface_view(svga, svga_surface(curr->zsbuf));
221 if (!dsv) {
222 return PIPE_ERROR_OUT_OF_MEMORY;
223 }
224 } else {
225 dsv = svga->state.hw_clear.dsv;
226 }
227
228 /* Set the rendered-to flag */
229 svga_set_texture_rendered_to(svga_texture(s->texture));
230 }
231 else {
232 dsv = NULL;
233 }
234
235 /* avoid emitting redundant SetRenderTargets command */
236 if ((num_color != svga->state.hw_clear.num_rendertargets) ||
237 (dsv != svga->state.hw_clear.dsv) ||
238 memcmp(rtv, svga->state.hw_clear.rtv, num_color * sizeof(rtv[0]))) {
239
240 ret = SVGA3D_vgpu10_SetRenderTargets(svga->swc, num_color, rtv, dsv);
241 if (ret != PIPE_OK)
242 return ret;
243
244 /* number of render targets sent to the device, not including trailing
245 * unbound render targets.
246 */
247 for (i = 0; i < ss->max_color_buffers; i++) {
248 if (hw->cbufs[i] != curr->cbufs[i]) {
249 /* propagate the backed view surface before unbinding it */
250 if (hw->cbufs[i] && svga_surface(hw->cbufs[i])->backed) {
251 svga_propagate_surface(svga,
252 &svga_surface(hw->cbufs[i])->backed->base,
253 true);
254 }
255 else if (svga->state.hw_clear.rtv[i] != hw->cbufs[i] &&
256 svga->state.hw_clear.rtv[i]) {
257 /* Free the alternate surface view when it is unbound. */
258 svga->pipe.surface_destroy(&svga->pipe, svga->state.hw_clear.rtv[i]);
259 }
260 pipe_surface_reference(&hw->cbufs[i], curr->cbufs[i]);
261 }
262 }
263 svga->state.hw_clear.num_rendertargets = last_rtv + 1;
264 memcpy(svga->state.hw_clear.rtv, rtv, num_color * sizeof(rtv[0]));
265 hw->nr_cbufs = curr->nr_cbufs;
266
267 if (hw->zsbuf != curr->zsbuf) {
268 /* propagate the backed view surface before unbinding it */
269 if (hw->zsbuf && svga_surface(hw->zsbuf)->backed) {
270 svga_propagate_surface(svga,
271 &svga_surface(hw->zsbuf)->backed->base,
272 true);
273 }
274 else if (svga->state.hw_clear.dsv != hw->zsbuf && svga->state.hw_clear.dsv) {
275 /* Free the alternate surface view when it is unbound. */
276 svga->pipe.surface_destroy(&svga->pipe, svga->state.hw_clear.dsv);
277 }
278 pipe_surface_reference(&hw->zsbuf, curr->zsbuf);
279 }
280 svga->state.hw_clear.dsv = dsv;
281 }
282
283 return ret;
284 }
285
286
287 static enum pipe_error
emit_framebuffer(struct svga_context * svga,uint64_t dirty)288 emit_framebuffer(struct svga_context *svga, uint64_t dirty)
289 {
290 if (svga_have_vgpu10(svga)) {
291 return emit_fb_vgpu10(svga);
292 }
293 else {
294 return emit_fb_vgpu9(svga);
295 }
296 }
297
298
299 /*
300 * Rebind rendertargets.
301 *
302 * Similar to emit_framebuffer, but without any state checking/update.
303 *
304 * Called at the beginning of every new command buffer to ensure that
305 * non-dirty rendertargets are properly paged-in.
306 */
307 enum pipe_error
svga_reemit_framebuffer_bindings(struct svga_context * svga)308 svga_reemit_framebuffer_bindings(struct svga_context *svga)
309 {
310 enum pipe_error ret;
311
312 assert(svga->rebind.flags.rendertargets);
313
314 if (svga_have_vgpu10(svga)) {
315 ret = emit_fb_vgpu10(svga);
316 }
317 else {
318 ret = svga_reemit_framebuffer_bindings_vgpu9(svga);
319 }
320
321 svga->rebind.flags.rendertargets = false;
322
323 return ret;
324 }
325
326
327 /*
328 * Send a private allocation command to page in rendertargets resource.
329 */
330 enum pipe_error
svga_rebind_framebuffer_bindings(struct svga_context * svga)331 svga_rebind_framebuffer_bindings(struct svga_context *svga)
332 {
333 struct svga_hw_clear_state *hw = &svga->state.hw_clear;
334 unsigned i;
335 enum pipe_error ret;
336
337 assert(svga_have_vgpu10(svga));
338
339 if (!svga->rebind.flags.rendertargets)
340 return PIPE_OK;
341
342 for (i = 0; i < hw->num_rendertargets; i++) {
343 if (hw->rtv[i]) {
344 ret = svga->swc->resource_rebind(svga->swc,
345 svga_surface(hw->rtv[i])->handle,
346 NULL,
347 SVGA_RELOC_WRITE);
348 if (ret != PIPE_OK)
349 return ret;
350 }
351 }
352
353 if (hw->dsv) {
354 ret = svga->swc->resource_rebind(svga->swc,
355 svga_surface(hw->dsv)->handle,
356 NULL,
357 SVGA_RELOC_WRITE);
358 if (ret != PIPE_OK)
359 return ret;
360 }
361
362 svga->rebind.flags.rendertargets = 0;
363
364 return PIPE_OK;
365 }
366
367
368 struct svga_tracked_state svga_hw_framebuffer =
369 {
370 "hw framebuffer state",
371 SVGA_NEW_FRAME_BUFFER,
372 emit_framebuffer
373 };
374
375
376
377
378 /***********************************************************************
379 */
380
381 static void
get_viewport_prescale(struct svga_context * svga,struct pipe_viewport_state * viewport,SVGA3dViewport * vp,struct svga_prescale * prescale)382 get_viewport_prescale(struct svga_context *svga,
383 struct pipe_viewport_state *viewport,
384 SVGA3dViewport *vp,
385 struct svga_prescale *prescale)
386 {
387 SVGA3dRect rect;
388
389 /* Not sure if this state is relevant with POSITIONT. Probably
390 * not, but setting to 0,1 avoids some state pingponging.
391 */
392 float range_min = 0.0;
393 float range_max = 1.0;
394 float flip = -1.0;
395 bool degenerate = false;
396 bool invertY = false;
397
398 float fb_width = (float) svga->curr.framebuffer.width;
399 float fb_height = (float) svga->curr.framebuffer.height;
400
401 float fx = viewport->scale[0] * -1.0f + viewport->translate[0];
402 float fy = flip * viewport->scale[1] * -1.0f + viewport->translate[1];
403 float fw = viewport->scale[0] * 2.0f;
404 float fh = flip * viewport->scale[1] * 2.0f;
405
406 memset(prescale, 0, sizeof(*prescale));
407
408 /* Examine gallium viewport transformation and produce a screen
409 * rectangle and possibly vertex shader pre-transformation to
410 * get the same results.
411 */
412
413 SVGA_DBG(DEBUG_VIEWPORT,
414 "\ninitial %f,%f %fx%f\n",
415 fx,
416 fy,
417 fw,
418 fh);
419
420 prescale->scale[0] = 1.0;
421 prescale->scale[1] = 1.0;
422 prescale->scale[2] = 1.0;
423 prescale->scale[3] = 1.0;
424 prescale->translate[0] = 0;
425 prescale->translate[1] = 0;
426 prescale->translate[2] = 0;
427 prescale->translate[3] = 0;
428
429 /* Enable prescale to adjust vertex positions to match
430 VGPU10 convention only if rasterization is enabled.
431 */
432 if (svga->curr.rast && svga->curr.rast->templ.rasterizer_discard) {
433 degenerate = true;
434 goto out;
435 } else {
436 prescale->enabled = true;
437 }
438
439 if (fw < 0) {
440 prescale->scale[0] *= -1.0f;
441 prescale->translate[0] += -fw;
442 fw = -fw;
443 fx = viewport->scale[0] * 1.0f + viewport->translate[0];
444 }
445
446 if (fh < 0.0) {
447 if (svga_have_vgpu10(svga)) {
448 /* floating point viewport params below */
449 prescale->translate[1] = fh + fy * 2.0f;
450 }
451 else {
452 /* integer viewport params below */
453 prescale->translate[1] = fh - 1.0f + fy * 2.0f;
454 }
455 fh = -fh;
456 fy -= fh;
457 prescale->scale[1] = -1.0f;
458 invertY = true;
459 }
460
461 if (fx < 0) {
462 prescale->translate[0] += fx;
463 prescale->scale[0] *= fw / (fw + fx);
464 fw += fx;
465 fx = 0.0f;
466 }
467
468 if (fy < 0) {
469 if (invertY) {
470 prescale->translate[1] -= fy;
471 }
472 else {
473 prescale->translate[1] += fy;
474 }
475 prescale->scale[1] *= fh / (fh + fy);
476 fh += fy;
477 fy = 0.0f;
478 }
479
480 if (fx + fw > fb_width) {
481 prescale->scale[0] *= fw / (fb_width - fx);
482 prescale->translate[0] -= fx * (fw / (fb_width - fx));
483 prescale->translate[0] += fx;
484 fw = fb_width - fx;
485 }
486
487 if (fy + fh > fb_height) {
488 prescale->scale[1] *= fh / (fb_height - fy);
489 if (invertY) {
490 float in = fb_height - fy; /* number of vp pixels inside view */
491 float out = fy + fh - fb_height; /* number of vp pixels out of view */
492 prescale->translate[1] += fy * out / in;
493 }
494 else {
495 prescale->translate[1] -= fy * (fh / (fb_height - fy));
496 prescale->translate[1] += fy;
497 }
498 fh = fb_height - fy;
499 }
500
501 if (fw < 0 || fh < 0) {
502 fw = fh = fx = fy = 0;
503 degenerate = true;
504 goto out;
505 }
506
507 /* D3D viewport is integer space. Convert fx,fy,etc. to
508 * integers.
509 *
510 * TODO: adjust pretranslate correct for any subpixel error
511 * introduced converting to integers.
512 */
513 rect.x = (uint32) fx;
514 rect.y = (uint32) fy;
515 rect.w = (uint32) fw;
516 rect.h = (uint32) fh;
517
518 SVGA_DBG(DEBUG_VIEWPORT,
519 "viewport error %f,%f %fx%f\n",
520 fabs((float)rect.x - fx),
521 fabs((float)rect.y - fy),
522 fabs((float)rect.w - fw),
523 fabs((float)rect.h - fh));
524
525 SVGA_DBG(DEBUG_VIEWPORT,
526 "viewport %d,%d %dx%d\n",
527 rect.x,
528 rect.y,
529 rect.w,
530 rect.h);
531
532 /* Finally, to get GL rasterization rules, need to tweak the
533 * screen-space coordinates slightly relative to D3D which is
534 * what hardware implements natively.
535 */
536 if (svga->curr.rast && svga->curr.rast->templ.half_pixel_center) {
537 float adjust_x = 0.0;
538 float adjust_y = 0.0;
539
540 if (svga_have_vgpu10(svga)) {
541 /* Normally, we don't have to do any sub-pixel coordinate
542 * adjustments for VGPU10. But when we draw wide points with
543 * a GS we need an X adjustment in order to be conformant.
544 */
545 if (svga->curr.reduced_prim == MESA_PRIM_POINTS &&
546 svga->curr.rast->pointsize > 1.0f) {
547 adjust_x = 0.5;
548 }
549 }
550 else {
551 /* Use (-0.5, -0.5) bias for all prim types.
552 * Regarding line rasterization, this does not seem to satisfy
553 * the Piglit gl-1.0-ortho-pos test but it generally produces
554 * results identical or very similar to VGPU10.
555 */
556 adjust_x = -0.5;
557 adjust_y = -0.5;
558 }
559
560 if (invertY)
561 adjust_y = -adjust_y;
562
563 prescale->translate[0] += adjust_x;
564 prescale->translate[1] += adjust_y;
565 prescale->translate[2] = 0.5; /* D3D clip space */
566 prescale->scale[2] = 0.5; /* D3D clip space */
567 }
568
569 range_min = viewport->scale[2] * -1.0f + viewport->translate[2];
570 range_max = viewport->scale[2] * 1.0f + viewport->translate[2];
571
572 /* D3D (and by implication SVGA) doesn't like dealing with zmax
573 * less than zmin. Detect that case, flip the depth range and
574 * invert our z-scale factor to achieve the same effect.
575 */
576 if (range_min > range_max) {
577 float range_tmp;
578 range_tmp = range_min;
579 range_min = range_max;
580 range_max = range_tmp;
581 prescale->scale[2] = -prescale->scale[2];
582 }
583
584 /* If zmin is less than 0, clamp zmin to 0 and adjust the prescale.
585 * zmin can be set to -1 when viewport->scale[2] is set to 1 and
586 * viewport->translate[2] is set to 0 in the blit code.
587 */
588 if (range_min < 0.0f) {
589 range_min = -0.5f * viewport->scale[2] + 0.5f + viewport->translate[2];
590 range_max = 0.5f * viewport->scale[2] + 0.5f + viewport->translate[2];
591 prescale->scale[2] *= 2.0f;
592 prescale->translate[2] -= 0.5f;
593 }
594
595 /* Clamp depth range, making sure it's between 0 and 1 */
596 range_min = CLAMP(range_min, 0.0f, 1.0f);
597 range_max = CLAMP(range_max, 0.0f, 1.0f);
598
599 if (prescale->enabled) {
600 float H[2];
601 float J[2];
602 int i;
603
604 SVGA_DBG(DEBUG_VIEWPORT,
605 "prescale %f,%f %fx%f\n",
606 prescale->translate[0],
607 prescale->translate[1],
608 prescale->scale[0],
609 prescale->scale[1]);
610
611 H[0] = (float)rect.w / 2.0f;
612 H[1] = -(float)rect.h / 2.0f;
613 J[0] = (float)rect.x + (float)rect.w / 2.0f;
614 J[1] = (float)rect.y + (float)rect.h / 2.0f;
615
616 SVGA_DBG(DEBUG_VIEWPORT,
617 "H %f,%f\n"
618 "J %fx%f\n",
619 H[0],
620 H[1],
621 J[0],
622 J[1]);
623
624 /* Adjust prescale to take into account the fact that it is
625 * going to be applied prior to the perspective divide and
626 * viewport transformation.
627 *
628 * Vwin = H(Vc/Vc.w) + J
629 *
630 * We want to tweak Vwin with scale and translation from above,
631 * as in:
632 *
633 * Vwin' = S Vwin + T
634 *
635 * But we can only modify the values at Vc. Plugging all the
636 * above together, and rearranging, eventually we get:
637 *
638 * Vwin' = H(Vc'/Vc'.w) + J
639 * where:
640 * Vc' = SVc + KVc.w
641 * K = (T + (S-1)J) / H
642 *
643 * Overwrite prescale.translate with values for K:
644 */
645 for (i = 0; i < 2; i++) {
646 prescale->translate[i] = ((prescale->translate[i] +
647 (prescale->scale[i] - 1.0f) * J[i]) / H[i]);
648 }
649
650 SVGA_DBG(DEBUG_VIEWPORT,
651 "clipspace %f,%f %fx%f\n",
652 prescale->translate[0],
653 prescale->translate[1],
654 prescale->scale[0],
655 prescale->scale[1]);
656 }
657
658 out:
659 if (degenerate) {
660 rect.x = 0;
661 rect.y = 0;
662 rect.w = 1;
663 rect.h = 1;
664 prescale->enabled = false;
665 }
666
667 vp->x = (float) rect.x;
668 vp->y = (float) rect.y;
669 vp->width = (float) rect.w;
670 vp->height = (float) rect.h;
671 vp->minDepth = range_min;
672 vp->maxDepth = range_max;
673 }
674
675
676 static enum pipe_error
emit_viewport(struct svga_context * svga,uint64_t dirty)677 emit_viewport( struct svga_context *svga,
678 uint64_t dirty )
679 {
680 struct svga_screen *svgascreen = svga_screen(svga->pipe.screen);
681 SVGA3dViewport viewports[SVGA3D_DX_MAX_VIEWPORTS];
682 struct svga_prescale prescale[SVGA3D_DX_MAX_VIEWPORTS];
683 unsigned i;
684 enum pipe_error ret;
685 unsigned max_viewports = svgascreen->max_viewports;
686
687 for (i = 0; i < max_viewports; i++) {
688 get_viewport_prescale(svga, &svga->curr.viewport[i],
689 &viewports[i], &prescale[i]);
690 }
691
692 if (memcmp(viewports, svga->state.hw_clear.viewports,
693 max_viewports * sizeof viewports[0]) != 0) {
694
695 if (!svga_have_vgpu10(svga)) {
696 SVGA3dRect rect;
697 SVGA3dViewport *vp = &viewports[0];
698
699 rect.x = (uint32)vp->x;
700 rect.y = (uint32)vp->y;
701 rect.w = (uint32)vp->width;
702 rect.h = (uint32)vp->height;
703
704 ret = SVGA3D_SetViewport(svga->swc, &rect);
705 if (ret != PIPE_OK)
706 return ret;
707
708 ret = SVGA3D_SetZRange(svga->swc, vp->minDepth, vp->maxDepth);
709 if (ret != PIPE_OK)
710 return ret;
711
712 svga->state.hw_clear.viewport = rect;
713 svga->state.hw_clear.depthrange.zmin = vp->minDepth;
714 svga->state.hw_clear.depthrange.zmax = vp->maxDepth;
715 }
716 else {
717 ret = SVGA3D_vgpu10_SetViewports(svga->swc, max_viewports,
718 viewports);
719 if (ret != PIPE_OK)
720 return ret;
721 }
722 memcpy(svga->state.hw_clear.viewports, viewports,
723 max_viewports * sizeof viewports[0]);
724 }
725
726 if (memcmp(prescale, svga->state.hw_clear.prescale,
727 max_viewports * sizeof prescale[0]) != 0) {
728 svga->dirty |= SVGA_NEW_PRESCALE;
729 memcpy(svga->state.hw_clear.prescale, prescale,
730 max_viewports * sizeof prescale[0]);
731
732 /*
733 * Determine number of unique prescales. This is to minimize the
734 * if check needed in the geometry shader to identify the prescale
735 * for the specified viewport.
736 */
737 unsigned last_prescale = SVGA3D_DX_MAX_VIEWPORTS - 1;
738 unsigned i;
739 for (i = SVGA3D_DX_MAX_VIEWPORTS-1; i > 0; i--) {
740 if (memcmp(&svga->state.hw_clear.prescale[i],
741 &svga->state.hw_clear.prescale[i-1],
742 sizeof svga->state.hw_clear.prescale[0])) {
743 break;
744 }
745 last_prescale--;
746 }
747 svga->state.hw_clear.num_prescale = last_prescale + 1;
748 }
749
750 return PIPE_OK;
751 }
752
753
754 struct svga_tracked_state svga_hw_viewport =
755 {
756 "hw viewport state",
757 ( SVGA_NEW_FRAME_BUFFER |
758 SVGA_NEW_VIEWPORT |
759 SVGA_NEW_RAST |
760 SVGA_NEW_REDUCED_PRIMITIVE ),
761 emit_viewport
762 };
763
764
765 /***********************************************************************
766 * Scissor state
767 */
768 static enum pipe_error
emit_scissor_rect(struct svga_context * svga,uint64_t dirty)769 emit_scissor_rect( struct svga_context *svga,
770 uint64_t dirty )
771 {
772 struct svga_screen *svgascreen = svga_screen(svga->pipe.screen);
773 const struct pipe_scissor_state *scissor = svga->curr.scissor;
774 unsigned max_viewports = svgascreen->max_viewports;
775 enum pipe_error ret;
776
777 if (memcmp(&svga->state.hw_clear.scissors[0], scissor,
778 max_viewports * sizeof *scissor) != 0) {
779
780 if (svga_have_vgpu10(svga)) {
781 SVGASignedRect rect[SVGA3D_DX_MAX_VIEWPORTS];
782 unsigned i;
783
784 for (i = 0; i < max_viewports; i++) {
785 rect[i].left = scissor[i].minx;
786 rect[i].top = scissor[i].miny;
787 rect[i].right = scissor[i].maxx;
788 rect[i].bottom = scissor[i].maxy;
789 }
790
791 ret = SVGA3D_vgpu10_SetScissorRects(svga->swc, max_viewports, rect);
792 }
793 else {
794 SVGA3dRect rect;
795
796 rect.x = scissor[0].minx;
797 rect.y = scissor[0].miny;
798 rect.w = scissor[0].maxx - scissor[0].minx; /* + 1 ?? */
799 rect.h = scissor[0].maxy - scissor[0].miny; /* + 1 ?? */
800
801 ret = SVGA3D_SetScissorRect(svga->swc, &rect);
802 }
803
804 if (ret != PIPE_OK)
805 return ret;
806
807 memcpy(svga->state.hw_clear.scissors, scissor,
808 max_viewports * sizeof *scissor);
809 }
810
811 return PIPE_OK;
812 }
813
814 struct svga_tracked_state svga_hw_scissor =
815 {
816 "hw scissor state",
817 SVGA_NEW_SCISSOR,
818 emit_scissor_rect
819 };
820
821
822 /***********************************************************************
823 * Userclip state
824 */
825
826 static enum pipe_error
emit_clip_planes(struct svga_context * svga,uint64_t dirty)827 emit_clip_planes( struct svga_context *svga,
828 uint64_t dirty )
829 {
830 unsigned i;
831 enum pipe_error ret;
832
833 /* TODO: just emit directly from svga_set_clip_state()?
834 */
835 for (i = 0; i < SVGA3D_MAX_CLIP_PLANES; i++) {
836 /* need to express the plane in D3D-style coordinate space.
837 * GL coords get converted to D3D coords with the matrix:
838 * [ 1 0 0 0 ]
839 * [ 0 -1 0 0 ]
840 * [ 0 0 2 0 ]
841 * [ 0 0 -1 1 ]
842 * Apply that matrix to our plane equation, and invert Y.
843 */
844 float a = svga->curr.clip.ucp[i][0];
845 float b = svga->curr.clip.ucp[i][1];
846 float c = svga->curr.clip.ucp[i][2];
847 float d = svga->curr.clip.ucp[i][3];
848 float plane[4];
849
850 plane[0] = a;
851 plane[1] = b;
852 plane[2] = 2.0f * c;
853 plane[3] = d - c;
854
855 if (svga_have_vgpu10(svga)) {
856 //debug_printf("XXX emit DX10 clip plane\n");
857 ret = PIPE_OK;
858 }
859 else {
860 ret = SVGA3D_SetClipPlane(svga->swc, i, plane);
861 if (ret != PIPE_OK)
862 return ret;
863 }
864 }
865
866 return PIPE_OK;
867 }
868
869
870 struct svga_tracked_state svga_hw_clip_planes =
871 {
872 "hw viewport state",
873 SVGA_NEW_CLIP,
874 emit_clip_planes
875 };
876