diff --git a/src/gallium/drivers/zink/zink_blit.c b/src/gallium/drivers/zink/zink_blit.c index 0ea97375e7c..a2632d5cdec 100644 --- a/src/gallium/drivers/zink/zink_blit.c +++ b/src/gallium/drivers/zink/zink_blit.c @@ -442,6 +442,8 @@ zink_blit(struct pipe_context *pctx, zink_resource_object_init_mutable(ctx, dst); zink_blit_barriers(ctx, use_src, dst, whole); ctx->blitting = true; + ctx->blit_scissor = info->scissor_enable; + ctx->blit_nearest = info->filter == PIPE_TEX_FILTER_NEAREST; if (stencil_blit) { struct pipe_surface *dst_view, dst_templ; @@ -636,3 +638,36 @@ zink_blit_region_covers(struct u_rect region, struct u_rect covers) return intersect.x0 == c.x0 && intersect.y0 == c.y0 && intersect.x1 == c.x1 && intersect.y1 == c.y1; } + +void +zink_draw_rectangle(struct blitter_context *blitter, void *vertex_elements_cso, + blitter_get_vs_func get_vs, int x1, int y1, int x2, int y2, + float depth, unsigned num_instances, enum blitter_attrib_type type, + const union blitter_attrib *attrib) +{ + struct zink_context *ctx = zink_context(blitter->pipe); + + union blitter_attrib new_attrib = *attrib; + + /* Avoid inconsistencies in rounding between both triangles which can show with + * nearest filtering by expanding the rect so only one triangle is effectively drawn. + */ + if (ctx->blit_scissor && ctx->blit_nearest) { + int64_t new_x1 = (int64_t)x1 * 2 - x2; + int64_t new_y2 = (int64_t)y2 * 2 - y1; + if (new_x1 < INT32_MAX && new_x1 > INT32_MIN && + new_y2 < INT32_MAX && new_y2 > INT32_MIN) { + x1 = new_x1; + y2 = new_y2; + + if (type == UTIL_BLITTER_ATTRIB_TEXCOORD_XY || + type == UTIL_BLITTER_ATTRIB_TEXCOORD_XYZW) { + new_attrib.texcoord.x1 += new_attrib.texcoord.x1 - new_attrib.texcoord.x2; + new_attrib.texcoord.y2 += new_attrib.texcoord.y2 - new_attrib.texcoord.y1; + } + } + } + + util_blitter_draw_rectangle(blitter, vertex_elements_cso, get_vs, x1, y1, x2, y2, + depth, num_instances, type, &new_attrib); +} diff --git a/src/gallium/drivers/zink/zink_context.c b/src/gallium/drivers/zink/zink_context.c index 68d29cf2de6..4c3b4a5d969 100644 --- a/src/gallium/drivers/zink/zink_context.c +++ b/src/gallium/drivers/zink/zink_context.c @@ -5212,6 +5212,8 @@ zink_context_create(struct pipe_screen *pscreen, void *priv, unsigned flags) ctx->blitter = util_blitter_create(&ctx->base); if (!ctx->blitter) goto fail; + if (screen->driver_workarounds.inconsistent_interpolation) + ctx->blitter->draw_rectangle = zink_draw_rectangle; } zink_set_last_vertex_key(ctx)->last_vertex_stage = true; diff --git a/src/gallium/drivers/zink/zink_context.h b/src/gallium/drivers/zink/zink_context.h index 42f1a55e038..85ed9d5ccad 100644 --- a/src/gallium/drivers/zink/zink_context.h +++ b/src/gallium/drivers/zink/zink_context.h @@ -232,6 +232,12 @@ zink_blit_region_fills(struct u_rect region, unsigned width, unsigned height); bool zink_blit_region_covers(struct u_rect region, struct u_rect covers); +void +zink_draw_rectangle(struct blitter_context *blitter, void *vertex_elements_cso, + blitter_get_vs_func get_vs, int x1, int y1, int x2, int y2, + float depth, unsigned num_instances, enum blitter_attrib_type type, + const union blitter_attrib *attrib); + static inline struct u_rect zink_rect_from_box(const struct pipe_box *box) { diff --git a/src/gallium/drivers/zink/zink_screen.c b/src/gallium/drivers/zink/zink_screen.c index 591e7e9ccc6..ba1622b37b0 100644 --- a/src/gallium/drivers/zink/zink_screen.c +++ b/src/gallium/drivers/zink/zink_screen.c @@ -3052,6 +3052,8 @@ init_driver_workarounds(struct zink_screen *screen) case VK_DRIVER_ID_AMD_PROPRIETARY: /* this has bad perf on AMD */ screen->info.have_KHR_push_descriptor = false; + /* Interpolation is not consistent between two triangles of a rectangle. */ + screen->driver_workarounds.inconsistent_interpolation = true; break; default: break; diff --git a/src/gallium/drivers/zink/zink_types.h b/src/gallium/drivers/zink/zink_types.h index 64f5d0a8e2c..421e2cd863e 100644 --- a/src/gallium/drivers/zink/zink_types.h +++ b/src/gallium/drivers/zink/zink_types.h @@ -46,6 +46,7 @@ #include "util/set.h" #include "util/simple_mtx.h" #include "util/slab.h" +#include "util/u_blitter.h" #include "util/u_dynarray.h" #include "util/u_idalloc.h" #include "util/u_live_shader_cache.h" @@ -1542,6 +1543,7 @@ struct zink_screen { bool needs_zs_shader_swizzle; bool can_do_invalid_linear_modifier; bool io_opt; + bool inconsistent_interpolation; unsigned z16_unscaled_bias; unsigned z24_unscaled_bias; } driver_workarounds; @@ -2009,6 +2011,8 @@ struct zink_context { bool is_device_lost; bool primitive_restart; bool blitting : 1; + bool blit_scissor : 1; + bool blit_nearest : 1; bool unordered_blitting : 1; bool vertex_state_changed : 1; bool blend_state_changed : 1;