xref: /aosp_15_r20/external/mesa3d/src/gallium/drivers/r600/radeon_video.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1 /*
2  * Copyright 2013 Advanced Micro Devices, Inc.
3  * Authors:
4  *      Christian König <[email protected]>
5  * SPDX-License-Identifier: MIT
6  */
7 
8 #include <unistd.h>
9 
10 #include "util/u_memory.h"
11 #include "util/u_video.h"
12 
13 #include "vl/vl_defines.h"
14 #include "vl/vl_video_buffer.h"
15 
16 #include "r600_pipe_common.h"
17 #include "radeon_video.h"
18 #include "radeon_vce.h"
19 
20 #define UVD_FW_1_66_16 ((1 << 24) | (66 << 16) | (16 << 8))
21 
22 /* generate an stream handle */
rvid_alloc_stream_handle()23 unsigned rvid_alloc_stream_handle()
24 {
25 	static unsigned counter = 0;
26 	unsigned stream_handle = 0;
27 	unsigned pid = getpid();
28 	int i;
29 
30 	for (i = 0; i < 32; ++i)
31 		stream_handle |= ((pid >> i) & 1) << (31 - i);
32 
33 	stream_handle ^= ++counter;
34 	return stream_handle;
35 }
36 
37 /* create a buffer in the winsys */
rvid_create_buffer(struct pipe_screen * screen,struct rvid_buffer * buffer,unsigned size,unsigned usage)38 bool rvid_create_buffer(struct pipe_screen *screen, struct rvid_buffer *buffer,
39 			unsigned size, unsigned usage)
40 {
41 	memset(buffer, 0, sizeof(*buffer));
42 	buffer->usage = usage;
43 
44 	/* Hardware buffer placement restrictions require the kernel to be
45 	 * able to move buffers around individually, so request a
46 	 * non-sub-allocated buffer.
47 	 */
48 	buffer->res = (struct r600_resource *)
49 		pipe_buffer_create(screen, PIPE_BIND_SHARED,
50 				   usage, size);
51 
52 	return buffer->res != NULL;
53 }
54 
55 /* destroy a buffer */
rvid_destroy_buffer(struct rvid_buffer * buffer)56 void rvid_destroy_buffer(struct rvid_buffer *buffer)
57 {
58 	r600_resource_reference(&buffer->res, NULL);
59 }
60 
61 /* reallocate a buffer, preserving its content */
rvid_resize_buffer(struct pipe_screen * screen,struct radeon_cmdbuf * cs,struct rvid_buffer * new_buf,unsigned new_size)62 bool rvid_resize_buffer(struct pipe_screen *screen, struct radeon_cmdbuf *cs,
63 			struct rvid_buffer *new_buf, unsigned new_size)
64 {
65 	struct r600_common_screen *rscreen = (struct r600_common_screen *)screen;
66 	struct radeon_winsys* ws = rscreen->ws;
67 	unsigned bytes = MIN2(new_buf->res->buf->size, new_size);
68 	struct rvid_buffer old_buf = *new_buf;
69 	void *src = NULL, *dst = NULL;
70 
71 	if (!rvid_create_buffer(screen, new_buf, new_size, new_buf->usage))
72 		goto error;
73 
74 	src = ws->buffer_map(ws, old_buf.res->buf, cs,
75 			     PIPE_MAP_READ | RADEON_MAP_TEMPORARY);
76 	if (!src)
77 		goto error;
78 
79 	dst = ws->buffer_map(ws, new_buf->res->buf, cs,
80 			     PIPE_MAP_WRITE | RADEON_MAP_TEMPORARY);
81 	if (!dst)
82 		goto error;
83 
84 	memcpy(dst, src, bytes);
85 	if (new_size > bytes) {
86 		new_size -= bytes;
87 		dst += bytes;
88 		memset(dst, 0, new_size);
89 	}
90 	ws->buffer_unmap(ws, new_buf->res->buf);
91 	ws->buffer_unmap(ws, old_buf.res->buf);
92 	rvid_destroy_buffer(&old_buf);
93 	return true;
94 
95 error:
96 	if (src)
97 		ws->buffer_unmap(ws, old_buf.res->buf);
98 	rvid_destroy_buffer(new_buf);
99 	*new_buf = old_buf;
100 	return false;
101 }
102 
103 /* clear the buffer with zeros */
rvid_clear_buffer(struct pipe_context * context,struct rvid_buffer * buffer)104 void rvid_clear_buffer(struct pipe_context *context, struct rvid_buffer* buffer)
105 {
106 	struct r600_common_context *rctx = (struct r600_common_context*)context;
107 
108 	rctx->dma_clear_buffer(context, &buffer->res->b.b, 0,
109 			       buffer->res->buf->size, 0);
110 	context->flush(context, NULL, 0);
111 }
112 
113 /**
114  * join surfaces into the same buffer with identical tiling params
115  * sumup their sizes and replace the backend buffers with a single bo
116  */
rvid_join_surfaces(struct r600_common_context * rctx,struct pb_buffer_lean ** buffers[VL_NUM_COMPONENTS],struct radeon_surf * surfaces[VL_NUM_COMPONENTS])117 void rvid_join_surfaces(struct r600_common_context *rctx,
118 			struct pb_buffer_lean** buffers[VL_NUM_COMPONENTS],
119 			struct radeon_surf *surfaces[VL_NUM_COMPONENTS])
120 {
121 	struct radeon_winsys* ws;
122 	unsigned best_tiling, best_wh, off;
123 	unsigned size, alignment;
124 	struct pb_buffer_lean *pb;
125 	unsigned i, j;
126 
127 	ws = rctx->ws;
128 
129 	for (i = 0, best_tiling = 0, best_wh = ~0; i < VL_NUM_COMPONENTS; ++i) {
130 		unsigned wh;
131 
132 		if (!surfaces[i])
133 			continue;
134 
135 		/* choose the smallest bank w/h for now */
136 		wh = surfaces[i]->u.legacy.bankw * surfaces[i]->u.legacy.bankh;
137 		if (wh < best_wh) {
138 			best_wh = wh;
139 			best_tiling = i;
140 		}
141 	}
142 
143 	for (i = 0, off = 0; i < VL_NUM_COMPONENTS; ++i) {
144 		if (!surfaces[i])
145 			continue;
146 
147 		/* adjust the texture layer offsets */
148 		off = align(off, 1 << surfaces[i]->surf_alignment_log2);
149 
150 		/* copy the tiling parameters */
151 		surfaces[i]->u.legacy.bankw = surfaces[best_tiling]->u.legacy.bankw;
152 		surfaces[i]->u.legacy.bankh = surfaces[best_tiling]->u.legacy.bankh;
153 		surfaces[i]->u.legacy.mtilea = surfaces[best_tiling]->u.legacy.mtilea;
154 		surfaces[i]->u.legacy.tile_split = surfaces[best_tiling]->u.legacy.tile_split;
155 
156 		for (j = 0; j < ARRAY_SIZE(surfaces[i]->u.legacy.level); ++j)
157 			surfaces[i]->u.legacy.level[j].offset_256B += off / 256;
158 
159 		off += surfaces[i]->surf_size;
160 	}
161 
162 	for (i = 0, size = 0, alignment = 0; i < VL_NUM_COMPONENTS; ++i) {
163 		if (!buffers[i] || !*buffers[i])
164 			continue;
165 
166 		size = align(size, 1 << (*buffers[i])->alignment_log2);
167 		size += (*buffers[i])->size;
168 		alignment = MAX2(alignment, 1 << (*buffers[i])->alignment_log2);
169 	}
170 
171 	if (!size)
172 		return;
173 
174 	/* TODO: 2D tiling workaround */
175 	alignment *= 2;
176 
177 	pb = ws->buffer_create(ws, size, alignment, RADEON_DOMAIN_VRAM,
178 			       RADEON_FLAG_GTT_WC);
179 	if (!pb)
180 		return;
181 
182 	for (i = 0; i < VL_NUM_COMPONENTS; ++i) {
183 		if (!buffers[i] || !*buffers[i])
184 			continue;
185 
186 		radeon_bo_reference(rctx->ws, buffers[i], pb);
187 	}
188 
189 	radeon_bo_reference(rctx->ws, &pb, NULL);
190 }
191 
rvid_get_video_param(struct pipe_screen * screen,enum pipe_video_profile profile,enum pipe_video_entrypoint entrypoint,enum pipe_video_cap param)192 int rvid_get_video_param(struct pipe_screen *screen,
193 			 enum pipe_video_profile profile,
194 			 enum pipe_video_entrypoint entrypoint,
195 			 enum pipe_video_cap param)
196 {
197 	struct r600_common_screen *rscreen = (struct r600_common_screen *)screen;
198 	enum pipe_video_format codec = u_reduce_video_profile(profile);
199 	struct radeon_info info;
200 
201 	rscreen->ws->query_info(rscreen->ws, &info);
202 
203 	if (entrypoint == PIPE_VIDEO_ENTRYPOINT_ENCODE) {
204 		switch (param) {
205 		case PIPE_VIDEO_CAP_SUPPORTED:
206 			return codec == PIPE_VIDEO_FORMAT_MPEG4_AVC &&
207 				rvce_is_fw_version_supported(rscreen);
208 		case PIPE_VIDEO_CAP_NPOT_TEXTURES:
209 			return 1;
210 		case PIPE_VIDEO_CAP_MAX_WIDTH:
211 			return 2048;
212 		case PIPE_VIDEO_CAP_MAX_HEIGHT:
213 			return 1152;
214 		case PIPE_VIDEO_CAP_PREFERED_FORMAT:
215 			return PIPE_FORMAT_NV12;
216 		case PIPE_VIDEO_CAP_PREFERS_INTERLACED:
217 			return false;
218 		case PIPE_VIDEO_CAP_SUPPORTS_INTERLACED:
219 			return false;
220 		case PIPE_VIDEO_CAP_SUPPORTS_PROGRESSIVE:
221 			return true;
222 		case PIPE_VIDEO_CAP_STACKED_FRAMES:
223 			return 1;
224 		default:
225 			return 0;
226 		}
227 	}
228 
229 	switch (param) {
230 	case PIPE_VIDEO_CAP_SUPPORTED:
231 		switch (codec) {
232 		case PIPE_VIDEO_FORMAT_MPEG12:
233 			return profile != PIPE_VIDEO_PROFILE_MPEG1;
234 		case PIPE_VIDEO_FORMAT_MPEG4:
235 			/* no support for MPEG4 on older hw */
236 			return rscreen->family >= CHIP_PALM;
237 		case PIPE_VIDEO_FORMAT_MPEG4_AVC:
238 			return true;
239 		case PIPE_VIDEO_FORMAT_VC1:
240 			return true;
241 		case PIPE_VIDEO_FORMAT_HEVC:
242 			return false;
243 		case PIPE_VIDEO_FORMAT_JPEG:
244 			return false;
245 		default:
246 			return false;
247 		}
248 	case PIPE_VIDEO_CAP_NPOT_TEXTURES:
249 		return 1;
250 	case PIPE_VIDEO_CAP_MAX_WIDTH:
251 		return 2048;
252 	case PIPE_VIDEO_CAP_MAX_HEIGHT:
253 		return 1152;
254 	case PIPE_VIDEO_CAP_PREFERED_FORMAT:
255 		return PIPE_FORMAT_NV12;
256 
257 	case PIPE_VIDEO_CAP_PREFERS_INTERLACED:
258 	case PIPE_VIDEO_CAP_SUPPORTS_INTERLACED:
259 		if (rscreen->family < CHIP_PALM) {
260 			/* MPEG2 only with shaders and no support for
261 			   interlacing on R6xx style UVD */
262 			return codec != PIPE_VIDEO_FORMAT_MPEG12 &&
263 			       rscreen->family > CHIP_RV770;
264 		} else {
265 			enum pipe_video_format format = u_reduce_video_profile(profile);
266 
267 			if (format == PIPE_VIDEO_FORMAT_JPEG)
268 				return false;
269 			return true;
270 		}
271 	case PIPE_VIDEO_CAP_SUPPORTS_PROGRESSIVE:
272 		return true;
273 	case PIPE_VIDEO_CAP_MAX_LEVEL:
274 		switch (profile) {
275 		case PIPE_VIDEO_PROFILE_MPEG1:
276 			return 0;
277 		case PIPE_VIDEO_PROFILE_MPEG2_SIMPLE:
278 		case PIPE_VIDEO_PROFILE_MPEG2_MAIN:
279 			return 3;
280 		case PIPE_VIDEO_PROFILE_MPEG4_SIMPLE:
281 			return 3;
282 		case PIPE_VIDEO_PROFILE_MPEG4_ADVANCED_SIMPLE:
283 			return 5;
284 		case PIPE_VIDEO_PROFILE_VC1_SIMPLE:
285 			return 1;
286 		case PIPE_VIDEO_PROFILE_VC1_MAIN:
287 			return 2;
288 		case PIPE_VIDEO_PROFILE_VC1_ADVANCED:
289 			return 4;
290 		case PIPE_VIDEO_PROFILE_MPEG4_AVC_BASELINE:
291 		case PIPE_VIDEO_PROFILE_MPEG4_AVC_MAIN:
292 		case PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH:
293 			return 41;
294 		default:
295 			return 0;
296 		}
297 	default:
298 		return 0;
299 	}
300 }
301 
rvid_is_format_supported(struct pipe_screen * screen,enum pipe_format format,enum pipe_video_profile profile,enum pipe_video_entrypoint entrypoint)302 bool rvid_is_format_supported(struct pipe_screen *screen,
303 			      enum pipe_format format,
304 			      enum pipe_video_profile profile,
305 			      enum pipe_video_entrypoint entrypoint)
306 {
307 	/* we can only handle this one with UVD */
308 	if (profile != PIPE_VIDEO_PROFILE_UNKNOWN)
309 		return format == PIPE_FORMAT_NV12;
310 
311 	return vl_video_buffer_is_format_supported(screen, format, profile, entrypoint);
312 }
313