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