freedreno: only do extra vertex-buffer state logic on a2xx
[mesa.git] / src / gallium / drivers / freedreno / freedreno_state.c
1 /* -*- mode: C; c-file-style: "k&r"; tab-width 4; indent-tabs-mode: t; -*- */
2
3 /*
4 * Copyright (C) 2012 Rob Clark <robclark@freedesktop.org>
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice (including the next
14 * paragraph) shall be included in all copies or substantial portions of the
15 * Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 * SOFTWARE.
24 *
25 * Authors:
26 * Rob Clark <robclark@freedesktop.org>
27 */
28
29 #include "pipe/p_state.h"
30 #include "util/u_dual_blend.h"
31 #include "util/u_string.h"
32 #include "util/u_memory.h"
33 #include "util/u_helpers.h"
34
35 #include "freedreno_state.h"
36 #include "freedreno_context.h"
37 #include "freedreno_resource.h"
38 #include "freedreno_texture.h"
39 #include "freedreno_gmem.h"
40 #include "freedreno_util.h"
41
42 /* All the generic state handling.. In case of CSO's that are specific
43 * to the GPU version, when the bind and the delete are common they can
44 * go in here.
45 */
46
47 static void
48 fd_set_blend_color(struct pipe_context *pctx,
49 const struct pipe_blend_color *blend_color)
50 {
51 struct fd_context *ctx = fd_context(pctx);
52 ctx->blend_color = *blend_color;
53 ctx->dirty |= FD_DIRTY_BLEND_COLOR;
54 }
55
56 static void
57 fd_set_stencil_ref(struct pipe_context *pctx,
58 const struct pipe_stencil_ref *stencil_ref)
59 {
60 struct fd_context *ctx = fd_context(pctx);
61 ctx->stencil_ref =* stencil_ref;
62 ctx->dirty |= FD_DIRTY_STENCIL_REF;
63 }
64
65 static void
66 fd_set_clip_state(struct pipe_context *pctx,
67 const struct pipe_clip_state *clip)
68 {
69 struct fd_context *ctx = fd_context(pctx);
70 ctx->ucp = *clip;
71 ctx->dirty |= FD_DIRTY_UCP;
72 }
73
74 static void
75 fd_set_sample_mask(struct pipe_context *pctx, unsigned sample_mask)
76 {
77 struct fd_context *ctx = fd_context(pctx);
78 ctx->sample_mask = (uint16_t)sample_mask;
79 ctx->dirty |= FD_DIRTY_SAMPLE_MASK;
80 }
81
82 /* notes from calim on #dri-devel:
83 * index==0 will be non-UBO (ie. glUniformXYZ()) all packed together padded
84 * out to vec4's
85 * I should be able to consider that I own the user_ptr until the next
86 * set_constant_buffer() call, at which point I don't really care about the
87 * previous values.
88 * index>0 will be UBO's.. well, I'll worry about that later
89 */
90 static void
91 fd_set_constant_buffer(struct pipe_context *pctx, uint shader, uint index,
92 struct pipe_constant_buffer *cb)
93 {
94 struct fd_context *ctx = fd_context(pctx);
95 struct fd_constbuf_stateobj *so = &ctx->constbuf[shader];
96
97 util_copy_constant_buffer(&so->cb[index], cb);
98
99 /* Note that the state tracker can unbind constant buffers by
100 * passing NULL here.
101 */
102 if (unlikely(!cb)) {
103 so->enabled_mask &= ~(1 << index);
104 so->dirty_mask &= ~(1 << index);
105 return;
106 }
107
108 so->enabled_mask |= 1 << index;
109 so->dirty_mask |= 1 << index;
110 ctx->dirty |= FD_DIRTY_CONSTBUF;
111 }
112
113 static void
114 fd_set_framebuffer_state(struct pipe_context *pctx,
115 const struct pipe_framebuffer_state *framebuffer)
116 {
117 struct fd_context *ctx = fd_context(pctx);
118 struct pipe_framebuffer_state *cso = &ctx->framebuffer;
119
120 DBG("%d: cbufs[0]=%p, zsbuf=%p", ctx->needs_flush,
121 framebuffer->cbufs[0], framebuffer->zsbuf);
122
123 fd_context_render(pctx);
124
125 if ((cso->width != framebuffer->width) ||
126 (cso->height != framebuffer->height))
127 ctx->needs_rb_fbd = true;
128
129 util_copy_framebuffer_state(cso, framebuffer);
130
131 ctx->dirty |= FD_DIRTY_FRAMEBUFFER;
132
133 ctx->disabled_scissor.minx = 0;
134 ctx->disabled_scissor.miny = 0;
135 ctx->disabled_scissor.maxx = cso->width;
136 ctx->disabled_scissor.maxy = cso->height;
137
138 ctx->dirty |= FD_DIRTY_SCISSOR;
139 }
140
141 static void
142 fd_set_polygon_stipple(struct pipe_context *pctx,
143 const struct pipe_poly_stipple *stipple)
144 {
145 struct fd_context *ctx = fd_context(pctx);
146 ctx->stipple = *stipple;
147 ctx->dirty |= FD_DIRTY_STIPPLE;
148 }
149
150 static void
151 fd_set_scissor_states(struct pipe_context *pctx,
152 unsigned start_slot,
153 unsigned num_scissors,
154 const struct pipe_scissor_state *scissor)
155 {
156 struct fd_context *ctx = fd_context(pctx);
157
158 ctx->scissor = *scissor;
159 ctx->dirty |= FD_DIRTY_SCISSOR;
160 }
161
162 static void
163 fd_set_viewport_states(struct pipe_context *pctx,
164 unsigned start_slot,
165 unsigned num_viewports,
166 const struct pipe_viewport_state *viewport)
167 {
168 struct fd_context *ctx = fd_context(pctx);
169 ctx->viewport = *viewport;
170 ctx->dirty |= FD_DIRTY_VIEWPORT;
171 }
172
173 static void
174 fd_set_vertex_buffers(struct pipe_context *pctx,
175 unsigned start_slot, unsigned count,
176 const struct pipe_vertex_buffer *vb)
177 {
178 struct fd_context *ctx = fd_context(pctx);
179 struct fd_vertexbuf_stateobj *so = &ctx->vtx.vertexbuf;
180 int i;
181
182 /* on a2xx, pitch is encoded in the vtx fetch instruction, so
183 * we need to mark VTXSTATE as dirty as well to trigger patching
184 * and re-emitting the vtx shader:
185 */
186 if (ctx->screen->gpu_id < 300) {
187 for (i = 0; i < count; i++) {
188 bool new_enabled = vb && (vb[i].buffer || vb[i].user_buffer);
189 bool old_enabled = so->vb[i].buffer || so->vb[i].user_buffer;
190 uint32_t new_stride = vb ? vb[i].stride : 0;
191 uint32_t old_stride = so->vb[i].stride;
192 if ((new_enabled != old_enabled) || (new_stride != old_stride)) {
193 ctx->dirty |= FD_DIRTY_VTXSTATE;
194 break;
195 }
196 }
197 }
198
199 util_set_vertex_buffers_mask(so->vb, &so->enabled_mask, vb, start_slot, count);
200 so->count = util_last_bit(so->enabled_mask);
201
202 ctx->dirty |= FD_DIRTY_VTXBUF;
203 }
204
205 static void
206 fd_set_index_buffer(struct pipe_context *pctx,
207 const struct pipe_index_buffer *ib)
208 {
209 struct fd_context *ctx = fd_context(pctx);
210
211 if (ib) {
212 pipe_resource_reference(&ctx->indexbuf.buffer, ib->buffer);
213 ctx->indexbuf.index_size = ib->index_size;
214 ctx->indexbuf.offset = ib->offset;
215 ctx->indexbuf.user_buffer = ib->user_buffer;
216 } else {
217 pipe_resource_reference(&ctx->indexbuf.buffer, NULL);
218 }
219
220 ctx->dirty |= FD_DIRTY_INDEXBUF;
221 }
222
223 static void
224 fd_blend_state_bind(struct pipe_context *pctx, void *hwcso)
225 {
226 struct fd_context *ctx = fd_context(pctx);
227 struct pipe_blend_state *cso = hwcso;
228 bool old_is_dual = ctx->blend ?
229 ctx->blend->rt[0].blend_enable && util_blend_state_is_dual(ctx->blend, 0) :
230 false;
231 bool new_is_dual = cso ?
232 cso->rt[0].blend_enable && util_blend_state_is_dual(cso, 0) :
233 false;
234 ctx->blend = hwcso;
235 ctx->dirty |= FD_DIRTY_BLEND;
236 if (old_is_dual != new_is_dual)
237 ctx->dirty |= FD_DIRTY_BLEND_DUAL;
238 }
239
240 static void
241 fd_blend_state_delete(struct pipe_context *pctx, void *hwcso)
242 {
243 FREE(hwcso);
244 }
245
246 static void
247 fd_rasterizer_state_bind(struct pipe_context *pctx, void *hwcso)
248 {
249 struct fd_context *ctx = fd_context(pctx);
250 struct pipe_scissor_state *old_scissor = fd_context_get_scissor(ctx);
251
252 ctx->rasterizer = hwcso;
253 ctx->dirty |= FD_DIRTY_RASTERIZER;
254
255 /* if scissor enable bit changed we need to mark scissor
256 * state as dirty as well:
257 * NOTE: we can do a shallow compare, since we only care
258 * if it changed to/from &ctx->disable_scissor
259 */
260 if (old_scissor != fd_context_get_scissor(ctx))
261 ctx->dirty |= FD_DIRTY_SCISSOR;
262 }
263
264 static void
265 fd_rasterizer_state_delete(struct pipe_context *pctx, void *hwcso)
266 {
267 FREE(hwcso);
268 }
269
270 static void
271 fd_zsa_state_bind(struct pipe_context *pctx, void *hwcso)
272 {
273 struct fd_context *ctx = fd_context(pctx);
274 ctx->zsa = hwcso;
275 ctx->dirty |= FD_DIRTY_ZSA;
276 }
277
278 static void
279 fd_zsa_state_delete(struct pipe_context *pctx, void *hwcso)
280 {
281 FREE(hwcso);
282 }
283
284 static void *
285 fd_vertex_state_create(struct pipe_context *pctx, unsigned num_elements,
286 const struct pipe_vertex_element *elements)
287 {
288 struct fd_vertex_stateobj *so = CALLOC_STRUCT(fd_vertex_stateobj);
289
290 if (!so)
291 return NULL;
292
293 memcpy(so->pipe, elements, sizeof(*elements) * num_elements);
294 so->num_elements = num_elements;
295
296 return so;
297 }
298
299 static void
300 fd_vertex_state_delete(struct pipe_context *pctx, void *hwcso)
301 {
302 FREE(hwcso);
303 }
304
305 static void
306 fd_vertex_state_bind(struct pipe_context *pctx, void *hwcso)
307 {
308 struct fd_context *ctx = fd_context(pctx);
309 ctx->vtx.vtx = hwcso;
310 ctx->dirty |= FD_DIRTY_VTXSTATE;
311 }
312
313 static struct pipe_stream_output_target *
314 fd_create_stream_output_target(struct pipe_context *pctx,
315 struct pipe_resource *prsc, unsigned buffer_offset,
316 unsigned buffer_size)
317 {
318 struct pipe_stream_output_target *target;
319
320 target = CALLOC_STRUCT(pipe_stream_output_target);
321 if (!target)
322 return NULL;
323
324 pipe_reference_init(&target->reference, 1);
325 pipe_resource_reference(&target->buffer, prsc);
326
327 target->context = pctx;
328 target->buffer_offset = buffer_offset;
329 target->buffer_size = buffer_size;
330
331 return target;
332 }
333
334 static void
335 fd_stream_output_target_destroy(struct pipe_context *pctx,
336 struct pipe_stream_output_target *target)
337 {
338 pipe_resource_reference(&target->buffer, NULL);
339 FREE(target);
340 }
341
342 static void
343 fd_set_stream_output_targets(struct pipe_context *pctx,
344 unsigned num_targets, struct pipe_stream_output_target **targets,
345 const unsigned *offsets)
346 {
347 struct fd_context *ctx = fd_context(pctx);
348 struct fd_streamout_stateobj *so = &ctx->streamout;
349 unsigned i;
350
351 debug_assert(num_targets <= ARRAY_SIZE(so->targets));
352
353 for (i = 0; i < num_targets; i++) {
354 boolean changed = targets[i] != so->targets[i];
355 boolean append = (offsets[i] == (unsigned)-1);
356
357 if (!changed && append)
358 continue;
359
360 if (!append)
361 so->offsets[i] = offsets[i];
362
363 pipe_so_target_reference(&so->targets[i], targets[i]);
364 }
365
366 for (; i < so->num_targets; i++) {
367 pipe_so_target_reference(&so->targets[i], NULL);
368 }
369
370 so->num_targets = num_targets;
371
372 ctx->dirty |= FD_DIRTY_STREAMOUT;
373 }
374
375 void
376 fd_state_init(struct pipe_context *pctx)
377 {
378 pctx->set_blend_color = fd_set_blend_color;
379 pctx->set_stencil_ref = fd_set_stencil_ref;
380 pctx->set_clip_state = fd_set_clip_state;
381 pctx->set_sample_mask = fd_set_sample_mask;
382 pctx->set_constant_buffer = fd_set_constant_buffer;
383 pctx->set_framebuffer_state = fd_set_framebuffer_state;
384 pctx->set_polygon_stipple = fd_set_polygon_stipple;
385 pctx->set_scissor_states = fd_set_scissor_states;
386 pctx->set_viewport_states = fd_set_viewport_states;
387
388 pctx->set_vertex_buffers = fd_set_vertex_buffers;
389 pctx->set_index_buffer = fd_set_index_buffer;
390
391 pctx->bind_blend_state = fd_blend_state_bind;
392 pctx->delete_blend_state = fd_blend_state_delete;
393
394 pctx->bind_rasterizer_state = fd_rasterizer_state_bind;
395 pctx->delete_rasterizer_state = fd_rasterizer_state_delete;
396
397 pctx->bind_depth_stencil_alpha_state = fd_zsa_state_bind;
398 pctx->delete_depth_stencil_alpha_state = fd_zsa_state_delete;
399
400 pctx->create_vertex_elements_state = fd_vertex_state_create;
401 pctx->delete_vertex_elements_state = fd_vertex_state_delete;
402 pctx->bind_vertex_elements_state = fd_vertex_state_bind;
403
404 pctx->create_stream_output_target = fd_create_stream_output_target;
405 pctx->stream_output_target_destroy = fd_stream_output_target_destroy;
406 pctx->set_stream_output_targets = fd_set_stream_output_targets;
407 }