diff options
author | Chia-I Wu <[email protected]> | 2014-09-24 13:06:45 +0800 |
---|---|---|
committer | Chia-I Wu <[email protected]> | 2014-09-26 21:15:55 +0800 |
commit | 392890d5de3970f5bee03a3ebce576e63e0a0bbf (patch) | |
tree | 692501acf1f093b60d6dce2febcd88ac89982d64 /src/gallium/drivers/ilo/ilo_draw.c | |
parent | 7e55c3b352b6616fa2780f683dd6c8e1a3f61815 (diff) |
ilo: rename ilo_3d.[ch] to ilo_draw.[ch]
There is not much left in struct ilo_3d. We want to kill it and ilo_3d.[ch]
will be bad names.
Signed-off-by: Chia-I Wu <[email protected]>
Diffstat (limited to 'src/gallium/drivers/ilo/ilo_draw.c')
-rw-r--r-- | src/gallium/drivers/ilo/ilo_draw.c | 701 |
1 files changed, 701 insertions, 0 deletions
diff --git a/src/gallium/drivers/ilo/ilo_draw.c b/src/gallium/drivers/ilo/ilo_draw.c new file mode 100644 index 00000000000..a155a41ac1b --- /dev/null +++ b/src/gallium/drivers/ilo/ilo_draw.c @@ -0,0 +1,701 @@ +/* + * Mesa 3-D graphics library + * + * Copyright (C) 2012-2013 LunarG, 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 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: + * Chia-I Wu <[email protected]> + */ + +#include "util/u_prim.h" +#include "intel_winsys.h" + +#include "ilo_3d_pipeline.h" +#include "ilo_blit.h" +#include "ilo_context.h" +#include "ilo_cp.h" +#include "ilo_query.h" +#include "ilo_shader.h" +#include "ilo_state.h" +#include "ilo_draw.h" + +static void +ilo_3d_own_render_ring(struct ilo_3d *hw3d) +{ + ilo_cp_set_owner(hw3d->cp, INTEL_RING_RENDER, &hw3d->owner); +} + +static uint64_t +query_timestamp_to_ns(const struct ilo_3d *hw3d, uint64_t timestamp) +{ + /* see ilo_get_timestamp() */ + return (timestamp & 0xffffffff) * 80; +} + +/** + * Process the bo and accumulate the result. The bo is emptied. + */ +static void +query_process_bo(const struct ilo_3d *hw3d, struct ilo_query *q) +{ + const uint64_t *vals; + uint64_t tmp; + int i; + + if (!q->used) + return; + + vals = intel_bo_map(q->bo, false); + if (!vals) { + q->used = 0; + return; + } + + switch (q->type) { + case PIPE_QUERY_OCCLUSION_COUNTER: + case PIPE_QUERY_TIME_ELAPSED: + case PIPE_QUERY_PRIMITIVES_GENERATED: + case PIPE_QUERY_PRIMITIVES_EMITTED: + assert(q->stride == sizeof(*vals) * 2); + + tmp = 0; + for (i = 0; i < q->used; i++) + tmp += vals[2 * i + 1] - vals[2 * i]; + + if (q->type == PIPE_QUERY_TIME_ELAPSED) + tmp = query_timestamp_to_ns(hw3d, tmp); + + q->result.u64 += tmp; + break; + case PIPE_QUERY_TIMESTAMP: + assert(q->stride == sizeof(*vals)); + + q->result.u64 = query_timestamp_to_ns(hw3d, vals[q->used - 1]); + break; + case PIPE_QUERY_PIPELINE_STATISTICS: + assert(q->stride == sizeof(*vals) * 22); + + for (i = 0; i < q->used; i++) { + struct pipe_query_data_pipeline_statistics *stats = + &q->result.pipeline_statistics; + const uint64_t *begin = vals + 22 * i; + const uint64_t *end = begin + 11; + + stats->ia_vertices += end[0] - begin[0]; + stats->ia_primitives += end[1] - begin[1]; + stats->vs_invocations += end[2] - begin[2]; + stats->gs_invocations += end[3] - begin[3]; + stats->gs_primitives += end[4] - begin[4]; + stats->c_invocations += end[5] - begin[5]; + stats->c_primitives += end[6] - begin[6]; + stats->ps_invocations += end[7] - begin[7]; + stats->hs_invocations += end[8] - begin[8]; + stats->ds_invocations += end[9] - begin[9]; + stats->cs_invocations += end[10] - begin[10]; + } + break; + default: + break; + } + + intel_bo_unmap(q->bo); + + q->used = 0; +} + +static void +query_begin_bo(struct ilo_3d *hw3d, struct ilo_query *q) +{ + /* bo is full */ + if (q->used >= q->count) + query_process_bo(hw3d, q); + + /* write the beginning value to the bo */ + if (q->in_pairs) + ilo_3d_pipeline_emit_query(hw3d->pipeline, q, q->stride * q->used); +} + +static void +query_end_bo(struct ilo_3d *hw3d, struct ilo_query *q) +{ + uint32_t offset; + + assert(q->used < q->count); + + offset = q->stride * q->used; + if (q->in_pairs) + offset += q->stride >> 1; + + q->used++; + + /* write the ending value to the bo */ + ilo_3d_pipeline_emit_query(hw3d->pipeline, q, offset); +} + +bool +ilo_3d_init_query(struct pipe_context *pipe, struct ilo_query *q) +{ + struct ilo_context *ilo = ilo_context(pipe); + unsigned bo_size; + + switch (q->type) { + case PIPE_QUERY_OCCLUSION_COUNTER: + case PIPE_QUERY_TIME_ELAPSED: + case PIPE_QUERY_PRIMITIVES_GENERATED: + case PIPE_QUERY_PRIMITIVES_EMITTED: + q->stride = sizeof(uint64_t); + q->in_pairs = true; + break; + case PIPE_QUERY_TIMESTAMP: + q->stride = sizeof(uint64_t); + q->in_pairs = false; + break; + case PIPE_QUERY_PIPELINE_STATISTICS: + q->stride = sizeof(uint64_t) * 11; + q->in_pairs = true; + break; + default: + return false; + break; + } + + q->cmd_len = ilo_3d_pipeline_estimate_size(ilo->hw3d->pipeline, + ILO_3D_PIPELINE_QUERY, q); + + /* double cmd_len and stride if in pairs */ + q->cmd_len <<= q->in_pairs; + q->stride <<= q->in_pairs; + + bo_size = (q->stride > 4096) ? q->stride : 4096; + q->bo = intel_winsys_alloc_buffer(ilo->winsys, "query", bo_size, false); + if (!q->bo) + return false; + + q->count = bo_size / q->stride; + + return true; +} + +void +ilo_3d_begin_query(struct pipe_context *pipe, struct ilo_query *q) +{ + struct ilo_3d *hw3d = ilo_context(pipe)->hw3d; + + ilo_3d_own_render_ring(hw3d); + + /* need to submit first */ + if (!ilo_builder_validate(&hw3d->cp->builder, 1, &q->bo) || + ilo_cp_space(hw3d->cp) < q->cmd_len) { + ilo_cp_submit(hw3d->cp, "out of aperture or space"); + + assert(ilo_builder_validate(&hw3d->cp->builder, 1, &q->bo)); + assert(ilo_cp_space(hw3d->cp) >= q->cmd_len); + + ilo_3d_own_render_ring(hw3d); + } + + /* reserve the space for ending/pausing the query */ + hw3d->owner.reserve += q->cmd_len >> q->in_pairs; + + query_begin_bo(hw3d, q); + + if (q->in_pairs) + list_add(&q->list, &hw3d->queries); +} + +void +ilo_3d_end_query(struct pipe_context *pipe, struct ilo_query *q) +{ + struct ilo_3d *hw3d = ilo_context(pipe)->hw3d; + + ilo_3d_own_render_ring(hw3d); + + /* reclaim the reserved space */ + hw3d->owner.reserve -= q->cmd_len >> q->in_pairs; + assert(hw3d->owner.reserve >= 0); + + query_end_bo(hw3d, q); + + list_delinit(&q->list); +} + +/** + * Process the raw query data. + */ +void +ilo_3d_process_query(struct pipe_context *pipe, struct ilo_query *q) +{ + struct ilo_3d *hw3d = ilo_context(pipe)->hw3d; + + query_process_bo(hw3d, q); +} + +static void +ilo_3d_own_cp(struct ilo_cp *cp, void *data) +{ + struct ilo_3d *hw3d = data; + + /* multiply by 2 for both resuming and pausing */ + if (ilo_cp_space(hw3d->cp) < hw3d->owner.reserve * 2) { + ilo_cp_submit(hw3d->cp, "out of space"); + assert(ilo_cp_space(hw3d->cp) >= hw3d->owner.reserve * 2); + } + + while (true) { + struct ilo_builder_snapshot snapshot; + struct ilo_query *q; + + ilo_builder_batch_snapshot(&hw3d->cp->builder, &snapshot); + + /* resume queries */ + LIST_FOR_EACH_ENTRY(q, &hw3d->queries, list) + query_begin_bo(hw3d, q); + + if (!ilo_builder_validate(&hw3d->cp->builder, 0, NULL)) { + ilo_builder_batch_restore(&hw3d->cp->builder, &snapshot); + + if (ilo_builder_batch_used(&hw3d->cp->builder)) { + ilo_cp_submit(hw3d->cp, "out of aperture"); + continue; + } + } + + break; + } + + assert(ilo_cp_space(hw3d->cp) >= hw3d->owner.reserve); +} + +static void +ilo_3d_release_cp(struct ilo_cp *cp, void *data) +{ + struct ilo_3d *hw3d = data; + struct ilo_query *q; + + assert(ilo_cp_space(hw3d->cp) >= hw3d->owner.reserve); + + /* pause queries */ + LIST_FOR_EACH_ENTRY(q, &hw3d->queries, list) + query_end_bo(hw3d, q); +} + +/** + * Hook for CP new-batch. + */ +void +ilo_3d_cp_submitted(struct ilo_3d *hw3d) +{ + /* invalidate the pipeline */ + ilo_3d_pipeline_invalidate(hw3d->pipeline, + ILO_3D_PIPELINE_INVALIDATE_BATCH_BO | + ILO_3D_PIPELINE_INVALIDATE_STATE_BO | + ILO_3D_PIPELINE_INVALIDATE_KERNEL_BO); + + hw3d->new_batch = true; +} + +/** + * Create a 3D context. + */ +struct ilo_3d * +ilo_3d_create(struct ilo_cp *cp, const struct ilo_dev_info *dev) +{ + struct ilo_3d *hw3d; + + hw3d = CALLOC_STRUCT(ilo_3d); + if (!hw3d) + return NULL; + + hw3d->cp = cp; + hw3d->owner.own = ilo_3d_own_cp; + hw3d->owner.release = ilo_3d_release_cp; + hw3d->owner.data = hw3d; + hw3d->owner.reserve = 0; + + hw3d->new_batch = true; + + list_inithead(&hw3d->queries); + + hw3d->pipeline = ilo_3d_pipeline_create(&cp->builder); + if (!hw3d->pipeline) { + FREE(hw3d); + return NULL; + } + + return hw3d; +} + +/** + * Destroy a 3D context. + */ +void +ilo_3d_destroy(struct ilo_3d *hw3d) +{ + ilo_3d_pipeline_destroy(hw3d->pipeline); + FREE(hw3d); +} + +static bool +draw_vbo(struct ilo_3d *hw3d, const struct ilo_state_vector *vec) +{ + bool need_flush = false; + bool success = true; + int max_len, before_space; + + /* on GEN7+, we need SOL_RESET to reset the SO write offsets */ + if (ilo_dev_gen(hw3d->pipeline->dev) >= ILO_GEN(7) && + (vec->dirty & ILO_DIRTY_SO) && vec->so.enabled && + !vec->so.append_bitmask) { + ilo_cp_submit(hw3d->cp, "SOL_RESET"); + ilo_cp_set_one_off_flags(hw3d->cp, INTEL_EXEC_GEN7_SOL_RESET); + } + + ilo_3d_own_render_ring(hw3d); + + if (!hw3d->new_batch) { + /* + * Without a better tracking mechanism, when the framebuffer changes, we + * have to assume that the old framebuffer may be sampled from. If that + * happens in the middle of a batch buffer, we need to insert manual + * flushes. + */ + need_flush = (vec->dirty & ILO_DIRTY_FB); + + /* same to SO target changes */ + need_flush |= (vec->dirty & ILO_DIRTY_SO); + } + + /* make sure there is enough room first */ + max_len = ilo_3d_pipeline_estimate_size(hw3d->pipeline, + ILO_3D_PIPELINE_DRAW, vec); + if (need_flush) { + max_len += ilo_3d_pipeline_estimate_size(hw3d->pipeline, + ILO_3D_PIPELINE_FLUSH, NULL); + } + + if (max_len > ilo_cp_space(hw3d->cp)) { + ilo_cp_submit(hw3d->cp, "out of space"); + need_flush = false; + assert(max_len <= ilo_cp_space(hw3d->cp)); + } + + /* space available before emission */ + before_space = ilo_cp_space(hw3d->cp); + + if (need_flush) + ilo_3d_pipeline_emit_flush(hw3d->pipeline); + + while (true) { + struct ilo_builder_snapshot snapshot; + + ilo_builder_batch_snapshot(&hw3d->cp->builder, &snapshot); + + ilo_3d_pipeline_emit_draw(hw3d->pipeline, vec); + + if (!ilo_builder_validate(&hw3d->cp->builder, 0, NULL)) { + ilo_builder_batch_restore(&hw3d->cp->builder, &snapshot); + + /* flush and try again */ + if (ilo_builder_batch_used(&hw3d->cp->builder)) { + ilo_cp_submit(hw3d->cp, "out of aperture"); + continue; + } + + success = false; + } + + break; + } + + hw3d->pipeline->invalidate_flags = 0x0; + + /* sanity check size estimation */ + assert(before_space - ilo_cp_space(hw3d->cp) <= max_len); + + return success; +} + +void +ilo_3d_draw_rectlist(struct ilo_3d *hw3d, const struct ilo_blitter *blitter) +{ + int max_len, before_space; + + ilo_3d_own_render_ring(hw3d); + + max_len = ilo_3d_pipeline_estimate_size(hw3d->pipeline, + ILO_3D_PIPELINE_RECTLIST, blitter); + max_len += ilo_3d_pipeline_estimate_size(hw3d->pipeline, + ILO_3D_PIPELINE_FLUSH, NULL) * 2; + + if (max_len > ilo_cp_space(hw3d->cp)) { + ilo_cp_submit(hw3d->cp, "out of space"); + assert(max_len <= ilo_cp_space(hw3d->cp)); + } + + before_space = ilo_cp_space(hw3d->cp); + + /* + * From the Sandy Bridge PRM, volume 2 part 1, page 313: + * + * "If other rendering operations have preceded this clear, a + * PIPE_CONTROL with write cache flush enabled and Z-inhibit + * disabled must be issued before the rectangle primitive used for + * the depth buffer clear operation." + * + * From the Sandy Bridge PRM, volume 2 part 1, page 314: + * + * "Depth buffer clear pass must be followed by a PIPE_CONTROL + * command with DEPTH_STALL bit set and Then followed by Depth + * FLUSH" + * + * But the pipeline has to be flushed both before and after not only + * because of these workarounds. We need them for reasons such as + * + * - we may sample from a texture that was rendered to + * - we may sample from the fb shortly after + * + * Skip checking blitter->op and do the flushes. + */ + if (!hw3d->new_batch) + ilo_3d_pipeline_emit_flush(hw3d->pipeline); + + while (true) { + struct ilo_builder_snapshot snapshot; + + ilo_builder_batch_snapshot(&hw3d->cp->builder, &snapshot); + + ilo_3d_pipeline_emit_rectlist(hw3d->pipeline, blitter); + + if (!ilo_builder_validate(&hw3d->cp->builder, 0, NULL)) { + ilo_builder_batch_restore(&hw3d->cp->builder, &snapshot); + + /* flush and try again */ + if (ilo_builder_batch_used(&hw3d->cp->builder)) { + ilo_cp_submit(hw3d->cp, "out of aperture"); + continue; + } + } + + break; + } + + ilo_3d_pipeline_invalidate(hw3d->pipeline, ILO_3D_PIPELINE_INVALIDATE_HW); + + ilo_3d_pipeline_emit_flush(hw3d->pipeline); + + /* sanity check size estimation */ + assert(before_space - ilo_cp_space(hw3d->cp) <= max_len); + + hw3d->new_batch = false; +} + +static void +draw_vbo_with_sw_restart(struct ilo_context *ilo, + const struct pipe_draw_info *info) +{ + const struct ilo_ib_state *ib = &ilo->state_vector.ib; + union { + const void *ptr; + const uint8_t *u8; + const uint16_t *u16; + const uint32_t *u32; + } u; + + /* we will draw with IB mapped */ + if (ib->buffer) { + u.ptr = intel_bo_map(ilo_buffer(ib->buffer)->bo, false); + if (u.ptr) + u.u8 += ib->offset; + } else { + u.ptr = ib->user_buffer; + } + + if (!u.ptr) + return; + +#define DRAW_VBO_WITH_SW_RESTART(pipe, info, ptr) do { \ + const unsigned end = (info)->start + (info)->count; \ + struct pipe_draw_info subinfo; \ + unsigned i; \ + \ + subinfo = *(info); \ + subinfo.primitive_restart = false; \ + for (i = (info)->start; i < end; i++) { \ + if ((ptr)[i] == (info)->restart_index) { \ + subinfo.count = i - subinfo.start; \ + if (subinfo.count) \ + (pipe)->draw_vbo(pipe, &subinfo); \ + subinfo.start = i + 1; \ + } \ + } \ + subinfo.count = i - subinfo.start; \ + if (subinfo.count) \ + (pipe)->draw_vbo(pipe, &subinfo); \ +} while (0) + + switch (ib->index_size) { + case 1: + DRAW_VBO_WITH_SW_RESTART(&ilo->base, info, u.u8); + break; + case 2: + DRAW_VBO_WITH_SW_RESTART(&ilo->base, info, u.u16); + break; + case 4: + DRAW_VBO_WITH_SW_RESTART(&ilo->base, info, u.u32); + break; + default: + assert(!"unsupported index size"); + break; + } + +#undef DRAW_VBO_WITH_SW_RESTART + + if (ib->buffer) + intel_bo_unmap(ilo_buffer(ib->buffer)->bo); +} + +static bool +draw_vbo_need_sw_restart(const struct ilo_context *ilo, + const struct pipe_draw_info *info) +{ + /* the restart index is fixed prior to GEN7.5 */ + if (ilo_dev_gen(ilo->dev) < ILO_GEN(7.5)) { + const unsigned cut_index = + (ilo->state_vector.ib.index_size == 1) ? 0xff : + (ilo->state_vector.ib.index_size == 2) ? 0xffff : + (ilo->state_vector.ib.index_size == 4) ? 0xffffffff : 0; + + if (info->restart_index < cut_index) + return true; + } + + switch (info->mode) { + case PIPE_PRIM_POINTS: + case PIPE_PRIM_LINES: + case PIPE_PRIM_LINE_STRIP: + case PIPE_PRIM_TRIANGLES: + case PIPE_PRIM_TRIANGLE_STRIP: + /* these never need software fallback */ + return false; + case PIPE_PRIM_LINE_LOOP: + case PIPE_PRIM_POLYGON: + case PIPE_PRIM_QUAD_STRIP: + case PIPE_PRIM_QUADS: + case PIPE_PRIM_TRIANGLE_FAN: + /* these need software fallback prior to GEN7.5 */ + return (ilo_dev_gen(ilo->dev) < ILO_GEN(7.5)); + default: + /* the rest always needs software fallback */ + return true; + } +} + +static void +ilo_draw_vbo(struct pipe_context *pipe, const struct pipe_draw_info *info) +{ + struct ilo_context *ilo = ilo_context(pipe); + struct ilo_3d *hw3d = ilo->hw3d; + + if (ilo_debug & ILO_DEBUG_DRAW) { + if (info->indexed) { + ilo_printf("indexed draw %s: " + "index start %d, count %d, vertex range [%d, %d]\n", + u_prim_name(info->mode), info->start, info->count, + info->min_index, info->max_index); + } + else { + ilo_printf("draw %s: vertex start %d, count %d\n", + u_prim_name(info->mode), info->start, info->count); + } + + ilo_state_vector_dump_dirty(&ilo->state_vector); + } + + if (ilo_skip_rendering(ilo)) + return; + + if (info->primitive_restart && info->indexed && + draw_vbo_need_sw_restart(ilo, info)) { + draw_vbo_with_sw_restart(ilo, info); + return; + } + + ilo_finalize_3d_states(ilo, info); + + ilo_shader_cache_upload(ilo->shader_cache, &hw3d->cp->builder); + + ilo_blit_resolve_framebuffer(ilo); + + /* If draw_vbo ever fails, return immediately. */ + if (!draw_vbo(hw3d, &ilo->state_vector)) + return; + + /* clear dirty status */ + ilo->state_vector.dirty = 0x0; + hw3d->new_batch = false; + + /* avoid dangling pointer reference */ + ilo->state_vector.draw = NULL; + + if (ilo_debug & ILO_DEBUG_NOCACHE) + ilo_3d_pipeline_emit_flush(hw3d->pipeline); +} + +static void +ilo_texture_barrier(struct pipe_context *pipe) +{ + struct ilo_context *ilo = ilo_context(pipe); + struct ilo_3d *hw3d = ilo->hw3d; + + if (ilo->cp->ring != INTEL_RING_RENDER) + return; + + ilo_3d_pipeline_emit_flush(hw3d->pipeline); + + /* don't know why */ + if (ilo_dev_gen(ilo->dev) >= ILO_GEN(7)) + ilo_cp_submit(hw3d->cp, "texture barrier"); +} + +static void +ilo_get_sample_position(struct pipe_context *pipe, + unsigned sample_count, + unsigned sample_index, + float *out_value) +{ + struct ilo_context *ilo = ilo_context(pipe); + struct ilo_3d *hw3d = ilo->hw3d; + + ilo_3d_pipeline_get_sample_position(hw3d->pipeline, + sample_count, sample_index, + &out_value[0], &out_value[1]); +} + +/** + * Initialize 3D-related functions. + */ +void +ilo_init_3d_functions(struct ilo_context *ilo) +{ + ilo->base.draw_vbo = ilo_draw_vbo; + ilo->base.texture_barrier = ilo_texture_barrier; + ilo->base.get_sample_position = ilo_get_sample_position; +} |