svga: disable rasterization if rasterizer_discard is set or FS undefined

With this patch, rasterization will be disabled if the
rasterizer_discard flag is set or the fragment shader
is undefined due to missing position output from the
vertex/geometry shader.

Tested with piglit test glsl-1.50-geometry-primitive-id-restart.
Also tested with full MTT glretrace and piglit.

v2: As suggested by Roland, to properly disable rasterization, besides
    setting FS to NULL, we will also need to disable depth and stencil test.

v3: As suggested by Brian, set SVGA_NEW_DEPTH_STENCIL_ALPHA dirty bit
    in svga_bind_rasterizer_state() if the rasterizer_discard flag is
    changed.

Reviewed-by: Brian Paul <brianp@vmware.com>
This commit is contained in:
Charmaine Lee 2017-04-04 12:47:49 -06:00 committed by Brian Paul
parent fed72ff6cb
commit b4c4ee0762
6 changed files with 129 additions and 40 deletions

View file

@ -67,6 +67,11 @@ svga_destroy(struct pipe_context *pipe)
}
}
/* free depthstencil_disable state */
if (svga->depthstencil_disable) {
pipe->delete_depth_stencil_alpha_state(pipe, svga->depthstencil_disable);
}
/* free HW constant buffers */
for (shader = 0; shader < ARRAY_SIZE(svga->state.hw_draw.constbuf); shader++) {
pipe_resource_reference(&svga->state.hw_draw.constbuf[shader], NULL);
@ -248,6 +253,7 @@ svga_context_create(struct pipe_screen *screen, void *priv, unsigned flags)
svga->state.hw_draw.num_views = 0;
svga->state.hw_draw.num_rendertargets = 0;
svga->state.hw_draw.dsv = NULL;
svga->state.hw_draw.rasterizer_discard = FALSE;
/* Initialize the shader pointers */
svga->state.hw_draw.vs = NULL;
@ -289,6 +295,7 @@ svga_context_create(struct pipe_screen *screen, void *priv, unsigned flags)
svga->dirty = ~0;
svga->pred.query_id = SVGA3D_INVALID_ID;
svga->disable_rasterizer = FALSE;
return &svga->pipe;

View file

@ -399,6 +399,8 @@ struct svga_hw_draw_state
/* used for rebinding */
unsigned default_constbuf_size[PIPE_SHADER_TYPES];
boolean rasterizer_discard; /* set if rasterization is disabled */
};
@ -583,6 +585,9 @@ struct svga_context
/** Alternate rasterizer states created for point sprite */
struct svga_rasterizer_state *rasterizer_no_cull[2];
/** Depth stencil state created to disable depth stencil test */
struct svga_depth_stencil_state *depthstencil_disable;
/** Current conditional rendering predicate */
struct {
SVGA3dQueryId query_id;
@ -590,6 +595,7 @@ struct svga_context
} pred;
boolean render_condition;
boolean disable_rasterizer; /* Set if to disable rasterization */
};
/* A flag for each state_tracker state object:

View file

@ -45,6 +45,16 @@
#include "svga_debug.h"
#include "svga_resource_buffer.h"
/* Returns TRUE if we are currently using flat shading.
*/
static boolean
is_using_flat_shading(const struct svga_context *svga)
{
return
svga->state.hw_draw.fs ? svga->state.hw_draw.fs->uses_flat_interp : FALSE;
}
static enum pipe_error
retry_draw_range_elements( struct svga_context *svga,
struct pipe_resource *index_buffer,
@ -74,7 +84,7 @@ retry_draw_range_elements( struct svga_context *svga,
*/
svga_hwtnl_set_flatshade(svga->hwtnl,
svga->curr.rast->templ.flatshade ||
svga->state.hw_draw.fs->uses_flat_interp,
is_using_flat_shading(svga),
svga->curr.rast->templ.flatshade_first);
ret = svga_hwtnl_draw_range_elements( svga->hwtnl,
@ -126,7 +136,7 @@ retry_draw_arrays( struct svga_context *svga,
*/
svga_hwtnl_set_flatshade(svga->hwtnl,
svga->curr.rast->templ.flatshade ||
svga->state.hw_draw.fs->uses_flat_interp,
is_using_flat_shading(svga),
svga->curr.rast->templ.flatshade_first);
ret = svga_hwtnl_draw_arrays(svga->hwtnl, prim, start, count,

View file

@ -378,11 +378,18 @@ svga_bind_rasterizer_state(struct pipe_context *pipe, void *state)
struct svga_context *svga = svga_context(pipe);
struct svga_rasterizer_state *raster = (struct svga_rasterizer_state *)state;
if (!raster ||
!svga->curr.rast ||
raster->templ.poly_stipple_enable !=
svga->curr.rast->templ.poly_stipple_enable) {
svga->dirty |= SVGA_NEW_STIPPLE;
if (!raster || !svga->curr.rast) {
svga->dirty |= SVGA_NEW_STIPPLE | SVGA_NEW_DEPTH_STENCIL_ALPHA;
}
else {
if (raster->templ.poly_stipple_enable !=
svga->curr.rast->templ.poly_stipple_enable) {
svga->dirty |= SVGA_NEW_STIPPLE;
}
if (raster->templ.rasterizer_discard !=
svga->curr.rast->templ.rasterizer_discard) {
svga->dirty |= SVGA_NEW_DEPTH_STENCIL_ALPHA;
}
}
svga->curr.rast = raster;

View file

@ -408,6 +408,27 @@ emit_hw_fs(struct svga_context *svga, unsigned dirty)
SVGA_STATS_TIME_PUSH(svga_sws(svga), SVGA_STATS_TIME_EMITFS);
/* Disable rasterization if rasterizer_discard flag is set or
* vs/gs does not output position.
*/
svga->disable_rasterizer =
svga->curr.rast->templ.rasterizer_discard ||
(svga->curr.gs && !svga->curr.gs->base.info.writes_position) ||
(!svga->curr.gs && !svga->curr.vs->base.info.writes_position);
/* Set FS to NULL when rasterization is to be disabled */
if (svga->disable_rasterizer) {
/* Set FS to NULL if it has not been done */
if (svga->state.hw_draw.fs) {
ret = svga_set_shader(svga, SVGA3D_SHADERTYPE_PS, NULL);
if (ret != PIPE_OK)
goto done;
}
svga->rebind.flags.fs = FALSE;
svga->state.hw_draw.fs = NULL;
goto done;
}
/* SVGA_NEW_BLEND
* SVGA_NEW_TEXTURE_BINDING
* SVGA_NEW_RAST

View file

@ -336,6 +336,21 @@ get_no_cull_rasterizer_state(struct svga_context *svga)
return svga->rasterizer_no_cull[aa_point];
}
/** Returns a depth stencil state object with depth and stencil test disabled.
*/
static struct svga_depth_stencil_state *
get_no_depth_stencil_test_state(struct svga_context *svga)
{
if (!svga->depthstencil_disable) {
struct pipe_depth_stencil_alpha_state ds = {{0}};
svga->depthstencil_disable =
svga->pipe.create_depth_stencil_alpha_state(&svga->pipe, &ds);
}
return svga->depthstencil_disable;
}
static enum pipe_error
emit_rss_vgpu10(struct svga_context *svga, unsigned dirty)
{
@ -394,45 +409,67 @@ emit_rss_vgpu10(struct svga_context *svga, unsigned dirty)
}
}
if (dirty & (SVGA_NEW_DEPTH_STENCIL_ALPHA | SVGA_NEW_STENCIL_REF)) {
const struct svga_depth_stencil_state *curr = svga->curr.depth;
unsigned curr_ref = svga->curr.stencil_ref.ref_value[0];
if (svga->disable_rasterizer) {
if (!svga->state.hw_draw.rasterizer_discard) {
struct svga_depth_stencil_state *ds;
if (curr->id != svga->state.hw_draw.depth_stencil_id ||
curr_ref != svga->state.hw_draw.stencil_ref) {
/* Set/bind the depth/stencil state object */
ret = SVGA3D_vgpu10_SetDepthStencilState(svga->swc, curr->id,
curr_ref);
if (ret != PIPE_OK)
return ret;
svga->state.hw_draw.depth_stencil_id = curr->id;
svga->state.hw_draw.stencil_ref = curr_ref;
}
}
if (dirty & (SVGA_NEW_REDUCED_PRIMITIVE | SVGA_NEW_RAST)) {
const struct svga_rasterizer_state *rast;
if (svga->curr.reduced_prim == PIPE_PRIM_POINTS &&
svga->curr.gs && svga->curr.gs->wide_point) {
/* If we are drawing a point sprite, we will need to
* bind a non-culling rasterizer state object
/* If rasterization is to be disabled, disable depth and stencil
* testing as well.
*/
rast = get_no_cull_rasterizer_state(svga);
ds = get_no_depth_stencil_test_state(svga);
if (ds->id != svga->state.hw_draw.depth_stencil_id) {
ret = SVGA3D_vgpu10_SetDepthStencilState(svga->swc, ds->id, 0);
if (ret != PIPE_OK)
return ret;
svga->state.hw_draw.depth_stencil_id = ds->id;
svga->state.hw_draw.stencil_ref = 0;
}
svga->state.hw_draw.rasterizer_discard = TRUE;
}
else {
rast = svga->curr.rast;
} else {
if ((dirty & (SVGA_NEW_DEPTH_STENCIL_ALPHA | SVGA_NEW_STENCIL_REF)) ||
svga->state.hw_draw.rasterizer_discard) {
const struct svga_depth_stencil_state *curr = svga->curr.depth;
unsigned curr_ref = svga->curr.stencil_ref.ref_value[0];
if (curr->id != svga->state.hw_draw.depth_stencil_id ||
curr_ref != svga->state.hw_draw.stencil_ref) {
/* Set/bind the depth/stencil state object */
ret = SVGA3D_vgpu10_SetDepthStencilState(svga->swc, curr->id,
curr_ref);
if (ret != PIPE_OK)
return ret;
svga->state.hw_draw.depth_stencil_id = curr->id;
svga->state.hw_draw.stencil_ref = curr_ref;
}
}
if (svga->state.hw_draw.rasterizer_id != rast->id) {
/* Set/bind the rasterizer state object */
ret = SVGA3D_vgpu10_SetRasterizerState(svga->swc, rast->id);
if (ret != PIPE_OK)
return ret;
svga->state.hw_draw.rasterizer_id = rast->id;
if (dirty & (SVGA_NEW_REDUCED_PRIMITIVE | SVGA_NEW_RAST)) {
const struct svga_rasterizer_state *rast;
if (svga->curr.reduced_prim == PIPE_PRIM_POINTS &&
svga->curr.gs && svga->curr.gs->wide_point) {
/* If we are drawing a point sprite, we will need to
* bind a non-culling rasterizer state object
*/
rast = get_no_cull_rasterizer_state(svga);
}
else {
rast = svga->curr.rast;
}
if (svga->state.hw_draw.rasterizer_id != rast->id) {
/* Set/bind the rasterizer state object */
ret = SVGA3D_vgpu10_SetRasterizerState(svga->swc, rast->id);
if (ret != PIPE_OK)
return ret;
svga->state.hw_draw.rasterizer_id = rast->id;
}
}
svga->state.hw_draw.rasterizer_discard = FALSE;
}
return PIPE_OK;
}
@ -461,6 +498,7 @@ struct svga_tracked_state svga_hw_rss =
SVGA_NEW_RAST |
SVGA_NEW_FRAME_BUFFER |
SVGA_NEW_NEED_PIPELINE |
SVGA_NEW_FS |
SVGA_NEW_REDUCED_PRIMITIVE),
emit_rss