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