freedreno: use util_copy_constant_buffer() helper
[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 for (i = 0; i < count; i++) {
187 bool new_enabled = vb && (vb[i].buffer || vb[i].user_buffer);
188 bool old_enabled = so->vb[i].buffer || so->vb[i].user_buffer;
189 uint32_t new_stride = vb ? vb[i].stride : 0;
190 uint32_t old_stride = so->vb[i].stride;
191 if ((new_enabled != old_enabled) || (new_stride != old_stride)) {
192 ctx->dirty |= FD_DIRTY_VTXSTATE;
193 break;
194 }
195 }
196
197 util_set_vertex_buffers_mask(so->vb, &so->enabled_mask, vb, start_slot, count);
198 so->count = util_last_bit(so->enabled_mask);
199
200 ctx->dirty |= FD_DIRTY_VTXBUF;
201 }
202
203 static void
204 fd_set_index_buffer(struct pipe_context *pctx,
205 const struct pipe_index_buffer *ib)
206 {
207 struct fd_context *ctx = fd_context(pctx);
208
209 if (ib) {
210 pipe_resource_reference(&ctx->indexbuf.buffer, ib->buffer);
211 ctx->indexbuf.index_size = ib->index_size;
212 ctx->indexbuf.offset = ib->offset;
213 ctx->indexbuf.user_buffer = ib->user_buffer;
214 } else {
215 pipe_resource_reference(&ctx->indexbuf.buffer, NULL);
216 }
217
218 ctx->dirty |= FD_DIRTY_INDEXBUF;
219 }
220
221 static void
222 fd_blend_state_bind(struct pipe_context *pctx, void *hwcso)
223 {
224 struct fd_context *ctx = fd_context(pctx);
225 struct pipe_blend_state *cso = hwcso;
226 bool old_is_dual = ctx->blend ?
227 ctx->blend->rt[0].blend_enable && util_blend_state_is_dual(ctx->blend, 0) :
228 false;
229 bool new_is_dual = cso ?
230 cso->rt[0].blend_enable && util_blend_state_is_dual(cso, 0) :
231 false;
232 ctx->blend = hwcso;
233 ctx->dirty |= FD_DIRTY_BLEND;
234 if (old_is_dual != new_is_dual)
235 ctx->dirty |= FD_DIRTY_BLEND_DUAL;
236 }
237
238 static void
239 fd_blend_state_delete(struct pipe_context *pctx, void *hwcso)
240 {
241 FREE(hwcso);
242 }
243
244 static void
245 fd_rasterizer_state_bind(struct pipe_context *pctx, void *hwcso)
246 {
247 struct fd_context *ctx = fd_context(pctx);
248 struct pipe_scissor_state *old_scissor = fd_context_get_scissor(ctx);
249
250 ctx->rasterizer = hwcso;
251 ctx->dirty |= FD_DIRTY_RASTERIZER;
252
253 /* if scissor enable bit changed we need to mark scissor
254 * state as dirty as well:
255 * NOTE: we can do a shallow compare, since we only care
256 * if it changed to/from &ctx->disable_scissor
257 */
258 if (old_scissor != fd_context_get_scissor(ctx))
259 ctx->dirty |= FD_DIRTY_SCISSOR;
260 }
261
262 static void
263 fd_rasterizer_state_delete(struct pipe_context *pctx, void *hwcso)
264 {
265 FREE(hwcso);
266 }
267
268 static void
269 fd_zsa_state_bind(struct pipe_context *pctx, void *hwcso)
270 {
271 struct fd_context *ctx = fd_context(pctx);
272 ctx->zsa = hwcso;
273 ctx->dirty |= FD_DIRTY_ZSA;
274 }
275
276 static void
277 fd_zsa_state_delete(struct pipe_context *pctx, void *hwcso)
278 {
279 FREE(hwcso);
280 }
281
282 static void *
283 fd_vertex_state_create(struct pipe_context *pctx, unsigned num_elements,
284 const struct pipe_vertex_element *elements)
285 {
286 struct fd_vertex_stateobj *so = CALLOC_STRUCT(fd_vertex_stateobj);
287
288 if (!so)
289 return NULL;
290
291 memcpy(so->pipe, elements, sizeof(*elements) * num_elements);
292 so->num_elements = num_elements;
293
294 return so;
295 }
296
297 static void
298 fd_vertex_state_delete(struct pipe_context *pctx, void *hwcso)
299 {
300 FREE(hwcso);
301 }
302
303 static void
304 fd_vertex_state_bind(struct pipe_context *pctx, void *hwcso)
305 {
306 struct fd_context *ctx = fd_context(pctx);
307 ctx->vtx.vtx = hwcso;
308 ctx->dirty |= FD_DIRTY_VTXSTATE;
309 }
310
311 static struct pipe_stream_output_target *
312 fd_create_stream_output_target(struct pipe_context *pctx,
313 struct pipe_resource *prsc, unsigned buffer_offset,
314 unsigned buffer_size)
315 {
316 struct pipe_stream_output_target *target;
317
318 target = CALLOC_STRUCT(pipe_stream_output_target);
319 if (!target)
320 return NULL;
321
322 pipe_reference_init(&target->reference, 1);
323 pipe_resource_reference(&target->buffer, prsc);
324
325 target->context = pctx;
326 target->buffer_offset = buffer_offset;
327 target->buffer_size = buffer_size;
328
329 return target;
330 }
331
332 static void
333 fd_stream_output_target_destroy(struct pipe_context *pctx,
334 struct pipe_stream_output_target *target)
335 {
336 pipe_resource_reference(&target->buffer, NULL);
337 FREE(target);
338 }
339
340 static void
341 fd_set_stream_output_targets(struct pipe_context *pctx,
342 unsigned num_targets, struct pipe_stream_output_target **targets,
343 const unsigned *offsets)
344 {
345 struct fd_context *ctx = fd_context(pctx);
346 struct fd_streamout_stateobj *so = &ctx->streamout;
347 unsigned i;
348
349 debug_assert(num_targets <= ARRAY_SIZE(so->targets));
350
351 for (i = 0; i < num_targets; i++) {
352 boolean changed = targets[i] != so->targets[i];
353 boolean append = (offsets[i] == (unsigned)-1);
354
355 if (!changed && append)
356 continue;
357
358 if (!append)
359 so->offsets[i] = offsets[i];
360
361 pipe_so_target_reference(&so->targets[i], targets[i]);
362 }
363
364 for (; i < so->num_targets; i++) {
365 pipe_so_target_reference(&so->targets[i], NULL);
366 }
367
368 so->num_targets = num_targets;
369
370 ctx->dirty |= FD_DIRTY_STREAMOUT;
371 }
372
373 void
374 fd_state_init(struct pipe_context *pctx)
375 {
376 pctx->set_blend_color = fd_set_blend_color;
377 pctx->set_stencil_ref = fd_set_stencil_ref;
378 pctx->set_clip_state = fd_set_clip_state;
379 pctx->set_sample_mask = fd_set_sample_mask;
380 pctx->set_constant_buffer = fd_set_constant_buffer;
381 pctx->set_framebuffer_state = fd_set_framebuffer_state;
382 pctx->set_polygon_stipple = fd_set_polygon_stipple;
383 pctx->set_scissor_states = fd_set_scissor_states;
384 pctx->set_viewport_states = fd_set_viewport_states;
385
386 pctx->set_vertex_buffers = fd_set_vertex_buffers;
387 pctx->set_index_buffer = fd_set_index_buffer;
388
389 pctx->bind_blend_state = fd_blend_state_bind;
390 pctx->delete_blend_state = fd_blend_state_delete;
391
392 pctx->bind_rasterizer_state = fd_rasterizer_state_bind;
393 pctx->delete_rasterizer_state = fd_rasterizer_state_delete;
394
395 pctx->bind_depth_stencil_alpha_state = fd_zsa_state_bind;
396 pctx->delete_depth_stencil_alpha_state = fd_zsa_state_delete;
397
398 pctx->create_vertex_elements_state = fd_vertex_state_create;
399 pctx->delete_vertex_elements_state = fd_vertex_state_delete;
400 pctx->bind_vertex_elements_state = fd_vertex_state_bind;
401
402 pctx->create_stream_output_target = fd_create_stream_output_target;
403 pctx->stream_output_target_destroy = fd_stream_output_target_destroy;
404 pctx->set_stream_output_targets = fd_set_stream_output_targets;
405 }