diff --git a/src/gallium/drivers/r300/ci/r300-rv380-fails.txt b/src/gallium/drivers/r300/ci/r300-rv380-fails.txt index b71fac13773..761b5580ade 100644 --- a/src/gallium/drivers/r300/ci/r300-rv380-fails.txt +++ b/src/gallium/drivers/r300/ci/r300-rv380-fails.txt @@ -1,16 +1,9 @@ -dEQP-GLES2.functional.clipping.line.wide_line_clip_viewport_center,Fail -dEQP-GLES2.functional.clipping.line.wide_line_clip_viewport_corner,Fail -dEQP-GLES2.functional.clipping.point.wide_point_clip,Fail -dEQP-GLES2.functional.clipping.point.wide_point_clip_viewport_center,Fail -dEQP-GLES2.functional.clipping.point.wide_point_clip_viewport_corner,Fail dEQP-GLES2.functional.fbo.completeness.renderable.texture.color0.rgb_half_float_oes,Fail dEQP-GLES2.functional.fbo.render.repeated_clear.tex2d_rgb,Fail dEQP-GLES2.functional.fbo.render.repeated_clear.tex2d_rgba,Fail dEQP-GLES2.functional.polygon_offset.fixed16_displacement_with_units,Fail dEQP-GLES2.functional.polygon_offset.fixed16_render_with_units,Fail -dEQP-GLES2.functional.rasterization.primitives.line_loop_wide,Fail -dEQP-GLES2.functional.rasterization.primitives.line_strip_wide,Fail dEQP-GLES2.functional.shaders.builtin_variable.frontfacing,Fail dEQP-GLES2.functional.shaders.conversions.vector_combine.vec2_bool_to_ivec3_fragment,Fail dEQP-GLES2.functional.shaders.conversions.vector_combine.vec2_bvec2_to_ivec4_fragment,Fail diff --git a/src/gallium/drivers/r300/ci/r300-rv410-fails.txt b/src/gallium/drivers/r300/ci/r300-rv410-fails.txt index 44d7e3dc8d5..b6a0ae3d509 100644 --- a/src/gallium/drivers/r300/ci/r300-rv410-fails.txt +++ b/src/gallium/drivers/r300/ci/r300-rv410-fails.txt @@ -1,8 +1,3 @@ -dEQP-GLES2.functional.clipping.line.wide_line_clip_viewport_center,Fail -dEQP-GLES2.functional.clipping.line.wide_line_clip_viewport_corner,Fail -dEQP-GLES2.functional.clipping.point.wide_point_clip,Fail -dEQP-GLES2.functional.clipping.point.wide_point_clip_viewport_center,Fail -dEQP-GLES2.functional.clipping.point.wide_point_clip_viewport_corner,Fail dEQP-GLES2.functional.fbo.completeness.renderable.texture.color0.rgb_half_float_oes,Fail dEQP-GLES2.functional.fbo.render.repeated_clear.tex2d_rgb,Fail diff --git a/src/gallium/drivers/r300/ci/r300-rv530-nohiz-fails.txt b/src/gallium/drivers/r300/ci/r300-rv530-nohiz-fails.txt index 61f35fd6e7d..744f9daee44 100644 --- a/src/gallium/drivers/r300/ci/r300-rv530-nohiz-fails.txt +++ b/src/gallium/drivers/r300/ci/r300-rv530-nohiz-fails.txt @@ -1,11 +1,3 @@ -# Wide points fully clipped when they should show up partially. -dEQP-GLES2.functional.clipping.point.wide_point_clip,Fail -dEQP-GLES2.functional.clipping.point.wide_point_clip_viewport_center,Fail -dEQP-GLES2.functional.clipping.point.wide_point_clip_viewport_corner,Fail -dEQP-GLES2.functional.clipping.line.wide_line_clip_viewport_center,Fail -dEQP-GLES2.functional.clipping.line.wide_line_clip_viewport_corner,Fail - - # "Framebuffer checked as complete, expected incomplete" dEQP-GLES2.functional.fbo.completeness.renderable.texture.color0.rgb_half_float_oes,Fail @@ -17,10 +9,6 @@ dEQP-GLES2.functional.polygon_offset.fixed16_displacement_with_units,Fail dEQP-GLES2.functional.polygon_offset.fixed16_render_with_units,Fail dEQP-GLES2.functional.polygon_offset.fixed16_factor_1_slope,Fail -# "Invalid line width at (119, 179) - (119, 180). Detected width of 2, expected 1" -dEQP-GLES2.functional.rasterization.primitives.line_strip_wide,Fail,Fail -dEQP-GLES2.functional.rasterization.primitives.line_loop_wide,Fail - dEQP-GLES2.functional.texture.format.a8_cube_npot,Fail dEQP-GLES2.functional.texture.format.l8_cube_npot,Fail dEQP-GLES2.functional.texture.format.la88_cube_npot,Fail diff --git a/src/gallium/drivers/r300/r300_context.c b/src/gallium/drivers/r300/r300_context.c index 1adb2363630..89334100d6e 100644 --- a/src/gallium/drivers/r300/r300_context.c +++ b/src/gallium/drivers/r300/r300_context.c @@ -104,6 +104,7 @@ static void r300_destroy_context(struct pipe_context* context) FREE(r300->invariant_state.state); FREE(r300->rs_block_state.state); FREE(r300->sample_mask.state); + FREE(r300->guardband_state.state); FREE(r300->scissor_state.state); FREE(r300->textures_state.state); FREE(r300->vap_invariant_state.state); @@ -184,6 +185,7 @@ static bool r300_setup_atoms(struct r300_context* r300) /* VAP. */ R300_INIT_ATOM(viewport_state, 9); R300_INIT_ATOM(pvs_flush, 2); + R300_INIT_ATOM(guardband_state, 5); R300_INIT_ATOM(vap_invariant_state, is_r500 || !has_tcl ? 11 : 9); R300_INIT_ATOM(vertex_stream_state, 0); R300_INIT_ATOM(vs_state, 0); @@ -228,6 +230,7 @@ static bool r300_setup_atoms(struct r300_context* r300) R300_ALLOC_ATOM(fb_state, pipe_framebuffer_state); R300_ALLOC_ATOM(gpu_flush, pipe_framebuffer_state); r300->sample_mask.state = malloc(4); + R300_ALLOC_ATOM(guardband_state, r300_guardband_state); R300_ALLOC_ATOM(scissor_state, pipe_scissor_state); R300_ALLOC_ATOM(rs_block_state, r300_rs_block); R300_ALLOC_ATOM(fs_constants, r300_constant_buffer); @@ -408,6 +411,18 @@ struct pipe_context* r300_create_context(struct pipe_screen* screen, if (!r300_setup_atoms(r300)) goto fail; + r300->current_clip_discard_distance = 0.0f; + r300->min_clip_discard_distance_watermark = 0.0f; + r300->current_rast_prim = ~0u; + struct r300_guardband_state *guard = + (struct r300_guardband_state *)r300->guardband_state.state; + if (guard) { + guard->vert_clip = 1.0f; + guard->vert_disc = 1.0f; + guard->horz_clip = 1.0f; + guard->horz_disc = 1.0f; + } + r300_init_blit_functions(r300); r300_init_flush_functions(r300); r300_init_query_functions(r300); diff --git a/src/gallium/drivers/r300/r300_context.h b/src/gallium/drivers/r300/r300_context.h index ce5ce00db65..05b3b0742ad 100644 --- a/src/gallium/drivers/r300/r300_context.h +++ b/src/gallium/drivers/r300/r300_context.h @@ -40,6 +40,18 @@ enum colormask_swizzle { COLORMASK_NUM_SWIZZLES }; +static inline bool r300_prim_is_lines(unsigned prim) +{ + switch (prim) { + case MESA_PRIM_LINES: + case MESA_PRIM_LINE_LOOP: + case MESA_PRIM_LINE_STRIP: + return true; + default: + return false; + } +} + struct r300_atom { /* Name, for debugging. */ const char* name; @@ -144,6 +156,9 @@ struct r300_rs_state { /* This is emitted in the draw function. */ uint32_t color_control; /* R300_GA_COLOR_CONTROL: 0x4278 */ + + float max_point_size; + float line_width; }; struct r300_rs_block { @@ -203,6 +218,13 @@ struct r300_texture_sampler_state { uint32_t border_color; /* R300_TX_BORDER_COLOR: 0x45c0 */ }; +struct r300_guardband_state { + float vert_clip; + float vert_disc; + float horz_clip; + float horz_disc; +}; + struct r300_textures_state { /* Textures. */ struct r300_sampler_view *sampler_views[16]; @@ -499,6 +521,8 @@ struct r300_context { struct r300_atom scissor_state; /* Sample mask. */ struct r300_atom sample_mask; + /* Guard band configuration. */ + struct r300_atom guardband_state; /* Invariant state. This must be emitted to get the engine started. */ struct r300_atom invariant_state; /* Viewport state. */ @@ -580,6 +604,24 @@ struct r300_context { bool alpha_to_one; bool alpha_to_coverage; + /* The number of pixels outside the viewport that are not culled by the clipper. + * Normally, the clipper clips everything outside the viewport, however, points and lines + * can have vertices outside the viewport, but their edges can be inside the viewport. Those + * shouldn't be culled. The problem is that the register setting (VAP_GB_*_DISC_ADJ) that + * controls the discard distance, which depends on the point size and line width, applies to + * all primitive types, and we would have to set 0 distance for triangles and non-zero for + * points and lines whenever the primitive type changes, which would add overhead and cause + * context rolls. + * + * To reduce that, whenever the discard distance changes for points and lines, we keep it + * at that higher value up to a certain small number for all primitive types including all + * points and lines within a specific size. This is slightly inefficient, but it eliminates + * a lot of guardband state updates and context register changes. + */ + float current_clip_discard_distance; + float min_clip_discard_distance_watermark; + unsigned current_rast_prim; + void *dsa_decompress_zmask; struct pipe_vertex_buffer vertex_buffer[PIPE_MAX_ATTRIBS]; @@ -709,6 +751,9 @@ void r300_init_render_functions(struct r300_context *r300); void r300_init_state_functions(struct r300_context* r300); void r300_init_resource_functions(struct r300_context* r300); +void r300_update_guardband_state(struct r300_context *r300); +void r300_set_clip_discard_distance(struct r300_context *r300, float distance); + /* r300_blit.c */ void r300_decompress_zmask(struct r300_context *r300); void r300_decompress_zmask_locked_unsafe(struct r300_context *r300); diff --git a/src/gallium/drivers/r300/r300_emit.c b/src/gallium/drivers/r300/r300_emit.c index c629e4fb829..b981f6b5b54 100644 --- a/src/gallium/drivers/r300/r300_emit.c +++ b/src/gallium/drivers/r300/r300_emit.c @@ -859,6 +859,24 @@ void r300_emit_sample_mask(struct r300_context *r300, END_CS; } +void r300_emit_guardband_state(struct r300_context *r300, + unsigned size, void *state) +{ + struct r300_guardband_state *guard = (struct r300_guardband_state *)state; + CS_LOCALS(r300); + + if (!guard) + return; + + BEGIN_CS(size); + OUT_CS_REG_SEQ(R300_VAP_GB_VERT_CLIP_ADJ, 4); + OUT_CS_32F(guard->vert_clip); + OUT_CS_32F(guard->vert_disc); + OUT_CS_32F(guard->horz_clip); + OUT_CS_32F(guard->horz_disc); + END_CS; +} + void r300_emit_scissor_state(struct r300_context* r300, unsigned size, void* state) { diff --git a/src/gallium/drivers/r300/r300_emit.h b/src/gallium/drivers/r300/r300_emit.h index 94e445f6d0e..a10a5f4af50 100644 --- a/src/gallium/drivers/r300/r300_emit.h +++ b/src/gallium/drivers/r300/r300_emit.h @@ -65,6 +65,8 @@ void r300_emit_rs_block_state(struct r300_context* r300, void r300_emit_sample_mask(struct r300_context *r300, unsigned size, void *state); +void r300_emit_guardband_state(struct r300_context *r300, + unsigned size, void *state); void r300_emit_scissor_state(struct r300_context* r300, unsigned size, void* state); diff --git a/src/gallium/drivers/r300/r300_render.c b/src/gallium/drivers/r300/r300_render.c index ee99933ac52..1033e4c14ff 100644 --- a/src/gallium/drivers/r300/r300_render.c +++ b/src/gallium/drivers/r300/r300_render.c @@ -778,6 +778,27 @@ static unsigned r300_max_vertex_count(struct r300_context *r300) return result; } +static void +r300_update_clip_discard_distance(struct r300_context *r300, unsigned prim) +{ + struct r300_rs_state *rs = (struct r300_rs_state*)r300->rs_state.state; + float target_distance = 0.0f; + + if (rs) { + if (prim == MESA_PRIM_POINTS) + target_distance = rs->max_point_size; + else if (r300_prim_is_lines(prim)) + target_distance = rs->line_width; + } + + if (r300->current_rast_prim != prim) { + r300->current_rast_prim = prim; + r300_set_clip_discard_distance(r300, target_distance); + } else if (prim == MESA_PRIM_POINTS || r300_prim_is_lines(prim)) { + r300_set_clip_discard_distance(r300, target_distance); + } +} + static void r300_draw_vbo(struct pipe_context* pipe, const struct pipe_draw_info *dinfo, @@ -800,6 +821,8 @@ static void r300_draw_vbo(struct pipe_context* pipe, return; } + r300_update_clip_discard_distance(r300, info.mode); + if (r300->sprite_coord_enable != 0) if ((info.mode == MESA_PRIM_POINTS) != r300->is_point) { r300->is_point = !r300->is_point; diff --git a/src/gallium/drivers/r300/r300_state.c b/src/gallium/drivers/r300/r300_state.c index abcf8c9bc60..901b88b66a9 100644 --- a/src/gallium/drivers/r300/r300_state.c +++ b/src/gallium/drivers/r300/r300_state.c @@ -55,6 +55,107 @@ r300_get_scissor_from_viewport(const struct pipe_viewport_state *vp, scissor->maxy = CLAMP(half_h + vp->translate[1], 0, max_scissor); } +#define R300_MAX_VIEWPORT_RANGE 16384.0f + +void r300_update_guardband_state(struct r300_context *r300) +{ + struct r300_guardband_state *guard = + (struct r300_guardband_state *)r300->guardband_state.state; + + if (!guard) + return; + + const float distance = r300->current_clip_discard_distance; + + if (distance == 0.0f) { + if (guard->vert_clip != 1.0f || guard->vert_disc != 1.0f || + guard->horz_clip != 1.0f || guard->horz_disc != 1.0f) { + DBG(r300, DBG_RS, "r300: guardband reset for zero distance\n"); + guard->vert_clip = 1.0f; + guard->vert_disc = 1.0f; + guard->horz_clip = 1.0f; + guard->horz_disc = 1.0f; + r300_mark_atom_dirty(r300, &r300->pvs_flush); + r300_mark_atom_dirty(r300, &r300->guardband_state); + } + return; + } + + const struct pipe_viewport_state *vp = &r300->viewport; + float scale_x = fabs(vp->scale[0]); + float scale_y = fabs(vp->scale[1]); + float translate_x = vp->translate[0]; + float translate_y = vp->translate[1]; + + /* Treat a 0x0 viewport as 1x1 to prevent a division by zero. */ + if (scale_x == 0.0f) + scale_x = 0.5f; + if (scale_y == 0.0f) + scale_y = 0.5f; + + /* Find the biggest guard band that is inside the supported viewport + * range. The guard band is specified as a horizontal and vertical + * distance from (0,0) in clip space. + * + * This is done by applying the inverse viewport transformation + * on the viewport limits to get those limits in clip space. + * + * Use a limit one pixel smaller to allow for some precision error. + */ + const float max_range = R300_MAX_VIEWPORT_RANGE - 1.0f; + float left = (-max_range - translate_x) / scale_x; + float right = (max_range - translate_x) / scale_x; + float top = (-max_range - translate_y) / scale_y; + float bottom = (max_range - translate_y) / scale_y; + assert(left <= -1 && top <= -1 && right >= 1 && bottom >= 1); + + float guardband_x = MIN2(-left, right); + float guardband_y = MIN2(-top, bottom); + + float discard_x = 1.0f + distance / (2.0f * scale_x); + float discard_y = 1.0f + distance / (2.0f * scale_y); + + discard_x = MIN2(discard_x, guardband_x); + discard_y = MIN2(discard_y, guardband_y); + + if (guard->vert_clip == guardband_y && + guard->vert_disc == discard_y && + guard->horz_clip == guardband_x && + guard->horz_disc == discard_x) { + return; + } + + guard->vert_clip = guardband_y; + guard->vert_disc = discard_y; + guard->horz_clip = guardband_x; + guard->horz_disc = discard_x; + + r300_mark_atom_dirty(r300, &r300->pvs_flush); + r300_mark_atom_dirty(r300, &r300->guardband_state); +} + +void r300_set_clip_discard_distance(struct r300_context *r300, float distance) +{ + /* Determine whether the guardband registers change. + * + * When we see a value greater than min_clip_discard_distance_watermark, we increase it + * up to a certain number to eliminate those state changes next time they happen. + * See the comment at min_clip_discard_distance_watermark. + */ + if (distance > r300->min_clip_discard_distance_watermark) { + /* This is based on r600, which is based on Viewperf. The number is in half-pixels. */ + r300->min_clip_discard_distance_watermark = MIN2(distance, 6.0f); + } + + float new_distance = MAX2(distance, r300->min_clip_discard_distance_watermark); + + if (r300->current_clip_discard_distance != new_distance) { + r300->current_clip_discard_distance = new_distance; + } + + r300_update_guardband_state(r300); +} + static void r300_delete_vs_state(struct pipe_context* pipe, void* shader); static void r300_delete_fs_state(struct pipe_context* pipe, void* shader); @@ -1265,6 +1366,7 @@ static void* r300_create_rs_state(struct pipe_context* pipe, (pack_float_16_6x(state->point_size) << R300_POINTSIZE_X_SHIFT); /* Point size clamping. */ + float max_point_size; if (state->point_size_per_vertex) { /* Per-vertex point size. * Clamp to [0, max FB size] */ @@ -1273,6 +1375,7 @@ static void* r300_create_rs_state(struct pipe_context* pipe, point_minmax = (pack_float_16_6x(min_psiz) << R300_GA_POINT_MINMAX_MIN_SHIFT) | (pack_float_16_6x(max_psiz) << R300_GA_POINT_MINMAX_MAX_SHIFT); + max_point_size = max_psiz; } else { /* We cannot disable the point-size vertex output, * so clamp it. */ @@ -1280,6 +1383,7 @@ static void* r300_create_rs_state(struct pipe_context* pipe, point_minmax = (pack_float_16_6x(psiz) << R300_GA_POINT_MINMAX_MIN_SHIFT) | (pack_float_16_6x(psiz) << R300_GA_POINT_MINMAX_MAX_SHIFT); + max_point_size = psiz; } /* Line control. */ @@ -1421,6 +1525,9 @@ static void* r300_create_rs_state(struct pipe_context* pipe, END_CB; } + rs->max_point_size = max_point_size; + rs->line_width = state->line_width; + return (void*)rs; } @@ -1485,6 +1592,16 @@ static void r300_bind_rs_state(struct pipe_context* pipe, void* state) if (last_scissor_enabled != r300->scissor_enabled) { r300_mark_atom_dirty(r300, &r300->scissor_state); } + + if (rs) { + if (r300->current_rast_prim == MESA_PRIM_POINTS) { + r300_set_clip_discard_distance(r300, rs->max_point_size); + } else if (r300_prim_is_lines(r300->current_rast_prim)) { + r300_set_clip_discard_distance(r300, rs->line_width); + } + } else { + r300_set_clip_discard_distance(r300, 0.0f); + } } /* Free rasterizer state. */