radeon_video.c revision af69d88d
1/**************************************************************************
2 *
3 * Copyright 2013 Advanced Micro Devices, Inc.
4 * All Rights Reserved.
5 *
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:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
16 * of the Software.
17 *
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.
25 *
26 **************************************************************************/
27
28/*
29 * Authors:
30 *      Christian König <christian.koenig@amd.com>
31 *
32 */
33
34#include <unistd.h>
35
36#include "util/u_memory.h"
37#include "util/u_video.h"
38
39#include "vl/vl_defines.h"
40#include "vl/vl_video_buffer.h"
41
42#include "../../winsys/radeon/drm/radeon_winsys.h"
43#include "r600_pipe_common.h"
44#include "radeon_video.h"
45#include "radeon_vce.h"
46
47/* generate an stream handle */
48unsigned rvid_alloc_stream_handle()
49{
50	static unsigned counter = 0;
51	unsigned stream_handle = 0;
52	unsigned pid = getpid();
53	int i;
54
55	for (i = 0; i < 32; ++i)
56		stream_handle |= ((pid >> i) & 1) << (31 - i);
57
58	stream_handle ^= ++counter;
59	return stream_handle;
60}
61
62/* create a buffer in the winsys */
63bool rvid_create_buffer(struct radeon_winsys *ws, struct rvid_buffer *buffer,
64			unsigned size, enum radeon_bo_domain domain,
65			enum radeon_bo_flag flags)
66{
67	buffer->domain = domain;
68	buffer->flags = flags;
69
70	buffer->buf = ws->buffer_create(ws, size, 4096, false, domain, flags);
71	if (!buffer->buf)
72		return false;
73
74	buffer->cs_handle = ws->buffer_get_cs_handle(buffer->buf);
75	if (!buffer->cs_handle)
76		return false;
77
78	return true;
79}
80
81/* destroy a buffer */
82void rvid_destroy_buffer(struct rvid_buffer *buffer)
83{
84	pb_reference(&buffer->buf, NULL);
85	buffer->cs_handle = NULL;
86}
87
88/* reallocate a buffer, preserving its content */
89bool rvid_resize_buffer(struct radeon_winsys *ws, struct radeon_winsys_cs *cs,
90			struct rvid_buffer *new_buf, unsigned new_size)
91{
92	unsigned bytes = MIN2(new_buf->buf->size, new_size);
93	struct rvid_buffer old_buf = *new_buf;
94	void *src = NULL, *dst = NULL;
95
96	if (!rvid_create_buffer(ws, new_buf, new_size, new_buf->domain,
97                                new_buf->flags))
98		goto error;
99
100	src = ws->buffer_map(old_buf.cs_handle, cs, PIPE_TRANSFER_READ);
101	if (!src)
102		goto error;
103
104	dst = ws->buffer_map(new_buf->cs_handle, cs, PIPE_TRANSFER_WRITE);
105	if (!dst)
106		goto error;
107
108	memcpy(dst, src, bytes);
109	if (new_size > bytes) {
110		new_size -= bytes;
111		dst += bytes;
112		memset(dst, 0, new_size);
113	}
114	ws->buffer_unmap(new_buf->cs_handle);
115	ws->buffer_unmap(old_buf.cs_handle);
116	rvid_destroy_buffer(&old_buf);
117	return true;
118
119error:
120	if (src)
121		ws->buffer_unmap(old_buf.cs_handle);
122	rvid_destroy_buffer(new_buf);
123	*new_buf = old_buf;
124	return false;
125}
126
127/* clear the buffer with zeros */
128void rvid_clear_buffer(struct radeon_winsys *ws, struct radeon_winsys_cs *cs, struct rvid_buffer* buffer)
129{
130        void *ptr = ws->buffer_map(buffer->cs_handle, cs, PIPE_TRANSFER_WRITE);
131        if (!ptr)
132                return;
133
134        memset(ptr, 0, buffer->buf->size);
135        ws->buffer_unmap(buffer->cs_handle);
136}
137
138/**
139 * join surfaces into the same buffer with identical tiling params
140 * sumup their sizes and replace the backend buffers with a single bo
141 */
142void rvid_join_surfaces(struct radeon_winsys* ws, unsigned bind,
143			struct pb_buffer** buffers[VL_NUM_COMPONENTS],
144			struct radeon_surface *surfaces[VL_NUM_COMPONENTS])
145{
146	unsigned best_tiling, best_wh, off;
147	unsigned size, alignment;
148	struct pb_buffer *pb;
149	unsigned i, j;
150
151	for (i = 0, best_tiling = 0, best_wh = ~0; i < VL_NUM_COMPONENTS; ++i) {
152		unsigned wh;
153
154		if (!surfaces[i])
155			continue;
156
157		/* choose the smallest bank w/h for now */
158		wh = surfaces[i]->bankw * surfaces[i]->bankh;
159		if (wh < best_wh) {
160			best_wh = wh;
161			best_tiling = i;
162		}
163	}
164
165	for (i = 0, off = 0; i < VL_NUM_COMPONENTS; ++i) {
166		if (!surfaces[i])
167			continue;
168
169		/* copy the tiling parameters */
170		surfaces[i]->bankw = surfaces[best_tiling]->bankw;
171		surfaces[i]->bankh = surfaces[best_tiling]->bankh;
172		surfaces[i]->mtilea = surfaces[best_tiling]->mtilea;
173		surfaces[i]->tile_split = surfaces[best_tiling]->tile_split;
174
175		/* adjust the texture layer offsets */
176		off = align(off, surfaces[i]->bo_alignment);
177		for (j = 0; j < Elements(surfaces[i]->level); ++j)
178			surfaces[i]->level[j].offset += off;
179		off += surfaces[i]->bo_size;
180	}
181
182	for (i = 0, size = 0, alignment = 0; i < VL_NUM_COMPONENTS; ++i) {
183		if (!buffers[i] || !*buffers[i])
184			continue;
185
186		size = align(size, (*buffers[i])->alignment);
187		size += (*buffers[i])->size;
188		alignment = MAX2(alignment, (*buffers[i])->alignment * 1);
189	}
190
191	if (!size)
192		return;
193
194	/* TODO: 2D tiling workaround */
195	alignment *= 2;
196
197	pb = ws->buffer_create(ws, size, alignment, bind, RADEON_DOMAIN_VRAM, 0);
198	if (!pb)
199		return;
200
201	for (i = 0; i < VL_NUM_COMPONENTS; ++i) {
202		if (!buffers[i] || !*buffers[i])
203			continue;
204
205		pb_reference(buffers[i], pb);
206	}
207
208	pb_reference(&pb, NULL);
209}
210
211int rvid_get_video_param(struct pipe_screen *screen,
212			 enum pipe_video_profile profile,
213			 enum pipe_video_entrypoint entrypoint,
214			 enum pipe_video_cap param)
215{
216	struct r600_common_screen *rscreen = (struct r600_common_screen *)screen;
217
218	if (entrypoint == PIPE_VIDEO_ENTRYPOINT_ENCODE) {
219		switch (param) {
220		case PIPE_VIDEO_CAP_SUPPORTED:
221			return u_reduce_video_profile(profile) == PIPE_VIDEO_FORMAT_MPEG4_AVC &&
222				rvce_is_fw_version_supported(rscreen);
223	        case PIPE_VIDEO_CAP_NPOT_TEXTURES:
224        	        return 1;
225	        case PIPE_VIDEO_CAP_MAX_WIDTH:
226        	        return 2048;
227	        case PIPE_VIDEO_CAP_MAX_HEIGHT:
228        	        return 1152;
229	        case PIPE_VIDEO_CAP_PREFERED_FORMAT:
230        	        return PIPE_FORMAT_NV12;
231	        case PIPE_VIDEO_CAP_PREFERS_INTERLACED:
232        	        return false;
233	        case PIPE_VIDEO_CAP_SUPPORTS_INTERLACED:
234        	        return false;
235	        case PIPE_VIDEO_CAP_SUPPORTS_PROGRESSIVE:
236        	        return true;
237	        default:
238        	        return 0;
239		}
240	}
241
242	/* UVD 2.x limits */
243	if (rscreen->family < CHIP_PALM) {
244		enum pipe_video_format codec = u_reduce_video_profile(profile);
245		switch (param) {
246		case PIPE_VIDEO_CAP_SUPPORTED:
247			/* no support for MPEG4 */
248			return codec != PIPE_VIDEO_FORMAT_MPEG4 &&
249			       /* FIXME: VC-1 simple/main profile is broken */
250			       profile != PIPE_VIDEO_PROFILE_VC1_SIMPLE &&
251			       profile != PIPE_VIDEO_PROFILE_VC1_MAIN;
252		case PIPE_VIDEO_CAP_PREFERS_INTERLACED:
253		case PIPE_VIDEO_CAP_SUPPORTS_INTERLACED:
254			/* MPEG2 only with shaders and no support for
255			   interlacing on R6xx style UVD */
256			return codec != PIPE_VIDEO_FORMAT_MPEG12 &&
257			       /* TODO: RV770 might actually work */
258			       rscreen->family > CHIP_RV770;
259		default:
260			break;
261		}
262	}
263
264	switch (param) {
265	case PIPE_VIDEO_CAP_SUPPORTED:
266		switch (u_reduce_video_profile(profile)) {
267		case PIPE_VIDEO_FORMAT_MPEG12:
268		case PIPE_VIDEO_FORMAT_MPEG4:
269		case PIPE_VIDEO_FORMAT_MPEG4_AVC:
270			return entrypoint != PIPE_VIDEO_ENTRYPOINT_ENCODE;
271		case PIPE_VIDEO_FORMAT_VC1:
272			/* FIXME: VC-1 simple/main profile is broken */
273			return profile == PIPE_VIDEO_PROFILE_VC1_ADVANCED &&
274			       entrypoint != PIPE_VIDEO_ENTRYPOINT_ENCODE;
275		default:
276			return false;
277		}
278	case PIPE_VIDEO_CAP_NPOT_TEXTURES:
279		return 1;
280	case PIPE_VIDEO_CAP_MAX_WIDTH:
281		return 2048;
282	case PIPE_VIDEO_CAP_MAX_HEIGHT:
283		return 1152;
284	case PIPE_VIDEO_CAP_PREFERED_FORMAT:
285		return PIPE_FORMAT_NV12;
286	case PIPE_VIDEO_CAP_PREFERS_INTERLACED:
287		return true;
288	case PIPE_VIDEO_CAP_SUPPORTS_INTERLACED:
289		return true;
290	case PIPE_VIDEO_CAP_SUPPORTS_PROGRESSIVE:
291		return true;
292	case PIPE_VIDEO_CAP_MAX_LEVEL:
293		switch (profile) {
294		case PIPE_VIDEO_PROFILE_MPEG1:
295			return 0;
296		case PIPE_VIDEO_PROFILE_MPEG2_SIMPLE:
297		case PIPE_VIDEO_PROFILE_MPEG2_MAIN:
298			return 3;
299		case PIPE_VIDEO_PROFILE_MPEG4_SIMPLE:
300			return 3;
301		case PIPE_VIDEO_PROFILE_MPEG4_ADVANCED_SIMPLE:
302			return 5;
303		case PIPE_VIDEO_PROFILE_VC1_SIMPLE:
304			return 1;
305		case PIPE_VIDEO_PROFILE_VC1_MAIN:
306			return 2;
307		case PIPE_VIDEO_PROFILE_VC1_ADVANCED:
308			return 4;
309		case PIPE_VIDEO_PROFILE_MPEG4_AVC_BASELINE:
310		case PIPE_VIDEO_PROFILE_MPEG4_AVC_MAIN:
311		case PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH:
312			return 41;
313		default:
314			return 0;
315		}
316	default:
317		return 0;
318	}
319}
320
321boolean rvid_is_format_supported(struct pipe_screen *screen,
322				 enum pipe_format format,
323				 enum pipe_video_profile profile,
324				 enum pipe_video_entrypoint entrypoint)
325{
326	/* we can only handle this one with UVD */
327	if (profile != PIPE_VIDEO_PROFILE_UNKNOWN)
328		return format == PIPE_FORMAT_NV12;
329
330	return vl_video_buffer_is_format_supported(screen, format, profile, entrypoint);
331}
332