1bf215546Sopenharmony_ci/************************************************************************** 2bf215546Sopenharmony_ci * 3bf215546Sopenharmony_ci * Copyright 2013 Advanced Micro Devices, Inc. 4bf215546Sopenharmony_ci * All Rights Reserved. 5bf215546Sopenharmony_ci * 6bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 7bf215546Sopenharmony_ci * copy of this software and associated documentation files (the 8bf215546Sopenharmony_ci * "Software"), to deal in the Software without restriction, including 9bf215546Sopenharmony_ci * without limitation the rights to use, copy, modify, merge, publish, 10bf215546Sopenharmony_ci * distribute, sub license, and/or sell copies of the Software, and to 11bf215546Sopenharmony_ci * permit persons to whom the Software is furnished to do so, subject to 12bf215546Sopenharmony_ci * the following conditions: 13bf215546Sopenharmony_ci * 14bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the 15bf215546Sopenharmony_ci * next paragraph) shall be included in all copies or substantial portions 16bf215546Sopenharmony_ci * of the Software. 17bf215546Sopenharmony_ci * 18bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19bf215546Sopenharmony_ci * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20bf215546Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 21bf215546Sopenharmony_ci * IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR 22bf215546Sopenharmony_ci * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 23bf215546Sopenharmony_ci * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 24bf215546Sopenharmony_ci * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25bf215546Sopenharmony_ci * 26bf215546Sopenharmony_ci **************************************************************************/ 27bf215546Sopenharmony_ci 28bf215546Sopenharmony_ci/* 29bf215546Sopenharmony_ci * Authors: 30bf215546Sopenharmony_ci * Christian König <christian.koenig@amd.com> 31bf215546Sopenharmony_ci * 32bf215546Sopenharmony_ci */ 33bf215546Sopenharmony_ci 34bf215546Sopenharmony_ci#include <unistd.h> 35bf215546Sopenharmony_ci 36bf215546Sopenharmony_ci#include "util/u_memory.h" 37bf215546Sopenharmony_ci#include "util/u_video.h" 38bf215546Sopenharmony_ci 39bf215546Sopenharmony_ci#include "vl/vl_defines.h" 40bf215546Sopenharmony_ci#include "vl/vl_video_buffer.h" 41bf215546Sopenharmony_ci 42bf215546Sopenharmony_ci#include "r600_pipe_common.h" 43bf215546Sopenharmony_ci#include "radeon_video.h" 44bf215546Sopenharmony_ci#include "radeon_vce.h" 45bf215546Sopenharmony_ci 46bf215546Sopenharmony_ci#define UVD_FW_1_66_16 ((1 << 24) | (66 << 16) | (16 << 8)) 47bf215546Sopenharmony_ci 48bf215546Sopenharmony_ci/* generate an stream handle */ 49bf215546Sopenharmony_ciunsigned rvid_alloc_stream_handle() 50bf215546Sopenharmony_ci{ 51bf215546Sopenharmony_ci static unsigned counter = 0; 52bf215546Sopenharmony_ci unsigned stream_handle = 0; 53bf215546Sopenharmony_ci unsigned pid = getpid(); 54bf215546Sopenharmony_ci int i; 55bf215546Sopenharmony_ci 56bf215546Sopenharmony_ci for (i = 0; i < 32; ++i) 57bf215546Sopenharmony_ci stream_handle |= ((pid >> i) & 1) << (31 - i); 58bf215546Sopenharmony_ci 59bf215546Sopenharmony_ci stream_handle ^= ++counter; 60bf215546Sopenharmony_ci return stream_handle; 61bf215546Sopenharmony_ci} 62bf215546Sopenharmony_ci 63bf215546Sopenharmony_ci/* create a buffer in the winsys */ 64bf215546Sopenharmony_cibool rvid_create_buffer(struct pipe_screen *screen, struct rvid_buffer *buffer, 65bf215546Sopenharmony_ci unsigned size, unsigned usage) 66bf215546Sopenharmony_ci{ 67bf215546Sopenharmony_ci memset(buffer, 0, sizeof(*buffer)); 68bf215546Sopenharmony_ci buffer->usage = usage; 69bf215546Sopenharmony_ci 70bf215546Sopenharmony_ci /* Hardware buffer placement restrictions require the kernel to be 71bf215546Sopenharmony_ci * able to move buffers around individually, so request a 72bf215546Sopenharmony_ci * non-sub-allocated buffer. 73bf215546Sopenharmony_ci */ 74bf215546Sopenharmony_ci buffer->res = (struct r600_resource *) 75bf215546Sopenharmony_ci pipe_buffer_create(screen, PIPE_BIND_SHARED, 76bf215546Sopenharmony_ci usage, size); 77bf215546Sopenharmony_ci 78bf215546Sopenharmony_ci return buffer->res != NULL; 79bf215546Sopenharmony_ci} 80bf215546Sopenharmony_ci 81bf215546Sopenharmony_ci/* destroy a buffer */ 82bf215546Sopenharmony_civoid rvid_destroy_buffer(struct rvid_buffer *buffer) 83bf215546Sopenharmony_ci{ 84bf215546Sopenharmony_ci r600_resource_reference(&buffer->res, NULL); 85bf215546Sopenharmony_ci} 86bf215546Sopenharmony_ci 87bf215546Sopenharmony_ci/* reallocate a buffer, preserving its content */ 88bf215546Sopenharmony_cibool rvid_resize_buffer(struct pipe_screen *screen, struct radeon_cmdbuf *cs, 89bf215546Sopenharmony_ci struct rvid_buffer *new_buf, unsigned new_size) 90bf215546Sopenharmony_ci{ 91bf215546Sopenharmony_ci struct r600_common_screen *rscreen = (struct r600_common_screen *)screen; 92bf215546Sopenharmony_ci struct radeon_winsys* ws = rscreen->ws; 93bf215546Sopenharmony_ci unsigned bytes = MIN2(new_buf->res->buf->size, new_size); 94bf215546Sopenharmony_ci struct rvid_buffer old_buf = *new_buf; 95bf215546Sopenharmony_ci void *src = NULL, *dst = NULL; 96bf215546Sopenharmony_ci 97bf215546Sopenharmony_ci if (!rvid_create_buffer(screen, new_buf, new_size, new_buf->usage)) 98bf215546Sopenharmony_ci goto error; 99bf215546Sopenharmony_ci 100bf215546Sopenharmony_ci src = ws->buffer_map(ws, old_buf.res->buf, cs, 101bf215546Sopenharmony_ci PIPE_MAP_READ | RADEON_MAP_TEMPORARY); 102bf215546Sopenharmony_ci if (!src) 103bf215546Sopenharmony_ci goto error; 104bf215546Sopenharmony_ci 105bf215546Sopenharmony_ci dst = ws->buffer_map(ws, new_buf->res->buf, cs, 106bf215546Sopenharmony_ci PIPE_MAP_WRITE | RADEON_MAP_TEMPORARY); 107bf215546Sopenharmony_ci if (!dst) 108bf215546Sopenharmony_ci goto error; 109bf215546Sopenharmony_ci 110bf215546Sopenharmony_ci memcpy(dst, src, bytes); 111bf215546Sopenharmony_ci if (new_size > bytes) { 112bf215546Sopenharmony_ci new_size -= bytes; 113bf215546Sopenharmony_ci dst += bytes; 114bf215546Sopenharmony_ci memset(dst, 0, new_size); 115bf215546Sopenharmony_ci } 116bf215546Sopenharmony_ci ws->buffer_unmap(ws, new_buf->res->buf); 117bf215546Sopenharmony_ci ws->buffer_unmap(ws, old_buf.res->buf); 118bf215546Sopenharmony_ci rvid_destroy_buffer(&old_buf); 119bf215546Sopenharmony_ci return true; 120bf215546Sopenharmony_ci 121bf215546Sopenharmony_cierror: 122bf215546Sopenharmony_ci if (src) 123bf215546Sopenharmony_ci ws->buffer_unmap(ws, old_buf.res->buf); 124bf215546Sopenharmony_ci rvid_destroy_buffer(new_buf); 125bf215546Sopenharmony_ci *new_buf = old_buf; 126bf215546Sopenharmony_ci return false; 127bf215546Sopenharmony_ci} 128bf215546Sopenharmony_ci 129bf215546Sopenharmony_ci/* clear the buffer with zeros */ 130bf215546Sopenharmony_civoid rvid_clear_buffer(struct pipe_context *context, struct rvid_buffer* buffer) 131bf215546Sopenharmony_ci{ 132bf215546Sopenharmony_ci struct r600_common_context *rctx = (struct r600_common_context*)context; 133bf215546Sopenharmony_ci 134bf215546Sopenharmony_ci rctx->dma_clear_buffer(context, &buffer->res->b.b, 0, 135bf215546Sopenharmony_ci buffer->res->buf->size, 0); 136bf215546Sopenharmony_ci context->flush(context, NULL, 0); 137bf215546Sopenharmony_ci} 138bf215546Sopenharmony_ci 139bf215546Sopenharmony_ci/** 140bf215546Sopenharmony_ci * join surfaces into the same buffer with identical tiling params 141bf215546Sopenharmony_ci * sumup their sizes and replace the backend buffers with a single bo 142bf215546Sopenharmony_ci */ 143bf215546Sopenharmony_civoid rvid_join_surfaces(struct r600_common_context *rctx, 144bf215546Sopenharmony_ci struct pb_buffer** buffers[VL_NUM_COMPONENTS], 145bf215546Sopenharmony_ci struct radeon_surf *surfaces[VL_NUM_COMPONENTS]) 146bf215546Sopenharmony_ci{ 147bf215546Sopenharmony_ci struct radeon_winsys* ws; 148bf215546Sopenharmony_ci unsigned best_tiling, best_wh, off; 149bf215546Sopenharmony_ci unsigned size, alignment; 150bf215546Sopenharmony_ci struct pb_buffer *pb; 151bf215546Sopenharmony_ci unsigned i, j; 152bf215546Sopenharmony_ci 153bf215546Sopenharmony_ci ws = rctx->ws; 154bf215546Sopenharmony_ci 155bf215546Sopenharmony_ci for (i = 0, best_tiling = 0, best_wh = ~0; i < VL_NUM_COMPONENTS; ++i) { 156bf215546Sopenharmony_ci unsigned wh; 157bf215546Sopenharmony_ci 158bf215546Sopenharmony_ci if (!surfaces[i]) 159bf215546Sopenharmony_ci continue; 160bf215546Sopenharmony_ci 161bf215546Sopenharmony_ci /* choose the smallest bank w/h for now */ 162bf215546Sopenharmony_ci wh = surfaces[i]->u.legacy.bankw * surfaces[i]->u.legacy.bankh; 163bf215546Sopenharmony_ci if (wh < best_wh) { 164bf215546Sopenharmony_ci best_wh = wh; 165bf215546Sopenharmony_ci best_tiling = i; 166bf215546Sopenharmony_ci } 167bf215546Sopenharmony_ci } 168bf215546Sopenharmony_ci 169bf215546Sopenharmony_ci for (i = 0, off = 0; i < VL_NUM_COMPONENTS; ++i) { 170bf215546Sopenharmony_ci if (!surfaces[i]) 171bf215546Sopenharmony_ci continue; 172bf215546Sopenharmony_ci 173bf215546Sopenharmony_ci /* adjust the texture layer offsets */ 174bf215546Sopenharmony_ci off = align(off, 1 << surfaces[i]->surf_alignment_log2); 175bf215546Sopenharmony_ci 176bf215546Sopenharmony_ci /* copy the tiling parameters */ 177bf215546Sopenharmony_ci surfaces[i]->u.legacy.bankw = surfaces[best_tiling]->u.legacy.bankw; 178bf215546Sopenharmony_ci surfaces[i]->u.legacy.bankh = surfaces[best_tiling]->u.legacy.bankh; 179bf215546Sopenharmony_ci surfaces[i]->u.legacy.mtilea = surfaces[best_tiling]->u.legacy.mtilea; 180bf215546Sopenharmony_ci surfaces[i]->u.legacy.tile_split = surfaces[best_tiling]->u.legacy.tile_split; 181bf215546Sopenharmony_ci 182bf215546Sopenharmony_ci for (j = 0; j < ARRAY_SIZE(surfaces[i]->u.legacy.level); ++j) 183bf215546Sopenharmony_ci surfaces[i]->u.legacy.level[j].offset_256B += off / 256; 184bf215546Sopenharmony_ci 185bf215546Sopenharmony_ci off += surfaces[i]->surf_size; 186bf215546Sopenharmony_ci } 187bf215546Sopenharmony_ci 188bf215546Sopenharmony_ci for (i = 0, size = 0, alignment = 0; i < VL_NUM_COMPONENTS; ++i) { 189bf215546Sopenharmony_ci if (!buffers[i] || !*buffers[i]) 190bf215546Sopenharmony_ci continue; 191bf215546Sopenharmony_ci 192bf215546Sopenharmony_ci size = align(size, 1 << (*buffers[i])->alignment_log2); 193bf215546Sopenharmony_ci size += (*buffers[i])->size; 194bf215546Sopenharmony_ci alignment = MAX2(alignment, 1 << (*buffers[i])->alignment_log2); 195bf215546Sopenharmony_ci } 196bf215546Sopenharmony_ci 197bf215546Sopenharmony_ci if (!size) 198bf215546Sopenharmony_ci return; 199bf215546Sopenharmony_ci 200bf215546Sopenharmony_ci /* TODO: 2D tiling workaround */ 201bf215546Sopenharmony_ci alignment *= 2; 202bf215546Sopenharmony_ci 203bf215546Sopenharmony_ci pb = ws->buffer_create(ws, size, alignment, RADEON_DOMAIN_VRAM, 204bf215546Sopenharmony_ci RADEON_FLAG_GTT_WC); 205bf215546Sopenharmony_ci if (!pb) 206bf215546Sopenharmony_ci return; 207bf215546Sopenharmony_ci 208bf215546Sopenharmony_ci for (i = 0; i < VL_NUM_COMPONENTS; ++i) { 209bf215546Sopenharmony_ci if (!buffers[i] || !*buffers[i]) 210bf215546Sopenharmony_ci continue; 211bf215546Sopenharmony_ci 212bf215546Sopenharmony_ci pb_reference(buffers[i], pb); 213bf215546Sopenharmony_ci } 214bf215546Sopenharmony_ci 215bf215546Sopenharmony_ci pb_reference(&pb, NULL); 216bf215546Sopenharmony_ci} 217bf215546Sopenharmony_ci 218bf215546Sopenharmony_ciint rvid_get_video_param(struct pipe_screen *screen, 219bf215546Sopenharmony_ci enum pipe_video_profile profile, 220bf215546Sopenharmony_ci enum pipe_video_entrypoint entrypoint, 221bf215546Sopenharmony_ci enum pipe_video_cap param) 222bf215546Sopenharmony_ci{ 223bf215546Sopenharmony_ci struct r600_common_screen *rscreen = (struct r600_common_screen *)screen; 224bf215546Sopenharmony_ci enum pipe_video_format codec = u_reduce_video_profile(profile); 225bf215546Sopenharmony_ci struct radeon_info info; 226bf215546Sopenharmony_ci 227bf215546Sopenharmony_ci rscreen->ws->query_info(rscreen->ws, &info, false, false); 228bf215546Sopenharmony_ci 229bf215546Sopenharmony_ci if (entrypoint == PIPE_VIDEO_ENTRYPOINT_ENCODE) { 230bf215546Sopenharmony_ci switch (param) { 231bf215546Sopenharmony_ci case PIPE_VIDEO_CAP_SUPPORTED: 232bf215546Sopenharmony_ci return codec == PIPE_VIDEO_FORMAT_MPEG4_AVC && 233bf215546Sopenharmony_ci rvce_is_fw_version_supported(rscreen); 234bf215546Sopenharmony_ci case PIPE_VIDEO_CAP_NPOT_TEXTURES: 235bf215546Sopenharmony_ci return 1; 236bf215546Sopenharmony_ci case PIPE_VIDEO_CAP_MAX_WIDTH: 237bf215546Sopenharmony_ci return 2048; 238bf215546Sopenharmony_ci case PIPE_VIDEO_CAP_MAX_HEIGHT: 239bf215546Sopenharmony_ci return 1152; 240bf215546Sopenharmony_ci case PIPE_VIDEO_CAP_PREFERED_FORMAT: 241bf215546Sopenharmony_ci return PIPE_FORMAT_NV12; 242bf215546Sopenharmony_ci case PIPE_VIDEO_CAP_PREFERS_INTERLACED: 243bf215546Sopenharmony_ci return false; 244bf215546Sopenharmony_ci case PIPE_VIDEO_CAP_SUPPORTS_INTERLACED: 245bf215546Sopenharmony_ci return false; 246bf215546Sopenharmony_ci case PIPE_VIDEO_CAP_SUPPORTS_PROGRESSIVE: 247bf215546Sopenharmony_ci return true; 248bf215546Sopenharmony_ci case PIPE_VIDEO_CAP_STACKED_FRAMES: 249bf215546Sopenharmony_ci return 1; 250bf215546Sopenharmony_ci default: 251bf215546Sopenharmony_ci return 0; 252bf215546Sopenharmony_ci } 253bf215546Sopenharmony_ci } 254bf215546Sopenharmony_ci 255bf215546Sopenharmony_ci switch (param) { 256bf215546Sopenharmony_ci case PIPE_VIDEO_CAP_SUPPORTED: 257bf215546Sopenharmony_ci switch (codec) { 258bf215546Sopenharmony_ci case PIPE_VIDEO_FORMAT_MPEG12: 259bf215546Sopenharmony_ci return profile != PIPE_VIDEO_PROFILE_MPEG1; 260bf215546Sopenharmony_ci case PIPE_VIDEO_FORMAT_MPEG4: 261bf215546Sopenharmony_ci /* no support for MPEG4 on older hw */ 262bf215546Sopenharmony_ci return rscreen->family >= CHIP_PALM; 263bf215546Sopenharmony_ci case PIPE_VIDEO_FORMAT_MPEG4_AVC: 264bf215546Sopenharmony_ci return true; 265bf215546Sopenharmony_ci case PIPE_VIDEO_FORMAT_VC1: 266bf215546Sopenharmony_ci return true; 267bf215546Sopenharmony_ci case PIPE_VIDEO_FORMAT_HEVC: 268bf215546Sopenharmony_ci return false; 269bf215546Sopenharmony_ci case PIPE_VIDEO_FORMAT_JPEG: 270bf215546Sopenharmony_ci return false; 271bf215546Sopenharmony_ci default: 272bf215546Sopenharmony_ci return false; 273bf215546Sopenharmony_ci } 274bf215546Sopenharmony_ci case PIPE_VIDEO_CAP_NPOT_TEXTURES: 275bf215546Sopenharmony_ci return 1; 276bf215546Sopenharmony_ci case PIPE_VIDEO_CAP_MAX_WIDTH: 277bf215546Sopenharmony_ci return 2048; 278bf215546Sopenharmony_ci case PIPE_VIDEO_CAP_MAX_HEIGHT: 279bf215546Sopenharmony_ci return 1152; 280bf215546Sopenharmony_ci case PIPE_VIDEO_CAP_PREFERED_FORMAT: 281bf215546Sopenharmony_ci return PIPE_FORMAT_NV12; 282bf215546Sopenharmony_ci 283bf215546Sopenharmony_ci case PIPE_VIDEO_CAP_PREFERS_INTERLACED: 284bf215546Sopenharmony_ci case PIPE_VIDEO_CAP_SUPPORTS_INTERLACED: 285bf215546Sopenharmony_ci if (rscreen->family < CHIP_PALM) { 286bf215546Sopenharmony_ci /* MPEG2 only with shaders and no support for 287bf215546Sopenharmony_ci interlacing on R6xx style UVD */ 288bf215546Sopenharmony_ci return codec != PIPE_VIDEO_FORMAT_MPEG12 && 289bf215546Sopenharmony_ci rscreen->family > CHIP_RV770; 290bf215546Sopenharmony_ci } else { 291bf215546Sopenharmony_ci enum pipe_video_format format = u_reduce_video_profile(profile); 292bf215546Sopenharmony_ci 293bf215546Sopenharmony_ci if (format == PIPE_VIDEO_FORMAT_JPEG) 294bf215546Sopenharmony_ci return false; 295bf215546Sopenharmony_ci return true; 296bf215546Sopenharmony_ci } 297bf215546Sopenharmony_ci case PIPE_VIDEO_CAP_SUPPORTS_PROGRESSIVE: 298bf215546Sopenharmony_ci return true; 299bf215546Sopenharmony_ci case PIPE_VIDEO_CAP_MAX_LEVEL: 300bf215546Sopenharmony_ci switch (profile) { 301bf215546Sopenharmony_ci case PIPE_VIDEO_PROFILE_MPEG1: 302bf215546Sopenharmony_ci return 0; 303bf215546Sopenharmony_ci case PIPE_VIDEO_PROFILE_MPEG2_SIMPLE: 304bf215546Sopenharmony_ci case PIPE_VIDEO_PROFILE_MPEG2_MAIN: 305bf215546Sopenharmony_ci return 3; 306bf215546Sopenharmony_ci case PIPE_VIDEO_PROFILE_MPEG4_SIMPLE: 307bf215546Sopenharmony_ci return 3; 308bf215546Sopenharmony_ci case PIPE_VIDEO_PROFILE_MPEG4_ADVANCED_SIMPLE: 309bf215546Sopenharmony_ci return 5; 310bf215546Sopenharmony_ci case PIPE_VIDEO_PROFILE_VC1_SIMPLE: 311bf215546Sopenharmony_ci return 1; 312bf215546Sopenharmony_ci case PIPE_VIDEO_PROFILE_VC1_MAIN: 313bf215546Sopenharmony_ci return 2; 314bf215546Sopenharmony_ci case PIPE_VIDEO_PROFILE_VC1_ADVANCED: 315bf215546Sopenharmony_ci return 4; 316bf215546Sopenharmony_ci case PIPE_VIDEO_PROFILE_MPEG4_AVC_BASELINE: 317bf215546Sopenharmony_ci case PIPE_VIDEO_PROFILE_MPEG4_AVC_MAIN: 318bf215546Sopenharmony_ci case PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH: 319bf215546Sopenharmony_ci return 41; 320bf215546Sopenharmony_ci default: 321bf215546Sopenharmony_ci return 0; 322bf215546Sopenharmony_ci } 323bf215546Sopenharmony_ci default: 324bf215546Sopenharmony_ci return 0; 325bf215546Sopenharmony_ci } 326bf215546Sopenharmony_ci} 327bf215546Sopenharmony_ci 328bf215546Sopenharmony_cibool rvid_is_format_supported(struct pipe_screen *screen, 329bf215546Sopenharmony_ci enum pipe_format format, 330bf215546Sopenharmony_ci enum pipe_video_profile profile, 331bf215546Sopenharmony_ci enum pipe_video_entrypoint entrypoint) 332bf215546Sopenharmony_ci{ 333bf215546Sopenharmony_ci /* we can only handle this one with UVD */ 334bf215546Sopenharmony_ci if (profile != PIPE_VIDEO_PROFILE_UNKNOWN) 335bf215546Sopenharmony_ci return format == PIPE_FORMAT_NV12; 336bf215546Sopenharmony_ci 337bf215546Sopenharmony_ci return vl_video_buffer_is_format_supported(screen, format, profile, entrypoint); 338bf215546Sopenharmony_ci} 339