13b0923a90f463a5de2d94e84e3a21d2de04b0c8
[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 "freedreno_state.h"
32
33 #include "fd6_image.h"
34 #include "fd6_format.h"
35 #include "fd6_resource.h"
36 #include "fd6_texture.h"
37
38 struct fd6_image {
39 struct pipe_resource *prsc;
40 enum pipe_format pfmt;
41 enum a6xx_format fmt;
42 enum a6xx_tex_type type;
43 bool srgb;
44 uint32_t cpp;
45 uint32_t level;
46 uint32_t width;
47 uint32_t height;
48 uint32_t depth;
49 uint32_t pitch;
50 uint32_t array_pitch;
51 struct fd_bo *bo;
52 uint32_t ubwc_offset;
53 uint32_t offset;
54 bool buffer;
55 };
56
57 static void translate_image(struct fd6_image *img, const struct pipe_image_view *pimg)
58 {
59 enum pipe_format format = pimg->format;
60 struct pipe_resource *prsc = pimg->resource;
61 struct fd_resource *rsc = fd_resource(prsc);
62
63 if (!prsc) {
64 memset(img, 0, sizeof(*img));
65 return;
66 }
67
68 img->prsc = prsc;
69 img->pfmt = format;
70 img->fmt = fd6_pipe2tex(format);
71 img->type = fd6_tex_type(prsc->target);
72 img->srgb = util_format_is_srgb(format);
73 img->cpp = rsc->layout.cpp;
74 img->bo = rsc->bo;
75
76 /* Treat cube textures as 2d-array: */
77 if (img->type == A6XX_TEX_CUBE)
78 img->type = A6XX_TEX_2D;
79
80 if (prsc->target == PIPE_BUFFER) {
81 img->buffer = true;
82 img->ubwc_offset = 0; /* not valid for buffers */
83 img->offset = pimg->u.buf.offset;
84 img->pitch = 0;
85 img->array_pitch = 0;
86
87 /* size is encoded with low 15b in WIDTH and high bits in
88 * HEIGHT, in units of elements:
89 */
90 unsigned sz = pimg->u.buf.size / util_format_get_blocksize(format);
91 img->width = sz & MASK(15);
92 img->height = sz >> 15;
93 img->depth = 0;
94 } else {
95 img->buffer = false;
96
97 unsigned lvl = pimg->u.tex.level;
98 unsigned layers = pimg->u.tex.last_layer - pimg->u.tex.first_layer + 1;
99
100 img->ubwc_offset = fd_resource_ubwc_offset(rsc, lvl, pimg->u.tex.first_layer);
101 img->offset = fd_resource_offset(rsc, lvl, pimg->u.tex.first_layer);
102 img->pitch = fd_resource_pitch(rsc, lvl);
103
104 switch (prsc->target) {
105 case PIPE_TEXTURE_RECT:
106 case PIPE_TEXTURE_1D:
107 case PIPE_TEXTURE_2D:
108 img->array_pitch = rsc->layout.layer_size;
109 img->depth = 1;
110 break;
111 case PIPE_TEXTURE_1D_ARRAY:
112 case PIPE_TEXTURE_2D_ARRAY:
113 case PIPE_TEXTURE_CUBE:
114 case PIPE_TEXTURE_CUBE_ARRAY:
115 img->array_pitch = rsc->layout.layer_size;
116 // TODO the CUBE/CUBE_ARRAY might need to be layers/6 for tex state,
117 // but empirically for ibo state it shouldn't be divided.
118 img->depth = layers;
119 break;
120 case PIPE_TEXTURE_3D:
121 img->array_pitch = fd_resource_slice(rsc, lvl)->size0;
122 img->depth = u_minify(prsc->depth0, lvl);
123 break;
124 default:
125 break;
126 }
127
128 img->level = lvl;
129 img->width = u_minify(prsc->width0, lvl);
130 img->height = u_minify(prsc->height0, lvl);
131 }
132 }
133
134 static void translate_buf(struct fd6_image *img, const struct pipe_shader_buffer *pimg)
135 {
136 enum pipe_format format = PIPE_FORMAT_R32_UINT;
137 struct pipe_resource *prsc = pimg->buffer;
138 struct fd_resource *rsc = fd_resource(prsc);
139
140 if (!prsc) {
141 memset(img, 0, sizeof(*img));
142 return;
143 }
144
145 img->prsc = prsc;
146 img->pfmt = format;
147 img->fmt = fd6_pipe2tex(format);
148 img->type = fd6_tex_type(prsc->target);
149 img->srgb = util_format_is_srgb(format);
150 img->cpp = rsc->layout.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 = fd_resource_ubwc_enabled(rsc, img->level);
172
173 OUT_RING(ring, fd6_tex_const_0(img->prsc, img->level, img->pfmt,
174 PIPE_SWIZZLE_X, PIPE_SWIZZLE_Y,
175 PIPE_SWIZZLE_Z, PIPE_SWIZZLE_W));
176 OUT_RING(ring, A6XX_TEX_CONST_1_WIDTH(img->width) |
177 A6XX_TEX_CONST_1_HEIGHT(img->height));
178 OUT_RING(ring,
179 COND(img->buffer, A6XX_TEX_CONST_2_UNK4 | A6XX_TEX_CONST_2_UNK31) |
180 A6XX_TEX_CONST_2_TYPE(img->type) |
181 A6XX_TEX_CONST_2_PITCH(img->pitch));
182 OUT_RING(ring, A6XX_TEX_CONST_3_ARRAY_PITCH(img->array_pitch) |
183 COND(ubwc_enabled, A6XX_TEX_CONST_3_FLAG | A6XX_TEX_CONST_3_TILE_ALL));
184 if (img->bo) {
185 OUT_RELOC(ring, img->bo, img->offset,
186 (uint64_t)A6XX_TEX_CONST_5_DEPTH(img->depth) << 32, 0);
187 } else {
188 OUT_RING(ring, 0x00000000);
189 OUT_RING(ring, A6XX_TEX_CONST_5_DEPTH(img->depth));
190 }
191
192 OUT_RING(ring, 0x00000000); /* texconst6 */
193
194 if (ubwc_enabled) {
195 struct fdl_slice *ubwc_slice = &rsc->layout.ubwc_slices[img->level];
196
197 uint32_t block_width, block_height;
198 fdl6_get_ubwc_blockwidth(&rsc->layout, &block_width, &block_height);
199
200 OUT_RELOC(ring, rsc->bo, img->ubwc_offset, 0, 0);
201 OUT_RING(ring, A6XX_TEX_CONST_9_FLAG_BUFFER_ARRAY_PITCH(rsc->layout.ubwc_layer_size >> 2));
202 OUT_RING(ring,
203 A6XX_TEX_CONST_10_FLAG_BUFFER_PITCH(ubwc_slice->pitch) |
204 A6XX_TEX_CONST_10_FLAG_BUFFER_LOGW(util_logbase2_ceil(DIV_ROUND_UP(img->width, block_width))) |
205 A6XX_TEX_CONST_10_FLAG_BUFFER_LOGH(util_logbase2_ceil(DIV_ROUND_UP(img->height, block_height))));
206 } else {
207 OUT_RING(ring, 0x00000000); /* texconst7 */
208 OUT_RING(ring, 0x00000000); /* texconst8 */
209 OUT_RING(ring, 0x00000000); /* texconst9 */
210 OUT_RING(ring, 0x00000000); /* texconst10 */
211 }
212
213 OUT_RING(ring, 0x00000000); /* texconst11 */
214 OUT_RING(ring, 0x00000000); /* texconst12 */
215 OUT_RING(ring, 0x00000000); /* texconst13 */
216 OUT_RING(ring, 0x00000000); /* texconst14 */
217 OUT_RING(ring, 0x00000000); /* texconst15 */
218 }
219
220 void
221 fd6_emit_image_tex(struct fd_ringbuffer *ring, const struct pipe_image_view *pimg)
222 {
223 struct fd6_image img;
224 translate_image(&img, pimg);
225 emit_image_tex(ring, &img);
226 }
227
228 void
229 fd6_emit_ssbo_tex(struct fd_ringbuffer *ring, const struct pipe_shader_buffer *pbuf)
230 {
231 struct fd6_image img;
232 translate_buf(&img, pbuf);
233 emit_image_tex(ring, &img);
234 }
235
236 static void emit_image_ssbo(struct fd_ringbuffer *ring, struct fd6_image *img)
237 {
238 /* If the SSBO isn't present (becasue gallium doesn't pack atomic
239 * counters), zero-fill the slot.
240 */
241 if (!img->prsc) {
242 for (int i = 0; i < 16; i++)
243 OUT_RING(ring, 0);
244 return;
245 }
246
247 struct fd_resource *rsc = fd_resource(img->prsc);
248 enum a6xx_tile_mode tile_mode = fd_resource_tile_mode(img->prsc, img->level);
249 bool ubwc_enabled = fd_resource_ubwc_enabled(rsc, img->level);
250
251 OUT_RING(ring, A6XX_IBO_0_FMT(img->fmt) |
252 A6XX_IBO_0_TILE_MODE(tile_mode));
253 OUT_RING(ring, A6XX_IBO_1_WIDTH(img->width) |
254 A6XX_IBO_1_HEIGHT(img->height));
255 OUT_RING(ring, A6XX_IBO_2_PITCH(img->pitch) |
256 COND(img->buffer, A6XX_IBO_2_UNK4 | A6XX_IBO_2_UNK31) |
257 A6XX_IBO_2_TYPE(img->type));
258 OUT_RING(ring, A6XX_IBO_3_ARRAY_PITCH(img->array_pitch) |
259 COND(ubwc_enabled, A6XX_IBO_3_FLAG | A6XX_IBO_3_UNK27));
260 if (img->bo) {
261 OUT_RELOC(ring, img->bo, img->offset,
262 (uint64_t)A6XX_IBO_5_DEPTH(img->depth) << 32, 0);
263 } else {
264 OUT_RING(ring, 0x00000000);
265 OUT_RING(ring, A6XX_IBO_5_DEPTH(img->depth));
266 }
267 OUT_RING(ring, 0x00000000);
268
269 if (ubwc_enabled) {
270 struct fdl_slice *ubwc_slice = &rsc->layout.ubwc_slices[img->level];
271 OUT_RELOC(ring, rsc->bo, img->ubwc_offset, 0, 0);
272 OUT_RING(ring, A6XX_IBO_9_FLAG_BUFFER_ARRAY_PITCH(rsc->layout.ubwc_layer_size >> 2));
273 OUT_RING(ring, A6XX_IBO_10_FLAG_BUFFER_PITCH(ubwc_slice->pitch));
274 } else {
275 OUT_RING(ring, 0x00000000);
276 OUT_RING(ring, 0x00000000);
277 OUT_RING(ring, 0x00000000);
278 OUT_RING(ring, 0x00000000);
279 }
280
281 OUT_RING(ring, 0x00000000);
282 OUT_RING(ring, 0x00000000);
283 OUT_RING(ring, 0x00000000);
284 OUT_RING(ring, 0x00000000);
285 OUT_RING(ring, 0x00000000);
286 }
287
288 /* Build combined image/SSBO "IBO" state, returns ownership of state reference */
289 struct fd_ringbuffer *
290 fd6_build_ibo_state(struct fd_context *ctx, const struct ir3_shader_variant *v,
291 enum pipe_shader_type shader)
292 {
293 struct fd_shaderbuf_stateobj *bufso = &ctx->shaderbuf[shader];
294 struct fd_shaderimg_stateobj *imgso = &ctx->shaderimg[shader];
295
296 struct fd_ringbuffer *state =
297 fd_submit_new_ringbuffer(ctx->batch->submit,
298 (v->shader->nir->info.num_ssbos +
299 v->shader->nir->info.num_images) * 16 * 4,
300 FD_RINGBUFFER_STREAMING);
301
302 assert(shader == PIPE_SHADER_COMPUTE || shader == PIPE_SHADER_FRAGMENT);
303
304 for (unsigned i = 0; i < v->shader->nir->info.num_ssbos; i++) {
305 struct fd6_image img;
306 translate_buf(&img, &bufso->sb[i]);
307 emit_image_ssbo(state, &img);
308 }
309
310 for (unsigned i = 0; i < v->shader->nir->info.num_images; i++) {
311 struct fd6_image img;
312 translate_image(&img, &imgso->si[i]);
313 emit_image_ssbo(state, &img);
314 }
315
316 return state;
317 }
318
319 static void fd6_set_shader_images(struct pipe_context *pctx,
320 enum pipe_shader_type shader,
321 unsigned start, unsigned count,
322 const struct pipe_image_view *images)
323 {
324 struct fd_context *ctx = fd_context(pctx);
325 struct fd_shaderimg_stateobj *so = &ctx->shaderimg[shader];
326
327 fd_set_shader_images(pctx, shader, start, count, images);
328
329 if (!images)
330 return;
331
332 for (unsigned i = 0; i < count; i++) {
333 unsigned n = i + start;
334 struct pipe_image_view *buf = &so->si[n];
335
336 if (!buf->resource)
337 continue;
338
339 fd6_validate_format(ctx, fd_resource(buf->resource), buf->format);
340 }
341 }
342
343 void
344 fd6_image_init(struct pipe_context *pctx)
345 {
346 pctx->set_shader_images = fd6_set_shader_images;
347 }