1bf215546Sopenharmony_ci/*
2bf215546Sopenharmony_ci * Copyright (C) 2016 Rob Clark <robclark@freedesktop.org>
3bf215546Sopenharmony_ci * Copyright © 2018 Google, Inc.
4bf215546Sopenharmony_ci *
5bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
6bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
7bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation
8bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
10bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
11bf215546Sopenharmony_ci *
12bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next
13bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the
14bf215546Sopenharmony_ci * Software.
15bf215546Sopenharmony_ci *
16bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21bf215546Sopenharmony_ci * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22bf215546Sopenharmony_ci * SOFTWARE.
23bf215546Sopenharmony_ci *
24bf215546Sopenharmony_ci * Authors:
25bf215546Sopenharmony_ci *    Rob Clark <robclark@freedesktop.org>
26bf215546Sopenharmony_ci */
27bf215546Sopenharmony_ci
28bf215546Sopenharmony_ci#include "pipe/p_state.h"
29bf215546Sopenharmony_ci#include "util/u_blend.h"
30bf215546Sopenharmony_ci#include "util/u_dual_blend.h"
31bf215546Sopenharmony_ci#include "util/u_memory.h"
32bf215546Sopenharmony_ci#include "util/u_string.h"
33bf215546Sopenharmony_ci
34bf215546Sopenharmony_ci#include "fd6_blend.h"
35bf215546Sopenharmony_ci#include "fd6_context.h"
36bf215546Sopenharmony_ci#include "fd6_pack.h"
37bf215546Sopenharmony_ci
38bf215546Sopenharmony_ci// XXX move somewhere common.. same across a3xx/a4xx/a5xx..
39bf215546Sopenharmony_cistatic enum a3xx_rb_blend_opcode
40bf215546Sopenharmony_ciblend_func(unsigned func)
41bf215546Sopenharmony_ci{
42bf215546Sopenharmony_ci   switch (func) {
43bf215546Sopenharmony_ci   case PIPE_BLEND_ADD:
44bf215546Sopenharmony_ci      return BLEND_DST_PLUS_SRC;
45bf215546Sopenharmony_ci   case PIPE_BLEND_MIN:
46bf215546Sopenharmony_ci      return BLEND_MIN_DST_SRC;
47bf215546Sopenharmony_ci   case PIPE_BLEND_MAX:
48bf215546Sopenharmony_ci      return BLEND_MAX_DST_SRC;
49bf215546Sopenharmony_ci   case PIPE_BLEND_SUBTRACT:
50bf215546Sopenharmony_ci      return BLEND_SRC_MINUS_DST;
51bf215546Sopenharmony_ci   case PIPE_BLEND_REVERSE_SUBTRACT:
52bf215546Sopenharmony_ci      return BLEND_DST_MINUS_SRC;
53bf215546Sopenharmony_ci   default:
54bf215546Sopenharmony_ci      DBG("invalid blend func: %x", func);
55bf215546Sopenharmony_ci      return 0;
56bf215546Sopenharmony_ci   }
57bf215546Sopenharmony_ci}
58bf215546Sopenharmony_ci
59bf215546Sopenharmony_cistruct fd6_blend_variant *
60bf215546Sopenharmony_ci__fd6_setup_blend_variant(struct fd6_blend_stateobj *blend,
61bf215546Sopenharmony_ci                          unsigned sample_mask)
62bf215546Sopenharmony_ci{
63bf215546Sopenharmony_ci   const struct pipe_blend_state *cso = &blend->base;
64bf215546Sopenharmony_ci   struct fd6_blend_variant *so;
65bf215546Sopenharmony_ci   enum a3xx_rop_code rop = ROP_COPY;
66bf215546Sopenharmony_ci   bool reads_dest = false;
67bf215546Sopenharmony_ci   unsigned mrt_blend = 0;
68bf215546Sopenharmony_ci
69bf215546Sopenharmony_ci   if (cso->logicop_enable) {
70bf215546Sopenharmony_ci      rop = cso->logicop_func; /* maps 1:1 */
71bf215546Sopenharmony_ci      reads_dest = util_logicop_reads_dest(cso->logicop_func);
72bf215546Sopenharmony_ci   }
73bf215546Sopenharmony_ci
74bf215546Sopenharmony_ci   so = rzalloc_size(blend, sizeof(*so));
75bf215546Sopenharmony_ci   if (!so)
76bf215546Sopenharmony_ci      return NULL;
77bf215546Sopenharmony_ci
78bf215546Sopenharmony_ci   struct fd_ringbuffer *ring = fd_ringbuffer_new_object(
79bf215546Sopenharmony_ci      blend->ctx->pipe, ((A6XX_MAX_RENDER_TARGETS * 4) + 6) * 4);
80bf215546Sopenharmony_ci   so->stateobj = ring;
81bf215546Sopenharmony_ci
82bf215546Sopenharmony_ci   for (unsigned i = 0; i <= cso->max_rt; i++) {
83bf215546Sopenharmony_ci      const struct pipe_rt_blend_state *rt;
84bf215546Sopenharmony_ci
85bf215546Sopenharmony_ci      if (cso->independent_blend_enable)
86bf215546Sopenharmony_ci         rt = &cso->rt[i];
87bf215546Sopenharmony_ci      else
88bf215546Sopenharmony_ci         rt = &cso->rt[0];
89bf215546Sopenharmony_ci
90bf215546Sopenharmony_ci      OUT_REG(ring,
91bf215546Sopenharmony_ci              A6XX_RB_MRT_BLEND_CONTROL(
92bf215546Sopenharmony_ci                 i, .rgb_src_factor = fd_blend_factor(rt->rgb_src_factor),
93bf215546Sopenharmony_ci                 .rgb_blend_opcode = blend_func(rt->rgb_func),
94bf215546Sopenharmony_ci                 .rgb_dest_factor = fd_blend_factor(rt->rgb_dst_factor),
95bf215546Sopenharmony_ci                 .alpha_src_factor = fd_blend_factor(rt->alpha_src_factor),
96bf215546Sopenharmony_ci                 .alpha_blend_opcode = blend_func(rt->alpha_func),
97bf215546Sopenharmony_ci                 .alpha_dest_factor = fd_blend_factor(rt->alpha_dst_factor), ));
98bf215546Sopenharmony_ci
99bf215546Sopenharmony_ci      OUT_REG(ring, A6XX_RB_MRT_CONTROL(i, .rop_code = rop,
100bf215546Sopenharmony_ci                                        .rop_enable = cso->logicop_enable,
101bf215546Sopenharmony_ci                                        .component_enable = rt->colormask,
102bf215546Sopenharmony_ci                                        .blend = rt->blend_enable,
103bf215546Sopenharmony_ci                                        .blend2 = rt->blend_enable, ));
104bf215546Sopenharmony_ci
105bf215546Sopenharmony_ci      if (rt->blend_enable) {
106bf215546Sopenharmony_ci         mrt_blend |= (1 << i);
107bf215546Sopenharmony_ci      }
108bf215546Sopenharmony_ci
109bf215546Sopenharmony_ci      if (reads_dest) {
110bf215546Sopenharmony_ci         mrt_blend |= (1 << i);
111bf215546Sopenharmony_ci      }
112bf215546Sopenharmony_ci   }
113bf215546Sopenharmony_ci
114bf215546Sopenharmony_ci   OUT_REG(
115bf215546Sopenharmony_ci      ring,
116bf215546Sopenharmony_ci      A6XX_RB_DITHER_CNTL(
117bf215546Sopenharmony_ci            .dither_mode_mrt0 = cso->dither ? DITHER_ALWAYS : DITHER_DISABLE,
118bf215546Sopenharmony_ci            .dither_mode_mrt1 = cso->dither ? DITHER_ALWAYS : DITHER_DISABLE,
119bf215546Sopenharmony_ci            .dither_mode_mrt2 = cso->dither ? DITHER_ALWAYS : DITHER_DISABLE,
120bf215546Sopenharmony_ci            .dither_mode_mrt3 = cso->dither ? DITHER_ALWAYS : DITHER_DISABLE,
121bf215546Sopenharmony_ci            .dither_mode_mrt4 = cso->dither ? DITHER_ALWAYS : DITHER_DISABLE,
122bf215546Sopenharmony_ci            .dither_mode_mrt5 = cso->dither ? DITHER_ALWAYS : DITHER_DISABLE,
123bf215546Sopenharmony_ci            .dither_mode_mrt6 = cso->dither ? DITHER_ALWAYS : DITHER_DISABLE,
124bf215546Sopenharmony_ci            .dither_mode_mrt7 =
125bf215546Sopenharmony_ci               cso->dither ? DITHER_ALWAYS : DITHER_DISABLE, ));
126bf215546Sopenharmony_ci
127bf215546Sopenharmony_ci   OUT_REG(ring, A6XX_SP_BLEND_CNTL(.enable_blend = mrt_blend,
128bf215546Sopenharmony_ci                                    .unk8 = true,
129bf215546Sopenharmony_ci                                    .alpha_to_coverage = cso->alpha_to_coverage,
130bf215546Sopenharmony_ci                                    .dual_color_in_enable =
131bf215546Sopenharmony_ci                                       blend->use_dual_src_blend, ));
132bf215546Sopenharmony_ci
133bf215546Sopenharmony_ci   OUT_REG(ring,
134bf215546Sopenharmony_ci      A6XX_RB_BLEND_CNTL(.enable_blend = mrt_blend,
135bf215546Sopenharmony_ci                         .alpha_to_coverage = cso->alpha_to_coverage,
136bf215546Sopenharmony_ci                         .alpha_to_one = cso->alpha_to_one,
137bf215546Sopenharmony_ci                         .independent_blend = cso->independent_blend_enable,
138bf215546Sopenharmony_ci                         .sample_mask = sample_mask,
139bf215546Sopenharmony_ci                         .dual_color_in_enable = blend->use_dual_src_blend, ));
140bf215546Sopenharmony_ci
141bf215546Sopenharmony_ci   so->sample_mask = sample_mask;
142bf215546Sopenharmony_ci
143bf215546Sopenharmony_ci   util_dynarray_append(&blend->variants, struct fd6_blend_variant *, so);
144bf215546Sopenharmony_ci
145bf215546Sopenharmony_ci   return so;
146bf215546Sopenharmony_ci}
147bf215546Sopenharmony_ci
148bf215546Sopenharmony_civoid *
149bf215546Sopenharmony_cifd6_blend_state_create(struct pipe_context *pctx,
150bf215546Sopenharmony_ci                       const struct pipe_blend_state *cso)
151bf215546Sopenharmony_ci{
152bf215546Sopenharmony_ci   struct fd6_blend_stateobj *so;
153bf215546Sopenharmony_ci
154bf215546Sopenharmony_ci   so = rzalloc_size(NULL, sizeof(*so));
155bf215546Sopenharmony_ci   if (!so)
156bf215546Sopenharmony_ci      return NULL;
157bf215546Sopenharmony_ci
158bf215546Sopenharmony_ci   so->base = *cso;
159bf215546Sopenharmony_ci   so->ctx = fd_context(pctx);
160bf215546Sopenharmony_ci
161bf215546Sopenharmony_ci   if (cso->logicop_enable) {
162bf215546Sopenharmony_ci      so->reads_dest |= util_logicop_reads_dest(cso->logicop_func);
163bf215546Sopenharmony_ci   }
164bf215546Sopenharmony_ci
165bf215546Sopenharmony_ci   so->use_dual_src_blend =
166bf215546Sopenharmony_ci      cso->rt[0].blend_enable && util_blend_state_is_dual(cso, 0);
167bf215546Sopenharmony_ci
168bf215546Sopenharmony_ci   unsigned nr = cso->independent_blend_enable ? cso->max_rt : 0;
169bf215546Sopenharmony_ci   for (unsigned i = 0; i <= nr; i++) {
170bf215546Sopenharmony_ci      const struct pipe_rt_blend_state *rt = &cso->rt[i];
171bf215546Sopenharmony_ci
172bf215546Sopenharmony_ci      so->reads_dest |= rt->blend_enable;
173bf215546Sopenharmony_ci
174bf215546Sopenharmony_ci      /* From the PoV of LRZ, having masked color channels is
175bf215546Sopenharmony_ci       * the same as having blend enabled, in that the draw will
176bf215546Sopenharmony_ci       * care about the fragments from an earlier draw.
177bf215546Sopenharmony_ci       *
178bf215546Sopenharmony_ci       * NOTE we actually don't care about masked color channels
179bf215546Sopenharmony_ci       * that don't actually exist in the render target, but we
180bf215546Sopenharmony_ci       * don't know the render target format here to determine
181bf215546Sopenharmony_ci       * that.  It is probably not worth worrying about, but if
182bf215546Sopenharmony_ci       * we find a game/benchmark that goes out of it's way to
183bf215546Sopenharmony_ci       * mask off non-existent channels, we should fixup the
184bf215546Sopenharmony_ci       * pipe_blend_state to give us more info.
185bf215546Sopenharmony_ci       */
186bf215546Sopenharmony_ci      if (rt->blend_enable || (rt->colormask != 0xf)) {
187bf215546Sopenharmony_ci         so->reads_dest = true;
188bf215546Sopenharmony_ci      }
189bf215546Sopenharmony_ci   }
190bf215546Sopenharmony_ci
191bf215546Sopenharmony_ci   util_dynarray_init(&so->variants, so);
192bf215546Sopenharmony_ci
193bf215546Sopenharmony_ci   return so;
194bf215546Sopenharmony_ci}
195bf215546Sopenharmony_ci
196bf215546Sopenharmony_civoid
197bf215546Sopenharmony_cifd6_blend_state_delete(struct pipe_context *pctx, void *hwcso)
198bf215546Sopenharmony_ci{
199bf215546Sopenharmony_ci   struct fd6_blend_stateobj *so = hwcso;
200bf215546Sopenharmony_ci
201bf215546Sopenharmony_ci   util_dynarray_foreach (&so->variants, struct fd6_blend_variant *, vp) {
202bf215546Sopenharmony_ci      struct fd6_blend_variant *v = *vp;
203bf215546Sopenharmony_ci      fd_ringbuffer_del(v->stateobj);
204bf215546Sopenharmony_ci   }
205bf215546Sopenharmony_ci
206bf215546Sopenharmony_ci   ralloc_free(so);
207bf215546Sopenharmony_ci}
208