vaapi_utils.cc 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363
  1. // Copyright 2018 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "media/gpu/vaapi/vaapi_utils.h"
  5. #include <type_traits>
  6. #include <utility>
  7. #include "base/cxx17_backports.h"
  8. #include "base/logging.h"
  9. #include "base/memory/ptr_util.h"
  10. #include "base/synchronization/lock.h"
  11. #include "build/chromeos_buildflags.h"
  12. #include "media/gpu/vaapi/vaapi_common.h"
  13. #include "media/gpu/vaapi/vaapi_wrapper.h"
  14. #include "media/gpu/vp8_picture.h"
  15. #include "media/gpu/vp8_reference_frame_vector.h"
  16. #include "third_party/libva_protected_content/va_protected_content.h"
  17. namespace media {
  18. namespace {
  19. template <typename To, typename From>
  20. void CheckedMemcpy(To& to, From& from) {
  21. static_assert(std::is_array<To>::value, "First parameter must be an array");
  22. static_assert(std::is_array<From>::value,
  23. "Second parameter must be an array");
  24. static_assert(sizeof(to) == sizeof(from), "arrays must be of same size");
  25. memcpy(&to, &from, sizeof(to));
  26. }
  27. } // namespace
  28. ScopedVABufferMapping::ScopedVABufferMapping(
  29. const base::Lock* lock,
  30. VADisplay va_display,
  31. VABufferID buffer_id,
  32. base::OnceCallback<void(VABufferID)> release_callback)
  33. : lock_(lock), va_display_(va_display), buffer_id_(buffer_id) {
  34. MAYBE_ASSERT_ACQUIRED(lock_);
  35. DCHECK_NE(buffer_id, VA_INVALID_ID);
  36. const VAStatus result =
  37. vaMapBuffer(va_display_, buffer_id_, &va_buffer_data_);
  38. const bool success = result == VA_STATUS_SUCCESS;
  39. LOG_IF(ERROR, !success) << "vaMapBuffer failed: " << vaErrorStr(result);
  40. DCHECK(success == (va_buffer_data_ != nullptr))
  41. << "|va_buffer_data| should be null if vaMapBuffer() fails";
  42. if (!success && release_callback)
  43. std::move(release_callback).Run(buffer_id_);
  44. }
  45. ScopedVABufferMapping::~ScopedVABufferMapping() {
  46. CHECK(sequence_checker_.CalledOnValidSequence());
  47. if (va_buffer_data_) {
  48. MAYBE_ASSERT_ACQUIRED(lock_);
  49. Unmap();
  50. }
  51. }
  52. VAStatus ScopedVABufferMapping::Unmap() {
  53. CHECK(sequence_checker_.CalledOnValidSequence());
  54. MAYBE_ASSERT_ACQUIRED(lock_);
  55. const VAStatus result = vaUnmapBuffer(va_display_, buffer_id_);
  56. if (result == VA_STATUS_SUCCESS)
  57. va_buffer_data_ = nullptr;
  58. else
  59. LOG(ERROR) << "vaUnmapBuffer failed: " << vaErrorStr(result);
  60. return result;
  61. }
  62. // static
  63. std::unique_ptr<ScopedVABuffer> ScopedVABuffer::Create(
  64. base::Lock* lock,
  65. VADisplay va_display,
  66. VAContextID va_context_id,
  67. VABufferType va_buffer_type,
  68. size_t size) {
  69. DCHECK(va_display);
  70. DCHECK_NE(va_context_id, VA_INVALID_ID);
  71. DCHECK(IsValidVABufferType(va_buffer_type));
  72. DCHECK_NE(size, 0u);
  73. MAYBE_ASSERT_ACQUIRED(lock);
  74. unsigned int va_buffer_size;
  75. if (!base::CheckedNumeric<size_t>(size).AssignIfValid(&va_buffer_size)) {
  76. LOG(ERROR) << "Invalid size, " << size;
  77. return nullptr;
  78. }
  79. VABufferID buffer_id = VA_INVALID_ID;
  80. const VAStatus va_res =
  81. vaCreateBuffer(va_display, va_context_id, va_buffer_type, va_buffer_size,
  82. 1, nullptr, &buffer_id);
  83. if (va_res != VA_STATUS_SUCCESS) {
  84. LOG(ERROR) << "Failed to create a VA buffer: " << vaErrorStr(va_res);
  85. return nullptr;
  86. }
  87. DCHECK_NE(buffer_id, VA_INVALID_ID);
  88. return base::WrapUnique(
  89. new ScopedVABuffer(lock, va_display, buffer_id, va_buffer_type, size));
  90. }
  91. // static
  92. std::unique_ptr<ScopedVABuffer> ScopedVABuffer::CreateForTesting(
  93. VABufferID va_buffer_id,
  94. VABufferType va_buffer_type,
  95. size_t size) {
  96. return base::WrapUnique(
  97. new ScopedVABuffer(nullptr, nullptr, va_buffer_id, va_buffer_type, size));
  98. }
  99. ScopedVABuffer::ScopedVABuffer(base::Lock* lock,
  100. VADisplay va_display,
  101. VABufferID va_buffer_id,
  102. VABufferType va_buffer_type,
  103. size_t size)
  104. : lock_(lock),
  105. va_display_(va_display),
  106. va_buffer_id_(va_buffer_id),
  107. va_buffer_type_(va_buffer_type),
  108. size_(size) {}
  109. ScopedVABuffer::~ScopedVABuffer() {
  110. DCHECK_NE(va_buffer_id_, VA_INVALID_ID);
  111. if (!va_display_)
  112. return; // Don't call VA-API function in test.
  113. base::AutoLockMaybe auto_lock(lock_.get());
  114. VAStatus va_res = vaDestroyBuffer(va_display_, va_buffer_id_);
  115. LOG_IF(ERROR, va_res != VA_STATUS_SUCCESS)
  116. << "Failed to destroy a VA buffer: " << vaErrorStr(va_res);
  117. }
  118. ScopedVAImage::ScopedVAImage(base::Lock* lock,
  119. VADisplay va_display,
  120. VASurfaceID va_surface_id,
  121. VAImageFormat* format,
  122. const gfx::Size& size)
  123. : lock_(lock), va_display_(va_display), image_(new VAImage{}) {
  124. MAYBE_ASSERT_ACQUIRED(lock_);
  125. VAStatus result = vaCreateImage(va_display_, format, size.width(),
  126. size.height(), image_.get());
  127. if (result != VA_STATUS_SUCCESS) {
  128. DCHECK_EQ(image_->image_id, VA_INVALID_ID);
  129. LOG(ERROR) << "vaCreateImage failed: " << vaErrorStr(result);
  130. return;
  131. }
  132. DCHECK_NE(image_->image_id, VA_INVALID_ID);
  133. result = vaGetImage(va_display_, va_surface_id, 0, 0, size.width(),
  134. size.height(), image_->image_id);
  135. if (result != VA_STATUS_SUCCESS) {
  136. LOG(ERROR) << "vaGetImage failed: " << vaErrorStr(result);
  137. return;
  138. }
  139. va_buffer_ =
  140. std::make_unique<ScopedVABufferMapping>(lock_, va_display, image_->buf);
  141. }
  142. ScopedVAImage::~ScopedVAImage() {
  143. CHECK(sequence_checker_.CalledOnValidSequence());
  144. if (image_->image_id != VA_INVALID_ID) {
  145. base::AutoLockMaybe auto_lock(lock_.get());
  146. // |va_buffer_| has to be deleted before vaDestroyImage().
  147. va_buffer_.reset();
  148. vaDestroyImage(va_display_, image_->image_id);
  149. }
  150. }
  151. ScopedVASurface::ScopedVASurface(scoped_refptr<VaapiWrapper> vaapi_wrapper,
  152. VASurfaceID va_surface_id,
  153. const gfx::Size& size,
  154. unsigned int va_rt_format)
  155. : vaapi_wrapper_(std::move(vaapi_wrapper)),
  156. va_surface_id_(va_surface_id),
  157. size_(size),
  158. va_rt_format_(va_rt_format) {
  159. DCHECK(vaapi_wrapper_);
  160. }
  161. ScopedVASurface::~ScopedVASurface() {
  162. if (va_surface_id_ != VA_INVALID_ID)
  163. vaapi_wrapper_->DestroySurface(va_surface_id_);
  164. }
  165. bool ScopedVASurface::IsValid() const {
  166. return va_surface_id_ != VA_INVALID_ID && !size_.IsEmpty() &&
  167. va_rt_format_ != kInvalidVaRtFormat;
  168. }
  169. void FillVP8DataStructures(const Vp8FrameHeader& frame_header,
  170. const Vp8ReferenceFrameVector& reference_frames,
  171. VAIQMatrixBufferVP8* iq_matrix_buf,
  172. VAProbabilityDataBufferVP8* prob_buf,
  173. VAPictureParameterBufferVP8* pic_param,
  174. VASliceParameterBufferVP8* slice_param) {
  175. const Vp8SegmentationHeader& sgmnt_hdr = frame_header.segmentation_hdr;
  176. const Vp8QuantizationHeader& quant_hdr = frame_header.quantization_hdr;
  177. static_assert(std::size(decltype(iq_matrix_buf->quantization_index){}) ==
  178. kMaxMBSegments,
  179. "incorrect quantization matrix segment size");
  180. static_assert(
  181. std::size(decltype(iq_matrix_buf->quantization_index){}[0]) == 6,
  182. "incorrect quantization matrix Q index size");
  183. for (size_t i = 0; i < kMaxMBSegments; ++i) {
  184. int q = quant_hdr.y_ac_qi;
  185. if (sgmnt_hdr.segmentation_enabled) {
  186. if (sgmnt_hdr.segment_feature_mode ==
  187. Vp8SegmentationHeader::FEATURE_MODE_ABSOLUTE) {
  188. q = sgmnt_hdr.quantizer_update_value[i];
  189. } else {
  190. q += sgmnt_hdr.quantizer_update_value[i];
  191. }
  192. }
  193. #define CLAMP_Q(q) base::clamp(q, 0, 127)
  194. iq_matrix_buf->quantization_index[i][0] = CLAMP_Q(q);
  195. iq_matrix_buf->quantization_index[i][1] = CLAMP_Q(q + quant_hdr.y_dc_delta);
  196. iq_matrix_buf->quantization_index[i][2] =
  197. CLAMP_Q(q + quant_hdr.y2_dc_delta);
  198. iq_matrix_buf->quantization_index[i][3] =
  199. CLAMP_Q(q + quant_hdr.y2_ac_delta);
  200. iq_matrix_buf->quantization_index[i][4] =
  201. CLAMP_Q(q + quant_hdr.uv_dc_delta);
  202. iq_matrix_buf->quantization_index[i][5] =
  203. CLAMP_Q(q + quant_hdr.uv_ac_delta);
  204. #undef CLAMP_Q
  205. }
  206. const Vp8EntropyHeader& entr_hdr = frame_header.entropy_hdr;
  207. CheckedMemcpy(prob_buf->dct_coeff_probs, entr_hdr.coeff_probs);
  208. pic_param->frame_width = frame_header.width;
  209. pic_param->frame_height = frame_header.height;
  210. const auto last_frame = reference_frames.GetFrame(Vp8RefType::VP8_FRAME_LAST);
  211. if (last_frame) {
  212. pic_param->last_ref_frame =
  213. last_frame->AsVaapiVP8Picture()->GetVASurfaceID();
  214. } else {
  215. pic_param->last_ref_frame = VA_INVALID_SURFACE;
  216. }
  217. const auto golden_frame =
  218. reference_frames.GetFrame(Vp8RefType::VP8_FRAME_GOLDEN);
  219. if (golden_frame) {
  220. pic_param->golden_ref_frame =
  221. golden_frame->AsVaapiVP8Picture()->GetVASurfaceID();
  222. } else {
  223. pic_param->golden_ref_frame = VA_INVALID_SURFACE;
  224. }
  225. const auto alt_frame =
  226. reference_frames.GetFrame(Vp8RefType::VP8_FRAME_ALTREF);
  227. if (alt_frame)
  228. pic_param->alt_ref_frame = alt_frame->AsVaapiVP8Picture()->GetVASurfaceID();
  229. else
  230. pic_param->alt_ref_frame = VA_INVALID_SURFACE;
  231. pic_param->out_of_loop_frame = VA_INVALID_SURFACE;
  232. const Vp8LoopFilterHeader& lf_hdr = frame_header.loopfilter_hdr;
  233. #define FHDR_TO_PP_PF(a, b) pic_param->pic_fields.bits.a = (b)
  234. FHDR_TO_PP_PF(key_frame, frame_header.IsKeyframe() ? 0 : 1);
  235. FHDR_TO_PP_PF(version, frame_header.version);
  236. FHDR_TO_PP_PF(segmentation_enabled, sgmnt_hdr.segmentation_enabled);
  237. FHDR_TO_PP_PF(update_mb_segmentation_map,
  238. sgmnt_hdr.update_mb_segmentation_map);
  239. FHDR_TO_PP_PF(update_segment_feature_data,
  240. sgmnt_hdr.update_segment_feature_data);
  241. FHDR_TO_PP_PF(filter_type, lf_hdr.type);
  242. FHDR_TO_PP_PF(sharpness_level, lf_hdr.sharpness_level);
  243. FHDR_TO_PP_PF(loop_filter_adj_enable, lf_hdr.loop_filter_adj_enable);
  244. FHDR_TO_PP_PF(mode_ref_lf_delta_update, lf_hdr.mode_ref_lf_delta_update);
  245. FHDR_TO_PP_PF(sign_bias_golden, frame_header.sign_bias_golden);
  246. FHDR_TO_PP_PF(sign_bias_alternate, frame_header.sign_bias_alternate);
  247. FHDR_TO_PP_PF(mb_no_coeff_skip, frame_header.mb_no_skip_coeff);
  248. FHDR_TO_PP_PF(loop_filter_disable, lf_hdr.level == 0);
  249. #undef FHDR_TO_PP_PF
  250. CheckedMemcpy(pic_param->mb_segment_tree_probs, sgmnt_hdr.segment_prob);
  251. static_assert(std::extent<decltype(sgmnt_hdr.lf_update_value)>() ==
  252. std::extent<decltype(pic_param->loop_filter_level)>(),
  253. "loop filter level arrays mismatch");
  254. for (size_t i = 0; i < std::size(sgmnt_hdr.lf_update_value); ++i) {
  255. int lf_level = lf_hdr.level;
  256. if (sgmnt_hdr.segmentation_enabled) {
  257. if (sgmnt_hdr.segment_feature_mode ==
  258. Vp8SegmentationHeader::FEATURE_MODE_ABSOLUTE) {
  259. lf_level = sgmnt_hdr.lf_update_value[i];
  260. } else {
  261. lf_level += sgmnt_hdr.lf_update_value[i];
  262. }
  263. }
  264. pic_param->loop_filter_level[i] = base::clamp(lf_level, 0, 63);
  265. }
  266. static_assert(
  267. std::extent<decltype(lf_hdr.ref_frame_delta)>() ==
  268. std::extent<decltype(pic_param->loop_filter_deltas_ref_frame)>(),
  269. "loop filter deltas arrays size mismatch");
  270. static_assert(std::extent<decltype(lf_hdr.mb_mode_delta)>() ==
  271. std::extent<decltype(pic_param->loop_filter_deltas_mode)>(),
  272. "loop filter deltas arrays size mismatch");
  273. static_assert(std::extent<decltype(lf_hdr.ref_frame_delta)>() ==
  274. std::extent<decltype(lf_hdr.mb_mode_delta)>(),
  275. "loop filter deltas arrays size mismatch");
  276. for (size_t i = 0; i < std::size(lf_hdr.ref_frame_delta); ++i) {
  277. pic_param->loop_filter_deltas_ref_frame[i] = lf_hdr.ref_frame_delta[i];
  278. pic_param->loop_filter_deltas_mode[i] = lf_hdr.mb_mode_delta[i];
  279. }
  280. #define FHDR_TO_PP(a) pic_param->a = frame_header.a
  281. FHDR_TO_PP(prob_skip_false);
  282. FHDR_TO_PP(prob_intra);
  283. FHDR_TO_PP(prob_last);
  284. FHDR_TO_PP(prob_gf);
  285. #undef FHDR_TO_PP
  286. CheckedMemcpy(pic_param->y_mode_probs, entr_hdr.y_mode_probs);
  287. CheckedMemcpy(pic_param->uv_mode_probs, entr_hdr.uv_mode_probs);
  288. CheckedMemcpy(pic_param->mv_probs, entr_hdr.mv_probs);
  289. pic_param->bool_coder_ctx.range = frame_header.bool_dec_range;
  290. pic_param->bool_coder_ctx.value = frame_header.bool_dec_value;
  291. pic_param->bool_coder_ctx.count = frame_header.bool_dec_count;
  292. slice_param->slice_data_size = frame_header.frame_size;
  293. slice_param->slice_data_offset = frame_header.first_part_offset;
  294. slice_param->slice_data_flag = VA_SLICE_DATA_FLAG_ALL;
  295. slice_param->macroblock_offset = frame_header.macroblock_bit_offset;
  296. // Number of DCT partitions plus control partition.
  297. slice_param->num_of_partitions = frame_header.num_of_dct_partitions + 1;
  298. // Per VAAPI, this size only includes the size of the macroblock data in
  299. // the first partition (in bytes), so we have to subtract the header size.
  300. slice_param->partition_size[0] =
  301. frame_header.first_part_size -
  302. ((frame_header.macroblock_bit_offset + 7) / 8);
  303. for (size_t i = 0; i < frame_header.num_of_dct_partitions; ++i)
  304. slice_param->partition_size[i + 1] = frame_header.dct_partition_sizes[i];
  305. }
  306. bool IsValidVABufferType(VABufferType type) {
  307. return type < VABufferTypeMax ||
  308. #if BUILDFLAG(IS_CHROMEOS_ASH)
  309. // TODO(jkardatzke): Remove this once we update to libva 2.0.10 in
  310. // ChromeOS.
  311. type == VAEncryptionParameterBufferType ||
  312. #endif // BUILDFLAG(IS_CHROMEOS_ASH)
  313. type == VACencStatusParameterBufferType;
  314. }
  315. } // namespace media