14a49301eSmrg/*
24a49301eSmrg * Copyright 2009 Corbin Simpson <MostAwesomeDude@gmail.com>
33464ebd5Sriastradh * Copyright 2010 Marek Olšák <maraeo@gmail.com>
44a49301eSmrg *
54a49301eSmrg * Permission is hereby granted, free of charge, to any person obtaining a
64a49301eSmrg * copy of this software and associated documentation files (the "Software"),
74a49301eSmrg * to deal in the Software without restriction, including without limitation
84a49301eSmrg * on the rights to use, copy, modify, merge, publish, distribute, sub
94a49301eSmrg * license, and/or sell copies of the Software, and to permit persons to whom
104a49301eSmrg * the Software is furnished to do so, subject to the following conditions:
114a49301eSmrg *
124a49301eSmrg * The above copyright notice and this permission notice (including the next
134a49301eSmrg * paragraph) shall be included in all copies or substantial portions of the
144a49301eSmrg * Software.
154a49301eSmrg *
164a49301eSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
174a49301eSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
184a49301eSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
194a49301eSmrg * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
204a49301eSmrg * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
214a49301eSmrg * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
224a49301eSmrg * USE OR OTHER DEALINGS IN THE SOFTWARE. */
234a49301eSmrg
244a49301eSmrg/* r300_render: Vertex and index buffer primitive emission. Contains both
254a49301eSmrg * HW TCL fastpath rendering, and SW TCL Draw-assisted rendering. */
264a49301eSmrg
274a49301eSmrg#include "draw/draw_context.h"
284a49301eSmrg#include "draw/draw_vbuf.h"
294a49301eSmrg
30cdc920a0Smrg#include "util/u_inlines.h"
314a49301eSmrg
327ec681f3Smrg#include "util/format/u_format.h"
337ec681f3Smrg#include "util/u_draw.h"
344a49301eSmrg#include "util/u_memory.h"
353464ebd5Sriastradh#include "util/u_upload_mgr.h"
364a49301eSmrg#include "util/u_prim.h"
374a49301eSmrg
384a49301eSmrg#include "r300_cs.h"
394a49301eSmrg#include "r300_context.h"
403464ebd5Sriastradh#include "r300_screen_buffer.h"
414a49301eSmrg#include "r300_emit.h"
424a49301eSmrg#include "r300_reg.h"
433464ebd5Sriastradh
443464ebd5Sriastradh#include <limits.h>
453464ebd5Sriastradh
463464ebd5Sriastradh#define IMMD_DWORDS 32
473464ebd5Sriastradh
483464ebd5Sriastradhstatic uint32_t r300_translate_primitive(unsigned prim)
493464ebd5Sriastradh{
503464ebd5Sriastradh    static const int prim_conv[] = {
513464ebd5Sriastradh        R300_VAP_VF_CNTL__PRIM_POINTS,
523464ebd5Sriastradh        R300_VAP_VF_CNTL__PRIM_LINES,
533464ebd5Sriastradh        R300_VAP_VF_CNTL__PRIM_LINE_LOOP,
543464ebd5Sriastradh        R300_VAP_VF_CNTL__PRIM_LINE_STRIP,
553464ebd5Sriastradh        R300_VAP_VF_CNTL__PRIM_TRIANGLES,
563464ebd5Sriastradh        R300_VAP_VF_CNTL__PRIM_TRIANGLE_STRIP,
573464ebd5Sriastradh        R300_VAP_VF_CNTL__PRIM_TRIANGLE_FAN,
583464ebd5Sriastradh        R300_VAP_VF_CNTL__PRIM_QUADS,
593464ebd5Sriastradh        R300_VAP_VF_CNTL__PRIM_QUAD_STRIP,
603464ebd5Sriastradh        R300_VAP_VF_CNTL__PRIM_POLYGON,
613464ebd5Sriastradh        -1,
623464ebd5Sriastradh        -1,
633464ebd5Sriastradh        -1,
643464ebd5Sriastradh        -1
653464ebd5Sriastradh    };
663464ebd5Sriastradh    unsigned hwprim = prim_conv[prim];
673464ebd5Sriastradh
683464ebd5Sriastradh    assert(hwprim != -1);
693464ebd5Sriastradh    return hwprim;
704a49301eSmrg}
714a49301eSmrg
72cdc920a0Smrgstatic uint32_t r300_provoking_vertex_fixes(struct r300_context *r300,
73cdc920a0Smrg                                            unsigned mode)
74cdc920a0Smrg{
75cdc920a0Smrg    struct r300_rs_state* rs = (struct r300_rs_state*)r300->rs_state.state;
76cdc920a0Smrg    uint32_t color_control = rs->color_control;
77cdc920a0Smrg
78cdc920a0Smrg    /* By default (see r300_state.c:r300_create_rs_state) color_control is
79cdc920a0Smrg     * initialized to provoking the first vertex.
80cdc920a0Smrg     *
81cdc920a0Smrg     * Triangle fans must be reduced to the second vertex, not the first, in
82cdc920a0Smrg     * Gallium flatshade-first mode, as per the GL spec.
83cdc920a0Smrg     * (http://www.opengl.org/registry/specs/ARB/provoking_vertex.txt)
84cdc920a0Smrg     *
85cdc920a0Smrg     * Quads never provoke correctly in flatshade-first mode. The first
86cdc920a0Smrg     * vertex is never considered as provoking, so only the second, third,
87cdc920a0Smrg     * and fourth vertices can be selected, and both "third" and "last" modes
88cdc920a0Smrg     * select the fourth vertex. This is probably due to D3D lacking quads.
89cdc920a0Smrg     *
90cdc920a0Smrg     * Similarly, polygons reduce to the first, not the last, vertex, when in
91cdc920a0Smrg     * "last" mode, and all other modes start from the second vertex.
92cdc920a0Smrg     *
93cdc920a0Smrg     * ~ C.
94cdc920a0Smrg     */
95cdc920a0Smrg
96cdc920a0Smrg    if (rs->rs.flatshade_first) {
97cdc920a0Smrg        switch (mode) {
98cdc920a0Smrg            case PIPE_PRIM_TRIANGLE_FAN:
99cdc920a0Smrg                color_control |= R300_GA_COLOR_CONTROL_PROVOKING_VERTEX_SECOND;
100cdc920a0Smrg                break;
101cdc920a0Smrg            case PIPE_PRIM_QUADS:
102cdc920a0Smrg            case PIPE_PRIM_QUAD_STRIP:
103cdc920a0Smrg            case PIPE_PRIM_POLYGON:
104cdc920a0Smrg                color_control |= R300_GA_COLOR_CONTROL_PROVOKING_VERTEX_LAST;
105cdc920a0Smrg                break;
106cdc920a0Smrg            default:
107cdc920a0Smrg                color_control |= R300_GA_COLOR_CONTROL_PROVOKING_VERTEX_FIRST;
108cdc920a0Smrg                break;
109cdc920a0Smrg        }
110cdc920a0Smrg    } else {
111cdc920a0Smrg        color_control |= R300_GA_COLOR_CONTROL_PROVOKING_VERTEX_LAST;
112cdc920a0Smrg    }
113cdc920a0Smrg
114cdc920a0Smrg    return color_control;
115cdc920a0Smrg}
116cdc920a0Smrg
1173464ebd5Sriastradhvoid r500_emit_index_bias(struct r300_context *r300, int index_bias)
1183464ebd5Sriastradh{
1193464ebd5Sriastradh    CS_LOCALS(r300);
1203464ebd5Sriastradh
1213464ebd5Sriastradh    BEGIN_CS(2);
1223464ebd5Sriastradh    OUT_CS_REG(R500_VAP_INDEX_OFFSET,
1233464ebd5Sriastradh               (index_bias & 0xFFFFFF) | (index_bias < 0 ? 1<<24 : 0));
1243464ebd5Sriastradh    END_CS;
1253464ebd5Sriastradh}
1263464ebd5Sriastradh
1273464ebd5Sriastradhstatic void r300_emit_draw_init(struct r300_context *r300, unsigned mode,
128af69d88dSmrg                                unsigned max_index)
1293464ebd5Sriastradh{
1303464ebd5Sriastradh    CS_LOCALS(r300);
1313464ebd5Sriastradh
132af69d88dSmrg    assert(max_index < (1 << 24));
133af69d88dSmrg
1343464ebd5Sriastradh    BEGIN_CS(5);
1353464ebd5Sriastradh    OUT_CS_REG(R300_GA_COLOR_CONTROL,
1363464ebd5Sriastradh            r300_provoking_vertex_fixes(r300, mode));
1373464ebd5Sriastradh    OUT_CS_REG_SEQ(R300_VAP_VF_MAX_VTX_INDX, 2);
1383464ebd5Sriastradh    OUT_CS(max_index);
139af69d88dSmrg    OUT_CS(0);
1403464ebd5Sriastradh    END_CS;
1413464ebd5Sriastradh}
1423464ebd5Sriastradh
1433464ebd5Sriastradh/* This function splits the index bias value into two parts:
1443464ebd5Sriastradh * - buffer_offset: the value that can be safely added to buffer offsets
1453464ebd5Sriastradh *   in r300_emit_vertex_arrays (it must yield a positive offset when added to
1463464ebd5Sriastradh *   a vertex buffer offset)
1473464ebd5Sriastradh * - index_offset: the value that must be manually subtracted from indices
1483464ebd5Sriastradh *   in an index buffer to achieve negative offsets. */
1493464ebd5Sriastradhstatic void r300_split_index_bias(struct r300_context *r300, int index_bias,
1503464ebd5Sriastradh                                  int *buffer_offset, int *index_offset)
1513464ebd5Sriastradh{
152af69d88dSmrg    struct pipe_vertex_buffer *vb, *vbufs = r300->vertex_buffer;
1533464ebd5Sriastradh    struct pipe_vertex_element *velem = r300->velems->velem;
1543464ebd5Sriastradh    unsigned i, size;
1553464ebd5Sriastradh    int max_neg_bias;
1563464ebd5Sriastradh
1573464ebd5Sriastradh    if (index_bias < 0) {
1583464ebd5Sriastradh        /* See how large index bias we may subtract. We must be careful
1593464ebd5Sriastradh         * here because negative buffer offsets are not allowed
1603464ebd5Sriastradh         * by the DRM API. */
1613464ebd5Sriastradh        max_neg_bias = INT_MAX;
1623464ebd5Sriastradh        for (i = 0; i < r300->velems->count; i++) {
1633464ebd5Sriastradh            vb = &vbufs[velem[i].vertex_buffer_index];
1643464ebd5Sriastradh            size = (vb->buffer_offset + velem[i].src_offset) / vb->stride;
1653464ebd5Sriastradh            max_neg_bias = MIN2(max_neg_bias, size);
1663464ebd5Sriastradh        }
1673464ebd5Sriastradh
1683464ebd5Sriastradh        /* Now set the minimum allowed value. */
1693464ebd5Sriastradh        *buffer_offset = MAX2(-max_neg_bias, index_bias);
1703464ebd5Sriastradh    } else {
1713464ebd5Sriastradh        /* A positive index bias is OK. */
1723464ebd5Sriastradh        *buffer_offset = index_bias;
1733464ebd5Sriastradh    }
1743464ebd5Sriastradh
1753464ebd5Sriastradh    *index_offset = index_bias - *buffer_offset;
1763464ebd5Sriastradh}
1773464ebd5Sriastradh
1783464ebd5Sriastradhenum r300_prepare_flags {
1793464ebd5Sriastradh    PREP_EMIT_STATES    = (1 << 0), /* call emit_dirty_state and friends? */
1803464ebd5Sriastradh    PREP_VALIDATE_VBOS  = (1 << 1), /* validate VBOs? */
1813464ebd5Sriastradh    PREP_EMIT_VARRAYS       = (1 << 2), /* call emit_vertex_arrays? */
1823464ebd5Sriastradh    PREP_EMIT_VARRAYS_SWTCL = (1 << 3), /* call emit_vertex_arrays_swtcl? */
1833464ebd5Sriastradh    PREP_INDEXED        = (1 << 4)  /* is this draw_elements? */
1843464ebd5Sriastradh};
1853464ebd5Sriastradh
1863464ebd5Sriastradh/**
1873464ebd5Sriastradh * Check if the requested number of dwords is available in the CS and
1883464ebd5Sriastradh * if not, flush.
1893464ebd5Sriastradh * \param r300          The context.
1903464ebd5Sriastradh * \param flags         See r300_prepare_flags.
1913464ebd5Sriastradh * \param cs_dwords     The number of dwords to reserve in CS.
1923464ebd5Sriastradh * \return TRUE if the CS was flushed
1933464ebd5Sriastradh */
1943464ebd5Sriastradhstatic boolean r300_reserve_cs_dwords(struct r300_context *r300,
1953464ebd5Sriastradh                                      enum r300_prepare_flags flags,
1963464ebd5Sriastradh                                      unsigned cs_dwords)
1973464ebd5Sriastradh{
1983464ebd5Sriastradh    boolean flushed        = FALSE;
1993464ebd5Sriastradh    boolean emit_states    = flags & PREP_EMIT_STATES;
2003464ebd5Sriastradh    boolean emit_vertex_arrays       = flags & PREP_EMIT_VARRAYS;
2013464ebd5Sriastradh    boolean emit_vertex_arrays_swtcl = flags & PREP_EMIT_VARRAYS_SWTCL;
2023464ebd5Sriastradh
2033464ebd5Sriastradh    /* Add dirty state, index offset, and AOS. */
2043464ebd5Sriastradh    if (emit_states)
2053464ebd5Sriastradh        cs_dwords += r300_get_num_dirty_dwords(r300);
2063464ebd5Sriastradh
2073464ebd5Sriastradh    if (r300->screen->caps.is_r500)
2083464ebd5Sriastradh        cs_dwords += 2; /* emit_index_offset */
2093464ebd5Sriastradh
2103464ebd5Sriastradh    if (emit_vertex_arrays)
2113464ebd5Sriastradh        cs_dwords += 55; /* emit_vertex_arrays */
2123464ebd5Sriastradh
2133464ebd5Sriastradh    if (emit_vertex_arrays_swtcl)
2143464ebd5Sriastradh        cs_dwords += 7; /* emit_vertex_arrays_swtcl */
2153464ebd5Sriastradh
2163464ebd5Sriastradh    cs_dwords += r300_get_num_cs_end_dwords(r300);
2173464ebd5Sriastradh
2183464ebd5Sriastradh    /* Reserve requested CS space. */
2197ec681f3Smrg    if (!r300->rws->cs_check_space(&r300->cs, cs_dwords, false)) {
22001e04c3fSmrg        r300_flush(&r300->context, PIPE_FLUSH_ASYNC, NULL);
2213464ebd5Sriastradh        flushed = TRUE;
2223464ebd5Sriastradh    }
2233464ebd5Sriastradh
2243464ebd5Sriastradh    return flushed;
2253464ebd5Sriastradh}
2263464ebd5Sriastradh
2273464ebd5Sriastradh/**
2283464ebd5Sriastradh * Validate buffers and emit dirty state.
2293464ebd5Sriastradh * \param r300          The context.
2303464ebd5Sriastradh * \param flags         See r300_prepare_flags.
2313464ebd5Sriastradh * \param index_buffer  The index buffer to validate. The parameter may be NULL.
2323464ebd5Sriastradh * \param buffer_offset The offset passed to emit_vertex_arrays.
2333464ebd5Sriastradh * \param index_bias    The index bias to emit.
2343464ebd5Sriastradh * \param instance_id   Index of instance to render
2353464ebd5Sriastradh * \return TRUE if rendering should be skipped
2363464ebd5Sriastradh */
2373464ebd5Sriastradhstatic boolean r300_emit_states(struct r300_context *r300,
2383464ebd5Sriastradh                                enum r300_prepare_flags flags,
2393464ebd5Sriastradh                                struct pipe_resource *index_buffer,
2403464ebd5Sriastradh                                int buffer_offset,
2413464ebd5Sriastradh                                int index_bias, int instance_id)
242cdc920a0Smrg{
2433464ebd5Sriastradh    boolean emit_states    = flags & PREP_EMIT_STATES;
2443464ebd5Sriastradh    boolean emit_vertex_arrays       = flags & PREP_EMIT_VARRAYS;
2453464ebd5Sriastradh    boolean emit_vertex_arrays_swtcl = flags & PREP_EMIT_VARRAYS_SWTCL;
2463464ebd5Sriastradh    boolean indexed        = flags & PREP_INDEXED;
2473464ebd5Sriastradh    boolean validate_vbos  = flags & PREP_VALIDATE_VBOS;
2483464ebd5Sriastradh
2493464ebd5Sriastradh    /* Validate buffers and emit dirty state if needed. */
2503464ebd5Sriastradh    if (emit_states || (emit_vertex_arrays && validate_vbos)) {
2513464ebd5Sriastradh        if (!r300_emit_buffer_validate(r300, validate_vbos,
2523464ebd5Sriastradh                                       index_buffer)) {
2533464ebd5Sriastradh           fprintf(stderr, "r300: CS space validation failed. "
2543464ebd5Sriastradh                   "(not enough memory?) Skipping rendering.\n");
2553464ebd5Sriastradh           return FALSE;
2563464ebd5Sriastradh        }
257cdc920a0Smrg    }
2583464ebd5Sriastradh
2593464ebd5Sriastradh    if (emit_states)
2603464ebd5Sriastradh        r300_emit_dirty_state(r300);
2613464ebd5Sriastradh
2623464ebd5Sriastradh    if (r300->screen->caps.is_r500) {
2633464ebd5Sriastradh        if (r300->screen->caps.has_tcl)
2643464ebd5Sriastradh            r500_emit_index_bias(r300, index_bias);
2653464ebd5Sriastradh        else
2663464ebd5Sriastradh            r500_emit_index_bias(r300, 0);
2673464ebd5Sriastradh    }
2683464ebd5Sriastradh
2693464ebd5Sriastradh    if (emit_vertex_arrays &&
2703464ebd5Sriastradh        (r300->vertex_arrays_dirty ||
2713464ebd5Sriastradh         r300->vertex_arrays_indexed != indexed ||
2723464ebd5Sriastradh         r300->vertex_arrays_offset != buffer_offset ||
2733464ebd5Sriastradh         r300->vertex_arrays_instance_id != instance_id)) {
2743464ebd5Sriastradh        r300_emit_vertex_arrays(r300, buffer_offset, indexed, instance_id);
2753464ebd5Sriastradh
2763464ebd5Sriastradh        r300->vertex_arrays_dirty = FALSE;
2773464ebd5Sriastradh        r300->vertex_arrays_indexed = indexed;
2783464ebd5Sriastradh        r300->vertex_arrays_offset = buffer_offset;
2793464ebd5Sriastradh        r300->vertex_arrays_instance_id = instance_id;
2803464ebd5Sriastradh    }
2813464ebd5Sriastradh
2823464ebd5Sriastradh    if (emit_vertex_arrays_swtcl)
2833464ebd5Sriastradh        r300_emit_vertex_arrays_swtcl(r300, indexed);
2843464ebd5Sriastradh
2853464ebd5Sriastradh    return TRUE;
2863464ebd5Sriastradh}
2873464ebd5Sriastradh
2883464ebd5Sriastradh/**
2893464ebd5Sriastradh * Check if the requested number of dwords is available in the CS and
2903464ebd5Sriastradh * if not, flush. Then validate buffers and emit dirty state.
2913464ebd5Sriastradh * \param r300          The context.
2923464ebd5Sriastradh * \param flags         See r300_prepare_flags.
2933464ebd5Sriastradh * \param index_buffer  The index buffer to validate. The parameter may be NULL.
2943464ebd5Sriastradh * \param cs_dwords     The number of dwords to reserve in CS.
2953464ebd5Sriastradh * \param buffer_offset The offset passed to emit_vertex_arrays.
2963464ebd5Sriastradh * \param index_bias    The index bias to emit.
2973464ebd5Sriastradh * \param instance_id The instance to render.
2983464ebd5Sriastradh * \return TRUE if rendering should be skipped
2993464ebd5Sriastradh */
3003464ebd5Sriastradhstatic boolean r300_prepare_for_rendering(struct r300_context *r300,
3013464ebd5Sriastradh                                          enum r300_prepare_flags flags,
3023464ebd5Sriastradh                                          struct pipe_resource *index_buffer,
3033464ebd5Sriastradh                                          unsigned cs_dwords,
3043464ebd5Sriastradh                                          int buffer_offset,
3053464ebd5Sriastradh                                          int index_bias,
3063464ebd5Sriastradh                                          int instance_id)
3073464ebd5Sriastradh{
3083464ebd5Sriastradh    /* Make sure there is enough space in the command stream and emit states. */
3093464ebd5Sriastradh    if (r300_reserve_cs_dwords(r300, flags, cs_dwords))
3103464ebd5Sriastradh        flags |= PREP_EMIT_STATES;
3113464ebd5Sriastradh
3123464ebd5Sriastradh    return r300_emit_states(r300, flags, index_buffer, buffer_offset,
3133464ebd5Sriastradh                            index_bias, instance_id);
314cdc920a0Smrg}
315cdc920a0Smrg
316cdc920a0Smrgstatic boolean immd_is_good_idea(struct r300_context *r300,
3173464ebd5Sriastradh                                 unsigned count)
318cdc920a0Smrg{
3193464ebd5Sriastradh    if (DBG_ON(r300, DBG_NO_IMMD)) {
3203464ebd5Sriastradh        return FALSE;
3213464ebd5Sriastradh    }
3223464ebd5Sriastradh
3233464ebd5Sriastradh    if (count * r300->velems->vertex_size_dwords > IMMD_DWORDS) {
3243464ebd5Sriastradh        return FALSE;
3253464ebd5Sriastradh    }
3263464ebd5Sriastradh
327af69d88dSmrg    /* Buffers can only be used for read by r300 (except query buffers, but
3287ec681f3Smrg     * those can't be bound by an gallium frontend as vertex buffers). */
3293464ebd5Sriastradh    return TRUE;
330cdc920a0Smrg}
331cdc920a0Smrg
3323464ebd5Sriastradh/*****************************************************************************
3333464ebd5Sriastradh * The HWTCL draw functions.                                                 *
3343464ebd5Sriastradh ****************************************************************************/
3353464ebd5Sriastradh
3363464ebd5Sriastradhstatic void r300_draw_arrays_immediate(struct r300_context *r300,
3377ec681f3Smrg                                       const struct pipe_draw_info *info,
3387ec681f3Smrg                                       const struct pipe_draw_start_count_bias *draw)
339cdc920a0Smrg{
340cdc920a0Smrg    struct pipe_vertex_element* velem;
341cdc920a0Smrg    struct pipe_vertex_buffer* vbuf;
3423464ebd5Sriastradh    unsigned vertex_element_count = r300->velems->count;
3433464ebd5Sriastradh    unsigned i, v, vbi;
344cdc920a0Smrg
345cdc920a0Smrg    /* Size of the vertex, in dwords. */
3463464ebd5Sriastradh    unsigned vertex_size = r300->velems->vertex_size_dwords;
347cdc920a0Smrg
3483464ebd5Sriastradh    /* The number of dwords for this draw operation. */
3497ec681f3Smrg    unsigned dwords = 4 + draw->count * vertex_size;
350cdc920a0Smrg
351cdc920a0Smrg    /* Size of the vertex element, in dwords. */
352cdc920a0Smrg    unsigned size[PIPE_MAX_ATTRIBS];
353cdc920a0Smrg
354cdc920a0Smrg    /* Stride to the same attrib in the next vertex in the vertex buffer,
355cdc920a0Smrg     * in dwords. */
3563464ebd5Sriastradh    unsigned stride[PIPE_MAX_ATTRIBS];
357cdc920a0Smrg
358cdc920a0Smrg    /* Mapped vertex buffers. */
359cdc920a0Smrg    uint32_t* map[PIPE_MAX_ATTRIBS] = {0};
3603464ebd5Sriastradh    uint32_t* mapelem[PIPE_MAX_ATTRIBS];
361cdc920a0Smrg
362cdc920a0Smrg    CS_LOCALS(r300);
363cdc920a0Smrg
3643464ebd5Sriastradh    if (!r300_prepare_for_rendering(r300, PREP_EMIT_STATES, NULL, dwords, 0, 0, -1))
3653464ebd5Sriastradh        return;
3663464ebd5Sriastradh
367cdc920a0Smrg    /* Calculate the vertex size, offsets, strides etc. and map the buffers. */
368cdc920a0Smrg    for (i = 0; i < vertex_element_count; i++) {
3693464ebd5Sriastradh        velem = &r300->velems->velem[i];
3703464ebd5Sriastradh        size[i] = r300->velems->format_size[i] / 4;
371cdc920a0Smrg        vbi = velem->vertex_buffer_index;
372af69d88dSmrg        vbuf = &r300->vertex_buffer[vbi];
3733464ebd5Sriastradh        stride[i] = vbuf->stride / 4;
374cdc920a0Smrg
375cdc920a0Smrg        /* Map the buffer. */
376cdc920a0Smrg        if (!map[vbi]) {
3777ec681f3Smrg            map[vbi] = (uint32_t*)r300->rws->buffer_map(r300->rws,
37801e04c3fSmrg                r300_resource(vbuf->buffer.resource)->buf,
3797ec681f3Smrg                &r300->cs, PIPE_MAP_READ | PIPE_MAP_UNSYNCHRONIZED);
3807ec681f3Smrg            map[vbi] += (vbuf->buffer_offset / 4) + stride[i] * draw->start;
381cdc920a0Smrg        }
3823464ebd5Sriastradh        mapelem[i] = map[vbi] + (velem->src_offset / 4);
383cdc920a0Smrg    }
384cdc920a0Smrg
3857ec681f3Smrg    r300_emit_draw_init(r300, info->mode, draw->count-1);
386cdc920a0Smrg
387cdc920a0Smrg    BEGIN_CS(dwords);
388cdc920a0Smrg    OUT_CS_REG(R300_VAP_VTX_SIZE, vertex_size);
3897ec681f3Smrg    OUT_CS_PKT3(R300_PACKET3_3D_DRAW_IMMD_2, draw->count * vertex_size);
3907ec681f3Smrg    OUT_CS(R300_VAP_VF_CNTL__PRIM_WALK_VERTEX_EMBEDDED | (draw->count << 16) |
3913464ebd5Sriastradh            r300_translate_primitive(info->mode));
392cdc920a0Smrg
393cdc920a0Smrg    /* Emit vertices. */
3947ec681f3Smrg    for (v = 0; v < draw->count; v++) {
395cdc920a0Smrg        for (i = 0; i < vertex_element_count; i++) {
3963464ebd5Sriastradh            OUT_CS_TABLE(&mapelem[i][stride[i] * v], size[i]);
397cdc920a0Smrg        }
398cdc920a0Smrg    }
399cdc920a0Smrg    END_CS;
400cdc920a0Smrg}
401cdc920a0Smrg
4024a49301eSmrgstatic void r300_emit_draw_arrays(struct r300_context *r300,
4034a49301eSmrg                                  unsigned mode,
4044a49301eSmrg                                  unsigned count)
4054a49301eSmrg{
406cdc920a0Smrg    boolean alt_num_verts = count > 65535;
4074a49301eSmrg    CS_LOCALS(r300);
4084a49301eSmrg
4093464ebd5Sriastradh    if (count >= (1 << 24)) {
4103464ebd5Sriastradh        fprintf(stderr, "r300: Got a huge number of vertices: %i, "
4113464ebd5Sriastradh                "refusing to render.\n", count);
4123464ebd5Sriastradh        return;
4133464ebd5Sriastradh    }
4143464ebd5Sriastradh
415af69d88dSmrg    r300_emit_draw_init(r300, mode, count-1);
4163464ebd5Sriastradh
4173464ebd5Sriastradh    BEGIN_CS(2 + (alt_num_verts ? 2 : 0));
418cdc920a0Smrg    if (alt_num_verts) {
419cdc920a0Smrg        OUT_CS_REG(R500_VAP_ALT_NUM_VERTICES, count);
420cdc920a0Smrg    }
4214a49301eSmrg    OUT_CS_PKT3(R300_PACKET3_3D_DRAW_VBUF_2, 0);
4224a49301eSmrg    OUT_CS(R300_VAP_VF_CNTL__PRIM_WALK_VERTEX_LIST | (count << 16) |
423cdc920a0Smrg           r300_translate_primitive(mode) |
424cdc920a0Smrg           (alt_num_verts ? R500_VAP_VF_CNTL__USE_ALT_NUM_VERTS : 0));
4254a49301eSmrg    END_CS;
4264a49301eSmrg}
4274a49301eSmrg
4284a49301eSmrgstatic void r300_emit_draw_elements(struct r300_context *r300,
4293464ebd5Sriastradh                                    struct pipe_resource* indexBuffer,
4304a49301eSmrg                                    unsigned indexSize,
4313464ebd5Sriastradh                                    unsigned max_index,
4324a49301eSmrg                                    unsigned mode,
4334a49301eSmrg                                    unsigned start,
4343464ebd5Sriastradh                                    unsigned count,
4353464ebd5Sriastradh                                    uint16_t *imm_indices3)
4364a49301eSmrg{
4373464ebd5Sriastradh    uint32_t count_dwords, offset_dwords;
438cdc920a0Smrg    boolean alt_num_verts = count > 65535;
4394a49301eSmrg    CS_LOCALS(r300);
4404a49301eSmrg
441af69d88dSmrg    if (count >= (1 << 24)) {
4423464ebd5Sriastradh        fprintf(stderr, "r300: Got a huge number of vertices: %i, "
4433464ebd5Sriastradh                "refusing to render (max_index: %i).\n", count, max_index);
4443464ebd5Sriastradh        return;
4453464ebd5Sriastradh    }
446cdc920a0Smrg
447af69d88dSmrg    DBG(r300, DBG_DRAW, "r300: Indexbuf of %u indices, max %u\n",
448af69d88dSmrg        count, max_index);
4493464ebd5Sriastradh
450af69d88dSmrg    r300_emit_draw_init(r300, mode, max_index);
4513464ebd5Sriastradh
4523464ebd5Sriastradh    /* If start is odd, render the first triangle with indices embedded
4533464ebd5Sriastradh     * in the command stream. This will increase start by 3 and make it
4543464ebd5Sriastradh     * even. We can then proceed without a fallback. */
4553464ebd5Sriastradh    if (indexSize == 2 && (start & 1) &&
4563464ebd5Sriastradh        mode == PIPE_PRIM_TRIANGLES) {
4573464ebd5Sriastradh        BEGIN_CS(4);
4583464ebd5Sriastradh        OUT_CS_PKT3(R300_PACKET3_3D_DRAW_INDX_2, 2);
4593464ebd5Sriastradh        OUT_CS(R300_VAP_VF_CNTL__PRIM_WALK_INDICES | (3 << 16) |
4603464ebd5Sriastradh               R300_VAP_VF_CNTL__PRIM_TRIANGLES);
4613464ebd5Sriastradh        OUT_CS(imm_indices3[1] << 16 | imm_indices3[0]);
4623464ebd5Sriastradh        OUT_CS(imm_indices3[2]);
4633464ebd5Sriastradh        END_CS;
4643464ebd5Sriastradh
4653464ebd5Sriastradh        start += 3;
4663464ebd5Sriastradh        count -= 3;
4673464ebd5Sriastradh        if (!count)
4683464ebd5Sriastradh           return;
4693464ebd5Sriastradh    }
470cdc920a0Smrg
4713464ebd5Sriastradh    offset_dwords = indexSize * start / sizeof(uint32_t);
4724a49301eSmrg
4733464ebd5Sriastradh    BEGIN_CS(8 + (alt_num_verts ? 2 : 0));
474cdc920a0Smrg    if (alt_num_verts) {
475cdc920a0Smrg        OUT_CS_REG(R500_VAP_ALT_NUM_VERTICES, count);
476cdc920a0Smrg    }
4774a49301eSmrg    OUT_CS_PKT3(R300_PACKET3_3D_DRAW_INDX_2, 0);
4784a49301eSmrg    if (indexSize == 4) {
479cdc920a0Smrg        count_dwords = count;
4804a49301eSmrg        OUT_CS(R300_VAP_VF_CNTL__PRIM_WALK_INDICES | (count << 16) |
4814a49301eSmrg               R300_VAP_VF_CNTL__INDEX_SIZE_32bit |
482cdc920a0Smrg               r300_translate_primitive(mode) |
483cdc920a0Smrg               (alt_num_verts ? R500_VAP_VF_CNTL__USE_ALT_NUM_VERTS : 0));
4844a49301eSmrg    } else {
485cdc920a0Smrg        count_dwords = (count + 1) / 2;
4864a49301eSmrg        OUT_CS(R300_VAP_VF_CNTL__PRIM_WALK_INDICES | (count << 16) |
487cdc920a0Smrg               r300_translate_primitive(mode) |
488cdc920a0Smrg               (alt_num_verts ? R500_VAP_VF_CNTL__USE_ALT_NUM_VERTS : 0));
4894a49301eSmrg    }
4904a49301eSmrg
4914a49301eSmrg    OUT_CS_PKT3(R300_PACKET3_INDX_BUFFER, 2);
4924a49301eSmrg    OUT_CS(R300_INDX_BUFFER_ONE_REG_WR | (R300_VAP_PORT_IDX0 >> 2) |
4934a49301eSmrg           (0 << R300_INDX_BUFFER_SKIP_SHIFT));
494cdc920a0Smrg    OUT_CS(offset_dwords << 2);
4953464ebd5Sriastradh    OUT_CS(count_dwords);
4963464ebd5Sriastradh    OUT_CS_RELOC(r300_resource(indexBuffer));
4974a49301eSmrg    END_CS;
4984a49301eSmrg}
4994a49301eSmrg
5003464ebd5Sriastradhstatic void r300_draw_elements_immediate(struct r300_context *r300,
5017ec681f3Smrg                                         const struct pipe_draw_info *info,
5027ec681f3Smrg                                         const struct pipe_draw_start_count_bias *draw)
5034a49301eSmrg{
504af69d88dSmrg    const uint8_t *ptr1;
505af69d88dSmrg    const uint16_t *ptr2;
506af69d88dSmrg    const uint32_t *ptr4;
50701e04c3fSmrg    unsigned index_size = info->index_size;
5087ec681f3Smrg    unsigned i, count_dwords = index_size == 4 ? draw->count :
5097ec681f3Smrg                                                 (draw->count + 1) / 2;
5103464ebd5Sriastradh    CS_LOCALS(r300);
511cdc920a0Smrg
5123464ebd5Sriastradh    /* 19 dwords for r300_draw_elements_immediate. Give up if the function fails. */
5133464ebd5Sriastradh    if (!r300_prepare_for_rendering(r300,
5143464ebd5Sriastradh            PREP_EMIT_STATES | PREP_VALIDATE_VBOS | PREP_EMIT_VARRAYS |
5157ec681f3Smrg            PREP_INDEXED, NULL, 2+count_dwords, 0, draw->index_bias, -1))
5163464ebd5Sriastradh        return;
517cdc920a0Smrg
518af69d88dSmrg    r300_emit_draw_init(r300, info->mode, info->max_index);
519cdc920a0Smrg
5203464ebd5Sriastradh    BEGIN_CS(2 + count_dwords);
5213464ebd5Sriastradh    OUT_CS_PKT3(R300_PACKET3_3D_DRAW_INDX_2, count_dwords);
5223464ebd5Sriastradh
5233464ebd5Sriastradh    switch (index_size) {
5243464ebd5Sriastradh    case 1:
52501e04c3fSmrg        ptr1 = (uint8_t*)info->index.user;
5267ec681f3Smrg        ptr1 += draw->start;
5273464ebd5Sriastradh
5287ec681f3Smrg        OUT_CS(R300_VAP_VF_CNTL__PRIM_WALK_INDICES | (draw->count << 16) |
5293464ebd5Sriastradh               r300_translate_primitive(info->mode));
5303464ebd5Sriastradh
5317ec681f3Smrg        if (draw->index_bias && !r300->screen->caps.is_r500) {
5327ec681f3Smrg            for (i = 0; i < draw->count-1; i += 2)
5337ec681f3Smrg                OUT_CS(((ptr1[i+1] + draw->index_bias) << 16) |
5347ec681f3Smrg                        (ptr1[i]   + draw->index_bias));
5353464ebd5Sriastradh
5367ec681f3Smrg            if (draw->count & 1)
5377ec681f3Smrg                OUT_CS(ptr1[i] + draw->index_bias);
5383464ebd5Sriastradh        } else {
5397ec681f3Smrg            for (i = 0; i < draw->count-1; i += 2)
5403464ebd5Sriastradh                OUT_CS(((ptr1[i+1]) << 16) |
5413464ebd5Sriastradh                        (ptr1[i]  ));
5423464ebd5Sriastradh
5437ec681f3Smrg            if (draw->count & 1)
5443464ebd5Sriastradh                OUT_CS(ptr1[i]);
5453464ebd5Sriastradh        }
5463464ebd5Sriastradh        break;
5474a49301eSmrg
5483464ebd5Sriastradh    case 2:
54901e04c3fSmrg        ptr2 = (uint16_t*)info->index.user;
5507ec681f3Smrg        ptr2 += draw->start;
5513464ebd5Sriastradh
5527ec681f3Smrg        OUT_CS(R300_VAP_VF_CNTL__PRIM_WALK_INDICES | (draw->count << 16) |
5533464ebd5Sriastradh               r300_translate_primitive(info->mode));
5543464ebd5Sriastradh
5557ec681f3Smrg        if (draw->index_bias && !r300->screen->caps.is_r500) {
5567ec681f3Smrg            for (i = 0; i < draw->count-1; i += 2)
5577ec681f3Smrg                OUT_CS(((ptr2[i+1] + draw->index_bias) << 16) |
5587ec681f3Smrg                        (ptr2[i]   + draw->index_bias));
5593464ebd5Sriastradh
5607ec681f3Smrg            if (draw->count & 1)
5617ec681f3Smrg                OUT_CS(ptr2[i] + draw->index_bias);
5623464ebd5Sriastradh        } else {
5633464ebd5Sriastradh            OUT_CS_TABLE(ptr2, count_dwords);
5643464ebd5Sriastradh        }
5653464ebd5Sriastradh        break;
5663464ebd5Sriastradh
5673464ebd5Sriastradh    case 4:
56801e04c3fSmrg        ptr4 = (uint32_t*)info->index.user;
5697ec681f3Smrg        ptr4 += draw->start;
5703464ebd5Sriastradh
5717ec681f3Smrg        OUT_CS(R300_VAP_VF_CNTL__PRIM_WALK_INDICES | (draw->count << 16) |
5723464ebd5Sriastradh               R300_VAP_VF_CNTL__INDEX_SIZE_32bit |
5733464ebd5Sriastradh               r300_translate_primitive(info->mode));
5744a49301eSmrg
5757ec681f3Smrg        if (draw->index_bias && !r300->screen->caps.is_r500) {
5767ec681f3Smrg            for (i = 0; i < draw->count; i++)
5777ec681f3Smrg                OUT_CS(ptr4[i] + draw->index_bias);
5783464ebd5Sriastradh        } else {
5793464ebd5Sriastradh            OUT_CS_TABLE(ptr4, count_dwords);
5803464ebd5Sriastradh        }
5813464ebd5Sriastradh        break;
5823464ebd5Sriastradh    }
5833464ebd5Sriastradh    END_CS;
5844a49301eSmrg}
5854a49301eSmrg
5863464ebd5Sriastradhstatic void r300_draw_elements(struct r300_context *r300,
5873464ebd5Sriastradh                               const struct pipe_draw_info *info,
5887ec681f3Smrg                               const struct pipe_draw_start_count_bias *draw,
5893464ebd5Sriastradh                               int instance_id)
5904a49301eSmrg{
59101e04c3fSmrg    struct pipe_resource *indexBuffer =
59201e04c3fSmrg       info->has_user_indices ? NULL : info->index.resource;
59301e04c3fSmrg    unsigned indexSize = info->index_size;
5943464ebd5Sriastradh    struct pipe_resource* orgIndexBuffer = indexBuffer;
5957ec681f3Smrg    unsigned start = draw->start;
5967ec681f3Smrg    unsigned count = draw->count;
5973464ebd5Sriastradh    boolean alt_num_verts = r300->screen->caps.is_r500 &&
598cdc920a0Smrg                            count > 65536;
599cdc920a0Smrg    unsigned short_count;
6003464ebd5Sriastradh    int buffer_offset = 0, index_offset = 0; /* for index bias emulation */
6013464ebd5Sriastradh    uint16_t indices3[3];
6024a49301eSmrg
6037ec681f3Smrg    if (draw->index_bias && !r300->screen->caps.is_r500) {
6047ec681f3Smrg        r300_split_index_bias(r300, draw->index_bias, &buffer_offset,
605af69d88dSmrg                              &index_offset);
6064a49301eSmrg    }
6074a49301eSmrg
60801e04c3fSmrg    r300_translate_index_buffer(r300, info, &indexBuffer,
609af69d88dSmrg                                &indexSize, index_offset, &start, count);
6104a49301eSmrg
6113464ebd5Sriastradh    /* Fallback for misaligned ushort indices. */
612af69d88dSmrg    if (indexSize == 2 && (start & 1) && indexBuffer) {
6133464ebd5Sriastradh        /* If we got here, then orgIndexBuffer == indexBuffer. */
6147ec681f3Smrg        uint16_t *ptr = r300->rws->buffer_map(r300->rws, r300_resource(orgIndexBuffer)->buf,
6157ec681f3Smrg                                              &r300->cs,
6167ec681f3Smrg                                              PIPE_MAP_READ |
6177ec681f3Smrg                                              PIPE_MAP_UNSYNCHRONIZED);
6184a49301eSmrg
6193464ebd5Sriastradh        if (info->mode == PIPE_PRIM_TRIANGLES) {
6203464ebd5Sriastradh           memcpy(indices3, ptr + start, 6);
6213464ebd5Sriastradh        } else {
6223464ebd5Sriastradh            /* Copy the mapped index buffer directly to the upload buffer.
6233464ebd5Sriastradh             * The start index will be aligned simply from the fact that
6243464ebd5Sriastradh             * every sub-buffer in the upload buffer is aligned. */
6253464ebd5Sriastradh            r300_upload_index_buffer(r300, &indexBuffer, indexSize, &start,
6263464ebd5Sriastradh                                     count, (uint8_t*)ptr);
6273464ebd5Sriastradh        }
6283464ebd5Sriastradh    } else {
62901e04c3fSmrg        if (info->has_user_indices)
6303464ebd5Sriastradh            r300_upload_index_buffer(r300, &indexBuffer, indexSize,
6313464ebd5Sriastradh                                     &start, count,
63201e04c3fSmrg                                     info->index.user);
6333464ebd5Sriastradh    }
6343464ebd5Sriastradh
6353464ebd5Sriastradh    /* 19 dwords for emit_draw_elements. Give up if the function fails. */
6363464ebd5Sriastradh    if (!r300_prepare_for_rendering(r300,
6373464ebd5Sriastradh            PREP_EMIT_STATES | PREP_VALIDATE_VBOS | PREP_EMIT_VARRAYS |
6387ec681f3Smrg            PREP_INDEXED, indexBuffer, 19, buffer_offset, draw->index_bias,
6393464ebd5Sriastradh            instance_id))
6403464ebd5Sriastradh        goto done;
6414a49301eSmrg
642cdc920a0Smrg    if (alt_num_verts || count <= 65535) {
643af69d88dSmrg        r300_emit_draw_elements(r300, indexBuffer, indexSize,
6443464ebd5Sriastradh                                info->max_index, info->mode, start, count,
6453464ebd5Sriastradh                                indices3);
646cdc920a0Smrg    } else {
647cdc920a0Smrg        do {
6483464ebd5Sriastradh            /* The maximum must be divisible by 4 and 3,
6493464ebd5Sriastradh             * so that quad and triangle lists are split correctly.
6503464ebd5Sriastradh             *
6513464ebd5Sriastradh             * Strips, loops, and fans won't work. */
6523464ebd5Sriastradh            short_count = MIN2(count, 65532);
6533464ebd5Sriastradh
6543464ebd5Sriastradh            r300_emit_draw_elements(r300, indexBuffer, indexSize,
655af69d88dSmrg                                     info->max_index,
6563464ebd5Sriastradh                                     info->mode, start, short_count, indices3);
657cdc920a0Smrg
658cdc920a0Smrg            start += short_count;
659cdc920a0Smrg            count -= short_count;
660cdc920a0Smrg
6613464ebd5Sriastradh            /* 15 dwords for emit_draw_elements */
6623464ebd5Sriastradh            if (count) {
6633464ebd5Sriastradh                if (!r300_prepare_for_rendering(r300,
6643464ebd5Sriastradh                        PREP_VALIDATE_VBOS | PREP_EMIT_VARRAYS | PREP_INDEXED,
6657ec681f3Smrg                        indexBuffer, 19, buffer_offset, draw->index_bias,
6663464ebd5Sriastradh                        instance_id))
6673464ebd5Sriastradh                    goto done;
668cdc920a0Smrg            }
669cdc920a0Smrg        } while (count);
670cdc920a0Smrg    }
6714a49301eSmrg
6723464ebd5Sriastradhdone:
673cdc920a0Smrg    if (indexBuffer != orgIndexBuffer) {
6743464ebd5Sriastradh        pipe_resource_reference( &indexBuffer, NULL );
6753464ebd5Sriastradh    }
6763464ebd5Sriastradh}
6773464ebd5Sriastradh
6783464ebd5Sriastradhstatic void r300_draw_arrays(struct r300_context *r300,
6793464ebd5Sriastradh                             const struct pipe_draw_info *info,
6807ec681f3Smrg                             const struct pipe_draw_start_count_bias *draw,
6813464ebd5Sriastradh                             int instance_id)
6823464ebd5Sriastradh{
6833464ebd5Sriastradh    boolean alt_num_verts = r300->screen->caps.is_r500 &&
6847ec681f3Smrg                            draw->count > 65536;
6857ec681f3Smrg    unsigned start = draw->start;
6867ec681f3Smrg    unsigned count = draw->count;
6873464ebd5Sriastradh    unsigned short_count;
6883464ebd5Sriastradh
6893464ebd5Sriastradh    /* 9 spare dwords for emit_draw_arrays. Give up if the function fails. */
6903464ebd5Sriastradh    if (!r300_prepare_for_rendering(r300,
6913464ebd5Sriastradh                                    PREP_EMIT_STATES | PREP_VALIDATE_VBOS | PREP_EMIT_VARRAYS,
6923464ebd5Sriastradh                                    NULL, 9, start, 0, instance_id))
6933464ebd5Sriastradh        return;
6943464ebd5Sriastradh
6953464ebd5Sriastradh    if (alt_num_verts || count <= 65535) {
6963464ebd5Sriastradh        r300_emit_draw_arrays(r300, info->mode, count);
6973464ebd5Sriastradh    } else {
6983464ebd5Sriastradh        do {
6993464ebd5Sriastradh            /* The maximum must be divisible by 4 and 3,
7003464ebd5Sriastradh             * so that quad and triangle lists are split correctly.
7013464ebd5Sriastradh             *
7023464ebd5Sriastradh             * Strips, loops, and fans won't work. */
7033464ebd5Sriastradh            short_count = MIN2(count, 65532);
7043464ebd5Sriastradh            r300_emit_draw_arrays(r300, info->mode, short_count);
7053464ebd5Sriastradh
7063464ebd5Sriastradh            start += short_count;
7073464ebd5Sriastradh            count -= short_count;
7083464ebd5Sriastradh
7093464ebd5Sriastradh            /* 9 spare dwords for emit_draw_arrays. Give up if the function fails. */
7103464ebd5Sriastradh            if (count) {
7113464ebd5Sriastradh                if (!r300_prepare_for_rendering(r300,
7123464ebd5Sriastradh                                                PREP_VALIDATE_VBOS | PREP_EMIT_VARRAYS, NULL, 9,
7133464ebd5Sriastradh                                                start, 0, instance_id))
7143464ebd5Sriastradh                    return;
7153464ebd5Sriastradh            }
7163464ebd5Sriastradh        } while (count);
717cdc920a0Smrg    }
7184a49301eSmrg}
7194a49301eSmrg
7203464ebd5Sriastradhstatic void r300_draw_arrays_instanced(struct r300_context *r300,
7217ec681f3Smrg                                       const struct pipe_draw_info *info,
7227ec681f3Smrg                                       const struct pipe_draw_start_count_bias *draw)
7233464ebd5Sriastradh{
7243464ebd5Sriastradh    int i;
7253464ebd5Sriastradh
7263464ebd5Sriastradh    for (i = 0; i < info->instance_count; i++)
7277ec681f3Smrg        r300_draw_arrays(r300, info, draw, i);
7283464ebd5Sriastradh}
7293464ebd5Sriastradh
7303464ebd5Sriastradhstatic void r300_draw_elements_instanced(struct r300_context *r300,
7317ec681f3Smrg                                         const struct pipe_draw_info *info,
7327ec681f3Smrg                                         const struct pipe_draw_start_count_bias *draw)
7334a49301eSmrg{
7343464ebd5Sriastradh    int i;
735cdc920a0Smrg
7363464ebd5Sriastradh    for (i = 0; i < info->instance_count; i++)
7377ec681f3Smrg        r300_draw_elements(r300, info, draw, i);
7384a49301eSmrg}
7394a49301eSmrg
740af69d88dSmrgstatic unsigned r300_max_vertex_count(struct r300_context *r300)
741af69d88dSmrg{
742af69d88dSmrg   unsigned i, nr = r300->velems->count;
743af69d88dSmrg   struct pipe_vertex_element *velems = r300->velems->velem;
744af69d88dSmrg   unsigned result = ~0;
745af69d88dSmrg
746af69d88dSmrg   for (i = 0; i < nr; i++) {
747af69d88dSmrg      struct pipe_vertex_buffer *vb =
748af69d88dSmrg            &r300->vertex_buffer[velems[i].vertex_buffer_index];
749af69d88dSmrg      unsigned size, max_count, value;
750af69d88dSmrg
751af69d88dSmrg      /* We're not interested in constant and per-instance attribs. */
75201e04c3fSmrg      if (!vb->buffer.resource ||
753af69d88dSmrg          !vb->stride ||
754af69d88dSmrg          velems[i].instance_divisor) {
755af69d88dSmrg         continue;
756af69d88dSmrg      }
757af69d88dSmrg
75801e04c3fSmrg      size = vb->buffer.resource->width0;
759af69d88dSmrg
760af69d88dSmrg      /* Subtract buffer_offset. */
761af69d88dSmrg      value = vb->buffer_offset;
762af69d88dSmrg      if (value >= size) {
763af69d88dSmrg         return 0;
764af69d88dSmrg      }
765af69d88dSmrg      size -= value;
766af69d88dSmrg
767af69d88dSmrg      /* Subtract src_offset. */
768af69d88dSmrg      value = velems[i].src_offset;
769af69d88dSmrg      if (value >= size) {
770af69d88dSmrg         return 0;
771af69d88dSmrg      }
772af69d88dSmrg      size -= value;
773af69d88dSmrg
774af69d88dSmrg      /* Subtract format_size. */
775af69d88dSmrg      value = r300->velems->format_size[i];
776af69d88dSmrg      if (value >= size) {
777af69d88dSmrg         return 0;
778af69d88dSmrg      }
779af69d88dSmrg      size -= value;
780af69d88dSmrg
781af69d88dSmrg      /* Compute the max count. */
782af69d88dSmrg      max_count = 1 + size / vb->stride;
783af69d88dSmrg      result = MIN2(result, max_count);
784af69d88dSmrg   }
785af69d88dSmrg   return result;
786af69d88dSmrg}
787af69d88dSmrg
788af69d88dSmrg
7893464ebd5Sriastradhstatic void r300_draw_vbo(struct pipe_context* pipe,
7907ec681f3Smrg                          const struct pipe_draw_info *dinfo,
7917ec681f3Smrg                          unsigned drawid_offset,
7927ec681f3Smrg                          const struct pipe_draw_indirect_info *indirect,
7937ec681f3Smrg                          const struct pipe_draw_start_count_bias *draws,
7947ec681f3Smrg                          unsigned num_draws)
7954a49301eSmrg{
7967ec681f3Smrg   if (num_draws > 1) {
7977ec681f3Smrg      util_draw_multi(pipe, dinfo, drawid_offset, indirect, draws, num_draws);
7987ec681f3Smrg      return;
7997ec681f3Smrg   }
8007ec681f3Smrg
8014a49301eSmrg    struct r300_context* r300 = r300_context(pipe);
8023464ebd5Sriastradh    struct pipe_draw_info info = *dinfo;
8037ec681f3Smrg    struct pipe_draw_start_count_bias draw = draws[0];
8044a49301eSmrg
8053464ebd5Sriastradh    if (r300->skip_rendering ||
8067ec681f3Smrg        !u_trim_pipe_prim(info.mode, &draw.count)) {
807cdc920a0Smrg        return;
8084a49301eSmrg    }
8094a49301eSmrg
8104a49301eSmrg    r300_update_derived_state(r300);
8114a49301eSmrg
8123464ebd5Sriastradh    /* Draw. */
81301e04c3fSmrg    if (info.index_size) {
814af69d88dSmrg        unsigned max_count = r300_max_vertex_count(r300);
815af69d88dSmrg
816af69d88dSmrg        if (!max_count) {
817af69d88dSmrg           fprintf(stderr, "r300: Skipping a draw command. There is a buffer "
818af69d88dSmrg                   " which is too small to be used for rendering.\n");
819af69d88dSmrg           return;
820af69d88dSmrg        }
821af69d88dSmrg
822af69d88dSmrg        if (max_count == ~0) {
823af69d88dSmrg           /* There are no per-vertex vertex elements. Use the hardware maximum. */
824af69d88dSmrg           max_count = 0xffffff;
825af69d88dSmrg        }
826af69d88dSmrg
827af69d88dSmrg        info.max_index = max_count - 1;
8283464ebd5Sriastradh
8293464ebd5Sriastradh        if (info.instance_count <= 1) {
8307ec681f3Smrg            if (draw.count <= 8 && info.has_user_indices) {
8317ec681f3Smrg                r300_draw_elements_immediate(r300, &info, &draw);
8323464ebd5Sriastradh            } else {
8337ec681f3Smrg                r300_draw_elements(r300, &info, &draw, -1);
8343464ebd5Sriastradh            }
8353464ebd5Sriastradh        } else {
8367ec681f3Smrg            r300_draw_elements_instanced(r300, &info, &draw);
8373464ebd5Sriastradh        }
8383464ebd5Sriastradh    } else {
8393464ebd5Sriastradh        if (info.instance_count <= 1) {
8407ec681f3Smrg            if (immd_is_good_idea(r300, draw.count)) {
8417ec681f3Smrg                r300_draw_arrays_immediate(r300, &info, &draw);
8423464ebd5Sriastradh            } else {
8437ec681f3Smrg                r300_draw_arrays(r300, &info, &draw, -1);
8443464ebd5Sriastradh            }
845cdc920a0Smrg        } else {
8467ec681f3Smrg            r300_draw_arrays_instanced(r300, &info, &draw);
847cdc920a0Smrg        }
8484a49301eSmrg    }
8494a49301eSmrg}
8504a49301eSmrg
8514a49301eSmrg/****************************************************************************
8524a49301eSmrg * The rest of this file is for SW TCL rendering only. Please be polite and *
8534a49301eSmrg * keep these functions separated so that they are easier to locate. ~C.    *
8544a49301eSmrg ***************************************************************************/
8554a49301eSmrg
8563464ebd5Sriastradh/* SW TCL elements, using Draw. */
8573464ebd5Sriastradhstatic void r300_swtcl_draw_vbo(struct pipe_context* pipe,
8587ec681f3Smrg                                const struct pipe_draw_info *info,
8597ec681f3Smrg                                unsigned drawid_offset,
8607ec681f3Smrg                                const struct pipe_draw_indirect_info *indirect,
8617ec681f3Smrg                                const struct pipe_draw_start_count_bias *draws,
8627ec681f3Smrg                                unsigned num_draws)
8634a49301eSmrg{
8647ec681f3Smrg   if (num_draws > 1) {
8657ec681f3Smrg      util_draw_multi(pipe, info, drawid_offset, indirect, draws, num_draws);
8667ec681f3Smrg      return;
8677ec681f3Smrg   }
8687ec681f3Smrg
8694a49301eSmrg    struct r300_context* r300 = r300_context(pipe);
8707ec681f3Smrg    struct pipe_draw_start_count_bias draw = draws[0];
8714a49301eSmrg
8723464ebd5Sriastradh    if (r300->skip_rendering) {
873cdc920a0Smrg        return;
8744a49301eSmrg    }
8754a49301eSmrg
8767ec681f3Smrg    if (!u_trim_pipe_prim(info->mode, &draw.count))
87701e04c3fSmrg       return;
87801e04c3fSmrg
87901e04c3fSmrg    if (info->index_size) {
88001e04c3fSmrg        draw_set_indexes(r300->draw,
88101e04c3fSmrg                         info->has_user_indices ?
88201e04c3fSmrg                             info->index.user :
88301e04c3fSmrg                             r300_resource(info->index.resource)->malloced_buffer,
88401e04c3fSmrg                         info->index_size, ~0);
88501e04c3fSmrg    }
88601e04c3fSmrg
8873464ebd5Sriastradh    r300_update_derived_state(r300);
8884a49301eSmrg
8897ec681f3Smrg    draw_vbo(r300->draw, info, drawid_offset, NULL, &draw, 1, 0);
8903464ebd5Sriastradh    draw_flush(r300->draw);
8914a49301eSmrg}
8924a49301eSmrg
8934a49301eSmrg/* Object for rendering using Draw. */
8944a49301eSmrgstruct r300_render {
8954a49301eSmrg    /* Parent class */
8964a49301eSmrg    struct vbuf_render base;
8974a49301eSmrg
8984a49301eSmrg    /* Pipe context */
8994a49301eSmrg    struct r300_context* r300;
9004a49301eSmrg
9014a49301eSmrg    /* Vertex information */
9024a49301eSmrg    size_t vertex_size;
9034a49301eSmrg    unsigned prim;
9044a49301eSmrg    unsigned hwprim;
9054a49301eSmrg
9064a49301eSmrg    /* VBO */
9074a49301eSmrg    size_t vbo_max_used;
908af69d88dSmrg    uint8_t *vbo_ptr;
9094a49301eSmrg};
9104a49301eSmrg
91101e04c3fSmrgstatic inline struct r300_render*
9124a49301eSmrgr300_render(struct vbuf_render* render)
9134a49301eSmrg{
9144a49301eSmrg    return (struct r300_render*)render;
9154a49301eSmrg}
9164a49301eSmrg
9174a49301eSmrgstatic const struct vertex_info*
9184a49301eSmrgr300_render_get_vertex_info(struct vbuf_render* render)
9194a49301eSmrg{
9204a49301eSmrg    struct r300_render* r300render = r300_render(render);
9214a49301eSmrg    struct r300_context* r300 = r300render->r300;
9224a49301eSmrg
923cdc920a0Smrg    return &r300->vertex_info;
9244a49301eSmrg}
9254a49301eSmrg
9264a49301eSmrgstatic boolean r300_render_allocate_vertices(struct vbuf_render* render,
927af69d88dSmrg                                             ushort vertex_size,
928af69d88dSmrg                                             ushort count)
9294a49301eSmrg{
9304a49301eSmrg    struct r300_render* r300render = r300_render(render);
9314a49301eSmrg    struct r300_context* r300 = r300render->r300;
932af69d88dSmrg    struct radeon_winsys *rws = r300->rws;
9334a49301eSmrg    size_t size = (size_t)vertex_size * (size_t)count;
9344a49301eSmrg
9353464ebd5Sriastradh    DBG(r300, DBG_DRAW, "r300: render_allocate_vertices (size: %d)\n", size);
9363464ebd5Sriastradh
937af69d88dSmrg    if (!r300->vbo || size + r300->draw_vbo_offset > r300->vbo->size) {
938af69d88dSmrg	pb_reference(&r300->vbo, NULL);
93901e04c3fSmrg        r300->vbo = NULL;
940af69d88dSmrg        r300render->vbo_ptr = NULL;
941af69d88dSmrg
942af69d88dSmrg        r300->vbo = rws->buffer_create(rws,
943af69d88dSmrg                                       MAX2(R300_MAX_DRAW_VBO_SIZE, size),
94401e04c3fSmrg                                       R300_BUFFER_ALIGNMENT,
9459f464c52Smaya                                       RADEON_DOMAIN_GTT,
9469f464c52Smaya                                       RADEON_FLAG_NO_INTERPROCESS_SHARING);
947af69d88dSmrg        if (!r300->vbo) {
948af69d88dSmrg            return FALSE;
949af69d88dSmrg        }
9503464ebd5Sriastradh        r300->draw_vbo_offset = 0;
9517ec681f3Smrg        r300render->vbo_ptr = rws->buffer_map(rws, r300->vbo, &r300->cs,
9527ec681f3Smrg                                              PIPE_MAP_WRITE);
9534a49301eSmrg    }
9544a49301eSmrg
9554a49301eSmrg    r300render->vertex_size = vertex_size;
956af69d88dSmrg    return TRUE;
9574a49301eSmrg}
9584a49301eSmrg
9594a49301eSmrgstatic void* r300_render_map_vertices(struct vbuf_render* render)
9604a49301eSmrg{
9614a49301eSmrg    struct r300_render* r300render = r300_render(render);
9623464ebd5Sriastradh    struct r300_context* r300 = r300render->r300;
9634a49301eSmrg
9643464ebd5Sriastradh    DBG(r300, DBG_DRAW, "r300: render_map_vertices\n");
9653464ebd5Sriastradh
9663464ebd5Sriastradh    assert(r300render->vbo_ptr);
967af69d88dSmrg    return r300render->vbo_ptr + r300->draw_vbo_offset;
9684a49301eSmrg}
9694a49301eSmrg
9704a49301eSmrgstatic void r300_render_unmap_vertices(struct vbuf_render* render,
9714a49301eSmrg                                             ushort min,
9724a49301eSmrg                                             ushort max)
9734a49301eSmrg{
9744a49301eSmrg    struct r300_render* r300render = r300_render(render);
9753464ebd5Sriastradh    struct r300_context* r300 = r300render->r300;
9763464ebd5Sriastradh
9773464ebd5Sriastradh    DBG(r300, DBG_DRAW, "r300: render_unmap_vertices\n");
9784a49301eSmrg
9794a49301eSmrg    r300render->vbo_max_used = MAX2(r300render->vbo_max_used,
9804a49301eSmrg                                    r300render->vertex_size * (max + 1));
9814a49301eSmrg}
9824a49301eSmrg
9834a49301eSmrgstatic void r300_render_release_vertices(struct vbuf_render* render)
9844a49301eSmrg{
9854a49301eSmrg    struct r300_render* r300render = r300_render(render);
9863464ebd5Sriastradh    struct r300_context* r300 = r300render->r300;
9874a49301eSmrg
9883464ebd5Sriastradh    DBG(r300, DBG_DRAW, "r300: render_release_vertices\n");
9893464ebd5Sriastradh
9903464ebd5Sriastradh    r300->draw_vbo_offset += r300render->vbo_max_used;
9914a49301eSmrg    r300render->vbo_max_used = 0;
9924a49301eSmrg}
9934a49301eSmrg
994af69d88dSmrgstatic void r300_render_set_primitive(struct vbuf_render* render,
99501e04c3fSmrg                                      enum pipe_prim_type prim)
9964a49301eSmrg{
9974a49301eSmrg    struct r300_render* r300render = r300_render(render);
9984a49301eSmrg
9994a49301eSmrg    r300render->prim = prim;
10004a49301eSmrg    r300render->hwprim = r300_translate_primitive(prim);
10014a49301eSmrg}
10024a49301eSmrg
10034a49301eSmrgstatic void r300_render_draw_arrays(struct vbuf_render* render,
10043464ebd5Sriastradh                                    unsigned start,
10053464ebd5Sriastradh                                    unsigned count)
10064a49301eSmrg{
10074a49301eSmrg    struct r300_render* r300render = r300_render(render);
10084a49301eSmrg    struct r300_context* r300 = r300render->r300;
10093464ebd5Sriastradh    uint8_t* ptr;
10103464ebd5Sriastradh    unsigned i;
10113464ebd5Sriastradh    unsigned dwords = 6;
10124a49301eSmrg
10134a49301eSmrg    CS_LOCALS(r300);
10143464ebd5Sriastradh    (void) i; (void) ptr;
10154a49301eSmrg
1016af69d88dSmrg    assert(start == 0);
1017af69d88dSmrg    assert(count < (1 << 16));
1018af69d88dSmrg
10193464ebd5Sriastradh    DBG(r300, DBG_DRAW, "r300: render_draw_arrays (count: %d)\n", count);
10204a49301eSmrg
1021af69d88dSmrg    if (!r300_prepare_for_rendering(r300,
1022af69d88dSmrg                                    PREP_EMIT_STATES | PREP_EMIT_VARRAYS_SWTCL,
1023af69d88dSmrg                                    NULL, dwords, 0, 0, -1)) {
1024af69d88dSmrg        return;
10253464ebd5Sriastradh    }
10264a49301eSmrg
10273464ebd5Sriastradh    BEGIN_CS(dwords);
10283464ebd5Sriastradh    OUT_CS_REG(R300_GA_COLOR_CONTROL,
10293464ebd5Sriastradh            r300_provoking_vertex_fixes(r300, r300render->prim));
10303464ebd5Sriastradh    OUT_CS_REG(R300_VAP_VF_MAX_VTX_INDX, count - 1);
10314a49301eSmrg    OUT_CS_PKT3(R300_PACKET3_3D_DRAW_VBUF_2, 0);
10324a49301eSmrg    OUT_CS(R300_VAP_VF_CNTL__PRIM_WALK_VERTEX_LIST | (count << 16) |
10334a49301eSmrg           r300render->hwprim);
10344a49301eSmrg    END_CS;
10354a49301eSmrg}
10364a49301eSmrg
10373464ebd5Sriastradhstatic void r300_render_draw_elements(struct vbuf_render* render,
10383464ebd5Sriastradh                                      const ushort* indices,
10393464ebd5Sriastradh                                      uint count)
10404a49301eSmrg{
10414a49301eSmrg    struct r300_render* r300render = r300_render(render);
10424a49301eSmrg    struct r300_context* r300 = r300render->r300;
1043af69d88dSmrg    unsigned max_index = (r300->vbo->size - r300->draw_vbo_offset) /
10443464ebd5Sriastradh                         (r300render->r300->vertex_info.size * 4) - 1;
1045af69d88dSmrg    struct pipe_resource *index_buffer = NULL;
1046af69d88dSmrg    unsigned index_buffer_offset;
10474a49301eSmrg
10484a49301eSmrg    CS_LOCALS(r300);
10493464ebd5Sriastradh    DBG(r300, DBG_DRAW, "r300: render_draw_elements (count: %d)\n", count);
10504a49301eSmrg
105101e04c3fSmrg    u_upload_data(r300->uploader, 0, count * 2, 4, indices,
1052af69d88dSmrg                  &index_buffer_offset, &index_buffer);
1053af69d88dSmrg    if (!index_buffer) {
1054af69d88dSmrg        return;
10554a49301eSmrg    }
10563464ebd5Sriastradh
1057af69d88dSmrg    if (!r300_prepare_for_rendering(r300,
1058af69d88dSmrg                                    PREP_EMIT_STATES |
1059af69d88dSmrg                                    PREP_EMIT_VARRAYS_SWTCL | PREP_INDEXED,
1060af69d88dSmrg                                    index_buffer, 12, 0, 0, -1)) {
1061af69d88dSmrg        pipe_resource_reference(&index_buffer, NULL);
1062af69d88dSmrg        return;
1063af69d88dSmrg    }
10643464ebd5Sriastradh
1065af69d88dSmrg    BEGIN_CS(12);
1066af69d88dSmrg    OUT_CS_REG(R300_GA_COLOR_CONTROL,
1067af69d88dSmrg               r300_provoking_vertex_fixes(r300, r300render->prim));
1068af69d88dSmrg    OUT_CS_REG(R300_VAP_VF_MAX_VTX_INDX, max_index);
10693464ebd5Sriastradh
1070af69d88dSmrg    OUT_CS_PKT3(R300_PACKET3_3D_DRAW_INDX_2, 0);
1071af69d88dSmrg    OUT_CS(R300_VAP_VF_CNTL__PRIM_WALK_INDICES | (count << 16) |
1072af69d88dSmrg           r300render->hwprim);
10733464ebd5Sriastradh
1074af69d88dSmrg    OUT_CS_PKT3(R300_PACKET3_INDX_BUFFER, 2);
1075af69d88dSmrg    OUT_CS(R300_INDX_BUFFER_ONE_REG_WR | (R300_VAP_PORT_IDX0 >> 2));
1076af69d88dSmrg    OUT_CS(index_buffer_offset);
1077af69d88dSmrg    OUT_CS((count + 1) / 2);
1078af69d88dSmrg    OUT_CS_RELOC(r300_resource(index_buffer));
1079af69d88dSmrg    END_CS;
10803464ebd5Sriastradh
1081af69d88dSmrg    pipe_resource_reference(&index_buffer, NULL);
10824a49301eSmrg}
10834a49301eSmrg
10844a49301eSmrgstatic void r300_render_destroy(struct vbuf_render* render)
10854a49301eSmrg{
10864a49301eSmrg    FREE(render);
10874a49301eSmrg}
10884a49301eSmrg
10894a49301eSmrgstatic struct vbuf_render* r300_render_create(struct r300_context* r300)
10904a49301eSmrg{
10914a49301eSmrg    struct r300_render* r300render = CALLOC_STRUCT(r300_render);
10924a49301eSmrg
10934a49301eSmrg    r300render->r300 = r300;
10944a49301eSmrg
1095af69d88dSmrg    r300render->base.max_vertex_buffer_bytes = R300_MAX_DRAW_VBO_SIZE;
10964a49301eSmrg    r300render->base.max_indices = 16 * 1024;
10974a49301eSmrg
10984a49301eSmrg    r300render->base.get_vertex_info = r300_render_get_vertex_info;
10994a49301eSmrg    r300render->base.allocate_vertices = r300_render_allocate_vertices;
11004a49301eSmrg    r300render->base.map_vertices = r300_render_map_vertices;
11014a49301eSmrg    r300render->base.unmap_vertices = r300_render_unmap_vertices;
11024a49301eSmrg    r300render->base.set_primitive = r300_render_set_primitive;
11033464ebd5Sriastradh    r300render->base.draw_elements = r300_render_draw_elements;
11044a49301eSmrg    r300render->base.draw_arrays = r300_render_draw_arrays;
11054a49301eSmrg    r300render->base.release_vertices = r300_render_release_vertices;
11064a49301eSmrg    r300render->base.destroy = r300_render_destroy;
11074a49301eSmrg
11084a49301eSmrg    return &r300render->base;
11094a49301eSmrg}
11104a49301eSmrg
11114a49301eSmrgstruct draw_stage* r300_draw_stage(struct r300_context* r300)
11124a49301eSmrg{
11134a49301eSmrg    struct vbuf_render* render;
11144a49301eSmrg    struct draw_stage* stage;
11154a49301eSmrg
11164a49301eSmrg    render = r300_render_create(r300);
11174a49301eSmrg
11184a49301eSmrg    if (!render) {
11194a49301eSmrg        return NULL;
11204a49301eSmrg    }
11214a49301eSmrg
11224a49301eSmrg    stage = draw_vbuf_stage(r300->draw, render);
11234a49301eSmrg
11244a49301eSmrg    if (!stage) {
11254a49301eSmrg        render->destroy(render);
11264a49301eSmrg        return NULL;
11274a49301eSmrg    }
11284a49301eSmrg
11294a49301eSmrg    draw_set_render(r300->draw, render);
11304a49301eSmrg
11314a49301eSmrg    return stage;
11324a49301eSmrg}
11333464ebd5Sriastradh
11343464ebd5Sriastradh/****************************************************************************
11353464ebd5Sriastradh *                         End of SW TCL functions                          *
11363464ebd5Sriastradh ***************************************************************************/
11373464ebd5Sriastradh
11383464ebd5Sriastradh/* This functions is used to draw a rectangle for the blitter module.
11393464ebd5Sriastradh *
11403464ebd5Sriastradh * If we rendered a quad, the pixels on the main diagonal
11413464ebd5Sriastradh * would be computed and stored twice, which makes the clear/copy codepaths
11423464ebd5Sriastradh * somewhat inefficient. Instead we use a rectangular point sprite. */
1143af69d88dSmrgvoid r300_blitter_draw_rectangle(struct blitter_context *blitter,
114401e04c3fSmrg                                 void *vertex_elements_cso,
114501e04c3fSmrg                                 blitter_get_vs_func get_vs,
1146af69d88dSmrg                                 int x1, int y1, int x2, int y2,
114701e04c3fSmrg                                 float depth, unsigned num_instances,
1148af69d88dSmrg                                 enum blitter_attrib_type type,
114901e04c3fSmrg                                 const union blitter_attrib *attrib)
11503464ebd5Sriastradh{
11513464ebd5Sriastradh    struct r300_context *r300 = r300_context(util_blitter_get_pipe(blitter));
11523464ebd5Sriastradh    unsigned last_sprite_coord_enable = r300->sprite_coord_enable;
11533464ebd5Sriastradh    unsigned width = x2 - x1;
11543464ebd5Sriastradh    unsigned height = y2 - y1;
11553464ebd5Sriastradh    unsigned vertex_size =
11563464ebd5Sriastradh            type == UTIL_BLITTER_ATTRIB_COLOR || !r300->draw ? 8 : 4;
11573464ebd5Sriastradh    unsigned dwords = 13 + vertex_size +
115801e04c3fSmrg                      (type == UTIL_BLITTER_ATTRIB_TEXCOORD_XY ? 7 : 0);
115901e04c3fSmrg    static const union blitter_attrib zeros;
11603464ebd5Sriastradh    CS_LOCALS(r300);
11613464ebd5Sriastradh
1162af69d88dSmrg    /* XXX workaround for a lockup in MSAA resolve on SWTCL chipsets, this
1163af69d88dSmrg     * function most probably doesn't handle type=NONE correctly */
116401e04c3fSmrg    if ((!r300->screen->caps.has_tcl && type == UTIL_BLITTER_ATTRIB_NONE) ||
116501e04c3fSmrg        type == UTIL_BLITTER_ATTRIB_TEXCOORD_XYZW ||
116601e04c3fSmrg        num_instances > 1) {
116701e04c3fSmrg        util_blitter_draw_rectangle(blitter, vertex_elements_cso, get_vs,
116801e04c3fSmrg                                    x1, y1, x2, y2,
116901e04c3fSmrg                                    depth, num_instances, type, attrib);
11703464ebd5Sriastradh        return;
1171af69d88dSmrg    }
11723464ebd5Sriastradh
1173af69d88dSmrg    if (r300->skip_rendering)
1174af69d88dSmrg        return;
11753464ebd5Sriastradh
117601e04c3fSmrg    r300->context.bind_vertex_elements_state(&r300->context, vertex_elements_cso);
117701e04c3fSmrg    r300->context.bind_vs_state(&r300->context, get_vs(blitter));
117801e04c3fSmrg
117901e04c3fSmrg    if (type == UTIL_BLITTER_ATTRIB_TEXCOORD_XY)
11803464ebd5Sriastradh        r300->sprite_coord_enable = 1;
11813464ebd5Sriastradh
11823464ebd5Sriastradh    r300_update_derived_state(r300);
11833464ebd5Sriastradh
11843464ebd5Sriastradh    /* Mark some states we don't care about as non-dirty. */
11853464ebd5Sriastradh    r300->viewport_state.dirty = FALSE;
11863464ebd5Sriastradh
11873464ebd5Sriastradh    if (!r300_prepare_for_rendering(r300, PREP_EMIT_STATES, NULL, dwords, 0, 0, -1))
11883464ebd5Sriastradh        goto done;
11893464ebd5Sriastradh
11903464ebd5Sriastradh    DBG(r300, DBG_DRAW, "r300: draw_rectangle\n");
11913464ebd5Sriastradh
11923464ebd5Sriastradh    BEGIN_CS(dwords);
11933464ebd5Sriastradh    /* Set up GA. */
11943464ebd5Sriastradh    OUT_CS_REG(R300_GA_POINT_SIZE, (height * 6) | ((width * 6) << 16));
11953464ebd5Sriastradh
119601e04c3fSmrg    if (type == UTIL_BLITTER_ATTRIB_TEXCOORD_XY) {
11973464ebd5Sriastradh        /* Set up the GA to generate texcoords. */
11983464ebd5Sriastradh        OUT_CS_REG(R300_GB_ENABLE, R300_GB_POINT_STUFF_ENABLE |
11993464ebd5Sriastradh                   (R300_GB_TEX_STR << R300_GB_TEX0_SOURCE_SHIFT));
12003464ebd5Sriastradh        OUT_CS_REG_SEQ(R300_GA_POINT_S0, 4);
120101e04c3fSmrg        OUT_CS_32F(attrib->texcoord.x1);
120201e04c3fSmrg        OUT_CS_32F(attrib->texcoord.y2);
120301e04c3fSmrg        OUT_CS_32F(attrib->texcoord.x2);
120401e04c3fSmrg        OUT_CS_32F(attrib->texcoord.y1);
12053464ebd5Sriastradh    }
12063464ebd5Sriastradh
12073464ebd5Sriastradh    /* Set up VAP controls. */
12083464ebd5Sriastradh    OUT_CS_REG(R300_VAP_CLIP_CNTL, R300_CLIP_DISABLE);
12093464ebd5Sriastradh    OUT_CS_REG(R300_VAP_VTE_CNTL, R300_VTX_XY_FMT | R300_VTX_Z_FMT);
12103464ebd5Sriastradh    OUT_CS_REG(R300_VAP_VTX_SIZE, vertex_size);
12113464ebd5Sriastradh    OUT_CS_REG_SEQ(R300_VAP_VF_MAX_VTX_INDX, 2);
12123464ebd5Sriastradh    OUT_CS(1);
12133464ebd5Sriastradh    OUT_CS(0);
12143464ebd5Sriastradh
12153464ebd5Sriastradh    /* Draw. */
12163464ebd5Sriastradh    OUT_CS_PKT3(R300_PACKET3_3D_DRAW_IMMD_2, vertex_size);
12173464ebd5Sriastradh    OUT_CS(R300_VAP_VF_CNTL__PRIM_WALK_VERTEX_EMBEDDED | (1 << 16) |
12183464ebd5Sriastradh           R300_VAP_VF_CNTL__PRIM_POINTS);
12193464ebd5Sriastradh
12203464ebd5Sriastradh    OUT_CS_32F(x1 + width * 0.5f);
12213464ebd5Sriastradh    OUT_CS_32F(y1 + height * 0.5f);
12223464ebd5Sriastradh    OUT_CS_32F(depth);
12233464ebd5Sriastradh    OUT_CS_32F(1);
12243464ebd5Sriastradh
12253464ebd5Sriastradh    if (vertex_size == 8) {
12263464ebd5Sriastradh        if (!attrib)
1227af69d88dSmrg            attrib = &zeros;
122801e04c3fSmrg        OUT_CS_TABLE(attrib->color, 4);
12293464ebd5Sriastradh    }
12303464ebd5Sriastradh    END_CS;
12313464ebd5Sriastradh
12323464ebd5Sriastradhdone:
12333464ebd5Sriastradh    /* Restore the state. */
12343464ebd5Sriastradh    r300_mark_atom_dirty(r300, &r300->rs_state);
12353464ebd5Sriastradh    r300_mark_atom_dirty(r300, &r300->viewport_state);
12363464ebd5Sriastradh
12373464ebd5Sriastradh    r300->sprite_coord_enable = last_sprite_coord_enable;
12383464ebd5Sriastradh}
12393464ebd5Sriastradh
12403464ebd5Sriastradhvoid r300_init_render_functions(struct r300_context *r300)
12413464ebd5Sriastradh{
12423464ebd5Sriastradh    /* Set draw functions based on presence of HW TCL. */
12433464ebd5Sriastradh    if (r300->screen->caps.has_tcl) {
12443464ebd5Sriastradh        r300->context.draw_vbo = r300_draw_vbo;
12453464ebd5Sriastradh    } else {
12463464ebd5Sriastradh        r300->context.draw_vbo = r300_swtcl_draw_vbo;
12473464ebd5Sriastradh    }
12483464ebd5Sriastradh
12493464ebd5Sriastradh    /* Plug in the two-sided stencil reference value fallback if needed. */
12503464ebd5Sriastradh    if (!r300->screen->caps.is_r500)
12513464ebd5Sriastradh        r300_plug_in_stencil_ref_fallback(r300);
12523464ebd5Sriastradh}
1253