freedreno/a6xx: UBWC support for images
[mesa.git] / src / gallium / drivers / freedreno / a6xx / fd6_image.c
1 /*
2 * Copyright (C) 2017 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
30 #include "freedreno_resource.h"
31 #include "fd6_image.h"
32 #include "fd6_format.h"
33 #include "fd6_texture.h"
34
35 struct fd6_image {
36 struct pipe_resource *prsc;
37 enum pipe_format pfmt;
38 enum a6xx_tex_fmt fmt;
39 enum a6xx_tex_fetchsize fetchsize;
40 enum a6xx_tex_type type;
41 bool srgb;
42 uint32_t cpp;
43 uint32_t level;
44 uint32_t width;
45 uint32_t height;
46 uint32_t depth;
47 uint32_t pitch;
48 uint32_t array_pitch;
49 struct fd_bo *bo;
50 uint32_t ubwc_offset;
51 uint32_t offset;
52 bool buffer;
53 };
54
55 static void translate_image(struct fd6_image *img, const struct pipe_image_view *pimg)
56 {
57 enum pipe_format format = pimg->format;
58 struct pipe_resource *prsc = pimg->resource;
59 struct fd_resource *rsc = fd_resource(prsc);
60
61 if (!prsc) {
62 memset(img, 0, sizeof(*img));
63 return;
64 }
65
66 img->prsc = prsc;
67 img->pfmt = format;
68 img->fmt = fd6_pipe2tex(format);
69 img->fetchsize = fd6_pipe2fetchsize(format);
70 img->type = fd6_tex_type(prsc->target);
71 img->srgb = util_format_is_srgb(format);
72 img->cpp = rsc->cpp;
73 img->bo = rsc->bo;
74
75 /* Treat cube textures as 2d-array: */
76 if (img->type == A6XX_TEX_CUBE)
77 img->type = A6XX_TEX_2D;
78
79 if (prsc->target == PIPE_BUFFER) {
80 img->buffer = true;
81 img->ubwc_offset = 0; /* not valid for buffers */
82 img->offset = pimg->u.buf.offset;
83 img->pitch = 0;
84 img->array_pitch = 0;
85
86 /* size is encoded with low 15b in WIDTH and high bits in
87 * HEIGHT, in units of elements:
88 */
89 unsigned sz = prsc->width0;
90 img->width = sz & MASK(15);
91 img->height = sz >> 15;
92 img->depth = 0;
93 } else {
94 img->buffer = false;
95
96 unsigned lvl = pimg->u.tex.level;
97 unsigned layers = pimg->u.tex.last_layer - pimg->u.tex.first_layer + 1;
98
99 img->ubwc_offset = rsc->ubwc_offset; // TODO helper
100 img->offset = fd_resource_offset(rsc, lvl, pimg->u.tex.first_layer) + rsc->offset;
101 img->pitch = rsc->slices[lvl].pitch * rsc->cpp;
102
103 switch (prsc->target) {
104 case PIPE_TEXTURE_RECT:
105 case PIPE_TEXTURE_1D:
106 case PIPE_TEXTURE_2D:
107 img->array_pitch = rsc->layer_size;
108 img->depth = 1;
109 break;
110 case PIPE_TEXTURE_1D_ARRAY:
111 case PIPE_TEXTURE_2D_ARRAY:
112 case PIPE_TEXTURE_CUBE:
113 case PIPE_TEXTURE_CUBE_ARRAY:
114 img->array_pitch = rsc->layer_size;
115 // TODO the CUBE/CUBE_ARRAY might need to be layers/6 for tex state,
116 // but empirically for ibo state it shouldn't be divided.
117 img->depth = layers;
118 break;
119 case PIPE_TEXTURE_3D:
120 img->array_pitch = rsc->slices[lvl].size0;
121 img->depth = u_minify(prsc->depth0, lvl);
122 break;
123 default:
124 break;
125 }
126
127 img->level = lvl;
128 img->width = u_minify(prsc->width0, lvl);
129 img->height = u_minify(prsc->height0, lvl);
130 }
131 }
132
133 static void translate_buf(struct fd6_image *img, const struct pipe_shader_buffer *pimg)
134 {
135 enum pipe_format format = PIPE_FORMAT_R32_UINT;
136 struct pipe_resource *prsc = pimg->buffer;
137 struct fd_resource *rsc = fd_resource(prsc);
138
139 if (!prsc) {
140 memset(img, 0, sizeof(*img));
141 return;
142 }
143
144 img->prsc = prsc;
145 img->pfmt = format;
146 img->fmt = fd6_pipe2tex(format);
147 img->fetchsize = fd6_pipe2fetchsize(format);
148 img->type = fd6_tex_type(prsc->target);
149 img->srgb = util_format_is_srgb(format);
150 img->cpp = rsc->cpp;
151 img->bo = rsc->bo;
152 img->buffer = true;
153
154 img->ubwc_offset = 0; /* not valid for buffers */
155 img->offset = pimg->buffer_offset;
156 img->pitch = 0;
157 img->array_pitch = 0;
158
159 /* size is encoded with low 15b in WIDTH and high bits in HEIGHT,
160 * in units of elements:
161 */
162 unsigned sz = pimg->buffer_size / 4;
163 img->width = sz & MASK(15);
164 img->height = sz >> 15;
165 img->depth = 0;
166 }
167
168 static void emit_image_tex(struct fd_ringbuffer *ring, struct fd6_image *img)
169 {
170 struct fd_resource *rsc = fd_resource(img->prsc);
171 bool ubwc_enabled = rsc->ubwc_size &&
172 !fd_resource_level_linear(img->prsc, img->level);
173
174 OUT_RING(ring, fd6_tex_const_0(img->prsc, img->level, img->pfmt,
175 PIPE_SWIZZLE_X, PIPE_SWIZZLE_Y,
176 PIPE_SWIZZLE_Z, PIPE_SWIZZLE_W));
177 OUT_RING(ring, A6XX_TEX_CONST_1_WIDTH(img->width) |
178 A6XX_TEX_CONST_1_HEIGHT(img->height));
179 OUT_RING(ring, A6XX_TEX_CONST_2_FETCHSIZE(img->fetchsize) |
180 COND(img->buffer, A6XX_TEX_CONST_2_UNK4 | A6XX_TEX_CONST_2_UNK31) |
181 A6XX_TEX_CONST_2_TYPE(img->type) |
182 A6XX_TEX_CONST_2_PITCH(img->pitch));
183 OUT_RING(ring, A6XX_TEX_CONST_3_ARRAY_PITCH(img->array_pitch) |
184 COND(ubwc_enabled, A6XX_TEX_CONST_3_FLAG | A6XX_TEX_CONST_3_UNK27));
185 if (img->bo) {
186 OUT_RELOC(ring, img->bo, img->offset,
187 (uint64_t)A6XX_TEX_CONST_5_DEPTH(img->depth) << 32, 0);
188 } else {
189 OUT_RING(ring, 0x00000000);
190 OUT_RING(ring, A6XX_TEX_CONST_5_DEPTH(img->depth));
191 }
192
193 OUT_RING(ring, 0x00000000); /* texconst6 */
194
195 if (ubwc_enabled) {
196 OUT_RELOC(ring, rsc->bo, img->ubwc_offset, 0, 0);
197 OUT_RING(ring, A6XX_TEX_CONST_9_FLAG_BUFFER_ARRAY_PITCH(rsc->ubwc_size));
198 OUT_RING(ring, A6XX_TEX_CONST_10_FLAG_BUFFER_PITCH(rsc->ubwc_pitch));
199 } else {
200 OUT_RING(ring, 0x00000000); /* texconst7 */
201 OUT_RING(ring, 0x00000000); /* texconst8 */
202 OUT_RING(ring, 0x00000000); /* texconst9 */
203 OUT_RING(ring, 0x00000000); /* texconst10 */
204 }
205
206 OUT_RING(ring, 0x00000000); /* texconst11 */
207 OUT_RING(ring, 0x00000000); /* texconst12 */
208 OUT_RING(ring, 0x00000000); /* texconst13 */
209 OUT_RING(ring, 0x00000000); /* texconst14 */
210 OUT_RING(ring, 0x00000000); /* texconst15 */
211 }
212
213 void
214 fd6_emit_image_tex(struct fd_ringbuffer *ring, const struct pipe_image_view *pimg)
215 {
216 struct fd6_image img;
217 translate_image(&img, pimg);
218 emit_image_tex(ring, &img);
219 }
220
221 void
222 fd6_emit_ssbo_tex(struct fd_ringbuffer *ring, const struct pipe_shader_buffer *pbuf)
223 {
224 struct fd6_image img;
225 translate_buf(&img, pbuf);
226 emit_image_tex(ring, &img);
227 }
228
229 static void emit_image_ssbo(struct fd_ringbuffer *ring, struct fd6_image *img)
230 {
231 struct fd_resource *rsc = fd_resource(img->prsc);
232 enum a6xx_tile_mode tile_mode = TILE6_LINEAR;
233 bool ubwc_enabled = rsc->ubwc_size &&
234 !fd_resource_level_linear(img->prsc, img->level);
235
236 if (rsc->tile_mode && !fd_resource_level_linear(img->prsc, img->level)) {
237 tile_mode = rsc->tile_mode;
238 }
239
240 OUT_RING(ring, A6XX_IBO_0_FMT(img->fmt) |
241 A6XX_IBO_0_TILE_MODE(tile_mode));
242 OUT_RING(ring, A6XX_IBO_1_WIDTH(img->width) |
243 A6XX_IBO_1_HEIGHT(img->height));
244 OUT_RING(ring, A6XX_IBO_2_PITCH(img->pitch) |
245 COND(img->buffer, A6XX_IBO_2_UNK4 | A6XX_IBO_2_UNK31) |
246 A6XX_IBO_2_TYPE(img->type));
247 OUT_RING(ring, A6XX_IBO_3_ARRAY_PITCH(img->array_pitch) |
248 COND(ubwc_enabled, A6XX_IBO_3_FLAG | A6XX_IBO_3_UNK27));
249 if (img->bo) {
250 OUT_RELOCW(ring, img->bo, img->offset,
251 (uint64_t)A6XX_IBO_5_DEPTH(img->depth) << 32, 0);
252 } else {
253 OUT_RING(ring, 0x00000000);
254 OUT_RING(ring, A6XX_IBO_5_DEPTH(img->depth));
255 }
256 OUT_RING(ring, 0x00000000);
257
258 if (ubwc_enabled) {
259 OUT_RELOCW(ring, rsc->bo, img->ubwc_offset, 0, 0);
260 OUT_RING(ring, A6XX_IBO_9_FLAG_BUFFER_ARRAY_PITCH(rsc->ubwc_size));
261 OUT_RING(ring, A6XX_IBO_10_FLAG_BUFFER_PITCH(rsc->ubwc_pitch));
262 } else {
263 OUT_RING(ring, 0x00000000);
264 OUT_RING(ring, 0x00000000);
265 OUT_RING(ring, 0x00000000);
266 OUT_RING(ring, 0x00000000);
267 }
268
269 OUT_RING(ring, 0x00000000);
270 OUT_RING(ring, 0x00000000);
271 OUT_RING(ring, 0x00000000);
272 OUT_RING(ring, 0x00000000);
273 OUT_RING(ring, 0x00000000);
274 }
275
276 /* Build combined image/SSBO "IBO" state, returns ownership of state reference */
277 struct fd_ringbuffer *
278 fd6_build_ibo_state(struct fd_context *ctx, const struct ir3_shader_variant *v,
279 enum pipe_shader_type shader)
280 {
281 struct fd_shaderbuf_stateobj *bufso = &ctx->shaderbuf[shader];
282 struct fd_shaderimg_stateobj *imgso = &ctx->shaderimg[shader];
283 const struct ir3_ibo_mapping *mapping = &v->image_mapping;
284
285 struct fd_ringbuffer *state =
286 fd_submit_new_ringbuffer(ctx->batch->submit,
287 mapping->num_ibo * 16 * 4, FD_RINGBUFFER_STREAMING);
288
289 assert(shader == PIPE_SHADER_COMPUTE || shader == PIPE_SHADER_FRAGMENT);
290
291 for (unsigned i = 0; i < mapping->num_ibo; i++) {
292 struct fd6_image img;
293 unsigned idx = mapping->ibo_to_image[i];
294
295 if (idx & IBO_SSBO) {
296 translate_buf(&img, &bufso->sb[idx & ~IBO_SSBO]);
297 } else {
298 translate_image(&img, &imgso->si[idx]);
299 }
300
301 emit_image_ssbo(state, &img);
302 }
303
304 return state;
305 }