diff options
Diffstat (limited to 'src/gallium/drivers/radeon')
-rw-r--r-- | src/gallium/drivers/radeon/Makefile.sources | 2 | ||||
-rw-r--r-- | src/gallium/drivers/radeon/r600_cs.h | 97 | ||||
-rw-r--r-- | src/gallium/drivers/radeon/r600_pipe_common.c | 85 | ||||
-rw-r--r-- | src/gallium/drivers/radeon/r600_pipe_common.h | 179 | ||||
-rw-r--r-- | src/gallium/drivers/radeon/r600_streamout.c | 338 | ||||
-rw-r--r-- | src/gallium/drivers/radeon/r600d_common.h | 143 |
6 files changed, 844 insertions, 0 deletions
diff --git a/src/gallium/drivers/radeon/Makefile.sources b/src/gallium/drivers/radeon/Makefile.sources index d33c81b0fc0..740dbc79011 100644 --- a/src/gallium/drivers/radeon/Makefile.sources +++ b/src/gallium/drivers/radeon/Makefile.sources @@ -1,4 +1,6 @@ C_SOURCES := \ + r600_pipe_common.c \ + r600_streamout.c \ radeon_uvd.c LLVM_C_FILES := \ diff --git a/src/gallium/drivers/radeon/r600_cs.h b/src/gallium/drivers/radeon/r600_cs.h new file mode 100644 index 00000000000..c8bb2976f84 --- /dev/null +++ b/src/gallium/drivers/radeon/r600_cs.h @@ -0,0 +1,97 @@ +/* + * Copyright 2013 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Marek Olšák <[email protected]> + */ + +/** + * This file contains helpers for writing commands to commands streams. + */ + +#ifndef R600_CS_H +#define R600_CS_H + +#include "../../winsys/radeon/drm/radeon_winsys.h" +#include "r600d_common.h" + +static INLINE uint64_t r600_resource_va(struct pipe_screen *screen, + struct pipe_resource *resource) +{ + struct r600_common_screen *rscreen = (struct r600_common_screen*)screen; + struct r600_resource *rresource = (struct r600_resource*)resource; + + return rscreen->ws->buffer_get_virtual_address(rresource->cs_buf); +} + +static INLINE unsigned r600_context_bo_reloc(struct r600_common_context *rctx, + struct r600_ring *ring, + struct r600_resource *rbo, + enum radeon_bo_usage usage) +{ + assert(usage); + + /* Make sure that all previous rings are flushed so that everything + * looks serialized from the driver point of view. + */ + if (!ring->flushing) { + if (ring == &rctx->rings.gfx) { + if (rctx->rings.dma.cs) { + /* flush dma ring */ + rctx->rings.dma.flush(rctx, RADEON_FLUSH_ASYNC); + } + } else { + /* flush gfx ring */ + rctx->rings.gfx.flush(rctx, RADEON_FLUSH_ASYNC); + } + } + return rctx->ws->cs_add_reloc(ring->cs, rbo->cs_buf, usage, rbo->domains) * 4; +} + +static INLINE void r600_write_config_reg_seq(struct radeon_winsys_cs *cs, unsigned reg, unsigned num) +{ + assert(reg < R600_CONTEXT_REG_OFFSET); + assert(cs->cdw+2+num <= RADEON_MAX_CMDBUF_DWORDS); + radeon_emit(cs, PKT3(PKT3_SET_CONFIG_REG, num, 0)); + radeon_emit(cs, (reg - R600_CONFIG_REG_OFFSET) >> 2); +} + +static INLINE void r600_write_config_reg(struct radeon_winsys_cs *cs, unsigned reg, unsigned value) +{ + r600_write_config_reg_seq(cs, reg, 1); + radeon_emit(cs, value); +} + +static INLINE void r600_write_context_reg_seq(struct radeon_winsys_cs *cs, unsigned reg, unsigned num) +{ + assert(reg >= R600_CONTEXT_REG_OFFSET); + assert(cs->cdw+2+num <= RADEON_MAX_CMDBUF_DWORDS); + radeon_emit(cs, PKT3(PKT3_SET_CONTEXT_REG, num, 0)); + radeon_emit(cs, (reg - R600_CONTEXT_REG_OFFSET) >> 2); +} + +static INLINE void r600_write_context_reg(struct radeon_winsys_cs *cs, unsigned reg, unsigned value) +{ + r600_write_context_reg_seq(cs, reg, 1); + radeon_emit(cs, value); +} + +#endif diff --git a/src/gallium/drivers/radeon/r600_pipe_common.c b/src/gallium/drivers/radeon/r600_pipe_common.c new file mode 100644 index 00000000000..cdfdc19bd0e --- /dev/null +++ b/src/gallium/drivers/radeon/r600_pipe_common.c @@ -0,0 +1,85 @@ +/* + * Copyright 2013 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Authors: Marek Olšák <[email protected]> + * + */ + +#include "r600_pipe_common.h" + +void r600_common_screen_init(struct r600_common_screen *rscreen, + struct radeon_winsys *ws) +{ + ws->query_info(ws, &rscreen->info); + + rscreen->ws = ws; + rscreen->family = rscreen->info.family; + rscreen->chip_class = rscreen->info.chip_class; +} + +bool r600_common_context_init(struct r600_common_context *rctx, + struct r600_common_screen *rscreen) +{ + rctx->ws = rscreen->ws; + rctx->family = rscreen->family; + rctx->chip_class = rscreen->chip_class; + + r600_streamout_init(rctx); + + rctx->allocator_so_filled_size = u_suballocator_create(&rctx->b, 4096, 4, + 0, PIPE_USAGE_STATIC, TRUE); + if (!rctx->allocator_so_filled_size) + return false; + + return true; +} + +void r600_common_context_cleanup(struct r600_common_context *rctx) +{ + if (rctx->allocator_so_filled_size) { + u_suballocator_destroy(rctx->allocator_so_filled_size); + } +} + +void r600_context_add_resource_size(struct pipe_context *ctx, struct pipe_resource *r) +{ + struct r600_common_context *rctx = (struct r600_common_context *)ctx; + struct r600_resource *rr = (struct r600_resource *)r; + + if (r == NULL) { + return; + } + + /* + * The idea is to compute a gross estimate of memory requirement of + * each draw call. After each draw call, memory will be precisely + * accounted. So the uncertainty is only on the current draw call. + * In practice this gave very good estimate (+/- 10% of the target + * memory limit). + */ + if (rr->domains & RADEON_DOMAIN_GTT) { + rctx->gtt += rr->buf->size; + } + if (rr->domains & RADEON_DOMAIN_VRAM) { + rctx->vram += rr->buf->size; + } +} diff --git a/src/gallium/drivers/radeon/r600_pipe_common.h b/src/gallium/drivers/radeon/r600_pipe_common.h new file mode 100644 index 00000000000..0bfdb47b62b --- /dev/null +++ b/src/gallium/drivers/radeon/r600_pipe_common.h @@ -0,0 +1,179 @@ +/* + * Copyright 2013 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Authors: Marek Olšák <[email protected]> + * + */ + +/** + * This file contains common screen and context structures and functions + * for r600g and radeonsi. + */ + +#ifndef R600_PIPE_COMMON_H +#define R600_PIPE_COMMON_H + +#include "../../winsys/radeon/drm/radeon_winsys.h" + +#include "util/u_range.h" +#include "util/u_suballoc.h" +#include "util/u_transfer.h" + +/* read caches */ +#define R600_CONTEXT_INV_VERTEX_CACHE (1 << 0) +#define R600_CONTEXT_INV_TEX_CACHE (1 << 1) +#define R600_CONTEXT_INV_CONST_CACHE (1 << 2) +/* read-write caches */ +#define R600_CONTEXT_STREAMOUT_FLUSH (1 << 8) +#define R600_CONTEXT_FLUSH_AND_INV (1 << 9) +#define R600_CONTEXT_FLUSH_AND_INV_CB_META (1 << 10) +#define R600_CONTEXT_FLUSH_AND_INV_DB_META (1 << 11) +#define R600_CONTEXT_FLUSH_AND_INV_DB (1 << 12) +#define R600_CONTEXT_FLUSH_AND_INV_CB (1 << 13) +/* engine synchronization */ +#define R600_CONTEXT_PS_PARTIAL_FLUSH (1 << 16) +#define R600_CONTEXT_WAIT_3D_IDLE (1 << 17) +#define R600_CONTEXT_WAIT_CP_DMA_IDLE (1 << 18) + +struct r600_common_context; + +struct r600_resource { + struct u_resource b; + + /* Winsys objects. */ + struct pb_buffer *buf; + struct radeon_winsys_cs_handle *cs_buf; + + /* Resource state. */ + enum radeon_bo_domain domains; + + /* The buffer range which is initialized (with a write transfer, + * streamout, DMA, or as a random access target). The rest of + * the buffer is considered invalid and can be mapped unsynchronized. + * + * This allows unsychronized mapping of a buffer range which hasn't + * been used yet. It's for applications which forget to use + * the unsynchronized map flag and expect the driver to figure it out. + */ + struct util_range valid_buffer_range; +}; + +struct r600_common_screen { + struct pipe_screen b; + struct radeon_winsys *ws; + enum radeon_family family; + enum chip_class chip_class; + struct radeon_info info; +}; + +/* This encapsulates a state or an operation which can emitted into the GPU + * command stream. */ +struct r600_atom { + void (*emit)(struct r600_common_context *ctx, struct r600_atom *state); + unsigned num_dw; + bool dirty; +}; + +struct r600_so_target { + struct pipe_stream_output_target b; + + /* The buffer where BUFFER_FILLED_SIZE is stored. */ + struct r600_resource *buf_filled_size; + unsigned buf_filled_size_offset; + + unsigned stride_in_dw; +}; + +struct r600_streamout { + struct r600_atom begin_atom; + bool begin_emitted; + unsigned num_dw_for_end; + + unsigned enabled_mask; + unsigned num_targets; + struct r600_so_target *targets[PIPE_MAX_SO_BUFFERS]; + + unsigned append_bitmask; + bool suspended; + + /* External state which comes from the vertex shader, + * it must be set explicitly when binding a shader. */ + unsigned *stride_in_dw; +}; + +struct r600_ring { + struct radeon_winsys_cs *cs; + bool flushing; + void (*flush)(void *ctx, unsigned flags); +}; + +struct r600_rings { + struct r600_ring gfx; + struct r600_ring dma; +}; + +struct r600_common_context { + struct pipe_context b; /* base class */ + + struct radeon_winsys *ws; + enum radeon_family family; + enum chip_class chip_class; + struct r600_rings rings; + + struct u_suballocator *allocator_so_filled_size; + + /* Current unaccounted memory usage. */ + uint64_t vram; + uint64_t gtt; + + /* States. */ + struct r600_streamout streamout; + + /* Additional context states. */ + unsigned flags; /* flush flags */ +}; + +/* r600_common_pipe.c */ +void r600_common_screen_init(struct r600_common_screen *rscreen, + struct radeon_winsys *ws); +bool r600_common_context_init(struct r600_common_context *rctx, + struct r600_common_screen *rscreen); +void r600_common_context_cleanup(struct r600_common_context *rctx); +void r600_context_add_resource_size(struct pipe_context *ctx, struct pipe_resource *r); + +/* r600_streamout.c */ +void r600_streamout_buffers_dirty(struct r600_common_context *rctx); +void r600_set_streamout_targets(struct pipe_context *ctx, + unsigned num_targets, + struct pipe_stream_output_target **targets, + unsigned append_bitmask); +void r600_emit_streamout_end(struct r600_common_context *rctx); +void r600_streamout_init(struct r600_common_context *rctx); + +/* Inline helpers. */ + +static INLINE struct r600_resource *r600_resource(struct pipe_resource *r) +{ + return (struct r600_resource*)r; +} + +#endif diff --git a/src/gallium/drivers/radeon/r600_streamout.c b/src/gallium/drivers/radeon/r600_streamout.c new file mode 100644 index 00000000000..ab40630920b --- /dev/null +++ b/src/gallium/drivers/radeon/r600_streamout.c @@ -0,0 +1,338 @@ +/* + * Copyright 2013 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Authors: Marek Olšák <[email protected]> + * + */ + +#include "r600_pipe_common.h" +#include "r600_cs.h" + +#include "util/u_memory.h" + +static struct pipe_stream_output_target * +r600_create_so_target(struct pipe_context *ctx, + struct pipe_resource *buffer, + unsigned buffer_offset, + unsigned buffer_size) +{ + struct r600_common_context *rctx = (struct r600_common_context *)ctx; + struct r600_so_target *t; + struct r600_resource *rbuffer = (struct r600_resource*)buffer; + + t = CALLOC_STRUCT(r600_so_target); + if (!t) { + return NULL; + } + + u_suballocator_alloc(rctx->allocator_so_filled_size, 4, + &t->buf_filled_size_offset, + (struct pipe_resource**)&t->buf_filled_size); + if (!t->buf_filled_size) { + FREE(t); + return NULL; + } + + t->b.reference.count = 1; + t->b.context = ctx; + pipe_resource_reference(&t->b.buffer, buffer); + t->b.buffer_offset = buffer_offset; + t->b.buffer_size = buffer_size; + + util_range_add(&rbuffer->valid_buffer_range, buffer_offset, + buffer_offset + buffer_size); + return &t->b; +} + +static void r600_so_target_destroy(struct pipe_context *ctx, + struct pipe_stream_output_target *target) +{ + struct r600_so_target *t = (struct r600_so_target*)target; + pipe_resource_reference(&t->b.buffer, NULL); + pipe_resource_reference((struct pipe_resource**)&t->buf_filled_size, NULL); + FREE(t); +} + +void r600_streamout_buffers_dirty(struct r600_common_context *rctx) +{ + rctx->streamout.num_dw_for_end = + 12 + /* flush_vgt_streamout */ + util_bitcount(rctx->streamout.enabled_mask) * 8 + /* STRMOUT_BUFFER_UPDATE */ + 3 /* set_streamout_enable(0) */; + + rctx->streamout.begin_atom.num_dw = + 12 + /* flush_vgt_streamout */ + 6 + /* set_streamout_enable */ + util_bitcount(rctx->streamout.enabled_mask) * 7 + /* SET_CONTEXT_REG */ + (rctx->family >= CHIP_RS780 && + rctx->family <= CHIP_RV740 ? util_bitcount(rctx->streamout.enabled_mask) * 5 : 0) + /* STRMOUT_BASE_UPDATE */ + util_bitcount(rctx->streamout.enabled_mask & rctx->streamout.append_bitmask) * 8 + /* STRMOUT_BUFFER_UPDATE */ + util_bitcount(rctx->streamout.enabled_mask & ~rctx->streamout.append_bitmask) * 6 + /* STRMOUT_BUFFER_UPDATE */ + (rctx->family > CHIP_R600 && rctx->family < CHIP_RS780 ? 2 : 0) + /* SURFACE_BASE_UPDATE */ + rctx->streamout.num_dw_for_end; + + rctx->streamout.begin_atom.dirty = true; +} + +void r600_set_streamout_targets(struct pipe_context *ctx, + unsigned num_targets, + struct pipe_stream_output_target **targets, + unsigned append_bitmask) +{ + struct r600_common_context *rctx = (struct r600_common_context *)ctx; + unsigned i; + + /* Stop streamout. */ + if (rctx->streamout.num_targets && rctx->streamout.begin_emitted) { + r600_emit_streamout_end(rctx); + } + + /* Set the new targets. */ + for (i = 0; i < num_targets; i++) { + pipe_so_target_reference((struct pipe_stream_output_target**)&rctx->streamout.targets[i], targets[i]); + r600_context_add_resource_size(ctx, targets[i]->buffer); + } + for (; i < rctx->streamout.num_targets; i++) { + pipe_so_target_reference((struct pipe_stream_output_target**)&rctx->streamout.targets[i], NULL); + } + + rctx->streamout.enabled_mask = (num_targets >= 1 && targets[0] ? 1 : 0) | + (num_targets >= 2 && targets[1] ? 2 : 0) | + (num_targets >= 3 && targets[2] ? 4 : 0) | + (num_targets >= 4 && targets[3] ? 8 : 0); + + rctx->streamout.num_targets = num_targets; + rctx->streamout.append_bitmask = append_bitmask; + + if (num_targets) { + r600_streamout_buffers_dirty(rctx); + } +} + +static void r600_flush_vgt_streamout(struct r600_common_context *rctx) +{ + struct radeon_winsys_cs *cs = rctx->rings.gfx.cs; + + r600_write_config_reg(cs, R_008490_CP_STRMOUT_CNTL, 0); + + radeon_emit(cs, PKT3(PKT3_EVENT_WRITE, 0, 0)); + radeon_emit(cs, EVENT_TYPE(EVENT_TYPE_SO_VGTSTREAMOUT_FLUSH) | EVENT_INDEX(0)); + + radeon_emit(cs, PKT3(PKT3_WAIT_REG_MEM, 5, 0)); + radeon_emit(cs, WAIT_REG_MEM_EQUAL); /* wait until the register is equal to the reference value */ + radeon_emit(cs, R_008490_CP_STRMOUT_CNTL >> 2); /* register */ + radeon_emit(cs, 0); + radeon_emit(cs, S_008490_OFFSET_UPDATE_DONE(1)); /* reference value */ + radeon_emit(cs, S_008490_OFFSET_UPDATE_DONE(1)); /* mask */ + radeon_emit(cs, 4); /* poll interval */ +} + +static void evergreen_flush_vgt_streamout(struct r600_common_context *rctx) +{ + struct radeon_winsys_cs *cs = rctx->rings.gfx.cs; + + r600_write_config_reg(cs, R_0084FC_CP_STRMOUT_CNTL, 0); + + radeon_emit(cs, PKT3(PKT3_EVENT_WRITE, 0, 0)); + radeon_emit(cs, EVENT_TYPE(EVENT_TYPE_SO_VGTSTREAMOUT_FLUSH) | EVENT_INDEX(0)); + + radeon_emit(cs, PKT3(PKT3_WAIT_REG_MEM, 5, 0)); + radeon_emit(cs, WAIT_REG_MEM_EQUAL); /* wait until the register is equal to the reference value */ + radeon_emit(cs, R_0084FC_CP_STRMOUT_CNTL >> 2); /* register */ + radeon_emit(cs, 0); + radeon_emit(cs, S_0084FC_OFFSET_UPDATE_DONE(1)); /* reference value */ + radeon_emit(cs, S_0084FC_OFFSET_UPDATE_DONE(1)); /* mask */ + radeon_emit(cs, 4); /* poll interval */ +} + +static void r600_set_streamout_enable(struct r600_common_context *rctx, unsigned buffer_enable_bit) +{ + struct radeon_winsys_cs *cs = rctx->rings.gfx.cs; + + if (buffer_enable_bit) { + r600_write_context_reg(cs, R_028AB0_VGT_STRMOUT_EN, S_028AB0_STREAMOUT(1)); + r600_write_context_reg(cs, R_028B20_VGT_STRMOUT_BUFFER_EN, buffer_enable_bit); + } else { + r600_write_context_reg(cs, R_028AB0_VGT_STRMOUT_EN, S_028AB0_STREAMOUT(0)); + } +} + +static void evergreen_set_streamout_enable(struct r600_common_context *rctx, unsigned buffer_enable_bit) +{ + struct radeon_winsys_cs *cs = rctx->rings.gfx.cs; + + if (buffer_enable_bit) { + r600_write_context_reg_seq(cs, R_028B94_VGT_STRMOUT_CONFIG, 2); + radeon_emit(cs, S_028B94_STREAMOUT_0_EN(1)); /* R_028B94_VGT_STRMOUT_CONFIG */ + radeon_emit(cs, S_028B98_STREAM_0_BUFFER_EN(buffer_enable_bit)); /* R_028B98_VGT_STRMOUT_BUFFER_CONFIG */ + } else { + r600_write_context_reg(cs, R_028B94_VGT_STRMOUT_CONFIG, S_028B94_STREAMOUT_0_EN(0)); + } +} + +static void r600_emit_reloc(struct r600_common_context *rctx, + struct r600_ring *ring, struct r600_resource *rbo, + enum radeon_bo_usage usage) +{ + struct radeon_winsys_cs *cs = ring->cs; + bool has_vm = ((struct r600_common_screen*)rctx->b.screen)->info.r600_virtual_address; + unsigned reloc = r600_context_bo_reloc(rctx, ring, rbo, usage); + + if (!has_vm) { + radeon_emit(cs, PKT3(PKT3_NOP, 0, 0)); + radeon_emit(cs, reloc); + } +} + +static void r600_emit_streamout_begin(struct r600_common_context *rctx, struct r600_atom *atom) +{ + struct radeon_winsys_cs *cs = rctx->rings.gfx.cs; + struct r600_so_target **t = rctx->streamout.targets; + unsigned *stride_in_dw = rctx->streamout.stride_in_dw; + unsigned i, update_flags = 0; + uint64_t va; + + if (rctx->chip_class >= EVERGREEN) { + evergreen_flush_vgt_streamout(rctx); + evergreen_set_streamout_enable(rctx, rctx->streamout.enabled_mask); + } else { + r600_flush_vgt_streamout(rctx); + r600_set_streamout_enable(rctx, rctx->streamout.enabled_mask); + } + + for (i = 0; i < rctx->streamout.num_targets; i++) { + if (!t[i]) + continue; + + t[i]->stride_in_dw = stride_in_dw[i]; + + va = r600_resource_va(rctx->b.screen, + (void*)t[i]->b.buffer); + + update_flags |= SURFACE_BASE_UPDATE_STRMOUT(i); + + r600_write_context_reg_seq(cs, R_028AD0_VGT_STRMOUT_BUFFER_SIZE_0 + 16*i, 3); + radeon_emit(cs, (t[i]->b.buffer_offset + + t[i]->b.buffer_size) >> 2); /* BUFFER_SIZE (in DW) */ + radeon_emit(cs, stride_in_dw[i]); /* VTX_STRIDE (in DW) */ + radeon_emit(cs, va >> 8); /* BUFFER_BASE */ + + r600_emit_reloc(rctx, &rctx->rings.gfx, r600_resource(t[i]->b.buffer), + RADEON_USAGE_WRITE); + + /* R7xx requires this packet after updating BUFFER_BASE. + * Without this, R7xx locks up. */ + if (rctx->family >= CHIP_RS780 && rctx->family <= CHIP_RV740) { + radeon_emit(cs, PKT3(PKT3_STRMOUT_BASE_UPDATE, 1, 0)); + radeon_emit(cs, i); + radeon_emit(cs, va >> 8); + + r600_emit_reloc(rctx, &rctx->rings.gfx, r600_resource(t[i]->b.buffer), + RADEON_USAGE_WRITE); + } + + if (rctx->streamout.append_bitmask & (1 << i)) { + va = r600_resource_va(rctx->b.screen, + (void*)t[i]->buf_filled_size) + t[i]->buf_filled_size_offset; + /* Append. */ + radeon_emit(cs, PKT3(PKT3_STRMOUT_BUFFER_UPDATE, 4, 0)); + radeon_emit(cs, STRMOUT_SELECT_BUFFER(i) | + STRMOUT_OFFSET_SOURCE(STRMOUT_OFFSET_FROM_MEM)); /* control */ + radeon_emit(cs, 0); /* unused */ + radeon_emit(cs, 0); /* unused */ + radeon_emit(cs, va); /* src address lo */ + radeon_emit(cs, va >> 32); /* src address hi */ + + r600_emit_reloc(rctx, &rctx->rings.gfx, t[i]->buf_filled_size, + RADEON_USAGE_READ); + } else { + /* Start from the beginning. */ + radeon_emit(cs, PKT3(PKT3_STRMOUT_BUFFER_UPDATE, 4, 0)); + radeon_emit(cs, STRMOUT_SELECT_BUFFER(i) | + STRMOUT_OFFSET_SOURCE(STRMOUT_OFFSET_FROM_PACKET)); /* control */ + radeon_emit(cs, 0); /* unused */ + radeon_emit(cs, 0); /* unused */ + radeon_emit(cs, t[i]->b.buffer_offset >> 2); /* buffer offset in DW */ + radeon_emit(cs, 0); /* unused */ + } + } + + if (rctx->family > CHIP_R600 && rctx->family < CHIP_RV770) { + radeon_emit(cs, PKT3(PKT3_SURFACE_BASE_UPDATE, 0, 0)); + radeon_emit(cs, update_flags); + } + rctx->streamout.begin_emitted = true; +} + +void r600_emit_streamout_end(struct r600_common_context *rctx) +{ + struct radeon_winsys_cs *cs = rctx->rings.gfx.cs; + struct r600_so_target **t = rctx->streamout.targets; + unsigned i; + uint64_t va; + + if (rctx->chip_class >= EVERGREEN) { + evergreen_flush_vgt_streamout(rctx); + } else { + r600_flush_vgt_streamout(rctx); + } + + for (i = 0; i < rctx->streamout.num_targets; i++) { + if (!t[i]) + continue; + + va = r600_resource_va(rctx->b.screen, + (void*)t[i]->buf_filled_size) + t[i]->buf_filled_size_offset; + radeon_emit(cs, PKT3(PKT3_STRMOUT_BUFFER_UPDATE, 4, 0)); + radeon_emit(cs, STRMOUT_SELECT_BUFFER(i) | + STRMOUT_OFFSET_SOURCE(STRMOUT_OFFSET_NONE) | + STRMOUT_STORE_BUFFER_FILLED_SIZE); /* control */ + radeon_emit(cs, va); /* dst address lo */ + radeon_emit(cs, va >> 32); /* dst address hi */ + radeon_emit(cs, 0); /* unused */ + radeon_emit(cs, 0); /* unused */ + + r600_emit_reloc(rctx, &rctx->rings.gfx, t[i]->buf_filled_size, + RADEON_USAGE_WRITE); + } + + if (rctx->chip_class >= EVERGREEN) { + evergreen_set_streamout_enable(rctx, 0); + } else { + r600_set_streamout_enable(rctx, 0); + } + + rctx->streamout.begin_emitted = false; + + if (rctx->chip_class >= R700) { + rctx->flags |= R600_CONTEXT_STREAMOUT_FLUSH; + } else { + rctx->flags |= R600_CONTEXT_FLUSH_AND_INV; + } +} + +void r600_streamout_init(struct r600_common_context *rctx) +{ + rctx->b.create_stream_output_target = r600_create_so_target; + rctx->b.stream_output_target_destroy = r600_so_target_destroy; + rctx->streamout.begin_atom.emit = r600_emit_streamout_begin; +} diff --git a/src/gallium/drivers/radeon/r600d_common.h b/src/gallium/drivers/radeon/r600d_common.h new file mode 100644 index 00000000000..b179757b424 --- /dev/null +++ b/src/gallium/drivers/radeon/r600d_common.h @@ -0,0 +1,143 @@ +/* + * Copyright 2013 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Marek Olšák <[email protected]> + */ + +#ifndef R600D_COMMON_H +#define R600D_COMMON_H + +#define R600_CONFIG_REG_OFFSET 0x08000 +#define R600_CONTEXT_REG_OFFSET 0x28000 + +#define PKT_TYPE_S(x) (((x) & 0x3) << 30) +#define PKT_COUNT_S(x) (((x) & 0x3FFF) << 16) +#define PKT3_IT_OPCODE_S(x) (((x) & 0xFF) << 8) +#define PKT3_PREDICATE(x) (((x) >> 0) & 0x1) +#define PKT3(op, count, predicate) (PKT_TYPE_S(3) | PKT_COUNT_S(count) | PKT3_IT_OPCODE_S(op) | PKT3_PREDICATE(predicate)) + +#define RADEON_CP_PACKET3_COMPUTE_MODE 0x00000002 + +#define PKT3_NOP 0x10 +#define PKT3_STRMOUT_BUFFER_UPDATE 0x34 +#define STRMOUT_STORE_BUFFER_FILLED_SIZE 1 +#define STRMOUT_OFFSET_SOURCE(x) (((x) & 0x3) << 1) +#define STRMOUT_OFFSET_FROM_PACKET 0 +#define STRMOUT_OFFSET_FROM_VGT_FILLED_SIZE 1 +#define STRMOUT_OFFSET_FROM_MEM 2 +#define STRMOUT_OFFSET_NONE 3 +#define STRMOUT_SELECT_BUFFER(x) (((x) & 0x3) << 8) +#define PKT3_WAIT_REG_MEM 0x3C +#define WAIT_REG_MEM_EQUAL 3 +#define PKT3_EVENT_WRITE 0x46 +#define PKT3_SET_CONFIG_REG 0x68 +#define PKT3_SET_CONTEXT_REG 0x69 +#define PKT3_STRMOUT_BASE_UPDATE 0x72 /* r700 only */ +#define PKT3_SURFACE_BASE_UPDATE 0x73 /* r600 only */ +#define SURFACE_BASE_UPDATE_DEPTH (1 << 0) +#define SURFACE_BASE_UPDATE_COLOR(x) (2 << (x)) +#define SURFACE_BASE_UPDATE_COLOR_NUM(x) (((1 << x) - 1) << 1) +#define SURFACE_BASE_UPDATE_STRMOUT(x) (0x200 << (x)) + +#define EVENT_TYPE_PS_PARTIAL_FLUSH 0x10 +#define EVENT_TYPE_CACHE_FLUSH_AND_INV_TS_EVENT 0x14 +#define EVENT_TYPE_ZPASS_DONE 0x15 +#define EVENT_TYPE_CACHE_FLUSH_AND_INV_EVENT 0x16 +#define EVENT_TYPE_PIPELINESTAT_START 25 +#define EVENT_TYPE_PIPELINESTAT_STOP 26 +#define EVENT_TYPE_SAMPLE_PIPELINESTAT 30 +#define EVENT_TYPE_SO_VGTSTREAMOUT_FLUSH 0x1f +#define EVENT_TYPE_SAMPLE_STREAMOUTSTATS 0x20 +#define EVENT_TYPE_FLUSH_AND_INV_DB_META 0x2c /* supported on r700+ */ +#define EVENT_TYPE_FLUSH_AND_INV_CB_META 46 /* supported on r700+ */ +#define EVENT_TYPE(x) ((x) << 0) +#define EVENT_INDEX(x) ((x) << 8) + /* 0 - any non-TS event + * 1 - ZPASS_DONE + * 2 - SAMPLE_PIPELINESTAT + * 3 - SAMPLE_STREAMOUTSTAT* + * 4 - *S_PARTIAL_FLUSH + * 5 - TS events + */ + +/* R600-R700*/ +#define R_008490_CP_STRMOUT_CNTL 0x008490 +#define S_008490_OFFSET_UPDATE_DONE(x) (((x) & 0x1) << 0) +#define R_028AB0_VGT_STRMOUT_EN 0x028AB0 +#define S_028AB0_STREAMOUT(x) (((x) & 0x1) << 0) +#define G_028AB0_STREAMOUT(x) (((x) >> 0) & 0x1) +#define C_028AB0_STREAMOUT 0xFFFFFFFE +#define R_028B20_VGT_STRMOUT_BUFFER_EN 0x028B20 +#define S_028B20_BUFFER_0_EN(x) (((x) & 0x1) << 0) +#define G_028B20_BUFFER_0_EN(x) (((x) >> 0) & 0x1) +#define C_028B20_BUFFER_0_EN 0xFFFFFFFE +#define S_028B20_BUFFER_1_EN(x) (((x) & 0x1) << 1) +#define G_028B20_BUFFER_1_EN(x) (((x) >> 1) & 0x1) +#define C_028B20_BUFFER_1_EN 0xFFFFFFFD +#define S_028B20_BUFFER_2_EN(x) (((x) & 0x1) << 2) +#define G_028B20_BUFFER_2_EN(x) (((x) >> 2) & 0x1) +#define C_028B20_BUFFER_2_EN 0xFFFFFFFB +#define S_028B20_BUFFER_3_EN(x) (((x) & 0x1) << 3) +#define G_028B20_BUFFER_3_EN(x) (((x) >> 3) & 0x1) +#define C_028B20_BUFFER_3_EN 0xFFFFFFF7 +#define R_028AD0_VGT_STRMOUT_BUFFER_SIZE_0 0x028AD0 + +/* EG+ */ +#define R_0084FC_CP_STRMOUT_CNTL 0x0084FC +#define S_0084FC_OFFSET_UPDATE_DONE(x) (((x) & 0x1) << 0) +#define R_028B94_VGT_STRMOUT_CONFIG 0x028B94 +#define S_028B94_STREAMOUT_0_EN(x) (((x) & 0x1) << 0) +#define G_028B94_STREAMOUT_0_EN(x) (((x) >> 0) & 0x1) +#define C_028B94_STREAMOUT_0_EN 0xFFFFFFFE +#define S_028B94_STREAMOUT_1_EN(x) (((x) & 0x1) << 1) +#define G_028B94_STREAMOUT_1_EN(x) (((x) >> 1) & 0x1) +#define C_028B94_STREAMOUT_1_EN 0xFFFFFFFD +#define S_028B94_STREAMOUT_2_EN(x) (((x) & 0x1) << 2) +#define G_028B94_STREAMOUT_2_EN(x) (((x) >> 2) & 0x1) +#define C_028B94_STREAMOUT_2_EN 0xFFFFFFFB +#define S_028B94_STREAMOUT_3_EN(x) (((x) & 0x1) << 3) +#define G_028B94_STREAMOUT_3_EN(x) (((x) >> 3) & 0x1) +#define C_028B94_STREAMOUT_3_EN 0xFFFFFFF7 +#define S_028B94_RAST_STREAM(x) (((x) & 0x07) << 4) +#define G_028B94_RAST_STREAM(x) (((x) >> 4) & 0x07) +#define C_028B94_RAST_STREAM 0xFFFFFF8F +#define S_028B94_RAST_STREAM_MASK(x) (((x) & 0x0F) << 8) /* SI+ */ +#define G_028B94_RAST_STREAM_MASK(x) (((x) >> 8) & 0x0F) +#define C_028B94_RAST_STREAM_MASK 0xFFFFF0FF +#define S_028B94_USE_RAST_STREAM_MASK(x) (((x) & 0x1) << 31) /* SI+ */ +#define G_028B94_USE_RAST_STREAM_MASK(x) (((x) >> 31) & 0x1) +#define C_028B94_USE_RAST_STREAM_MASK 0x7FFFFFFF +#define R_028B98_VGT_STRMOUT_BUFFER_CONFIG 0x028B98 +#define S_028B98_STREAM_0_BUFFER_EN(x) (((x) & 0x0F) << 0) +#define G_028B98_STREAM_0_BUFFER_EN(x) (((x) >> 0) & 0x0F) +#define C_028B98_STREAM_0_BUFFER_EN 0xFFFFFFF0 +#define S_028B98_STREAM_1_BUFFER_EN(x) (((x) & 0x0F) << 4) +#define G_028B98_STREAM_1_BUFFER_EN(x) (((x) >> 4) & 0x0F) +#define C_028B98_STREAM_1_BUFFER_EN 0xFFFFFF0F +#define S_028B98_STREAM_2_BUFFER_EN(x) (((x) & 0x0F) << 8) +#define G_028B98_STREAM_2_BUFFER_EN(x) (((x) >> 8) & 0x0F) +#define C_028B98_STREAM_2_BUFFER_EN 0xFFFFF0FF +#define S_028B98_STREAM_3_BUFFER_EN(x) (((x) & 0x0F) << 12) +#define G_028B98_STREAM_3_BUFFER_EN(x) (((x) >> 12) & 0x0F) +#define C_028B98_STREAM_3_BUFFER_EN 0xFFFF0FFF + +#endif |