static void ilo_draw_vbo(struct pipe_context *pipe, const struct pipe_draw_info *info) { struct ilo_context *ilo = ilo_context(pipe); int vs_scratch_size, gs_scratch_size, fs_scratch_size; 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); /* upload kernels */ ilo_shader_cache_upload(ilo->shader_cache, &ilo->cp->builder); /* prepare scratch spaces */ ilo_shader_cache_get_max_scratch_sizes(ilo->shader_cache, &vs_scratch_size, &gs_scratch_size, &fs_scratch_size); ilo_render_prepare_scratch_spaces(ilo->render, vs_scratch_size, gs_scratch_size, fs_scratch_size); ilo_blit_resolve_framebuffer(ilo); /* If draw_vbo ever fails, return immediately. */ if (!draw_vbo(ilo, &ilo->state_vector)) return; /* clear dirty status */ ilo->state_vector.dirty = 0x0; /* avoid dangling pointer reference */ ilo->state_vector.draw = NULL; if (ilo_debug & ILO_DEBUG_NOCACHE) ilo_render_emit_flush(ilo->render); }
static void dump_VC4_PACKET_GL_ARRAY_PRIMITIVE(void *cl, uint32_t offset, uint32_t hw_offset) { uint8_t *b = cl + offset; uint32_t *count = cl + offset + 1; uint32_t *start = cl + offset + 5; fprintf(stderr, "0x%08x 0x%08x: 0x%02x %s\n", offset, hw_offset, b[0], u_prim_name(b[0] & 0x7)); fprintf(stderr, "0x%08x 0x%08x: %d verts\n", offset + 1, hw_offset + 1, *count); fprintf(stderr, "0x%08x 0x%08x: 0x%08x start\n", offset + 5, hw_offset + 5, *start); }
static enum pc_di_primtype mode2primtype(unsigned mode) { switch (mode) { case PIPE_PRIM_POINTS: return DI_PT_POINTLIST; case PIPE_PRIM_LINES: return DI_PT_LINELIST; case PIPE_PRIM_LINE_STRIP: return DI_PT_LINESTRIP; case PIPE_PRIM_TRIANGLES: return DI_PT_TRILIST; case PIPE_PRIM_TRIANGLE_STRIP: return DI_PT_TRISTRIP; case PIPE_PRIM_TRIANGLE_FAN: return DI_PT_TRIFAN; case PIPE_PRIM_QUADS: return DI_PT_QUADLIST; case PIPE_PRIM_QUAD_STRIP: return DI_PT_QUADSTRIP; case PIPE_PRIM_POLYGON: return DI_PT_POLYGON; } DBG("unsupported mode: (%s) %d", u_prim_name(mode), mode); assert(0); return DI_PT_NONE; }
static void dump_VC4_PACKET_GL_INDEXED_PRIMITIVE(void *cl, uint32_t offset, uint32_t hw_offset) { uint8_t *b = cl + offset; uint32_t *count = cl + offset + 1; uint32_t *ib_offset = cl + offset + 5; uint32_t *max_index = cl + offset + 9; fprintf(stderr, "0x%08x 0x%08x: 0x%02x %s %s\n", offset, hw_offset, b[0], (b[0] & VC4_INDEX_BUFFER_U16) ? "16-bit" : "8-bit", u_prim_name(b[0] & 0x7)); fprintf(stderr, "0x%08x 0x%08x: %d verts\n", offset + 1, hw_offset + 1, *count); fprintf(stderr, "0x%08x 0x%08x: 0x%08x IB offset\n", offset + 5, hw_offset + 5, *ib_offset); fprintf(stderr, "0x%08x 0x%08x: 0x%08x max index\n", offset + 9, hw_offset + 9, *max_index); }
/** * Execute geometry shader. */ int draw_geometry_shader_run(struct draw_geometry_shader *shader, const void *constants[PIPE_MAX_CONSTANT_BUFFERS], const unsigned constants_size[PIPE_MAX_CONSTANT_BUFFERS], const struct draw_vertex_info *input_verts, const struct draw_prim_info *input_prim, const struct tgsi_shader_info *input_info, struct draw_vertex_info *output_verts, struct draw_prim_info *output_prims ) { const float (*input)[4] = (const float (*)[4])input_verts->verts->data; unsigned input_stride = input_verts->vertex_size; unsigned num_outputs = draw_total_gs_outputs(shader->draw); unsigned vertex_size = sizeof(struct vertex_header) + num_outputs * 4 * sizeof(float); unsigned num_input_verts = input_prim->linear ? input_verts->count : input_prim->count; unsigned num_in_primitives = align( MAX2(u_decomposed_prims_for_vertices(input_prim->prim, num_input_verts), u_decomposed_prims_for_vertices(shader->input_primitive, num_input_verts)), shader->vector_length); unsigned max_out_prims = u_decomposed_prims_for_vertices(shader->output_primitive, shader->max_output_vertices) * num_in_primitives; //Assume at least one primitive max_out_prims = MAX2(max_out_prims, 1); output_verts->vertex_size = vertex_size; output_verts->stride = output_verts->vertex_size; /* we allocate exactly one extra vertex per primitive to allow the GS to emit * overflown vertices into some area where they won't harm anyone */ output_verts->verts = (struct vertex_header *)MALLOC(output_verts->vertex_size * max_out_prims * shader->primitive_boundary); #if 0 debug_printf("%s count = %d (in prims # = %d)\n", __FUNCTION__, num_input_verts, num_in_primitives); debug_printf("\tlinear = %d, prim_info->count = %d\n", input_prim->linear, input_prim->count); debug_printf("\tprim pipe = %s, shader in = %s, shader out = %s, max out = %d\n", u_prim_name(input_prim->prim), u_prim_name(shader->input_primitive), u_prim_name(shader->output_primitive), shader->max_output_vertices); #endif shader->emitted_vertices = 0; shader->emitted_primitives = 0; shader->vertex_size = vertex_size; shader->tmp_output = (float (*)[4])output_verts->verts->data; shader->fetched_prim_count = 0; shader->input_vertex_stride = input_stride; shader->input = input; shader->input_info = input_info; FREE(shader->primitive_lengths); shader->primitive_lengths = MALLOC(max_out_prims * sizeof(unsigned)); #ifdef HAVE_LLVM if (draw_get_option_use_llvm()) { shader->gs_output = output_verts->verts; if (max_out_prims > shader->max_out_prims) { unsigned i; if (shader->llvm_prim_lengths) { for (i = 0; i < shader->max_out_prims; ++i) { align_free(shader->llvm_prim_lengths[i]); } FREE(shader->llvm_prim_lengths); } shader->llvm_prim_lengths = MALLOC(max_out_prims * sizeof(unsigned*)); for (i = 0; i < max_out_prims; ++i) { int vector_size = shader->vector_length * sizeof(unsigned); shader->llvm_prim_lengths[i] = align_malloc(vector_size, vector_size); } shader->max_out_prims = max_out_prims; } shader->jit_context->prim_lengths = shader->llvm_prim_lengths; shader->jit_context->emitted_vertices = shader->llvm_emitted_vertices; shader->jit_context->emitted_prims = shader->llvm_emitted_primitives; } #endif shader->prepare(shader, constants, constants_size); if (input_prim->linear) gs_run(shader, input_prim, input_verts, output_prims, output_verts); else gs_run_elts(shader, input_prim, input_verts, output_prims, output_verts); /* Flush the remaining primitives. Will happen if * num_input_primitives % 4 != 0 */ if (shader->fetched_prim_count > 0) { gs_flush(shader); } debug_assert(shader->fetched_prim_count == 0); /* Update prim_info: */ output_prims->linear = TRUE; output_prims->elts = NULL; output_prims->start = 0; output_prims->count = shader->emitted_vertices; output_prims->prim = shader->output_primitive; output_prims->flags = 0x0; output_prims->primitive_lengths = shader->primitive_lengths; output_prims->primitive_count = shader->emitted_primitives; output_verts->count = shader->emitted_vertices; if (shader->draw->collect_statistics) { unsigned i; for (i = 0; i < shader->emitted_primitives; ++i) { shader->draw->statistics.gs_primitives += u_decomposed_prims_for_vertices(shader->output_primitive, shader->primitive_lengths[i]); } } #if 0 debug_printf("GS finished, prims = %d, verts = %d\n", output_prims->primitive_count, output_verts->count); #endif return shader->emitted_vertices; }
static void vc4_draw_vbo(struct pipe_context *pctx, const struct pipe_draw_info *info) { struct vc4_context *vc4 = vc4_context(pctx); if (info->mode >= PIPE_PRIM_QUADS) { util_primconvert_save_index_buffer(vc4->primconvert, &vc4->indexbuf); util_primconvert_save_rasterizer_state(vc4->primconvert, &vc4->rasterizer->base); util_primconvert_draw_vbo(vc4->primconvert, info); perf_debug("Fallback conversion for %d %s vertices\n", info->count, u_prim_name(info->mode)); return; } /* Before setting up the draw, do any fixup blits necessary. */ vc4_update_shadow_textures(pctx, &vc4->verttex); vc4_update_shadow_textures(pctx, &vc4->fragtex); vc4_hw_2116_workaround(pctx); vc4_get_draw_cl_space(vc4); if (vc4->prim_mode != info->mode) { vc4->prim_mode = info->mode; vc4->dirty |= VC4_DIRTY_PRIM_MODE; } vc4_start_draw(vc4); vc4_update_compiled_shaders(vc4, info->mode); vc4_emit_state(pctx); if ((vc4->dirty & (VC4_DIRTY_VTXBUF | VC4_DIRTY_VTXSTATE | VC4_DIRTY_PRIM_MODE | VC4_DIRTY_RASTERIZER | VC4_DIRTY_COMPILED_CS | VC4_DIRTY_COMPILED_VS | VC4_DIRTY_COMPILED_FS | vc4->prog.cs->uniform_dirty_bits | vc4->prog.vs->uniform_dirty_bits | vc4->prog.fs->uniform_dirty_bits)) || vc4->last_index_bias != info->index_bias) { vc4_emit_gl_shader_state(vc4, info); } vc4->dirty = 0; /* Note that the primitive type fields match with OpenGL/gallium * definitions, up to but not including QUADS. */ struct vc4_cl_out *bcl = cl_start(&vc4->bcl); if (info->indexed) { uint32_t offset = vc4->indexbuf.offset; uint32_t index_size = vc4->indexbuf.index_size; struct pipe_resource *prsc; if (vc4->indexbuf.index_size == 4) { prsc = vc4_get_shadow_index_buffer(pctx, &vc4->indexbuf, info->count, &offset); index_size = 2; } else { if (vc4->indexbuf.user_buffer) { prsc = NULL; u_upload_data(vc4->uploader, 0, info->count * index_size, 4, vc4->indexbuf.user_buffer, &offset, &prsc); } else { prsc = vc4->indexbuf.buffer; } } struct vc4_resource *rsc = vc4_resource(prsc); cl_start_reloc(&vc4->bcl, &bcl, 1); cl_u8(&bcl, VC4_PACKET_GL_INDEXED_PRIMITIVE); cl_u8(&bcl, info->mode | (index_size == 2 ? VC4_INDEX_BUFFER_U16: VC4_INDEX_BUFFER_U8)); cl_u32(&bcl, info->count); cl_reloc(vc4, &vc4->bcl, &bcl, rsc->bo, offset); cl_u32(&bcl, vc4->max_index); if (vc4->indexbuf.index_size == 4 || vc4->indexbuf.user_buffer) pipe_resource_reference(&prsc, NULL); } else { cl_u8(&bcl, VC4_PACKET_GL_ARRAY_PRIMITIVE); cl_u8(&bcl, info->mode); cl_u32(&bcl, info->count); cl_u32(&bcl, info->start); } cl_end(&vc4->bcl, bcl); if (vc4->zsa && vc4->zsa->base.depth.enabled) { vc4->resolve |= PIPE_CLEAR_DEPTH; } if (vc4->zsa && vc4->zsa->base.stencil[0].enabled) vc4->resolve |= PIPE_CLEAR_STENCIL; vc4->resolve |= PIPE_CLEAR_COLOR0; vc4->shader_rec_count++; if (vc4_debug & VC4_DEBUG_ALWAYS_FLUSH) vc4_flush(pctx); }
/** * This function gets plugged into the VBO module and is called when * we have something to render. * Basically, translate the information into the format expected by gallium. */ void st_draw_vbo(struct gl_context *ctx, const struct _mesa_prim *prims, GLuint nr_prims, const struct _mesa_index_buffer *ib, GLboolean index_bounds_valid, GLuint min_index, GLuint max_index, struct gl_transform_feedback_object *tfb_vertcount, struct gl_buffer_object *indirect) { struct st_context *st = st_context(ctx); struct pipe_index_buffer ibuffer = {0}; struct pipe_draw_info info; const struct gl_client_array **arrays = ctx->Array._DrawArrays; unsigned i; /* Mesa core state should have been validated already */ assert(ctx->NewState == 0x0); /* Validate state. */ if (st->dirty.st || ctx->NewDriverState) { st_validate_state(st); #if 0 if (MESA_VERBOSE & VERBOSE_GLSL) { check_uniforms(ctx); } #else (void) check_uniforms; #endif } if (st->vertex_array_out_of_memory) { return; } util_draw_init_info(&info); if (ib) { /* Get index bounds for user buffers. */ if (!index_bounds_valid) if (!all_varyings_in_vbos(arrays)) vbo_get_minmax_indices(ctx, prims, ib, &min_index, &max_index, nr_prims); if (!setup_index_buffer(st, ib, &ibuffer)) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBegin/DrawElements/DrawArray"); return; } info.indexed = TRUE; if (min_index != ~0 && max_index != ~0) { info.min_index = min_index; info.max_index = max_index; } /* The VBO module handles restart for the non-indexed GLDrawArrays * so we only set these fields for indexed drawing: */ info.primitive_restart = ctx->Array._PrimitiveRestart; info.restart_index = ctx->Array.RestartIndex; } else { /* Transform feedback drawing is always non-indexed. */ /* Set info.count_from_stream_output. */ if (tfb_vertcount) { st_transform_feedback_draw_init(tfb_vertcount, &info); } } /* do actual drawing */ for (i = 0; i < nr_prims; i++) { info.mode = translate_prim(ctx, prims[i].mode); info.start = prims[i].start; info.count = prims[i].count; info.start_instance = prims[i].base_instance; info.instance_count = prims[i].num_instances; info.index_bias = prims[i].basevertex; if (!ib) { info.min_index = info.start; info.max_index = info.start + info.count - 1; } if (ST_DEBUG & DEBUG_DRAW) { debug_printf("st/draw: mode %s start %u count %u indexed %d\n", u_prim_name(info.mode), info.start, info.count, info.indexed); } if (info.count_from_stream_output) { cso_draw_vbo(st->cso_context, &info); } else if (info.primitive_restart) { /* don't trim, restarts might be inside index list */ cso_draw_vbo(st->cso_context, &info); } else if (u_trim_pipe_prim(prims[i].mode, &info.count)) { cso_draw_vbo(st->cso_context, &info); } } if (ib && st->indexbuf_uploader && !_mesa_is_bufferobj(ib->obj)) { pipe_resource_reference(&ibuffer.buffer, NULL); } }
/** * Execute geometry shader using TGSI interpreter. */ int draw_geometry_shader_run(struct draw_geometry_shader *shader, const void *constants[PIPE_MAX_CONSTANT_BUFFERS], const unsigned constants_size[PIPE_MAX_CONSTANT_BUFFERS], const struct draw_vertex_info *input_verts, const struct draw_prim_info *input_prim, const struct tgsi_shader_info *input_info, struct draw_vertex_info *output_verts, struct draw_prim_info *output_prims ) { const float (*input)[4] = (const float (*)[4])input_verts->verts->data; unsigned input_stride = input_verts->vertex_size; unsigned num_outputs = shader->info.num_outputs; unsigned vertex_size = sizeof(struct vertex_header) + num_outputs * 4 * sizeof(float); struct tgsi_exec_machine *machine = shader->machine; unsigned num_input_verts = input_prim->linear ? input_verts->count : input_prim->count; unsigned num_in_primitives = MAX2(u_gs_prims_for_vertices(input_prim->prim, num_input_verts), u_gs_prims_for_vertices(shader->input_primitive, num_input_verts)); unsigned max_out_prims = u_gs_prims_for_vertices(shader->output_primitive, shader->max_output_vertices) * num_in_primitives; output_verts->vertex_size = vertex_size; output_verts->stride = output_verts->vertex_size; output_verts->verts = (struct vertex_header *)MALLOC(output_verts->vertex_size * num_in_primitives * shader->max_output_vertices); #if 0 debug_printf("%s count = %d (in prims # = %d)\n", __FUNCTION__, num_input_verts, num_in_primitives); debug_printf("\tlinear = %d, prim_info->count = %d\n", input_prim->linear, input_prim->count); debug_printf("\tprim pipe = %s, shader in = %s, shader out = %s, max out = %d\n", u_prim_name(input_prim->prim), u_prim_name(shader->input_primitive), u_prim_name(shader->output_primitive), shader->max_output_vertices); #endif shader->emitted_vertices = 0; shader->emitted_primitives = 0; shader->vertex_size = vertex_size; shader->tmp_output = (float (*)[4])output_verts->verts->data; shader->in_prim_idx = 0; shader->input_vertex_stride = input_stride; shader->input = input; shader->input_info = input_info; FREE(shader->primitive_lengths); shader->primitive_lengths = MALLOC(max_out_prims * sizeof(unsigned)); tgsi_exec_set_constant_buffers(machine, PIPE_MAX_CONSTANT_BUFFERS, constants, constants_size); if (input_prim->linear) gs_run(shader, input_prim, input_verts, output_prims, output_verts); else gs_run_elts(shader, input_prim, input_verts, output_prims, output_verts); /* Update prim_info: */ output_prims->linear = TRUE; output_prims->elts = NULL; output_prims->start = 0; output_prims->count = shader->emitted_vertices; output_prims->prim = shader->output_primitive; output_prims->flags = 0x0; output_prims->primitive_lengths = shader->primitive_lengths; output_prims->primitive_count = shader->emitted_primitives; output_verts->count = shader->emitted_vertices; #if 0 debug_printf("GS finished, prims = %d, verts = %d\n", output_prims->primitive_count, output_verts->count); #endif return shader->emitted_vertices; }
static void st_indirect_draw_vbo(struct gl_context *ctx, GLuint mode, struct gl_buffer_object *indirect_data, GLsizeiptr indirect_offset, unsigned draw_count, unsigned stride, struct gl_buffer_object *indirect_params, GLsizeiptr indirect_params_offset, const struct _mesa_index_buffer *ib) { struct st_context *st = st_context(ctx); struct pipe_index_buffer ibuffer = {0}; struct pipe_draw_info info; /* Mesa core state should have been validated already */ assert(ctx->NewState == 0x0); assert(stride); /* Validate state. */ if ((st->dirty | ctx->NewDriverState) & ST_PIPELINE_RENDER_STATE_MASK || st->gfx_shaders_may_be_dirty) { st_validate_state(st, ST_PIPELINE_RENDER); } if (st->vertex_array_out_of_memory) { return; } util_draw_init_info(&info); if (ib) { if (!setup_index_buffer(st, ib, &ibuffer)) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "gl%sDrawElementsIndirect%s", (draw_count > 1) ? "Multi" : "", indirect_params ? "CountARB" : ""); return; } info.indexed = TRUE; /* Primitive restart is not handled by the VBO module in this case. */ setup_primitive_restart(ctx, ib, &info); } info.mode = translate_prim(ctx, mode); info.vertices_per_patch = ctx->TessCtrlProgram.patch_vertices; info.indirect = st_buffer_object(indirect_data)->buffer; info.indirect_offset = indirect_offset; if (ST_DEBUG & DEBUG_DRAW) { debug_printf("st/draw indirect: mode %s drawcount %d indexed %d\n", u_prim_name(info.mode), draw_count, info.indexed); } if (!st->has_multi_draw_indirect) { int i; assert(!indirect_params); info.indirect_count = 1; for (i = 0; i < draw_count; i++) { info.drawid = i; cso_draw_vbo(st->cso_context, &info); info.indirect_offset += stride; } } else { info.indirect_count = draw_count; info.indirect_stride = stride; if (indirect_params) { info.indirect_params = st_buffer_object(indirect_params)->buffer; info.indirect_params_offset = indirect_params_offset; } cso_draw_vbo(st->cso_context, &info); } }
static void vc4_draw_vbo(struct pipe_context *pctx, const struct pipe_draw_info *info) { struct vc4_context *vc4 = vc4_context(pctx); if (info->mode >= PIPE_PRIM_QUADS) { util_primconvert_save_index_buffer(vc4->primconvert, &vc4->indexbuf); util_primconvert_save_rasterizer_state(vc4->primconvert, &vc4->rasterizer->base); util_primconvert_draw_vbo(vc4->primconvert, info); perf_debug("Fallback conversion for %d %s vertices\n", info->count, u_prim_name(info->mode)); return; } /* Before setting up the draw, do any fixup blits necessary. */ vc4_predraw_check_textures(pctx, &vc4->verttex); vc4_predraw_check_textures(pctx, &vc4->fragtex); vc4_hw_2116_workaround(pctx, info->count); struct vc4_job *job = vc4_get_job_for_fbo(vc4); vc4_get_draw_cl_space(job, info->count); if (vc4->prim_mode != info->mode) { vc4->prim_mode = info->mode; vc4->dirty |= VC4_DIRTY_PRIM_MODE; } vc4_start_draw(vc4); if (!vc4_update_compiled_shaders(vc4, info->mode)) { debug_warn_once("shader compile failed, skipping draw call.\n"); return; } vc4_emit_state(pctx); if ((vc4->dirty & (VC4_DIRTY_VTXBUF | VC4_DIRTY_VTXSTATE | VC4_DIRTY_PRIM_MODE | VC4_DIRTY_RASTERIZER | VC4_DIRTY_COMPILED_CS | VC4_DIRTY_COMPILED_VS | VC4_DIRTY_COMPILED_FS | vc4->prog.cs->uniform_dirty_bits | vc4->prog.vs->uniform_dirty_bits | vc4->prog.fs->uniform_dirty_bits)) || vc4->last_index_bias != info->index_bias) { vc4_emit_gl_shader_state(vc4, info, 0); } vc4->dirty = 0; /* Note that the primitive type fields match with OpenGL/gallium * definitions, up to but not including QUADS. */ struct vc4_cl_out *bcl = cl_start(&job->bcl); if (info->indexed) { uint32_t offset = vc4->indexbuf.offset; uint32_t index_size = vc4->indexbuf.index_size; struct pipe_resource *prsc; if (vc4->indexbuf.index_size == 4) { prsc = vc4_get_shadow_index_buffer(pctx, &vc4->indexbuf, info->count, &offset); index_size = 2; } else { if (vc4->indexbuf.user_buffer) { prsc = NULL; u_upload_data(vc4->uploader, 0, info->count * index_size, 4, vc4->indexbuf.user_buffer, &offset, &prsc); } else { prsc = vc4->indexbuf.buffer; } } struct vc4_resource *rsc = vc4_resource(prsc); cl_start_reloc(&job->bcl, &bcl, 1); cl_u8(&bcl, VC4_PACKET_GL_INDEXED_PRIMITIVE); cl_u8(&bcl, info->mode | (index_size == 2 ? VC4_INDEX_BUFFER_U16: VC4_INDEX_BUFFER_U8)); cl_u32(&bcl, info->count); cl_reloc(job, &job->bcl, &bcl, rsc->bo, offset); cl_u32(&bcl, vc4->max_index); job->draw_calls_queued++; if (vc4->indexbuf.index_size == 4 || vc4->indexbuf.user_buffer) pipe_resource_reference(&prsc, NULL); } else { uint32_t count = info->count; uint32_t start = info->start; uint32_t extra_index_bias = 0; while (count) { uint32_t this_count = count; uint32_t step = count; static const uint32_t max_verts = 65535; /* GFXH-515 / SW-5891: The binner emits 16 bit indices * for drawarrays, which means that if start + count > * 64k it would truncate the top bits. Work around * this by emitting a limited number of primitives at * a time and reemitting the shader state pointing * farther down the vertex attribute arrays. * * To do this properly for line loops or trifans, we'd * need to make a new VB containing the first vertex * plus whatever remainder. */ if (extra_index_bias) { cl_end(&job->bcl, bcl); vc4_emit_gl_shader_state(vc4, info, extra_index_bias); bcl = cl_start(&job->bcl); } if (start + count > max_verts) { switch (info->mode) { case PIPE_PRIM_POINTS: this_count = step = max_verts; break; case PIPE_PRIM_LINES: this_count = step = max_verts - (max_verts % 2); break; case PIPE_PRIM_LINE_STRIP: this_count = max_verts; step = max_verts - 1; break; case PIPE_PRIM_LINE_LOOP: this_count = max_verts; step = max_verts - 1; debug_warn_once("unhandled line loop " "looping behavior with " ">65535 verts\n"); break; case PIPE_PRIM_TRIANGLES: this_count = step = max_verts - (max_verts % 3); break; case PIPE_PRIM_TRIANGLE_STRIP: this_count = max_verts; step = max_verts - 2; break; default: debug_warn_once("unhandled primitive " "max vert count, truncating\n"); this_count = step = max_verts; } } cl_u8(&bcl, VC4_PACKET_GL_ARRAY_PRIMITIVE); cl_u8(&bcl, info->mode); cl_u32(&bcl, this_count); cl_u32(&bcl, start); job->draw_calls_queued++; count -= step; extra_index_bias += start + step; start = 0; } } cl_end(&job->bcl, bcl); /* We shouldn't have tripped the HW_2116 bug with the GFXH-515 * workaround. */ assert(job->draw_calls_queued <= VC4_HW_2116_COUNT); if (vc4->zsa && vc4->framebuffer.zsbuf) { struct vc4_resource *rsc = vc4_resource(vc4->framebuffer.zsbuf->texture); if (vc4->zsa->base.depth.enabled) { job->resolve |= PIPE_CLEAR_DEPTH; rsc->initialized_buffers = PIPE_CLEAR_DEPTH; } if (vc4->zsa->base.stencil[0].enabled) { job->resolve |= PIPE_CLEAR_STENCIL; rsc->initialized_buffers |= PIPE_CLEAR_STENCIL; } } job->resolve |= PIPE_CLEAR_COLOR0; if (vc4_debug & VC4_DEBUG_ALWAYS_FLUSH) vc4_flush(pctx); }
enum pipe_error svga_hwtnl_draw_arrays(struct svga_hwtnl *hwtnl, enum pipe_prim_type prim, unsigned start, unsigned count, unsigned start_instance, unsigned instance_count) { enum pipe_prim_type gen_prim; unsigned gen_size, gen_nr; enum indices_mode gen_type; u_generate_func gen_func; enum pipe_error ret = PIPE_OK; unsigned api_pv = hwtnl->api_pv; struct svga_context *svga = hwtnl->svga; if (svga->curr.rast->templ.fill_front != svga->curr.rast->templ.fill_back) { assert(hwtnl->api_fillmode == PIPE_POLYGON_MODE_FILL); } if (svga->curr.rast->templ.flatshade && svga->state.hw_draw.fs->constant_color_output) { /* The fragment color is a constant, not per-vertex so the whole * primitive will be the same color (except for possible blending). * We can ignore the current provoking vertex state and use whatever * the hardware wants. */ api_pv = hwtnl->hw_pv; if (hwtnl->api_fillmode == PIPE_POLYGON_MODE_FILL) { /* Do some simple primitive conversions to avoid index buffer * generation below. Note that polygons and quads are not directly * supported by the svga device. Also note, we can only do this * for flat/constant-colored rendering because of provoking vertex. */ if (prim == PIPE_PRIM_POLYGON) { prim = PIPE_PRIM_TRIANGLE_FAN; } else if (prim == PIPE_PRIM_QUADS && count == 4) { prim = PIPE_PRIM_TRIANGLE_FAN; } } } if (svga_need_unfilled_fallback(hwtnl, prim)) { /* Convert unfilled polygons into points, lines, triangles */ gen_type = u_unfilled_generator(prim, start, count, hwtnl->api_fillmode, &gen_prim, &gen_size, &gen_nr, &gen_func); } else { /* Convert PIPE_PRIM_LINE_LOOP to PIPE_PRIM_LINESTRIP, * convert PIPE_PRIM_POLYGON to PIPE_PRIM_TRIANGLE_FAN, * etc, if needed (as determined by svga_hw_prims mask). */ gen_type = u_index_generator(svga_hw_prims, prim, start, count, api_pv, hwtnl->hw_pv, &gen_prim, &gen_size, &gen_nr, &gen_func); } if (gen_type == U_GENERATE_LINEAR) { return simple_draw_arrays(hwtnl, gen_prim, start, count, start_instance, instance_count); } else { struct pipe_resource *gen_buf = NULL; /* Need to draw as indexed primitive. * Potentially need to run the gen func to build an index buffer. */ ret = retrieve_or_generate_indices(hwtnl, prim, gen_type, gen_nr, gen_size, gen_func, &gen_buf); if (ret != PIPE_OK) goto done; pipe_debug_message(&svga->debug.callback, PERF_INFO, "generating temporary index buffer for drawing %s", u_prim_name(prim)); ret = svga_hwtnl_simple_draw_range_elements(hwtnl, gen_buf, gen_size, start, 0, count - 1, gen_prim, 0, gen_nr, start_instance, instance_count); if (ret != PIPE_OK) goto done; done: if (gen_buf) pipe_resource_reference(&gen_buf, NULL); return ret; } }