diff --git a/src/gallium/drivers/r600/evergreen_state.c b/src/gallium/drivers/r600/evergreen_state.c index 84c7e05d781..b20e9a861d3 100644 --- a/src/gallium/drivers/r600/evergreen_state.c +++ b/src/gallium/drivers/r600/evergreen_state.c @@ -4670,6 +4670,7 @@ void evergreen_init_state_functions(struct r600_context *rctx) r600_add_atom(rctx, &rctx->b.render_cond_atom, id++); r600_add_atom(rctx, &rctx->b.streamout.begin_atom, id++); r600_add_atom(rctx, &rctx->b.streamout.enable_atom, id++); + r600_add_atom(rctx, &rctx->b.window_rectangles.atom, id++); for (i = 0; i < EG_NUM_HW_STAGES; i++) r600_init_atom(rctx, &rctx->hw_shader_stages[i].atom, id++, r600_emit_shader, 0); r600_init_atom(rctx, &rctx->shader_stages.atom, id++, evergreen_emit_shader_stages, 15); diff --git a/src/gallium/drivers/r600/r600_blit.c b/src/gallium/drivers/r600/r600_blit.c index 9f54885f672..3d3da99512c 100644 --- a/src/gallium/drivers/r600/r600_blit.c +++ b/src/gallium/drivers/r600/r600_blit.c @@ -65,6 +65,9 @@ static void r600_blitter_begin(struct pipe_context *ctx, enum r600_blitter_op op util_blitter_save_depth_stencil_alpha(rctx->blitter, rctx->dsa_state.cso); util_blitter_save_stencil_ref(rctx->blitter, &rctx->stencil_ref.pipe_state); util_blitter_save_sample_mask(rctx->blitter, rctx->sample_mask.sample_mask, rctx->ps_iter_samples); + util_blitter_save_window_rectangles(rctx->blitter, rctx->b.window_rectangles.include, + rctx->b.window_rectangles.number, + rctx->b.window_rectangles.states); } if (op & R600_SAVE_CONST_BUF0) { diff --git a/src/gallium/drivers/r600/r600_pipe.c b/src/gallium/drivers/r600/r600_pipe.c index 3ab26877e1b..f8f6b04fcdd 100644 --- a/src/gallium/drivers/r600/r600_pipe.c +++ b/src/gallium/drivers/r600/r600_pipe.c @@ -475,6 +475,7 @@ static void r600_init_screen_caps(struct r600_screen *rscreen) caps->two_sided_color = false; caps->cull_distance = true; + caps->max_window_rectangles = R600_MAX_WINDOW_RECTANGLES; caps->shader_buffer_offset_alignment = family >= CHIP_CEDAR ? 256 : 0; caps->max_shader_patch_varyings = family >= CHIP_CEDAR ? 30 : 0; diff --git a/src/gallium/drivers/r600/r600_pipe.h b/src/gallium/drivers/r600/r600_pipe.h index 8c0315a8dbe..08fd97f771f 100644 --- a/src/gallium/drivers/r600/r600_pipe.h +++ b/src/gallium/drivers/r600/r600_pipe.h @@ -20,7 +20,7 @@ #include "tgsi/tgsi_scan.h" -#define R600_NUM_ATOMS 56 +#define R600_NUM_ATOMS 57 #define R600_MAX_IMAGES 8 /* diff --git a/src/gallium/drivers/r600/r600_pipe_common.h b/src/gallium/drivers/r600/r600_pipe_common.h index 0adf361a34e..74ccbe9f53a 100644 --- a/src/gallium/drivers/r600/r600_pipe_common.h +++ b/src/gallium/drivers/r600/r600_pipe_common.h @@ -446,6 +446,16 @@ struct r600_viewports { struct r600_signed_scissor as_scissor[R600_MAX_VIEWPORTS]; }; +/* EXT_window_rectangles */ +#define R600_MAX_WINDOW_RECTANGLES 4 + +struct r600_window_rectangles { + unsigned number; + bool include; + struct pipe_scissor_state states[R600_MAX_WINDOW_RECTANGLES]; + struct r600_atom atom; +}; + struct r600_ring { struct radeon_cmdbuf cs; void (*flush)(void *ctx, unsigned flags, @@ -493,6 +503,7 @@ struct r600_common_context { struct r600_streamout streamout; struct r600_scissors scissors; struct r600_viewports viewports; + struct r600_window_rectangles window_rectangles; bool scissor_enabled; bool clip_halfz; bool vs_writes_viewport_index; diff --git a/src/gallium/drivers/r600/r600_state.c b/src/gallium/drivers/r600/r600_state.c index 1d94da82da0..5a6f69e9828 100644 --- a/src/gallium/drivers/r600/r600_state.c +++ b/src/gallium/drivers/r600/r600_state.c @@ -3104,6 +3104,7 @@ void r600_init_state_functions(struct r600_context *rctx) r600_add_atom(rctx, &rctx->b.render_cond_atom, id++); r600_add_atom(rctx, &rctx->b.streamout.begin_atom, id++); r600_add_atom(rctx, &rctx->b.streamout.enable_atom, id++); + r600_add_atom(rctx, &rctx->b.window_rectangles.atom, id++); for (i = 0; i < R600_NUM_HW_STAGES; i++) r600_init_atom(rctx, &rctx->hw_shader_stages[i].atom, id++, r600_emit_shader, 0); r600_init_atom(rctx, &rctx->shader_stages.atom, id++, r600_emit_shader_stages, 0); diff --git a/src/gallium/drivers/r600/r600_viewport.c b/src/gallium/drivers/r600/r600_viewport.c index 0730a50f3e0..753a32668f6 100644 --- a/src/gallium/drivers/r600/r600_viewport.c +++ b/src/gallium/drivers/r600/r600_viewport.c @@ -6,6 +6,7 @@ #include "r600_cs.h" #include "util/u_viewport.h" #include "tgsi/tgsi_scan.h" +#include "r600d.h" #define R600_R_028C0C_PA_CL_GB_VERT_CLIP_ADJ 0x028C0C #define CM_R_028BE8_PA_CL_GB_VERT_CLIP_ADJ 0x28be8 @@ -425,14 +426,96 @@ void r600_update_vs_writes_viewport_index(struct r600_common_context *rctx, rctx->set_atom_dirty(rctx, &rctx->viewports.atom, true); } +static void r600_emit_window_rectangles(struct r600_common_context *rctx, + struct r600_atom *atom) +{ + /* There are four clipping rectangles. Their corner coordinates are inclusive. + * Every pixel is assigned a number from 0 and 15 by setting bits 0-3 depending + * on whether the pixel is inside cliprects 0-3, respectively. For example, + * if a pixel is inside cliprects 0 and 1, but outside 2 and 3, it is assigned + * the number 3 (binary 0011). + * + * If CLIPRECT_RULE & (1 << number), the pixel is rasterized. + */ + struct radeon_cmdbuf *cs = &rctx->gfx.cs; + static const unsigned outside[4] = { + /* outside rectangle 0 */ + V_02820C_OUT | + V_02820C_IN_1 | + V_02820C_IN_2 | + V_02820C_IN_21 | + V_02820C_IN_3 | + V_02820C_IN_31 | + V_02820C_IN_32 | + V_02820C_IN_321, + /* outside rectangles 0, 1 */ + V_02820C_OUT | + V_02820C_IN_2 | + V_02820C_IN_3 | + V_02820C_IN_32, + /* outside rectangles 0, 1, 2 */ + V_02820C_OUT | + V_02820C_IN_3, + /* outside rectangles 0, 1, 2, 3 */ + V_02820C_OUT, + }; + const unsigned disabled = 0xffff; /* all inside and outside cases */ + unsigned num_rectangles = rctx->window_rectangles.number; + struct pipe_scissor_state *rects = rctx->window_rectangles.states; + unsigned rule; + + assert(num_rectangles <= R600_MAX_WINDOW_RECTANGLES); + + if (num_rectangles == 0) + rule = disabled; + else if (rctx->window_rectangles.include) + rule = ~outside[num_rectangles - 1]; + else + rule = outside[num_rectangles - 1]; + + radeon_set_context_reg_seq(cs, R_02820C_PA_SC_CLIPRECT_RULE, 1); + radeon_emit(cs, rule); + + if (num_rectangles == 0) + return; + + radeon_set_context_reg_seq(cs, R_028210_PA_SC_CLIPRECT_0_TL, + num_rectangles * 2); + for (unsigned i = 0; i < num_rectangles; i++) { + radeon_emit(cs, S_028210_TL_X(rects[i].minx) | + S_028210_TL_Y(rects[i].miny)); + radeon_emit(cs, S_028214_BR_X(rects[i].maxx) | + S_028214_BR_Y(rects[i].maxy)); + } +} + +static void r600_set_window_rectangles(struct pipe_context *ctx, + bool include, + unsigned num_rectangles, + const struct pipe_scissor_state *rects) +{ + struct r600_common_context *rctx = (struct r600_common_context *)ctx; + + rctx->window_rectangles.number = num_rectangles; + rctx->window_rectangles.include = include; + + if (num_rectangles) + memcpy(rctx->window_rectangles.states, rects, + sizeof(*rects) * num_rectangles); + + rctx->set_atom_dirty(rctx, &rctx->window_rectangles.atom, true); +} + void r600_init_viewport_functions(struct r600_common_context *rctx) { rctx->scissors.atom.emit = r600_emit_scissors; rctx->viewports.atom.emit = r600_emit_viewport_states; + rctx->window_rectangles.atom.emit = r600_emit_window_rectangles; rctx->scissors.atom.num_dw = (2 + 16 * 2) + 6; rctx->viewports.atom.num_dw = 2 + 16 * 6; rctx->b.set_scissor_states = r600_set_scissor_states; rctx->b.set_viewport_states = r600_set_viewport_states; + rctx->b.set_window_rectangles = r600_set_window_rectangles; } diff --git a/src/gallium/drivers/r600/r600d.h b/src/gallium/drivers/r600/r600d.h index 1eb0a7422c5..0cb92cb2e26 100644 --- a/src/gallium/drivers/r600/r600d.h +++ b/src/gallium/drivers/r600/r600d.h @@ -2849,6 +2849,22 @@ #define S_02820C_CLIP_RULE(x) (((unsigned)(x) & 0xFFFF) << 0) #define G_02820C_CLIP_RULE(x) (((x) >> 0) & 0xFFFF) #define C_02820C_CLIP_RULE 0xFFFF0000 +#define V_02820C_OUT 0x0001 +#define V_02820C_IN_0 0x0002 +#define V_02820C_IN_1 0x0004 +#define V_02820C_IN_10 0x0008 +#define V_02820C_IN_2 0x0010 +#define V_02820C_IN_20 0x0020 +#define V_02820C_IN_21 0x0040 +#define V_02820C_IN_210 0x0080 +#define V_02820C_IN_3 0x0100 +#define V_02820C_IN_30 0x0200 +#define V_02820C_IN_31 0x0400 +#define V_02820C_IN_310 0x0800 +#define V_02820C_IN_32 0x1000 +#define V_02820C_IN_320 0x2000 +#define V_02820C_IN_321 0x4000 +#define V_02820C_IN_3210 0x8000 #define R_028210_PA_SC_CLIPRECT_0_TL 0x028210 #define S_028210_TL_X(x) (((unsigned)(x) & 0x3FFF) << 0) #define G_028210_TL_X(x) (((x) >> 0) & 0x3FFF)