boolean r300_draw_arrays(struct pipe_context* pipe, unsigned mode, unsigned start, unsigned count) { struct r300_context* r300 = r300_context(pipe); if (!u_trim_pipe_prim(mode, &count)) { return FALSE; } if (count > 65535) { return FALSE; } r300_update_derived_state(r300); if (!r300_setup_vertex_buffers(r300)) { return FALSE; } setup_vertex_attributes(r300); r300_emit_dirty_state(r300); r300_emit_aos(r300, start); r300_emit_draw_arrays(r300, mode, count); return TRUE; }
/* SW TCL elements, using Draw. */ static void r300_swtcl_draw_vbo(struct pipe_context* pipe, const struct pipe_draw_info *info) { struct r300_context* r300 = r300_context(pipe); struct pipe_transfer *vb_transfer[PIPE_MAX_ATTRIBS]; struct pipe_transfer *ib_transfer = NULL; int i; void *indices = NULL; boolean indexed = info->indexed && r300->vbuf_mgr->index_buffer.buffer; if (r300->skip_rendering) { return; } r300_update_derived_state(r300); r300_reserve_cs_dwords(r300, PREP_EMIT_STATES | PREP_EMIT_VARRAYS_SWTCL | (indexed ? PREP_INDEXED : 0), indexed ? 256 : 6); for (i = 0; i < r300->vbuf_mgr->nr_vertex_buffers; i++) { if (r300->vbuf_mgr->vertex_buffer[i].buffer) { void *buf = pipe_buffer_map(pipe, r300->vbuf_mgr->vertex_buffer[i].buffer, PIPE_TRANSFER_READ | PIPE_TRANSFER_UNSYNCHRONIZED, &vb_transfer[i]); draw_set_mapped_vertex_buffer(r300->draw, i, buf); } } if (indexed) { indices = pipe_buffer_map(pipe, r300->vbuf_mgr->index_buffer.buffer, PIPE_TRANSFER_READ | PIPE_TRANSFER_UNSYNCHRONIZED, &ib_transfer); } draw_set_mapped_index_buffer(r300->draw, indices); r300->draw_vbo_locked = TRUE; r300->draw_first_emitted = FALSE; draw_vbo(r300->draw, info); draw_flush(r300->draw); r300->draw_vbo_locked = FALSE; for (i = 0; i < r300->vbuf_mgr->nr_vertex_buffers; i++) { if (r300->vbuf_mgr->vertex_buffer[i].buffer) { pipe_buffer_unmap(pipe, vb_transfer[i]); draw_set_mapped_vertex_buffer(r300->draw, i, NULL); } } if (indexed) { pipe_buffer_unmap(pipe, ib_transfer); draw_set_mapped_index_buffer(r300->draw, NULL); } }
static const struct vertex_info* r300_render_get_vertex_info(struct vbuf_render* render) { struct r300_render* r300render = r300_render(render); struct r300_context* r300 = r300render->r300; r300_update_derived_state(r300); return &r300->vertex_info->vinfo; }
static void r300_draw_vbo(struct pipe_context* pipe, const struct pipe_draw_info *dinfo) { struct r300_context* r300 = r300_context(pipe); struct pipe_draw_info info = *dinfo; info.indexed = info.indexed; if (r300->skip_rendering || !u_trim_pipe_prim(info.mode, &info.count)) { return; } r300_update_derived_state(r300); /* Draw. */ if (info.indexed) { unsigned max_count = r300_max_vertex_count(r300); if (!max_count) { fprintf(stderr, "r300: Skipping a draw command. There is a buffer " " which is too small to be used for rendering.\n"); return; } if (max_count == ~0) { /* There are no per-vertex vertex elements. Use the hardware maximum. */ max_count = 0xffffff; } info.max_index = max_count - 1; info.start += r300->index_buffer.offset / r300->index_buffer.index_size; if (info.instance_count <= 1) { if (info.count <= 8 && r300->index_buffer.user_buffer) { r300_draw_elements_immediate(r300, &info); } else { r300_draw_elements(r300, &info, -1); } } else { r300_draw_elements_instanced(r300, &info); } } else { if (info.instance_count <= 1) { if (immd_is_good_idea(r300, info.count)) { r300_draw_arrays_immediate(r300, &info); } else { r300_draw_arrays(r300, &info, -1); } } else { r300_draw_arrays_instanced(r300, &info); } } }
/* SW TCL elements, using Draw. */ static void r300_swtcl_draw_vbo(struct pipe_context* pipe, const struct pipe_draw_info *info) { struct r300_context* r300 = r300_context(pipe); if (r300->skip_rendering) { return; } r300_update_derived_state(r300); draw_vbo(r300->draw, info); draw_flush(r300->draw); }
/* This is the fast-path drawing & emission for HW TCL. */ boolean r300_draw_range_elements(struct pipe_context* pipe, struct pipe_buffer* indexBuffer, unsigned indexSize, unsigned minIndex, unsigned maxIndex, unsigned mode, unsigned start, unsigned count) { struct r300_context* r300 = r300_context(pipe); if (!u_trim_pipe_prim(mode, &count)) { return FALSE; } if (count > 65535) { return FALSE; } r300_update_derived_state(r300); if (!r300_setup_vertex_buffers(r300)) { return FALSE; } setup_vertex_attributes(r300); setup_index_buffer(r300, indexBuffer, indexSize); r300_emit_dirty_state(r300); r300_emit_aos(r300, 0); r300_emit_draw_elements(r300, indexBuffer, indexSize, minIndex, maxIndex, mode, start, count); return TRUE; }
/* This functions is used to draw a rectangle for the blitter module. * * If we rendered a quad, the pixels on the main diagonal * would be computed and stored twice, which makes the clear/copy codepaths * somewhat inefficient. Instead we use a rectangular point sprite. */ void r300_blitter_draw_rectangle(struct blitter_context *blitter, int x1, int y1, int x2, int y2, float depth, enum blitter_attrib_type type, const union pipe_color_union *attrib) { struct r300_context *r300 = r300_context(util_blitter_get_pipe(blitter)); unsigned last_sprite_coord_enable = r300->sprite_coord_enable; unsigned width = x2 - x1; unsigned height = y2 - y1; unsigned vertex_size = type == UTIL_BLITTER_ATTRIB_COLOR || !r300->draw ? 8 : 4; unsigned dwords = 13 + vertex_size + (type == UTIL_BLITTER_ATTRIB_TEXCOORD ? 7 : 0); static const union pipe_color_union zeros; CS_LOCALS(r300); /* XXX workaround for a lockup in MSAA resolve on SWTCL chipsets, this * function most probably doesn't handle type=NONE correctly */ if (!r300->screen->caps.has_tcl && type == UTIL_BLITTER_ATTRIB_NONE) { util_blitter_draw_rectangle(blitter, x1, y1, x2, y2, depth, type, attrib); return; } if (r300->skip_rendering) return; if (type == UTIL_BLITTER_ATTRIB_TEXCOORD) r300->sprite_coord_enable = 1; r300_update_derived_state(r300); /* Mark some states we don't care about as non-dirty. */ r300->viewport_state.dirty = FALSE; if (!r300_prepare_for_rendering(r300, PREP_EMIT_STATES, NULL, dwords, 0, 0, -1)) goto done; DBG(r300, DBG_DRAW, "r300: draw_rectangle\n"); BEGIN_CS(dwords); /* Set up GA. */ OUT_CS_REG(R300_GA_POINT_SIZE, (height * 6) | ((width * 6) << 16)); if (type == UTIL_BLITTER_ATTRIB_TEXCOORD) { /* Set up the GA to generate texcoords. */ OUT_CS_REG(R300_GB_ENABLE, R300_GB_POINT_STUFF_ENABLE | (R300_GB_TEX_STR << R300_GB_TEX0_SOURCE_SHIFT)); OUT_CS_REG_SEQ(R300_GA_POINT_S0, 4); OUT_CS_32F(attrib->f[0]); OUT_CS_32F(attrib->f[3]); OUT_CS_32F(attrib->f[2]); OUT_CS_32F(attrib->f[1]); } /* Set up VAP controls. */ OUT_CS_REG(R300_VAP_CLIP_CNTL, R300_CLIP_DISABLE); OUT_CS_REG(R300_VAP_VTE_CNTL, R300_VTX_XY_FMT | R300_VTX_Z_FMT); OUT_CS_REG(R300_VAP_VTX_SIZE, vertex_size); OUT_CS_REG_SEQ(R300_VAP_VF_MAX_VTX_INDX, 2); OUT_CS(1); OUT_CS(0); /* Draw. */ OUT_CS_PKT3(R300_PACKET3_3D_DRAW_IMMD_2, vertex_size); OUT_CS(R300_VAP_VF_CNTL__PRIM_WALK_VERTEX_EMBEDDED | (1 << 16) | R300_VAP_VF_CNTL__PRIM_POINTS); OUT_CS_32F(x1 + width * 0.5f); OUT_CS_32F(y1 + height * 0.5f); OUT_CS_32F(depth); OUT_CS_32F(1); if (vertex_size == 8) { if (!attrib) attrib = &zeros; OUT_CS_TABLE(attrib->f, 4); } END_CS; done: /* Restore the state. */ r300_mark_atom_dirty(r300, &r300->rs_state); r300_mark_atom_dirty(r300, &r300->viewport_state); r300->sprite_coord_enable = last_sprite_coord_enable; }
static void r300_draw_vbo(struct pipe_context* pipe, const struct pipe_draw_info *dinfo) { struct r300_context* r300 = r300_context(pipe); struct pipe_draw_info info = *dinfo; info.indexed = info.indexed && r300->vbuf_mgr->index_buffer.buffer; if (r300->skip_rendering || !u_trim_pipe_prim(info.mode, &info.count)) { return; } r300_update_derived_state(r300); /* Start the vbuf manager and update buffers if needed. */ if (u_vbuf_draw_begin(r300->vbuf_mgr, &info) & U_VBUF_BUFFERS_UPDATED) { r300->vertex_arrays_dirty = TRUE; } /* Draw. */ if (info.indexed) { unsigned max_count = u_vbuf_draw_max_vertex_count(r300->vbuf_mgr); if (!max_count) { fprintf(stderr, "r300: Skipping a draw command. There is a buffer " " which is too small to be used for rendering.\n"); goto done; } if (max_count == ~0) { /* There are no per-vertex vertex elements. Use the hardware maximum. */ max_count = 0xffffff; } info.max_index = max_count - 1; info.start += r300->vbuf_mgr->index_buffer.offset / r300->vbuf_mgr->index_buffer.index_size; if (info.instance_count <= 1) { if (info.count <= 8 && r300_resource(r300->vbuf_mgr->index_buffer.buffer)->b.user_ptr) { r300_draw_elements_immediate(r300, &info); } else { r300_draw_elements(r300, &info, -1); } } else { r300_draw_elements_instanced(r300, &info); } } else { if (info.instance_count <= 1) { if (immd_is_good_idea(r300, info.count)) { r300_draw_arrays_immediate(r300, &info); } else { r300_draw_arrays(r300, &info, -1); } } else { r300_draw_arrays_instanced(r300, &info); } } done: u_vbuf_draw_end(r300->vbuf_mgr); }
/* SW TCL elements, using Draw. */ static void r300_swtcl_draw_vbo(struct pipe_context* pipe, const struct pipe_draw_info *info) { struct r300_context* r300 = r300_context(pipe); struct pipe_transfer *vb_transfer[PIPE_MAX_ATTRIBS]; struct pipe_transfer *ib_transfer = NULL; unsigned count = info->count; int i; void *indices = NULL; boolean indexed = info->indexed && r300->index_buffer.buffer; if (r300->skip_rendering) { return; } if (!u_trim_pipe_prim(info->mode, &count)) { return; } r300_update_derived_state(r300); r300_reserve_cs_dwords(r300, PREP_FIRST_DRAW | PREP_EMIT_AOS_SWTCL | (indexed ? PREP_INDEXED : 0), indexed ? 256 : 6); for (i = 0; i < r300->vertex_buffer_count; i++) { if (r300->vertex_buffer[i].buffer) { void *buf = pipe_buffer_map(pipe, r300->vertex_buffer[i].buffer, PIPE_TRANSFER_READ, &vb_transfer[i]); draw_set_mapped_vertex_buffer(r300->draw, i, buf); } } if (indexed) { indices = pipe_buffer_map(pipe, r300->index_buffer.buffer, PIPE_TRANSFER_READ, &ib_transfer); } draw_set_mapped_index_buffer(r300->draw, indices); r300->draw_vbo_locked = TRUE; r300->draw_first_emitted = FALSE; draw_vbo(r300->draw, info); draw_flush(r300->draw); r300->draw_vbo_locked = FALSE; for (i = 0; i < r300->vertex_buffer_count; i++) { if (r300->vertex_buffer[i].buffer) { pipe_buffer_unmap(pipe, r300->vertex_buffer[i].buffer, vb_transfer[i]); draw_set_mapped_vertex_buffer(r300->draw, i, NULL); } } if (indexed) { pipe_buffer_unmap(pipe, r300->index_buffer.buffer, ib_transfer); draw_set_mapped_index_buffer(r300->draw, NULL); } }
static void r300_draw_arrays(struct pipe_context* pipe, unsigned mode, unsigned start, unsigned count) { struct r300_context* r300 = r300_context(pipe); boolean alt_num_verts = r300->screen->caps.is_r500 && count > 65536 && r300->rws->get_value(r300->rws, R300_VID_DRM_2_3_0); unsigned short_count; boolean translate = FALSE; if (r300->skip_rendering) { return; } if (!u_trim_pipe_prim(mode, &count)) { return; } /* Set up fallback for incompatible vertex layout if needed. */ if (r300->incompatible_vb_layout || r300->velems->incompatible_layout) { r300_begin_vertex_translate(r300); translate = TRUE; } r300_update_derived_state(r300); if (immd_is_good_idea(r300, count)) { r300_emit_draw_arrays_immediate(r300, mode, start, count); } else { /* 9 spare dwords for emit_draw_arrays. Give up if the function fails. */ if (!r300_prepare_for_rendering(r300, PREP_FIRST_DRAW | PREP_VALIDATE_VBOS | PREP_EMIT_AOS, NULL, 9, start, 0)) goto done; if (alt_num_verts || count <= 65535) { r300_emit_draw_arrays(r300, mode, count); } else { do { short_count = MIN2(count, 65535); r300_emit_draw_arrays(r300, mode, short_count); start += short_count; count -= short_count; /* 9 spare dwords for emit_draw_arrays. Give up if the function fails. */ if (count) { if (!r300_prepare_for_rendering(r300, PREP_VALIDATE_VBOS | PREP_EMIT_AOS, NULL, 9, start, 0)) goto done; } } while (count); } } done: if (translate) { r300_end_vertex_translate(r300); } }
/* This is the fast-path drawing & emission for HW TCL. */ static void r300_draw_range_elements(struct pipe_context* pipe, struct pipe_resource* indexBuffer, unsigned indexSize, int indexBias, unsigned minIndex, unsigned maxIndex, unsigned mode, unsigned start, unsigned count) { struct r300_context* r300 = r300_context(pipe); struct pipe_resource* orgIndexBuffer = indexBuffer; boolean alt_num_verts = r300->screen->caps.is_r500 && count > 65536 && r300->rws->get_value(r300->rws, R300_VID_DRM_2_3_0); unsigned short_count; int buffer_offset = 0, index_offset = 0; /* for index bias emulation */ boolean translate = FALSE; unsigned new_offset; if (r300->skip_rendering) { return; } if (!u_trim_pipe_prim(mode, &count)) { return; } /* Index buffer range checking. */ if ((start + count) * indexSize > indexBuffer->width0) { fprintf(stderr, "r300: Invalid index buffer range. Skipping rendering.\n"); return; } /* Set up fallback for incompatible vertex layout if needed. */ if (r300->incompatible_vb_layout || r300->velems->incompatible_layout) { r300_begin_vertex_translate(r300); translate = TRUE; } if (indexBias && !r500_index_bias_supported(r300)) { r300_split_index_bias(r300, indexBias, &buffer_offset, &index_offset); } r300_translate_index_buffer(r300, &indexBuffer, &indexSize, index_offset, &start, count); r300_update_derived_state(r300); r300_upload_index_buffer(r300, &indexBuffer, indexSize, start, count, &new_offset); start = new_offset; /* 15 dwords for emit_draw_elements. Give up if the function fails. */ if (!r300_prepare_for_rendering(r300, PREP_FIRST_DRAW | PREP_VALIDATE_VBOS | PREP_EMIT_AOS | PREP_INDEXED, indexBuffer, 15, buffer_offset, indexBias)) goto done; if (alt_num_verts || count <= 65535) { r300_emit_draw_elements(r300, indexBuffer, indexSize, minIndex, maxIndex, mode, start, count); } else { do { short_count = MIN2(count, 65534); r300_emit_draw_elements(r300, indexBuffer, indexSize, minIndex, maxIndex, mode, start, short_count); start += short_count; count -= short_count; /* 15 dwords for emit_draw_elements */ if (count) { if (!r300_prepare_for_rendering(r300, PREP_VALIDATE_VBOS | PREP_EMIT_AOS | PREP_INDEXED, indexBuffer, 15, buffer_offset, indexBias)) goto done; } } while (count); } done: if (indexBuffer != orgIndexBuffer) { pipe_resource_reference( &indexBuffer, NULL ); } if (translate) { r300_end_vertex_translate(r300); } }
/* This functions is used to draw a rectangle for the blitter module. * * If we rendered a quad, the pixels on the main diagonal * would be computed and stored twice, which makes the clear/copy codepaths * somewhat inefficient. Instead we use a rectangular point sprite. */ static void r300_blitter_draw_rectangle(struct blitter_context *blitter, unsigned x1, unsigned y1, unsigned x2, unsigned y2, float depth, enum blitter_attrib_type type, const float attrib[4]) { struct r300_context *r300 = r300_context(util_blitter_get_pipe(blitter)); unsigned last_sprite_coord_enable = r300->sprite_coord_enable; unsigned width = x2 - x1; unsigned height = y2 - y1; unsigned vertex_size = type == UTIL_BLITTER_ATTRIB_COLOR || !r300->draw ? 8 : 4; unsigned dwords = 13 + vertex_size + (type == UTIL_BLITTER_ATTRIB_TEXCOORD ? 7 : 0); const float zeros[4] = {0, 0, 0, 0}; CS_LOCALS(r300); if (type == UTIL_BLITTER_ATTRIB_TEXCOORD) r300->sprite_coord_enable = 1; r300_update_derived_state(r300); /* Mark some states we don't care about as non-dirty. */ r300->clip_state.dirty = FALSE; r300->viewport_state.dirty = FALSE; if (!r300_prepare_for_rendering(r300, PREP_FIRST_DRAW, NULL, dwords, 0, 0)) goto done; DBG(r300, DBG_DRAW, "r300: draw_rectangle\n"); BEGIN_CS(dwords); /* Set up GA. */ OUT_CS_REG(R300_GA_POINT_SIZE, (height * 6) | ((width * 6) << 16)); if (type == UTIL_BLITTER_ATTRIB_TEXCOORD) { /* Set up the GA to generate texcoords. */ OUT_CS_REG(R300_GB_ENABLE, R300_GB_POINT_STUFF_ENABLE | (R300_GB_TEX_STR << R300_GB_TEX0_SOURCE_SHIFT)); OUT_CS_REG_SEQ(R300_GA_POINT_S0, 4); OUT_CS_32F(attrib[0]); OUT_CS_32F(attrib[3]); OUT_CS_32F(attrib[2]); OUT_CS_32F(attrib[1]); } /* Set up VAP controls. */ OUT_CS_REG(R300_VAP_CLIP_CNTL, R300_CLIP_DISABLE); OUT_CS_REG(R300_VAP_VTE_CNTL, R300_VTX_XY_FMT | R300_VTX_Z_FMT); OUT_CS_REG(R300_VAP_VTX_SIZE, vertex_size); OUT_CS_REG_SEQ(R300_VAP_VF_MAX_VTX_INDX, 2); OUT_CS(1); OUT_CS(0); /* Draw. */ OUT_CS_PKT3(R300_PACKET3_3D_DRAW_IMMD_2, vertex_size); OUT_CS(R300_VAP_VF_CNTL__PRIM_WALK_VERTEX_EMBEDDED | (1 << 16) | R300_VAP_VF_CNTL__PRIM_POINTS); OUT_CS_32F(x1 + width * 0.5f); OUT_CS_32F(y1 + height * 0.5f); OUT_CS_32F(depth); OUT_CS_32F(1); if (vertex_size == 8) { if (!attrib) attrib = zeros; OUT_CS_TABLE(attrib, 4); } END_CS; done: /* Restore the state. */ r300->clip_state.dirty = TRUE; r300->rs_state.dirty = TRUE; r300->viewport_state.dirty = TRUE; r300->sprite_coord_enable = last_sprite_coord_enable; }