etnaviv: SINGLE_BUFFER support on GC3000

This patch adds support for the SINGLE_BUFFER feature on GC3000
GPUs, which allows rendering to a single buffer using multiple pixel
pipes.

This feature is always used when it is available, which means that
multi-tiled formats are no longer being used in that case, and all
buffers will be normal (super)tiled. This mimics the behavior of the
blob on GC3000.

- Because the same format can be used to render to and texture from,
  this avoids an extra resolve pass when rendering to texture.

- i.MX6qp includes a PRE which can scan-out directly from tiled formats,
  avoiding untiling overhead.

Signed-off-by: Wladimir J. van der Laan <laanwj@gmail.com>
Reviewed-by: Christian Gmeiner <christian.gmeiner@gmail.com>
This commit is contained in:
Wladimir J. van der Laan 2017-04-14 09:44:27 +02:00 committed by Christian Gmeiner
parent 1dcb1d4925
commit 6a8d5ab932
8 changed files with 63 additions and 28 deletions

View File

@ -293,6 +293,9 @@ etna_cmd_stream_reset_notify(struct etna_cmd_stream *stream, void *priv)
etna_set_state(stream, VIVS_RA_EARLY_DEPTH, 0x00000031);
etna_set_state(stream, VIVS_PA_W_CLIP_LIMIT, 0x34000001);
/* Enable SINGLE_BUFFER for resolve, if supported */
etna_set_state(stream, VIVS_RS_SINGLE_BUFFER, COND(ctx->specs.single_buffer, VIVS_RS_SINGLE_BUFFER_ENABLE));
ctx->dirty = ~0L;
/* go through all the used resources and clear their status flag */

View File

@ -603,10 +603,12 @@ etna_emit_state(struct etna_context *ctx)
if (unlikely(dirty & (ETNA_DIRTY_STENCIL_REF))) {
/*014A0*/ EMIT_STATE(PE_STENCIL_CONFIG_EXT, ctx->stencil_ref.PE_STENCIL_CONFIG_EXT);
}
if (unlikely(dirty & (ETNA_DIRTY_BLEND | ETNA_DIRTY_FRAMEBUFFER))) {
struct etna_blend_state *blend = etna_blend_state(ctx->blend);
/*014A4*/ EMIT_STATE(PE_LOGIC_OP, blend->PE_LOGIC_OP | ctx->framebuffer.PE_LOGIC_OP);
}
if (unlikely(dirty & (ETNA_DIRTY_BLEND))) {
struct etna_blend_state *blend = etna_blend_state(ctx->blend);
/*014A4*/ EMIT_STATE(PE_LOGIC_OP, blend->PE_LOGIC_OP);
for (int x = 0; x < 2; ++x) {
/*014A8*/ EMIT_STATE(PE_DITHER(x), blend->PE_DITHER[x]);
}

View File

@ -72,6 +72,8 @@ struct etna_specs {
unsigned has_shader_range_registers : 1;
/* has the new sin/cos functions */
unsigned has_new_sin_cos : 1;
/* supports single-buffer rendering with multiple pixel pipes */
unsigned single_buffer : 1;
/* can use any kind of wrapping mode on npot textures */
unsigned npot_tex_any_wrap;
/* number of bits per TS tile */
@ -191,6 +193,7 @@ struct compiled_framebuffer_state {
uint32_t TS_COLOR_CLEAR_VALUE;
struct etna_reloc TS_COLOR_STATUS_BASE;
struct etna_reloc TS_COLOR_SURFACE_BASE;
uint32_t PE_LOGIC_OP;
bool msaa_mode; /* adds input (and possible temp) to PS */
};

View File

@ -249,9 +249,15 @@ etna_resource_create(struct pipe_screen *pscreen,
if (util_format_is_compressed(templat->format))
layout = ETNA_LAYOUT_LINEAR;
} else if (templat->target != PIPE_BUFFER) {
bool want_multitiled = screen->specs.pixel_pipes > 1;
bool want_multitiled = false;
bool want_supertiled = screen->specs.can_supertile && !DBG_ENABLED(ETNA_DBG_NO_SUPERTILE);
/* When this GPU supports single-buffer rendering, don't ever enable
* multi-tiling. This replicates the blob behavior on GC3000.
*/
if (!screen->specs.single_buffer)
want_multitiled = screen->specs.pixel_pipes > 1;
/* Keep single byte blocksized resources as tiled, since we
* are unable to use the RS blit to de-tile them. However,
* if they're used as a render target or depth/stencil, they

View File

@ -70,44 +70,45 @@ etna_compile_rs_state(struct etna_context *ctx, struct compiled_rs_state *cs,
COND(rs->source_tiling & 2, VIVS_RS_SOURCE_STRIDE_TILING) |
COND(source_multi, VIVS_RS_SOURCE_STRIDE_MULTI);
cs->source[0].bo = rs->source;
cs->source[0].offset = rs->source_offset;
cs->source[0].flags = ETNA_RELOC_READ;
/* Initially all pipes are set to the base address of the source and
* destination buffer respectively. This will be overridden below as
* necessary for the multi-pipe, multi-tiled case.
*/
for (unsigned pipe = 0; pipe < ctx->specs.pixel_pipes; ++pipe) {
cs->source[pipe].bo = rs->source;
cs->source[pipe].offset = rs->source_offset;
cs->source[pipe].flags = ETNA_RELOC_READ;
cs->dest[0].bo = rs->dest;
cs->dest[0].offset = rs->dest_offset;
cs->dest[0].flags = ETNA_RELOC_WRITE;
cs->dest[pipe].bo = rs->dest;
cs->dest[pipe].offset = rs->dest_offset;
cs->dest[pipe].flags = ETNA_RELOC_WRITE;
cs->RS_PIPE_OFFSET[pipe] = VIVS_RS_PIPE_OFFSET_X(0) | VIVS_RS_PIPE_OFFSET_Y(0);
}
cs->RS_DEST_STRIDE = (rs->dest_stride << dest_stride_shift) |
COND(rs->dest_tiling & 2, VIVS_RS_DEST_STRIDE_TILING) |
COND(dest_multi, VIVS_RS_DEST_STRIDE_MULTI);
if (ctx->specs.pixel_pipes == 1) {
if (ctx->specs.pixel_pipes == 1 || ctx->specs.single_buffer) {
cs->RS_WINDOW_SIZE = VIVS_RS_WINDOW_SIZE_WIDTH(rs->width) |
VIVS_RS_WINDOW_SIZE_HEIGHT(rs->height);
} else if (ctx->specs.pixel_pipes == 2) {
assert((rs->height & 7) == 0); /* GPU hangs happen if height not 8-aligned */
if (source_multi) {
cs->source[1].bo = rs->source;
if (source_multi)
cs->source[1].offset = rs->source_offset + rs->source_stride * rs->source_padded_height / 2;
cs->source[1].flags = ETNA_RELOC_READ;
}
if (dest_multi) {
cs->dest[1].bo = rs->dest;
if (dest_multi)
cs->dest[1].offset = rs->dest_offset + rs->dest_stride * rs->dest_padded_height / 2;
cs->dest[1].flags = ETNA_RELOC_WRITE;
}
cs->RS_WINDOW_SIZE = VIVS_RS_WINDOW_SIZE_WIDTH(rs->width) |
VIVS_RS_WINDOW_SIZE_HEIGHT(rs->height / 2);
cs->RS_PIPE_OFFSET[1] = VIVS_RS_PIPE_OFFSET_X(0) | VIVS_RS_PIPE_OFFSET_Y(rs->height / 2);
} else {
abort();
}
cs->RS_PIPE_OFFSET[0] = VIVS_RS_PIPE_OFFSET_X(0) | VIVS_RS_PIPE_OFFSET_Y(0);
cs->RS_PIPE_OFFSET[1] = VIVS_RS_PIPE_OFFSET_X(0) | VIVS_RS_PIPE_OFFSET_Y(rs->height / 2);
cs->RS_DITHER[0] = rs->dither[0];
cs->RS_DITHER[1] = rs->dither[1];
cs->RS_CLEAR_CONTROL = VIVS_RS_CLEAR_CONTROL_BITS(rs->clear_bits) | rs->clear_mode;
@ -117,6 +118,10 @@ etna_compile_rs_state(struct etna_context *ctx, struct compiled_rs_state *cs,
cs->RS_FILL_VALUE[3] = rs->clear_value[3];
cs->RS_EXTRA_CONFIG = VIVS_RS_EXTRA_CONFIG_AA(rs->aa) |
VIVS_RS_EXTRA_CONFIG_ENDIAN(rs->endian_mode);
/* TODO: cs->RS_UNK016B0 = s->size / 64 ?
* The blob does this consistently but there seems to be no currently supported
* model that needs it.
*/
}
void

View File

@ -675,6 +675,10 @@ etna_get_specs(struct etna_screen *screen)
screen->specs.max_rendertarget_size =
VIV_FEATURE(screen, chipMinorFeatures0, RENDERTARGET_8K) ? 8192 : 2048;
screen->specs.single_buffer = VIV_FEATURE(screen, chipMinorFeatures4, SINGLE_BUFFER);
if (screen->specs.single_buffer)
DBG("etnaviv: Single buffer mode enabled with %d pixel pipes\n", screen->specs.pixel_pipes);
return true;
fail:

View File

@ -168,8 +168,8 @@ etna_set_framebuffer_state(struct pipe_context *pctx,
cs->PE_COLOR_ADDR = cbuf->reloc[0];
cs->PE_COLOR_ADDR.flags = ETNA_RELOC_READ | ETNA_RELOC_WRITE;
} else {
/* Rendered textures must always be multi-tiled */
assert(res->layout & ETNA_LAYOUT_BIT_MULTI);
/* Rendered textures must always be multi-tiled, or single-buffer mode must be supported */
assert((res->layout & ETNA_LAYOUT_BIT_MULTI) || ctx->specs.single_buffer);
for (int i = 0; i < ctx->specs.pixel_pipes; i++) {
cs->PE_PIPE_COLOR_ADDR[i] = cbuf->reloc[i];
cs->PE_PIPE_COLOR_ADDR[i].flags = ETNA_RELOC_READ | ETNA_RELOC_WRITE;
@ -331,6 +331,12 @@ etna_set_framebuffer_state(struct pipe_context *pctx,
cs->TS_MEM_CONFIG = ts_mem_config;
/* Single buffer setup. There is only one switch for this, not a separate
* one per color buffer / depth buffer. To keep the logic simple always use
* single buffer when this feature is available.
*/
cs->PE_LOGIC_OP = VIVS_PE_LOGIC_OP_SINGLE_BUFFER(ctx->specs.single_buffer ? 2 : 0);
ctx->framebuffer_s = *sv; /* keep copy of original structure */
ctx->dirty |= ETNA_DIRTY_FRAMEBUFFER;
}

View File

@ -91,12 +91,18 @@ etna_create_surface(struct pipe_context *pctx, struct pipe_resource *prsc,
struct etna_resource_level *lev = &rsc->levels[level];
/* Setup template relocations for this surface */
surf->reloc[0].bo = rsc->bo;
surf->reloc[0].offset = surf->surf.offset;
surf->reloc[0].flags = 0;
surf->reloc[1].bo = rsc->bo;
surf->reloc[1].offset = surf->surf.offset + lev->stride * lev->padded_height / 2;
surf->reloc[1].flags = 0;
for (unsigned pipe = 0; pipe < ctx->specs.pixel_pipes; ++pipe) {
surf->reloc[pipe].bo = rsc->bo;
surf->reloc[pipe].offset = surf->surf.offset;
surf->reloc[pipe].flags = 0;
}
/* In single buffer mode, both pixel pipes must point to the same address,
* for multi-tiled surfaces on the other hand the second pipe is expected to
* point halfway the image vertically.
*/
if (rsc->layout & ETNA_LAYOUT_BIT_MULTI)
surf->reloc[1].offset = surf->surf.offset + lev->stride * lev->padded_height / 2;
if (surf->surf.ts_size) {
unsigned int layer_offset = layer * surf->surf.ts_layer_stride;