1/*
2 * Copyright (c) 2011-2013 Luc Verhaegen <libv@skynet.be>
3 * Copyright (c) 2017-2019 Lima Project
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, sub license,
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
13 * next paragraph) shall be included in all copies or substantial portions
14 * of the 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 NON-INFRINGEMENT. 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
22 * DEALINGS IN THE SOFTWARE.
23 *
24 */
25
26#include "util/u_memory.h"
27#include "util/u_inlines.h"
28#include "util/u_helpers.h"
29#include "util/u_debug.h"
30
31#include "pipe/p_state.h"
32
33#include "lima_screen.h"
34#include "lima_context.h"
35#include "lima_resource.h"
36
37static void
38lima_set_framebuffer_state(struct pipe_context *pctx,
39                           const struct pipe_framebuffer_state *framebuffer)
40{
41   struct lima_context *ctx = lima_context(pctx);
42
43   /* submit need framebuffer info, flush before change it */
44   lima_flush(ctx);
45
46   struct lima_context_framebuffer *fb = &ctx->framebuffer;
47
48   fb->base.samples = framebuffer->samples;
49
50   fb->base.nr_cbufs = framebuffer->nr_cbufs;
51   pipe_surface_reference(&fb->base.cbufs[0], framebuffer->cbufs[0]);
52   pipe_surface_reference(&fb->base.zsbuf, framebuffer->zsbuf);
53
54   /* need align here? */
55   fb->base.width = framebuffer->width;
56   fb->base.height = framebuffer->height;
57
58   int width = align(framebuffer->width, 16) >> 4;
59   int height = align(framebuffer->height, 16) >> 4;
60   if (fb->tiled_w != width || fb->tiled_h != height) {
61      fb->tiled_w = width;
62      fb->tiled_h = height;
63
64      fb->shift_h = 0;
65      fb->shift_w = 0;
66
67      int limit = ctx->plb_max_blk;
68      while ((width * height) > limit) {
69         if (width >= height) {
70            width = (width + 1) >> 1;
71            fb->shift_w++;
72         } else {
73            height = (height + 1) >> 1;
74            fb->shift_h++;
75         }
76      }
77
78      fb->block_w = width;
79      fb->block_h = height;
80
81      fb->shift_min = MIN3(fb->shift_w, fb->shift_h, 2);
82
83      debug_printf("fb dim change tiled=%d/%d block=%d/%d shift=%d/%d/%d\n",
84                   fb->tiled_w, fb->tiled_h, fb->block_w, fb->block_h,
85                   fb->shift_w, fb->shift_h, fb->shift_min);
86   }
87
88   ctx->dirty |= LIMA_CONTEXT_DIRTY_FRAMEBUFFER;
89}
90
91static void
92lima_set_polygon_stipple(struct pipe_context *pctx,
93                         const struct pipe_poly_stipple *stipple)
94{
95
96}
97
98static void *
99lima_create_depth_stencil_alpha_state(struct pipe_context *pctx,
100                                      const struct pipe_depth_stencil_alpha_state *cso)
101{
102   struct lima_depth_stencil_alpha_state *so;
103
104   so = CALLOC_STRUCT(lima_depth_stencil_alpha_state);
105   if (!so)
106      return NULL;
107
108   so->base = *cso;
109
110   return so;
111}
112
113static void
114lima_bind_depth_stencil_alpha_state(struct pipe_context *pctx, void *hwcso)
115{
116   struct lima_context *ctx = lima_context(pctx);
117
118   ctx->zsa = hwcso;
119   ctx->dirty |= LIMA_CONTEXT_DIRTY_ZSA;
120}
121
122static void
123lima_delete_depth_stencil_alpha_state(struct pipe_context *pctx, void *hwcso)
124{
125   FREE(hwcso);
126}
127
128static void *
129lima_create_rasterizer_state(struct pipe_context *pctx,
130                             const struct pipe_rasterizer_state *cso)
131{
132   struct lima_rasterizer_state *so;
133
134   so = CALLOC_STRUCT(lima_rasterizer_state);
135   if (!so)
136      return NULL;
137
138   so->base = *cso;
139
140   return so;
141}
142
143static void
144lima_bind_rasterizer_state(struct pipe_context *pctx, void *hwcso)
145{
146   struct lima_context *ctx = lima_context(pctx);
147
148   ctx->rasterizer = hwcso;
149   ctx->dirty |= LIMA_CONTEXT_DIRTY_RASTERIZER;
150}
151
152static void
153lima_delete_rasterizer_state(struct pipe_context *pctx, void *hwcso)
154{
155   FREE(hwcso);
156}
157
158static void *
159lima_create_blend_state(struct pipe_context *pctx,
160                        const struct pipe_blend_state *cso)
161{
162   struct lima_blend_state *so;
163
164   so = CALLOC_STRUCT(lima_blend_state);
165   if (!so)
166      return NULL;
167
168   so->base = *cso;
169
170   return so;
171}
172
173static void
174lima_bind_blend_state(struct pipe_context *pctx, void *hwcso)
175{
176   struct lima_context *ctx = lima_context(pctx);
177
178   ctx->blend = hwcso;
179   ctx->dirty |= LIMA_CONTEXT_DIRTY_BLEND;
180}
181
182static void
183lima_delete_blend_state(struct pipe_context *pctx, void *hwcso)
184{
185   FREE(hwcso);
186}
187
188static void *
189lima_create_vertex_elements_state(struct pipe_context *pctx, unsigned num_elements,
190                                  const struct pipe_vertex_element *elements)
191{
192   struct lima_vertex_element_state *so;
193
194   so = CALLOC_STRUCT(lima_vertex_element_state);
195   if (!so)
196      return NULL;
197
198   memcpy(so->pipe, elements, sizeof(*elements) * num_elements);
199   so->num_elements = num_elements;
200
201   return so;
202}
203
204static void
205lima_bind_vertex_elements_state(struct pipe_context *pctx, void *hwcso)
206{
207   struct lima_context *ctx = lima_context(pctx);
208
209   ctx->vertex_elements = hwcso;
210   ctx->dirty |= LIMA_CONTEXT_DIRTY_VERTEX_ELEM;
211}
212
213static void
214lima_delete_vertex_elements_state(struct pipe_context *pctx, void *hwcso)
215{
216   FREE(hwcso);
217}
218
219static void
220lima_set_vertex_buffers(struct pipe_context *pctx,
221                        unsigned start_slot, unsigned count,
222                        const struct pipe_vertex_buffer *vb)
223{
224   struct lima_context *ctx = lima_context(pctx);
225   struct lima_context_vertex_buffer *so = &ctx->vertex_buffers;
226
227   util_set_vertex_buffers_mask(so->vb + start_slot, &so->enabled_mask,
228                                vb, start_slot, count);
229   so->count = util_last_bit(so->enabled_mask);
230
231   ctx->dirty |= LIMA_CONTEXT_DIRTY_VERTEX_BUFF;
232}
233
234static void
235lima_set_viewport_states(struct pipe_context *pctx,
236                         unsigned start_slot,
237                         unsigned num_viewports,
238                         const struct pipe_viewport_state *viewport)
239{
240   struct lima_context *ctx = lima_context(pctx);
241
242   /* reverse calculate the parameter of glViewport */
243   ctx->viewport.x = viewport->translate[0] - viewport->scale[0];
244   ctx->viewport.y = fabsf(viewport->translate[1] - fabsf(viewport->scale[1]));
245   ctx->viewport.width = viewport->scale[0] * 2;
246   ctx->viewport.height = fabsf(viewport->scale[1] * 2);
247
248   /* reverse calculate the parameter of glDepthRange */
249   ctx->viewport.near = viewport->translate[2] - viewport->scale[2];
250   ctx->viewport.far = viewport->translate[2] + viewport->scale[2];
251
252   ctx->viewport.transform = *viewport;
253   ctx->dirty |= LIMA_CONTEXT_DIRTY_VIEWPORT;
254}
255
256static void
257lima_set_scissor_states(struct pipe_context *pctx,
258                        unsigned start_slot,
259                        unsigned num_scissors,
260                        const struct pipe_scissor_state *scissor)
261{
262   struct lima_context *ctx = lima_context(pctx);
263
264   ctx->scissor = *scissor;
265   ctx->dirty |= LIMA_CONTEXT_DIRTY_SCISSOR;
266}
267
268static void
269lima_set_blend_color(struct pipe_context *pctx,
270                     const struct pipe_blend_color *blend_color)
271{
272   struct lima_context *ctx = lima_context(pctx);
273
274   ctx->blend_color = *blend_color;
275   ctx->dirty |= LIMA_CONTEXT_DIRTY_BLEND_COLOR;
276}
277
278static void
279lima_set_stencil_ref(struct pipe_context *pctx,
280                     const struct pipe_stencil_ref *stencil_ref)
281{
282   struct lima_context *ctx = lima_context(pctx);
283
284   ctx->stencil_ref = *stencil_ref;
285   ctx->dirty |= LIMA_CONTEXT_DIRTY_STENCIL_REF;
286}
287
288static void
289lima_set_constant_buffer(struct pipe_context *pctx,
290                         enum pipe_shader_type shader, uint index,
291                         const struct pipe_constant_buffer *cb)
292{
293   struct lima_context *ctx = lima_context(pctx);
294   struct lima_context_constant_buffer *so = ctx->const_buffer + shader;
295
296   assert(index == 0);
297
298   if (unlikely(!cb)) {
299      so->buffer = NULL;
300      so->size = 0;
301   } else {
302      assert(!cb->buffer);
303
304      so->buffer = cb->user_buffer + cb->buffer_offset;
305      so->size = cb->buffer_size;
306   }
307
308   so->dirty = true;
309   ctx->dirty |= LIMA_CONTEXT_DIRTY_CONST_BUFF;
310
311}
312
313static void *
314lima_create_sampler_state(struct pipe_context *pctx,
315                         const struct pipe_sampler_state *cso)
316{
317   struct lima_sampler_state *so = CALLOC_STRUCT(lima_sampler_state);
318   if (!so)
319      return NULL;
320
321   memcpy(so, cso, sizeof(*cso));
322
323   return so;
324}
325
326static void
327lima_sampler_state_delete(struct pipe_context *pctx, void *sstate)
328{
329   free(sstate);
330}
331
332static void
333lima_sampler_states_bind(struct pipe_context *pctx,
334                        enum pipe_shader_type shader, unsigned start,
335                        unsigned nr, void **hwcso)
336{
337   struct lima_context *ctx = lima_context(pctx);
338   struct lima_texture_stateobj *lima_tex = &ctx->tex_stateobj;
339   unsigned i;
340   unsigned new_nr = 0;
341
342   assert(start == 0);
343
344   for (i = 0; i < nr; i++) {
345      if (hwcso[i])
346         new_nr = i + 1;
347      lima_tex->samplers[i] = hwcso[i];
348   }
349
350   for (; i < lima_tex->num_samplers; i++) {
351      lima_tex->samplers[i] = NULL;
352   }
353
354   lima_tex->num_samplers = new_nr;
355   ctx->dirty |= LIMA_CONTEXT_DIRTY_TEXTURES;
356}
357
358static struct pipe_sampler_view *
359lima_create_sampler_view(struct pipe_context *pctx, struct pipe_resource *prsc,
360                        const struct pipe_sampler_view *cso)
361{
362   struct lima_sampler_view *so = CALLOC_STRUCT(lima_sampler_view);
363
364   if (!so)
365      return NULL;
366
367   so->base = *cso;
368
369   pipe_reference(NULL, &prsc->reference);
370   so->base.texture = prsc;
371   so->base.reference.count = 1;
372   so->base.context = pctx;
373
374   return &so->base;
375}
376
377static void
378lima_sampler_view_destroy(struct pipe_context *pctx,
379                         struct pipe_sampler_view *pview)
380{
381   struct lima_sampler_view *view = lima_sampler_view(pview);
382
383   pipe_resource_reference(&pview->texture, NULL);
384
385   free(view);
386}
387
388static void
389lima_set_sampler_views(struct pipe_context *pctx,
390                      enum pipe_shader_type shader,
391                      unsigned start, unsigned nr,
392                      struct pipe_sampler_view **views)
393{
394   struct lima_context *ctx = lima_context(pctx);
395   struct lima_texture_stateobj *lima_tex = &ctx->tex_stateobj;
396   int i;
397   unsigned new_nr = 0;
398
399   assert(start == 0);
400
401   for (i = 0; i < nr; i++) {
402      if (views[i])
403         new_nr = i + 1;
404      pipe_sampler_view_reference(&lima_tex->textures[i], views[i]);
405   }
406
407   for (; i < lima_tex->num_textures; i++) {
408      pipe_sampler_view_reference(&lima_tex->textures[i], NULL);
409   }
410
411   lima_tex->num_textures = new_nr;
412   ctx->dirty |= LIMA_CONTEXT_DIRTY_TEXTURES;
413}
414
415static boolean
416lima_set_damage_region(struct pipe_context *pctx, unsigned num_rects, int *rects)
417{
418   struct lima_context *ctx = lima_context(pctx);
419   struct lima_damage_state *damage = &ctx->damage;
420   int i;
421
422   if (damage->region)
423      ralloc_free(damage->region);
424
425   if (!num_rects) {
426      damage->region = NULL;
427      damage->num_region = 0;
428      return true;
429   }
430
431   damage->region = ralloc_size(ctx, sizeof(*damage->region) * num_rects);
432   if (!damage->region) {
433      damage->num_region = 0;
434      return false;
435   }
436
437   for (i = 0; i < num_rects; i++) {
438      struct pipe_scissor_state *r = damage->region + i;
439      /* region in tile unit */
440      r->minx = rects[i * 4] >> 4;
441      r->miny = rects[i * 4 + 1] >> 4;
442      r->maxx = (rects[i * 4] + rects[i * 4 + 2] + 0xf) >> 4;
443      r->maxy = (rects[i * 4 + 1] + rects[i * 4 + 3] + 0xf) >> 4;
444   }
445
446   /* is region aligned to tiles? */
447   damage->aligned = true;
448   for (i = 0; i < num_rects * 4; i++) {
449      if (rects[i] & 0xf) {
450         damage->aligned = false;
451         break;
452      }
453   }
454
455   damage->num_region = num_rects;
456   return true;
457}
458
459static void
460lima_set_sample_mask(struct pipe_context *pctx,
461                     unsigned sample_mask)
462{
463}
464
465void
466lima_state_init(struct lima_context *ctx)
467{
468   ctx->base.set_framebuffer_state = lima_set_framebuffer_state;
469   ctx->base.set_polygon_stipple = lima_set_polygon_stipple;
470   ctx->base.set_viewport_states = lima_set_viewport_states;
471   ctx->base.set_scissor_states = lima_set_scissor_states;
472   ctx->base.set_blend_color = lima_set_blend_color;
473   ctx->base.set_stencil_ref = lima_set_stencil_ref;
474
475   ctx->base.set_vertex_buffers = lima_set_vertex_buffers;
476   ctx->base.set_constant_buffer = lima_set_constant_buffer;
477
478   ctx->base.create_depth_stencil_alpha_state = lima_create_depth_stencil_alpha_state;
479   ctx->base.bind_depth_stencil_alpha_state = lima_bind_depth_stencil_alpha_state;
480   ctx->base.delete_depth_stencil_alpha_state = lima_delete_depth_stencil_alpha_state;
481
482   ctx->base.create_rasterizer_state = lima_create_rasterizer_state;
483   ctx->base.bind_rasterizer_state = lima_bind_rasterizer_state;
484   ctx->base.delete_rasterizer_state = lima_delete_rasterizer_state;
485
486   ctx->base.create_blend_state = lima_create_blend_state;
487   ctx->base.bind_blend_state = lima_bind_blend_state;
488   ctx->base.delete_blend_state = lima_delete_blend_state;
489
490   ctx->base.create_vertex_elements_state = lima_create_vertex_elements_state;
491   ctx->base.bind_vertex_elements_state = lima_bind_vertex_elements_state;
492   ctx->base.delete_vertex_elements_state = lima_delete_vertex_elements_state;
493
494   ctx->base.create_sampler_state = lima_create_sampler_state;
495   ctx->base.delete_sampler_state = lima_sampler_state_delete;
496   ctx->base.bind_sampler_states = lima_sampler_states_bind;
497
498   ctx->base.create_sampler_view = lima_create_sampler_view;
499   ctx->base.sampler_view_destroy = lima_sampler_view_destroy;
500   ctx->base.set_sampler_views = lima_set_sampler_views;
501
502   ctx->base.set_sample_mask = lima_set_sample_mask;
503}
504
505void
506lima_state_fini(struct lima_context *ctx)
507{
508   struct lima_context_vertex_buffer *so = &ctx->vertex_buffers;
509
510   util_set_vertex_buffers_mask(so->vb, &so->enabled_mask, NULL,
511                                0, ARRAY_SIZE(so->vb));
512
513   pipe_surface_reference(&ctx->framebuffer.base.cbufs[0], NULL);
514   pipe_surface_reference(&ctx->framebuffer.base.zsbuf, NULL);
515}
516