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