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