vc4_draw.c revision 848b8605
1/*
2 * Copyright (c) 2014 Scott Mansell
3 * Copyright © 2014 Broadcom
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the next
13 * paragraph) shall be included in all copies or substantial portions of the
14 * Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 * IN THE SOFTWARE.
23 */
24
25#include <stdio.h>
26
27#include "util/u_format.h"
28#include "util/u_pack_color.h"
29#include "indices/u_primconvert.h"
30
31#include "vc4_context.h"
32#include "vc4_resource.h"
33
34/**
35 * Does the initial bining command list setup for drawing to a given FBO.
36 */
37static void
38vc4_start_draw(struct vc4_context *vc4)
39{
40        if (vc4->needs_flush)
41                return;
42
43        uint32_t width = vc4->framebuffer.width;
44        uint32_t height = vc4->framebuffer.height;
45        uint32_t tilew = align(width, 64) / 64;
46        uint32_t tileh = align(height, 64) / 64;
47
48        /* Tile alloc memory setup: We use an initial alloc size of 32b.  The
49         * hardware then aligns that to 256b (we use 4096, because all of our
50         * BO allocations align to that anyway), then for some reason the
51         * simulator wants an extra page available, even if you have overflow
52         * memory set up.
53         */
54        uint32_t tile_alloc_size = 32 * tilew * tileh;
55        tile_alloc_size = align(tile_alloc_size, 4096);
56        tile_alloc_size += 4096;
57        uint32_t tile_state_size = 48 * tilew * tileh;
58        if (!vc4->tile_alloc || vc4->tile_alloc->size < tile_alloc_size) {
59                vc4_bo_unreference(&vc4->tile_alloc);
60                vc4->tile_alloc = vc4_bo_alloc(vc4->screen, tile_alloc_size,
61                                               "tile_alloc");
62        }
63        if (!vc4->tile_state || vc4->tile_state->size < tile_state_size) {
64                vc4_bo_unreference(&vc4->tile_state);
65                vc4->tile_state = vc4_bo_alloc(vc4->screen, tile_state_size,
66                                               "tile_state");
67        }
68
69        //   Tile state data is 48 bytes per tile, I think it can be thrown away
70        //   as soon as binning is finished.
71        cl_start_reloc(&vc4->bcl, 2);
72        cl_u8(&vc4->bcl, VC4_PACKET_TILE_BINNING_MODE_CONFIG);
73        cl_reloc(vc4, &vc4->bcl, vc4->tile_alloc, 0);
74        cl_u32(&vc4->bcl, vc4->tile_alloc->size);
75        cl_reloc(vc4, &vc4->bcl, vc4->tile_state, 0);
76        cl_u8(&vc4->bcl, tilew);
77        cl_u8(&vc4->bcl, tileh);
78        cl_u8(&vc4->bcl,
79              VC4_BIN_CONFIG_AUTO_INIT_TSDA |
80              VC4_BIN_CONFIG_ALLOC_BLOCK_SIZE_32 |
81              VC4_BIN_CONFIG_ALLOC_INIT_BLOCK_SIZE_32);
82
83        cl_u8(&vc4->bcl, VC4_PACKET_START_TILE_BINNING);
84
85        vc4->needs_flush = true;
86        vc4->draw_call_queued = true;
87}
88
89static void
90vc4_draw_vbo(struct pipe_context *pctx, const struct pipe_draw_info *info)
91{
92        struct vc4_context *vc4 = vc4_context(pctx);
93
94        if (info->mode >= PIPE_PRIM_QUADS) {
95                util_primconvert_save_index_buffer(vc4->primconvert, &vc4->indexbuf);
96                util_primconvert_save_rasterizer_state(vc4->primconvert, &vc4->rasterizer->base);
97                util_primconvert_draw_vbo(vc4->primconvert, info);
98                return;
99        }
100
101        vc4_start_draw(vc4);
102        vc4_update_compiled_shaders(vc4, info->mode);
103
104        vc4_emit_state(pctx);
105
106        /* the actual draw call. */
107        struct vc4_vertex_stateobj *vtx = vc4->vtx;
108        struct vc4_vertexbuf_stateobj *vertexbuf = &vc4->vertexbuf;
109        cl_u8(&vc4->bcl, VC4_PACKET_GL_SHADER_STATE);
110        assert(vtx->num_elements <= 8);
111        /* Note that number of attributes == 0 in the packet means 8
112         * attributes.  This field also contains the offset into shader_rec.
113         */
114        cl_u32(&vc4->bcl, vtx->num_elements & 0x7);
115
116        /* Note that the primitive type fields match with OpenGL/gallium
117         * definitions, up to but not including QUADS.
118         */
119        if (info->indexed) {
120                struct vc4_resource *rsc = vc4_resource(vc4->indexbuf.buffer);
121
122                assert(vc4->indexbuf.index_size == 1 ||
123                       vc4->indexbuf.index_size == 2);
124
125                cl_start_reloc(&vc4->bcl, 1);
126                cl_u8(&vc4->bcl, VC4_PACKET_GL_INDEXED_PRIMITIVE);
127                cl_u8(&vc4->bcl,
128                      info->mode |
129                      (vc4->indexbuf.index_size == 2 ?
130                       VC4_INDEX_BUFFER_U16:
131                       VC4_INDEX_BUFFER_U8));
132                cl_u32(&vc4->bcl, info->count);
133                cl_reloc(vc4, &vc4->bcl, rsc->bo, vc4->indexbuf.offset);
134                cl_u32(&vc4->bcl, info->max_index);
135        } else {
136                cl_u8(&vc4->bcl, VC4_PACKET_GL_ARRAY_PRIMITIVE);
137                cl_u8(&vc4->bcl, info->mode);
138                cl_u32(&vc4->bcl, info->count);
139                cl_u32(&vc4->bcl, info->start);
140        }
141
142// Shader Record
143
144        vc4_write_uniforms(vc4, vc4->prog.fs,
145                           &vc4->constbuf[PIPE_SHADER_FRAGMENT],
146                           &vc4->fragtex,
147                           0);
148        vc4_write_uniforms(vc4, vc4->prog.vs,
149                           &vc4->constbuf[PIPE_SHADER_VERTEX],
150                           &vc4->verttex,
151                           0);
152        vc4_write_uniforms(vc4, vc4->prog.vs,
153                           &vc4->constbuf[PIPE_SHADER_VERTEX],
154                           &vc4->verttex,
155                           1);
156
157        cl_start_shader_reloc(&vc4->shader_rec, 3 + vtx->num_elements);
158        cl_u16(&vc4->shader_rec, VC4_SHADER_FLAG_ENABLE_CLIPPING);
159        cl_u8(&vc4->shader_rec, 0); /* fs num uniforms (unused) */
160        cl_u8(&vc4->shader_rec, vc4->prog.fs->num_inputs);
161        cl_reloc(vc4, &vc4->shader_rec, vc4->prog.fs->bo, 0);
162        cl_u32(&vc4->shader_rec, 0); /* UBO offset written by kernel */
163
164        cl_u16(&vc4->shader_rec, 0); /* vs num uniforms */
165        cl_u8(&vc4->shader_rec, (1 << vtx->num_elements) - 1); /* vs attribute array bitfield */
166        cl_u8(&vc4->shader_rec, 16 * vtx->num_elements); /* vs total attribute size */
167        cl_reloc(vc4, &vc4->shader_rec, vc4->prog.vs->bo, 0);
168        cl_u32(&vc4->shader_rec, 0); /* UBO offset written by kernel */
169
170        cl_u16(&vc4->shader_rec, 0); /* cs num uniforms */
171        cl_u8(&vc4->shader_rec, (1 << vtx->num_elements) - 1); /* cs attribute array bitfield */
172        cl_u8(&vc4->shader_rec, 16 * vtx->num_elements); /* vs total attribute size */
173        cl_reloc(vc4, &vc4->shader_rec, vc4->prog.vs->bo,
174                vc4->prog.vs->coord_shader_offset);
175        cl_u32(&vc4->shader_rec, 0); /* UBO offset written by kernel */
176
177        for (int i = 0; i < vtx->num_elements; i++) {
178                struct pipe_vertex_element *elem = &vtx->pipe[i];
179                struct pipe_vertex_buffer *vb =
180                        &vertexbuf->vb[elem->vertex_buffer_index];
181                struct vc4_resource *rsc = vc4_resource(vb->buffer);
182
183                cl_reloc(vc4, &vc4->shader_rec, rsc->bo,
184                         vb->buffer_offset + elem->src_offset);
185                cl_u8(&vc4->shader_rec,
186                      util_format_get_blocksize(elem->src_format) - 1);
187                cl_u8(&vc4->shader_rec, vb->stride);
188                cl_u8(&vc4->shader_rec, i * 16); /* VS VPM offset */
189                cl_u8(&vc4->shader_rec, i * 16); /* CS VPM offset */
190        }
191
192        if (vc4->zsa && vc4->zsa->base.depth.enabled) {
193                vc4->resolve |= PIPE_CLEAR_DEPTH;
194        }
195        vc4->resolve |= PIPE_CLEAR_COLOR0;
196
197        vc4->shader_rec_count++;
198}
199
200static uint32_t
201pack_rgba(enum pipe_format format, const float *rgba)
202{
203        union util_color uc;
204        util_pack_color(rgba, format, &uc);
205        return uc.ui[0];
206}
207
208static void
209vc4_clear(struct pipe_context *pctx, unsigned buffers,
210          const union pipe_color_union *color, double depth, unsigned stencil)
211{
212        struct vc4_context *vc4 = vc4_context(pctx);
213
214        /* We can't flag new buffers for clearing once we've queued draws.  We
215         * could avoid this by using the 3d engine to clear.
216         */
217        if (vc4->draw_call_queued)
218                vc4_flush(pctx);
219
220        if (buffers & PIPE_CLEAR_COLOR0) {
221                vc4->clear_color[0] = vc4->clear_color[1] =
222                        pack_rgba(vc4->framebuffer.cbufs[0]->format,
223                                  color->f);
224        }
225
226        if (buffers & PIPE_CLEAR_DEPTH)
227                vc4->clear_depth = util_pack_z(PIPE_FORMAT_Z24X8_UNORM, depth);
228
229        vc4->cleared |= buffers;
230        vc4->resolve |= buffers;
231
232        vc4_start_draw(vc4);
233}
234
235static void
236vc4_clear_render_target(struct pipe_context *pctx, struct pipe_surface *ps,
237                        const union pipe_color_union *color,
238                        unsigned x, unsigned y, unsigned w, unsigned h)
239{
240        fprintf(stderr, "unimpl: clear RT\n");
241}
242
243static void
244vc4_clear_depth_stencil(struct pipe_context *pctx, struct pipe_surface *ps,
245                        unsigned buffers, double depth, unsigned stencil,
246                        unsigned x, unsigned y, unsigned w, unsigned h)
247{
248        fprintf(stderr, "unimpl: clear DS\n");
249}
250
251void
252vc4_draw_init(struct pipe_context *pctx)
253{
254        pctx->draw_vbo = vc4_draw_vbo;
255        pctx->clear = vc4_clear;
256        pctx->clear_render_target = vc4_clear_render_target;
257        pctx->clear_depth_stencil = vc4_clear_depth_stencil;
258}
259