1 /**********************************************************
2 * Copyright 2008-2009 VMware, Inc. All rights reserved.
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:
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
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
24 **********************************************************/
26 #include "util/u_inlines.h"
27 #include "pipe/p_defines.h"
28 #include "util/u_math.h"
29 #include "util/u_format.h"
31 #include "svga_context.h"
32 #include "svga_state.h"
34 #include "svga_debug.h"
35 #include "svga_screen.h"
36 #include "svga_surface.h"
37 #include "svga_resource_texture.h"
41 * flush our command buffer after the 8th distinct render target
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.
49 #define MAX_RT_PER_BATCH 8
53 static enum pipe_error
54 emit_fb_vgpu9(struct svga_context
*svga
)
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
;
63 assert(!svga_have_vgpu10(svga
));
66 * We need to reemit non-null surface bindings, even when they are not
67 * dirty, to ensure that the resources are paged in.
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
;
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
);
79 ret
= SVGA3D_SetRenderTarget(svga
->swc
, SVGA3D_RT_COLOR0
+ i
,
84 pipe_surface_reference(&hw
->cbufs
[i
], curr
->cbufs
[i
]);
87 /* Set the rendered-to flag */
88 struct pipe_surface
*s
= curr
->cbufs
[i
];
90 svga_set_texture_rendered_to(svga_texture(s
->texture
),
91 s
->u
.tex
.first_layer
, s
->u
.tex
.level
);
95 if ((curr
->zsbuf
!= hw
->zsbuf
) || (reemit
&& hw
->zsbuf
)) {
96 ret
= SVGA3D_SetRenderTarget(svga
->swc
, SVGA3D_RT_DEPTH
, curr
->zsbuf
);
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
);
105 util_format_is_depth_and_stencil(curr
->zsbuf
->format
)) {
106 ret
= SVGA3D_SetRenderTarget(svga
->swc
, SVGA3D_RT_STENCIL
,
112 ret
= SVGA3D_SetRenderTarget(svga
->swc
, SVGA3D_RT_STENCIL
, NULL
);
117 pipe_surface_reference(&hw
->zsbuf
, curr
->zsbuf
);
119 /* Set the rendered-to flag */
120 struct pipe_surface
*s
= curr
->zsbuf
;
122 svga_set_texture_rendered_to(svga_texture(s
->texture
),
123 s
->u
.tex
.first_layer
, s
->u
.tex
.level
);
132 * Rebind rendertargets.
134 * Similar to emit_framebuffer, but without any state checking/update.
136 * Called at the beginning of every new command buffer to ensure that
137 * non-dirty rendertargets are properly paged-in.
139 static enum pipe_error
140 svga_reemit_framebuffer_bindings_vgpu9(struct svga_context
*svga
)
142 struct svga_screen
*svgascreen
= svga_screen(svga
->pipe
.screen
);
143 struct pipe_framebuffer_state
*hw
= &svga
->state
.hw_clear
.framebuffer
;
147 assert(!svga_have_vgpu10(svga
));
149 for (i
= 0; i
< svgascreen
->max_color_buffers
; i
++) {
151 ret
= SVGA3D_SetRenderTarget(svga
->swc
, SVGA3D_RT_COLOR0
+ i
,
153 if (ret
!= PIPE_OK
) {
160 ret
= SVGA3D_SetRenderTarget(svga
->swc
, SVGA3D_RT_DEPTH
, hw
->zsbuf
);
161 if (ret
!= PIPE_OK
) {
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
) {
173 ret
= SVGA3D_SetRenderTarget(svga
->swc
, SVGA3D_RT_STENCIL
, NULL
);
174 if (ret
!= PIPE_OK
) {
185 static enum pipe_error
186 emit_fb_vgpu10(struct svga_context
*svga
)
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
);
196 enum pipe_error ret
= PIPE_OK
;
198 assert(svga_have_vgpu10(svga
));
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.
204 svga
->state
.hw_draw
.has_backed_views
= FALSE
;
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.
211 for (i
= 0; i
< num_color
; i
++) {
212 if (curr
->cbufs
[i
]) {
213 struct pipe_surface
*s
= curr
->cbufs
[i
];
215 rtv
[i
] = svga_validate_surface_view(svga
, svga_surface(s
));
216 if (rtv
[i
] == NULL
) {
217 return PIPE_ERROR_OUT_OF_MEMORY
;
220 assert(svga_surface(rtv
[i
])->view_id
!= SVGA3D_INVALID_ID
);
223 /* Set the rendered-to flag */
224 svga_set_texture_rendered_to(svga_texture(s
->texture
),
225 s
->u
.tex
.first_layer
, s
->u
.tex
.level
);
232 /* Setup depth stencil view */
234 struct pipe_surface
*s
= curr
->zsbuf
;
236 dsv
= svga_validate_surface_view(svga
, svga_surface(curr
->zsbuf
));
238 return PIPE_ERROR_OUT_OF_MEMORY
;
241 /* Set the rendered-to flag */
242 svga_set_texture_rendered_to(svga_texture(s
->texture
),
243 s
->u
.tex
.first_layer
, s
->u
.tex
.level
);
249 /* avoid emitting redundant SetRenderTargets command */
250 if ((num_color
!= svga
->state
.hw_clear
.num_rendertargets
) ||
251 (dsv
!= svga
->state
.hw_clear
.dsv
) ||
252 memcmp(rtv
, svga
->state
.hw_clear
.rtv
, num_color
* sizeof(rtv
[0]))) {
254 ret
= SVGA3D_vgpu10_SetRenderTargets(svga
->swc
, num_color
, rtv
, dsv
);
258 /* number of render targets sent to the device, not including trailing
259 * unbound render targets.
261 svga
->state
.hw_clear
.num_rendertargets
= last_rtv
+ 1;
262 svga
->state
.hw_clear
.dsv
= dsv
;
263 memcpy(svga
->state
.hw_clear
.rtv
, rtv
, num_color
* sizeof(rtv
[0]));
265 for (i
= 0; i
< ss
->max_color_buffers
; i
++) {
266 if (hw
->cbufs
[i
] != curr
->cbufs
[i
]) {
267 /* propagate the backed view surface before unbinding it */
268 if (hw
->cbufs
[i
] && svga_surface(hw
->cbufs
[i
])->backed
) {
269 svga_propagate_surface(svga
,
270 &svga_surface(hw
->cbufs
[i
])->backed
->base
,
273 pipe_surface_reference(&hw
->cbufs
[i
], curr
->cbufs
[i
]);
276 hw
->nr_cbufs
= curr
->nr_cbufs
;
278 if (hw
->zsbuf
!= curr
->zsbuf
) {
279 /* propagate the backed view surface before unbinding it */
280 if (hw
->zsbuf
&& svga_surface(hw
->zsbuf
)->backed
) {
281 svga_propagate_surface(svga
, &svga_surface(hw
->zsbuf
)->backed
->base
,
284 pipe_surface_reference(&hw
->zsbuf
, curr
->zsbuf
);
292 static enum pipe_error
293 emit_framebuffer(struct svga_context
*svga
, unsigned dirty
)
295 if (svga_have_vgpu10(svga
)) {
296 return emit_fb_vgpu10(svga
);
299 return emit_fb_vgpu9(svga
);
305 * Rebind rendertargets.
307 * Similar to emit_framebuffer, but without any state checking/update.
309 * Called at the beginning of every new command buffer to ensure that
310 * non-dirty rendertargets are properly paged-in.
313 svga_reemit_framebuffer_bindings(struct svga_context
*svga
)
317 assert(svga
->rebind
.flags
.rendertargets
);
319 if (svga_have_vgpu10(svga
)) {
320 ret
= emit_fb_vgpu10(svga
);
323 ret
= svga_reemit_framebuffer_bindings_vgpu9(svga
);
326 svga
->rebind
.flags
.rendertargets
= FALSE
;
333 * Send a private allocation command to page in rendertargets resource.
336 svga_rebind_framebuffer_bindings(struct svga_context
*svga
)
338 struct svga_hw_clear_state
*hw
= &svga
->state
.hw_clear
;
342 assert(svga_have_vgpu10(svga
));
344 if (!svga
->rebind
.flags
.rendertargets
)
347 for (i
= 0; i
< hw
->num_rendertargets
; i
++) {
349 ret
= svga
->swc
->resource_rebind(svga
->swc
,
350 svga_surface(hw
->rtv
[i
])->handle
,
359 ret
= svga
->swc
->resource_rebind(svga
->swc
,
360 svga_surface(hw
->dsv
)->handle
,
367 svga
->rebind
.flags
.rendertargets
= 0;
373 struct svga_tracked_state svga_hw_framebuffer
=
375 "hw framebuffer state",
376 SVGA_NEW_FRAME_BUFFER
,
383 /***********************************************************************
386 static enum pipe_error
387 emit_viewport( struct svga_context
*svga
,
390 const struct pipe_viewport_state
*viewport
= &svga
->curr
.viewport
;
391 struct svga_prescale prescale
;
393 /* Not sure if this state is relevant with POSITIONT. Probably
394 * not, but setting to 0,1 avoids some state pingponging.
396 float range_min
= 0.0;
397 float range_max
= 1.0;
399 boolean degenerate
= FALSE
;
400 boolean invertY
= FALSE
;
403 float fb_width
= (float) svga
->curr
.framebuffer
.width
;
404 float fb_height
= (float) svga
->curr
.framebuffer
.height
;
406 float fx
= viewport
->scale
[0] * -1.0f
+ viewport
->translate
[0];
407 float fy
= flip
* viewport
->scale
[1] * -1.0f
+ viewport
->translate
[1];
408 float fw
= viewport
->scale
[0] * 2.0f
;
409 float fh
= flip
* viewport
->scale
[1] * 2.0f
;
410 boolean emit_vgpu10_viewport
= FALSE
;
412 memset( &prescale
, 0, sizeof(prescale
) );
414 /* Examine gallium viewport transformation and produce a screen
415 * rectangle and possibly vertex shader pre-transformation to
416 * get the same results.
419 SVGA_DBG(DEBUG_VIEWPORT
,
420 "\ninitial %f,%f %fx%f\n",
426 prescale
.scale
[0] = 1.0;
427 prescale
.scale
[1] = 1.0;
428 prescale
.scale
[2] = 1.0;
429 prescale
.scale
[3] = 1.0;
430 prescale
.translate
[0] = 0;
431 prescale
.translate
[1] = 0;
432 prescale
.translate
[2] = 0;
433 prescale
.translate
[3] = 0;
435 /* Enable prescale to adjust vertex positions to match
436 VGPU10 convention only if rasterization is enabled.
438 if (svga
->curr
.rast
&& svga
->curr
.rast
->templ
.rasterizer_discard
) {
442 prescale
.enabled
= TRUE
;
446 prescale
.scale
[0] *= -1.0f
;
447 prescale
.translate
[0] += -fw
;
449 fx
= viewport
->scale
[0] * 1.0f
+ viewport
->translate
[0];
453 if (svga_have_vgpu10(svga
)) {
454 /* floating point viewport params below */
455 prescale
.translate
[1] = fh
+ fy
* 2.0f
;
458 /* integer viewport params below */
459 prescale
.translate
[1] = fh
- 1.0f
+ fy
* 2.0f
;
463 prescale
.scale
[1] = -1.0f
;
468 prescale
.translate
[0] += fx
;
469 prescale
.scale
[0] *= fw
/ (fw
+ fx
);
476 prescale
.translate
[1] -= fy
;
479 prescale
.translate
[1] += fy
;
481 prescale
.scale
[1] *= fh
/ (fh
+ fy
);
486 if (fx
+ fw
> fb_width
) {
487 prescale
.scale
[0] *= fw
/ (fb_width
- fx
);
488 prescale
.translate
[0] -= fx
* (fw
/ (fb_width
- fx
));
489 prescale
.translate
[0] += fx
;
493 if (fy
+ fh
> fb_height
) {
494 prescale
.scale
[1] *= fh
/ (fb_height
- fy
);
496 float in
= fb_height
- fy
; /* number of vp pixels inside view */
497 float out
= fy
+ fh
- fb_height
; /* number of vp pixels out of view */
498 prescale
.translate
[1] += fy
* out
/ in
;
501 prescale
.translate
[1] -= fy
* (fh
/ (fb_height
- fy
));
502 prescale
.translate
[1] += fy
;
507 if (fw
< 0 || fh
< 0) {
508 fw
= fh
= fx
= fy
= 0;
513 /* D3D viewport is integer space. Convert fx,fy,etc. to
516 * TODO: adjust pretranslate correct for any subpixel error
517 * introduced converting to integers.
519 rect
.x
= (uint32
) fx
;
520 rect
.y
= (uint32
) fy
;
521 rect
.w
= (uint32
) fw
;
522 rect
.h
= (uint32
) fh
;
524 SVGA_DBG(DEBUG_VIEWPORT
,
525 "viewport error %f,%f %fx%f\n",
526 fabs((float)rect
.x
- fx
),
527 fabs((float)rect
.y
- fy
),
528 fabs((float)rect
.w
- fw
),
529 fabs((float)rect
.h
- fh
));
531 SVGA_DBG(DEBUG_VIEWPORT
,
532 "viewport %d,%d %dx%d\n",
538 /* Finally, to get GL rasterization rules, need to tweak the
539 * screen-space coordinates slightly relative to D3D which is
540 * what hardware implements natively.
542 if (svga
->curr
.rast
&& svga
->curr
.rast
->templ
.half_pixel_center
) {
543 float adjust_x
= 0.0;
544 float adjust_y
= 0.0;
546 if (svga_have_vgpu10(svga
)) {
547 /* Normally, we don't have to do any sub-pixel coordinate
548 * adjustments for VGPU10. But when we draw wide points with
549 * a GS we need an X adjustment in order to be conformant.
551 if (svga
->curr
.reduced_prim
== PIPE_PRIM_POINTS
&&
552 svga
->curr
.rast
->pointsize
> 1.0f
) {
557 switch (svga
->curr
.reduced_prim
) {
558 case PIPE_PRIM_POINTS
:
562 case PIPE_PRIM_LINES
:
566 case PIPE_PRIM_TRIANGLES
:
577 adjust_y
= -adjust_y
;
579 prescale
.translate
[0] += adjust_x
;
580 prescale
.translate
[1] += adjust_y
;
581 prescale
.translate
[2] = 0.5; /* D3D clip space */
582 prescale
.scale
[2] = 0.5; /* D3D clip space */
585 range_min
= viewport
->scale
[2] * -1.0f
+ viewport
->translate
[2];
586 range_max
= viewport
->scale
[2] * 1.0f
+ viewport
->translate
[2];
588 /* D3D (and by implication SVGA) doesn't like dealing with zmax
589 * less than zmin. Detect that case, flip the depth range and
590 * invert our z-scale factor to achieve the same effect.
592 if (range_min
> range_max
) {
594 range_tmp
= range_min
;
595 range_min
= range_max
;
596 range_max
= range_tmp
;
597 prescale
.scale
[2] = -prescale
.scale
[2];
600 /* If zmin is less than 0, clamp zmin to 0 and adjust the prescale.
601 * zmin can be set to -1 when viewport->scale[2] is set to 1 and
602 * viewport->translate[2] is set to 0 in the blit code.
604 if (range_min
< 0.0f
) {
605 range_min
= -0.5f
* viewport
->scale
[2] + 0.5f
+ viewport
->translate
[2];
606 range_max
= 0.5f
* viewport
->scale
[2] + 0.5f
+ viewport
->translate
[2];
607 prescale
.scale
[2] *= 2.0f
;
608 prescale
.translate
[2] -= 0.5f
;
611 if (prescale
.enabled
) {
616 SVGA_DBG(DEBUG_VIEWPORT
,
617 "prescale %f,%f %fx%f\n",
618 prescale
.translate
[0],
619 prescale
.translate
[1],
623 H
[0] = (float)rect
.w
/ 2.0f
;
624 H
[1] = -(float)rect
.h
/ 2.0f
;
625 J
[0] = (float)rect
.x
+ (float)rect
.w
/ 2.0f
;
626 J
[1] = (float)rect
.y
+ (float)rect
.h
/ 2.0f
;
628 SVGA_DBG(DEBUG_VIEWPORT
,
636 /* Adjust prescale to take into account the fact that it is
637 * going to be applied prior to the perspective divide and
638 * viewport transformation.
640 * Vwin = H(Vc/Vc.w) + J
642 * We want to tweak Vwin with scale and translation from above,
647 * But we can only modify the values at Vc. Plugging all the
648 * above together, and rearranging, eventually we get:
650 * Vwin' = H(Vc'/Vc'.w) + J
653 * K = (T + (S-1)J) / H
655 * Overwrite prescale.translate with values for K:
657 for (i
= 0; i
< 2; i
++) {
658 prescale
.translate
[i
] = ((prescale
.translate
[i
] +
659 (prescale
.scale
[i
] - 1.0f
) * J
[i
]) / H
[i
]);
662 SVGA_DBG(DEBUG_VIEWPORT
,
663 "clipspace %f,%f %fx%f\n",
664 prescale
.translate
[0],
665 prescale
.translate
[1],
676 prescale
.enabled
= FALSE
;
679 if (!svga_rects_equal(&rect
, &svga
->state
.hw_clear
.viewport
)) {
680 if (svga_have_vgpu10(svga
)) {
681 emit_vgpu10_viewport
= TRUE
;
684 ret
= SVGA3D_SetViewport(svga
->swc
, &rect
);
688 svga
->state
.hw_clear
.viewport
= rect
;
692 if (svga
->state
.hw_clear
.depthrange
.zmin
!= range_min
||
693 svga
->state
.hw_clear
.depthrange
.zmax
!= range_max
)
695 if (svga_have_vgpu10(svga
)) {
696 emit_vgpu10_viewport
= TRUE
;
699 ret
= SVGA3D_SetZRange(svga
->swc
, range_min
, range_max
);
703 svga
->state
.hw_clear
.depthrange
.zmin
= range_min
;
704 svga
->state
.hw_clear
.depthrange
.zmax
= range_max
;
708 if (emit_vgpu10_viewport
) {
710 vp
.x
= (float) rect
.x
;
711 vp
.y
= (float) rect
.y
;
712 vp
.width
= (float) rect
.w
;
713 vp
.height
= (float) rect
.h
;
714 vp
.minDepth
= range_min
;
715 vp
.maxDepth
= range_max
;
716 ret
= SVGA3D_vgpu10_SetViewports(svga
->swc
, 1, &vp
);
720 svga
->state
.hw_clear
.viewport
= rect
;
722 svga
->state
.hw_clear
.depthrange
.zmin
= range_min
;
723 svga
->state
.hw_clear
.depthrange
.zmax
= range_max
;
726 if (memcmp(&prescale
, &svga
->state
.hw_clear
.prescale
, sizeof prescale
) != 0) {
727 svga
->dirty
|= SVGA_NEW_PRESCALE
;
728 svga
->state
.hw_clear
.prescale
= prescale
;
735 struct svga_tracked_state svga_hw_viewport
=
738 ( SVGA_NEW_FRAME_BUFFER
|
741 SVGA_NEW_REDUCED_PRIMITIVE
),
746 /***********************************************************************
749 static enum pipe_error
750 emit_scissor_rect( struct svga_context
*svga
,
753 const struct pipe_scissor_state
*scissor
= &svga
->curr
.scissor
;
755 if (svga_have_vgpu10(svga
)) {
758 rect
.left
= scissor
->minx
;
759 rect
.top
= scissor
->miny
;
760 rect
.right
= scissor
->maxx
;
761 rect
.bottom
= scissor
->maxy
;
763 return SVGA3D_vgpu10_SetScissorRects(svga
->swc
, 1, &rect
);
768 rect
.x
= scissor
->minx
;
769 rect
.y
= scissor
->miny
;
770 rect
.w
= scissor
->maxx
- scissor
->minx
; /* + 1 ?? */
771 rect
.h
= scissor
->maxy
- scissor
->miny
; /* + 1 ?? */
773 return SVGA3D_SetScissorRect(svga
->swc
, &rect
);
778 struct svga_tracked_state svga_hw_scissor
=
786 /***********************************************************************
790 static enum pipe_error
791 emit_clip_planes( struct svga_context
*svga
,
797 /* TODO: just emit directly from svga_set_clip_state()?
799 for (i
= 0; i
< SVGA3D_MAX_CLIP_PLANES
; i
++) {
800 /* need to express the plane in D3D-style coordinate space.
801 * GL coords get converted to D3D coords with the matrix:
806 * Apply that matrix to our plane equation, and invert Y.
808 float a
= svga
->curr
.clip
.ucp
[i
][0];
809 float b
= svga
->curr
.clip
.ucp
[i
][1];
810 float c
= svga
->curr
.clip
.ucp
[i
][2];
811 float d
= svga
->curr
.clip
.ucp
[i
][3];
819 if (svga_have_vgpu10(svga
)) {
820 //debug_printf("XXX emit DX10 clip plane\n");
824 ret
= SVGA3D_SetClipPlane(svga
->swc
, i
, plane
);
834 struct svga_tracked_state svga_hw_clip_planes
=