freedreno/a3xx: add basic clip plane support
[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_string.h"
31 #include "util/u_memory.h"
32 #include "util/u_helpers.h"
33
34 #include "freedreno_state.h"
35 #include "freedreno_context.h"
36 #include "freedreno_resource.h"
37 #include "freedreno_texture.h"
38 #include "freedreno_gmem.h"
39 #include "freedreno_util.h"
40
41 /* All the generic state handling.. In case of CSO's that are specific
42 * to the GPU version, when the bind and the delete are common they can
43 * go in here.
44 */
45
46 static void
47 fd_set_blend_color(struct pipe_context *pctx,
48 const struct pipe_blend_color *blend_color)
49 {
50 struct fd_context *ctx = fd_context(pctx);
51 ctx->blend_color = *blend_color;
52 ctx->dirty |= FD_DIRTY_BLEND_COLOR;
53 }
54
55 static void
56 fd_set_stencil_ref(struct pipe_context *pctx,
57 const struct pipe_stencil_ref *stencil_ref)
58 {
59 struct fd_context *ctx = fd_context(pctx);
60 ctx->stencil_ref =* stencil_ref;
61 ctx->dirty |= FD_DIRTY_STENCIL_REF;
62 }
63
64 static void
65 fd_set_clip_state(struct pipe_context *pctx,
66 const struct pipe_clip_state *clip)
67 {
68 struct fd_context *ctx = fd_context(pctx);
69 ctx->ucp = *clip;
70 ctx->dirty |= FD_DIRTY_UCP;
71 }
72
73 static void
74 fd_set_sample_mask(struct pipe_context *pctx, unsigned sample_mask)
75 {
76 struct fd_context *ctx = fd_context(pctx);
77 ctx->sample_mask = (uint16_t)sample_mask;
78 ctx->dirty |= FD_DIRTY_SAMPLE_MASK;
79 }
80
81 /* notes from calim on #dri-devel:
82 * index==0 will be non-UBO (ie. glUniformXYZ()) all packed together padded
83 * out to vec4's
84 * I should be able to consider that I own the user_ptr until the next
85 * set_constant_buffer() call, at which point I don't really care about the
86 * previous values.
87 * index>0 will be UBO's.. well, I'll worry about that later
88 */
89 static void
90 fd_set_constant_buffer(struct pipe_context *pctx, uint shader, uint index,
91 struct pipe_constant_buffer *cb)
92 {
93 struct fd_context *ctx = fd_context(pctx);
94 struct fd_constbuf_stateobj *so = &ctx->constbuf[shader];
95
96 /* Note that the state tracker can unbind constant buffers by
97 * passing NULL here.
98 */
99 if (unlikely(!cb)) {
100 so->enabled_mask &= ~(1 << index);
101 so->dirty_mask &= ~(1 << index);
102 pipe_resource_reference(&so->cb[index].buffer, NULL);
103 return;
104 }
105
106 pipe_resource_reference(&so->cb[index].buffer, cb->buffer);
107 so->cb[index].buffer_offset = cb->buffer_offset;
108 so->cb[index].buffer_size = cb->buffer_size;
109 so->cb[index].user_buffer = cb->user_buffer;
110
111 so->enabled_mask |= 1 << index;
112 so->dirty_mask |= 1 << index;
113 ctx->dirty |= FD_DIRTY_CONSTBUF;
114 }
115
116 static void
117 fd_set_framebuffer_state(struct pipe_context *pctx,
118 const struct pipe_framebuffer_state *framebuffer)
119 {
120 struct fd_context *ctx = fd_context(pctx);
121 struct pipe_framebuffer_state *cso = &ctx->framebuffer;
122
123 DBG("%d: cbufs[0]=%p, zsbuf=%p", ctx->needs_flush,
124 framebuffer->cbufs[0], framebuffer->zsbuf);
125
126 fd_context_render(pctx);
127
128 if ((cso->width != framebuffer->width) ||
129 (cso->height != framebuffer->height))
130 ctx->needs_rb_fbd = true;
131
132 util_copy_framebuffer_state(cso, framebuffer);
133
134 ctx->dirty |= FD_DIRTY_FRAMEBUFFER;
135
136 ctx->disabled_scissor.minx = 0;
137 ctx->disabled_scissor.miny = 0;
138 ctx->disabled_scissor.maxx = cso->width;
139 ctx->disabled_scissor.maxy = cso->height;
140
141 ctx->dirty |= FD_DIRTY_SCISSOR;
142 }
143
144 static void
145 fd_set_polygon_stipple(struct pipe_context *pctx,
146 const struct pipe_poly_stipple *stipple)
147 {
148 struct fd_context *ctx = fd_context(pctx);
149 ctx->stipple = *stipple;
150 ctx->dirty |= FD_DIRTY_STIPPLE;
151 }
152
153 static void
154 fd_set_scissor_states(struct pipe_context *pctx,
155 unsigned start_slot,
156 unsigned num_scissors,
157 const struct pipe_scissor_state *scissor)
158 {
159 struct fd_context *ctx = fd_context(pctx);
160
161 ctx->scissor = *scissor;
162 ctx->dirty |= FD_DIRTY_SCISSOR;
163 }
164
165 static void
166 fd_set_viewport_states(struct pipe_context *pctx,
167 unsigned start_slot,
168 unsigned num_viewports,
169 const struct pipe_viewport_state *viewport)
170 {
171 struct fd_context *ctx = fd_context(pctx);
172 ctx->viewport = *viewport;
173 ctx->dirty |= FD_DIRTY_VIEWPORT;
174 }
175
176 static void
177 fd_set_vertex_buffers(struct pipe_context *pctx,
178 unsigned start_slot, unsigned count,
179 const struct pipe_vertex_buffer *vb)
180 {
181 struct fd_context *ctx = fd_context(pctx);
182 struct fd_vertexbuf_stateobj *so = &ctx->vtx.vertexbuf;
183 int i;
184
185 /* on a2xx, pitch is encoded in the vtx fetch instruction, so
186 * we need to mark VTXSTATE as dirty as well to trigger patching
187 * and re-emitting the vtx shader:
188 */
189 for (i = 0; i < count; i++) {
190 bool new_enabled = vb && (vb[i].buffer || vb[i].user_buffer);
191 bool old_enabled = so->vb[i].buffer || so->vb[i].user_buffer;
192 uint32_t new_stride = vb ? vb[i].stride : 0;
193 uint32_t old_stride = so->vb[i].stride;
194 if ((new_enabled != old_enabled) || (new_stride != old_stride)) {
195 ctx->dirty |= FD_DIRTY_VTXSTATE;
196 break;
197 }
198 }
199
200 util_set_vertex_buffers_mask(so->vb, &so->enabled_mask, vb, start_slot, count);
201 so->count = util_last_bit(so->enabled_mask);
202
203 ctx->dirty |= FD_DIRTY_VTXBUF;
204 }
205
206 static void
207 fd_set_index_buffer(struct pipe_context *pctx,
208 const struct pipe_index_buffer *ib)
209 {
210 struct fd_context *ctx = fd_context(pctx);
211
212 if (ib) {
213 pipe_resource_reference(&ctx->indexbuf.buffer, ib->buffer);
214 ctx->indexbuf.index_size = ib->index_size;
215 ctx->indexbuf.offset = ib->offset;
216 ctx->indexbuf.user_buffer = ib->user_buffer;
217 } else {
218 pipe_resource_reference(&ctx->indexbuf.buffer, NULL);
219 }
220
221 ctx->dirty |= FD_DIRTY_INDEXBUF;
222 }
223
224 static void
225 fd_blend_state_bind(struct pipe_context *pctx, void *hwcso)
226 {
227 struct fd_context *ctx = fd_context(pctx);
228 ctx->blend = hwcso;
229 ctx->dirty |= FD_DIRTY_BLEND;
230 }
231
232 static void
233 fd_blend_state_delete(struct pipe_context *pctx, void *hwcso)
234 {
235 FREE(hwcso);
236 }
237
238 static void
239 fd_rasterizer_state_bind(struct pipe_context *pctx, void *hwcso)
240 {
241 struct fd_context *ctx = fd_context(pctx);
242 struct pipe_scissor_state *old_scissor = fd_context_get_scissor(ctx);
243
244 ctx->rasterizer = hwcso;
245 ctx->dirty |= FD_DIRTY_RASTERIZER;
246
247 /* if scissor enable bit changed we need to mark scissor
248 * state as dirty as well:
249 * NOTE: we can do a shallow compare, since we only care
250 * if it changed to/from &ctx->disable_scissor
251 */
252 if (old_scissor != fd_context_get_scissor(ctx))
253 ctx->dirty |= FD_DIRTY_SCISSOR;
254 }
255
256 static void
257 fd_rasterizer_state_delete(struct pipe_context *pctx, void *hwcso)
258 {
259 FREE(hwcso);
260 }
261
262 static void
263 fd_zsa_state_bind(struct pipe_context *pctx, void *hwcso)
264 {
265 struct fd_context *ctx = fd_context(pctx);
266 ctx->zsa = hwcso;
267 ctx->dirty |= FD_DIRTY_ZSA;
268 }
269
270 static void
271 fd_zsa_state_delete(struct pipe_context *pctx, void *hwcso)
272 {
273 FREE(hwcso);
274 }
275
276 static void *
277 fd_vertex_state_create(struct pipe_context *pctx, unsigned num_elements,
278 const struct pipe_vertex_element *elements)
279 {
280 struct fd_vertex_stateobj *so = CALLOC_STRUCT(fd_vertex_stateobj);
281
282 if (!so)
283 return NULL;
284
285 memcpy(so->pipe, elements, sizeof(*elements) * num_elements);
286 so->num_elements = num_elements;
287
288 return so;
289 }
290
291 static void
292 fd_vertex_state_delete(struct pipe_context *pctx, void *hwcso)
293 {
294 FREE(hwcso);
295 }
296
297 static void
298 fd_vertex_state_bind(struct pipe_context *pctx, void *hwcso)
299 {
300 struct fd_context *ctx = fd_context(pctx);
301 ctx->vtx.vtx = hwcso;
302 ctx->dirty |= FD_DIRTY_VTXSTATE;
303 }
304
305 static struct pipe_stream_output_target *
306 fd_create_stream_output_target(struct pipe_context *pctx,
307 struct pipe_resource *prsc, unsigned buffer_offset,
308 unsigned buffer_size)
309 {
310 struct pipe_stream_output_target *target;
311
312 target = CALLOC_STRUCT(pipe_stream_output_target);
313 if (!target)
314 return NULL;
315
316 pipe_reference_init(&target->reference, 1);
317 pipe_resource_reference(&target->buffer, prsc);
318
319 target->context = pctx;
320 target->buffer_offset = buffer_offset;
321 target->buffer_size = buffer_size;
322
323 return target;
324 }
325
326 static void
327 fd_stream_output_target_destroy(struct pipe_context *pctx,
328 struct pipe_stream_output_target *target)
329 {
330 pipe_resource_reference(&target->buffer, NULL);
331 FREE(target);
332 }
333
334 static void
335 fd_set_stream_output_targets(struct pipe_context *pctx,
336 unsigned num_targets, struct pipe_stream_output_target **targets,
337 const unsigned *offsets)
338 {
339 struct fd_context *ctx = fd_context(pctx);
340 struct fd_streamout_stateobj *so = &ctx->streamout;
341 unsigned i;
342
343 debug_assert(num_targets <= ARRAY_SIZE(so->targets));
344
345 for (i = 0; i < num_targets; i++) {
346 boolean changed = targets[i] != so->targets[i];
347 boolean append = (offsets[i] == (unsigned)-1);
348
349 if (!changed && append)
350 continue;
351
352 so->offsets[i] = 0;
353
354 pipe_so_target_reference(&so->targets[i], targets[i]);
355 }
356
357 for (; i < so->num_targets; i++) {
358 pipe_so_target_reference(&so->targets[i], NULL);
359 }
360
361 so->num_targets = num_targets;
362
363 ctx->dirty |= FD_DIRTY_STREAMOUT;
364 }
365
366 void
367 fd_state_init(struct pipe_context *pctx)
368 {
369 pctx->set_blend_color = fd_set_blend_color;
370 pctx->set_stencil_ref = fd_set_stencil_ref;
371 pctx->set_clip_state = fd_set_clip_state;
372 pctx->set_sample_mask = fd_set_sample_mask;
373 pctx->set_constant_buffer = fd_set_constant_buffer;
374 pctx->set_framebuffer_state = fd_set_framebuffer_state;
375 pctx->set_polygon_stipple = fd_set_polygon_stipple;
376 pctx->set_scissor_states = fd_set_scissor_states;
377 pctx->set_viewport_states = fd_set_viewport_states;
378
379 pctx->set_vertex_buffers = fd_set_vertex_buffers;
380 pctx->set_index_buffer = fd_set_index_buffer;
381
382 pctx->bind_blend_state = fd_blend_state_bind;
383 pctx->delete_blend_state = fd_blend_state_delete;
384
385 pctx->bind_rasterizer_state = fd_rasterizer_state_bind;
386 pctx->delete_rasterizer_state = fd_rasterizer_state_delete;
387
388 pctx->bind_depth_stencil_alpha_state = fd_zsa_state_bind;
389 pctx->delete_depth_stencil_alpha_state = fd_zsa_state_delete;
390
391 pctx->create_vertex_elements_state = fd_vertex_state_create;
392 pctx->delete_vertex_elements_state = fd_vertex_state_delete;
393 pctx->bind_vertex_elements_state = fd_vertex_state_bind;
394
395 pctx->create_stream_output_target = fd_create_stream_output_target;
396 pctx->stream_output_target_destroy = fd_stream_output_target_destroy;
397 pctx->set_stream_output_targets = fd_set_stream_output_targets;
398 }