1 /**************************************************************************
3 * Copyright 2013 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 * Christian König <christian.koenig@amd.com>
36 #include "pipe/p_video_codec.h"
38 #include "util/u_video.h"
39 #include "util/u_memory.h"
41 #include "vl/vl_video_buffer.h"
43 #include "r600_pipe_common.h"
44 #include "radeon_video.h"
45 #include "radeon_vce.h"
48 * flush commands to the hardware
50 static void flush(struct rvce_encoder
*enc
)
52 enc
->ws
->cs_flush(enc
->cs
, RADEON_FLUSH_ASYNC
, NULL
, 0);
56 static void dump_feedback(struct rvce_encoder
*enc
, struct rvid_buffer
*fb
)
58 uint32_t *ptr
= enc
->ws
->buffer_map(fb
->res
->cs_buf
, enc
->cs
, PIPE_TRANSFER_READ_WRITE
);
60 fprintf(stderr
, "\n");
61 fprintf(stderr
, "encStatus:\t\t\t%08x\n", ptr
[i
++]);
62 fprintf(stderr
, "encHasBitstream:\t\t%08x\n", ptr
[i
++]);
63 fprintf(stderr
, "encHasAudioBitstream:\t\t%08x\n", ptr
[i
++]);
64 fprintf(stderr
, "encBitstreamOffset:\t\t%08x\n", ptr
[i
++]);
65 fprintf(stderr
, "encBitstreamSize:\t\t%08x\n", ptr
[i
++]);
66 fprintf(stderr
, "encAudioBitstreamOffset:\t%08x\n", ptr
[i
++]);
67 fprintf(stderr
, "encAudioBitstreamSize:\t\t%08x\n", ptr
[i
++]);
68 fprintf(stderr
, "encExtrabytes:\t\t\t%08x\n", ptr
[i
++]);
69 fprintf(stderr
, "encAudioExtrabytes:\t\t%08x\n", ptr
[i
++]);
70 fprintf(stderr
, "videoTimeStamp:\t\t\t%08x\n", ptr
[i
++]);
71 fprintf(stderr
, "audioTimeStamp:\t\t\t%08x\n", ptr
[i
++]);
72 fprintf(stderr
, "videoOutputType:\t\t%08x\n", ptr
[i
++]);
73 fprintf(stderr
, "attributeFlags:\t\t\t%08x\n", ptr
[i
++]);
74 fprintf(stderr
, "seiPrivatePackageOffset:\t%08x\n", ptr
[i
++]);
75 fprintf(stderr
, "seiPrivatePackageSize:\t\t%08x\n", ptr
[i
++]);
76 fprintf(stderr
, "\n");
77 enc
->ws
->buffer_unmap(fb
->res
->cs_buf
);
82 * reset the CPB handling
84 static void reset_cpb(struct rvce_encoder
*enc
)
88 LIST_INITHEAD(&enc
->cpb_slots
);
89 for (i
= 0; i
< enc
->cpb_num
; ++i
) {
90 struct rvce_cpb_slot
*slot
= &enc
->cpb_array
[i
];
92 slot
->picture_type
= PIPE_H264_ENC_PICTURE_TYPE_SKIP
;
94 slot
->pic_order_cnt
= 0;
95 LIST_ADDTAIL(&slot
->list
, &enc
->cpb_slots
);
100 * sort l0 and l1 to the top of the list
102 static void sort_cpb(struct rvce_encoder
*enc
)
104 struct rvce_cpb_slot
*i
, *l0
= NULL
, *l1
= NULL
;
106 LIST_FOR_EACH_ENTRY(i
, &enc
->cpb_slots
, list
) {
107 if (i
->frame_num
== enc
->pic
.ref_idx_l0
)
110 if (i
->frame_num
== enc
->pic
.ref_idx_l1
)
113 if (enc
->pic
.picture_type
== PIPE_H264_ENC_PICTURE_TYPE_P
&& l0
)
116 if (enc
->pic
.picture_type
== PIPE_H264_ENC_PICTURE_TYPE_B
&&
123 LIST_ADD(&l1
->list
, &enc
->cpb_slots
);
128 LIST_ADD(&l0
->list
, &enc
->cpb_slots
);
133 * get number of cpbs based on dpb
135 static unsigned get_cpb_num(struct rvce_encoder
*enc
)
137 unsigned w
= align(enc
->base
.width
, 16) / 16;
138 unsigned h
= align(enc
->base
.height
, 16) / 16;
141 switch (enc
->base
.level
) {
182 return MIN2(dpb
/ (w
* h
), 16);
186 * Get the slot for the currently encoded frame
188 struct rvce_cpb_slot
*current_slot(struct rvce_encoder
*enc
)
190 return LIST_ENTRY(struct rvce_cpb_slot
, enc
->cpb_slots
.prev
, list
);
194 * Get the slot for L0
196 struct rvce_cpb_slot
*l0_slot(struct rvce_encoder
*enc
)
198 return LIST_ENTRY(struct rvce_cpb_slot
, enc
->cpb_slots
.next
, list
);
202 * Get the slot for L1
204 struct rvce_cpb_slot
*l1_slot(struct rvce_encoder
*enc
)
206 return LIST_ENTRY(struct rvce_cpb_slot
, enc
->cpb_slots
.next
->next
, list
);
210 * Calculate the offsets into the CPB
212 void rvce_frame_offset(struct rvce_encoder
*enc
, struct rvce_cpb_slot
*slot
,
213 unsigned *luma_offset
, unsigned *chroma_offset
)
215 unsigned pitch
= align(enc
->luma
->level
[0].pitch_bytes
, 128);
216 unsigned vpitch
= align(enc
->luma
->npix_y
, 16);
217 unsigned fsize
= pitch
* (vpitch
+ vpitch
/ 2);
219 *luma_offset
= slot
->index
* fsize
;
220 *chroma_offset
= *luma_offset
+ pitch
* vpitch
;
224 * destroy this video encoder
226 static void rvce_destroy(struct pipe_video_codec
*encoder
)
228 struct rvce_encoder
*enc
= (struct rvce_encoder
*)encoder
;
229 if (enc
->stream_handle
) {
230 struct rvid_buffer fb
;
231 rvid_create_buffer(enc
->screen
, &fb
, 512, PIPE_USAGE_STAGING
);
237 rvid_destroy_buffer(&fb
);
239 rvid_destroy_buffer(&enc
->cpb
);
240 enc
->ws
->cs_destroy(enc
->cs
);
241 FREE(enc
->cpb_array
);
245 static void rvce_begin_frame(struct pipe_video_codec
*encoder
,
246 struct pipe_video_buffer
*source
,
247 struct pipe_picture_desc
*picture
)
249 struct rvce_encoder
*enc
= (struct rvce_encoder
*)encoder
;
250 struct vl_video_buffer
*vid_buf
= (struct vl_video_buffer
*)source
;
251 struct pipe_h264_enc_picture_desc
*pic
= (struct pipe_h264_enc_picture_desc
*)picture
;
253 bool need_rate_control
=
254 enc
->pic
.rate_ctrl
.rate_ctrl_method
!= pic
->rate_ctrl
.rate_ctrl_method
||
255 enc
->pic
.quant_i_frames
!= pic
->quant_i_frames
||
256 enc
->pic
.quant_p_frames
!= pic
->quant_p_frames
||
257 enc
->pic
.quant_b_frames
!= pic
->quant_b_frames
;
261 enc
->get_buffer(vid_buf
->resources
[0], &enc
->handle
, &enc
->luma
);
262 enc
->get_buffer(vid_buf
->resources
[1], NULL
, &enc
->chroma
);
264 if (pic
->picture_type
== PIPE_H264_ENC_PICTURE_TYPE_IDR
)
266 else if (pic
->picture_type
== PIPE_H264_ENC_PICTURE_TYPE_P
||
267 pic
->picture_type
== PIPE_H264_ENC_PICTURE_TYPE_B
)
270 if (!enc
->stream_handle
) {
271 struct rvid_buffer fb
;
272 enc
->stream_handle
= rvid_alloc_stream_handle();
273 rvid_create_buffer(enc
->screen
, &fb
, 512, PIPE_USAGE_STAGING
);
277 enc
->rate_control(enc
);
278 need_rate_control
= false;
279 enc
->config_extension(enc
);
280 enc
->motion_estimation(enc
);
284 enc
->pic_control(enc
);
287 //dump_feedback(enc, &fb);
288 rvid_destroy_buffer(&fb
);
293 if (need_rate_control
)
294 enc
->rate_control(enc
);
297 static void rvce_encode_bitstream(struct pipe_video_codec
*encoder
,
298 struct pipe_video_buffer
*source
,
299 struct pipe_resource
*destination
,
302 struct rvce_encoder
*enc
= (struct rvce_encoder
*)encoder
;
303 enc
->get_buffer(destination
, &enc
->bs_handle
, NULL
);
304 enc
->bs_size
= destination
->width0
;
306 *fb
= enc
->fb
= CALLOC_STRUCT(rvid_buffer
);
307 if (!rvid_create_buffer(enc
->screen
, enc
->fb
, 512, PIPE_USAGE_STAGING
)) {
308 RVID_ERR("Can't create feedback buffer.\n");
315 static void rvce_end_frame(struct pipe_video_codec
*encoder
,
316 struct pipe_video_buffer
*source
,
317 struct pipe_picture_desc
*picture
)
319 struct rvce_encoder
*enc
= (struct rvce_encoder
*)encoder
;
320 struct rvce_cpb_slot
*slot
= LIST_ENTRY(
321 struct rvce_cpb_slot
, enc
->cpb_slots
.prev
, list
);
325 /* update the CPB backtrack with the just encoded frame */
326 slot
->picture_type
= enc
->pic
.picture_type
;
327 slot
->frame_num
= enc
->pic
.frame_num
;
328 slot
->pic_order_cnt
= enc
->pic
.pic_order_cnt
;
329 if (!enc
->pic
.not_referenced
) {
330 LIST_DEL(&slot
->list
);
331 LIST_ADD(&slot
->list
, &enc
->cpb_slots
);
335 static void rvce_get_feedback(struct pipe_video_codec
*encoder
,
336 void *feedback
, unsigned *size
)
338 struct rvce_encoder
*enc
= (struct rvce_encoder
*)encoder
;
339 struct rvid_buffer
*fb
= feedback
;
342 uint32_t *ptr
= enc
->ws
->buffer_map(fb
->res
->cs_buf
, enc
->cs
, PIPE_TRANSFER_READ_WRITE
);
345 *size
= ptr
[4] - ptr
[9];
350 enc
->ws
->buffer_unmap(fb
->res
->cs_buf
);
352 //dump_feedback(enc, fb);
353 rvid_destroy_buffer(fb
);
358 * flush any outstanding command buffers to the hardware
360 static void rvce_flush(struct pipe_video_codec
*encoder
)
364 static void rvce_cs_flush(void *ctx
, unsigned flags
,
365 struct pipe_fence_handle
**fence
)
370 struct pipe_video_codec
*rvce_create_encoder(struct pipe_context
*context
,
371 const struct pipe_video_codec
*templ
,
372 struct radeon_winsys
* ws
,
373 rvce_get_buffer get_buffer
)
375 struct r600_common_screen
*rscreen
= (struct r600_common_screen
*)context
->screen
;
376 struct rvce_encoder
*enc
;
377 struct pipe_video_buffer
*tmp_buf
, templat
= {};
378 struct radeon_surf
*tmp_surf
;
381 if (!rscreen
->info
.vce_fw_version
) {
382 RVID_ERR("Kernel doesn't supports VCE!\n");
385 } else if (!rvce_is_fw_version_supported(rscreen
)) {
386 RVID_ERR("Unsupported VCE fw version loaded!\n");
390 enc
= CALLOC_STRUCT(rvce_encoder
);
394 if ((rscreen
->info
.drm_major
> 2) || (rscreen
->info
.drm_minor
>= 42))
398 enc
->base
.context
= context
;
400 enc
->base
.destroy
= rvce_destroy
;
401 enc
->base
.begin_frame
= rvce_begin_frame
;
402 enc
->base
.encode_bitstream
= rvce_encode_bitstream
;
403 enc
->base
.end_frame
= rvce_end_frame
;
404 enc
->base
.flush
= rvce_flush
;
405 enc
->base
.get_feedback
= rvce_get_feedback
;
406 enc
->get_buffer
= get_buffer
;
408 enc
->screen
= context
->screen
;
410 enc
->cs
= ws
->cs_create(ws
, RING_VCE
, rvce_cs_flush
, enc
, NULL
);
412 RVID_ERR("Can't get command submission context.\n");
416 templat
.buffer_format
= PIPE_FORMAT_NV12
;
417 templat
.chroma_format
= PIPE_VIDEO_CHROMA_FORMAT_420
;
418 templat
.width
= enc
->base
.width
;
419 templat
.height
= enc
->base
.height
;
420 templat
.interlaced
= false;
421 if (!(tmp_buf
= context
->create_video_buffer(context
, &templat
))) {
422 RVID_ERR("Can't create video buffer.\n");
426 enc
->cpb_num
= get_cpb_num(enc
);
430 get_buffer(((struct vl_video_buffer
*)tmp_buf
)->resources
[0], NULL
, &tmp_surf
);
431 cpb_size
= align(tmp_surf
->level
[0].pitch_bytes
, 128);
432 cpb_size
= cpb_size
* align(tmp_surf
->npix_y
, 16);
433 cpb_size
= cpb_size
* 3 / 2;
434 cpb_size
= cpb_size
* enc
->cpb_num
;
435 tmp_buf
->destroy(tmp_buf
);
436 if (!rvid_create_buffer(enc
->screen
, &enc
->cpb
, cpb_size
, PIPE_USAGE_DEFAULT
)) {
437 RVID_ERR("Can't create CPB buffer.\n");
441 enc
->cpb_array
= CALLOC(enc
->cpb_num
, sizeof(struct rvce_cpb_slot
));
447 radeon_vce_40_2_2_init(enc
);
453 enc
->ws
->cs_destroy(enc
->cs
);
455 rvid_destroy_buffer(&enc
->cpb
);
457 FREE(enc
->cpb_array
);
463 * check if kernel has the right fw version loaded
465 bool rvce_is_fw_version_supported(struct r600_common_screen
*rscreen
)
467 return rscreen
->info
.vce_fw_version
== ((40 << 24) | (2 << 16) | (2 << 8));