1 /**************************************************************************
3 * Copyright 2017 Advanced Micro Devices, Inc.
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 * IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 **************************************************************************/
30 #include "pipe/p_video_codec.h"
32 #include "util/u_video.h"
33 #include "util/u_memory.h"
35 #include "vl/vl_video_buffer.h"
37 #include "radeonsi/si_pipe.h"
38 #include "radeon_video.h"
39 #include "radeon_vcn_enc.h"
41 static void radeon_vcn_enc_get_param(struct radeon_encoder
*enc
, struct pipe_h264_enc_picture_desc
*pic
)
43 enc
->enc_pic
.picture_type
= pic
->picture_type
;
44 enc
->enc_pic
.frame_num
= pic
->frame_num
;
45 enc
->enc_pic
.pic_order_cnt
= pic
->pic_order_cnt
;
46 enc
->enc_pic
.pic_order_cnt_type
= pic
->pic_order_cnt_type
;
47 enc
->enc_pic
.ref_idx_l0
= pic
->ref_idx_l0
;
48 enc
->enc_pic
.ref_idx_l1
= pic
->ref_idx_l1
;
49 enc
->enc_pic
.not_referenced
= pic
->not_referenced
;
50 enc
->enc_pic
.is_idr
= (pic
->picture_type
== PIPE_H264_ENC_PICTURE_TYPE_IDR
);
51 enc
->enc_pic
.crop_left
= 0;
52 enc
->enc_pic
.crop_right
= (align(enc
->base
.width
, 16) - enc
->base
.width
) / 2;
53 enc
->enc_pic
.crop_top
= 0;
54 enc
->enc_pic
.crop_bottom
= (align(enc
->base
.height
, 16) - enc
->base
.height
) / 2;
57 static void flush(struct radeon_encoder
*enc
)
59 enc
->ws
->cs_flush(enc
->cs
, PIPE_FLUSH_ASYNC
, NULL
);
62 static void radeon_enc_flush(struct pipe_video_codec
*encoder
)
64 struct radeon_encoder
*enc
= (struct radeon_encoder
*)encoder
;
68 static void radeon_enc_cs_flush(void *ctx
, unsigned flags
,
69 struct pipe_fence_handle
**fence
)
74 static unsigned get_cpb_num(struct radeon_encoder
*enc
)
76 unsigned w
= align(enc
->base
.width
, 16) / 16;
77 unsigned h
= align(enc
->base
.height
, 16) / 16;
80 switch (enc
->base
.level
) {
122 return MIN2(dpb
/ (w
* h
), 16);
125 static void radeon_enc_begin_frame(struct pipe_video_codec
*encoder
,
126 struct pipe_video_buffer
*source
,
127 struct pipe_picture_desc
*picture
)
129 struct radeon_encoder
*enc
= (struct radeon_encoder
*)encoder
;
130 struct vl_video_buffer
*vid_buf
= (struct vl_video_buffer
*)source
;
131 struct pipe_h264_enc_picture_desc
*pic
= (struct pipe_h264_enc_picture_desc
*)picture
;
133 radeon_vcn_enc_get_param(enc
, pic
);
135 enc
->get_buffer(vid_buf
->resources
[0], &enc
->handle
, &enc
->luma
);
136 enc
->get_buffer(vid_buf
->resources
[1], NULL
, &enc
->chroma
);
138 enc
->need_feedback
= false;
140 if (!enc
->stream_handle
) {
141 struct rvid_buffer fb
;
142 enc
->stream_handle
= si_vid_alloc_stream_handle();
143 enc
->si
= CALLOC_STRUCT(rvid_buffer
);
144 si_vid_create_buffer(enc
->screen
, enc
->si
, 128 * 1024, PIPE_USAGE_STAGING
);
145 si_vid_create_buffer(enc
->screen
, &fb
, 4096, PIPE_USAGE_STAGING
);
147 enc
->begin(enc
, pic
);
149 si_vid_destroy_buffer(&fb
);
153 static void radeon_enc_encode_bitstream(struct pipe_video_codec
*encoder
,
154 struct pipe_video_buffer
*source
,
155 struct pipe_resource
*destination
,
158 struct radeon_encoder
*enc
= (struct radeon_encoder
*)encoder
;
159 enc
->get_buffer(destination
, &enc
->bs_handle
, NULL
);
160 enc
->bs_size
= destination
->width0
;
162 *fb
= enc
->fb
= CALLOC_STRUCT(rvid_buffer
);
164 if (!si_vid_create_buffer(enc
->screen
, enc
->fb
, 4096, PIPE_USAGE_STAGING
)) {
165 RVID_ERR("Can't create feedback buffer.\n");
169 enc
->need_feedback
= true;
173 static void radeon_enc_end_frame(struct pipe_video_codec
*encoder
,
174 struct pipe_video_buffer
*source
,
175 struct pipe_picture_desc
*picture
)
177 struct radeon_encoder
*enc
= (struct radeon_encoder
*)encoder
;
181 static void radeon_enc_destroy(struct pipe_video_codec
*encoder
)
183 struct radeon_encoder
*enc
= (struct radeon_encoder
*)encoder
;
185 if (enc
->stream_handle
) {
186 struct rvid_buffer fb
;
187 enc
->need_feedback
= false;
188 si_vid_create_buffer(enc
->screen
, &fb
, 512, PIPE_USAGE_STAGING
);
192 si_vid_destroy_buffer(&fb
);
195 si_vid_destroy_buffer(&enc
->cpb
);
196 enc
->ws
->cs_destroy(enc
->cs
);
200 static void radeon_enc_get_feedback(struct pipe_video_codec
*encoder
,
201 void *feedback
, unsigned *size
)
203 struct radeon_encoder
*enc
= (struct radeon_encoder
*)encoder
;
204 struct rvid_buffer
*fb
= feedback
;
207 uint32_t *ptr
= enc
->ws
->buffer_map(fb
->res
->buf
, enc
->cs
, PIPE_TRANSFER_READ_WRITE
);
212 enc
->ws
->buffer_unmap(fb
->res
->buf
);
215 si_vid_destroy_buffer(fb
);
219 struct pipe_video_codec
*radeon_create_encoder(struct pipe_context
*context
,
220 const struct pipe_video_codec
*templ
,
221 struct radeon_winsys
* ws
,
222 radeon_enc_get_buffer get_buffer
)
224 struct si_screen
*sscreen
= (struct si_screen
*)context
->screen
;
225 struct r600_common_context
*rctx
= (struct r600_common_context
*)context
;
226 struct radeon_encoder
*enc
;
227 struct pipe_video_buffer
*tmp_buf
, templat
= {};
228 struct radeon_surf
*tmp_surf
;
231 enc
= CALLOC_STRUCT(radeon_encoder
);
236 enc
->alignment
= 256;
238 enc
->base
.context
= context
;
239 enc
->base
.destroy
= radeon_enc_destroy
;
240 enc
->base
.begin_frame
= radeon_enc_begin_frame
;
241 enc
->base
.encode_bitstream
= radeon_enc_encode_bitstream
;
242 enc
->base
.end_frame
= radeon_enc_end_frame
;
243 enc
->base
.flush
= radeon_enc_flush
;
244 enc
->base
.get_feedback
= radeon_enc_get_feedback
;
245 enc
->get_buffer
= get_buffer
;
246 enc
->bits_in_shifter
= 0;
247 enc
->screen
= context
->screen
;
249 enc
->cs
= ws
->cs_create(rctx
->ctx
, RING_VCN_ENC
, radeon_enc_cs_flush
, enc
);
252 RVID_ERR("Can't get command submission context.\n");
256 struct rvid_buffer si
;
257 si_vid_create_buffer(enc
->screen
, &si
, 128 * 1024, PIPE_USAGE_STAGING
);
260 templat
.buffer_format
= PIPE_FORMAT_NV12
;
261 templat
.chroma_format
= PIPE_VIDEO_CHROMA_FORMAT_420
;
262 templat
.width
= enc
->base
.width
;
263 templat
.height
= enc
->base
.height
;
264 templat
.interlaced
= false;
266 if (!(tmp_buf
= context
->create_video_buffer(context
, &templat
))) {
267 RVID_ERR("Can't create video buffer.\n");
271 enc
->cpb_num
= get_cpb_num(enc
);
276 get_buffer(((struct vl_video_buffer
*)tmp_buf
)->resources
[0], NULL
, &tmp_surf
);
278 cpb_size
= (sscreen
->info
.chip_class
< GFX9
) ?
279 align(tmp_surf
->u
.legacy
.level
[0].nblk_x
* tmp_surf
->bpe
, 128) *
280 align(tmp_surf
->u
.legacy
.level
[0].nblk_y
, 32) :
281 align(tmp_surf
->u
.gfx9
.surf_pitch
* tmp_surf
->bpe
, 256) *
282 align(tmp_surf
->u
.gfx9
.surf_height
, 32);
284 cpb_size
= cpb_size
* 3 / 2;
285 cpb_size
= cpb_size
* enc
->cpb_num
;
286 tmp_buf
->destroy(tmp_buf
);
288 if (!si_vid_create_buffer(enc
->screen
, &enc
->cpb
, cpb_size
, PIPE_USAGE_DEFAULT
)) {
289 RVID_ERR("Can't create CPB buffer.\n");
293 radeon_enc_1_2_init(enc
);
299 enc
->ws
->cs_destroy(enc
->cs
);
301 si_vid_destroy_buffer(&enc
->cpb
);