1b8e80941Smrg/**************************************************************************
2b8e80941Smrg *
3b8e80941Smrg * Copyright 2013 Advanced Micro Devices, Inc.
4b8e80941Smrg * All Rights Reserved.
5b8e80941Smrg *
6b8e80941Smrg * Permission is hereby granted, free of charge, to any person obtaining a
7b8e80941Smrg * copy of this software and associated documentation files (the
8b8e80941Smrg * "Software"), to deal in the Software without restriction, including
9b8e80941Smrg * without limitation the rights to use, copy, modify, merge, publish,
10b8e80941Smrg * distribute, sub license, and/or sell copies of the Software, and to
11b8e80941Smrg * permit persons to whom the Software is furnished to do so, subject to
12b8e80941Smrg * the following conditions:
13b8e80941Smrg *
14b8e80941Smrg * The above copyright notice and this permission notice (including the
15b8e80941Smrg * next paragraph) shall be included in all copies or substantial portions
16b8e80941Smrg * of the Software.
17b8e80941Smrg *
18b8e80941Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19b8e80941Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20b8e80941Smrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21b8e80941Smrg * IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR
22b8e80941Smrg * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23b8e80941Smrg * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24b8e80941Smrg * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25b8e80941Smrg *
26b8e80941Smrg **************************************************************************/
27b8e80941Smrg
28b8e80941Smrg/*
29b8e80941Smrg * Authors:
30b8e80941Smrg *      Christian König <christian.koenig@amd.com>
31b8e80941Smrg *
32b8e80941Smrg */
33b8e80941Smrg
34b8e80941Smrg#include <stdio.h>
35b8e80941Smrg
36b8e80941Smrg#include "pipe/p_video_codec.h"
37b8e80941Smrg
38b8e80941Smrg#include "util/u_video.h"
39b8e80941Smrg#include "util/u_memory.h"
40b8e80941Smrg
41b8e80941Smrg#include "vl/vl_video_buffer.h"
42b8e80941Smrg
43b8e80941Smrg#include "r600_pipe_common.h"
44b8e80941Smrg#include "radeon_video.h"
45b8e80941Smrg#include "radeon_vce.h"
46b8e80941Smrg
47b8e80941Smrg#define FW_40_2_2 ((40 << 24) | (2 << 16) | (2 << 8))
48b8e80941Smrg#define FW_50_0_1 ((50 << 24) | (0 << 16) | (1 << 8))
49b8e80941Smrg#define FW_50_1_2 ((50 << 24) | (1 << 16) | (2 << 8))
50b8e80941Smrg#define FW_50_10_2 ((50 << 24) | (10 << 16) | (2 << 8))
51b8e80941Smrg#define FW_50_17_3 ((50 << 24) | (17 << 16) | (3 << 8))
52b8e80941Smrg#define FW_52_0_3 ((52 << 24) | (0 << 16) | (3 << 8))
53b8e80941Smrg#define FW_52_4_3 ((52 << 24) | (4 << 16) | (3 << 8))
54b8e80941Smrg#define FW_52_8_3 ((52 << 24) | (8 << 16) | (3 << 8))
55b8e80941Smrg#define FW_53 (53 << 24)
56b8e80941Smrg
57b8e80941Smrg/**
58b8e80941Smrg * flush commands to the hardware
59b8e80941Smrg */
60b8e80941Smrgstatic void flush(struct rvce_encoder *enc)
61b8e80941Smrg{
62b8e80941Smrg	enc->ws->cs_flush(enc->cs, PIPE_FLUSH_ASYNC, NULL);
63b8e80941Smrg	enc->task_info_idx = 0;
64b8e80941Smrg	enc->bs_idx = 0;
65b8e80941Smrg}
66b8e80941Smrg
67b8e80941Smrg#if 0
68b8e80941Smrgstatic void dump_feedback(struct rvce_encoder *enc, struct rvid_buffer *fb)
69b8e80941Smrg{
70b8e80941Smrg	uint32_t *ptr = enc->ws->buffer_map(fb->res->buf, enc->cs, PIPE_TRANSFER_READ_WRITE);
71b8e80941Smrg	unsigned i = 0;
72b8e80941Smrg	fprintf(stderr, "\n");
73b8e80941Smrg	fprintf(stderr, "encStatus:\t\t\t%08x\n", ptr[i++]);
74b8e80941Smrg	fprintf(stderr, "encHasBitstream:\t\t%08x\n", ptr[i++]);
75b8e80941Smrg	fprintf(stderr, "encHasAudioBitstream:\t\t%08x\n", ptr[i++]);
76b8e80941Smrg	fprintf(stderr, "encBitstreamOffset:\t\t%08x\n", ptr[i++]);
77b8e80941Smrg	fprintf(stderr, "encBitstreamSize:\t\t%08x\n", ptr[i++]);
78b8e80941Smrg	fprintf(stderr, "encAudioBitstreamOffset:\t%08x\n", ptr[i++]);
79b8e80941Smrg	fprintf(stderr, "encAudioBitstreamSize:\t\t%08x\n", ptr[i++]);
80b8e80941Smrg	fprintf(stderr, "encExtrabytes:\t\t\t%08x\n", ptr[i++]);
81b8e80941Smrg	fprintf(stderr, "encAudioExtrabytes:\t\t%08x\n", ptr[i++]);
82b8e80941Smrg	fprintf(stderr, "videoTimeStamp:\t\t\t%08x\n", ptr[i++]);
83b8e80941Smrg	fprintf(stderr, "audioTimeStamp:\t\t\t%08x\n", ptr[i++]);
84b8e80941Smrg	fprintf(stderr, "videoOutputType:\t\t%08x\n", ptr[i++]);
85b8e80941Smrg	fprintf(stderr, "attributeFlags:\t\t\t%08x\n", ptr[i++]);
86b8e80941Smrg	fprintf(stderr, "seiPrivatePackageOffset:\t%08x\n", ptr[i++]);
87b8e80941Smrg	fprintf(stderr, "seiPrivatePackageSize:\t\t%08x\n", ptr[i++]);
88b8e80941Smrg	fprintf(stderr, "\n");
89b8e80941Smrg	enc->ws->buffer_unmap(fb->res->buf);
90b8e80941Smrg}
91b8e80941Smrg#endif
92b8e80941Smrg
93b8e80941Smrg/**
94b8e80941Smrg * reset the CPB handling
95b8e80941Smrg */
96b8e80941Smrgstatic void reset_cpb(struct rvce_encoder *enc)
97b8e80941Smrg{
98b8e80941Smrg	unsigned i;
99b8e80941Smrg
100b8e80941Smrg	LIST_INITHEAD(&enc->cpb_slots);
101b8e80941Smrg	for (i = 0; i < enc->cpb_num; ++i) {
102b8e80941Smrg		struct rvce_cpb_slot *slot = &enc->cpb_array[i];
103b8e80941Smrg		slot->index = i;
104b8e80941Smrg		slot->picture_type = PIPE_H264_ENC_PICTURE_TYPE_SKIP;
105b8e80941Smrg		slot->frame_num = 0;
106b8e80941Smrg		slot->pic_order_cnt = 0;
107b8e80941Smrg		LIST_ADDTAIL(&slot->list, &enc->cpb_slots);
108b8e80941Smrg	}
109b8e80941Smrg}
110b8e80941Smrg
111b8e80941Smrg/**
112b8e80941Smrg * sort l0 and l1 to the top of the list
113b8e80941Smrg */
114b8e80941Smrgstatic void sort_cpb(struct rvce_encoder *enc)
115b8e80941Smrg{
116b8e80941Smrg	struct rvce_cpb_slot *i, *l0 = NULL, *l1 = NULL;
117b8e80941Smrg
118b8e80941Smrg	LIST_FOR_EACH_ENTRY(i, &enc->cpb_slots, list) {
119b8e80941Smrg		if (i->frame_num == enc->pic.ref_idx_l0)
120b8e80941Smrg			l0 = i;
121b8e80941Smrg
122b8e80941Smrg		if (i->frame_num == enc->pic.ref_idx_l1)
123b8e80941Smrg			l1 = i;
124b8e80941Smrg
125b8e80941Smrg		if (enc->pic.picture_type == PIPE_H264_ENC_PICTURE_TYPE_P && l0)
126b8e80941Smrg			break;
127b8e80941Smrg
128b8e80941Smrg		if (enc->pic.picture_type == PIPE_H264_ENC_PICTURE_TYPE_B &&
129b8e80941Smrg		    l0 && l1)
130b8e80941Smrg			break;
131b8e80941Smrg	}
132b8e80941Smrg
133b8e80941Smrg	if (l1) {
134b8e80941Smrg		LIST_DEL(&l1->list);
135b8e80941Smrg		LIST_ADD(&l1->list, &enc->cpb_slots);
136b8e80941Smrg	}
137b8e80941Smrg
138b8e80941Smrg	if (l0) {
139b8e80941Smrg		LIST_DEL(&l0->list);
140b8e80941Smrg		LIST_ADD(&l0->list, &enc->cpb_slots);
141b8e80941Smrg	}
142b8e80941Smrg}
143b8e80941Smrg
144b8e80941Smrg/**
145b8e80941Smrg * get number of cpbs based on dpb
146b8e80941Smrg */
147b8e80941Smrgstatic unsigned get_cpb_num(struct rvce_encoder *enc)
148b8e80941Smrg{
149b8e80941Smrg	unsigned w = align(enc->base.width, 16) / 16;
150b8e80941Smrg	unsigned h = align(enc->base.height, 16) / 16;
151b8e80941Smrg	unsigned dpb;
152b8e80941Smrg
153b8e80941Smrg	switch (enc->base.level) {
154b8e80941Smrg	case 10:
155b8e80941Smrg		dpb = 396;
156b8e80941Smrg		break;
157b8e80941Smrg	case 11:
158b8e80941Smrg		dpb = 900;
159b8e80941Smrg		break;
160b8e80941Smrg	case 12:
161b8e80941Smrg	case 13:
162b8e80941Smrg	case 20:
163b8e80941Smrg		dpb = 2376;
164b8e80941Smrg		break;
165b8e80941Smrg	case 21:
166b8e80941Smrg		dpb = 4752;
167b8e80941Smrg		break;
168b8e80941Smrg	case 22:
169b8e80941Smrg	case 30:
170b8e80941Smrg		dpb = 8100;
171b8e80941Smrg		break;
172b8e80941Smrg	case 31:
173b8e80941Smrg		dpb = 18000;
174b8e80941Smrg		break;
175b8e80941Smrg	case 32:
176b8e80941Smrg		dpb = 20480;
177b8e80941Smrg		break;
178b8e80941Smrg	case 40:
179b8e80941Smrg	case 41:
180b8e80941Smrg		dpb = 32768;
181b8e80941Smrg		break;
182b8e80941Smrg	case 42:
183b8e80941Smrg		dpb = 34816;
184b8e80941Smrg		break;
185b8e80941Smrg	case 50:
186b8e80941Smrg		dpb = 110400;
187b8e80941Smrg		break;
188b8e80941Smrg	default:
189b8e80941Smrg	case 51:
190b8e80941Smrg	case 52:
191b8e80941Smrg		dpb = 184320;
192b8e80941Smrg		break;
193b8e80941Smrg	}
194b8e80941Smrg
195b8e80941Smrg	return MIN2(dpb / (w * h), 16);
196b8e80941Smrg}
197b8e80941Smrg
198b8e80941Smrg/**
199b8e80941Smrg * Get the slot for the currently encoded frame
200b8e80941Smrg */
201b8e80941Smrgstruct rvce_cpb_slot *current_slot(struct rvce_encoder *enc)
202b8e80941Smrg{
203b8e80941Smrg	return LIST_ENTRY(struct rvce_cpb_slot, enc->cpb_slots.prev, list);
204b8e80941Smrg}
205b8e80941Smrg
206b8e80941Smrg/**
207b8e80941Smrg * Get the slot for L0
208b8e80941Smrg */
209b8e80941Smrgstruct rvce_cpb_slot *l0_slot(struct rvce_encoder *enc)
210b8e80941Smrg{
211b8e80941Smrg	return LIST_ENTRY(struct rvce_cpb_slot, enc->cpb_slots.next, list);
212b8e80941Smrg}
213b8e80941Smrg
214b8e80941Smrg/**
215b8e80941Smrg * Get the slot for L1
216b8e80941Smrg */
217b8e80941Smrgstruct rvce_cpb_slot *l1_slot(struct rvce_encoder *enc)
218b8e80941Smrg{
219b8e80941Smrg	return LIST_ENTRY(struct rvce_cpb_slot, enc->cpb_slots.next->next, list);
220b8e80941Smrg}
221b8e80941Smrg
222b8e80941Smrg/**
223b8e80941Smrg * Calculate the offsets into the CPB
224b8e80941Smrg */
225b8e80941Smrgvoid rvce_frame_offset(struct rvce_encoder *enc, struct rvce_cpb_slot *slot,
226b8e80941Smrg		       signed *luma_offset, signed *chroma_offset)
227b8e80941Smrg{
228b8e80941Smrg	unsigned pitch, vpitch, fsize;
229b8e80941Smrg
230b8e80941Smrg	pitch = align(enc->luma->u.legacy.level[0].nblk_x * enc->luma->bpe, 128);
231b8e80941Smrg	vpitch = align(enc->luma->u.legacy.level[0].nblk_y, 16);
232b8e80941Smrg	fsize = pitch * (vpitch + vpitch / 2);
233b8e80941Smrg
234b8e80941Smrg	*luma_offset = slot->index * fsize;
235b8e80941Smrg	*chroma_offset = *luma_offset + pitch * vpitch;
236b8e80941Smrg}
237b8e80941Smrg
238b8e80941Smrg/**
239b8e80941Smrg * destroy this video encoder
240b8e80941Smrg */
241b8e80941Smrgstatic void rvce_destroy(struct pipe_video_codec *encoder)
242b8e80941Smrg{
243b8e80941Smrg	struct rvce_encoder *enc = (struct rvce_encoder*)encoder;
244b8e80941Smrg	if (enc->stream_handle) {
245b8e80941Smrg		struct rvid_buffer fb;
246b8e80941Smrg		rvid_create_buffer(enc->screen, &fb, 512, PIPE_USAGE_STAGING);
247b8e80941Smrg		enc->fb = &fb;
248b8e80941Smrg		enc->session(enc);
249b8e80941Smrg		enc->feedback(enc);
250b8e80941Smrg		enc->destroy(enc);
251b8e80941Smrg		flush(enc);
252b8e80941Smrg		rvid_destroy_buffer(&fb);
253b8e80941Smrg	}
254b8e80941Smrg	rvid_destroy_buffer(&enc->cpb);
255b8e80941Smrg	enc->ws->cs_destroy(enc->cs);
256b8e80941Smrg	FREE(enc->cpb_array);
257b8e80941Smrg	FREE(enc);
258b8e80941Smrg}
259b8e80941Smrg
260b8e80941Smrgstatic void rvce_begin_frame(struct pipe_video_codec *encoder,
261b8e80941Smrg			     struct pipe_video_buffer *source,
262b8e80941Smrg			     struct pipe_picture_desc *picture)
263b8e80941Smrg{
264b8e80941Smrg	struct rvce_encoder *enc = (struct rvce_encoder*)encoder;
265b8e80941Smrg	struct vl_video_buffer *vid_buf = (struct vl_video_buffer *)source;
266b8e80941Smrg	struct pipe_h264_enc_picture_desc *pic = (struct pipe_h264_enc_picture_desc *)picture;
267b8e80941Smrg
268b8e80941Smrg	bool need_rate_control =
269b8e80941Smrg		enc->pic.rate_ctrl.rate_ctrl_method != pic->rate_ctrl.rate_ctrl_method ||
270b8e80941Smrg		enc->pic.quant_i_frames != pic->quant_i_frames ||
271b8e80941Smrg		enc->pic.quant_p_frames != pic->quant_p_frames ||
272b8e80941Smrg		enc->pic.quant_b_frames != pic->quant_b_frames;
273b8e80941Smrg
274b8e80941Smrg	enc->pic = *pic;
275b8e80941Smrg	get_pic_param(enc, pic);
276b8e80941Smrg
277b8e80941Smrg	enc->get_buffer(vid_buf->resources[0], &enc->handle, &enc->luma);
278b8e80941Smrg	enc->get_buffer(vid_buf->resources[1], NULL, &enc->chroma);
279b8e80941Smrg
280b8e80941Smrg	if (pic->picture_type == PIPE_H264_ENC_PICTURE_TYPE_IDR)
281b8e80941Smrg		reset_cpb(enc);
282b8e80941Smrg	else if (pic->picture_type == PIPE_H264_ENC_PICTURE_TYPE_P ||
283b8e80941Smrg	         pic->picture_type == PIPE_H264_ENC_PICTURE_TYPE_B)
284b8e80941Smrg		sort_cpb(enc);
285b8e80941Smrg
286b8e80941Smrg	if (!enc->stream_handle) {
287b8e80941Smrg		struct rvid_buffer fb;
288b8e80941Smrg		enc->stream_handle = rvid_alloc_stream_handle();
289b8e80941Smrg		rvid_create_buffer(enc->screen, &fb, 512, PIPE_USAGE_STAGING);
290b8e80941Smrg		enc->fb = &fb;
291b8e80941Smrg		enc->session(enc);
292b8e80941Smrg		enc->create(enc);
293b8e80941Smrg		enc->config(enc);
294b8e80941Smrg		enc->feedback(enc);
295b8e80941Smrg		flush(enc);
296b8e80941Smrg		//dump_feedback(enc, &fb);
297b8e80941Smrg		rvid_destroy_buffer(&fb);
298b8e80941Smrg		need_rate_control = false;
299b8e80941Smrg	}
300b8e80941Smrg
301b8e80941Smrg	if (need_rate_control) {
302b8e80941Smrg		enc->session(enc);
303b8e80941Smrg		enc->config(enc);
304b8e80941Smrg		flush(enc);
305b8e80941Smrg	}
306b8e80941Smrg}
307b8e80941Smrg
308b8e80941Smrgstatic void rvce_encode_bitstream(struct pipe_video_codec *encoder,
309b8e80941Smrg				  struct pipe_video_buffer *source,
310b8e80941Smrg				  struct pipe_resource *destination,
311b8e80941Smrg				  void **fb)
312b8e80941Smrg{
313b8e80941Smrg	struct rvce_encoder *enc = (struct rvce_encoder*)encoder;
314b8e80941Smrg	enc->get_buffer(destination, &enc->bs_handle, NULL);
315b8e80941Smrg	enc->bs_size = destination->width0;
316b8e80941Smrg
317b8e80941Smrg	*fb = enc->fb = CALLOC_STRUCT(rvid_buffer);
318b8e80941Smrg	if (!rvid_create_buffer(enc->screen, enc->fb, 512, PIPE_USAGE_STAGING)) {
319b8e80941Smrg		RVID_ERR("Can't create feedback buffer.\n");
320b8e80941Smrg		return;
321b8e80941Smrg	}
322b8e80941Smrg	if (!radeon_emitted(enc->cs, 0))
323b8e80941Smrg		enc->session(enc);
324b8e80941Smrg	enc->encode(enc);
325b8e80941Smrg	enc->feedback(enc);
326b8e80941Smrg}
327b8e80941Smrg
328b8e80941Smrgstatic void rvce_end_frame(struct pipe_video_codec *encoder,
329b8e80941Smrg			   struct pipe_video_buffer *source,
330b8e80941Smrg			   struct pipe_picture_desc *picture)
331b8e80941Smrg{
332b8e80941Smrg	struct rvce_encoder *enc = (struct rvce_encoder*)encoder;
333b8e80941Smrg	struct rvce_cpb_slot *slot = LIST_ENTRY(
334b8e80941Smrg		struct rvce_cpb_slot, enc->cpb_slots.prev, list);
335b8e80941Smrg
336b8e80941Smrg	if (!enc->dual_inst || enc->bs_idx > 1)
337b8e80941Smrg		flush(enc);
338b8e80941Smrg
339b8e80941Smrg	/* update the CPB backtrack with the just encoded frame */
340b8e80941Smrg	slot->picture_type = enc->pic.picture_type;
341b8e80941Smrg	slot->frame_num = enc->pic.frame_num;
342b8e80941Smrg	slot->pic_order_cnt = enc->pic.pic_order_cnt;
343b8e80941Smrg	if (!enc->pic.not_referenced) {
344b8e80941Smrg		LIST_DEL(&slot->list);
345b8e80941Smrg		LIST_ADD(&slot->list, &enc->cpb_slots);
346b8e80941Smrg	}
347b8e80941Smrg}
348b8e80941Smrg
349b8e80941Smrgstatic void rvce_get_feedback(struct pipe_video_codec *encoder,
350b8e80941Smrg			      void *feedback, unsigned *size)
351b8e80941Smrg{
352b8e80941Smrg	struct rvce_encoder *enc = (struct rvce_encoder*)encoder;
353b8e80941Smrg	struct rvid_buffer *fb = feedback;
354b8e80941Smrg
355b8e80941Smrg	if (size) {
356b8e80941Smrg		uint32_t *ptr = enc->ws->buffer_map(
357b8e80941Smrg			fb->res->buf, enc->cs,
358b8e80941Smrg			PIPE_TRANSFER_READ_WRITE | RADEON_TRANSFER_TEMPORARY);
359b8e80941Smrg
360b8e80941Smrg		if (ptr[1]) {
361b8e80941Smrg			*size = ptr[4] - ptr[9];
362b8e80941Smrg		} else {
363b8e80941Smrg			*size = 0;
364b8e80941Smrg		}
365b8e80941Smrg
366b8e80941Smrg		enc->ws->buffer_unmap(fb->res->buf);
367b8e80941Smrg	}
368b8e80941Smrg	//dump_feedback(enc, fb);
369b8e80941Smrg	rvid_destroy_buffer(fb);
370b8e80941Smrg	FREE(fb);
371b8e80941Smrg}
372b8e80941Smrg
373b8e80941Smrg/**
374b8e80941Smrg * flush any outstanding command buffers to the hardware
375b8e80941Smrg */
376b8e80941Smrgstatic void rvce_flush(struct pipe_video_codec *encoder)
377b8e80941Smrg{
378b8e80941Smrg	struct rvce_encoder *enc = (struct rvce_encoder*)encoder;
379b8e80941Smrg
380b8e80941Smrg	flush(enc);
381b8e80941Smrg}
382b8e80941Smrg
383b8e80941Smrgstatic void rvce_cs_flush(void *ctx, unsigned flags,
384b8e80941Smrg			  struct pipe_fence_handle **fence)
385b8e80941Smrg{
386b8e80941Smrg	// just ignored
387b8e80941Smrg}
388b8e80941Smrg
389b8e80941Smrgstruct pipe_video_codec *rvce_create_encoder(struct pipe_context *context,
390b8e80941Smrg					     const struct pipe_video_codec *templ,
391b8e80941Smrg					     struct radeon_winsys* ws,
392b8e80941Smrg					     rvce_get_buffer get_buffer)
393b8e80941Smrg{
394b8e80941Smrg	struct r600_common_screen *rscreen = (struct r600_common_screen *)context->screen;
395b8e80941Smrg	struct r600_common_context *rctx = (struct r600_common_context*)context;
396b8e80941Smrg	struct rvce_encoder *enc;
397b8e80941Smrg	struct pipe_video_buffer *tmp_buf, templat = {};
398b8e80941Smrg	struct radeon_surf *tmp_surf;
399b8e80941Smrg	unsigned cpb_size;
400b8e80941Smrg
401b8e80941Smrg	if (!rscreen->info.vce_fw_version) {
402b8e80941Smrg		RVID_ERR("Kernel doesn't supports VCE!\n");
403b8e80941Smrg		return NULL;
404b8e80941Smrg
405b8e80941Smrg	} else if (!rvce_is_fw_version_supported(rscreen)) {
406b8e80941Smrg		RVID_ERR("Unsupported VCE fw version loaded!\n");
407b8e80941Smrg		return NULL;
408b8e80941Smrg	}
409b8e80941Smrg
410b8e80941Smrg	enc = CALLOC_STRUCT(rvce_encoder);
411b8e80941Smrg	if (!enc)
412b8e80941Smrg		return NULL;
413b8e80941Smrg
414b8e80941Smrg	if (rscreen->info.drm_major == 3)
415b8e80941Smrg		enc->use_vm = true;
416b8e80941Smrg	if ((rscreen->info.drm_major == 2 && rscreen->info.drm_minor >= 42) ||
417b8e80941Smrg            rscreen->info.drm_major == 3)
418b8e80941Smrg		enc->use_vui = true;
419b8e80941Smrg
420b8e80941Smrg	enc->base = *templ;
421b8e80941Smrg	enc->base.context = context;
422b8e80941Smrg
423b8e80941Smrg	enc->base.destroy = rvce_destroy;
424b8e80941Smrg	enc->base.begin_frame = rvce_begin_frame;
425b8e80941Smrg	enc->base.encode_bitstream = rvce_encode_bitstream;
426b8e80941Smrg	enc->base.end_frame = rvce_end_frame;
427b8e80941Smrg	enc->base.flush = rvce_flush;
428b8e80941Smrg	enc->base.get_feedback = rvce_get_feedback;
429b8e80941Smrg	enc->get_buffer = get_buffer;
430b8e80941Smrg
431b8e80941Smrg	enc->screen = context->screen;
432b8e80941Smrg	enc->ws = ws;
433b8e80941Smrg	enc->cs = ws->cs_create(rctx->ctx, RING_VCE, rvce_cs_flush, enc, false);
434b8e80941Smrg	if (!enc->cs) {
435b8e80941Smrg		RVID_ERR("Can't get command submission context.\n");
436b8e80941Smrg		goto error;
437b8e80941Smrg	}
438b8e80941Smrg
439b8e80941Smrg	templat.buffer_format = PIPE_FORMAT_NV12;
440b8e80941Smrg	templat.chroma_format = PIPE_VIDEO_CHROMA_FORMAT_420;
441b8e80941Smrg	templat.width = enc->base.width;
442b8e80941Smrg	templat.height = enc->base.height;
443b8e80941Smrg	templat.interlaced = false;
444b8e80941Smrg	if (!(tmp_buf = context->create_video_buffer(context, &templat))) {
445b8e80941Smrg		RVID_ERR("Can't create video buffer.\n");
446b8e80941Smrg		goto error;
447b8e80941Smrg	}
448b8e80941Smrg
449b8e80941Smrg	enc->cpb_num = get_cpb_num(enc);
450b8e80941Smrg	if (!enc->cpb_num)
451b8e80941Smrg		goto error;
452b8e80941Smrg
453b8e80941Smrg	get_buffer(((struct vl_video_buffer *)tmp_buf)->resources[0], NULL, &tmp_surf);
454b8e80941Smrg
455b8e80941Smrg	cpb_size = align(tmp_surf->u.legacy.level[0].nblk_x * tmp_surf->bpe, 128) *
456b8e80941Smrg	  align(tmp_surf->u.legacy.level[0].nblk_y, 32);
457b8e80941Smrg
458b8e80941Smrg	cpb_size = cpb_size * 3 / 2;
459b8e80941Smrg	cpb_size = cpb_size * enc->cpb_num;
460b8e80941Smrg	if (enc->dual_pipe)
461b8e80941Smrg		cpb_size +=  RVCE_MAX_AUX_BUFFER_NUM *
462b8e80941Smrg			RVCE_MAX_BITSTREAM_OUTPUT_ROW_SIZE * 2;
463b8e80941Smrg	tmp_buf->destroy(tmp_buf);
464b8e80941Smrg	if (!rvid_create_buffer(enc->screen, &enc->cpb, cpb_size, PIPE_USAGE_DEFAULT)) {
465b8e80941Smrg		RVID_ERR("Can't create CPB buffer.\n");
466b8e80941Smrg		goto error;
467b8e80941Smrg	}
468b8e80941Smrg
469b8e80941Smrg	enc->cpb_array = CALLOC(enc->cpb_num, sizeof(struct rvce_cpb_slot));
470b8e80941Smrg	if (!enc->cpb_array)
471b8e80941Smrg		goto error;
472b8e80941Smrg
473b8e80941Smrg	reset_cpb(enc);
474b8e80941Smrg
475b8e80941Smrg	goto error;
476b8e80941Smrg
477b8e80941Smrg	return &enc->base;
478b8e80941Smrg
479b8e80941Smrgerror:
480b8e80941Smrg	if (enc->cs)
481b8e80941Smrg		enc->ws->cs_destroy(enc->cs);
482b8e80941Smrg
483b8e80941Smrg	rvid_destroy_buffer(&enc->cpb);
484b8e80941Smrg
485b8e80941Smrg	FREE(enc->cpb_array);
486b8e80941Smrg	FREE(enc);
487b8e80941Smrg	return NULL;
488b8e80941Smrg}
489b8e80941Smrg
490b8e80941Smrg/**
491b8e80941Smrg * check if kernel has the right fw version loaded
492b8e80941Smrg */
493b8e80941Smrgbool rvce_is_fw_version_supported(struct r600_common_screen *rscreen)
494b8e80941Smrg{
495b8e80941Smrg	switch (rscreen->info.vce_fw_version) {
496b8e80941Smrg	case FW_40_2_2:
497b8e80941Smrg	case FW_50_0_1:
498b8e80941Smrg	case FW_50_1_2:
499b8e80941Smrg	case FW_50_10_2:
500b8e80941Smrg	case FW_50_17_3:
501b8e80941Smrg	case FW_52_0_3:
502b8e80941Smrg	case FW_52_4_3:
503b8e80941Smrg	case FW_52_8_3:
504b8e80941Smrg		return true;
505b8e80941Smrg	default:
506b8e80941Smrg		if ((rscreen->info.vce_fw_version & (0xff << 24)) == FW_53)
507b8e80941Smrg			return true;
508b8e80941Smrg		else
509b8e80941Smrg			return false;
510b8e80941Smrg	}
511b8e80941Smrg}
512b8e80941Smrg
513b8e80941Smrg/**
514b8e80941Smrg * Add the buffer as relocation to the current command submission
515b8e80941Smrg */
516b8e80941Smrgvoid rvce_add_buffer(struct rvce_encoder *enc, struct pb_buffer *buf,
517b8e80941Smrg                     enum radeon_bo_usage usage, enum radeon_bo_domain domain,
518b8e80941Smrg                     signed offset)
519b8e80941Smrg{
520b8e80941Smrg	int reloc_idx;
521b8e80941Smrg
522b8e80941Smrg	reloc_idx = enc->ws->cs_add_buffer(enc->cs, buf, usage | RADEON_USAGE_SYNCHRONIZED,
523b8e80941Smrg					   domain, 0);
524b8e80941Smrg	if (enc->use_vm) {
525b8e80941Smrg		uint64_t addr;
526b8e80941Smrg		addr = enc->ws->buffer_get_virtual_address(buf);
527b8e80941Smrg		addr = addr + offset;
528b8e80941Smrg		RVCE_CS(addr >> 32);
529b8e80941Smrg		RVCE_CS(addr);
530b8e80941Smrg	} else {
531b8e80941Smrg		offset += enc->ws->buffer_get_reloc_offset(buf);
532b8e80941Smrg		RVCE_CS(reloc_idx * 4);
533b8e80941Smrg		RVCE_CS(offset);
534b8e80941Smrg	}
535b8e80941Smrg}
536