r300_render.c revision 8648c2685870174cf620ef15de70ef030a8d5a20
1/*
2 * Copyright 2009 Corbin Simpson <MostAwesomeDude@gmail.com>
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * on the rights to use, copy, modify, merge, publish, distribute, sub
8 * license, and/or sell copies of the Software, and to permit persons to whom
9 * the Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
19 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
20 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
21 * USE OR OTHER DEALINGS IN THE SOFTWARE. */
22
23#include "draw/draw_pipe.h"
24#include "draw/draw_vbuf.h"
25#include "util/u_memory.h"
26
27#include "r300_cs.h"
28#include "r300_context.h"
29#include "r300_reg.h"
30#include "r300_state_derived.h"
31
32/* r300_render: Vertex and index buffer primitive emission. */
33
34struct r300_render {
35    /* Parent class */
36    struct vbuf_render base;
37
38    /* Pipe context */
39    struct r300_context* r300;
40
41    /* Vertex information */
42    size_t vertex_size;
43    unsigned prim;
44    unsigned hwprim;
45
46    /* VBO */
47    struct pipe_buffer* vbo;
48    size_t vbo_size;
49    size_t vbo_offset;
50    void* vbo_map;
51    size_t vbo_alloc_size;
52    size_t vbo_max_used;
53};
54
55static INLINE struct r300_render*
56r300_render(struct vbuf_render* render)
57{
58    return (struct r300_render*)render;
59}
60
61static const struct vertex_info*
62r300_render_get_vertex_info(struct vbuf_render* render)
63{
64    struct r300_render* r300render = r300_render(render);
65    struct r300_context* r300 = r300render->r300;
66
67    r300_update_derived_state(r300);
68
69    return &r300->vertex_info.vinfo;
70}
71
72static boolean r300_render_allocate_vertices(struct vbuf_render* render,
73                                                   ushort vertex_size,
74                                                   ushort count)
75{
76    struct r300_render* r300render = r300_render(render);
77    struct r300_context* r300 = r300render->r300;
78    struct pipe_screen* screen = r300->context.screen;
79    size_t size = (size_t)vertex_size * (size_t)count;
80
81    if (r300render->vbo) {
82        pipe_buffer_reference(&r300render->vbo, NULL);
83    }
84
85    r300render->vbo_size = MAX2(size, r300render->vbo_alloc_size);
86    r300render->vbo_offset = 0;
87    r300render->vbo = pipe_buffer_create(screen,
88                                         64,
89                                         PIPE_BUFFER_USAGE_VERTEX,
90                                         r300render->vbo_size);
91
92    r300render->vertex_size = vertex_size;
93
94    if (r300render->vbo) {
95        return TRUE;
96    } else {
97        return FALSE;
98    }
99}
100
101static void* r300_render_map_vertices(struct vbuf_render* render)
102{
103    struct r300_render* r300render = r300_render(render);
104    struct pipe_screen* screen = r300render->r300->context.screen;
105
106    r300render->vbo_map = pipe_buffer_map(screen, r300render->vbo,
107                                          PIPE_BUFFER_USAGE_CPU_WRITE);
108
109    return (unsigned char*)r300render->vbo_map + r300render->vbo_offset;
110}
111
112static void r300_render_unmap_vertices(struct vbuf_render* render,
113                                             ushort min,
114                                             ushort max)
115{
116    struct r300_render* r300render = r300_render(render);
117    struct pipe_screen* screen = r300render->r300->context.screen;
118
119    r300render->vbo_max_used = MAX2(r300render->vbo_max_used,
120             r300render->vertex_size * (max + 1));
121
122    pipe_buffer_unmap(screen, r300render->vbo);
123}
124
125static void r300_render_release_vertices(struct vbuf_render* render)
126{
127    struct r300_render* r300render = r300_render(render);
128
129    pipe_buffer_reference(&r300render->vbo, NULL);
130}
131
132static boolean r300_render_set_primitive(struct vbuf_render* render,
133                                               unsigned prim)
134{
135    struct r300_render* r300render = r300_render(render);
136    r300render->prim = prim;
137
138    switch (prim) {
139        case PIPE_PRIM_POINTS:
140            r300render->hwprim = R300_VAP_VF_CNTL__PRIM_POINTS;
141            break;
142        case PIPE_PRIM_LINES:
143            r300render->hwprim = R300_VAP_VF_CNTL__PRIM_LINES;
144            break;
145        case PIPE_PRIM_LINE_LOOP:
146            r300render->hwprim = R300_VAP_VF_CNTL__PRIM_LINE_LOOP;
147            break;
148        case PIPE_PRIM_LINE_STRIP:
149            r300render->hwprim = R300_VAP_VF_CNTL__PRIM_LINE_STRIP;
150            break;
151        case PIPE_PRIM_TRIANGLES:
152            r300render->hwprim = R300_VAP_VF_CNTL__PRIM_TRIANGLES;
153            break;
154        case PIPE_PRIM_TRIANGLE_STRIP:
155            r300render->hwprim = R300_VAP_VF_CNTL__PRIM_TRIANGLE_STRIP;
156            break;
157        case PIPE_PRIM_TRIANGLE_FAN:
158            r300render->hwprim = R300_VAP_VF_CNTL__PRIM_TRIANGLE_FAN;
159            break;
160        case PIPE_PRIM_QUADS:
161            r300render->hwprim = R300_VAP_VF_CNTL__PRIM_QUADS;
162            break;
163        case PIPE_PRIM_QUAD_STRIP:
164            r300render->hwprim = R300_VAP_VF_CNTL__PRIM_QUAD_STRIP;
165            break;
166        case PIPE_PRIM_POLYGON:
167            r300render->hwprim = R300_VAP_VF_CNTL__PRIM_POLYGON;
168            break;
169        default:
170            return FALSE;
171            break;
172    }
173
174    return TRUE;
175}
176
177static void prepare_render(struct r300_render* render, unsigned count)
178{
179    struct r300_context* r300 = render->r300;
180
181    CS_LOCALS(r300);
182
183    /* Make sure that all possible state is emitted. */
184    r300_emit_dirty_state(r300);
185
186    debug_printf("r300: Preparing vertex buffer %p for render, "
187            "vertex size %d, vertex count %d\n", render->vbo,
188            r300->vertex_info.vinfo.size, count);
189    /* Set the pointer to our vertex buffer. The emitted values are this:
190     * PACKET3 [3D_LOAD_VBPNTR]
191     * COUNT   [1]
192     * FORMAT  [size | stride << 8]
193     * OFFSET  [0]
194     * VBPNTR  [relocated BO]
195     */
196    BEGIN_CS(7);
197    OUT_CS_PKT3(R300_PACKET3_3D_LOAD_VBPNTR, 3);
198    OUT_CS(1);
199    OUT_CS(r300->vertex_info.vinfo.size |
200            (r300->vertex_info.vinfo.size << 8));
201    OUT_CS(render->vbo_offset);
202    OUT_CS_RELOC(render->vbo, 0, RADEON_GEM_DOMAIN_GTT, 0, 0);
203    END_CS;
204}
205
206static void r300_render_draw_arrays(struct vbuf_render* render,
207                                          unsigned start,
208                                          unsigned count)
209{
210    struct r300_render* r300render = r300_render(render);
211    struct r300_context* r300 = r300render->r300;
212
213    CS_LOCALS(r300);
214
215    r300render->vbo_offset = start;
216
217    prepare_render(r300render, count);
218
219    debug_printf("r300: Doing vbuf render, count %d\n", count);
220
221    BEGIN_CS(2);
222    OUT_CS_PKT3(R300_PACKET3_3D_DRAW_VBUF_2, 0);
223    OUT_CS(R300_VAP_VF_CNTL__PRIM_WALK_VERTEX_LIST | (count << 16) |
224           r300render->hwprim);
225    END_CS;
226}
227
228static void r300_render_draw(struct vbuf_render* render,
229                                   const ushort* indices,
230                                   uint count)
231{
232    struct r300_render* r300render = r300_render(render);
233    struct r300_context* r300 = r300render->r300;
234    struct pipe_screen* screen = r300->context.screen;
235    struct pipe_buffer* index_buffer;
236    void* index_map;
237
238    CS_LOCALS(r300);
239
240    prepare_render(r300render, count);
241
242    /* Send our indices into an index buffer. */
243    index_buffer = pipe_buffer_create(screen, 64, PIPE_BUFFER_USAGE_VERTEX,
244                                      count * 2);
245    if (!index_buffer) {
246        return;
247    }
248
249    index_map = pipe_buffer_map(screen, index_buffer,
250                                PIPE_BUFFER_USAGE_CPU_WRITE);
251    memcpy(index_map, indices, count);
252    pipe_buffer_unmap(screen, index_buffer);
253
254    debug_printf("r300: Doing indexbuf render, count %d\n", count);
255
256    BEGIN_CS(6);
257    OUT_CS_PKT3(R300_PACKET3_3D_DRAW_INDX_2, 0);
258    OUT_CS(R300_VAP_VF_CNTL__PRIM_WALK_INDICES | (count << 16) |
259           r300render->hwprim);
260    OUT_CS_PKT3(R300_PACKET3_INDX_BUFFER, 2);
261    OUT_CS(R300_INDX_BUFFER_ONE_REG_WR | (R300_VAP_PORT_IDX0 >> 2));
262    OUT_CS_INDEX_RELOC(index_buffer, 0, count, RADEON_GEM_DOMAIN_GTT, 0, 0);
263    END_CS;
264}
265
266static void r300_render_destroy(struct vbuf_render* render)
267{
268    FREE(render);
269}
270
271static struct vbuf_render* r300_render_create(struct r300_context* r300)
272{
273    struct r300_render* r300render = CALLOC_STRUCT(r300_render);
274
275    r300render->r300 = r300;
276
277    /* XXX find real numbers plz */
278    r300render->base.max_vertex_buffer_bytes = 128 * 1024;
279    r300render->base.max_indices = 16 * 1024;
280
281    r300render->base.get_vertex_info = r300_render_get_vertex_info;
282    r300render->base.allocate_vertices = r300_render_allocate_vertices;
283    r300render->base.map_vertices = r300_render_map_vertices;
284    r300render->base.unmap_vertices = r300_render_unmap_vertices;
285    r300render->base.set_primitive = r300_render_set_primitive;
286    r300render->base.draw = r300_render_draw;
287    r300render->base.draw_arrays = r300_render_draw_arrays;
288    r300render->base.release_vertices = r300_render_release_vertices;
289    r300render->base.destroy = r300_render_destroy;
290
291    return &r300render->base;
292}
293
294struct draw_stage* r300_draw_stage(struct r300_context* r300)
295{
296    struct vbuf_render* render;
297    struct draw_stage* stage;
298
299    render = r300_render_create(r300);
300
301    if (!render) {
302        return NULL;
303    }
304
305    stage = draw_vbuf_stage(r300->draw, render);
306
307    if (!stage) {
308        render->destroy(render);
309        return NULL;
310    }
311
312    draw_set_render(r300->draw, render);
313
314    return stage;
315}
316