• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright © 2022 Raspberry Pi Ltd
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
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21  * IN THE SOFTWARE.
22  */
23 
24 #include "v3d_context.h"
25 #include "broadcom/common/v3d_tfu.h"
26 #include "util/perf/cpu_trace.h"
27 
28 bool
v3dX(tfu)29 v3dX(tfu)(struct pipe_context *pctx,
30           struct pipe_resource *pdst,
31           struct pipe_resource *psrc,
32           unsigned int src_level,
33           unsigned int base_level,
34           unsigned int last_level,
35           unsigned int src_layer,
36           unsigned int dst_layer,
37           bool for_mipmap)
38 {
39         struct v3d_context *v3d = v3d_context(pctx);
40         struct v3d_screen *screen = v3d->screen;
41         struct v3d_resource *src = v3d_resource(psrc);
42         struct v3d_resource *dst = v3d_resource(pdst);
43         struct v3d_resource_slice *src_base_slice = &src->slices[src_level];
44         struct v3d_resource_slice *dst_base_slice = &dst->slices[base_level];
45         int msaa_scale = pdst->nr_samples > 1 ? 2 : 1;
46         int width = u_minify(pdst->width0, base_level) * msaa_scale;
47         int height = u_minify(pdst->height0, base_level) * msaa_scale;
48         enum pipe_format pformat;
49 
50         if (psrc->format != pdst->format)
51                 return false;
52         if (psrc->nr_samples != pdst->nr_samples)
53                 return false;
54 
55         if (pdst->target != PIPE_TEXTURE_2D || psrc->target != PIPE_TEXTURE_2D)
56                 return false;
57 
58         /* Can't write to raster. */
59         if (dst_base_slice->tiling == V3D_TILING_RASTER)
60                 return false;
61 
62         /* When using TFU for blit, we are doing exact copies (both input and
63          * output format must be the same, no scaling, etc), so there is no
64          * pixel format conversions. Thus we can rewrite the format to use one
65          * that is TFU compatible based on its texel size.
66          */
67         if (for_mipmap) {
68                 pformat = pdst->format;
69         } else {
70                 switch (dst->cpp) {
71                 case 16: pformat = PIPE_FORMAT_R32G32B32A32_FLOAT;   break;
72                 case 8:  pformat = PIPE_FORMAT_R16G16B16A16_FLOAT;   break;
73                 case 4:  pformat = PIPE_FORMAT_R32_FLOAT;            break;
74                 case 2:  pformat = PIPE_FORMAT_R16_FLOAT;            break;
75                 case 1:  pformat = PIPE_FORMAT_R8_UNORM;             break;
76                 default: unreachable("unsupported format bit-size"); break;
77                 };
78         }
79 
80         uint32_t tex_format = v3d_get_tex_format(&screen->devinfo, pformat);
81 
82         if (!v3dX(tfu_supports_tex_format)(tex_format, for_mipmap)) {
83                 assert(for_mipmap);
84                 return false;
85         }
86 
87         MESA_TRACE_FUNC();
88 
89         v3d_flush_jobs_writing_resource(v3d, psrc, V3D_FLUSH_DEFAULT, false);
90         v3d_flush_jobs_reading_resource(v3d, pdst, V3D_FLUSH_DEFAULT, false);
91 
92         struct drm_v3d_submit_tfu tfu = {
93                 .ios = (height << 16) | width,
94                 .bo_handles = {
95                         dst->bo->handle,
96                         src != dst ? src->bo->handle : 0
97                 },
98                 .in_sync = v3d->out_sync,
99                 .out_sync = v3d->out_sync,
100         };
101         uint32_t src_offset = (src->bo->offset +
102                                v3d_layer_offset(psrc, src_level, src_layer));
103         tfu.iia |= src_offset;
104 
105         uint32_t dst_offset = (dst->bo->offset +
106                                v3d_layer_offset(pdst, base_level, dst_layer));
107         tfu.ioa |= dst_offset;
108 
109         switch (src_base_slice->tiling) {
110         case V3D_TILING_UIF_NO_XOR:
111         case V3D_TILING_UIF_XOR:
112                 tfu.iis |= (src_base_slice->padded_height /
113                             (2 * v3d_utile_height(src->cpp)));
114                 break;
115         case V3D_TILING_RASTER:
116                 tfu.iis |= src_base_slice->stride / src->cpp;
117                 break;
118         case V3D_TILING_LINEARTILE:
119         case V3D_TILING_UBLINEAR_1_COLUMN:
120         case V3D_TILING_UBLINEAR_2_COLUMN:
121                 break;
122        }
123 
124 #if V3D_VERSION == 42
125         if (src_base_slice->tiling == V3D_TILING_RASTER) {
126                 tfu.icfg |= (V3D33_TFU_ICFG_FORMAT_RASTER <<
127                              V3D33_TFU_ICFG_FORMAT_SHIFT);
128         } else {
129                 tfu.icfg |= ((V3D33_TFU_ICFG_FORMAT_LINEARTILE +
130                               (src_base_slice->tiling - V3D_TILING_LINEARTILE)) <<
131                              V3D33_TFU_ICFG_FORMAT_SHIFT);
132         }
133         tfu.icfg |= tex_format << V3D33_TFU_ICFG_TTYPE_SHIFT;
134 
135         if (last_level != base_level)
136                 tfu.ioa |= V3D33_TFU_IOA_DIMTW;
137 
138         tfu.ioa |= ((V3D33_TFU_IOA_FORMAT_LINEARTILE +
139                      (dst_base_slice->tiling - V3D_TILING_LINEARTILE)) <<
140                     V3D33_TFU_IOA_FORMAT_SHIFT);
141 
142         tfu.icfg |= (last_level - base_level) << V3D33_TFU_ICFG_NUMMM_SHIFT;
143 
144         /* If we're writing level 0 (!IOA_DIMTW), then we need to supply the
145          * OPAD field for the destination (how many extra UIF blocks beyond
146          * those necessary to cover the height).  When filling mipmaps, the
147          * miplevel 1+ tiling state is inferred.
148          */
149         if (dst_base_slice->tiling == V3D_TILING_UIF_NO_XOR ||
150             dst_base_slice->tiling == V3D_TILING_UIF_XOR) {
151                 int uif_block_h = 2 * v3d_utile_height(dst->cpp);
152                 int implicit_padded_height = align(height, uif_block_h);
153 
154                 tfu.icfg |= (((dst_base_slice->padded_height -
155                                implicit_padded_height) / uif_block_h) <<
156                              V3D33_TFU_ICFG_OPAD_SHIFT);
157         }
158 #endif /* V3D_VERSION == 42 */
159 
160 #if V3D_VERSION >= 71
161         if (src_base_slice->tiling == V3D_TILING_RASTER) {
162                 tfu.icfg = V3D71_TFU_ICFG_FORMAT_RASTER << V3D71_TFU_ICFG_IFORMAT_SHIFT;
163         } else {
164                 tfu.icfg = (V3D71_TFU_ICFG_FORMAT_LINEARTILE +
165                             (src_base_slice->tiling - V3D_TILING_LINEARTILE)) <<
166                         V3D71_TFU_ICFG_IFORMAT_SHIFT;
167         }
168         tfu.icfg |= tex_format << V3D71_TFU_ICFG_OTYPE_SHIFT;
169 
170         if (last_level != base_level)
171                 tfu.v71.ioc |= V3D71_TFU_IOC_DIMTW;
172 
173         tfu.v71.ioc |= ((V3D71_TFU_IOC_FORMAT_LINEARTILE +
174                          (dst_base_slice->tiling - V3D_TILING_LINEARTILE)) <<
175                         V3D71_TFU_IOC_FORMAT_SHIFT);
176 
177         switch (dst_base_slice->tiling) {
178         case V3D_TILING_UIF_NO_XOR:
179         case V3D_TILING_UIF_XOR:
180                 tfu.v71.ioc |=
181                         (dst_base_slice->padded_height / (2 * v3d_utile_height(dst->cpp))) <<
182                         V3D71_TFU_IOC_STRIDE_SHIFT;
183                 break;
184         case V3D_TILING_RASTER:
185                 tfu.v71.ioc |= (dst_base_slice->padded_height / dst->cpp) <<
186                         V3D71_TFU_IOC_STRIDE_SHIFT;
187                 break;
188         default:
189                 break;
190         }
191 
192         tfu.v71.ioc |= (last_level - base_level) << V3D71_TFU_IOC_NUMMM_SHIFT;
193 #endif /* V3D_VERSION >= 71*/
194 
195         int ret = v3d_ioctl(screen->fd, DRM_IOCTL_V3D_SUBMIT_TFU, &tfu);
196         if (ret != 0) {
197                 fprintf(stderr, "Failed to submit TFU job: %d\n", ret);
198                 return false;
199         }
200         if (V3D_DBG(SYNC)) {
201                 drmSyncobjWait(v3d->fd, &v3d->out_sync, 1, INT64_MAX,
202                                DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL, NULL);
203         }
204 
205         dst->writes++;
206 
207         return true;
208 }
209 
210