101e04c3fSmrg/**************************************************************************
201e04c3fSmrg *
301e04c3fSmrg * Copyright 2013 Advanced Micro Devices, Inc.
401e04c3fSmrg * All Rights Reserved.
501e04c3fSmrg *
601e04c3fSmrg * Permission is hereby granted, free of charge, to any person obtaining a
701e04c3fSmrg * copy of this software and associated documentation files (the
801e04c3fSmrg * "Software"), to deal in the Software without restriction, including
901e04c3fSmrg * without limitation the rights to use, copy, modify, merge, publish,
1001e04c3fSmrg * distribute, sub license, and/or sell copies of the Software, and to
1101e04c3fSmrg * permit persons to whom the Software is furnished to do so, subject to
1201e04c3fSmrg * the following conditions:
1301e04c3fSmrg *
1401e04c3fSmrg * The above copyright notice and this permission notice (including the
1501e04c3fSmrg * next paragraph) shall be included in all copies or substantial portions
1601e04c3fSmrg * of the Software.
1701e04c3fSmrg *
1801e04c3fSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
1901e04c3fSmrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
2001e04c3fSmrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
2101e04c3fSmrg * IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR
2201e04c3fSmrg * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
2301e04c3fSmrg * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
2401e04c3fSmrg * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2501e04c3fSmrg *
2601e04c3fSmrg **************************************************************************/
2701e04c3fSmrg
2801e04c3fSmrg/*
2901e04c3fSmrg * Authors:
3001e04c3fSmrg *      Christian König <christian.koenig@amd.com>
3101e04c3fSmrg *
3201e04c3fSmrg */
3301e04c3fSmrg
3401e04c3fSmrg#include <unistd.h>
3501e04c3fSmrg
3601e04c3fSmrg#include "util/u_memory.h"
3701e04c3fSmrg#include "util/u_video.h"
3801e04c3fSmrg
3901e04c3fSmrg#include "vl/vl_defines.h"
4001e04c3fSmrg#include "vl/vl_video_buffer.h"
4101e04c3fSmrg
4201e04c3fSmrg#include "r600_pipe_common.h"
4301e04c3fSmrg#include "radeon_video.h"
4401e04c3fSmrg#include "radeon_vce.h"
4501e04c3fSmrg
4601e04c3fSmrg#define UVD_FW_1_66_16 ((1 << 24) | (66 << 16) | (16 << 8))
4701e04c3fSmrg
4801e04c3fSmrg/* generate an stream handle */
4901e04c3fSmrgunsigned rvid_alloc_stream_handle()
5001e04c3fSmrg{
5101e04c3fSmrg	static unsigned counter = 0;
5201e04c3fSmrg	unsigned stream_handle = 0;
5301e04c3fSmrg	unsigned pid = getpid();
5401e04c3fSmrg	int i;
5501e04c3fSmrg
5601e04c3fSmrg	for (i = 0; i < 32; ++i)
5701e04c3fSmrg		stream_handle |= ((pid >> i) & 1) << (31 - i);
5801e04c3fSmrg
5901e04c3fSmrg	stream_handle ^= ++counter;
6001e04c3fSmrg	return stream_handle;
6101e04c3fSmrg}
6201e04c3fSmrg
6301e04c3fSmrg/* create a buffer in the winsys */
6401e04c3fSmrgbool rvid_create_buffer(struct pipe_screen *screen, struct rvid_buffer *buffer,
6501e04c3fSmrg			unsigned size, unsigned usage)
6601e04c3fSmrg{
6701e04c3fSmrg	memset(buffer, 0, sizeof(*buffer));
6801e04c3fSmrg	buffer->usage = usage;
6901e04c3fSmrg
7001e04c3fSmrg	/* Hardware buffer placement restrictions require the kernel to be
7101e04c3fSmrg	 * able to move buffers around individually, so request a
7201e04c3fSmrg	 * non-sub-allocated buffer.
7301e04c3fSmrg	 */
7401e04c3fSmrg	buffer->res = (struct r600_resource *)
7501e04c3fSmrg		pipe_buffer_create(screen, PIPE_BIND_SHARED,
7601e04c3fSmrg				   usage, size);
7701e04c3fSmrg
7801e04c3fSmrg	return buffer->res != NULL;
7901e04c3fSmrg}
8001e04c3fSmrg
8101e04c3fSmrg/* destroy a buffer */
8201e04c3fSmrgvoid rvid_destroy_buffer(struct rvid_buffer *buffer)
8301e04c3fSmrg{
8401e04c3fSmrg	r600_resource_reference(&buffer->res, NULL);
8501e04c3fSmrg}
8601e04c3fSmrg
8701e04c3fSmrg/* reallocate a buffer, preserving its content */
8801e04c3fSmrgbool rvid_resize_buffer(struct pipe_screen *screen, struct radeon_cmdbuf *cs,
8901e04c3fSmrg			struct rvid_buffer *new_buf, unsigned new_size)
9001e04c3fSmrg{
9101e04c3fSmrg	struct r600_common_screen *rscreen = (struct r600_common_screen *)screen;
9201e04c3fSmrg	struct radeon_winsys* ws = rscreen->ws;
9301e04c3fSmrg	unsigned bytes = MIN2(new_buf->res->buf->size, new_size);
9401e04c3fSmrg	struct rvid_buffer old_buf = *new_buf;
9501e04c3fSmrg	void *src = NULL, *dst = NULL;
9601e04c3fSmrg
9701e04c3fSmrg	if (!rvid_create_buffer(screen, new_buf, new_size, new_buf->usage))
9801e04c3fSmrg		goto error;
9901e04c3fSmrg
1007ec681f3Smrg	src = ws->buffer_map(ws, old_buf.res->buf, cs,
1017ec681f3Smrg			     PIPE_MAP_READ | RADEON_MAP_TEMPORARY);
10201e04c3fSmrg	if (!src)
10301e04c3fSmrg		goto error;
10401e04c3fSmrg
1057ec681f3Smrg	dst = ws->buffer_map(ws, new_buf->res->buf, cs,
1067ec681f3Smrg			     PIPE_MAP_WRITE | RADEON_MAP_TEMPORARY);
10701e04c3fSmrg	if (!dst)
10801e04c3fSmrg		goto error;
10901e04c3fSmrg
11001e04c3fSmrg	memcpy(dst, src, bytes);
11101e04c3fSmrg	if (new_size > bytes) {
11201e04c3fSmrg		new_size -= bytes;
11301e04c3fSmrg		dst += bytes;
11401e04c3fSmrg		memset(dst, 0, new_size);
11501e04c3fSmrg	}
1167ec681f3Smrg	ws->buffer_unmap(ws, new_buf->res->buf);
1177ec681f3Smrg	ws->buffer_unmap(ws, old_buf.res->buf);
11801e04c3fSmrg	rvid_destroy_buffer(&old_buf);
11901e04c3fSmrg	return true;
12001e04c3fSmrg
12101e04c3fSmrgerror:
12201e04c3fSmrg	if (src)
1237ec681f3Smrg		ws->buffer_unmap(ws, old_buf.res->buf);
12401e04c3fSmrg	rvid_destroy_buffer(new_buf);
12501e04c3fSmrg	*new_buf = old_buf;
12601e04c3fSmrg	return false;
12701e04c3fSmrg}
12801e04c3fSmrg
12901e04c3fSmrg/* clear the buffer with zeros */
13001e04c3fSmrgvoid rvid_clear_buffer(struct pipe_context *context, struct rvid_buffer* buffer)
13101e04c3fSmrg{
13201e04c3fSmrg	struct r600_common_context *rctx = (struct r600_common_context*)context;
13301e04c3fSmrg
13401e04c3fSmrg	rctx->dma_clear_buffer(context, &buffer->res->b.b, 0,
13501e04c3fSmrg			       buffer->res->buf->size, 0);
13601e04c3fSmrg	context->flush(context, NULL, 0);
13701e04c3fSmrg}
13801e04c3fSmrg
13901e04c3fSmrg/**
14001e04c3fSmrg * join surfaces into the same buffer with identical tiling params
14101e04c3fSmrg * sumup their sizes and replace the backend buffers with a single bo
14201e04c3fSmrg */
14301e04c3fSmrgvoid rvid_join_surfaces(struct r600_common_context *rctx,
14401e04c3fSmrg			struct pb_buffer** buffers[VL_NUM_COMPONENTS],
14501e04c3fSmrg			struct radeon_surf *surfaces[VL_NUM_COMPONENTS])
14601e04c3fSmrg{
14701e04c3fSmrg	struct radeon_winsys* ws;
14801e04c3fSmrg	unsigned best_tiling, best_wh, off;
14901e04c3fSmrg	unsigned size, alignment;
15001e04c3fSmrg	struct pb_buffer *pb;
15101e04c3fSmrg	unsigned i, j;
15201e04c3fSmrg
15301e04c3fSmrg	ws = rctx->ws;
15401e04c3fSmrg
15501e04c3fSmrg	for (i = 0, best_tiling = 0, best_wh = ~0; i < VL_NUM_COMPONENTS; ++i) {
15601e04c3fSmrg		unsigned wh;
15701e04c3fSmrg
15801e04c3fSmrg		if (!surfaces[i])
15901e04c3fSmrg			continue;
16001e04c3fSmrg
16101e04c3fSmrg		/* choose the smallest bank w/h for now */
16201e04c3fSmrg		wh = surfaces[i]->u.legacy.bankw * surfaces[i]->u.legacy.bankh;
16301e04c3fSmrg		if (wh < best_wh) {
16401e04c3fSmrg			best_wh = wh;
16501e04c3fSmrg			best_tiling = i;
16601e04c3fSmrg		}
16701e04c3fSmrg	}
16801e04c3fSmrg
16901e04c3fSmrg	for (i = 0, off = 0; i < VL_NUM_COMPONENTS; ++i) {
17001e04c3fSmrg		if (!surfaces[i])
17101e04c3fSmrg			continue;
17201e04c3fSmrg
17301e04c3fSmrg		/* adjust the texture layer offsets */
1747ec681f3Smrg		off = align(off, 1 << surfaces[i]->surf_alignment_log2);
17501e04c3fSmrg
17601e04c3fSmrg		/* copy the tiling parameters */
17701e04c3fSmrg		surfaces[i]->u.legacy.bankw = surfaces[best_tiling]->u.legacy.bankw;
17801e04c3fSmrg		surfaces[i]->u.legacy.bankh = surfaces[best_tiling]->u.legacy.bankh;
17901e04c3fSmrg		surfaces[i]->u.legacy.mtilea = surfaces[best_tiling]->u.legacy.mtilea;
18001e04c3fSmrg		surfaces[i]->u.legacy.tile_split = surfaces[best_tiling]->u.legacy.tile_split;
18101e04c3fSmrg
18201e04c3fSmrg		for (j = 0; j < ARRAY_SIZE(surfaces[i]->u.legacy.level); ++j)
1837ec681f3Smrg			surfaces[i]->u.legacy.level[j].offset_256B += off / 256;
18401e04c3fSmrg
18501e04c3fSmrg		off += surfaces[i]->surf_size;
18601e04c3fSmrg	}
18701e04c3fSmrg
18801e04c3fSmrg	for (i = 0, size = 0, alignment = 0; i < VL_NUM_COMPONENTS; ++i) {
18901e04c3fSmrg		if (!buffers[i] || !*buffers[i])
19001e04c3fSmrg			continue;
19101e04c3fSmrg
1927ec681f3Smrg		size = align(size, 1 << (*buffers[i])->alignment_log2);
19301e04c3fSmrg		size += (*buffers[i])->size;
1947ec681f3Smrg		alignment = MAX2(alignment, 1 << (*buffers[i])->alignment_log2);
19501e04c3fSmrg	}
19601e04c3fSmrg
19701e04c3fSmrg	if (!size)
19801e04c3fSmrg		return;
19901e04c3fSmrg
20001e04c3fSmrg	/* TODO: 2D tiling workaround */
20101e04c3fSmrg	alignment *= 2;
20201e04c3fSmrg
20301e04c3fSmrg	pb = ws->buffer_create(ws, size, alignment, RADEON_DOMAIN_VRAM,
20401e04c3fSmrg			       RADEON_FLAG_GTT_WC);
20501e04c3fSmrg	if (!pb)
20601e04c3fSmrg		return;
20701e04c3fSmrg
20801e04c3fSmrg	for (i = 0; i < VL_NUM_COMPONENTS; ++i) {
20901e04c3fSmrg		if (!buffers[i] || !*buffers[i])
21001e04c3fSmrg			continue;
21101e04c3fSmrg
21201e04c3fSmrg		pb_reference(buffers[i], pb);
21301e04c3fSmrg	}
21401e04c3fSmrg
21501e04c3fSmrg	pb_reference(&pb, NULL);
21601e04c3fSmrg}
21701e04c3fSmrg
21801e04c3fSmrgint rvid_get_video_param(struct pipe_screen *screen,
21901e04c3fSmrg			 enum pipe_video_profile profile,
22001e04c3fSmrg			 enum pipe_video_entrypoint entrypoint,
22101e04c3fSmrg			 enum pipe_video_cap param)
22201e04c3fSmrg{
22301e04c3fSmrg	struct r600_common_screen *rscreen = (struct r600_common_screen *)screen;
22401e04c3fSmrg	enum pipe_video_format codec = u_reduce_video_profile(profile);
22501e04c3fSmrg	struct radeon_info info;
22601e04c3fSmrg
2277ec681f3Smrg	rscreen->ws->query_info(rscreen->ws, &info, false, false);
22801e04c3fSmrg
22901e04c3fSmrg	if (entrypoint == PIPE_VIDEO_ENTRYPOINT_ENCODE) {
23001e04c3fSmrg		switch (param) {
23101e04c3fSmrg		case PIPE_VIDEO_CAP_SUPPORTED:
23201e04c3fSmrg			return codec == PIPE_VIDEO_FORMAT_MPEG4_AVC &&
23301e04c3fSmrg				rvce_is_fw_version_supported(rscreen);
23401e04c3fSmrg		case PIPE_VIDEO_CAP_NPOT_TEXTURES:
23501e04c3fSmrg			return 1;
23601e04c3fSmrg		case PIPE_VIDEO_CAP_MAX_WIDTH:
23701e04c3fSmrg			return 2048;
23801e04c3fSmrg		case PIPE_VIDEO_CAP_MAX_HEIGHT:
23901e04c3fSmrg			return 1152;
24001e04c3fSmrg		case PIPE_VIDEO_CAP_PREFERED_FORMAT:
24101e04c3fSmrg			return PIPE_FORMAT_NV12;
24201e04c3fSmrg		case PIPE_VIDEO_CAP_PREFERS_INTERLACED:
24301e04c3fSmrg			return false;
24401e04c3fSmrg		case PIPE_VIDEO_CAP_SUPPORTS_INTERLACED:
24501e04c3fSmrg			return false;
24601e04c3fSmrg		case PIPE_VIDEO_CAP_SUPPORTS_PROGRESSIVE:
24701e04c3fSmrg			return true;
24801e04c3fSmrg		case PIPE_VIDEO_CAP_STACKED_FRAMES:
24901e04c3fSmrg			return 1;
25001e04c3fSmrg		default:
25101e04c3fSmrg			return 0;
25201e04c3fSmrg		}
25301e04c3fSmrg	}
25401e04c3fSmrg
25501e04c3fSmrg	switch (param) {
25601e04c3fSmrg	case PIPE_VIDEO_CAP_SUPPORTED:
25701e04c3fSmrg		switch (codec) {
25801e04c3fSmrg		case PIPE_VIDEO_FORMAT_MPEG12:
25901e04c3fSmrg			return profile != PIPE_VIDEO_PROFILE_MPEG1;
26001e04c3fSmrg		case PIPE_VIDEO_FORMAT_MPEG4:
26101e04c3fSmrg			/* no support for MPEG4 on older hw */
26201e04c3fSmrg			return rscreen->family >= CHIP_PALM;
26301e04c3fSmrg		case PIPE_VIDEO_FORMAT_MPEG4_AVC:
26401e04c3fSmrg			return true;
26501e04c3fSmrg		case PIPE_VIDEO_FORMAT_VC1:
26601e04c3fSmrg			return true;
26701e04c3fSmrg		case PIPE_VIDEO_FORMAT_HEVC:
26801e04c3fSmrg			return false;
26901e04c3fSmrg		case PIPE_VIDEO_FORMAT_JPEG:
27001e04c3fSmrg			return false;
27101e04c3fSmrg		default:
27201e04c3fSmrg			return false;
27301e04c3fSmrg		}
27401e04c3fSmrg	case PIPE_VIDEO_CAP_NPOT_TEXTURES:
27501e04c3fSmrg		return 1;
27601e04c3fSmrg	case PIPE_VIDEO_CAP_MAX_WIDTH:
27701e04c3fSmrg		return 2048;
27801e04c3fSmrg	case PIPE_VIDEO_CAP_MAX_HEIGHT:
27901e04c3fSmrg		return 1152;
28001e04c3fSmrg	case PIPE_VIDEO_CAP_PREFERED_FORMAT:
2817ec681f3Smrg		return PIPE_FORMAT_NV12;
28201e04c3fSmrg
28301e04c3fSmrg	case PIPE_VIDEO_CAP_PREFERS_INTERLACED:
28401e04c3fSmrg	case PIPE_VIDEO_CAP_SUPPORTS_INTERLACED:
28501e04c3fSmrg		if (rscreen->family < CHIP_PALM) {
28601e04c3fSmrg			/* MPEG2 only with shaders and no support for
28701e04c3fSmrg			   interlacing on R6xx style UVD */
28801e04c3fSmrg			return codec != PIPE_VIDEO_FORMAT_MPEG12 &&
28901e04c3fSmrg			       rscreen->family > CHIP_RV770;
29001e04c3fSmrg		} else {
29101e04c3fSmrg			enum pipe_video_format format = u_reduce_video_profile(profile);
29201e04c3fSmrg
2937ec681f3Smrg			if (format == PIPE_VIDEO_FORMAT_JPEG)
29401e04c3fSmrg				return false;
29501e04c3fSmrg			return true;
29601e04c3fSmrg		}
29701e04c3fSmrg	case PIPE_VIDEO_CAP_SUPPORTS_PROGRESSIVE:
29801e04c3fSmrg		return true;
29901e04c3fSmrg	case PIPE_VIDEO_CAP_MAX_LEVEL:
30001e04c3fSmrg		switch (profile) {
30101e04c3fSmrg		case PIPE_VIDEO_PROFILE_MPEG1:
30201e04c3fSmrg			return 0;
30301e04c3fSmrg		case PIPE_VIDEO_PROFILE_MPEG2_SIMPLE:
30401e04c3fSmrg		case PIPE_VIDEO_PROFILE_MPEG2_MAIN:
30501e04c3fSmrg			return 3;
30601e04c3fSmrg		case PIPE_VIDEO_PROFILE_MPEG4_SIMPLE:
30701e04c3fSmrg			return 3;
30801e04c3fSmrg		case PIPE_VIDEO_PROFILE_MPEG4_ADVANCED_SIMPLE:
30901e04c3fSmrg			return 5;
31001e04c3fSmrg		case PIPE_VIDEO_PROFILE_VC1_SIMPLE:
31101e04c3fSmrg			return 1;
31201e04c3fSmrg		case PIPE_VIDEO_PROFILE_VC1_MAIN:
31301e04c3fSmrg			return 2;
31401e04c3fSmrg		case PIPE_VIDEO_PROFILE_VC1_ADVANCED:
31501e04c3fSmrg			return 4;
31601e04c3fSmrg		case PIPE_VIDEO_PROFILE_MPEG4_AVC_BASELINE:
31701e04c3fSmrg		case PIPE_VIDEO_PROFILE_MPEG4_AVC_MAIN:
31801e04c3fSmrg		case PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH:
31901e04c3fSmrg			return 41;
32001e04c3fSmrg		default:
32101e04c3fSmrg			return 0;
32201e04c3fSmrg		}
32301e04c3fSmrg	default:
32401e04c3fSmrg		return 0;
32501e04c3fSmrg	}
32601e04c3fSmrg}
32701e04c3fSmrg
3287ec681f3Smrgbool rvid_is_format_supported(struct pipe_screen *screen,
3297ec681f3Smrg			      enum pipe_format format,
3307ec681f3Smrg			      enum pipe_video_profile profile,
3317ec681f3Smrg			      enum pipe_video_entrypoint entrypoint)
33201e04c3fSmrg{
33301e04c3fSmrg	/* we can only handle this one with UVD */
33401e04c3fSmrg	if (profile != PIPE_VIDEO_PROFILE_UNKNOWN)
33501e04c3fSmrg		return format == PIPE_FORMAT_NV12;
33601e04c3fSmrg
33701e04c3fSmrg	return vl_video_buffer_is_format_supported(screen, format, profile, entrypoint);
33801e04c3fSmrg}
339