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
35struct 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
55static 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 = fd_resource_ubwc_offset(rsc, lvl, pimg->u.tex.first_layer);
100		img->offset = fd_resource_offset(rsc, lvl, pimg->u.tex.first_layer);
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
133static 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
168static 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, A6XX_TEX_CONST_2_FETCHSIZE(img->fetchsize) |
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_UNK27));
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		OUT_RELOC(ring, rsc->bo, img->ubwc_offset, 0, 0);
196		OUT_RING(ring, A6XX_TEX_CONST_9_FLAG_BUFFER_ARRAY_PITCH(rsc->ubwc_size));
197		OUT_RING(ring, A6XX_TEX_CONST_10_FLAG_BUFFER_PITCH(rsc->ubwc_pitch));
198	} else {
199		OUT_RING(ring, 0x00000000);   /* texconst7 */
200		OUT_RING(ring, 0x00000000);   /* texconst8 */
201		OUT_RING(ring, 0x00000000);   /* texconst9 */
202		OUT_RING(ring, 0x00000000);   /* texconst10 */
203	}
204
205	OUT_RING(ring, 0x00000000);   /* texconst11 */
206	OUT_RING(ring, 0x00000000);   /* texconst12 */
207	OUT_RING(ring, 0x00000000);   /* texconst13 */
208	OUT_RING(ring, 0x00000000);   /* texconst14 */
209	OUT_RING(ring, 0x00000000);   /* texconst15 */
210}
211
212void
213fd6_emit_image_tex(struct fd_ringbuffer *ring, const struct pipe_image_view *pimg)
214{
215	struct fd6_image img;
216	translate_image(&img, pimg);
217	emit_image_tex(ring, &img);
218}
219
220void
221fd6_emit_ssbo_tex(struct fd_ringbuffer *ring, const struct pipe_shader_buffer *pbuf)
222{
223	struct fd6_image img;
224	translate_buf(&img, pbuf);
225	emit_image_tex(ring, &img);
226}
227
228static void emit_image_ssbo(struct fd_ringbuffer *ring, struct fd6_image *img)
229{
230	struct fd_resource *rsc = fd_resource(img->prsc);
231	enum a6xx_tile_mode tile_mode = TILE6_LINEAR;
232	bool ubwc_enabled = fd_resource_ubwc_enabled(rsc, img->level);
233
234	if (rsc->tile_mode && !fd_resource_level_linear(img->prsc, img->level)) {
235		tile_mode = rsc->tile_mode;
236	}
237
238	OUT_RING(ring, A6XX_IBO_0_FMT(img->fmt) |
239		A6XX_IBO_0_TILE_MODE(tile_mode));
240	OUT_RING(ring, A6XX_IBO_1_WIDTH(img->width) |
241		A6XX_IBO_1_HEIGHT(img->height));
242	OUT_RING(ring, A6XX_IBO_2_PITCH(img->pitch) |
243		COND(img->buffer, A6XX_IBO_2_UNK4 | A6XX_IBO_2_UNK31) |
244		A6XX_IBO_2_TYPE(img->type));
245	OUT_RING(ring, A6XX_IBO_3_ARRAY_PITCH(img->array_pitch) |
246		COND(ubwc_enabled, A6XX_IBO_3_FLAG | A6XX_IBO_3_UNK27));
247	if (img->bo) {
248		OUT_RELOCW(ring, img->bo, img->offset,
249			(uint64_t)A6XX_IBO_5_DEPTH(img->depth) << 32, 0);
250	} else {
251		OUT_RING(ring, 0x00000000);
252		OUT_RING(ring, A6XX_IBO_5_DEPTH(img->depth));
253	}
254	OUT_RING(ring, 0x00000000);
255
256	if (ubwc_enabled) {
257		OUT_RELOCW(ring, rsc->bo, img->ubwc_offset, 0, 0);
258		OUT_RING(ring, A6XX_IBO_9_FLAG_BUFFER_ARRAY_PITCH(rsc->ubwc_size));
259		OUT_RING(ring, A6XX_IBO_10_FLAG_BUFFER_PITCH(rsc->ubwc_pitch));
260	} else {
261		OUT_RING(ring, 0x00000000);
262		OUT_RING(ring, 0x00000000);
263		OUT_RING(ring, 0x00000000);
264		OUT_RING(ring, 0x00000000);
265	}
266
267	OUT_RING(ring, 0x00000000);
268	OUT_RING(ring, 0x00000000);
269	OUT_RING(ring, 0x00000000);
270	OUT_RING(ring, 0x00000000);
271	OUT_RING(ring, 0x00000000);
272}
273
274/* Build combined image/SSBO "IBO" state, returns ownership of state reference */
275struct fd_ringbuffer *
276fd6_build_ibo_state(struct fd_context *ctx, const struct ir3_shader_variant *v,
277		enum pipe_shader_type shader)
278{
279	struct fd_shaderbuf_stateobj *bufso = &ctx->shaderbuf[shader];
280	struct fd_shaderimg_stateobj *imgso = &ctx->shaderimg[shader];
281	const struct ir3_ibo_mapping *mapping = &v->image_mapping;
282
283	struct fd_ringbuffer *state =
284		fd_submit_new_ringbuffer(ctx->batch->submit,
285			mapping->num_ibo * 16 * 4, FD_RINGBUFFER_STREAMING);
286
287	assert(shader == PIPE_SHADER_COMPUTE || shader == PIPE_SHADER_FRAGMENT);
288
289	for (unsigned i = 0; i < mapping->num_ibo; i++) {
290		struct fd6_image img;
291		unsigned idx = mapping->ibo_to_image[i];
292
293		if (idx & IBO_SSBO) {
294			translate_buf(&img, &bufso->sb[idx & ~IBO_SSBO]);
295		} else {
296			translate_image(&img, &imgso->si[idx]);
297		}
298
299		emit_image_ssbo(state, &img);
300	}
301
302	return state;
303}
304