99edd0186d33c4466744933a73cae9b39affdaf2
[mesa.git] / src / gallium / drivers / freedreno / freedreno_blitter.c
1 /*
2 * Copyright (C) 2017 Rob Clark <robclark@freedesktop.org>
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 * SOFTWARE.
22 *
23 * Authors:
24 * Rob Clark <robclark@freedesktop.org>
25 */
26
27 #include "util/u_blitter.h"
28 #include "util/u_surface.h"
29
30 #include "freedreno_blitter.h"
31 #include "freedreno_context.h"
32 #include "freedreno_resource.h"
33
34 /* generic blit using u_blitter.. slightly modified version of util_blitter_blit
35 * which also handles PIPE_BUFFER:
36 */
37
38 static void
39 default_dst_texture(struct pipe_surface *dst_templ, struct pipe_resource *dst,
40 unsigned dstlevel, unsigned dstz)
41 {
42 memset(dst_templ, 0, sizeof(*dst_templ));
43 if (dst->target == PIPE_BUFFER)
44 dst_templ->format = PIPE_FORMAT_R8_UINT;
45 else
46 dst_templ->format = util_format_linear(dst->format);
47 dst_templ->u.tex.level = dstlevel;
48 dst_templ->u.tex.first_layer = dstz;
49 dst_templ->u.tex.last_layer = dstz;
50 }
51
52 static void
53 default_src_texture(struct pipe_sampler_view *src_templ,
54 struct pipe_resource *src, unsigned srclevel)
55 {
56 bool cube_as_2darray = src->screen->get_param(src->screen,
57 PIPE_CAP_SAMPLER_VIEW_TARGET);
58
59 memset(src_templ, 0, sizeof(*src_templ));
60
61 if (cube_as_2darray && (src->target == PIPE_TEXTURE_CUBE ||
62 src->target == PIPE_TEXTURE_CUBE_ARRAY))
63 src_templ->target = PIPE_TEXTURE_2D_ARRAY;
64 else
65 src_templ->target = src->target;
66
67 if (src->target == PIPE_BUFFER) {
68 src_templ->target = PIPE_TEXTURE_1D;
69 src_templ->format = PIPE_FORMAT_R8_UINT;
70 } else {
71 src_templ->format = util_format_linear(src->format);
72 }
73 src_templ->u.tex.first_level = srclevel;
74 src_templ->u.tex.last_level = srclevel;
75 src_templ->u.tex.first_layer = 0;
76 src_templ->u.tex.last_layer =
77 src->target == PIPE_TEXTURE_3D ? u_minify(src->depth0, srclevel) - 1
78 : (unsigned)(src->array_size - 1);
79 src_templ->swizzle_r = PIPE_SWIZZLE_X;
80 src_templ->swizzle_g = PIPE_SWIZZLE_Y;
81 src_templ->swizzle_b = PIPE_SWIZZLE_Z;
82 src_templ->swizzle_a = PIPE_SWIZZLE_W;
83 }
84
85 bool
86 fd_blitter_blit(struct fd_context *ctx, const struct pipe_blit_info *info)
87 {
88 struct pipe_resource *dst = info->dst.resource;
89 struct pipe_resource *src = info->src.resource;
90 struct pipe_context *pipe = &ctx->base;
91 struct pipe_surface *dst_view, dst_templ;
92 struct pipe_sampler_view src_templ, *src_view;
93 bool discard = false;
94
95 if (!info->scissor_enable && !info->alpha_blend) {
96 discard = util_texrange_covers_whole_level(info->dst.resource,
97 info->dst.level, info->dst.box.x, info->dst.box.y,
98 info->dst.box.z, info->dst.box.width,
99 info->dst.box.height, info->dst.box.depth);
100 }
101
102 fd_blitter_pipe_begin(ctx, info->render_condition_enable, discard, FD_STAGE_BLIT);
103
104 /* Initialize the surface. */
105 default_dst_texture(&dst_templ, dst, info->dst.level,
106 info->dst.box.z);
107 dst_templ.format = info->dst.format;
108 dst_view = pipe->create_surface(pipe, dst, &dst_templ);
109
110 /* Initialize the sampler view. */
111 default_src_texture(&src_templ, src, info->src.level);
112 src_templ.format = info->src.format;
113 src_view = pipe->create_sampler_view(pipe, src, &src_templ);
114
115 /* Copy. */
116 util_blitter_blit_generic(ctx->blitter, dst_view, &info->dst.box,
117 src_view, &info->src.box, src->width0, src->height0,
118 info->mask, info->filter,
119 info->scissor_enable ? &info->scissor : NULL,
120 info->alpha_blend);
121
122 pipe_surface_reference(&dst_view, NULL);
123 pipe_sampler_view_reference(&src_view, NULL);
124
125 fd_blitter_pipe_end(ctx);
126
127 /* The fallback blitter must never fail: */
128 return true;
129 }
130
131 /**
132 * _copy_region using pipe (3d engine)
133 */
134 static bool
135 fd_blitter_pipe_copy_region(struct fd_context *ctx,
136 struct pipe_resource *dst,
137 unsigned dst_level,
138 unsigned dstx, unsigned dsty, unsigned dstz,
139 struct pipe_resource *src,
140 unsigned src_level,
141 const struct pipe_box *src_box)
142 {
143 /* not until we allow rendertargets to be buffers */
144 if (dst->target == PIPE_BUFFER || src->target == PIPE_BUFFER)
145 return false;
146
147 if (!util_blitter_is_copy_supported(ctx->blitter, dst, src))
148 return false;
149
150 /* TODO we could discard if dst box covers dst level fully.. */
151 fd_blitter_pipe_begin(ctx, false, false, FD_STAGE_BLIT);
152 util_blitter_copy_texture(ctx->blitter,
153 dst, dst_level, dstx, dsty, dstz,
154 src, src_level, src_box);
155 fd_blitter_pipe_end(ctx);
156
157 return true;
158 }
159
160 /**
161 * Copy a block of pixels from one resource to another.
162 * The resource must be of the same format.
163 */
164 void
165 fd_resource_copy_region(struct pipe_context *pctx,
166 struct pipe_resource *dst,
167 unsigned dst_level,
168 unsigned dstx, unsigned dsty, unsigned dstz,
169 struct pipe_resource *src,
170 unsigned src_level,
171 const struct pipe_box *src_box)
172 {
173 struct fd_context *ctx = fd_context(pctx);
174
175 if (ctx->blit) {
176 struct pipe_blit_info info;
177
178 memset(&info, 0, sizeof info);
179 info.dst.resource = dst;
180 info.dst.level = dst_level;
181 info.dst.box.x = dstx;
182 info.dst.box.y = dsty;
183 info.dst.box.z = dstz;
184 info.dst.box.width = src_box->width;
185 info.dst.box.height = src_box->height;
186 assert(info.dst.box.width >= 0);
187 assert(info.dst.box.height >= 0);
188 info.dst.box.depth = 1;
189 info.dst.format = dst->format;
190 info.src.resource = src;
191 info.src.level = src_level;
192 info.src.box = *src_box;
193 info.src.format = src->format;
194 info.mask = util_format_get_mask(src->format);
195 info.filter = PIPE_TEX_FILTER_NEAREST;
196 info.scissor_enable = 0;
197
198 if (ctx->blit(ctx, &info))
199 return;
200 }
201
202 /* TODO if we have 2d core, or other DMA engine that could be used
203 * for simple copies and reasonably easily synchronized with the 3d
204 * core, this is where we'd plug it in..
205 */
206
207 /* try blit on 3d pipe: */
208 if (fd_blitter_pipe_copy_region(ctx,
209 dst, dst_level, dstx, dsty, dstz,
210 src, src_level, src_box))
211 return;
212
213 /* else fallback to pure sw: */
214 util_resource_copy_region(pctx,
215 dst, dst_level, dstx, dsty, dstz,
216 src, src_level, src_box);
217 }