1 /**************************************************************************
2 *
3 * Copyright 2011 Advanced Micro Devices, Inc.
4 *
5 * SPDX-License-Identifier: MIT
6 *
7 **************************************************************************/
8
9 #include "drm-uapi/drm_fourcc.h"
10 #include "radeon_uvd.h"
11 #include "radeon_uvd_enc.h"
12 #include "radeon_vce.h"
13 #include "radeon_vcn_dec.h"
14 #include "radeon_vcn_enc.h"
15 #include "radeon_video.h"
16 #include "si_pipe.h"
17 #include "si_vpe.h"
18 #include "util/u_video.h"
19
20 /**
21 * creates an video buffer with an UVD compatible memory layout
22 */
si_video_buffer_create(struct pipe_context * pipe,const struct pipe_video_buffer * tmpl)23 struct pipe_video_buffer *si_video_buffer_create(struct pipe_context *pipe,
24 const struct pipe_video_buffer *tmpl)
25 {
26 struct pipe_video_buffer vidbuf = *tmpl;
27 uint64_t *modifiers = NULL;
28 int modifiers_count = 0;
29 uint64_t mod = DRM_FORMAT_MOD_LINEAR;
30
31 if (tmpl->bind & (PIPE_BIND_VIDEO_DECODE_DPB | PIPE_BIND_VIDEO_ENCODE_DPB))
32 return vl_video_buffer_create_as_resource(pipe, &vidbuf, NULL, 0);
33
34 /* To get tiled buffers, users need to explicitly provide a list of
35 * modifiers. */
36 vidbuf.bind |= PIPE_BIND_LINEAR;
37
38 if (pipe->screen->resource_create_with_modifiers) {
39 modifiers = &mod;
40 modifiers_count = 1;
41 }
42
43 return vl_video_buffer_create_as_resource(pipe, &vidbuf, modifiers,
44 modifiers_count);
45 }
46
si_video_buffer_create_with_modifiers(struct pipe_context * pipe,const struct pipe_video_buffer * tmpl,const uint64_t * modifiers,unsigned int modifiers_count)47 struct pipe_video_buffer *si_video_buffer_create_with_modifiers(struct pipe_context *pipe,
48 const struct pipe_video_buffer *tmpl,
49 const uint64_t *modifiers,
50 unsigned int modifiers_count)
51 {
52 uint64_t *allowed_modifiers;
53 unsigned int allowed_modifiers_count, i;
54
55 /* Filter out DCC modifiers, because we don't support them for video
56 * for now. */
57 allowed_modifiers = calloc(modifiers_count, sizeof(uint64_t));
58 if (!allowed_modifiers)
59 return NULL;
60
61 allowed_modifiers_count = 0;
62 for (i = 0; i < modifiers_count; i++) {
63 if (ac_modifier_has_dcc(modifiers[i]))
64 continue;
65 allowed_modifiers[allowed_modifiers_count++] = modifiers[i];
66 }
67
68 struct pipe_video_buffer *buf =
69 vl_video_buffer_create_as_resource(pipe, tmpl, allowed_modifiers, allowed_modifiers_count);
70 free(allowed_modifiers);
71 return buf;
72 }
73
74 /* set the decoding target buffer offsets */
si_uvd_set_dtb(struct ruvd_msg * msg,struct vl_video_buffer * buf)75 static struct pb_buffer_lean *si_uvd_set_dtb(struct ruvd_msg *msg, struct vl_video_buffer *buf)
76 {
77 struct si_screen *sscreen = (struct si_screen *)buf->base.context->screen;
78 struct si_texture *luma = (struct si_texture *)buf->resources[0];
79 struct si_texture *chroma = (struct si_texture *)buf->resources[1];
80 enum ruvd_surface_type type =
81 (sscreen->info.gfx_level >= GFX9) ? RUVD_SURFACE_TYPE_GFX9 : RUVD_SURFACE_TYPE_LEGACY;
82
83 msg->body.decode.dt_field_mode = buf->base.interlaced;
84
85 si_uvd_set_dt_surfaces(msg, &luma->surface, (chroma) ? &chroma->surface : NULL, type);
86
87 return luma->buffer.buf;
88 }
89
90 /* get the radeon resources for VCE */
si_vce_get_buffer(struct pipe_resource * resource,struct pb_buffer_lean ** handle,struct radeon_surf ** surface)91 static void si_vce_get_buffer(struct pipe_resource *resource, struct pb_buffer_lean **handle,
92 struct radeon_surf **surface)
93 {
94 struct si_texture *res = (struct si_texture *)resource;
95
96 if (handle)
97 *handle = res->buffer.buf;
98
99 if (surface)
100 *surface = &res->surface;
101 }
102
si_vcn_need_context(struct si_context * ctx)103 static bool si_vcn_need_context(struct si_context *ctx)
104 {
105 /* Kernel does VCN instance scheduling per context, so when we have
106 * multiple instances we should use new context to be able to utilize
107 * all of them.
108 * Another issue is with AV1, VCN 3 and VCN 4 only support AV1 on
109 * first instance. Kernel parses IBs and switches to first instance when
110 * it detects AV1, but this only works for first submitted IB in context.
111 * The CS would be rejected if we first decode/encode other codecs, kernel
112 * schedules on second instance (default) and then we try to decode/encode AV1.
113 */
114 return ctx->screen->info.ip[AMD_IP_VCN_ENC].num_instances > 1;
115 }
116
117 /**
118 * creates an UVD compatible decoder
119 */
si_uvd_create_decoder(struct pipe_context * context,const struct pipe_video_codec * templ)120 struct pipe_video_codec *si_uvd_create_decoder(struct pipe_context *context,
121 const struct pipe_video_codec *templ)
122 {
123 struct si_context *ctx = (struct si_context *)context;
124 bool vcn = ctx->vcn_ip_ver >= VCN_1_0_0;
125 struct pipe_video_codec *codec = NULL;
126
127 if (templ->entrypoint == PIPE_VIDEO_ENTRYPOINT_ENCODE) {
128 if (vcn) {
129 codec = radeon_create_encoder(context, templ, ctx->ws, si_vce_get_buffer);
130 ctx->vcn_has_ctx = si_vcn_need_context(ctx);
131 return codec;
132 } else {
133 if (u_reduce_video_profile(templ->profile) == PIPE_VIDEO_FORMAT_HEVC)
134 return radeon_uvd_create_encoder(context, templ, ctx->ws, si_vce_get_buffer);
135 else
136 return si_vce_create_encoder(context, templ, ctx->ws, si_vce_get_buffer);
137 }
138 } else if (((struct si_screen *)(context->screen))->info.ip[AMD_IP_VPE].num_queues &&
139 templ->entrypoint == PIPE_VIDEO_ENTRYPOINT_PROCESSING)
140 return si_vpe_create_processor(context, templ);
141
142 if (vcn) {
143 codec = radeon_create_decoder(context, templ);
144 ctx->vcn_has_ctx = si_vcn_need_context(ctx);
145 return codec;
146 }
147 return si_common_uvd_create_decoder(context, templ, si_uvd_set_dtb);
148 }
149